████████╗██████╗ █████╗ ██████╗ ██████╗███████╗
╚══██╔══╝██╔══██╗██╔══██╗██╔════╝██╔════╝██╔════╝
██║ ██████╔╝███████║██║ ██║ █████╗
██║ ██╔══██╗██╔══██║██║ ██║ ██╔══╝
██║ ██║ ██║██║ ██║╚██████╗╚██████╗███████╗
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚══════╝
A macOS kernel-event tracer for Claude Code sessions — every process, file, and network connection, live in your terminal or replayed later.
⚠ on sensitive paths (.env, ~/.ssh, *.pem, …)tracce view it latereslogger runs as root, with a hardcoded argument list; tracce itself never does[!NOTE] Personal/audit tool, macOS only. Your terminal app needs Full Disk Access. tracce runs as you and uses
sudoonly to launcheslogger(the default event source). Decline the prompt and it degrades to poll-only — no file events.
brew install chungchihhan/tap/tracce
# Terminal A — start a Claude Code session, traced
tracce claude
# Terminal B — watch it live (and replay anytime later)
tracce view
Homebrew (recommended)
brew install chungchihhan/tap/tracce
Builds from source via the tap, so it works on Apple Silicon and Intel with no
code-signing prompts. Homebrew pulls in the Rust toolchain automatically; you
just need the Xcode Command Line Tools. Upgrade with brew upgrade tracce.
cargo (needs Rust)
cargo install --git https://github.com/chungchihhan/tracce
From source
git clone https://github.com/chungchihhan/tracce
cd tracce
cargo build --release
sudo cp target/release/tracce /usr/local/bin/
The dashboard always runs in a second terminal — Claude Code is itself a TUI and can't share one. There are two ways to get there.
Launch claude under tracce, watch with view (recommended):
# Terminal A — start a traced Claude Code session (claude owns this terminal)
tracce claude
tracce claude --print "explain this repo"
# Terminal B — follow it live (auto-picks the live session)
tracce view
Attach to a claude that's already running:
# Terminal B — sudo prompts once to start eslogger. With no pid, tracce finds
# the running claude (or lets you pick if several are running).
tracce attach
tracce attach <pid>
Replay & inspect recordings — every run is saved, so view works after the fact too:
tracce view # follows the live session, else opens the picker
tracce view --latest
tracce view <session-id-prefix>
tracce list # sessions as a text table
tracce exec -- npm test # testing hatch: trace any command
If a trace crashes and leaves files in an odd state, run tracce fix-perms.
attach and view render a live grid of panels:
| Pane | Key | Shows |
|---|---|---|
| PROCESS TREE | 1 |
the descendant process tree by pid, with each command name and its event count |
| ACTIVITY | 2 |
recent file ops (R read · W write · C create · X close · D delete · M move · E edit · A multi-edit · $ bash), ⚠ sensitive · (burst) coalesced |
| COMMANDS | 3 |
exec'd command lines (full argv) |
| NETWORK | 4 |
remote hosts and connection counts |
| EVENTS/s | 5 |
full-width bar graph of the events-per-second rate, with a labeled Y-axis (0 → peak) and an X-axis time scale (−Ns … now) |
By default nothing is focused and every pane follows the latest events. Tab cycles
focus through the panes and back to that follow-all state. In a focused row pane, the
arrows (or j/k) move a highlighted selection and Enter opens a detail view (full
path / argv / host, untruncated, plus when it happened). On the focused EVENTS/s graph,
Left/Right scrub a cyan cursor along time and Up/Down zoom the time axis
(1 → 2 → 5 → 10 → 30 → 60 seconds per bar).
| Key | Action |
|---|---|
Tab / Shift-Tab |
cycle focus (incl. follow-all) |
1–5 |
show / hide panels |
↑ ↓ or j k |
move selection |
← → (graph) |
scrub the time cursor |
↑ ↓ (graph) |
zoom the time axis |
Enter |
open row detail |
/ |
filter the focused pane |
f / g / G |
follow latest / jump top / oldest |
p |
pause |
h or ? |
help |
q / Esc |
quit · Ctrl-C quits immediately |
/usr/bin/eslogger (macOS Endpoint Security), on by defaultlsof -i polled every 500 ms.env, ~/.aws, ~/.ssh, *.pem, etc.) get a ⚠ glyphtracce asks for sudo on start, which is a fair thing to be cautious about —
especially for a tool whose whole job is auditing what software does. Here's
exactly what that privilege buys and where it stops:
/usr/bin/eslogger, Apple's own signed
binary, with a fixed argument list:sudo /usr/bin/eslogger exec fork exit open close create write unlink rename
Those are the kernel event types it subscribes to. macOS Endpoint Security is a privileged API, so reading these events requires root — there's no unprivileged path to them.
tracce itself never runs as root. Your tracce process stays as you; it
just reads the event stream that the root eslogger child writes to a pipe.
No user input reaches the privileged command. The argument list is hardcoded, the paths are absolute, and there's no shell — nothing you type (PIDs, paths, anything) is ever interpolated into the command run as root.
No standing privilege. eslogger is a transient child, killed when the
trace ends. tracce installs no daemon, no setuid binary, and makes no changes
to your sudoers — every trace prompts (or reuses your normal sudo cache).
Read-only by design. eslogger observes; it cannot block or modify anything. tracce is not a sandbox (see below).
Auditable. It's open source, and the entire sudo invocation lives in one
function — bring_up_eslogger in src/trace/run.rs. Read it.
You can decline. Say no to the prompt and tracce degrades to poll-only (process tree + network + claude tool calls), with no file events.
attach captures from the attach moment forward — it can't replay what claude did before you attachedMIT © Chih-han Chung
$ claude mcp add tracce \
-- python -m otcore.mcp_server <graph>