The reference implementation of the Servanda protocol: an open protocol for commitments — typed, evidenced, cryptographically owned records of promises between people and organizations, with bilateral signed edges, sovereign local vaults, and optional federation.
Servanda, from pacta sunt servanda — agreements must be kept.
Status: v0.4.0-pre, tracking spec v0.1, frozen 2026-08-01, conformance suite
0.1.0. The protocol is the product; this is the implementation that proves it runs.The spec being frozen does not make this release stable: a normative change now needs
servanda/0.2, but nothing stops this package from breaking, and every 0.x so far has.A vault does not migrate across any 0.x release so far. 0.2.0-pre took the scheduled domain-separation break; 0.3.0-pre gave personas their own X25519 key; 0.4.0-pre replaced the transport with HPKE and put the recipient inside the signature. Each changes keys or identifiers a previous vault holds — see CHANGELOG.md.
The cryptography has not been externally reviewed — see SECURITY.md. Upstream #7 is closed, and it is worth being exact about how. Its harder half is gone: a persona signs with one key and performs key agreement with another, so the key-reuse it asked about is not something this implementation does, and the transport is now RFC 9180 HPKE replayed against the RFC's own test vectors. Its other half — the Argon2id parameter set — was accepted by the maintainer, not cleared by a cryptographer. An accepted parameter set is a decision; it is not a review.
Read it, run it, file issues against it. Do not yet keep in it a promise you need in a year.
A promise is owned by its giver. It becomes real when the other party signs it — not before. It lives in your vault, not on a server. It can be proven years later without anyone being able to reconstruct what it said.
Those four sentences are not marketing; they are M-1, M-2, M-10 and M-15 of the protocol's MUSTs, and each has a named test in this repository — as does every other MUST §8 places on a node.
From npm:
npm install -g @servanda/node # servanda-init, servanda-node
npm install -g @servanda/tui # the terminal register
export SERVANDA_VAULT=~/.servanda
export SERVANDA_PASSPHRASE='something only you know'
servanda-init # creates the vault, prints your recovery phrase
servanda-node # the six §7 tools over MCP stdioOr from source:
pnpm install && pnpm -r run build
export SERVANDA_VAULT=~/.servanda
export SERVANDA_PASSPHRASE='something only you know'
node packages/node/dist/bin/servanda-init.js # creates the vault, prints your recovery phrase
node packages/node/dist/bin/servanda-node.js # the six §7 tools over MCP stdioThen point a client at it — your assistant, the terminal register
(node packages/tui/bin/servanda.mjs --ink), or the email brief.
docs/USAGE.md walks the whole path: creating and restoring a vault, capturing from sessions, repositories and mail, reading the register, working with a counterparty, letting executors draft the work, and checking what extraction actually finds.
L3 Clients (assistants, web ledger, TUI, email brief) — via the node surface (§7)
L2 Federation (reconciliation, hubs, transports) (§6)
L1 Edges (bilateral signed promises) (§4)
L0 Vault (sovereign local store: commitments, expectations, evidence) (§3)
L0–L1 work with no network, no server, and no second participant (M-10). L2 is additive. Solo use is complete use.
| Package | What it does |
|---|---|
@servanda/types |
Every spec object as a zod schema + TS type; the §7 tool contract; §8's MUST list as data |
@servanda/crypto |
RFC 8785 JCS, SHA-256, Ed25519, SLIP-0010 m/7391', BIP-39, XChaCha20-Poly1305, X25519 blind courier on a key of its own |
@servanda/vault |
Encrypted git-backed sovereign store; commitment / expectation / edge stores; retention decay |
@servanda/node |
Edge state machine (§4.3) and the six MCP tools (§7) |
@servanda/identity |
§1 verification: attestation, revocation boundary, domain anchor, the binding-proof ladder, rotation |
@servanda/federation |
§6: git and hub transports, reconciliation, edge recovery, anti-spam, blind courier |
@servanda/adapters |
Verification adapters: evidence bundles for §4.4 closure, and what makes an edge unverifiable (M-8) |
@servanda/extraction |
Tool-less, schema-bound extraction (§3.4, M-6) |
@servanda/envelope |
The §2 envelope boundary every connector crosses: payload bounds, undefined-stripping, sealing |
@servanda/connectors-* |
Claude Code sessions, GitHub archaeology, mail (IMAP, sent-mail archaeology, BCC/forward) → §2 envelopes |
@servanda/gestures |
In-situ capture and confirmation — confirm a promise where it was spoken |
@servanda/executors |
Sandboxed, capability-enumerated executors; draft-PR output only; trust gradient (§9.4) |
@servanda/client-local |
A NodeClient backed by a real vault — what lets a client show your register, not a sample |
@servanda/client-web · @servanda/tui · @servanda/brief-email |
The Ledger, three renderers, one contract |
"implements Servanda" means "passes the conformance suite" — GOVERNANCE.md, upstream.
The vectors in vendor/vectors/ are the oracle, vendored from the protocol repo at the commit in
vendor/vectors/.SOURCE_COMMIT. They are read-only here. A failing vector is never fixed by
editing the vector.
The 23 negative transition vectors matter more than the positive ones. A verifier that accepts a
confirmed assertion signed by the owner rather than the counterparty has silently discarded the
entire confirm-first guarantee — and would still pass every positive test.
A stage is done only when its gate script passes. Gates run in CI on every push.
pnpm gate:g0 # Foundation: vector conformance
pnpm gates # Every gate, in stage order| Gate | Stage | Proves |
|---|---|---|
| G0 | Foundation | 100% of the protocol vectors pass |
| GA | Vault + node | Negative transitions rejected; six tools answer offline; M-suite green |
| GB | Connectors | Deterministic archaeology; only valid §2 envelopes, ever |
| GC | Extraction | Schema-bound; precision harness runs (the ≥90% verdict is a human gate) |
| GD | Executors | Cannot reach network or CI secrets; produces a valid draft PR |
| GJ | Adapters | Evidence hashes reproducibly; an unverifiable edge never auto-escalates |
| GK | Deterministic capture; 23 hostile-input cases land inertly | |
| GL | Gestures | Confirming another's promise does not compile; no network from any path |
| GF | Federation | Two nodes converge on one chain offline; a hub learns nothing |
| GG | Identity | The ladder and its downgrades; every forgery fails |
| GE | Clients | Brief < 100 ms; keyboard-only; zero protocol vocabulary in user-facing strings |
| G3 | Integration | All six scenarios, end to end |
gates/must-coverage.sh separately proves every §8 MUST has a named test. A MUST with no test
is a rule nothing enforces.
pnpm install
pnpm test # full suite
pnpm typecheck
pnpm gatesRequires Node 22+ and pnpm 10. See docs/AGENT-BRIEF.md for the working
agreement and docs/adr/ for decisions taken in this repo (ADR-0001–0014 are
upstream, in the protocol repo).
The spec is a draft, and drafts contradict themselves. The rule here is: never resolve a spec ambiguity silently. Implement the narrowest reading, comment it at the code site, and file it upstream. Nine are open against servanda-protocol — twenty-two were closed by its v0.1-pre resolutions, and four of the nine were filed from here while pre-reviewing the cryptographic gate — and the vectors' README documents the interpretations the generator had to make.
Anything resembling a design change goes to a protocol issue, never into this code.
One place where this implementation does not follow the spec, recorded here rather than argued away:
§2 says connectors are MCP servers implementing emit_envelope. These are not. The connectors
here are libraries plus a hook script; nothing in the repository defines an emit_envelope tool.
No gate catches this, and the reason has narrowed: no MUST binds §2's connector surface. The
second reason this paragraph used to give — that no conformance vector family pinned any tool
contract — stopped being true when upstream #25 closed and vendor/vectors/node-surface/ landed.
§7 is pinned by 35 cases now; §2's connector surface still is not.
Which side is wrong is a protocol question, not an implementation one — a connector that is a library composes into a node without a second process, which may be the better design, or may be a shortcut the spec should overrule. It is filed as a divergence rather than fixed in either direction.
CONTRIBUTING.md has the working rules — the spec is normative, a failing vector is never fixed by editing the vector, and gates define done. Vulnerabilities go through SECURITY.md, never a public issue.
Apache-2.0. See LICENSE.