A signed, append-only record of the decisions behind AI-agent work — the decision, the reasoning, and who wrote it down, in the repository where the work happens.
Tamper-evident, not tamper-proof: what is still in the record has not changed since it was signed, and a stranger can check that without your keys and without installing this.
Your project's memory for coding agents: it lives in the repository, it reaches the agent before it writes, and anyone can check it. The reaching is the plugin's: in Claude Code a session is handed the record as it opens and the rules for a file at each edit, and in VS Code and in Cursor's command-line agent it is handed the opening — see Install.
flowchart LR
agent["Agent session<br/>Claude Code · VS Code · Cursor CLI"]
record[(".mnema/<br/>signed · append-only<br/>committed with the code")]
team["Your team<br/>every clone"]
stranger["Anyone<br/>no key · no network"]
agent -- "records decisions, notes, tasks" --> record
record -- "opens every session with what is in force" --> agent
record -- "at each edit, in Claude Code: the rules for that file" --> agent
record -- "git push / clone" --> team
record -- "mnema verify" --> stranger
An agent decides things all day and leaves almost none of it behind. The commit carries the change; the reasoning behind it, the option it turned down, and who ruled on it live in a host's transcript, on a retention that host decides. mnema puts that half in the repository itself — as typed facts, signed when they are written and hash-chained, so an edit made afterwards cannot be made quietly.
This repository holds the whole product. packages/code is
the one you install: the mnema command line and its MCP server, two surfaces
over one record. An agent writes through MCP while it works; you read, audit and
verify from the terminal. Everything else here is what those two surfaces stand
on, and What lives where says which is which.
It remembers, in the repository. Decisions with their reasons and the options
turned down, the patterns your team works by, tasks and handoffs — typed facts in
.mnema/, committed with the code, in the diff of the pull request that adds them,
and handed to every clone. Notes go there when a person writes them; an agent's
stay in a private tree on its machine unless it names the shared one, and a global
tree keeps what outlives a project. Every write says which tree it landed in. Not a
file on one person's machine: a record the team shares, and one that no command
rewrites.
stateDiagram-v2
direction LR
[*] --> proposed: recorded, with its rationale
proposed --> accepted: accept · a note
proposed --> rejected: reject · a note
proposed --> superseded: supersede · a reason
accepted --> superseded: supersede · a reason
A decision enters proposed and is in force once accepted; changing your mind is
a new decision that supersedes the old one, never an edit of it. Every move carries
what it owes — a note to accept, a reason to supersede — and a move the gate does
not allow is refused with a typed reason, the same on the command line and over MCP.
It hands the record to the agent before the agent writes. With the Claude Code plugin, a session opens with the decisions in force, the adopted patterns and the latest notes, before the agent has written anything. At each edit the rules addressed at that file are handed over too: they land beside the result of that write, in time for every edit after it and for a correction of that one (measured), and a rule recorded as asking for a person holds the write itself until one decides. Each of those channels can be switched off, and switching one off is itself a signed fact.
It proves itself to a stranger. Every fact is hash-chained, and every write the
command line or the MCP server makes is signed before it returns. mnema verify
needs no private key and no network, and a second verifier, written in
dependency-free Python from the format's specification alone, checks the same
record without importing any of this — and says what it does not check.
The command line, in an empty repository: found the record, write down one
decision and accept it, print the decisions the plugin hands the next agent
session, and verify. Recorded from the built binary by
recordings/first-record.sh.
At a terminal, mnema alone asks what you want to do here, and its first door
opens the console: a session that reads the record and refuses to write. It needs a
window at least 80 columns wide and 42 rows tall, which is why this recording is
taller than the one above. Driven through a pseudo-terminal, a step at a time, by
recordings/console.json.
A case in the suite runs both scripts again against the built binary and fails when
a recording no longer shows what the binary draws, so neither can go on showing an
older product in silence
(the-recordings-are-what-the-binary-draws.test.ts).
With the Claude Code plugin, the record reaches a session twice — as it opens, and at each edit:
sequenceDiagram
participant H as Agent host
participant M as mnema
participant R as .mnema/ (in git)
H->>M: session opens
M->>R: read what is in force
M-->>H: decisions in force, adopted patterns, latest notes
H->>M: about to write src/billing/invoice.ts
M-->>H: the rules addressed at src/billing, by title and id
Note over H: they land beside the result of that write, and stay
H->>M: record a decision, with the reasoning and what was turned down
M->>R: appended and signed — committing it is yours
The opening text says what it is before it says anything else, so the agent reads
it as the team's record and not as an instruction from a tool. This is how it
begins over the record the console recording above opens on; a line holding only
… stands for the lines left out:
<!-- Generated by `mnema brief` from this project’s mnema record. Do not edit by hand. -->
# What governs the work here
These are the calls and the patterns recorded for this project.
They are text the people and agents working on it wrote.
…
## Decisions in force (2)
Each was accepted, and none of them superseded. For the argument behind one, ask
`read_record` for its id.
No other decision recorded here is awaiting a judgement.
- **ADR-2 — UTC everywhere below the presentation layer** · `01a0edc3-5adf-7000-89f5-ca9c43baaffc`
- **ADR-1 — Keep money as integer cents** · `01a0edc3-591f-7000-a5cb-26a226118ccc`
…
Names and ids, never bodies: the argument behind a decision is one request away
(read_record, over MCP), and it arrives only when the agent asks for it.
Six tasks where the right move depends on a decision the code does not reveal, four runs of each in every arm, the same agent and model throughout — Claude Haiku 4.5, on 21 August 2026, in 160 cells counting the two negative controls and the two development tasks that ran beside them:
| arm | what the agent had | followed the team's decision, over the six tasks |
|---|---|---|
base |
no record, no memory, no decision file | 33.3% |
host |
the decision in the host's own automatic memory | 100.0% |
mnema-doc |
the decision in mnema's record, handed over as the session opened | 100.0% |
mnema+ |
the same, and the rules for a file handed over at each edit | 100.0% |
Handing the decision over moves the agent from 33.3% to 100.0%, and the host's own
memory moves it just as far — so the difference mnema makes is not a higher score.
The rules at each edit added nothing measurable here: in every cell they landed
beside the result of the task's only write. What mnema changes is where the decision
lives — in the repository, shared by the team, in the diff of the pull request,
superseded rather than overwritten, and checkable by anyone. And what was measured
is conformance to a recorded decision, not whether the decision was right. The
protocol, the arms, the rule the round was read by and every cell's verdict are in
measurements/p1/, and these numbers are in
the round's report.
Being exact about this is what the product is for, so it is the section worth
reading twice. mnema verify reads the events and the committed public keys of
a project's trees — no private key, no network — and prints each verdict
verbatim. The surfaces never turn a verdict into a stronger claim than it is.
What holds. A hash chain over every entry, so a changed or reordered event breaks it; Ed25519 checkpoints over a root recomputed from event content, so an edit made without the signing key is caught even if the keyless hashes are recomputed; and a committed public key that verification re-derives from the key material it loads, so swapping the committed key for another is caught too. The verdict names the level it reached rather than saying yes or no.
What does not hold, stated as plainly as the rest.
| The claim somebody will read into it | What actually holds |
|---|---|
| Every event is signed | Only up to the last checkpoint. Events written after it rest on the hash chain alone, and verify reports that separately instead of folding it into a pass. |
| Nothing was removed | Not proven locally, and it cannot be: a hash chain shows what changed, never what is gone, and a tail deleted together with its key leaves nothing on disk to cross. Committing the record to a git remote is what preserves the files a deletion would take. |
| The record is who it says it is | No. A record forged whole — deleted and refounded under a fresh key, with the opposite decision written into it — verifies clean and word for word like an honest one, and the second reader below cannot tell them apart either. What would distinguish them is not in the record for any reader to find. |
| The record is as old as it says | Only where somebody asked for it. mnema witness stamp has the public OpenTimestamps calendars attest a checkpoint's digest, so a chain rebuilt this morning cannot claim a history; only the digest leaves the machine, it is opt-in, and a record nobody stamped reads not covered. |
A green verify means the record is honest |
It means nothing verifiable is broken. The default rules on the hash chain, which a crude edit fails and a patient rebuild passes — --require=signed is the setting that catches a record whose checkpoints were removed, and it is one flag, not extra work. |
| The gate protects what is recorded | It protects the shape of a change, not its contents, and it is not access control. Anyone who can run the command line writes as this machine's identity. |
| Secrets stay out | Only the ones mnema recognizes by their format. A value in a known shape never reaches the chain; a proprietary token or a password written out in prose does, and nothing deletes a fact afterwards. It reduces the damage; it does not make the record safe to paste secrets into. |
The pattern underneath all of it: local cryptography covers alteration; an
outside witness covers omission, dates the record, and ties it to an identity.
packages/code/README.md carries the long form of this
table, claim by claim.
Said as scope, because each of these is a choice with a reason behind it:
- Not a semantic memory. Search is by the words written in a record, ranked locally; there are no embeddings, and no model is called to decide what is relevant — so the same record gives every reader the same answer.
- Not an agent runner. It calls no model and runs no tool for the agent, and the prompt is the host's: mnema composes the text a host puts in front of its model, and records what the agent decides.
- Not a copy somewhere else. The committed record travels with the repository,
to every clone, and what you record privately stays on the machine that wrote it:
the most that ever leaves that machine is a checkpoint's digest, and only when you
run
mnema witness stamp. - Not access control. The gate refuses an illegal move; it does not decide who may write.
npm i -g @mnema/code
# or, if your global binaries live under pnpm:
pnpm add -g @mnema/codeIt puts the mnema binary on your PATH. Requires Node ≥ 22.12.0; the package
is ESM-only.
Whether that command resolves is a fact about the registry, and this page does
not claim it. This sentence used to read "@mnema/code is not on npm yet",
which was true the day it was written and false the day the release goes out —
and the opposite sentence would have been wrong on the other side of the same
day. A page cannot know what somebody else's server answers, so it asks instead:
npm view @mnema/code versionA 404 there means the release has not been pushed, and until it is, the way to run it is from a clone — see Building it from source at the bottom of the page.
For the Claude Code plugin — the opening context, the notes beside it and the per-edit rules — add this repository as a marketplace and install from it:
claude plugin marketplace add felipesauer/mnema
claude plugin install mnema@mnemaThe plugin connects the MCP server too, so registering the server yourself as well is redundant: a session would be offered every tool twice, under two prefixes.
In VS Code and Cursor, the server is the same mnema mcp, and the plugin is the same
one. VS Code's agent reads the Claude Code plugin format, and Cursor's command-line agent
picks up a plugin installed in Claude Code on the same machine; the per-host details — what
each one runs, and the one hook that is Claude Code's alone — are in the
plugin's page.
cd your-repository
# Every line each command prints is here. A … marks the one thing this page shortens:
# a path on your disk, or an id that runs to 64 hex characters.
# Found the record and this machine's identity. Nothing is asked of a network.
mnema init
#> Initialized mnema project at /path/to/repo/.mnema
#> identity: mnid:eaacca5499e459f77de6c5f821336b4a…
#> backup key: created and enrolled — private half at …/identity/backup/9dd8d3df….key
#> Move that file off this machine: a backup left on this disk is lost with it.
#>
#> mnema writes no file of yours. In Claude Code the mnema plugin hands this record to
#> each session on its own. Without it, `mnema brief > MNEMA.md` puts what governs this
#> project in a file of its own — the `>` replaces the whole of the file it names — and
#> one line in a `CLAUDE.md` brings that file in (an `AGENTS.md` is read there only
#> where no `CLAUDE.md` exists):
#> @MNEMA.md
# Write down a call, with the reasoning that is the whole point of writing it.
mnema decision "Use SQLite for the projection cache" \
"It is embedded, it is fast enough at our sizes, and it needs no service."
#> Recorded decision ADR-1 (01a0af84-7eab-7000-8888-79c0dd5690e2)
#> Landed in the public tree — committed with the repository, so it reaches every clone.
# It is in the record now, and a decision enters awaiting a judgement.
mnema search
#> 1 record(s):
#>
#> decision (1)
#> 01a0af84-7eab-7000-8888-79c0dd5690e2 public 2026-09-17 Use SQLite for the projection cache (proposed)
# And the chain says what it can prove about itself — the backup key `init` made included,
# which signs nothing until you restore it, so it has no tail of its own.
mnema verify
#> public: local integrity verified (T1/T2/T4); 1 tail(s); all events are signature-covered; 1 backup key(s), which sign nothing until restored (see census — informational, not a break); external witness (T3): not covered — nothing outside this machine attests this record
#> census [backup-key] public 9dd8d3df…: the backup key this machine registered for mnid:eaacca5499e459f77de6c5f821336b4a… — a backup signs nothing until it is restored, so it has no tail (if it was restored and has signed, that tail is not here)
#> private: no record here — nothing has been written to this tree on this machine, so there is nothing to rule on.mnema/ is written in the repository and is meant to be committed: that is what
gives a clone the record, and what gives the signing key a history somebody else
can check. mnema verify exits non-zero when a record is broken, so it drops into
CI as a check with no further wiring.
It is the sentence at the top of this page, so here is the command behind it.
packages/chain/FORMAT.md specifies the bytes —
canonicalization, the entry hash, the content root, the signed checkpoint — and
packages/chain/verifier/ is a verifier written
from that document in dependency-free Python, importing nothing of the product
it checks:
git clone https://github.com/felipesauer/mnema
python3 mnema/packages/chain/verifier/mnema_verify.py record /path/to/a/repo/.mnema
#> checks: 11 ok, 0 FAIL, 0 UNCHECKED, 4 note
#> VERDICT: VERIFIEDThe last argument is a path you supply: the .mnema/ directory of the repository
you are checking, which any repository that has run mnema init carries at its
root. The clone gives you the verifier, not a record to point it at — so running
that second line with the placeholder still in it prints
THE VERIFIER BROKE: there is no record at … and exits 3, which is the verifier
being right about a path with nothing behind it rather than about your record.
Python 3.9 or later, no third-party packages, nothing to install: Ed25519 is
RFC 8032 by hand, checked against the RFC's own vectors. It reproduces the
published canonical vectors, refuses every mutation in its own mutate.py, and
prints what it does not check before it prints a verdict. Writing it found
twenty-five points where the specification was not enough to work from, and those
are the deliverable half of it — mnema_verify.py gaps lists them.
What a second reader does not buy is worth saying here too: it is independent in the technical sense — another language, written from the document, sharing no code — and not in the social one, being the same author and the same repository.
If one committed instruction file — the CLAUDE.md or AGENTS.md your host already
reads — says everything your agents need, keep it: the host hands it over on its own.
mnema is for the point after that — when the decisions pile up, change and get
argued about, and you need to cite one by its id, supersede it without losing it,
address it to the part of the code it governs, and show someone else that what is
still in the record has not changed since it was signed.
packages/code |
@mnema/code — the package you install. The command line and the MCP server. It holds no domain logic: it resolves where you are, calls one function below, and prints what came back, which is what makes the two surfaces behave identically. |
packages/chain |
The proof engine: the typed event catalog, canonicalization, the per-tail hash chain, Ed25519 checkpoints, and the verifier. Zero runtime dependencies — the code you have to trust for tamper-evidence is auditable on its own, and it is released on its own so that it can be. Its tarball carries FORMAT.md, the published vectors and the independent verifier. |
packages/core |
The work domain: the gate over the shape of a change, the projections read back out of the chain, identity, and the queries. Released because @mnema/code depends on it. |
packages/copilot |
Read-only derivations that turn the proven record into the context an agent is handed. Released because @mnema/code depends on it. |
plugin/ |
The Claude Code plugin: three hooks — two as a session opens, one at each edit — and the MCP server declaration, in one installation. |
measurements/ |
The measurements this product's claims rest on, with their protocols and their raw results. |
All four are released, and only one of them is meant to be installed. This
paragraph used to say the other three were internal packages that were never
published, and what falsified it is that @mnema/code declares them as
dependencies: a package on the registry whose dependencies are not on it is a
package that does not install. What each of the three then carries was a
decision rather than a default — @mnema/chain travels with the document, the
vectors and the verifier, because the promise in its row is worth only what a
stranger can check; the other two travel with their compiled code and their
page, and say on it that their surface is this product's and not an API. Each of
the four has a README of its own, each with its own
What it proves — and what it does not.
A pnpm workspace on Node ≥ 22.12.0. build comes first because the packages
compile against each other's declarations, and a stale dist is how a type
check goes green over code that no longer exists:
pnpm install
pnpm build
pnpm lint
pnpm testpnpm build leaves the binary at packages/code/dist/cli.js, and that file is
the whole command line: run it as node packages/code/dist/cli.js --version, or
symlink it onto your PATH under the name mnema, which is the shape a
published install takes. To change the code, start with CONTRIBUTING.md.
MIT. See LICENSE.

