preimage
Enables checkpointing and restoring SQLite databases, including rows, schema, and dropped tables, with table-scoped rollback and optional removal of extra rows.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@preimagecheckpoint before the agent refactors this project, then show the diff"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
preimage
The undo layer for AI agents.
Your agent is one confident rm -rf away from deleting a table, rewriting a
config, or "helpfully" migrating a database. git can't save you: those changes
never entered a commit, and they often aren't files at all.
preimage writes a checkpoint before the work starts, then puts everything back
byte-for-byte — including database rows git has never heard of.

$ preimage checkpoint "before the agent gets creative"
checkpoint 0001 created
4 files, 893 B
$ # the agent quietly changes the port and the greeting, and leaves a stray file
│ config.js rewritten, DEBUG.md added
$ # the project's own tests notice
✖ 2 failing, 0 passing
$ preimage diff 1
diff against checkpoint 0001
1 added
1 modified
0 deleted
3 unchanged
config.js
DEBUG.md
--- /dev/null
+++ b/DEBUG.md
@@ -0,0 +1 @@
+# scratch notes, will delete later
--- a/config.js
+++ b/config.js
@@ -1,5 +1,5 @@
export const config = {
name: "hello-service",
- port: 3000,
- greeting: "Hello",
+ port: Number(process.env.PORT) || 8080,
+ greeting: "Hi",
};
$ preimage restore 1 --purge --yes
restored checkpoint 0001 (before the agent gets creative)
1 files written
3 already identical
1 new files removed
$ # tests again, after the rollback
✔ 2 passing, 0 failing
$ and the stray file
│ DEBUG.md: goneThe project's own tests go from failing to passing, and the scratch file the agent left behind is gone.
Now the part git can never do:

$ preimage checkpoint "before migration" --db app.db
checkpoint 0001 created
1 files, 8.0 KB
2 rows across 1 database(s)
$ # a migration drops a user, promotes another, invents a third
$ preimage diff 1
diff against checkpoint 0001
0 added
0 modified
0 deleted
0 unchanged
rows: 1 missing, 1 changed, 1 extra
$ preimage restore 1 --remove-extra
restored checkpoint 0001 (before migration)
0 files written
0 already identical
2 rows written
1 rows removed
$ sqlite3 app.db "SELECT * FROM users"
[{"id":1,"email":"ada@org.org","role":"admin"},
{"id":2,"email":"bob@org.org","role":"staff"}]ada is an admin again. bob is back. The ghost row is gone. No commit, no
git checkout, no hand-written UPDATE.
And when the agent drops a whole table, the schema comes back with it:
$ preimage checkpoint "before the schema change" --db app.db
checkpoint 0001 created
1 files, 12 KB
2 rows across 1 database(s)
$ # the agent decides users is no longer needed
$ preimage diff 1
diff against checkpoint 0001
0 added
0 modified
0 deleted
0 unchanged
rows: 1 missing, 0 changed, 0 extra
table dropped: app.db:users
$ preimage restore 1 --yes
restored checkpoint 0001 (before the schema change)
0 files written
0 already identical
1 tables recreated
2 rows written
$ sqlite3 app.db ".tables"
invoices usersDROP TABLE users is undoable. preimage stored the CREATE statement next to
the rows, so recreating the table is part of the restore rather than a separate
recovery ritual.
Run the whole demo yourself:
git clone https://github.com/muraa-p/preimage && cd preimage
node scripts/demo.mjsInstall
npm install -g @muraa-p/preimageZero dependencies. Node 22.5+ (it uses the built-in node:sqlite, so there is
no native build step and no supply chain to audit).
Then wire it to your agent — see Agent integration.
If you're on Windows
Two things that are not preimage's fault, and that will otherwise look like it is:
PowerShell blocks the command. npm installs a .ps1 shim, and the default
ExecutionPolicy refuses to run it:
preimage : File ...\npm\preimage.ps1 cannot be loaded because running scripts is
disabled on this system.Either call preimage.cmd instead (preimage.cmd checkpoint), or widen the
policy once:
Set-ExecutionPolicy -Scope CurrentUser RemoteSignedNode cannot spawn the .cmd without a shell. If you are calling preimage
from a script rather than a terminal, execFile("preimage", ...) fails with
EINVAL. Use shell: true, or point at the entry point directly:
const bin = "C:/Users/You/AppData/Roaming/npm/node_modules/@muraa-p/preimage/bin/preimage.js";
execFileSync(process.execPath, [bin, "checkpoint", "before the refactor"]);MCP is unaffected by all of this — the client launches the server, not your shell.
Related MCP server: undo
Why this exists
The tooling around coding agents is very good at watching them. Session logs, traces, prompt caches, token dashboards, eval harnesses — all of it observes what the agent did. Almost nothing helps you undo it.
git | preimage | |
Untracked files | No | Yes |
| No | Yes |
Database rows | No | Yes |
Works outside a repo | No | Yes |
Needs | Yes | No |
Reverts agent-created junk | No | Yes, with |
Preimage is not a backup tool and not a VCS. It is the write-ahead log for the one window where a non-human is editing your machine.
Usage
preimage init # create the journal
preimage checkpoint "before refactor" # snapshot now
preimage list # see checkpoints
preimage diff # what changed since the latest
preimage diff 3 # ...since a specific one
preimage restore 3 # put it backdiff doesn't just name the files. It prints a real unified diff, byte for byte
what git diff would print, so you can read the damage instead of opening each
file to find it:
$ preimage diff
diff against checkpoint 0001
1 added
1 modified
0 deleted
2 unchanged
app.js
SCRATCH.js
--- a/app.js
+++ b/app.js
@@ -1,4 +1,8 @@
-export function greet(name) {
- return `hello ${name}`;
+export function greet(name, greeting = 'hi') {
+ const msg = `${greeting} ${name}`;
+ console.log(msg);
+ return msg;
+}
+
+export function farewell(name) {
+ return 'bye';
}--no-hunks gives you just the file list. Binary files and files too large to
diff line-by-line are reported with the reason rather than skipped silently.
diff and show default to the most recent checkpoint. restore always wants
an explicit id, because guessing wrong there is expensive.
Every command takes --json for machine-readable output. diff --json puts the
patches in a patches array, each with path, added, removed and the
diff -u text.
Options that matter
--root <dir> Project root (default: cwd)
--db <path> Capture a SQLite database too (repeatable)
--table <name> Limit to specific tables (repeatable)
--max-bytes <n> Skip files larger than this (default 10 MB)
--no-hunks diff: file names only, no line-level patches
--dry-run Report what restore would do, change nothing
--purge Also delete files created after the checkpoint
--remove-extra Also delete rows created after the checkpoint
--yes Skip the confirmation promptAgent integration
MCP — this is the path, and it is agent-agnostic
preimage mcp speaks the Model Context Protocol over stdio, so it works with
every MCP client, not just Claude. That includes OpenAI Codex and ChatGPT,
Cursor, VS Code and Copilot, Windsurf, Gemini CLI, Zed, Cline, Roo Code, Kilo
Code, Amazon Q and Claude Desktop. If your agent speaks MCP, preimage plugs in.
Most clients take the same JSON:
{
"mcpServers": {
"preimage": { "command": "preimage", "args": ["mcp"] }
}
}Where each one wants it:
Agent | How to add it |
Claude Code |
|
OpenAI Codex |
|
Gemini CLI |
|
Cursor |
|
VS Code / Copilot |
|
Windsurf |
|
Zed |
|
Claude Desktop |
|
Clients that launch the server in the wrong working directory will snapshot the wrong tree, so pass the path explicitly if that happens:
"preimage": { "command": "preimage", "args": ["mcp", "--root", "/path/to/project"] }Four tools:
preimage_checkpoint— snapshot before risky workpreimage_diff— what changed since a checkpoint, with a unified diff per filepreimage_restore— roll backpreimage_list— what's recoverable
preimage_restore requires an explicit confirm: true, and refuses
otherwise. An agent mid-task should not be able to undo your working state by
accident; it has to ask.
preimage_diff returns the patches, so the agent sees the lines it changed
rather than being told a file changed and having to go read it. The patch text is
capped at a budget; if a refactor exceeds it, the response says how many files
were left out rather than letting the agent conclude they were untouched. Pass
includePatches: false when you only want the file names.
Hooks (automatic)
Snapshotting before every single edit is correct but wasteful, so the bundled hooks debounce: one checkpoint per 120 seconds. The first write in a burst captures the state you actually want to return to.
preimage hook install claude-code # prints a settings.json fragment
preimage hook install opencode # prints a plugin commandMerge the printed fragment into ~/.claude/settings.json. The hook never fails
your session — if the checkpoint can't be taken, the edit proceeds anyway.
Set PREIMAGE_SESSION_WINDOW=0 to snapshot on literally every write.
This is the one part that is not agent-agnostic: hooks are wired for Claude
Code and OpenCode only. Every other agent is covered by MCP above — the
difference is that a hook snapshots without the model asking, so on the other
agents you either rely on the model calling preimage_checkpoint or wrap your
own command chain.
The bundled hook scripts are bash. On Windows they need WSL or Git Bash on your
PATH; MCP has no such requirement and is the path to use there. If you want
hook behaviour on Windows, the script is four lines — call preimage checkpoint --root <dir> from whatever your harness runs before a write.
The GIFs above were recorded before
diffprinted line-level hunks, so they show the file list without the patch. The transcripts below them are regenerated from real runs and are current. Re-recording the GIFs needsvhs,ffmpegandttyd; the tapes are intape/.
Safety design
This tool deletes things, so the defaults are conservative.
Nothing destructive without a flag.
restoreonly rewrites files it recorded. Deleting agent-created files requires--purge; deleting agent-created rows requires--remove-extra.Confirmation before you lose data. Interactive restores prompt first. Agent restores need
confirm: true.Big files are skipped, never blanked. Files over
--max-bytesare recorded as existing but their content is not stored. On restore preimage leaves them completely alone rather than overwriting them with nothing.Writes are atomic. Every restore goes through a temp file and a rename, so a crash mid-restore cannot leave a half-written file.
A checkpoint is all-or-nothing. The row, the file entries and the database rows are written in one transaction. A checkpoint that dies partway through leaves nothing behind rather than an empty row that looks restorable. Anything unfinished is refused outright, because a restore that reports success without restoring anything is the one failure this tool cannot have.
Parallel agents do not collide. Several
preimage checkpointprocesses can run at once; they queue on the journal rather than failing on a lock.Path traversal is blocked. A tampered journal record cannot write outside the project root.
Table scope is explicit. preimage never snapshots an entire database silently. You name the tables, or you opt in per database. And a database you captured with
--dbis restored table by table, never as a file — that's the only way--table userscan leaveaudit_logalone.A dropped table comes back. The
CREATEstatement is stored alongside the rows, soDROP TABLE usersis undoable, schema included.
How it works
A checkpoint is a content-addressed snapshot in a SQLite journal at
<root>/.preimage/journal.db.
checkpoints id, created_at, label, source, status
files checkpoint_id, path, kind, mode, size, sha
blobs sha, bytes -- deduplicated by content hash
db_tables checkpoint_id, db_path, table_name, ddl
db_rows checkpoint_id, db_path, table_name, pk, row_jsonBlobs are keyed by sha256, so a file that appears in twenty checkpoints is
stored once. Restore looks up the blob and writes it back; identical files are
skipped, which makes restore idempotent and fast. preimage gc drops blobs no
longer referenced.
Database rows are stored as JSON keyed by primary key (falling back to rowid),
with BigInt and BLOB columns tagged so they round-trip exactly. Each table's
CREATE statement is stored too, which is what lets restore rebuild a table the
agent dropped. Restores run inside a transaction per table.
A database captured with --db is handed to the table adapter and removed from
the file layer's work list. Without that, restoring --table users would
rewrite the whole .db file and silently revert every table you never asked
about.
Add .preimage/ to .gitignore.
Limitations
Worth knowing before you rely on it:
SQLite only for database capture. Postgres and MySQL adapters are the obvious next step; the
dbadapter.jsinterface is small.Not a backup. The journal lives next to your project. It protects you from the agent's mistakes, not from your disk failing.
Restore is a snapshot, not a merge. You get the state at the checkpoint, not a three-way diff. If you changed something by hand after the checkpoint and want to keep it, restoring loses it.
First 10 MB per file. Larger files are tracked but not restorable.
Single-writer. The journal is not designed for concurrent restores from several processes at once.
Development
npm test # 153 tests, node:test
npm run check # syntax check every entrypoint
node scripts/demo.mjs # all three stories, instant
node scripts/demo.mjs --story=1 # just one storyCI runs the suite on Linux, macOS and Windows across Node 22 and 24, and additionally installs the packed tarball into a clean project to check that the real binary works from a real install.
Re-recording the demos
The GIFs in this README come from tape/, recorded with
vhs. Needs vhs, ffmpeg and ttyd on
PATH.
vhs tape/files.tape # -> docs/demo-files.gif
vhs tape/database.tape # -> docs/demo-database.gifBoth record scripts/demo.mjs with --paced, so the text in the GIFs is
generated by the same code path quoted above. If you change the demo, re-record
and update the transcripts here in the same commit.
Contributing
Issues and PRs welcome. Keep it dependency-free — that constraint is the whole security argument for a tool that sits in the agent's hot path. Destructive behaviour stays behind a flag, and every bug fix ships with the test that fails without it.
See CONTRIBUTING.md. Vulnerabilities go to SECURITY.md, not the issue tracker.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Agent checkpoints. Resume after context resets and handoffs with retry-safe, versioned saves.
Preventive human-approval write-gate for AI agents: writes commit only after a human approves.
- RowsafeOAuthsh.rowsafe
PostgreSQL backups and a safety net for AI agents: check recoverability, set restore points.
Cross-agent artifact workspace with provenance across Claude Code, Codex, Cursor, LangGraph.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceAuto-snapshot tool for AI agents. Reduces the risk of AI agents breaking your code by automatically saving a snapshot of every file change locally. Rewind sessions, audit code changes, and inspect diffs directly from your AI chat or the built-in dashboard. Free and safe no cloud run local.1-
- AlicenseAqualityCmaintenanceProvides checkpoint and rollback capabilities for AI agents, reversing file system changes and recording network mutations.1610 npm1MIT

statecli-mcp-serverofficial
AlicenseNot gradedqualityDmaintenanceGives AI agents memory, undo, and self-awareness by tracking file changes and enabling checkpoints and rollbacks.54 npm2MIT- AlicenseNot gradedqualityAmaintenanceEnables AI coding agents to checkpoint workspace state, branch parallel attempts, inspect diffs, and roll back to known-good states mid-task through MCP tools, with automatic safety checkpoints to prevent data loss.5 npmMIT