Decision memory · local-first · MCP-native

Agents propose. You decide what binds.

varve is local-first decision memory for Claude Code, Cursor, Windsurf and any MCP agent. What an agent saves stays inert until a human accepts it, and every commit after that is recorded against it.

install
$ brew install varve-sh/tap/varve
binding
accepted by a human. Binds every session.
proposed
saved by an agent. Binds nothing yet.
violated
still binding. The code parts from it.
reverted
repealed, and kept as record.

01 — The model

Every band
is a memory.

A varve is one year of lake sediment. Read the column and you read the record, in order, without asking anyone what happened. That is the whole idea behind the tool.

decisions and conventions

Governed. They declare which files they cover, carry evidence, and every transition lands in an append-only log.

An agent can propose one. It cannot accept one, cannot repeal one, and cannot delete one. Those are your commands, run from your terminal.

notes

Ungoverned. Durable facts, session summaries, captured prompts.

Retrievable, never binding, and deleted outright when you ask. Most of what an agent learns belongs here, and that is fine.

what your agent sees

The first call of a task returns what binds the files being touched, ranked, inside a token budget. Nothing is dropped in silence.

memory_pack
files: internal/auth/middleware.go
budget: 2000 est-tokens · used: 1712 · omitted: 2

[1] DECISION 01J9W… · active · scope: internal/auth/**
Refresh tokens rotate on every use.
evidence: commit 4f2a91c, pr #87

[2] DECISION 01J8Q… · VIOLATED (2 unresolved)
Session records are never written from a handler.

-- proposed decisions touching these files: 2, not binding
-- omitted (over budget): 2, named with their rank

02 — The lifecycle

A decision is not a row you edit.

It is a governed object with states, evidence and an append-only history. Here is every state it can reach.

proposed

An agent, an importer or the v1 migration saves a decision. It is captured and inert: it does not bind, and it is never packed as context.

varve decision pending

active

A human accepts it, with at least one piece of evidence. Now it binds, and it is packed into every session that touches its scope.

varve decision accept 01KMDX --evidence commit:9f2c1ab

violated

A commit contradicted it. The rule still binds, and the report says how many unresolved places contradict it. This is not a repeal.

varve report --decision 01KMDX --raw

superseded

Content is immutable once accepted. Changing what a rule says means a successor decision that replaces it, so the history keeps its meaning.

memory_save(topic_key: "decision/database")

reverted

Repealed, terminally. Nothing is deleted: re-adopting the rule later means a new decision citing this one, never a resurrection.

varve decision revert 01KMDX

Acceptance, rejection and repeal are CLI actions. There is no MCP tool for them, because an agent asserting that you approved something is exactly the assertion the quarantine exists to distrust.

03 — The record

Then it records
what happened next.

  1. packed A decision enters an agent session.
  2. matched A commit lands touching its scope.
  3. verdict Conform, or violate.
  4. undone A later commit reverts the violation.

Every link is an append-only event, and every figure in the report drills back down to the rows behind it. A number that cannot be traced is not printed.

varve report
coverage      3 of 5 agent sessions (60%) produced an
              attributable decision to diff event
              via pack: 3 · via recall: 0
follow-through  4 of 5 attributed changes conformed
observer      16 of 16 default-branch commits observed

  ID           packed  matched  conform  violate
  01J9WKQ2M4        7        4        3        0
  01J8QF7RTB        5        2        1        1

what varve does not claim

Attribution is a traceable record, not a causal one. Conform means no violation signal was detected, not that compliance was verified. The report prints its own limits, every time, on the report.

04 — The surface

Eight tools,
one command.

varve setup writes the MCP entry and the instruction block your agent reads. Governance stays off this surface entirely.

  • Claude Code
  • Cursor
  • Windsurf
  • OpenCode
  • Gemini CLI
  • memory_pack what binds these files, ranked, inside a budget
  • memory_recall search by natural language, mid-task
  • memory_context what is linked to these files
  • memory_save save a decision, convention or note
  • memory_get full content of one memory by id
  • memory_update patch a note, never a decision
  • memory_forget deletes a note, files a request for a decision
  • memory_prompt capture the goal at session start

05 — Install

Running in about a minute.

One binary. No daemon, no container, no account. Your store is a SQLite file in the repository you are working in.

homebrew
$ brew trust varve-sh/tap
$ brew install varve-sh/tap/varve

Homebrew 6 refuses any third-party tap until you trust it, so the first line is not optional. That is Homebrew policy, not something specific to this tap.

go
$ go install github.com/varve-sh/varve/cmd/varve@latest
then
$ varve init
creates .varve/varve.db, installs the commit hook
$ varve setup
detects claude-code, cursor, vscode, opencode, windsurf, gemini
$ varve decision pending
review what your agents proposed, then accept