docs

Collaboration

Collaboration

A space is the unit of sharing: one encrypted CRDT world with its own access-control list. Everything on these pages is about who is in a space, how they got there, what they may do, and how several devices or members converge on the same objects without a coordinator deciding for them.

The model in one picture

owner ── mints invite ──► token ──► joiner: POST /v1/spaces/join  (status: joining)
   │                                            │
   └── acl/accept {requestRecordId, permission} ─┘  ──► member (status: active)

owner ── acl/add {identity, permission} ──► added account sees invite_pending ──► invite/accept

me ── one-to-one {otherIdentity} ──► both derive the same space, both writers
Concept What it is Page
Member an identity on a space's ACL with a permission and a status Members and roles
Invite a shareable token that lets someone request to join, or a public read-only guest key Invites
ACL operation owner/admin actions: accept, decline, change permissions, remove, add by identity, transfer ownership, stop sharing ACL
One-to-one space a two-identity space derived from both account keys — no invite, no owner One-to-one
Derived space a well-known per-account space every device resolves to the same id Derived spaces
Bundle one root object per install registered in the space, so members converge on one chat, one setup Bundles

Roles

Permission Can
owner everything, including ACL operations and ownership transfer
admin manage members
writer read and write content
reader read content
guest read-only via a shared public guest key; writes return 403 space.read_only
none no access (also "not mirrored yet" on SpaceInfo.ownRole)

Your own role in every space is mirrored onto the space list as SpaceInfo.ownRole, so a UI can gate role-dependent controls straight from GET /v1/spaces — no per-space fan-out. GET /v1/spaces/:id/members/me is the authoritative read when it matters.

Why it matters. Access control is cryptographic, not a policy a server enforces: a grant hands the member the space's read key, a removal rotates it. A relay that stores the space cannot read it, and cannot quietly add itself as a member.

Convergence without a coordinator

Two themes recur across the section:

  • Derive instead of create when several parties must land on the same object. A one-to-one space id is a function of both account keys; a derived space id is a function of the account keys and a fixed seed; a bundle root can be derived from its bundle id. Nothing to race, nothing to reconcile.
  • Approval is local when the cryptography cannot gate it. A one-to-one ACL is immutable and a direct-add already puts you on the ACL, so "accept" governs whether this device materializes the space, surfaced as a space status, not an ACL write.