Skip to main content
Glama

Pentimento

ci

An open, local, single-file ledger for AI agent actions — with undo.

Ogni azione dichiara la propria inversa. Every action declares its inverse.

In painting, a pentimento is the visible trace of an earlier choice beneath the surface — proof that the artist changed their mind, preserved in the work itself. Pentimento is that, for AI agents: a flight recorder for everything an agent does on your machine, written as one plain, append-only .pnt file per session. Every action carries its timestamp, its target, and its declared inverse.

Not a service. Not a SaaS. Not a framework. A file format, a tiny CLI, and an MCP server. The SQLite move, not the platform move.

The 30-second demo

$ # an agent (via the pentimento-fs MCP server) deletes a folder…
$ pentimento log
   4  09:14:02  fs.delete  reversible  done  src/old

$ pentimento undo --last
undone action #4 (fs.delete src/old)

$ ls src/old        # the folder is back, byte for byte
a.txt  sub/

That is the entire pitch.

Want to see it end to end? examples/refactor_rescue/ plays an agent doing a refactor through the real MCP server, then rescues what it broke — undo restoring a deleted tree, undo refusing to trample your edits, and a risky deploy parked as a draft. Run it: python examples/refactor_rescue/demo.py.

Related MCP server: GoLogX (logx-mcp)

How it works

  • One session = one file. .pentimento/sessions/<date>_<id>.pnt, JSON Lines, append-only. An undo never rewrites history — it is a new event referencing the old one. The correction stays visible beneath the surface, like in the painting.

  • Record before effect. The action event is durable on disk before the action touches the world. A flight recorder that loses exactly the crashes is not a flight recorder.

  • Snapshots are content-addressed. Prior state goes into .pentimento/objects/ keyed by SHA-256, git-style; identical content is stored once. Directories are snapshotted as tree manifests.

  • Undo never tramples. Reverting requires proof that the world still matches the state the action left behind; otherwise the undo is refused — and the refusal is recorded too.

  • Reversibility is declared, never assumed. Every action carries its class — reversible, compensable, irreversible — fixed by the spec, so that policy becomes possible.

Read the full format in PENTIMENTO_SPEC.md.

Install

$ pip install .

Zero runtime dependencies — Python ≥ 3.10 standard library only.

The CLI

$ pentimento log              # timeline of the current session, with derived states
$ pentimento diff 7           # before/after (or evidence) of one action
$ pentimento undo 7           # revert one reversible action (post-state verified first)
$ pentimento undo --last      # revert the most recent revertible action
$ pentimento compensate 9     # present the declared compensation, run it on confirmation
$ pentimento approve 11       # present a drafted action, execute it on confirmation
$ pentimento discard 11       # kill a draft, visibly and terminally
$ pentimento status           # sessions, ledger size, snapshot store size
$ pentimento verify           # check the optional per-line hash chain, if present
$ pentimento gc [--dry-run]   # remove blobs no session on disk references

Undo executes, compensation proposes. Exact inverses run mechanically; a compensation — closing the ticket an agent created, deleting the resource it provisioned — is shown to you, command included, and runs only when you confirm. Either way, it lands in the ledger.

And a draft proposes before the act. An agent can journal a shell command or an HTTP request as a draft: fully on the record, not executed. pentimento approve runs it after you've seen it; pentimento discard kills it — and the discarded stroke stays visible in the ledger, a pentimento in the original sense.

The pentimento-fs MCP server

Point any MCP client — Claude Code, Claude Desktop, Cursor — at pentimento-fs and every file operation it performs is journaled, snapshotted, and undoable, with zero changes to the agent.

{
  "mcpServers": {
    "pentimento-fs": {
      "command": "pentimento-fs",
      "args": ["--root", "/path/to/your/project"]
    }
  }
}

Then tell the agent to prefer the journaled tools — one line in your CLAUDE.md (or equivalent):

For file writes, deletions and moves in this project, use the pentimento-fs tools instead of native file access.

The server exposes eight tools. Four journaled filesystem tools — write, delete, move, mkdir — where each response names the action id, so the human always knows the undo handle: journaled as action #7 (reversible: pentimento undo 7). Two executable outbound tools — exec and http — that run a command or a request through the journal, storing exit codes, output and response bodies as content-addressed evidence; both accept draft: true to journal without executing. And two for everything else: record journals an external action before it happens (compensable ones declare their compensation up front; irreversible ones are flagged for human approval first), and report appends the outcome afterwards.

A note on secrets in evidence

exec and http store commands, headers, bodies, and outputs verbatim. That evidence is local — it never leaves your machine — but it is not redacted by default, so it can capture tokens, Authorization headers, or passwords that appear in arguments or output. Opt in to redaction and those values are stripped before they are hashed and stored, so the secret never reaches the ledger or the blob store (spec §14):

$ pentimento-fs --redact                       # strip Authorization, Cookie, … headers
$ pentimento-fs --redact-pattern 'sk-[A-Za-z0-9]+'   # and any matching pattern

Redaction is visible (pentimento diff marks it), it applies to immediately-executed actions and to all evidence, and — because a draft must stay runnable until you approve it — a draft's own command and headers are stored verbatim.

Running the tests

$ PYTHONPATH=src python3 -m unittest discover -s tests

Durability, safety, integrity

The reference implementation aims to match the spec's strongest promise under abrupt failure:

  • Crash durability. Snapshot blobs, the files an action writes or restores, and every ledger append are fsynced and atomically renamed, and their directory entry is fsynced too — so a started event and its snapshot reach stable storage before the effect runs (spec §4).

  • Symlinks are refused before they are followed — at every path component, not just the final target — so no link ever redirects where an action lands (spec §17).

  • Serialized appends. A session may have more than one writer (an agent, plus you running pentimento undo); appends take a brief advisory lock and the event id is assigned under it, so ids never collide and lines never interleave (spec §4).

  • Optional integrity chain. Opt in with pentimento-fs --hash-chain and each line hashes the previous one; pentimento verify reports the first break. It catches corruption and naive edits — not a determined actor with write access (spec §15).

  • No SSRF footgun by default. Because http performs the request, it refuses targets with no legitimate HTTP use — link-local (169.254.169.254 cloud metadata), multicast, reserved — while leaving loopback and private hosts reachable for local dev. pentimento-fs --block-private hardens further by also refusing loopback/private ranges (spec §11). It's a best-effort send-time check, not DNS-rebinding-proof.

  • Tunable timeouts. exec and http default to 600s and 60s; override with pentimento-fs --exec-timeout / --http-timeout so a hung command can't pin a session forever.

Status

Spec v0.3 (draft). The registry covers reversible filesystem actions and the executable outbound pair (shell.exec, http.request — irreversible unless a compensation is declared); everything else is journaled through x. extension kinds as compensable or irreversible — never anything rosier. Scope discipline is a feature.

Draft v0.3 — written to be argued with. Issues and pull requests welcome.

License

MIT — spec and reference implementation. A Red Rio Lab open spec.

A
license - permissive license
-
quality - not tested
D
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/RedRio-bit/pentimento'

If you have feedback or need assistance with the MCP directory API, please join our Discord server