Toolog keeps a forensic log of Claude Code tool calls

In the owner’s own database, 77% of recorded calls were Bash commands that none of Toolog’s twelve risk rules had ever matched. That figure comes from the README of Toolog, a macOS audit trail for Claude Code tool calls that zaghaghi posted to Show HN on September 6. A rule engine shows those calls as nothing, which, the author writes, “reads as these are fine and means these were not examined.”
That gap is why Toolog ships an optional local model as a second opinion. Most of the rest of the project’s README on GitHub deals with other numbers: what each capture path misses, how big the model is next to the data it reads, and how a CI build checks that the app makes no network calls. Every shell command, file edit and network fetch Claude Code runs goes into a SQLite file on the machine. Three views sit on top of it: a forensic timeline, a permission and risk review, and the state of capture itself.
Why two lanes
Claude Code leaves two partial records of what it did. Transcripts under ~/.claude/projects/**/*.jsonl hold the untruncated content: the full shell command and the full file diff. The OpenTelemetry export truncates tool inputs at 512 characters, “which is not evidence,” the README says. But OTEL carries what transcripts never record: who approved or refused each call, under which rule, and how long it took.
The OTEL side is standard Claude Code. The CLI has OpenTelemetry built in and emits a structured log event for each tool result, plus counters for tool decisions, per Anthropic’s documentation. That telemetry stays off until CLAUDE_CODE_ENABLE_TELEMETRY=1 is set and an exporter is chosen. Wiring this up is the job of toolog doctor --fix.
Toolog runs as a single process. An OTLP receiver accepts POST /v1/logs on 127.0.0.1:47318, an fsevents tailer follows the transcript files, and a normalizer joins the two streams into SQLite, running in WAL mode with FTS5 (SQLite’s full-text search extension). A WebView window shows the result. The two records are joined exactly on tool_use_id, and a mismatch counts as a finding. A call that only the transcript saw is a gap in collection. A call that only OTEL saw had no transcript body written. toolog verify reports both, along with refusals and completeness. That, the author argues, is how the tool shows its own completeness instead of just claiming it.
Neither lane sits on Claude Code’s critical path. One is a read-only file watch. The other is a fire-and-forget export, and if it fails, nothing breaks.
The split has a price. Approval decisions and latency exist only for sessions captured live, because the OTEL stream can’t be replayed. toolog backfill imports your existing history from the transcripts, so older sessions keep their commands and results, but they will never have a decision layer. toolog verify lists exactly which sessions those are, rather than averaging across the gap. The same applies after quitting from the menu bar, which stops capture on purpose: a later backfill recovers what ran in the meantime, minus the decisions.
A 3.1 GB second opinion
The timeline lists every call newest first under one query box, with two separate columns: the severity a rule gave the call, and the score a local model gave the calls no rule matched. The risk review lists the rules worst first and shows what each one looks for, whether it matched or not. Filters use a short syntax: @risk:high shows what a rule flagged, with the rule’s name on hover, and @model-risk:>=4 shows calls the model scored 4 or 5, each with its one-line reading on hover. The home directory is blurred.
The model is a 4.6B quantized .gguf weighing 3.1 GB, against a 166 MB store, so the second opinion is almost nineteen times the size of the data it reviews. Toolog links llama.cpp and doesn’t download anything: you fetch the file yourself and run toolog model set PATH, and the docs give the one command that fetches it. toolog model status shows how far the review has got.
The author’s own measurements on that store show where it falls short. The model scored a benign cargo test at 2, and it needed its rubric spelled out before it called a raw-device dd dangerous, a command that a blocking hook like the Field Kit’s Bash guard stops before it runs. Toolog only records after the fact. Those results already argue for how the model is fenced off: it is never a rule, never a severity and never a number in the summary, and it gets its own column, its own section and its own block in the detail pane. The README makes the point directly: “a rule’s severity is deterministic, a model’s score is not.” The author adds that the one-line intent summary may be the half worth keeping even where the score is not.
Checking the privacy claim
The receiver binds to loopback only. The app has no analytics, crash reporting, remote config, account or update check. A CI test runs a full ingest and every query the window issues, then asks the operating system which sockets the process holds, and any address that isn’t loopback fails the build. A second test checks that the first one works: it opens a socket pointed off the machine and asserts that the socket check sees it. “The guarantee is a build failure when broken, not a promise in a readme,” the author writes.
The model got the same treatment. llama.cpp has its own --hf-repo fetcher, which a check that reads Cargo.toml can’t see. So each release also runs otool -L on the shipped binary and asserts that it lists no libcurl and no TLS library. “A config option is not a guarantee; the binary is.”
The cost of making no network calls is that nothing tells a direct .dmg user when a new version is out. For Homebrew installs, brew upgrade --cask toolog is the update path.
Install, and undoing it
Install with brew install --cask zaghaghi/tap/toolog, or download the .dmg from Releases. It is a universal build, signed with a Developer ID and notarized by Apple, and you can check it with shasum -a 256 -c SHA256SUMS and spctl --assess. The same binary is both the menu-bar app and the CLI. toolog doctor --fix writes only to ~/.claude/settings.json, merges instead of overwriting, and keeps a timestamped backup. It refuses outright if a non-loopback OTEL endpoint is already configured: “your existing telemetry pipeline is not ours to redirect.” After that come toolog backfill and toolog itself. toolog agent install adds a login agent so capture survives a restart.
toolog uninstall first shows what it would change, then --apply removes the login agent and restores settings.json byte for byte from the backup. If you have edited that file since, it removes only Toolog’s own six keys and says why it didn’t restore. Recorded history stays unless you pass --delete-data, or --zap with brew uninstall.
Some limits are listed up front. Toolog needs macOS 11 or later and runs only on macOS. Only the LaunchAgent is Mac-specific, and a Linux port would need a systemd user unit for both install and uninstall. Cost data from api_request records is stored and counted but never shown, which ADR-0010 records as a scope decision. Project attribution comes from cwd in the records, because Claude Code encodes / as - in directory names: /a/b/my-app and /a/b/my/app end up as the same name.
The database is a plain SQLite file, on purpose, so anyone who can read your disk can read it. That is also what lets you check the claims in PRIVACY.md without trusting the program. The author considered encryption at rest and left it to FileVault.
Up next
Claude Fable 5.1’s “Never” rules pulled into one document
@vivek pulled every “Never do this” line out of what’s presented as the Claude Fable 5.1 system prompt into a single file of 2,196 lines and 40,046 words, which Anthropic hasn’t confirmed.
Related stories
- claude-sniff pauses Claude Code’s Bedrock invokes
- Gage scans Claude Code sessions for bugs the diff hides
- Function Hooks would wrap Claude Code like middleware
- lcc cut one Claude Code session 49.5% without a summary
- catnap keeps Claude Code from compacting mid-task
- Script checks whether your network breaks Claude API uploads
Comments
No comments yet. Be the first.
Join the conversation
Sign in to leave a comment. It appears after moderation.

