State Grain
What is a State grain?
A State grain captures a point-in-time snapshot of an agent’s state as arbitrary JSON. States serve as portable save points in the context database — session context, configuration snapshots, or any structured data that represents “how things are right now.”
Unlike Events (which record what happened) or Beliefs (which assert knowledge), State grains capture the full picture at a moment in time. This makes them central to AI agent memory workflows where agents need to pause, resume, or roll back to a prior configuration. The data field accepts any valid JSON object, so you can store everything from user preferences to complex multi-turn conversation state. (Internally this is stored as context_data in the Rust struct, but the API field name is data.)
The text representation for embedding is extracted by looking for a label, description, title, or name key inside the data object. If none of these keys exist, the state has no text representation and will not appear in full-text search results. It can still be queried by hash, tags, namespace, or any common field. For autonomous memory systems that need text-searchable states, include a label key in your data object.
| Field | Type | Required | Description |
|---|---|---|---|
data | object | no | Arbitrary JSON representing the state snapshot (defaults to {}) |
Plus all common fields (confidence, tags, namespace, etc.).
How do I create a State?
Pass a JSON object as data through the /batch-add endpoint with grain_type: "state". Include a label or description key in the JSON if you want the state to appear in full-text search results.
State grains accept any JSON structure in data. The field defaults to an empty object {} when omitted. There is no enforced schema beyond valid JSON. This flexibility lets you store session state, feature flags, model parameters, or any configuration your agent needs to resume later. Use namespace to group states by session or environment, and tags to categorize them (e.g., "checkpoint", "config", "preferences").
For high-frequency state updates, consider batching multiple states in a single /batch-add call. Each state gets its own content-address hash. The supersession mechanism (described below) keeps only the latest version active while preserving history.
import areev
db = areev.open("./data")
h = db.add("state", {"data": {
"label": "session checkpoint",
"user_preferences": {"theme": "dark", "language": "en"},
"last_page": "/dashboard",
"cart_items": 3
}})
POST /api/memories/default/batch-add
Content-Type: application/json
{
"grains": [
{
"grain_type": "state",
"fields": {
"data": {
"label": "session checkpoint",
"user_preferences": {"theme": "dark", "language": "en"},
"last_page": "/dashboard",
"cart_items": 3
}
}
}
]
}
areev add state data='{"label":"session checkpoint","last_page":"/dashboard"}'
How do I update a State?
States are immutable once written. To record a new state, supersede the previous one. This preserves the full history of state transitions while keeping recall queries clean — superseded grains are excluded from results by default.
The supersession chain lets you walk backward through state history to any previous checkpoint. This is useful for debugging agent behavior (“what did the session look like three steps ago?”) and for rollback scenarios where you need to restore a prior configuration.
A common pattern is to store an Event describing what triggered a change and a State capturing the resulting configuration, linked with related_to. This gives you both the narrative (“user changed theme”) and the structured snapshot (“theme is now dark”) in a single audit trail.
old_hash = db.add("state", {"data": {"label": "v1", "mode": "draft"}})
new_hash = db.supersede(old_hash, "state", {"data": {"label": "v2", "mode": "published"}})
POST /api/memories/default/supersede
Content-Type: application/json
{"blob_hash": "<old_hash>", "fields": {"data": {"label": "v2", "mode": "published"}}}
When should I use State vs. Event?
Use State when you need to capture “what things look like right now” as structured data that can be restored later. Use Event when you need to record “what just happened” as a narrative description. States are snapshots; events are occurrences.
The distinction matters for recall. When an agent resumes a session, it loads the latest State to restore context. When it reviews history, it queries Events to understand the sequence of actions. Mixing the two — storing snapshots as Events or narrating changes as States — makes both use cases harder.
If you find yourself putting structured JSON into an Event’s content field, that data belongs in a State grain’s data instead. If you find yourself writing prose into a State’s data.description, consider whether an Event with content is a better fit.
Related
- Grain Types: Overview of all 10 OMS grain types and shared fields
- Event: For recording occurrences rather than snapshots
- Workflow: For multi-step procedures rather than static snapshots
- Action: For logging operations that may have produced the state change