The problem is not a shortage of distributed components. TalkCo can become less dependent on a central service while still leaving one gateway, indexer, key directory, repair scheduler, or identity provider with effective control. It can also become more distributed while exposing every private context through public topics, stable endpoint identifiers, or searchable provider metadata.
The design therefore distributes responsibility per object and per failure domain. It keeps private authority at endpoints, makes coordination bounded and replaceable, and treats every network or storage substrate as an adapter with a declared metadata budget.
#1. Architecture decision
Build TalkCo as a Rust-owned, local-first encrypted event system with:
- SQLite-backed device state and local-only search;
- context-scoped cryptographic identities and signed protocol events;
- causal/eventual replication for authored state and bounded CRDT use for drafts;
- quorum-certified community root operations;
- replaceable transports, relays, discovery paths, and repair workers;
- a TalkCo-specific ciphertext storage protocol over replaceable storage substrates.
Confidence is high for the layered shape and medium for exact PQ suites, overlay choice, redundancy parameters, and the first platform. The full decision record and claim-evidence case are in distributed-architecture.case.json.
#2. Definitions and non-goals
| Term | TalkCo meaning |
|---|---|
| Local-first | Devices can create, read, search, and queue authorized state offline. Local state is primary; synchronization provides availability and convergence. |
| Distributed | Responsibility and failure handling are split across devices, relays, discovery nodes, stewards, storage hosts, repair workers, and monitors. No single coordinator is required for ordinary private reads. |
| Decentralized | No permanent central owner controls identity, private content, or recovery. Distributed custody is required; it is not sufficient by itself. |
| Federated | Independent operators may run compatible relays, storage, communities, or services. Federation does not provide E2EE or metadata privacy automatically. |
| E2EE | Plaintext is available only to authorized endpoint clients. Ciphertext size, timing, routing, membership changes, and behavior may remain visible to infrastructure. |
The design does not promise perfect unlinkability, metadata-free operation, immediate writes through every partition, trustless governance, universal deletion after decryption, protection against a modified client copying plaintext, or a CRDT representation for every object.
#3. The boundary map
┌──────────────────────────────────────────────────────────────────────┐
│ TalkCo client │
│ │
│ UI/editor ── local policy ── KeyStore / platform keystore │
│ │ │ │
│ ▼ ▼ │
│ Local projections ◄──── SQLite + FTS5 + SQLCipher │
│ ▲ │ │
│ └──── signed, encrypted, versioned event log │
│ │ │
│ COSE + deterministic CBOR; Protobuf/Buf transport schemas │
│ │ │
│ ┌──────────────────────┼──────────────────────┐ │
│ ▼ ▼ ▼ │
│ Pairwise/group crypto Capabilities/quorums Key transparency │
│ PQXDH/ratchets/MLS grants/2-of-3 roots scoped logs/monitors │
│ │ │ │ │
│ └──────────────────────┼──────────────────────┘ │
│ ▼ │
│ Sync and transport adapter │
│ p2panda / iroh / relay / future overlay │
└──────────────────────────────┬───────────────────────────────────────┘
│ opaque encrypted envelopes
┌──────────────┼──────────────┐
▼ ▼ ▼
Relays/store Discovery Optional KT replicas
and-forward and rendezvous no global directory
│
▼
Signed manifest chain
│
▼
Encrypted fixed-size blob chunks
│
erasure-coded ciphertext shards
│
S3 / Tahoe-style / Storj / self-hosted stores
│
repair workers
reconstruct ciphertext only
| Boundary | Authority | Working candidate | Hard rule |
|---|---|---|---|
| Local store | Device durability and projections | SQLite, FTS5, SQLCipher, platform keystore | FTS stays local; WAL is not network replication. |
| Event protocol | Meaning, signatures, versions, causal ancestry | TalkCo envelopes; COSE/CBOR; Protobuf/Buf where useful | Database rows never define security semantics. |
| Sync/overlay | Delivery, anti-entropy, partial replication | p2panda first; iroh comparison; libp2p/Waku/Hypercore later | Replaceable and non-authoritative. |
| Key exchange/group crypto | Session and epoch secrets | PQXDH/ratchet reference, HPKE, MLS/OpenMLS | Group IDs, epochs, timing, and sizes may remain visible. |
| Authorization | Permission to perform or receive an operation | Scoped COSE/CBOR capabilities, group epochs, signed policies | A capability never automatically grants decryption. |
| Key transparency | Detection of key-directory equivocation | Sphere/community append-only logs and monitors | No global identity directory or public search endpoint. |
| Discovery | Finding an invited peer or rendezvous | QR/invite paths and private rendezvous | No global DHT for private namespaces. |
| Relay | Store-and-forward encrypted traffic | Dumb relay or optional Waku-style relay | Relay cannot define ordering, membership, or history. |
| Manifest | Signed pointer to immutable object generations | LogicalAssetManifest, ShardSetManifest | Provider listings are not canonical application state. |
| Blob/shard storage | Retention of opaque ciphertext | S3 first; Tahoe/Storj/self-hosted benchmarks | Hosts do not receive content keys by default. |
| Repair | Restoration of shard availability | Ciphertext-only repair workers | Repair proves possession, not authorization. |
| Recovery | Restoration of user-held keys and sphere state | Encrypted recovery bundles and old-device pairing | No central account reset or permanent recovery authority. |
| UI/editor | Authorized projections and local behavior | Platform spike; Automerge/Yjs for drafts | UI hiding is not a cryptographic boundary. |
#4. Authority and consistency are per object
There is no single correct consistency model for TalkCo. Authorship, membership, key epochs, manifests, and search projections have different conflict semantics.
| Object | Canonical authority | Consistency model | Partition/conflict rule |
|---|---|---|---|
| Direct messages | Author/device stream and recipient validation | Signed append-only, causal/eventual | Queue offline; deduplicate by event ID; never use LWW. |
| Channel posts | Author-signed post/version events | Append-only with successor manifests | Preserve forks; owner/community resolves explicitly. |
| Drafts | Authorized editors | Automerge/Yjs CRDT inside encrypted artifact | Merge only when semantics are genuinely mergeable. |
| Membership | Community policy and authorized root operation | Ordered signed membership events | Conflicts freeze or require explicit quorum resolution. |
| Key epochs | Group/community authority | Strict predecessor chain | Reject stale, replayed, or conflicting epochs. |
| Community roots | Explicit 2-of-3 steward approval | Quorum-certified transition | No silent merge; fork/export if custody is captured. |
| Asset manifests | Owner or community signer | Signed immutable generations | Stale replicas may serve old state but cannot supersede valid newer state. |
| Shards | Storage manifest and placement receipts | Availability and repair state | Loss degrades availability; repair reconstructs ciphertext only. |
| Search indexes | Local device | Rebuildable projection | Never synchronize FTS terms or query history. |
| Receipts | Recipient device, only when explicitly sent | Optional signed event | Default is local-only. |
| Deletion/tombstones | Authorized owner/community policy | Append-only tombstone plus retention/GC rules | Future access is revoked; decrypted copies cannot be erased remotely. |
CRDT convergence is useful for drafts and user-owned documents. It is not an authorization decision and must not decide membership, revocation, key epochs, recovery, governance, or deletion precedence.
#5. Ranked implementation choices
#Local state and synchronization
- SQLite + FTS5 + SQLCipher/platform keystore — adopt for v0. SQLite supplies mature local ACID storage and FTS5 supplies a rebuildable local index. SQLCipher or platform encryption protects local files, but TalkCo still owns key lifecycle and event authorization. File size, WAL, timestamps, and FTS structure are local metadata. See SQLite FTS5, SQLite WAL, and SQLCipher.
- TalkCo signed event layer — mandatory. Use versioned encrypted envelopes, explicit predecessors and causal parents, COSE signatures, deterministic CBOR for signed objects, and Protobuf/Buf where a versioned transport schema is useful. See COSE, CBOR, and Buf compatibility checks.
- p2panda — first distributed-sync prototype behind
SyncTransport. Its signed logs, causal ordering, partial replication, and Rust fit are strong matches. It is pre-1.0; application authorization remains TalkCo’s responsibility, and peers, topics, timing, and discovery can still leak context. See p2panda and p2panda sync. - iroh — transport comparison, not an architecture commitment. Rust/QUIC, NAT traversal, and relays are useful for the same encrypted envelope harness. Endpoint IDs, relay use, timing, and direct network paths can correlate contexts. See iroh documentation.
- Automerge or Yjs — bounded drafts only. Nest the document inside a TalkCo encrypted artifact. Actor IDs, history, tombstones, room names, and awareness metadata remain leakage risks. See Automerge and Yjs.
- libp2p, Waku, and Hypercore/Autobase — later comparisons. libp2p provides broad DHT, pubsub, relay, and rendezvous primitives but exposes lookup/topic metadata and does not provide consensus. Waku offers relay/store/filter patterns but Store is not canonical durability and Filter subscriptions reveal interest. Hypercore/Autobase offers signed append-only logs but does not solve authorization, repair, or durable storage and adds a JavaScript/Rust boundary. See libp2p, Waku, Hypercore, and Autobase.
Hosted sync databases such as RxDB, PowerSync, Electric, Turso Sync, PouchDB/CouchDB, and Zero remain useful for UI or ciphertext-only experiments. They retain a backend authority model and must not become TalkCo’s private-content authority.
#Key exchange and access control
| Choice | Role | Stage | Boundary |
|---|---|---|---|
| PQXDH and Triple Ratchet semantics | Direct asynchronous messaging | Protocol reference and narrow adapter | Do not make unsupported external libsignal use the core dependency. PQXDH, Double Ratchet, libsignal |
| HPKE with hybrid ML-KEM/X25519 | One-shot encryption and content-key wrapping | Experimental suite behind KemSuite | The hybrid profile is still a draft; bind suite, sphere, object type, and policy epoch. RFC 9180, HPKE-PQ draft |
| MLS/OpenMLS | Private groups and invite-only channels | First group prototype | MLS requires application conflict resolution for simultaneous Commits; PQ-MLS is draft work. RFC 9420, OpenMLS, MLS PQ draft |
| Scoped capabilities | Offline grants and attenuation | Minimal custom COSE/CBOR format | Borrow UCAN/Biscuit ideas without global DIDs or a broad policy language. UCAN, Biscuit |
| Key transparency | Detection of dishonest key-directory behavior | Per-sphere/community prototype | Append-only logs must not become a global identity graph. KT architecture |
| Independent signatures | Community root approvals | Adopt for v0 | Two-of-three is a validation rule using independent signatures, not necessarily a threshold primitive. |
| FROST | Compact threshold signatures | Later | Not PQ, not robust against misbehaving signers, and not Byzantine consensus. RFC 9591 |
| TACo/PRE | Exceptional conditional-access content | Adapter only | Current implementation and governance are transition-sensitive; it is not routine messaging membership. TACo access control, pyUmbral status |
#Storage substrates
TalkCo should own six storage-level objects: EncryptedBlob, ShardSetManifest, LogicalAssetManifest, Tombstone, ProviderLease, and AvailabilityProof. The mutable application state is the signed manifest chain; the blob substrate stores opaque immutable bytes.
| Choice | Recommendation | Strength | Caveat | Stage |
|---|---|---|---|---|
| S3-compatible storage | First substrate | Simple, widespread, strong object semantics | Provider sees existence, timing, sizes, and access; encrypt before upload. S3 client-side encryption | v0 |
| Tahoe-LAFS | Architectural reference and controlled backend | Client encryption, capabilities, erasure coding, leases, and repair | Higher integration and license review; capability and timing metadata remain sensitive. Tahoe-LAFS | Benchmark |
| Storj | Repair and heterogeneous-host benchmark | Practical encrypted erasure-coded storage | Satellite coordinates metadata, audits, repair, billing, and authorization. Storj encryption | Benchmark |
| SeaweedFS | Self-hosted controlled cluster | Apache-licensed, S3-compatible, multi-node testable | Cluster metadata and administration remain centralized within the deployment. SeaweedFS | Prototype |
| Garage | Small geo-distributed self-hosted S3 | Rust and compact deployment | AGPLv3; replication is not automatically TalkCo K-of-N storage. Garage | Prototype if license permits |
| Hypercore/Hyperdrive | Manifest/log adjunct | Sparse replication and append-only history | No durability, repair, or economic storage guarantee | Later |
| IPFS/Kubo | Restricted export/public-content adapter | Content addressing and ecosystem reach | Public DHT/provider queries expose identifiers and timing; persistence requires pinning. IPFS privacy, IPFS persistence | Restricted |
| Filecoin/Sia | Economic archive adapters | Proof-bearing paid storage | On-chain contracts, payments, deal metadata, and operational complexity | Later |
| Arweave | Reject for ordinary content | Permanence | Conflicts with expiry, revocation, legal hold, exit, and deletion semantics | Reject |
| MinIO community | Do not add as a new default | Familiar S3 API | Current community repository status makes it unsuitable as a new foundation | Reject for v0 |
The storage boundary should expose narrow operations such as put_shard, get_shard, stat_shard, renew_lease, delete_shard, challenge_shard, record_receipt, claim_repair, and append_signed_manifest. It should not expose global listings, people or relationship lookup, plaintext search, provider-side application authorization, arbitrary mutable overwrite, or host decryption keys.
Erasure coding occurs after encryption. Small hot objects may use replication; large or cold objects may use erasure coding after failure-domain simulation. Repair workers reconstruct ciphertext only, use bounded leases and repair epochs, and must be tested against correlated household, network, power, geographic, and operator failures rather than node count alone.
Deletion means several different things: logical deletion, future access revocation, tombstoning, lease expiry, physical garbage collection, and crypto-erasure. TalkCo must not promise erasure of plaintext already decrypted, unknown ciphertext copies, external backups, public replicas, or recovery bundles that still contain a key.
#6. Key hierarchy and mechanism separation
| Material | Scope | Purpose |
|---|---|---|
| Device ownership root | Device-local | Owns sphere roots, recovery, and migration decisions |
| Sphere signing key | One per sphere | Signs profile manifests, introductions, grants, and migration records |
| Sphere KEM key | One per sphere/device | Receives HPKE or PQXDH bootstrap material |
| Device/session keys | Per device and peer | Pairwise ratchet establishment and message secrecy |
| MLS credential key | Per group member | Authenticates proposals and Commits |
| MLS epoch secret | Per group epoch | Encrypts group messages and derives attachment keys |
| Content/object key | Per object or channel epoch | AEAD encryption of content and manifests |
| Steward keys | Per community steward | Signs governance/root transitions |
| Recovery-bundle key | User-held and separately wrapped | Protects recovery material |
| Migration key | Per transition | Signs successor device/sphere records |
| Conditional-access wrapper | Exceptional object only | Wraps a content key for future PRE/TACo-style release |
| Shard metadata | Per object/shard set | Placement, integrity, repair, and retention only |
The five unresolved architectural contradictions have these working resolutions:
- Signal fork versus Rust core: retain Signal protocol semantics as a reference and implement a narrow Rust-owned adapter. Direct
libsignalreuse remains gated by API stability, license, platform, and security review. - TACo commitment versus conditional access: commit to a
ConditionalAccessinterface; treat TACo as one candidate implementation for exceptional content, not ordinary messages. - PQ confidentiality versus PQ authenticity: hybrid ML-KEM/X25519 can provide post-quantum confidentiality while Ed25519 remains classical authentication. Long-lived governance, migration, and recovery records should support dual Ed25519/ML-DSA signatures. Do not claim full PQ security until authentication, recovery, and governance are included. See FIPS 203 and FIPS 204.
- Key transparency versus no global directory: use blinded, sphere/community-scoped logs with local pinning, independent monitors, and optional peer gossip. Do not create a global lookup or equivalence graph.
- Threshold signatures versus threshold custody, erasure coding, and Byzantine consensus: signatures authorize records; custody releases key material; erasure coding reconstructs encrypted bytes; Byzantine consensus orders committee state. Separate APIs, threat models, and tests are mandatory.
#7. Minimal v0 and staged adoption
#Minimal v0 composition
- Rust protocol core.
- SQLite + FTS5 + SQLCipher/platform keystore.
- Signed, encrypted, versioned append-only events.
- COSE + deterministic CBOR for signed records; Protobuf/Buf where useful for transport.
- HPKE hybrid experiment and OpenMLS group prototype behind crypto adapters.
- Independent two-of-three community signatures.
- Minimal scoped capability grants.
- p2panda sync adapter plus a dumb relay fallback.
- S3 ciphertext blob adapter.
- Fixed-size encrypted chunks, signed manifests, tombstones, leases, and ciphertext-only repair.
- Local-only FTS and no global private index.
#Roadmap
- Freeze the object authority/consistency matrix, key hierarchy, metadata budgets, and adapter traits.
- Build the two-device encrypted-event slice with offline writes, duplicate delivery, local search, pairing, and membership removal.
- Run identical envelopes over p2panda and iroh; measure convergence, mobile behavior, metadata, battery, and coordinator dependence.
- Build a five-host ciphertext harness with S3 and one self-hosted substrate; test manifests, repair, migration, expiry, tombstones, and failure domains.
- Add two-of-three roots, fork handling, scoped key transparency, and recovery bundles.
- Trial Storj, Tahoe-style storage, libp2p/Waku, Garage/SeaweedFS, and conditional access only after the preceding evidence gates pass.
Every dependency needs a stable adapter boundary, reproducible tests, compatible licensing, documented metadata leakage, explicit failure behavior, no authority over TalkCo identity or security state, migration evidence, and an acceptable maintenance history.
Hard rejects are global plaintext state, public people/content search, reusable cross-sphere identifiers, central permanent recovery, online centralized coordination for ordinary private reads, public enumeration of private DHT namespaces, hosts with default decryption rights, unversioned remote policies, provider listings as canonical state, universal deletion claims, and generic LWW/CRDT merges for membership, revocation, or key epochs.
#8. Smallest falsifying experiment
Build a disposable harness containing:
- two devices and two unrevealed spheres owned by one device-local root;
- two direct-message peers and one three-steward community;
- two key-transparency replicas and three relays/rendezvous nodes;
- five storage hosts across at least three failure domains and one repair worker;
- S3 plus one self-hosted storage adapter;
- p2panda and iroh transport adapters.
Exercise offline creation, duplicate delivery, reordering, replay, simultaneous MLS Commits, steward equivocation, hybrid key establishment, group removal, capability attenuation/expiry/replay, key-directory forks, corruption, withholding, sleeping hosts, correlated failures, repair races, provider migration, tombstones, leases, legal hold, crypto-erasure, recovery, and removal of relay/discovery/repair/steward roles.
The design is falsified if a host decrypts content; a coordinator is required for ordinary reads; duplicate delivery changes meaning; a removed member decrypts a future epoch; membership conflicts silently resolve; fewer than the quorum authorizes a root transition; stale manifests resurrect state; two unrevealed spheres share a recoverable protocol identifier; repair requires plaintext; migration changes object meaning; key-transparency forks remain undetectable under the stated assumptions; or traces reveal unacceptable cross-sphere correlation.
Acceptance evidence should include Wycheproof and official ML-KEM/ML-DSA vectors, property/state-machine tests, TLA+/TLC models for epochs/recovery/quorum/tombstones, Testcontainers multi-node runs, Toxiproxy fault injection, packet-capture metadata summaries, cross-implementation COSE/CBOR and HPKE tests, explicit t-1 quorum failures, and migration/revocation/deletion-boundary tests. See Wycheproof, TLA+, Testcontainers, and Toxiproxy.
#9. Open questions ranked by impact
| Priority | Question | Next evidence |
|---|---|---|
| P0 | What is the first platform? | Build the same encrypted event and secure-storage slice in native and browser/WASM shells. |
| P0 | What metadata budget is acceptable for sphere separation? | Run p2panda, iroh, and dumb-relay traces with two spheres and automated correlation tests. |
| P0 | Which objects require multi-writer collaboration beyond drafts? | Model every object in the authority matrix and reject CRDT use without an authorized deterministic merge. |
| P0 | What PQ posture is required at launch? | Implement hybrid ML-KEM-768/X25519, classical signatures, dual-sign governance records, downgrade tests, and migration. |
| P1 | p2panda or iroh first? | Use identical events, failure schedules, latency, battery, coordinator-loss, and metadata measurements. |
| P1 | What redundancy and repair profile survives churn? | Simulate multiple redundancy profiles across host, household, network, geography, and jurisdiction failures. |
| P1 | Can friends-and-family hosting ship legally and operationally? | Review host pause, drain, notice-routing, legal-hold, and migration flows. |
| P1 | Is scoped key transparency practical without creating a directory? | Prototype blinded labels, local tree-head pinning, independent monitors, and gossip. |
| P2 | What recovery authority is acceptable? | Threat-model user-held bundles, paired devices, trustees, and threshold recovery without central continuity. |
| P2 | Which licenses can TalkCo accept? | Create the dependency policy before selecting AGPL/GPL, commercial SQLCipher, native SDKs, or hosted services. |
#10. Do next
- Freeze the object authority/consistency matrix as the protocol contract.
- Define
LocalStore,EventLog,SyncTransport,KeyStore,BlobStore,ManifestStore, andRecoveryStoretraits. - Build the two-device encrypted event and local-search slice.
- Prototype OpenMLS membership and epoch removal behind a crypto adapter.
- Compare p2panda and iroh with identical envelopes and failure schedules.
- Build the five-host ciphertext storage harness with S3 and one self-hosted substrate.
- Run cross-sphere packet/storage correlation tests before adding public discovery.
- Freeze dependency-license and metadata-leakage gates before selecting production packages.