# claude-code-trace shows the redacted payload before it sends anything to an analyzer

> A Rust and React viewer for the JSONL session files Claude Code leaves in your home directory, with three front ends, live tailing, and an optional external analysis step that requires you to look at the exact redacted request and confirm before it is sent.

**delexw/claude-code-trace** — Claude Code session log viewer for JSONL files in ~/.claude/projects. Browse conversations, tool calls, tokens, and live tail sessions on desktop, web, and TUI.

- Repository: https://github.com/delexw/claude-code-trace
- Stars: 373 · Forks: 23
- Language: Rust
- License: MIT
- Published: 2026-09-15 · Updated: 2026-09-15 · Language: en
- Canonical page: https://hysenlabs.com/projects/delexw-claude-code-trace

## The redacted payload is shown and confirmed before anything is sent

The tool's headline feature is an optional external analysis step, and the interesting part is not the analysis but what surrounds it.

The trace is turned into a privacy reviewed, redacted analysis request, and the redacted payload is displayed with confirmation required before sending. That is the whole privacy story in one line, and it is a stronger design than the usual arrangement where a tool redacts and sends in one step.

Showing the payload is the part that matters. A redaction scheme you cannot inspect is a promise, and you have no way to know whether the thing that looks like a session id is actually an email address until you read the request.

The analysis itself scores six things: agent progress, tool use, focus, exploration, recovery and token efficiency. The stated purpose of the resulting dashboard is to help identify repeated work, thrashing, excessive exploration, failed retries, effective recovery, useful subagent work and inefficient token usage.

One boundary is drawn explicitly in the feature list: token efficiency analysis considers totals, context growth, turns, repeated work and tool activity, and does not evaluate monetary cost. So the tool tells you an agent used a lot of tokens, and stops there rather than converting that into a number you might act on wrongly.

## The macOS build is unsigned on purpose, which is why there is no dmg

The install section explains its own oddities, which is rarer than it should be.

macOS gets a one line install that pipes a script into a shell, and the tip block promises no clone, no build tools and no quarantine clearing. ```bash
curl -fsSL https://raw.githubusercontent.com/delexw/claude-code-trace/main/script/install-macos.sh | bash
```

The script downloads the latest release and installs the application bundle into the Applications folder, ready to open from Spotlight.

Then the reason, which is the interesting sentence. macOS blocks unsigned apps that were flagged as downloaded, and `curl` never sets that flag, so the app just opens. That is why macOS releases ship a tarball and no disk image. Apple silicon only.

The reasoning is a genuine trade rather than a workaround. A disk image is a download, so anything the browser fetches gets quarantined and refuses to open until the user clears the flag by hand. A script that fetches over the terminal does not, so the user never meets that wall. The cost is that the install path is a shell pipe, which is its own kind of thing to ask a user to run.

Version pinning and a different install directory are both available through the same script, and the release channel exists because there is a real upgrade path to control.

## Three front ends from one codebase, including a Python terminal UI

The repository layout explains the three interfaces better than a feature list would.

The desktop application is built with the Tauri v2 framework in Rust, with a React frontend. The web application is the same thing served as a static bundle. And the terminal interface is not part of that stack at all: it lives in its own directory as a Python program with its own requirements file, and the manifest has a script that starts the desktop app in headless mode, installs the terminal interface's dependencies, waits for the backend to be available with a small Node helper, and then launches the Python program.

That script is worth reading because it encodes an architectural assumption. The terminal interface is a client of the same backend the desktop application uses, not a reimplementation. Which means the wait helper exists, and which means a terminal session and a desktop session share one engine.

The description also frames the tool in a specific way: a session log viewer and an agent efficiency analyzer for local files, not an observability platform. The stated difference from general observability tooling is that it does not require sending traces to an external service, which is true of the default path and worth remembering when you enable the part that does.

## The container mounts your session logs read only, and says why

The compose file is small and its comments are the substance.

Claude Code writes sessions to a directory in the user's home folder, and that host directory is mounted read only into the container, with a comment stating that the app never needs to write there. Read only is the right mount for a directory of logs you would not want modified accidentally, and it also means a bug in the viewer cannot damage the source data.

The environment sets the bind host and port explicitly, and defaults them to all interfaces on port 1421 in the image, with a comment telling you to override them if you change the container side port. That default is the one thing to check before running this on a shared host, since binding to all interfaces on a machine with port forwarding exposes your traces.

Secrets are handled through Docker managed secret storage, mounted read only at runtime, and the environment variable names a file path rather than containing the key. The comment on that line is the important part: the entrypoint reads it server side and the browser never receives the key.

Two volumes exist for configuration and for secrets, and the configuration volume has a comment explaining a specific failure: without it the settings file only lives in the container's writable layer and resets to empty on every recreate.

## A display is required in the container because the Linux webview links one

The image header explains an arrangement that looks unnecessary until you read the reason.

The backend runs in headless mode behind a virtual X display. The reason given is that the Tauri v2 webview runtime on Linux links against a desktop webkit library and needs a display even when no window is shown.

So the container carries an X virtual framebuffer for a graphical runtime that renders nothing. That is the cost of reusing the desktop application's backend for a server deployment rather than writing a headless one.

The frontend is built to a static bundle and served from the same backend process as an API fallback, so the entire application is reachable on a single port. That single port design is what makes the compose file two services rather than a frontend container and a backend container, and it means the port comment in the compose file is the only networking knob there is.

The build is a multi stage one. The frontend stage installs from the lock file with audit and fund lookups disabled, then copies the source, the shared contracts and the two configuration files. The comment on those copies explains a real constraint: the bundler configuration imports a token helper module at configuration load time, so the copy order has to satisfy it.

## The check script chains eight verifications into one command

The manifest has a single verification script and it is worth reading as a statement of what the project considers done.

It type checks the frontend and the node side configuration separately, both with no emit. Then it runs the JavaScript and Rust linters. Then both formatters in check mode. Then the Rust unit tests. Then the frontend tests.

Two details in that chain are deliberate. Linting and formatting both run for both languages, so a Rust and a TypeScript change are held to the same standard in one command. And the Rust formatter and the JavaScript formatter are each invoked in check mode, so a formatting diff fails rather than being written.

The individual scripts are there for iteration as well. There is a watch mode for the frontend tests, a separate end to end suite driven by a browser automation runner with its own configuration file, and a script that runs only the formatter.

The dependency list explains what the frontend actually does. Beyond the desktop framework bindings there is a charting library with a React wrapper for the efficiency dashboard, two markdown renderers including one that renders to terminal text, a syntax highlighter, a virtualised list for the conversation view, and GitHub flavoured markdown support.

## A versioned cache marks results stale when the trace or the formula changes

One feature line in the list describes a small correctness problem being solved carefully: versioned local results.

The cache keeps one latest result per session, and it marks the result stale when either the trace changes or the analysis formula changes.

That second condition is the interesting one. A cached analysis is a function of two inputs, and the naive implementation only checks the first. If the scoring logic changes in an update and the trace does not, a naive cache serves a score computed by code that no longer exists, with no indication that anything is wrong.

Tying staleness to the analysis formula means an upgrade that changes the scoring invalidates cached results automatically. For a tool whose output is a judgement about your own workflow, serving a stale judgement silently would be worse than recomputing.

Related to this is the secure token storage, which is named per platform rather than generically: the macOS Keychain, Windows Credential Manager, and the Linux Secret Service. Three platform APIs rather than a file with keys in it, which is the difference between a credential being protected by the operating system and a credential being protected by file permissions.

## Token counts are shown where available, which is a hedge about the data

The token feature is worded carefully and the wording is informative.

Token visibility shows token counts where available in the session data.

Where available is doing real work in that sentence. It means the viewer does not compute token counts, and it means some entries in a session file carry usage information while others do not. A tool that claimed to show token counts everywhere would be either estimating or filling in gaps.

The same restraint shows up in the MCP feature. The tool detects Model Context Protocol calls and displays human friendly names, so instead of a raw tool identifier you get something that says what was called.

The core viewer features are the ones you would expect from a log reader that is trying to be readable: the JSONL files become scrollable conversations, sessions can be found by user message, tool calls expand for detailed inspection, and live tailing monitors active sessions in real time.

The stated motivation is worth repeating because it is narrow. Those files are useful for debugging and reviewing, and difficult to read directly. This exists to remove the second problem without introducing an external service, which is also why the sibling project for the other agent's logs is a separate repository rather than a plugin here.

## Conclusion

Use claude-code-trace if you have accumulated Claude Code session logs and want to read them as conversations rather than JSONL, especially if you are debugging a workflow that kept looping. The live tail and the MCP tool detection are what make it more than a file reader. Do not turn on the external analysis step without reading the payload preview first, because that is the only part of the tool that leaves your machine. Four things to check before you install. That you are on Apple silicon if you are on macOS, since that is the only macOS build and it is unsigned. Whether you want a desktop app, a web app or a terminal interface, since all three ship from the same code. Where the settings file lives if you use the container, since it is on a volume precisely so it does not reset when the container is recreated. And whether your traces are readable by another person, because the viewer shows what was sent and received including tool arguments. Licence is MIT, there are GitHub releases, and the last push to main is dated 1 October 2026.

## FAQ

### What is delexw/claude-code-trace?

It is a Claude Code session log viewer for the JSONL files stored in ~/.claude/projects/. It renders those logs as readable conversations, lets you find sessions by user message, expand tool calls, detect MCP tool calls, shows token counts where available, and can tail a session live while it is running.

### Does claude-code-trace send my traces to an external service?

Not by default. The stated difference from general observability platforms is that it does not require sending traces anywhere. The optional analysis step does send a redacted request, and the tool shows the exact redacted payload and requires confirmation before it goes out.

### How do I install claude-code-trace on macOS?

With a one line install that pipes a script into your shell, no clone and no build tools, which downloads the latest release and installs the app bundle into Applications. The app is unsigned, and releases ship a tarball rather than a disk image so that a terminal download never gets the quarantine flag that makes a browser download refuse to open. Apple silicon only.

### Can I run claude-code-trace in a container?

Yes. The compose file mounts your host session directory read only, since the app never writes there, binds a single configurable port, and reads the analysis key from a Docker managed secret mounted read only so the browser never receives it. A configuration volume keeps your settings from resetting every time the container is recreated.

### Where does claude-code-trace store API tokens?

In the operating system's credential store rather than a file: the macOS Keychain, Windows Credential Manager, or the Linux Secret Service. Analysis results are cached one latest result per session and marked stale when either the trace or the analysis formula changes.

## Sources

- [delexw/claude-code-trace on GitHub](https://github.com/delexw/claude-code-trace)
- [Issues](https://github.com/delexw/claude-code-trace/issues)
- [License: MIT](https://github.com/delexw/claude-code-trace/blob/main/LICENSE)
- [README](https://github.com/delexw/claude-code-trace/blob/main/README.md)
- [Releases](https://github.com/delexw/claude-code-trace/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/delexw-claude-code-trace
