The three layers
- Onchain
- Device
- Off-device
The chain is canonical for everything about who and how much.
The runtime reads these at use time. It does not store an agent id, an owner, or caps of its own and act on them.
Config values that describe the chain
Some[chain] config values look like state but are not:
chain.owner,chain.device_name,chain.per_tx_cap,chain.daily_capare claim inputs. They are used once, to build the claim link. After the claim, the vault and the Identity Registry are the truth. Changingchain.per_tx_capafter claiming does nothing to the vault. Use/limitsinstead.chain.registry,chain.vault,chain.attestor,chain.rpc_url,chain.chain_idare pointers. They name where the canonical state is.
The device key
The device key is created the first time the runtime needs it, after Telegram pairing, not during quickstart. It is a secp256k1 key held behind theDeviceSigner interface, which has two operations: return the address, and sign a 32-byte digest. The software implementation:
- encrypts
device.keyat rest with the runtime secret store, - zeroizes key bytes in memory after use,
- never logs, prints, or serializes the key.
Plugin state
Plugins run as WebAssembly components and have no filesystem. When a plugin needs to remember something across calls and restarts, such as a counter, the last processed order id, or a calibration value, it uses the host state interface.Scoped and encrypted
Scoped and encrypted
Every value is scoped to the exact plugin package, capability, and binding that wrote it. One plugin cannot read another’s keys. The SQLite file stores only opaque locators and encrypted envelopes, and is created owner-only (
0600).Compare-and-swap revisions
Compare-and-swap revisions
Each value has a revision.
put with none only succeeds if the key does not exist. put with some(revision) only succeeds if the current revision matches. A mismatch returns conflict. Revisions are never reused, even after a key is deleted and recreated, so a stale writer can never overwrite a newer value.Keys and quotas
Keys and quotas
Keys are 1 to 128 bytes of ASCII letters, digits,
_, -, or .. Keys are not paths. Each plugin may hold up to 1,024 entries, 64 KiB per value, and 8 MiB in total. Going over returns quota-exceeded.Permissions
Permissions
Reading requires the
state_read permission and writing requires state_write, both declared in the plugin’s manifest.toml. Without them, calls return access-denied.
Plugin state is private working memory. It is never attested and never listed. For data that should be provable and sellable, use operation records.