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

FeaturePersistent MemoryBlackboard
ScopePer-agentShared (all agents)
PersistenceSQLite, survives restartsIn-memory (lost on restart)
TTL supportYesYes
CASYes (version-based)Yes (value-based)
Access controlmemory.read/write capabilitiesbb.read/write capabilities