A scrub you can take back without losing the session

A scrub that cannot be taken back makes people hesitate before running it. So spillscan now has spillscan undo. The hard part was not copying a .bak over a file. The hard part is that agent transcripts keep growing: Claude Code and Codex append to the same session JSONL while you keep working.

A naive undo would copy the backup over the transcript and quietly delete everything written since the scrub. spillscan does something stricter. For each <file>.bak it re-runs the same deterministic scrub on the backup and checks that the current file still begins with exactly those bytes. Then there are three cases:

$ spillscan undo
UNDO (dry-run)  backups=2 restorable=1
STATE     FILE                             NOTE
appended  ~/.claude/projects/…/a.jsonl     keeps 1 line the agent wrote after the scrub
diverged  ~/.claude/projects/…/b.jsonl     edited since the scrub; compare with …/b.jsonl.bak by hand
Would restore 1 transcript, secrets included. Nothing changed. Apply with: spillscan undo --write

Like redact, it is a dry-run until you pass --write. A restore goes through a temp file and a rename, and the .bak is removed only once the original is back in place.

Building this surfaced a quieter bug. If you ran redact --write once, the agent then printed another key into the same session, and you scrubbed again, the second run overwrote .bak with the already-scrubbed file. The first originals were gone. Now a repeat scrub extends the existing backup with only the new tail, and refuses outright (with a clear message) if a .bak it did not write is sitting there.

One reminder that has not changed: undo puts plaintext secrets back on disk. Rotate at the provider first either way.

This is on main and ships in the next release. Source and README.

— 2026-10-21