See what your coding agent actually put in its context window.
Peektrace reads the sessions and memories that Claude Code, Codex, Pi and OpenCode scatter across your disk, and shows you where the tokens went: what the model was carrying at peak, when a session crossed into the dumb zone, which tool calls failed, and how much wall-clock time went to waiting.
It runs on 127.0.0.1, reads your files, and sends nothing anywhere.
curl -fsSL https://raw.githubusercontent.com/Mark-Life/peektrace/main/scripts/install.sh | sh
peektrace serve
# or, if you have Node
npx peektrace serveThe native installer pulls a prebuilt standalone binary from GitHub Releases with the inspector embedded, verifies its SHA-256, and needs no Node and no build step:
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/Mark-Life/peektrace/main/scripts/install.sh | sh# Windows (PowerShell)
irm https://raw.githubusercontent.com/Mark-Life/peektrace/main/scripts/install.ps1 | iexIt installs to ~/.local/bin (macOS/Linux) or %LOCALAPPDATA%\peektrace\bin
(Windows) and prints PATH guidance if needed. Pin a version with
PEEKTRACE_VERSION=cli-v1.2.3 ($env:PEEKTRACE_VERSION on Windows);
PEEKTRACE_INSTALL_DIR overrides the target directory. Later, peektrace upgrade replaces the binary in place, and peektrace upgrade --check only
reports whether a newer release exists.
Binaries cover macOS (arm64, x64), Linux (x64, arm64) and Windows (x64). The Linux builds link glibc — on musl (Alpine) or anything else, build from source.
With Node already installed, npx runs the same binary without installing
anything:
npx peektrace servenpm install -g peektrace puts it on your PATH instead. Either way you get the
peektrace wrapper, which pulls only the prebuilt binary matching your platform
and skips the other four.
Update it with npm rather than peektrace upgrade. The upgrade command replaces
the binary where it stands, which under npm means inside node_modules, and the
next install undoes it.
CI publishes these packages with npm trusted publishing, so each one carries a
provenance attestation tying the tarball to the commit and workflow that built
it. Check yours with npm audit signatures.
If you see "could not locate a platform binary", your platform has no prebuilt
binary: reinstall, or build from source. To run an explicit binary, set
PEEKTRACE_BIN_PATH=/path/to/peektrace (on Windows,
$env:PEEKTRACE_BIN_PATH pointing at peektrace.exe).
There is no desktop download yet. Anything claiming otherwise under the name
peektrace is not published by this project.
peektrace serve starts the loopback server and opens the web app.
peektrace tui does the same but drives a terminal UI, with the web app served
alongside it on the same port. Pass --no-open to skip the browser.
Both read the same data through the same in-process core, so you can switch between them mid-investigation.
On a headless box, tunnel over SSH. Run peektrace serve --no-open on the box
(loopback, no token needed) and forward the same port:
ssh -N -L 4321:127.0.0.1:4321 user@host.
Direct network access is the second choice. peektrace serve --host 0.0.0.0
needs a token (printed in the URL) and is read-only unless you pass
--allow-write. It is plain HTTP, so use a private network or a tunnel. The
default is loopback only.
Browse Claude, Codex, Pi and OpenCode sessions in the web app, filter by agent, then open one for the full context-budget breakdown: peak context against the window, the partition at peak including the hidden thinking band, a growth timeline marking the dumb-zone crossing and every compaction cliff, the artifacts injected on each turn, and searchable history.
Codex reports its context window authoritatively; for Claude it is inferred, and subagents fold into their parent session. History reads either as a table or as a chat, with per-turn context and inline diffs.
Transcripts are secret-redacted by default. The reveal toggle is deliberate and per-session.
Rank what fails and what costs time across every session on the machine, not one
at a time. Findings come sorted by cheapest fix first — one run caught 561
of 603 lint invocations piping into head, so the exit code belonged to the pipe
and every failure read as a pass.
Named causes lead: an unquoted --include=*.ts that zsh aborted, a pkill -f
that killed its own shell, a missing binary, a harness-blocked sleep. Each one
counts the retries it caused (a failed call followed by a similar call that
worked), the seconds and context tokens those retries re-read, and carries a
one-line fix. When CLAUDE.md / AGENTS.md already states the rule and the
cause still fires, it says so and names an env or prompt-level change instead
of another memory line.
Subagent and workflow-agent transcripts count their own model calls, so their tokens, cost and retries are measured rather than read as zero. Reports from earlier versions showed their cost as about $0.
Underneath sit shell time by job type, error signatures grouped by shape, and a waiting panel that separates real work from parked polling.
Command text, error signatures and cluster labels are redacted before they are stored or shown. Every number ships with its caveats.
"Copy prompt", on the page and on each open row, hands an agent a short
investigation prompt: the goal, that row's numbers, sample calls by transcript
path and tool-use id, and the commands that pull more. stats prompt prints the
same text in a terminal.
peektrace stats [--days 60] [--agent claude|codex|pi|opencode|all] [--limit 20]
peektrace stats refresh [--force] # rescan and rebuild the cache
peektrace stats drill --fail <key> # expand one row
peektrace stats drill --cause <id> # failed → retry pairs behind a cause
peektrace stats prompt [--cause <id> | --fail <key> | --time <job>] # agent prompt
peektrace stats usage [--by day|month|block] [--days N] [--tz IANA] # tokens and cost over timeView, create, edit and delete Claude Code memories across all projects, with
per-project drill-in. Alongside the CRUD sits the forensic surface: a MEMORY.md
budget gauge against the 200-line / 25 KB cliff with below-fold entries flagged
INVISIBLE TO CLAUDE, a type donut, an index ↔ files diff that catches orphans,
and a [[wikilink]] graph.
Writes go back to disk atomically — temp file plus rename, compare-and-swap on mtime.
A feature × agent matrix for Claude, Codex, Pi and OpenCode. Click a cell to see why a capability is supported, partial, planned or unsupported. In the web app, session browsing is live for all four. Context debugging is full on Claude and partial on Codex, Pi and OpenCode. Memory tooling is Claude-only. Open the matrix from Settings in the web app. The terminal UI keeps its own Capabilities screen.
The same binary exposes one-shot commands, in-process or --remote <url>
against a running server. Root flags go before the subcommand: --json
(raw JSON instead of tables), --pretty (aligned instead of tab-separated),
--read-only (refuse mutating commands), --remote <url>, --otel,
--no-telemetry. --json and --read-only also work after the subcommand on
sessions, memory and stats (not stats prompt). Put --remote
before the subcommand.
peektrace sessions ls [--agent <id>] [--project <name>] [--since <when>] [--cwd <path>] [--limit <n>]
peektrace sessions search <text> [--agent <id>] [--project <name>] [--since <when>] [--limit <n>] [--no-redact]
peektrace sessions analyze [<session-id>] [--latest] [--cwd <path>]
peektrace sessions export [<session-id>] [--format html|md|json] [--out <file>] [--no-redact]
peektrace statusline [--timeout <ms>] # Claude Code status line, reads stdin
peektrace memory ls [project] # --json for raw output
peektrace memory show <project> <name>
peektrace --read-only memory rm <project> <name> # refused, nothing written
peektrace doctor # write a local support bundlepeektrace doctor collects recent local run-log events, recursively redacts
them, and writes a JSON bundle to ~/.peektrace (or PEEKTRACE_DIR) for you to
email. It is a diagnostics export, not a health check — nothing is uploaded.
peektrace sessions search "retry backoff" finds sessions whose text holds the
phrase, newest first, with the matching line and a snippet. Snippets are
redacted unless you pass --no-redact.
peektrace sessions analyze --latest scores the newest session of any agent.
--cwd . limits it to sessions run in this directory or below.
peektrace sessions export --latest --out session.html saves one session as
HTML, Markdown or JSON. Secrets and home paths are redacted unless you pass
--no-redact.
To show context health in the Claude Code status line, add this to
~/.claude/settings.json. It prints ctx 42% Healthy, or ctx -- on any
problem.
{ "statusLine": { "type": "command", "command": "peektrace statusline" } }Full flag reference: apps/cli/README.md.
apps/desktop wraps the same binary in an Electron shell — native window,
single-instance lock, auto-update from GitHub Releases — spawning the binary as a
loopback sidecar and loading its URL.
It is not distributed yet. The workflow is manual-dispatch only until builds can be signed and notarized; Mac builds are currently unsigned (right-click → Open on first launch)..
- Loopback by default. The server binds
127.0.0.1. A non-loopback--hostneeds a token and is read-only unless--allow-write. - Secret redaction on by default for every rendered or exported transcript.
- No model ever sees your data. The core reads bodies itself; no transcript and no memory is sent to an LLM.
- Safe writes. Atomic temp-write plus rename, compare-and-swap with a
per-file lock, and a compile-time read-only filesystem layer behind
--read-only. Editing is enabled only where the capability registry says the agent supports it. - Local run log, on by default, never sent anywhere. Each invocation appends
one wide event to a SQLite file under
~/.peektrace(orPEEKTRACE_DIR). It makes no network calls. Opt out with--no-telemetryorPEEKTRACE_NO_TELEMETRY=1.peektrace doctoris the only way this data leaves your machine, and only if you email the redacted bundle yourself. - One outbound call, at startup.
peektrace servefires a best-effort, non-blocking GET at the GitHub releases API to see whether a newercli-v*exists, and prints one hint line if so. The result caches for ~24h, so it hits the network at most once a day, and it never delays the server. It sends nothing about you. Disable withPEEKTRACE_NO_UPDATE_CHECK=1.
- Bun
>=1.3.0— runtime and package manager. - Node.js
>=20.9.0— required by some workspace tooling.
bun install
bun run serve # build the inspector, then serve on 127.0.0.1
bun run tui # same, into the terminal UIBoth scripts build apps/inspector first. To skip the rebuild and pass flags
straight through:
bun run --filter=inspector build # emit apps/inspector/dist once
bun run apps/cli/src/index.ts serve --port 4321Dev vs prod transport is explained in
apps/inspector/README.md.
| Path | Role |
|---|---|
packages/core |
Effect services: agents · capabilities · sessions · memory · stats · fs · watch |
packages/rpc |
Effect-RPC contract, handlers, typed client |
packages/viz |
Shared chart primitives |
packages/ui |
shadcn/ui component library |
apps/cli |
the peektrace binary: one-shot commands, serve, tui |
apps/inspector |
Vite + React + Effect-Atom web UI |
apps/desktop |
Electron shell around the compiled binary |
apps/web |
Next.js marketing site, independent of the inspector |
apps/web and its oRPC packages/api are a separate concern from Peektrace
itself. The site runs behind portless at
https://web.localhost:8443 — automatic HTTPS on an unprivileged port, so it
never needs sudo. For plain http://localhost:3000, run bun run dev:app in
apps/web.
| Command | Description |
|---|---|
bun dev |
Start all apps in dev mode |
bun run build |
Build every app and package |
bun run typecheck |
tsc --noEmit per package |
bun run check |
Lint and format check (Ultracite / Biome) |
bun run fix |
Auto-fix lint and formatting |
bun run desktop:dev |
Run the Electron shell unpackaged |
bun run desktop:package |
Build an unsigned macOS .dmg |
Typecheck with bun run typecheck only. Never tsc -b or bare tsc — build
mode emits .js and .d.ts next to sources and pollutes the tree.
Add shadcn components to the shared package, then import from @workspace/ui:
bunx shadcn@latest add button -c packages/uiOpen the repo in VS Code or Cursor and accept the recommended extensions
(.vscode/extensions.json): Biome as the default formatter, Tailwind
IntelliSense inside cn / cva / tv, the Bun debugger, and Pretty TypeScript
Errors. Format-on-save, import organization and lint auto-fix run through Biome
on every save; .editorconfig covers other editors.
apps/cli compiles to a standalone executable with the inspector embedded:
bun run --filter=peektrace build:binaryThe result serves with zero external files. Linux builds strip debug info from
OpenTUI's native library (needs llvm-strip, or GNU strip on a same-arch Linux host; see
docs/binary-size.md). CI publishes it on cli-v* tags,
feeding the installers in scripts/ and the npm packages. The same binary is the
sidecar inside the undistributed desktop app.
npm gets six packages per release: the peektrace wrapper plus one
@peektrace/cli-<platform>-<arch> per binary, published over OIDC with no stored
token. See the header of .github/workflows/publish-cli.yml.
The GitHub Release body is the matching ## cli-vX.Y.Z section of
CHANGELOG.md. A tag with no section gets generated notes instead.
MIT © Mark-Life Ltd and Andrey Markin. The licence sits at the repo
root and covers the whole workspace — every package under packages/ and
apps/, and the standalone peektrace binary built from apps/cli.







