01 — transcript-audit

I had six months of AI coding sessions on disk and no idea what was in them.

Every session you run with Claude Code or Codex writes a transcript to your machine. Mine came to 2,105 files and 2.2 GB. That is the most accurate record that exists of how I actually work: what I ask for, how I phrase it, where I lose hours, which corrections I have typed forty times without ever writing down as a rule.

It is also completely unreadable. Too big for me to sit and read, and far too big to paste into a model. So it sits there, accumulating, being the answer to a question nobody can ask.

transcript-audit is the thing I built to ask it. It points an agent at all of it and hands back a report where every finding carries a receipt from my own history, and every fix has an approve button. It is open source, MIT, and it runs entirely on your machine.

The whole thing is one Python file with no dependencies and a skill that drives it. Nothing leaves your computer.

02 — The one design decision

Arithmetic on one side, judgement on the other.

Everything else in this project follows from a single line drawn down the middle of it.

Anything countable, groupable, sortable or extractable happens in Python, deterministically, with no model involved. Anything requiring taste happens in a model, reading only small shaped windows that the Python produced. If I am adding something, the first question is which side of the line it goes on.

That is not a performance optimisation. It is the thing that makes the output specific instead of generic. A model that has read a fair sample of six months says different things than one that has read last Tuesday, and a model that never sees raw transcript text cannot quietly start pattern-matching on the last thing it read.

There is a hard rule attached: no transcript text ever enters a model's context except through a bounded read. Not rarely. Never. The moment you let an agent cat a transcript "just to see", every judgement it makes afterwards is polluted by material it did not choose, and you have rebuilt the problem you were trying to solve.

03 — The deterministic layer

One file, 2,100 lines, standard library only.

The install is a copy. There is no pip, no package, no virtualenv, no network call anywhere in it. That is deliberate: this thing reads your entire private working history, so you should be able to audit the one file that touches it before you run it. A dependency tree makes that impossible in practice.

It reads both Claude Code (~/.claude) and Codex (~/.codex) history, normalises both onto one small dict, and makes a single streaming pass over the corpus. The last time I ran it that was 2,105 files and 2.2 GB in 77 seconds, timed by the tool itself. It writes ten JSONL slices to disk, each one a different question about the same history:

promptsevery instruction you typed, in order
correctionswhere you redirected the agent, what it had just done, and which kind of thinking you were pulling back
interruptswhere you cut it off, and what was running
commandsevery shell command, normalised to its shape
tool_errorswhat failed, with the target
dispatchesthe subagent packets you sent
invocationsskills and slash commands, when, where
reworkfiles edited repeatedly inside one session
sessionsone row each: shape, cost, duration, strain
praisethe approvals. The weakest slice, and I say so in the docs

Then there are the aggregates, which are free and where most of the real findings actually come from. Cost by month, tools by error rate, the hours you work, what every session pays to start before you type a word, and the command shapes you have retyped by hand. On my corpus the arithmetic alone found that I had typed PYTHONPATH=subsystems in front of commands 1,010 times because one repo had no packaging file, and rebuilt the same eleven-line remote environment preamble across 1,240 ssh calls.

Neither of those needed a language model to notice. They needed someone to run the counts and look.

One of the aggregates is about the other side of the conversation. Every correction gets classed by what was being steered against, sorted into the aim (it did more than I asked, or solved a different problem), the approach (it treated a symptom, or produced an artifact before it understood the thing), the grounding (it assumed instead of reading, or claimed done with nothing checkable attached), and the conduct (it narrated instead of working, or lost something we had already settled). The number worth reading is not how often a class fires. It is how many separate projects it spans, because one project is a bad week and six is a rule I never wrote down. Of 190 corrections in my history 43 carried a class at all, which is 23%, and the table prints that share before it prints anything else.

$ transcript-audit scan
  scanned 2105 files (2209 MB) in 77s

$ transcript-audit stats --what shape
bucket                 sessions   share  human turns    tools
-------------------------------------------------------------
did work (>=5 tools)       1239   59.4%         4798    69924
thin (1-4 tools)            131    6.3%          157      329
no tool calls at all        715   34.3%          730        0

! 715 session records made zero tool calls (34% of the corpus).
  Heaviest day: 2026-07-20 (343).
  They are in every per-session denominator unless you exclude them.

That last warning exists because it caught me. A third of what called itself a session in my corpus did no work at all, and one of my findings inverted completely once I filtered them out.

04 — The nine seats

Nine ways of being interested in the same history.

Once the Python has done the counting, the skill seats a set of independent subagents on different corners of the evidence. Each one is a person with an appetite, not a checklist. That distinction matters more than it sounds: a seat that wants something finds things that look bright to it and goes past everything else, and two seats reading the same slice come back with genuinely different findings.

So I do not tell a seat what to find. It gets the appetite, the material, and the shape of the return. The ideas are its own. If I specify the conclusions I have written a search query with extra steps, and I will get back exactly what I already believed, dressed up as discovery.

The economist Where the time and the tokens went, and what came back for them. Has seen a lot of expensive sessions and has stopped being impressed by activity. Allergic to averages that hide the tail.
The instruction reader Reads my prompts the way an editor reads a draft: not for what I meant, but for what was on the page and what a stranger would have built from it. Hunting for the correction I have typed more than once.
The cartographer of friction Finds repetition physically uncomfortable. Thinks in terms of what a machine should have been doing while a human did it by hand. Refuses to automate anything that ran twice.
The steersman Reads the corrections for the kind of thinking that had to be pulled back, and only cares about the classes that keep coming back. A correction I have typed by hand in six separate projects is not a correction. It is a mechanism nobody built.
The salvor Treats every closed session as a shipwreck and goes down looking for cargo. After the thing that was worked out once, at cost, and written nowhere durable.
The inventory The distance between the machine as configured and the machine as used. Its best output is usually subtraction: the skill never invoked, the rule the transcripts show being ignored.
The coroner Reads the worst sessions as timelines, without sentiment. Only interested in a death it has seen more than once, because one bad session is weather.
The witness Every other seat reads me. This one reads the other side of the conversation: what my agents claimed, versus what the record shows happened next.
The falsifier Runs last, alone, and never sees how the findings were made. It assumes the draft is flattering and padded, because drafts usually are, and its job is to kill things. Its judgement is final on cuts.

There is no historian, and the empty chair took a while to accept. A seat for how my prompting has changed over six months sounds obviously worth having, but its entire material is one precomputed table that the driving agent is already holding, and a mind whose whole job is to find change will find it in a corpus that switched client halfway through. That is a schema, not a habit. So the table gets read where the numbers already are, and nobody is paid to interpret it.

The coroner is the one I argued about most while building it. The first version was a full session-autopsy tool, and I killed it. If a session went badly, the user was there. The frustration is already encoded in their memory and they do not need an AI to parrot it back at them. What they cannot see from inside any one session is recurrence: the same death happening for the fourth time across three projects. So the seat only ships a finding if the failure class repeats.

05 — What comes out

A document, not a dashboard.

What comes out is one HTML file: the end of the analysis, compiled, ready to read and approve. Each finding names something specific about your setup and carries the literal change that would fix it, so approving it is the whole decision rather than the start of one. You tick what you want, skip the rest, hit copy, and paste that back to the agent, which then edits the CLAUDE.md, installs the hook and writes the script. Everything you skipped is dropped and never mentioned again.

The top of a transcript-audit report, showing the title, the corpus summary, five counted statistics and the opening of the verdict.
The top of a report. This one is on synthetic data, not my own.

Read the whole thing. Same synthetic data, so every quote and number in it is invented. A real one is rendered from your own history and never leaves your machine, which is exactly why I am not publishing mine.

06 — What it does not do

Stated plainly, because every tool has these and most pages hide them.

I ran it end to end on the 2,094 transcripts I had at the time and made the agent face me with the result. Twenty-two findings reached the draft, the adversary cut five, and the interesting part was how the false ones failed: nearly all of them were the instrument lying rather than the model inventing. One field stored the first 240 characters of an agent's completion claim, so a seat reported confidently on the other nine tenths of a message it had never seen. A third of my session records did no work at all and sat in every per-session denominator, which turned a habit that had risen into one that had collapsed. Both are fixed in the tool now rather than patched in the prompt, and the renderer still refuses any finding that arrives without a receipt, though a receipt cannot tell you the instrument behind it was reading a truncated field.

The correction I liked most was one I made myself. The report told me I was paying a 43,000 token agent context to make what was functionally a single API call, 676 times. True, but the fix it proposed was wrong: routing those through the CLI is deliberate, because it bills a subscription rather than an API balance. The waste was that each call loaded a full CLAUDE.md, skills, hooks and MCP schemas to run a stateless extraction prompt. Stripping that took four flags and measured 30,289 tokens down to 6,618, with the billing unchanged. A checkbox could not have told me that, which is worth remembering if you are building anything that asks someone to approve things.

07 — Get it

MIT. Python 3.9+. Nothing else.

git clone https://github.com/JustOscarJ1/transcript-audit
cd transcript-audit
python install.py

Then /transcript-audit in Claude Code. The scan takes a minute or two, the seats read their windows in parallel, and the report opens in your browser.

The Python layer also works entirely on its own if you just want the numbers and none of the agents:

python tools/transcript_audit.py stats --what costs       # tokens by month, cache hit rate
python tools/transcript_audit.py stats --what overhead   # what your sessions pay to start
python tools/transcript_audit.py stats --what automation # commands you keep retyping
python tools/transcript_audit.py stats --what steering   # which thinking you keep correcting
python tools/transcript_audit.py stats --what shape      # read this before dividing by anything

github.com/JustOscarJ1/transcript-audit