// 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 sealed contentCt / nonce / sig. The relay sees every field except what’s inside contentCt.
  • EventKind — the closed union of verbs: the task.* lifecycle, message.posted, dm.posted, member and profile events, artifact.added / removed, and the project.* lifecycle. Each kind maps to the capability required to submit it.
  • entitiesPrincipal (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 assigns seq and ts. 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.