# The Minca protocol

This is the specification of Minca: what goes over the wire, what is stored,
what is signed, and what every peer must check. It is written so that someone
can build a client that interoperates with this implementation without
reading its code, and so that a reader, or a model, can understand the
architecture from the spec and the tests alone.

The code in `packages/core/src/` is the reference implementation. Where this document and
the code disagree, that is a bug in one of them: open an issue, and say which.

## Parts

**The core.** What every peer implements to sync with others, store what they
store, and judge every record the same way:

| Part                                            | Covers                                                                                                                                                                                                               |
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [01 — Identity](https://minca.dev/spec/01-identity.md)                 | Seeds and recovery codes, key derivation, DIDs, root and session signers, delegations (UCAN 1.0, JSON profile), what a note lets a key do, envelopes and HPKE, contact keys, the account vault, device keys, pairing |
| [02 — Records](https://minca.dev/spec/02-records.md)                   | Records and their versions, canonical encoding and hashing, signatures, which version wins, links, collection definitions, rules, topics, the validation pipeline                                                    |
| [03 — Spaces](https://minca.dev/spec/03-spaces.md)                     | Spaces, roles and grants, the access log and its replay (`strong-remove/1`), invites, encryption and key distribution, the account registry, profiles                                                                |
| [04 — Network](https://minca.dev/spec/04-network.md)                   | Relays of every kind and meeting through them, several relays at once, peer authentication, WebRTC and WebSocket transports, the mesh, introductions, live messages, ICE and TURN                                    |
| [05 — Sync and storage](https://minca.dev/spec/05-sync-and-storage.md) | Negentropy set reconciliation and its messages, what is stored and how, data folders, sealing at rest, segments, mirrors, blobs                                                                                      |

**Built on the core.** Exchanges between two parties that a peer needs only
if it takes part in them; a peer that doesn't still syncs, stores and judges
everything the same:

| Part                                                      | Covers                                                                                                                                |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [06 — Nodes, sessions and apps](https://minca.dev/spec/06-nodes-and-sessions.md) | The session note and following the account, the account home and app grants, connecting by code, carriers                             |
| [07 — Inbox](https://minca.dev/spec/07-inbox.md)                                 | The inbox and usernames: how someone you share no space with can ask to become your contact, and the relay mailbox that holds a knock |
| [08 — Hosting](https://minca.dev/spec/08-hosting.md)                             | Hosts: subscriptions and payment, a space's own fund, bots a host runs                                                                |

**Judged by readers.** What a version must be to count. Peers keep and sync
every version whatever it says; two readers that judge it must count the
same records:

| Part                              | Covers                                                                                                                                      |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| [09 — Contracts](https://minca.dev/spec/09-contracts.md) | Contracts in a strict subset of CEL, cost limits, citing evidence, the verdicts (passes, fails, pending, unjudged), lines and double spends |

### A minimal peer

A peer that joins spaces and syncs them needs, from the core:

- 01 §1–9: keys, DIDs, notes, what a note lets a key do, and envelopes;
  §10.2 and §11.1 for the member keys a private space's new keys are boxed to;
- 02 whole;
- 03 §1–7, and §8–9 for private spaces;
- 04 §1–2, one transport from §5, §6–7 and §9;
- 05 §1–10.

The rest of the core is shared between the devices of one account (the vault,
device keys, pairing, the data folder, sealing at rest) or optional (several
relays, introductions, blobs and mirrors). An implementation can add it
later and still interoperate.

What it defends, against whom, and where it does not yet, is in the
[threat model](https://minca.dev/spec/threat-model.md). Every part answers to it, and every change to
the protocol is reviewed against it before it merges.

## What is not in it

Only what two implementations must agree on to work together is here. What
one implementation offers its own users is not, however useful: another may
do it differently and still interoperate. Those parts are described with the
package, in [`packages/core/docs/`](https://minca.dev/understand.md), and
change without touching this spec:

- **The library's interface**: creating a node, its stores, holding spaces,
  events, sign-in, the app-side client, React ([node](https://minca.dev/node/node.md),
  [sign-in](https://minca.dev/identity/sign-in.md)).
- **How the library handles spaces**: role presets, invite defaults, how it
  reads and publishes profiles, and where it keeps spaces and their keys
  ([spaces](https://minca.dev/spaces/spaces.md)).
- **The query format** a node answers ([query format](https://minca.dev/records/query-format.md)).
  Peers never exchange queries.
- **Node actions** and the tools the CLI, MCP and WebMCP make of them
  ([actions](https://minca.dev/automations/actions.md)).
- **The standard collections** (`std.*`), which are a naming convention, not
  reserved ([standard library](https://minca.dev/collections/standard-library.md)).
- **Collections proposed for a space** (`std.blueprint`), their review, and
  guides to how a space's collections are used (`std.guide`)
  ([blueprints and guides](https://minca.dev/collections/blueprints-and-guides.md)).
  Apps with screens of their own are an app's convention
  ([blueprints and guides](https://minca.dev/collections/blueprints-and-guides.md#apps-with-a-screen-of-their-own);
  the example app's launcher, `apps/example/src/components/apps/launcher.ts`).
- **Contacts**: the contact list, and asking someone in a space you share
  ([contacts](https://minca.dev/spaces/contacts.md)); the knock itself is
  [07](https://minca.dev/spec/07-inbox.md) §6.
- **Direct messages**, sealed to members' keys ([direct messages](https://minca.dev/records/direct-messages.md)).
- **The inbox's settings kept as a record**, and how a knock becomes a
  contact; the inbox code, the relay mailbox and the knock itself are in
  [07](https://minca.dev/spec/07-inbox.md) ([inbox](https://minca.dev/spaces/inbox.md)).
- **Calls**, built from live messages ([calls](https://minca.dev/calls/calls.md)).
- **What one node keeps for itself**: its stores and caches, how it paces
  sync, its timers, retries and defaults ([storage](https://minca.dev/node/storage.md),
  [node](https://minca.dev/node/node.md)).

The test for a new rule: would a peer that has never heard of it still sync,
store and judge every record the same way? Then it is a layer on the
protocol and belongs with the package, even when it seals, signs or fixes
exact bytes two apps must agree on. Does a peer have to check, refuse or send
something new, or do two parties (an app and its account home, a carrier, a
relay) exchange it? Then it belongs here. What only one node ever reads is
not protocol either; a number is, only when the other side enforces it.

## Conventions

- **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT** and **MAY** are used as
  in RFC 2119, and only where they mean it. Everything else is description.
- **Wire and storage formats** are given exactly: field names, types, byte
  layouts, encodings, and an example. A format a peer must produce or accept
  is normative; a format only this implementation uses internally is marked
  _implementation detail_.
- **Encodings.** Unless a part says otherwise: JSON is UTF-8; `base64url` is
  RFC 4648 §5 without padding; `base58btc` is the Bitcoin alphabet; hashes are
  SHA-256; keys are P-256 (secp256r1); signatures are ECDSA P-256 over SHA-256
  in the 64-byte IEEE P1363 form (r ‖ s).
- **Canonical JSON** is defined once, in [02 — Records](https://minca.dev/spec/02-records.md), and
  every "hash of" or "signature over" a JSON value means over its canonical form.
- **Labels.** Keys derived from the seed, and signed or sealed messages, are
  bound to string labels. The full list is in [01 — Identity](https://minca.dev/spec/01-identity.md),
  including the few places one label serves two uses today.
- **Source.** Each section ends with the files that implement it and the
  tests that pin it down, e.g. _Source: `packages/core/src/sync/negentropy.ts`. Tests:
  `packages/core/tests/sync.test.ts`._ Tests are the executable half of this spec.
- **Rationale** is kept short and set apart, so the rules can be read without it.
- **Planned.** Work that is designed but not built lives in the part it
  belongs to, in a section or blockquote headed **Planned**, saying what it
  will add, what it depends on, and its issue when one exists. Planned text is
  not normative. This spec is the working document: when planned work is
  built, its section becomes the specification; when plans change, it is
  edited. (Earlier plans lived in `docs/blocks/`, kept in git history.)
- **Not yet specified.** Where behaviour is left to the implementation, or is
  still moving, the spec says so rather than guessing.
- **Known defect.** Where this implementation does something the protocol
  should not require, the spec says so in a blockquote starting
  "> **Known defect:**", describing current behaviour and what a fix will
  change. Other implementations MUST NOT rely on it, and SHOULD NOT copy it.

## Planned work

Designed but not built. Each entry is specified, as **Planned**, where it
belongs. Rows marked _after v1_ link parked issues, closed with the `idea`
label. Issues track the larger ones. Known defects link their issue where
they are described; the smaller ones share
[#20](https://github.com/leifriksheim/minca/issues/20).

| Planned                                                                         | Where                                                                                                                                      |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| A check character on recovery codes                                             | [01 §2](https://minca.dev/spec/01-identity.md), [#20](https://github.com/leifriksheim/minca/issues/20)                                                            |
| One spelling per key                                                            | [01 §4](https://minca.dev/spec/01-identity.md)                                                                                                                    |
| Grants narrower than a space (reading)                                          | [06 §2.8](https://minca.dev/spec/06-nodes-and-sessions.md)                                                                                                        |
| Removing a lost device from another one (sign-out already revokes)              | [01 §7.6](https://minca.dev/spec/01-identity.md), [#165](https://github.com/leifriksheim/minca/issues/165)                                                        |
| Merging inside one record                                                       | [02 §4.8](https://minca.dev/spec/02-records.md)                                                                                                                   |
| Forgetting in blob stores                                                       | [02 §4.9](https://minca.dev/spec/02-records.md)                                                                                                                   |
| References to records in other spaces _(after v1)_                              | [02 §5.3](https://minca.dev/spec/02-records.md), [#38](https://github.com/leifriksheim/minca/issues/38)                                                           |
| `pattern` and `format` in definitions                                           | [02 §6](https://minca.dev/spec/02-records.md)                                                                                                                     |
| Uniqueness that cannot be a key                                                 | [02 §7.3](https://minca.dev/spec/02-records.md)                                                                                                                   |
| Deleted access records can't leave access standing                              | [03 §7.2](https://minca.dev/spec/03-spaces.md), [#20](https://github.com/leifriksheim/minca/issues/20)                                                            |
| What a private space still shows (profile keys and collection names)            | [03 §8.6](https://minca.dev/spec/03-spaces.md), [#223](https://github.com/leifriksheim/minca/issues/223)                                                          |
| Access-control convergence                                                      | [05 §8](https://minca.dev/spec/05-sync-and-storage.md), [#10](https://github.com/leifriksheim/minca/issues/10)                                                    |
| Limits on what one peer can cost another                                        | [04 §7.4](https://minca.dev/spec/04-network.md), [05 §6.4, §8](https://minca.dev/spec/05-sync-and-storage.md), [#33](https://github.com/leifriksheim/minca/issues/33)                    |
| Binary sync messages                                                            | [05 §4](https://minca.dev/spec/05-sync-and-storage.md)                                                                                                            |
| Caches that fetch by record key; subsets smaller than a collection _(after v1)_ | [05 §9.1](https://minca.dev/spec/05-sync-and-storage.md), [#27](https://github.com/leifriksheim/minca/issues/27)                                                  |
| Mirrors: restoring an account, absorbing a quiet store writer                   | [05 §16.5](https://minca.dev/spec/05-sync-and-storage.md)                                                                                                         |
| A wallet as the account home                                                    | [06 §2](https://minca.dev/spec/06-nodes-and-sessions.md)                                                                                                          |
| Connecting by code: programs that can't run code of their own                   | [06 §3.1](https://minca.dev/spec/06-nodes-and-sessions.md)                                                                                                        |
| Wakes delivered per device, by Web Push to an app that is closed _(after v1)_   | [03 §15](https://minca.dev/spec/03-spaces.md), [06 §4.4](https://minca.dev/spec/06-nodes-and-sessions.md), [#60](https://github.com/leifriksheim/minca/issues/60)                        |
| Hosts: stopping a host, user storage, metering, reminders, private payments     | [08 §4](https://minca.dev/spec/08-hosting.md), [#220](https://github.com/leifriksheim/minca/issues/220), [#289](https://github.com/leifriksheim/minca/issues/289) |
| Corrections in a line, after a double spend                                     | [09 §7.5](https://minca.dev/spec/09-contracts.md)                                                                                                                 |
| Asking for what a version cites                                                 | [09 §9](https://minca.dev/spec/09-contracts.md), [#138](https://github.com/leifriksheim/minca/issues/138)                                                         |
| Content-addressed definitions; definition tiers, additive-only _(after v1)_     | [02 §6.5](https://minca.dev/spec/02-records.md), [#11](https://github.com/leifriksheim/minca/issues/11), [#12](https://github.com/leifriksheim/minca/issues/12)   |

Proposed in an issue but not yet designed into the spec, so listed under
**Not yet specified** in their part: key rotation, KERI-style pre-rotation
([01 §16](https://minca.dev/spec/01-identity.md), [#9](https://github.com/leifriksheim/minca/issues/9)), and access-history checkpoints
([03 §17](https://minca.dev/spec/03-spaces.md), [#25](https://github.com/leifriksheim/minca/issues/25)).

## The shape of it, in one page

```
 account (seed) ──derives──▶ root key ──signs note──▶ session key ──signs──▶ records
                                                                           │
                                                          stored per space │ synced by Negentropy
                                                                           ▼
 space = { id, visibility, roles & access log, collections, records } ◀── peers in the space
                                                                           ▲
             relays (WebSocket) introduce peers ─▶ WebRTC data channels ───┘
```

- An **account** is a 16-byte seed. Everything else about it is derived.
- The **root key** almost never signs data. It signs short-lived delegations
  (notes, a JSON profile of UCAN 1.0) to **session keys**, which sign **records**.
- A **record** is a signed, versioned JSON document in a **collection** of a
  **space**. Private spaces encrypt record bodies with the space key.
- A **space** carries its own rules: its constitution (its founders, or
  none, and the roles it starts with), whose hash is its id; then roles and
  the grants they hold, who is assigned which, what each collection accepts. Every peer replays the same history and reaches the
  same answer about who may write what. There is no server to ask.
- **Relays** only introduce peers. **Carriers** and **hosts** keep spaces
  online without being able to read them. Neither has authority.
- An **inbox** lets someone you share no space with ask to become your
  contact, through a relay mailbox that holds only sealed knocks.
