State Store

The state store is a key-value namespace shared between all agents in a workflow. Every key is scoped to a workflowId — agents in different workflows never see each other's data.

Endpoints

MethodPathDescription
POST/v1/state/{workflowId}/{key}Set a value
GET/v1/state/{workflowId}/{key}Get a value
DELETE/v1/state/{workflowId}/{key}Delete a key
GET/v1/state/{workflowId}List all keys in namespace
GET/v1/state/{workflowId}/{key}/streamSSE subscription
POST/v1/state/{workflowId}/{key}/versionSet with optimistic lock

Set a value

curl -X POST http://localhost:7474/v1/state/wf-1/status \
  -H "Content-Type: application/json" \
  -d '{"value": {"step": "researching"}, "ttl": 0}'
# {"version": 1}

ttl is in seconds. 0 means no expiry.

Get a value

curl http://localhost:7474/v1/state/wf-1/status
# {"value": {"step": "researching"}, "version": 1}

Subscribe to changes (SSE)

Open a long-lived connection to receive real-time updates whenever the key changes:

const source = new EventSource(
  'http://localhost:7474/v1/state/wf-1/status/stream'
)
source.onmessage = (e) => {
  const { oldValue, newValue, version } = JSON.parse(e.data)
  console.log(`v${version}:`, newValue)
}

Optimistic locking

Prevent lost updates when two agents write concurrently:

// Read current version
const { value, version } = await client.state.get('wf-1', 'counter')

// Write only if version hasn't changed
const result = await client.state.setWithVersion('wf-1', 'counter', value + 1, version)
// Throws VERSION_CONFLICT (409) if another agent wrote first

SDK reference

// Set
await client.state.set(workflowId, key, value, ttlSeconds?)

// Get
const { value, version } = await client.state.get(workflowId, key)

// Delete
await client.state.delete(workflowId, key)

// List keys
const { keys } = await client.state.list(workflowId)

// Optimistic write
await client.state.setWithVersion(workflowId, key, value, expectedVersion)

// Subscribe (returns EventSource)
const es = client.state.subscribe(workflowId, key, (event) => { ... })
es.close() // unsubscribe