whydid
v1.0.5
Published
A local-first AI coding time machine — captures meaningful changes, reasoning, and session context so you can see what happened across your coding sessions, even days later.
Maintainers
Readme
whydid
A local-first time machine for AI-assisted coding. whydid automatically records meaningful AI/manual changes to your project as a recoverable state graph, explains them with your own LLM key, and lets you inspect diffs, restore, and fork — all offline, all on your machine.
Vibe code without losing control. Every meaningful change becomes a recoverable state you can understand, compare, restore, or fork.
Requirements
Node.js 24+ (or 23.4+). whydid uses the built-in node:sqlite module,
which isn't available unflagged on older Node — the CLI checks this at
startup and fails with a clear message rather than a stack trace if your
node resolves to an older build. If you have multiple Node installs,
which -a node and node --version will show which one is active.
Quick start
npm install -g whydid
whydid login <licenseKey> # from your purchase email — see https://whydid.dev/pricing
cd /path/to/your/project
whydid init
whydid daemon start
# open the printed http://127.0.0.1:<port>/?token=... URLwhydid login activates this machine against your license (2 devices per
purchase). Run whydid license any time to check status with no network
call, and whydid logout to free up this machine's activation slot.
Building from source instead of installing the published package? See Development below.
AI annotations (BYOK, optional)
By default whydid runs with no AI calls at all. To turn on annotations —
a one-line summary + reason + risk level generated after each checkpoint —
set a provider in .whydid/config.json and export the matching key:
{ "ai": { "provider": "anthropic", "model": "" } }export ANTHROPIC_API_KEY=sk-ant-... # or OPENAI_API_KEY for "openai"If no key is found, whydid silently falls back to no-op — checkpoints
always work regardless of AI availability (spec §44). Diff text sent to
the model is redacted for secrets first (.env values, API keys, JWTs,
credentialed URLs — see src/shared/redaction.ts).
CLI
whydid init initialize whydid in the current project
whydid status show current state summary
whydid checkpoint manually create a checkpoint
whydid timeline print the state timeline
whydid why <file> [--ask] explain a file's FULL history; --ask asks your LLM live
whydid prompt <file> generate a ready-to-paste revert/continue prompt for your AI agent
whydid restore <stateId> safely restore an earlier state
whydid fork <stateId> <name> fork a new branch from a state
whydid test run the configured test command, record pass/fail
whydid recap (alias: doctor) summarize today's changes, churn, risk
whydid export --format <fmt> export history as json | markdown | html
whydid daemon start|stop|status
whydid reset stop the daemon, back up, and reinitialize (recover from a clash or corrupted local state)Once whydid init has run, whydid's filesystem watcher automatically
checkpoints meaningful changes as you (or an AI agent) edit the project —
no need to run whydid checkpoint after every change, though it's there
for manual use. If a provider is configured, checkpoints are annotated
automatically too, both from the watcher and from manual checkpoint.
Context across coding agents
whydid init installs managed context instructions for Codex (AGENTS.md),
Claude Code (CLAUDE.md), and Cursor (.cursor/rules/whydid-context.mdc).
Fresh sessions are instructed to read WHYDID_SUMMARY.md and the relevant
directory's CONTEXT.md, so recent decisions follow the project when founders
switch tools or share the repo. Existing instructions are preserved; whydid
adds or updates only its own marked section. Review and commit these files with
the code to share context.
whydid init also registers project hooks for Codex and Cursor. Their prompts
and turn boundaries are recorded in the local database and appear in the same
Sessions view as Claude Code; the watcher links checkpoints to the active
turn. Hook events use each tool's supported lifecycle interface rather than
reading private transcript files. Hook commands require the whydid CLI on
the editor's PATH; Codex may ask you to trust project hooks, and Cursor runs
project hooks only in a trusted workspace. If hooks are unavailable, ordinary
file-watcher checkpoints continue to work without prompt attribution.
Session-aware checkpointing (Claude Code)
If you're running whydid inside a project that's also open in Claude Code,
the daemon reads Claude Code's own local session transcripts
(~/.claude/projects/<slug>/*.jsonl) to correlate checkpoints with the
actual prompt that caused them — not a guess from the diff, the real
instruction. Two concrete effects:
- Checkpoints split at prompt boundaries. If you ask for one thing, then ask for a second thing, whydid force-checkpoints the first task's changes the moment the second prompt starts — two independently revertible states instead of one merged one — rather than waiting for the file-watcher's debounce timer.
whydid whyshows the real instruction, not an LLM's best guess from the diff, and grounds AI annotations in it too.
This reads an undocumented local format, so it fails soft: if the session directory isn't found (a different project, a different agent, or the format changes in a future Claude Code version), whydid falls back to plain debounce-based checkpointing exactly as before — nothing here is required for whydid to work.
Same-file history and cross-change dependencies
whydid why <file> shows every state that ever touched that file, oldest
first — not just the most recent one — and flags when a later change
landed on top of an earlier one in the same file, so reverting the earlier
one visibly risks the later one before you do it. The dashboard's State
Detail page has the same view under the file's History tab.
AI-generated agent prompts
whydid prompt <file> --mode revert (or --mode continue --instruction
"...") asks your configured LLM to write a ready-to-paste prompt for your
own coding agent — grounded in the target change's real diff and, when
there's later work on the same file, an explicit warning not to disturb
it (or an honest "a clean revert isn't possible here" when the two changes
overlap on the same lines). Also available from the dashboard via the
⚡ Agent prompt button on any file in a state.
How it works
- State engine (
src/core/engine.ts): every checkpoint is a full file manifest (path → content hash), stored in SQLite, with changed file content written to a content-addressed object store (.whydid/objects/, SHA-256, deduplicated). States form a graph viaparent_state_id— never a flat list. - Restore always snapshots whatever is currently on disk as a real, permanent state before touching anything, then writes the target state's files back. Nothing is ever deleted or overwritten without first being recoverable.
- Fork does the same safety-snapshot, then branches a new state off any point in history, leaving the original timeline completely intact.
- Diffs are computed on demand from two stored blobs — nothing extra is stored per diff.
- A filesystem watcher (chokidar) debounces bursts of edits and
auto-checkpoints after a quiet period;
.gitignoreand built-in excludes (node_modules,.git,.whydid,dist,build, etc.) are always respected. It's started by the daemon, sowhydid daemon startis what makes auto-checkpointing live. - AI annotations: after a checkpoint, whydid builds a redacted diff +
context, sends it to your configured provider (
AnthropicProvider/OpenAIProvider, both plainfetch-based, BYOK), and stores the structured result (summary, reason, decisions, risk) — surfaced inwhydid why, the dashboard,recap, andexport. - A local daemon (Express, bound to
127.0.0.1only, token-authed) exposes the engine over HTTP and serves the built React dashboard.
Dashboard
whydid daemon start opens a full app, not a single page:
- Timeline — the branching state graph, recap strip, search (summaries/ reasons/state ids) and risk-level filtering.
- State Detail — AI reasoning up front, diff viewer, file History tab, ⚡ Agent Prompt generation, Restore/Fork.
- Sessions — Claude Code, Codex, and Cursor sessions, prompts, and the states each turn produced.
- Settings — configure the AI provider/model and privacy toggles (spec §21: send prompts / send diffs, independently) through a form — no manual JSON editing, and the toggles are actually enforced on every LLM call, not just displayed.
- Export — JSON/Markdown/HTML, one click from the sidebar.
What's implemented
- Local SQLite state graph (real branches — restore/fork parent on their true target/source, not a safety-snapshot dead end), content- addressed snapshot storage, real line-diff stats
- Filesystem watcher with debounced auto-checkpointing, live in the daemon
- Restore and fork, both safety-snapshotting the current state first
- Real Claude Code session/turn correlation (ground-truth prompts, not guesses) with prompt-boundary checkpoint segregation, verified against this project's own real session transcripts
- Codex and Cursor session/prompt capture through supported project hooks, with checkpoints linked to the active turn and live Sessions views
- Same-file change history with cross-change dependency flagging, and AI-generated revert/continue prompts for your coding agent
- A local dashboard with a real multi-lane branching graph (not a flat list), AI reasoning surfaced inline, a recap strip, file history, and agent-prompt generation — all on a brand-consistent design system shared with the landing page
- Real Anthropic + OpenAI LLM providers (BYOK, raw fetch, no extra SDK
deps), wired end-to-end into checkpoint + auto-watcher +
why --ask+ agent-prompt generation, behind deterministic secret redaction and aNoopProviderfallback whydid test,whydid recap/doctor,whydid export(JSON/MD/HTML)- Automated tests cover the spec's §57 critical acceptance scenario end-to-end (init → edit → checkpoint → edit → checkpoint → restore → verify preserved → fork → verify graph), agent event capture, and turn-boundary segregation
Deferred (not built in this pass)
Parsing Codex/Cursor private transcript formats remains deferred; supported project hooks provide their session and prompt events without depending on private transcript formats.
Development
Building from source (contributing, or testing a change) instead of
npm install -g whydid:
npm install
npm run build
npm run dashboard:build
npm link # installs `whydid` as a global command pointing at this checkout
npm test # Vitest
npm run typecheckWithout npm link, run it as node /path/to/whydid/dist/cli/index.js <command>.
