Deed
Deed answers one question for every app you build: who is this, and can they prove it? It's a peer of Atomic, Backbone, and Canvas, not a primitive that lives under any of them, because identity is a different kind of problem than data storage or compute. Five primitives cover the whole shape of it: KeyAuth for passwordless login, JWT for general-purpose tokens, Vault for recovery blobs the slice can't read, Link for multi-device continuity, and Pocket for the app data that follows an identity to every device it uses.
Reach every primitive through the SDK exactly like Backbone's: no connection strings, no accounts to register anywhere but your own slice. There is no service to provision.
The primitives
- KeyAuthPasswordless login with a device key pair.
- JWTSign and verify with your slice's own key.
- VaultA recovery blob the slice cannot read.
- LinkEnroll a second device by signed attestation.
- PocketE2EE data that follows an identity everywhere.
Every primitive is called from inside your Atomic functions through the SDK. Deed's own CLI surface is entirely read-only support tooling, never something your app calls: see Inspecting Deed.
Encrypting client-side
Vault's and Pocket's guarantees are only as strong as the encryption you do before you call them. Drift
ships a zero-dependency ES module for that half: e2ee.js, a thin wrapper over WebCrypto
with no npm install and no build step. Copy it into your app's JS from
github.com/ondrift/cloud, under
cli/cmd/canvas/templates/. It is vendored by hand; there is no scaffold command.
import { generateKey, encryptJSON, decryptJSON } from "./e2ee.js";
const key = generateKey(); // 32 random bytes, hex
const sealed = await encryptJSON(key, { balance: 42 });
await fetch("/api/pocket", { method: "POST", body: JSON.stringify(sealed) });
encryptBytes and decryptBytes do the same for files.
encryptWithPassphrase and encryptWithSeed wrap a key under a passphrase or a
recovery seed, and that ciphertext is exactly what belongs in Vault
so a user recovers on a new device without the slice ever holding the key.
The content key must never travel through your slice.
Limits
- Value
- 4 KB on the free tier
- Past it
413, not persisted
- Value
- 100 on the free tier
- Past it
- The oldest entry is deleted
- Value
- 16 KB on the free tier
- Past it
413, not persisted
- Value
- 2 KB
- Past it
400
- Value
- 16 KB
- Past it
400
- Value
- 256 bytes
- Past it
400
- Value
- 120 s, single use
- Past it
- The handshake restarts at
Challenge
- Value
- 300 s
- Past it
- The enrollment restarts at
Begin
- Value
- 30 days
- Past it
Verifyreportsexpired
The Vault and Pocket rows come from your slice's tier; the rest are fixed. There is no
deed section in the Driftfile, so none of these are raised in the manifest.
Inspecting Deed
KeyAuth and JWT are challenge/response protocols an application drives; there is nothing at rest to look at, so neither has a CLI command. Vault, Link and Pocket each keep state, and every command below is a read: the write side stays with the customer's own signing device, matching a pillar that verifies rather than decides.
drift deed statusPrints a line each for Vault (entries), Link (identities) and Pocket (items), the quickest way to see whether Deed is holding anything at all.
drift deed vault list
drift deed vault get <uid>
drift deed link list
drift deed link get <identity>
drift deed pocket list <identity>
list names records without opening them: uids for Vault, identities with a device
registry for Link, key names for Pocket. get is the deliberate, single-record act of
opening one: Vault's get prints one uid's newest blob, still the ciphertext the
customer's own application stored, never anything this platform can read. Link's get
prints one identity's full device list, revoked devices included, and reports the implicit genesis
device honestly for an identity that has never completed an attestation. There is no
pocket get: a Pocket value is ciphertext nobody holds the key for, so printing one would
answer no question a support ticket asks.