See what your coding agent really sends.
Every request Claude Code makes -- messages, OAuth, usage/credits, MCP -- captured live in your browser. Codex, Grok, and Kimi Code too.
English | 简体中文
Docs · Install · Web UI · Saved traces · Beyond Claude · llms.txt
AI agents / LLMs: read /llms.txt; an agent skill ships in skills/cctrace.
cctrace sits between your coding agent and its API, recording every HTTP
call to a live categorized web UI and a .jsonl trace you can reopen any
time with cctrace view. No cloud, no account, nothing leaves your machine.
cctrace # trace Claude Code
cctrace codex # or the OpenAI Codex CLI
cctrace grok # or the Grok CLI
cctrace kimi # or the Kimi Code CLI (Moonshot AI)
cctrace opencode # or opencode (any provider it routes to)That's it. The agent launches normally. You get a browser tab showing everything it does.
cctrace is built for exactly two jobs:
- LLM tracing -- see exactly what your agent sends and receives each turn: system prompt, context, tool definitions, streamed replies, token/cache usage.
- Security & privacy tracing -- audit what actually leaves your machine: which hosts get contacted, what telemetry goes out, what's inside every payload.
Both jobs need the full picture -- every request, not just the convenient
ones. Claude Code ships as a Bun-compiled native binary, so the classic
node --require fetch-hook is dead. cctrace captures at the transport
layer instead: a zero-config TLS-intercepting proxy (Charles-style)
that the agent routes through via HTTPS_PROXY, trusting an auto-generated
CA. Intercepting below where URLs are built is what reaches the OAuth and
usage/credit endpoints a base-URL proxy physically cannot see -- and since
0.16 the scope is deliberate: first-party hosts are decrypted, everything
else (npm, GitHub, apt) passes through as an opaque byte-counted tunnel.
-
The full picture.
/v1/messages, OAuth, usage/credits, MCP registry, bootstrap, telemetry -- not just the chat endpoint. -
Live, categorized UI. Filter chips with counts, decoded SSE streams, reasoning-effort and prompt-cache verdicts, first-token latency, estimated cost per request. The full tour.
-
Reconstructed sessions. Turns the way a human counts them (user request -> agent work -> final response; a 213-message trace reads as 3 turns), tool rows naming the files they touched, subagent branches,
/modelepochs, compaction boundaries, superseded exchanges -- and replay: step or play back any captured session, deep-link any moment -- on a stage: lanes over time (prompts, requests, tools, subagents, cuts), the agent's observed state diagram with the current transition lit, and the beat of what it did at this step. Live, the model node lights the moment a request leaves. -
Context insights, DevTools-shaped. A Context view shows the agent's window over time. An interactive overview owns the top and never scrolls away: one stacked column per wire request, colored by the six things a window is made of, ✂ marking the compactions, and a second track showing where that step's wall-clock went (model / tools / waiting). Drag across it to select a range, drag the handles to resize it, wheel to zoom in, click a column to pin a step. A margin beside it states the balance for that step -- prompt tokens, a six-color composition bar against the model's context window, how far the chars/4 estimate reads under the billed prompt, and the six categories as lines you click to zoom. Then the selection is read three ways, one deck at a time:
- window -- the pinned step as a context graph: an icicle where
width is tokens and rows are levels, decomposing the request into
category -> group -> item, with tool results grouped by the tool that
made them, schemas by MCP server, injections by producer.
Bash x189, 38% of the windowis the widest block on the row, not a number you had to go find; click it to zoom, click a leaf to read the exact bytes, and every row says which turn first carried it in. - stream -- the agent's path as one linear list of records: system prompt, your turns, the context the harness injected (inline, at the moment it entered), the model's thinking, each tool call fused with its result, the reply. MAP / READ / FULL filters it down to the skeleton or up to everything without ever summarizing; a kind filter isolates just the injections -- the context trajectory.
- events -- every injection, compaction, model switch and tool-schema change, with what it did to the window.
Traces holding several sessions compare their peaks on one scale. Anchored to provider-reported tokens -- the wire, not a guess.
- window -- the pinned step as a context graph: an icicle where
width is tokens and rows are levels, decomposing the request into
category -> group -> item, with tool results grouped by the tool that
made them, schemas by MCP server, injections by producer.
-
Where the quota goes. The overview carries a third track: what each step cost, stacked cache read / cache write / input / output -- and an amber
$on the steps that bought their prefix twice. The margin says where the money went (per component, per model), counts those bumps and names each cause off the wire: cache expired (1h ttl, 15h idle), prefix changed (tool schemas changed), retry after 529 -- each with what a warm cache would have saved. Beside it, the account's quota as the client polled it: 5h / 7d / model-scoped, percent, when it resets, and how far it moved across this trace. Every dollar is an estimate from catalog rates; every cause is a wire fact. -
The trajectory, in the timeline. Every step on the sessions rail carries a track: how full the window was, split into the prefix read from cache and what was billed fresh. Down the rail that column is the agent's context trajectory -- it climbs, a compaction drops it, the next step runs cold, then warms again.
-
Replayable traces. Every run writes a
.jsonl;cctrace viewreopens it anytime,--htmlrenders an offline snapshot you can send around. -
One dashboard for everything.
/dashboardon any instance shows every live run and every finished trace across all your projects -- grouped by project or client, with size/tokens/cost per run -- and any row opens as a rendered session view in one click. -
Zero config. Auto-generates its CA, auto-detects your install, full first-party capture by default.
-
Scoped by design. External hosts your agent's subprocesses contact pass through as opaque tunnels (host + byte counts) -- a
go installnever lands 53MB of tarball in your trace. Details in capture modes. -
Safe by default. Credentials are redacted from headers, bodies, and URLs before anything hits disk (see Security & privacy).
| cctrace | base-URL proxy | claude-trace (node --require) |
Charles / mitmproxy | |
|---|---|---|---|---|
| Works on the native binary | yes | yes | no | yes |
Captures /v1/messages |
yes | yes | yes | yes |
| Captures OAuth / usage / credits | yes | no | no | manual |
| Zero config (auto CA + trust) | yes | yes | yes | no |
| Agent-aware UI (categories, sessions, SSE decode) | yes | -- | partial | no |
| Local-only, nothing leaves your machine | yes | yes | yes | yes |
The fetch()-hook approach (claude-trace and friends) stopped working when
Claude Code went native. A base-URL proxy still works but only sees
/v1/messages. A general TLS proxy sees everything but needs manual CA
setup and knows nothing about the endpoints. cctrace is the middle path:
zero-config, whole first-party picture, and it speaks your agent's wire.
Requires Bun, openssl, and the CLI you want to trace.
npm install -g @thevibeworks/cctrace # or: bunx @thevibeworks/cctraceOr build the standalone binary (recommended -- no Bun at runtime, exact
-- pass-through):
git clone https://github.com/thevibeworks/cctrace && cd cctrace
make install # compiles, installs to ~/.local/binThen:
cctrace # trace claude, open the live UI
cctrace -- --continue # resume your last session, traced
cctrace -- -p "hello" # args after -- go to the agent verbatim[cctrace] Live UI: http://localhost:8722/trace
[cctrace] Capture: MITM proxy http://127.0.0.1:44775 (all Anthropic hosts)
Open the Live UI and watch requests stream in. Ctrl-C when done -- the
trace lands in the store (~/.local/share/cctrace/traces/<project>/, one
dir per project, archived to .jsonl.zst at exit); reopen anytime with
cctrace view, see what the store holds with cctrace store.
Install variants, runtime notes, and the bun -- caveat:
docs/install.md.
cctrace view # reopen a saved trace (Enter = newest)
cctrace view <target> --html # render a shareable offline snapshot
cctrace ps # live instances: URL, client, project, session
cctrace history # every traced run, all projects, newest first
cctrace clean|merge|compress # housekeeping -- dry-run by default, --yes applies
cctrace purge # drop noise categories from saved traces
cctrace compact # fold redundant bodies (-95%+), view unchangedHousekeeping never shrinks your data (verified deletes, union merges,
live-append safety); compact is the one stated exception. The full
guarantees: docs/traces.md.
| Option | Description |
|---|---|
--mode MODE |
auto (default), mitm, base-url, node |
-p, --port PORT |
Live UI port (default: 8722, walks 8722..8821 when busy) |
--messages-only |
Capture only the model API calls |
--capture-external |
Decrypt every host (bodies over 64KB summarized) |
--intercept-host H |
Also decrypt host H (repeatable -- remote MCP servers) |
--bypass-host H |
Exempt host H from the proxy entirely (child NO_PROXY) |
--dir PATH |
Log directory (default: the project's dir in the store) |
--client-path PATH |
Custom binary path for any client |
Full table incl. --fresh, --with, --data-dir, --print-ca:
docs/install.md.
flowchart LR
CC["Claude Code<br/>(native binary)"]
FD{"cctrace<br/>CONNECT front door"}
TLS["TLS terminator<br/>(our leaf cert)"]
BT["TLS terminator<br/>(dynamic cert)"]
TUN["opaque tunnel<br/>(byte counts only)"]
API[("api.anthropic.com")]
PIN[("pinned / enrolled<br/>host")]
EXT[("external host<br/>npm · github · apt")]
TEE(["tee response"])
RD["redact<br/>headers · bodies · URLs"]
UI["live UI<br/>(categorized)"]
OUT[["store · jsonl.zst"]]
CC -- "HTTPS_PROXY +<br/>NODE_EXTRA_CA_CERTS" --> FD
FD -- "Anthropic host" --> TLS
FD -- "include-listed host" --> BT
FD -- "anything else" --> TUN
TLS --> API
BT --> PIN
TUN --> EXT
PIN -- "response stream" --> TEE
API -- "response stream" --> TEE
TUN -- "one meta row" --> RD
TEE -- "streamed to Claude,<br/>no buffering" --> CC
TEE -- "captured copy" --> RD
RD --> UI
RD --> OUT
classDef accent stroke:#3fb950,stroke-width:2px;
class RD accent
The proxy terminates TLS with an auto-generated leaf cert, forwards to the
real API, and tees the response so the agent gets bytes immediately while
cctrace captures a copy -- zero SSE buffering. Every captured pair is
redacted before it reaches any sink. Subprocess trust (the combined CA
bundle), why HTTP_PROXY stays unset, and the tunnel scope model:
docs/capture-modes.md.
cctrace is a local debugging tool, but it intercepts real credentialed traffic, so it redacts before writing anything:
- Headers --
authorization,x-api-key,cookie, etc. masked to a first-10/last-4 preview (enough to tell which key, not the key itself). - Bodies -- credential fields (
access_token,refresh_token,client_secret,api_key, ...) masked in JSON and form bodies. Your conversation content is left intact. - URLs -- credential-bearing query params (e.g. OAuth
?code=) masked. - Identity ids (session/user/device UUIDs) are not masked by default --
they're workflow identity, not credentials, and session-keyed features
depend on them. Sharing a trace outside your machine?
--redact-ids(orCCTRACE_REDACT_IDS=1) masks them too.
Redaction happens at a single choke point, so it applies uniformly to the
.jsonl, the .html, and the live WebSocket. Traces live outside the
project tree (the store under ~/.local/share/cctrace/), so nothing lands
in your repo by accident.
Still: a trace is a record of your real session. Review it before sharing. Never paste raw output into a public issue. Seriously.
| Start here | Go deeper |
|---|---|
| Install & options | Capture modes & proxy internals |
| The web UI tour | Saved traces & housekeeping |
| Codex / Grok / Kimi / opencode / providers | Agent skill · CHANGELOG |
- Session replay P3/P4 -- opt-in
--record-timingfor chunk-timed streaming replay (design). - WebSocket relay -- capture ws frames instead of the current fast refusal + HTTP fallback.
- Conversation dump -- export the reconstructed conversation as Markdown or JSON.
- MCP server -- query captured traffic from any agent (the agent skill already ships; the MCP surface is the remaining half).
- Tunnel PID attribution -- which subprocess called npm (Linux, investigated, deferred).
bun test # unit tests
bun run tests/e2e-live.ts mitm "hi" # end-to-end against real ClaudeSee CONTRIBUTING.md.
