State & migration
State is what makes sessions durable and portable. The StateBackend abstraction gives the agent a versioned, content-addressed store that can checkpoint progress and move work between machines as a delta.
The backend
#[async_trait]
pub trait StateBackend: Send + Sync {
async fn get(&self, key: &str) -> Result<Option<Value>>;
async fn set(&self, key: &str, value: Value) -> Result<()>;
async fn commit(&self, message: &str) -> Result<String>; // → content hash
async fn snapshot(&self) -> Result<StateSnapshot>;
async fn restore(&self, snapshot: StateSnapshot) -> Result<()>;
async fn push(&self, remote: &str) -> Result<()>;
async fn pull(&self, remote: &str) -> Result<()>;
}commit() writes a content-addressed commit and returns its hash. Two commits share unchanged data, so only the difference is ever stored or transferred.
Persistence tiers
State is written at one of four durabilities — the engine behind the user-facing data model:
| Tier | Survives reboot | Migratable | Cross-device |
|---|---|---|---|
| Ephemeral | — | — | — |
| Session | — | — | — |
| Durable | ✓ | ✓ | — |
| Eternal | ✓ | ✓ | ✓ |
Durable is what #[kiki::durable] checkpoints to; Eternal is for data that should follow a user across devices.
Migration
Moving a session to another machine is a sequence of backend calls, transferring only the delta:
This is the mechanism behind parking and migrating sessions. Because state is content-addressed, only what the target doesn't already have transfers.
Backends
| Backend | Use |
|---|---|
| OSTree | Production — Durable/Eternal state, versioned and migratable. |
| Memory | Ephemeral/Session state and tests. |
| Hybrid | A local cache with async sync to a remote. |
Content-addressing is why durable execution and session migration are cheap rather than expensive: checkpoints and moves ship the difference, not the whole state.