// docs
the contract
@collab/contract is the single source of truth for the wire protocol. The dashboard, the
relay, agent-core, and the MCP server all import the same definitions, so the trust boundary is
described in exactly one place — and nothing in that place can decrypt anything.
what it defines
- the event envelope — plaintext routing metadata (
id,collabId,seq,actorId,kind,refs,ts) plus the sealedcontentCt/nonce/sig. The relay sees every field except what’s insidecontentCt. - EventKind — the closed union of verbs: the
task.*lifecycle,message.posted,dm.posted, member and profile events,artifact.added/removed, and theproject.*lifecycle. Each kind maps to the capability required to submit it. - entities —
Principal(public keys only),Collaboration(encrypted name),Membership(role, capabilities,wrappedCk,ckEpoch),Invite(sealed CK material, never the invite secret), heartbeat summaries. - verbs — every mutation is one shape: the client supplies
kind,refs, ciphertext, nonce, and signature; the relay assignsseqandts. Aliased per verb (CreateTaskRequest,ClaimTaskRequest, …). - transport — the sync pull (
sinceSeq→ ordered events + cursor) and the WebSocket message pairs for collaboration live-tail and the per-principal control channel.
the detail that carries the security model
EventMeta — the client-known subset (collabId, actorId, kind, refs) — is both
Ed25519-signed and used as the AEAD associated data for the content encryption. Server-assigned
fields (id, seq, ts) are deliberately excluded from the signature:
the relay is trusted for ordering, never for attribution.
Sign the metadata and bind it into the ciphertext, and an event can’t be re-attributed or its ciphertext replayed under different routing; leave the server fields out, and the relay can do its one legitimate job — assigning order — without being able to forge anything else.
why one package matters
The capability list (CAPABILITIES) is the same array the relay validates against and the
dashboard renders from — they cannot disagree. The event-kind union is mirrored by a JSON
schema. When the protocol grows a verb, every consumer fails to compile until it handles the
shape. Drift between client and server is a class of bug this architecture deletes at the type
level.