Grain Types
What are grain types?
Every memory stored in the Areev context database is classified as one of 10 grain types defined by the Open Memory Schema (OMS) 1.2. The grain type determines which fields a memory carries, how it is indexed, and how AI agent memory recall surfaces it in queries.
Grain types enforce structure at the storage layer. When you write a grain, Areev validates the type-specific fields, serializes the grain into the .mg binary format with a single-byte type header, and indexes it for retrieval. When you recall grains, the type constrains which fields are available for filtering and how the text representation is built for BM25 and vector search. This structure is what separates an autonomous memory system from an untyped key-value store: each grain carries semantic meaning that agents can reason over.
The 10 types cover the full lifecycle of agent cognition — from perceiving the world (Observation) to forming knowledge (Belief), making decisions (Reasoning, Consensus), taking action (Action, Workflow), tracking objectives (Goal), managing state (State, Event), and handling compliance (Consent). The first seven types originated in OMS 1.1 under different names; Reasoning, Consensus, and Consent were introduced in OMS 1.2.
| Byte | Type | Serialized Name | Purpose |
|---|---|---|---|
0x01 | Belief | belief | Structured knowledge triple (subject/relation/object) |
0x02 | Event | event | Timestamped occurrence or message |
0x03 | State | state | Agent state snapshot or checkpoint |
0x04 | Workflow | workflow | Directed-graph procedural plan (nodes + edges) |
0x05 | Action | action | Tool invocation or operation record |
0x06 | Observation | observation | Cognitive observer perception |
0x07 | Goal | goal | Agent objective with satisfaction criteria |
0x08 | Reasoning | reasoning | Inference chain and thought audit trail |
0x09 | Consensus | consensus | Multi-agent agreement record |
0x0A | Consent | consent | DID-scoped permission grant or withdrawal |
How do I add a grain to the context database?
Pass the grain_type string and the type-specific fields to the appropriate endpoint. The /add endpoint is reserved for Belief grains and indexes subject/relation/object in the hexastore for graph traversal. The /batch-add endpoint accepts any grain type and supports writing multiple grains in a single request.
When using the Python SDK, db.add() accepts the grain type as its first argument and a dict of type-specific fields as its second argument. The method returns a content-address hash that uniquely identifies the grain. For HTTP, Belief grains use /add with a flat JSON body; all other types use /batch-add with a grains array where each entry specifies grain_type and fields.
Areev validates fields against the OMS 1.2 schema before writing. Required fields that are missing cause a 400 error. Optional fields default to null or their documented defaults (for example, goal_state defaults to "active").
import areev
db = areev.open("./data")
# Belief -- triple-indexed in the hexastore
db.add("belief", {"subject": "john", "relation": "likes", "object": "coffee"})
# Event -- free-text content
db.add("event", {"content": "User completed onboarding"})
# Action -- tool call with result
db.add("action", {"tool_name": "web_search", "input": {"q": "weather"}, "content": "72F sunny"})
POST /api/memories/default/add
Content-Type: application/json
{"subject": "john", "relation": "likes", "object": "coffee"}
POST /api/memories/default/batch-add
Content-Type: application/json
{
"grains": [
{"grain_type": "event", "fields": {"content": "User completed onboarding"}},
{"grain_type": "action", "fields": {"tool_name": "web_search", "content": "72F sunny"}}
]
}
Which grain type should I use?
Choose based on what the memory represents, not how you plan to query it.
- Storing knowledge claims (who/what/how relationships) — use Belief. Its subject/relation/object triple is indexed in the hexastore for graph queries.
- Recording things that happened (messages, logs, conversations) — use Event. Events are optimized for temporal queries.
- Saving agent checkpoints (session state, config snapshots) — use State. States carry arbitrary JSON and support supersession for updates.
- Encoding procedures (runbooks, multi-step plans) — use Workflow. Workflows are directed graphs with
nodes,edges, optionalbindings,retries, and atrigger. - Logging tool calls (API calls, code execution, computer use) — use Action. Actions track tool name, input, output, errors, and duration.
- Capturing perceptions (sensor data, LLM observations, multi-agent views) — use Observation. Observations track observer identity and scope.
- Tracking objectives (tasks, targets, milestones) — use Goal. Goals have state transitions (active/satisfied/failed/suspended) and priority levels.
- Preserving inference chains (decision audit trails, thought traces) — use Reasoning. Reasoning grains store premises, conclusions, and alternatives.
- Recording multi-agent decisions (votes, quorum outcomes) — use Consensus. Consensus tracks participating observers, agreement/dissent counts, and thresholds.
- Managing permissions (data-subject consent, access grants) — use Consent. Consent grains are DID-scoped and purpose-bounded for compliance.
What fields do all grains share?
Every grain type inherits a set of common fields from GrainCommon in addition to its type-specific fields. These common fields control indexing, access, temporal validity, and inter-grain relationships across the entire AI memory system.
The confidence field (0.0 to 1.0) lets agents express certainty. The namespace and tags fields scope queries and organize grains into logical groups. The superseded_by field and supersession mechanism support immutable updates — rather than modifying a grain in place, you create a new version and link the old grain to it. Bi-temporal fields (valid_from, valid_to, temporal_type) let you model business time separately from storage time.
Fields like related_to and content_refs create explicit links between grains and to external resources. The verification_status field tracks whether a grain has been independently verified, contested, or retracted. The invalidation_policy field protects regulated grains from premature deletion.
| Field | Type | Default | Description |
|---|---|---|---|
namespace | string | null | Logical grouping for scoped queries |
user_id | string | null | Owner user ID for access control and erasure |
tags | string[] | [] | Searchable labels |
confidence | float | 1.0 | Trust score from 0.0 to 1.0 |
source_type | string | null | Origin indicator (e.g., "user", "agent", "system") |
importance | float | null | Priority weight for recall ranking |
temporal_type | string | null | Bi-temporal model: "state", "event", or "interval" |
valid_from | int | null | Start of business validity (Unix timestamp) |
valid_to | int | null | End of business validity (Unix timestamp) |
verification_status | string | null | "unverified", "verified", "contested", or "retracted" |
embedding_text | string | null | Custom text override for vector embedding (max 8192 bytes) |
related_to | object[] | [] | Links to other grains by hash with relation type and weight |
content_refs | object[] | [] | References to external content (URIs, MIME types, checksums) |
superseded_by | string | null | Hash of the grain that replaced this one |
invalidation_policy | object | null | Protection rules for regulated grains |
How did grain type names change from OMS 1.1 to 1.2?
OMS 1.2 renamed four grain types from OMS 1.1 to better reflect their semantics. The byte codes remain the same, and Areev accepts both old and new names during a transition period.
The renames are: Fact became Belief (0x01), Episode became Event (0x02), Checkpoint became State (0x03), and ToolCall became Action (0x05). The Action grain also changed three field names: arguments became input, result became content, and success became is_error (with inverted boolean logic — success: true maps to is_error: false). If you have existing code using OMS 1.1 names, update to the new names to avoid deprecation warnings.