Daochi

Protocol

Signed sync with a stable compatibility window.

The protocol keeps shipped compatibility clients working while moving new clients toward encrypted private records, app-owned collection namespaces, signed transaction envelopes, and transport-neutral record envelopes.

Identity and authentication

A client account is identified by the hash of its public account key. Login starts with a single-use challenge for that account, then the client signs a canonical request body with ML-DSA-44. Daochi verifies the signature and returns a bearer token for ordinary sync and social endpoints.

Bearer tokens are operational credentials, not the durable account identity. Clients should repeat the challenge and login flow when a token expires, receives a 401, or the server restarts with a new development token secret.

ChallengeGET /api/v1/sync/challenge?user_id=<hash>
LoginPOST /api/v1/sync/login with signed JSON
TokenHMAC bearer credential scoped to the account hash
ClockResponses include server Unix time for client expiry skew handling

Sync surfaces

The legacy typed sync surface stores rows and JSON payloads that the server can read and compact. It remains available for clients that shipped before encrypted private records were primary.

Encrypted records are keyed by collection and id. The server validates names, versions the records, relays them to newer clients, exports them, and deletes them with the account, but does not need to inspect the ciphertext. Protocol v5 treats encrypted records as the primary private-data surface and returns legacy private rows only when clients explicitly request them.

v4 transition

Clients can dual-write legacy typed rows and encrypted records. Released legacy encrypted collections remain valid so users do not need an immediate second backfill.

v5 primary mode

Private app data moves through encrypted hierarchical collections such as private.app.v1.records while social projections stay readable by design.

v6 signed mode

Strict requests include a registered app_id, an app-owned collection prefix, and an X-Daochi-Tx envelope signed by both the account key and an active app key.

Signed transactions

Protocol v6 uses X-Daochi-Tx to bind the account, app, HTTP method, path, exact request body hash, nonce, and expiry into one replay-protected transaction. The account signature proves user authority. The app signature proves the request came from software holding an active key from the signed app manifest.

The envelope is JSON or base64url JSON. It is verified the same way for CLI, TUI, mobile, desktop, and browser clients because the signed material is protocol data, not a platform-specific package identifier. Transactions expire quickly and are stored by tx_id and nonce so replayed requests are rejected.

HeaderX-Daochi-Tx
Contextdaochi-tx-v1
AccountML-DSA-44 signature over the canonical transaction
AppEd25519 signature from an active manifest key

Compatibility policy

Protocol v1 through v5 remain valid through 2027-09-01. After that, protocol retirement is staged: the current protocol remains valid, and the immediately previous protocol remains valid for at least 365 days after any deprecation decision. Compatibility warnings are recorded server-side without blocking those older clients.

Remote event stream

GET /api/v1/sync/ws upgrades to a small event stream that tells clients when newer sync data is available. Native clients authenticate with Authorization: Bearer <token>. Browser clients can use Sec-WebSocket-Protocol: ksync-sync-v1, bearer.<token> because browser WebSocket APIs cannot set arbitrary headers.

Daochi rejects ?token= WebSocket URLs so bearer tokens do not leak through request URLs, browser history, proxy logs, or crash reports.

challenge
sign canonical body
login
sync
remote-event
sync again