Claude Time Machine
Scrub a file's Claude Code edit history, read the reasoning behind each edit, and surgically revert one edit — without touching everything that came after it.
Repo ·
Issues ·
MIT
Everything is local. No network calls, no telemetry.
Try it in two minutes
git clone https://github.com/nuhmanpk/claude-time-machine.git
cd claude-time-machine
npm install
npm run compile
Then press F5 ("Run Extension"). In the new window:
- Command palette → Time Machine: Seed Mock Data (demo) — writes
demo/cart.js plus two fake Claude edits and opens the file.
- Open the Claude Time Machine panel (bottom panel, or Time Machine: Show Timeline).
- Click either dot on the track → the diff card shows prompt → reasoning → diff.
- Click Revert this edit on the first dot. The older edit is undone while the newer one survives — that's the part git can't do cleanly.
Wiring up real capture
Command palette → Time Machine: Enable Capture (install hooks). It shows exactly what it will write, then adds three hooks to .claude/settings.json in the workspace (your existing hooks are preserved):
| Hook |
Matcher |
What it records |
UserPromptSubmit |
— |
The prompt you typed |
PreToolUse |
Edit\|Write\|MultiEdit\|NotebookEdit |
Full file snapshot before the edit |
PostToolUse |
same |
The changed hunk(s) + snapshot after |
Restart any running Claude Code session so it picks up the settings, then ask Claude to edit a file. Time Machine: Disable Capture removes only the hooks it added.
Everything lands in .claude-time-machine/ (git-ignored automatically):
events.jsonl append-only log of prompts, pre-images, edits, reverts
reasoning.json reasoning extracted from transcripts, cached per edit
Where reasoning comes from
The tool call tells you what changed but not why — the plan lives in the assistant text block just before the tool_use in the session transcript. transcriptReader.ts finds that tool call (by file path, then by hunk text) and walks backwards to the nearest assistant text block, ignoring terse ones like "Done." so the card falls back to prompt-only instead of showing noise. Thinking blocks are the second choice, null the third.
⚠️ Hook event names, hook payload shape, and transcript location/format are Claude Code internals and do drift between versions. If capture goes quiet after an upgrade, that's the first place to look — /tmp/claude-time-machine-hook.log catches hook crashes, and the hook always exits 0 so a break can never wedge your Claude Code session.
How revert works
reversePatch.ts, in order:
- reverse-hunk — replace
newContent with oldContent. Requires exactly one occurrence; two copies means we'd be guessing which one you meant. This is what makes reverting an old edit safe.
- snapshot — whole-file restore from the pre-image, allowed only when the file still matches the post-image (nothing else would be lost).
- conflict — no silent mangling: you get
current ↔ before this edit in a side-by-side diff to resolve by hand.
Reverts are recorded as new events, never deletions, so the history stays immutable and a reverted edit still shows on the timeline (dashed red dot).
Layout
Settings
| Setting |
Default |
|
claudeTimeMachine.reasoningMaxChars |
1200 |
Truncation for transcript reasoning |
claudeTimeMachine.showGutterMarkers |
true |
Gutter icon + hover on Claude-touched lines |
Not in this MVP
Cross-file architecture map, generated PR descriptions, "alternatives considered" extraction, team sync, "Ask why" follow-up questions. Open an issue if you want one of them first.
License
MIT