Git history tells you what changed. Git history is the LinkedIn profile of the work. It does not record that you tried three other approaches first. It does not record that the second approach failed for a reason you would never guess. It does not record that the shipped fix was the fourth idea, and that the first three are still bad ideas today.

That reasoning happens in the session where the work happens. Then the terminal closes, and the reasoning is gone.

But it is not gone. Every Claude Code session writes a full transcript to disk as JSONL. I went looking. I had 463 of them — 355 MB of conversational history with no search surface at all. Six months of decisions sat in a format that nobody would read.

So I wrote a pipeline. It reads the transcripts and files the useful ones in my notes.

The shape of it

read JSONL → strip non-text → redact secrets → grade → summarize (Haiku) → markdown

It is one Python script with one dependency. The output is dated markdown in my Obsidian vault, tagged #worklog. Today that is 315 notes from April to August: 244 graded high signal, 65 medium, 6 low.

The extraction step has strong opinions. A tool call becomes a single line, with its input truncated to 240 characters. A tool result is truncated to 600. Thinking blocks are dropped, with a comment that explains why:

elif t == "thinking":
    # Drop thinking blocks — they're encrypted/signed model state, not useful for summary
    continue

What survives: the user turns, the assistant prose, and a compact ledger of the tools that ran on which files. That is the raw material.

Signal grading and the reason it exists

The summarizer returns a fixed JSON shape: title, summary, decisions, learnings, commands, files, tags, and a signal grade. The grading rubric is three lines in the system prompt:

high — concrete deliverable, decision logged, or persistent infra change medium — research/scoping/planning, useful context low — debugging dead-ends, abandoned thread, off-topic chat

The automated path writes only medium and up. The reason is more interesting than “avoid clutter.” These notes go into a personal retrieval system as embeddings. That system has a ranking pathology: small pages rank higher than they deserve. A one-paragraph note about a typo fix does not only add noise. It outranks the real answer. Low-signal notes made retrieval measurably worse.

So the gate is not tidiness. The gate protects the index.

The redaction ladder, and the leak that taught me its top step

The pipeline scrubs everything before the summarizer sees it: API key formats, OAuth tokens, JWTs, AWS keys, bearer headers, private LAN and mesh-network IP ranges, personal phone and email patterns, and a defense-in-depth list of specific known credentials. The pipeline counts each hit. The counts appear in the note itself, so I can see what was caught.

That is the easy half. I got the other half wrong.

Some topics must not be summarized at all: finance, tax, and anything that touches a client’s credentials. My first version filtered by working directory. That failed immediately, because most of my work starts from my home directory, not from a project folder with a clear name. So I added content-level redaction and reprocessed.

Then a published note described an excluded topic anyway. The text was scrubbed correctly. The model rebuilt the subject from the file paths in the metadata — the files_touched list that I included to be helpful.

The fix: stop trying to sanitize those sessions at all.

# Hard kill on confidential-topic detection. Don't summarize, don't publish.
confidential_hit = {k: v for k, v in counts.items() if k in CONFIDENTIAL_LABELS}
if confidential_hit:
    return None  # treat same as opt-out — no markdown written

If a confidential marker appears anywhere, the pipeline drops the session before the API call. The model never sees it. For sessions that survive, confidential path fragments are stripped from their file lists.

The general lesson cost me two full reprocessing runs: redaction that keeps the metadata is not redaction. A capable model will rebuild what you removed from what you kept.

There is also a blunt ratio guard. If the scrub removed more than 40% of the text, the session is too dirty to summarize. In 315 notes, the guard never fired. Either my regexes are well-targeted, or the threshold is too generous. I do not know which.

Provenance is the part I will never remove

Every note ends with a block like this:

## Provenance
- Source: `~/.claude/projects/<slug>/<uuid>.jsonl`
- Bytes read: 398,163
- Tools: Bash:20, Edit:3, Read:2, ToolSearch:2, Skill:1, Write:1
- First user prompt: _...
- Redactions: {'PRIVATE_IP_TS': 4}

A model generates these notes, so the notes can be wrong. The provenance block makes them auditable. It points at the exact transcript, so I can check any claim against the source. The tool histogram is also a good fingerprint. Twenty Bash calls and three edits is a debugging session. Thirty edits and two Bash calls is a build.

The frontmatter carries the date, title, session UUID, project, model, duration, event count, signal, tags, and the touched files. All of it is queryable, sortable, and searchable from the same ⌘K box as the rest of my notes.

Then I stopped the manual runs

For the first six weeks, I ran this by hand. One rule governed it, and I learned that rule the expensive way: always preview to /tmp first, never write straight to the vault. The eyeball gate is the only reason I caught the metadata leak.

Now the pipeline is automatic. A SessionEnd hook fires when a session closes. It skips transcripts under 32 KB, because they are too small for a summary. It detaches and runs the pipeline with a medium signal floor. A nightly sweep catches what the hook misses: sessions that ended in a crash, a power loss, or a Cmd+Q. The sweep also reprocesses any transcript that grew after its note was written.

The preview-first rule is formally superseded on the automated path. Four gates replaced the eyeball: opt-out, then redaction, then the confidential hard-kill, then the signal floor. I preview manually only for bulk backfills.

What it costs

The initial backfill was 131 in-scope sessions. It produced 104 notes for approximately $1.50 in API spend. I paid that twice more to reprocess after the two redaction failures. Call it $4.50 total. The ongoing cost is approximately $3 a month.

There is a fourth $3 that I do not count as well spent. My --skip-existing flag called the summarizer before it checked whether the note existed. That is exactly as useless as it sounds.

What does not work

Seven sessions from the original backfill are gone. Their transcripts were compacted mid-run, and the files vanished under me. There is no recovery for those.

The “first user prompt” field should be a one-line reminder of the session’s topic. It is frequently useless. A pasted screenshot renders as [Image #1] [IMAGE attached], and that tells me nothing at all. A screenshot is the “you had to be there” of prompts. Many of my sessions start with a screenshot.

The whole system also depends on a model’s judgment about what mattered. The signal grades are good, not perfect. A session graded low is silently never written. I do not know what is in that gap. The design makes it unknowable.

The payoff, honestly

Here is the test I did not design but received.

I wrote most of the systems posts on this blog months after the work happened. Not from memory. I do not have that kind of memory. I rebuilt them from these notes. The post about my Cloudflare tunnel, dead for three days, came out of a note the pipeline wrote on the day I fixed it. The note held the container stuck in Created state, the network name that no longer existed, the specific clue that cracked it, and the monitor I added afterward so the failure could not repeat in silence.

I would remember none of that. I would remember “the tunnel broke once.”

A year of work was recoverable in specific, quotable detail, because a cheap model wrote it down every night while I paid no attention. That is approximately three dollars a month for an engineering memory that does not decay.

I think it is the best value in my entire stack. I almost did not build it, because to read my own transcripts felt like an act of vanity. I stayed curious long enough to try, and I am glad. The transcripts were the only place where my reasoning was written down.