Why local-first
Traces are one of the files that make the runtime inspectable, and one of the reasons the state directory is sensitive.
A trace is the full record of what a session actually did: every turn, every step, the prompt that went to the model, the completion that came back, and each tool call with its arguments and result. One append-only NDJSON file per session, on your disk, readable in any text editor.
Traces answer the questions logs cannot. Why did the agent pick that tool? What exactly was in the prompt when it went wrong? And β via replay β has anything changed underneath a session since it ran?
The interactive entry points all record. run, tui, and serve boot the runtime with traceDefault: true, so a fresh install traces every session you drive by hand.
Two things do not trace by default:
task command boots with traceDefault: false. Turns executed by the task runner are not recorded unless you opt in explicitly.The config key is tri-state, which is what makes that split work:
{ "tracing": { "trace": { "enabled": null, "maxBytesPerSession": 10485760 } }}tracing.trace.enabled | Meaning |
|---|---|
null (default) | Defer to the entry point. run / tui / serve trace; task drains and the sidecar do not. |
true | Always trace, whatever the entry point. This is how you record background task runs. |
false | Never trace, including interactive sessions. |
An explicit true or false always wins over the entry-point default.
maxBytesPerSession (default 10 MB) is a hard cap on one sessionβs file. Once a trace hits it, writes stop β the file does not rotate and the session keeps running untraced.
<stateDir>/traces/<sessionId>.ndjsonWith the default state directory that is ~/.atomic-agent/traces/. Override the root with ATOMIC_AGENT_STATE_DIR.
atomic-agent trace list [--limit N]atomic-agent trace show <sessionId> [--step N] [--raw]atomic-agent trace export <sessionId> [--format ndjson|json]atomic-agent trace replay <sessionId>Summarise the most recent trace files in the traces directory.
atomic-agent trace list --limit 20Pretty-print one session as a human-readable chronology.
atomic-agent trace show s-1234atomic-agent trace show s-1234 --step 2atomic-agent trace show s-1234 --raw--step N isolates a single step. --raw prints the unformatted lines instead of the formatted chronology. A session id with no trace file on disk exits 1.
Dump the raw trace for processing elsewhere.
atomic-agent trace export s-1234 # ndjson (default)atomic-agent trace export s-1234 --format json > session.json--format accepts ndjson (the default) or json. Anything else exits 1. NDJSON streams the file as-is, one event per line β good for jq and grep. JSON wraps the events into a single array, easier to load whole.
Rebuild the stable prompt prefix with the current tools, skills, and capabilities, then compare its hash against what the trace recorded.
atomic-agent trace replay s-1234Output lists each turn and step with its recorded hash, the current hash, and whether they diverge:
turn step drift recordedHash currentHashreplay does not re-run the agent. It answers a narrower and more useful question: would this session get the same prompt prefix today?
The stable prefix is the byte-identical head of every prompt β persona, tool catalog, skill index, capabilities. Replay reconstructs it from the current runtime and compares hashes with the ones the trace recorded. A mismatch means something underneath the session changed: a tool was added or removed, a skill was installed or disabled, or capabilities shifted.
The exit code is the part to script against:
| Exit code | Meaning |
|---|---|
0 | No drift. The current runtime reproduces the recorded prefix. |
2 | Drift detected on at least one step. |
1 | The command failed β no such session, unreadable file, bad arguments. |
atomic-agent trace replay s-1234 || echo "prefix changed since this session ran"The file is NDJSON, so the usual tools work:
# Every tool call in a sessionjq -c 'select(.type == "tool_call")' ~/.atomic-agent/traces/s-1234.ndjson
# Follow a live sessiontail -f ~/.atomic-agent/traces/s-1234.ndjsonIf you would rather record nothing:
{ "tracing": { "trace": { "enabled": false } }}That covers every entry point, interactive ones included. Existing files stay on disk β delete <stateDir>/traces/ yourself if you want them gone.
Why local-first
Traces are one of the files that make the runtime inspectable, and one of the reasons the state directory is sensitive.
Approval gates
What stopped for approval during a turn, and why it is in the trace.
CLI Reference
Every command and flag, trace included.
Troubleshooting
Using a trace to work out why a turn went the way it did.