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.
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.
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:
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.
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.
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.
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.
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.
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.
- It is a one-off, not a dashboard. It is built to be run occasionally, mine everything available, and hand you a decision surface. There is a
diff --sincethat scores whether a previous run's changes actually moved anything, and that is the closest it gets to monitoring. - No slice can see the contents of a file the agent read. So any question of the form "did it actually follow the instruction to read X first" is structurally unanswerable here. The docs say so rather than letting a seat infer it.
- The heuristics are hypotheses, not verdicts. Redirect scoring, vagueness, praise detection, the steering classes: all of it is regex, all of it is declared in one visible block at the top of the file, and every score is written onto the record so a reader can disagree with it. The praise slice in particular is weak, and I would rather say that than let someone build a finding on it. The steering classes recognise about a quarter of corrections, which means three quarters of them are something the tool has no name for.
- There are no parser fixture tests. The corpora it was built against are private, so the test is a selftest that parses the largest transcript on your machine and asserts the shape comes out right. An anonymised fixture corpus is the single most useful thing anyone could contribute.
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