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.

ByteTypeSerialized NamePurpose
0x01BeliefbeliefStructured knowledge triple (subject/relation/object)
0x02EventeventTimestamped occurrence or message
0x03StatestateAgent state snapshot or checkpoint
0x04WorkflowworkflowDirected-graph procedural plan (nodes + edges)
0x05ActionactionTool invocation or operation record
0x06ObservationobservationCognitive observer perception
0x07GoalgoalAgent objective with satisfaction criteria
0x08ReasoningreasoningInference chain and thought audit trail
0x09ConsensusconsensusMulti-agent agreement record
0x0AConsentconsentDID-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 either endpoint. The /add endpoint accepts any grain type but is optimized for Belief grains — it defaults to grain_type: "belief" and accepts a flat {subject, relation, object} body. For other grain types, pass grain_type plus the type-specific keys (e.g. content for an event, description for a goal); unrecognized fields are forwarded via the fields map. The /batch-add endpoint shares the same write pipeline and is preferred when 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 commonly use /add with a flat JSON body; other types may use either /add (with explicit grain_type) or /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 graph index
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 graph index 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, optional bindings, retries, and a trigger.
  • 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 let you model business time (valid_from, valid_to, temporal_type) separately from storage time (system_valid_from, system_valid_to).

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.

FieldTypeDefaultDescription
namespacestringnullLogical grouping for scoped queries
user_idstringnullOwner user ID for access control and erasure
tagsstring[][]Searchable labels
confidencefloat1.0Trust score from 0.0 to 1.0
source_typestringnullOrigin indicator (e.g., "user", "agent", "system")
importancefloatnullPriority weight for recall ranking
temporal_typestringnullBi-temporal model: "state", "event", or "interval"
valid_fromintnullStart of business validity (Unix timestamp)
valid_tointnullEnd of business validity (Unix timestamp)
system_valid_fromintnullStart of storage (transaction) time — when the grain became known to the system (Unix timestamp)
system_valid_tointnullEnd of storage (transaction) time — when the grain was superseded in storage (Unix timestamp)
verification_statusstringnull"unverified", "verified", "contested", or "retracted"
embedding_textstringnullCustom text override for vector embedding (max 8192 bytes)
related_toobject[][]Links to other grains by hash with relation type and weight
content_refsobject[][]References to external content (URIs, MIME types, checksums)
superseded_bystringnullHash of the grain that replaced this one
supersession_justificationstringnullHuman-readable reason this grain was superseded
supersession_authobject[]nullAuthorization records backing the supersession
invalidation_policyobjectnullProtection rules for regulated grains
embedding_refsobject[][]References to stored vector embeddings for this grain
provenance_chainobject[][]Ordered record of how this grain was derived
derived_fromstringnullHash of the grain this one was derived from
author_didstringnullDecentralized identifier (DID) of the author
origin_didstringnullDID of the originating agent or system
origin_namespacestringnullNamespace the grain originated in
consolidation_levelintnullMemory-consolidation tier, raised as a grain is reinforced
success_countintnullTimes this grain (e.g. an Action) has succeeded
failure_countintnullTimes this grain has failed
contextobjectnullArbitrary structured context attached to the grain
created_atintnullCreation timestamp (Unix)
extra_fieldsobject{}Custom fields preserved through the serialization round-trip

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, but only the canonical OMS 1.2 names are accepted — the old OMS 1.1 type names are rejected.

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). Areev accepts only the 10 canonical OMS 1.2 lowercase names (belief, event, state, workflow, action, observation, goal, reasoning, consensus, consent); the old OMS 1.1 type names (fact, episode, checkpoint, toolcall) are rejected with a 400 “unknown grain type” error, and the old Action field names (arguments, result, success) are ignored. There is no deprecation-warning mechanism — update any existing code to the canonical names.

  • Belief: Structured knowledge triples indexed in the graph index
  • Event: Timestamped occurrences and messages
  • State: Agent state snapshots with supersession
  • Action: Tool invocations with input, output, and error tracking