Persistent Memory
Agents have access to a per-agent persistent key-value memory store backed by SQLite. Memory survives agent restarts and daemon restarts. It is independent of the workspace filesystem.
Overview
- Scope: Per-agent. Each agent has its own isolated namespace.
- Backend: SQLite database managed by
agentd - Persistence: Survives agent and daemon restarts
- Versioning: Every key has a version number, enabling optimistic compare-and-swap
- TTL: Optional per-entry time-to-live
Reading a Value
Via SDK:
#![allow(unused)] fn main() { let value = agent.memory_get("config").await?; }
Via ash:
ash memory read <agent-id> config
# Output: {"theme": "dark", "max_retries": 3}
Writing a Value
Via SDK:
#![allow(unused)] fn main() { agent.memory_set("config", json!({"theme": "dark"})).await?; }
Via ash:
ash memory write <agent-id> config '{"theme": "dark"}'
# With TTL (expires after 3600 seconds)
ash memory write <agent-id> session-token '"abc123"' --ttl 3600
Compare-and-Swap
For safe concurrent updates, use CAS:
ash memory cas <agent-id> counter 2 '"new-value"'
# Expected version = 2; if current version != 2, the write is rejected
Via IPC request:
{
"MemoryWriteCas": {
"agent_id": "<uuid>",
"key": "counter",
"expected_version": 2,
"value": 42,
"ttl_secs": null
}
}
Deleting a Key
ash memory delete <agent-id> session-token
Listing Keys
ash memory list <agent-id>
# With glob filter
ash memory list <agent-id> --pattern "cache.*"
Capabilities Required
spec:
capabilities:
- memory.read:* # Read any key
- memory.write:* # Write any key
- memory.read:config # Read only the "config" key
- memory.write:notes # Write only the "notes" key
Difference from Blackboard
| Feature | Persistent Memory | Blackboard |
|---|---|---|
| Scope | Per-agent | Shared (all agents) |
| Persistence | SQLite, survives restarts | In-memory (lost on restart) |
| TTL support | Yes | Yes |
| CAS | Yes (version-based) | Yes (value-based) |
| Access control | memory.read/write capabilities | bb.read/write capabilities |