Skip to content

Core Principles

Draft

These principles apply to every Capsule component, client and server, and the rules below apply to every doc in design/.

  • Determinism + idempotency. Raw original data is the source of truth; every process is repeatable from its inputs.
  • 4 KiB alignment. Data touching disk or memory boundaries is processed and written 4 KiB-aligned unless a concrete case demands otherwise.
  • Forward and backward compatibility. Old clients ignore new fields; new clients tolerate missing ones — subject to the asymmetry below.
  • Data integrity. Capsule never deletes data unexpectedly: act only in strict scenarios, otherwise crash early. Server data is assumed durable; client data is assumed losable.
  • Ephemeral derived data. Anything that is not an original asset is rebuildable and treated as such.
  • Encryption + compartmentalization. Metadata is encrypted alongside data. Every boundary (album, peer, event, user, version) is a failure-containment boundary.
  • Offline/online divide. A feature works either solely online or solely offline, never differently by connectivity.
  • Recovery-first. The filesystem is reconstructible from partial corruption. Sidecars are the canonical metadata store; the database is a rebuildable query cache.
  • Self-describing. Each media file is paired with a CBOR sidecar holding all user-editable and stable metadata, interpretable without a database.
  • Atomic writes. Temp-file + rename everywhere; never overwrite in place.

Liberal within a known schema version: unknown sidecar fields are preserved verbatim and missing optional fields tolerated. Cross-version is closed: a structure announcing a schema version (sidecar_schema, crypto_suite_id, protocol_version) above the receiver’s maximum is rejected, never best-effort-parsed. See Threat Model — Schema Rules.

Every primitive, construction, format, or component identity is declared in exactly one owner doc; other docs link the declaration and never restate the choice. Explaining a behaviour elsewhere (“STREAM tags catch chunk reordering”) is fine; restating the choice (“we use SHA-256”) is not. When in doubt, link.

DomainOwner doc
Cryptographic primitives, constructions, version identifiersCryptography — Primitives
Key hierarchy, device coordinationCryptography — Keys
MLS membership, ciphersuite bindingCryptography — MLS
Asset + metadata encryptionCryptography — Encryption
Provenance chains, signed manifestsCryptography — Provenance
Recovery paths, failure modes, transport securityCryptography — Failure Modes
MLS resilienceMLS Resilience
Device enrollmentDevice Enrollment
ML model identities, embedding provenanceAI/ML Integrations
LQIP, thumbnail/preview formatsThumbnails and Previews
Server filesystem, required servicesFilesystem — Server
Client filesystem, local indexFilesystem — Client
Library self-maintenance, atomic-write granularityFilesystem — Maintenance
Tokens, identity binding, auth flowAuthentication
Backup container, escrow, recoveryBackup and Recovery
CRDTs, identifiers, geolocation, sidecar schemaMetadata
Import pipelineImport — Pipeline
Upload protocolTransfer — Upload
Download, sync feed, auto-syncTransfer — Download
Storage durability, verify-before-destroyTransfer — Durability
Tethered camera importImport — Camera Import
Connection and retry classesNetwork Resilience
Offline-first requirementsLocal Gallery
Federation trust, capability tokensFederation
LAN discovery, peer channelPeering
Album protocol version pinningVersioning
Stacking, trash retentionAsset Organization
Lifecycle action setAuthorization
Damage scenarios, client classesThreat Model
Refuse-by-default validation invariantsThreat Model — Validation
Schema evolution, deprecationThreat Model — Schema Rules
Outbound licence, dependency-licence policyLicensing
Dependency and tooling pinsDependencies
Share linksShare Links
Upload links, guest dropsWeb Upload
Moderation, reporting, blocklistsModeration
Quota accounting + enforcementQuota
Client validation duties, sandboxed decoderClients
Alerts, delivery, wake tierNotifications
Catalogs, locale resolution, error codesInternationalization
Crate graph, bounded E2E surfaceModule Map
API surface ↔ transport mapAPI Surfaces
Developer-reference generationDeveloper Documentation

Design docs are not templated, but each must let a reader answer: where does this live (crate or module), what is its public surface (schema, wire format, trait, error domain), what does it defer to (owner-doc links), and how is it validated (a tier, where non-obvious). The code is the source of truth for module layout; docs state contracts, not restated code.

A doc naming an implementing module states per surface whether it is Implemented (module exists, its tier runs in CI), Planned (contract designed, no code), or Blocked (planned, with a named external blocker). A planned contract is written in normative present tense but must not claim the code exists; a module a doc names that does not exist yet must be listed in capsule-docs/planned-modules.txt.

Every page carries a required status frontmatter field tracking human review: draft (not re-reviewed since the last substantive change) or stable (signed off; substantive edits flip it back). Drafts still publish.

  • Unit — in-module tests against the contract, peers and externals mocked. Deterministic and fast.
  • Smoke — one module’s real implementation with real I/O and backing services (e.g. testcontainers Postgres or Valkey), peers mocked.
  • E2E — several modules wired against real infrastructure. The list is bounded in Module Map — E2E Test Surface; growth past it signals unwanted coupling.

The tier is decided by what is mocked, not where the test lives.

A faulty, malicious, or version-mismatched client must not inflict irreparable damage on user data. These principles name the posture; the Threat Model owns the defenses: the client-class taxonomy, the damage-scenario → invariant map, validation invariants, fail-closed protocol negotiation, and the cross-cutting idempotency, atomicity, and quarantine rules.