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.