traceroutine
Process mining for LLM agent traces — where the tokens and the time actually go.
Observability platforms attribute spend by who: per user, per team, per API key.
traceroutine attributes it by how — per execution path.
An agent's cost is a property of its trajectory, not of its request.
One command, zero instrumentation
If you use Claude Code, the data is already on your disk. No exporter, no collector, no account, no arguments:
$ uvx traceroutine
reading ~/.claude/projects as claude-code — nothing leaves this machine
483 cases · 335 paths · $849.06 at list prices · rework 89.2% -> report.html
1. Results of `tool:Bash` carry 12% of the budget through context (up to $105.23)
2. Loop `chat → tool:Edit` runs an extra time (up to $51.33)
3. Working rhythm `chat → tool:Bash` — 41% of the budget
Three seconds, and that is my own history. The first finding is the whole thesis:
Results of
tool:Bashcarry 12% of the budget through context. The step itself burns no tokens and shows as $0.00 in every cost breakdown. But each of its results adds ~1,391 tokens to the prompt, and those are re-read on every subsequent turn: 129M tokens carried in total. Fix by truncating output, not by switching models.
A tool call costs nothing when it happens and keeps costing for the rest of the run. That is why the unit of cost is the path, not the request.
Context re-reading is a known phenomenon — vendors document it. What is missing everywhere else is the attribution: not "context grows", but which step's results carried how many dollars across the rest of the trajectory.
The dollars are API list prices, not an invoice. I pay a $20 subscription, so this is what those tokens would have cost — which is its own small finding: a flat fee hides a month that prices out at $849. Cross-checked against ccusage on the same instant: the two agree to 0.05% on the total and to within 0.25% on every token category.
The shape of the work
A usage dashboard gives you a number. This gives you the shape it came from — the same
run as above, rendered by GitHub straight out of report -f md, no image involved:
flowchart TD
S(["▶ start"])
n0["chat<br/>7,096× · $849.06"]
n1["tool:Bash<br/>4,422×"]
n2["tool:Edit<br/>1,060×"]
n3["tool:Read<br/>617×"]
n4["tool:Write<br/>392×"]
E(["■ end"])
n0 -->|4257| n1
n1 -->|4237| n0
n0 -->|1049| n2
n2 -->|1049| n0
n0 -->|603| n3
n3 -->|596| n0
S -->|483| n0
n0 -->|440| E
n0 -->|390| n4
n4 -->|388| n0
n1 -->|143| n1
classDef hot fill:#b4322e,stroke:#7d1f1c,color:#fff
classDef err stroke:#d97706,stroke-width:3px
class n0 hot
class n1,n2,n3,n4 err
Everything returns to chat, because that is what a coding agent is: 4,257 calls out to
tool:Bash and 4,237 back. That traffic is the 41% of the budget in finding 3 — not an
anomaly but the working rhythm, and it only reads as a rhythm once it is drawn.
tool:Bash also follows itself 143 times: commands issued back to back with no model
turn in between. Amber outlines mark activities that produced errors.
Steps shown without a dollar figure spend no tokens at the moment of the call. That is not the same as free — their results stay in the prompt and are re-read on every later turn, which is finding 1 above.
That graph is the transitions. The picture at the top of this page is the trajectories: runs merged by their common start, each block as wide as the share of the bill that went down that branch. It is a flame graph with the stack replaced by the run, and it is there because a list of paths stops working on long runs — past step 16 in that log, most runs are already on a path no other run takes. Prefixes still agree long after whole paths have stopped.
Does it read my code?
A fair question: you are pointing a tool at your entire working history.
Nothing leaves your machine. The command above makes no network calls at all. There is no telemetry, no config in your home directory, no account.
What the event log holds: activity names (tool:Bash, chat), timestamps, token
counters, cost, opaque IDs, and the basename of the project directory. No message
text, no tool arguments, no file paths, no commands. That is enforced in the adapter
rather than in the report — because reports get shared — and it is tested:
test_no_message_content_leaks_into_spans, test_project_name_is_basename_only.
One command can talk to a cloud, and only if you ask it to. traceroutine abstract --backend anthropic sends the list of distinct activity names — a few dozen short
strings — to group them semantically. Nothing else: no events, no counters, no content.
The default path above never runs it. To see that list before trusting anyone with it,
look at the mapping: keys in activity_map.yaml; they are exactly what would be sent.
--backend ollama keeps the step on your own machine.
Install
uvx traceroutine # no install
pip install traceroutine # or into your environment
When there is more to ask
The one-shot is ingest → abstract → report with sensible defaults. Each is also a
command, for when the defaults are not what you want:
ingest <src> |
traces → a canonical event log (parquet) |
abstract <log> |
raw span labels → activity_map.yaml, a semantic vocabulary |
report <log> |
findings + process graph: -f html or -f md |
check <log> |
conformance against a declared process.yaml; exit codes for CI |
diff <a> <b> |
compare two logs: a prompt release, a model swap, two cohorts |
- The guide — sources, the case notion that decides everything, the abstraction layer, what gets computed, architecture.
- Conformance — declaring how the agent is supposed to work, and failing CI when it stops doing that. This is the part no dashboard does.
Reading a log other than Claude Code's: traceroutine --from <file-or-directory>.
OpenTelemetry JSON and OpenAI-style chat transcripts are detected automatically.
When this will not help you
Stated up front, because a tool that always returns five findings eventually returns five invented ones.
Variant analysis has a measured limit. Path uniqueness climbs from 17% at 1–3 steps
to 100% at 26+. Above roughly 13 steps trajectories stop repeating, and "rare paths eat
the budget" becomes the tautology "expensive runs are expensive". So the variant lens
fits short structured agents — RAG, support, routing — and not long ones. When repeated
paths drop below 50%, traceroutine says so and suppresses those findings instead of
dressing up a tautology.
What still works on long runs: context inflation, cohort diff, and conformance — all
three get stronger with trace length rather than degenerating.
Status
Alpha, and honest about it: it runs end to end on three sources, its cost accounting agrees with an independently written tool to within 0.1%, and it has 153 tests. The interactive graph renderer is not built yet.
License
Apache-2.0
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file traceroutine-0.4.0.tar.gz.
File metadata
- Download URL: traceroutine-0.4.0.tar.gz
- Upload date:
- Size: 297.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
abddeb8c9e5053082cbef47dd2528fc46df6ecd3e378051fef17e00a97be90c0
|
|
| MD5 |
a7289b30a7bee75c25ce2db67013515b
|
|
| BLAKE2b-256 |
c65af72e6ef07b69ab8d577880c30ce4ea999a2788ee61dbbac1270f5862c30c
|
File details
Details for the file traceroutine-0.4.0-py3-none-any.whl.
File metadata
- Download URL: traceroutine-0.4.0-py3-none-any.whl
- Upload date:
- Size: 93.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
907d1c3ecac6ce1baac3e9deb5fccde2a713bb5516bd2fd29ed49e54dce641f9
|
|
| MD5 |
8e473990b6e583551591055f22db9e65
|
|
| BLAKE2b-256 |
bab2e7c02259952fcb550f13ac1a4e5eeac3d2aeead92b4a558c051c9c735139
|