Workflow Grain
What is a Workflow grain?
A Workflow grain encodes a procedural plan as a directed graph — nodes representing steps and edges defining the flow between them. Workflows turn implicit procedures into explicit AI memory that agents retrieve and execute when the right conditions arise.
Each workflow carries a nodes array of string labels, an edges array defining directed connections between nodes, and an optional trigger string describing when the procedure activates. The context database indexes the trigger text and node labels for BM25 and vector search, so agents can recall relevant workflows by describing the situation they face. Workflows without a trigger rely on tag-based or namespace-based queries for retrieval.
The directed graph model supports linear sequences, conditional branching (via cond on edges), parallel execution, and retry loops (via retries). Node labels are both IDs and human-readable names. The bindings map links nodes to Action grain hashes, connecting the plan to concrete tool definitions. For AI agent memory systems that manage complex processes, workflows provide the reusable procedure layer that sits between goals (“what to achieve”) and actions (“what was executed”).
| Field | Type | Required | Description |
|---|---|---|---|
nodes | string[] | no | Node IDs/labels in the graph (must be unique) |
edges | object[] | no | Directed edges between nodes (each with src, dst, optional cond and max_cycles) |
bindings | object | no | Map of node ID to Action grain hash |
retries | object | no | Map of node ID to max retry count on failure |
trigger | string | no | Condition or event that activates this workflow |
Plus all common fields (confidence, tags, namespace, etc.).
How do I create a Workflow?
Pass the nodes array, edges array, and optional trigger through the /batch-add endpoint with grain_type: "workflow". Define node labels as strings and edges as objects with src and dst referencing node IDs.
Design your graph to match how your agent will execute the procedure. Linear sequences use a chain of edges from one node to the next. Conditional branching uses the cond field on edges to specify when a path is taken. Use bindings to link nodes to Action grain hashes so the executor knows which tool to invoke at each step. The trigger field should describe the activation condition in natural language so that BM25 and vector search can match it during recall.
Use tags to categorize workflows by domain (e.g., "e-commerce", "onboarding", "incident-response") and namespace to scope them to a project or team. The confidence common field can indicate how well-tested a workflow is — a newly created workflow might start at 0.5 and increase to 1.0 after successful executions.
import areev
db = areev.open("./data")
h = db.add("workflow", {
"nodes": ["check_inventory", "reserve_stock", "send_confirmation"],
"edges": [
{"src": "check_inventory", "dst": "reserve_stock"},
{"src": "reserve_stock", "dst": "send_confirmation"}
],
"trigger": "new order received"
})
POST /api/memories/default/batch-add
Content-Type: application/json
{
"grains": [
{
"grain_type": "workflow",
"fields": {
"nodes": ["check_inventory", "reserve_stock", "send_confirmation"],
"edges": [
{"src": "check_inventory", "dst": "reserve_stock"},
{"src": "reserve_stock", "dst": "send_confirmation"}
],
"trigger": "new order received"
}
}
]
}
areev add workflow trigger="new order received" nodes='["check_inventory","reserve_stock","send_confirmation"]' edges='[{"src":"check_inventory","dst":"reserve_stock"},{"src":"reserve_stock","dst":"send_confirmation"}]'
How do I query Workflows?
Search by trigger text, tags, or namespace using the standard /recall endpoint. The text representation for embedding and BM25 indexing is the trigger (if set) combined with node labels joined by arrows: "new order received | check_inventory -> reserve_stock -> send_confirmation". This lets agents recall workflows by both their activation condition and their step names.
When multiple workflows match a query, BM25 and vector scores determine the ranking. Use grain_type: "workflow" to exclude other grain types from results. If you tag workflows consistently (e.g., "incident-response", "customer-support"), tag-based filtering provides deterministic results without relying on text similarity.
Workflows without a trigger field and with no nodes have no text representation and will not appear in text-based queries. Query them by tag, namespace, or hash instead.
# Find workflows by trigger description
results = db.recall(query="order received", grain_type="workflow")
# Find all workflows tagged for a specific domain
results = db.recall(grain_type="workflow", tags="e-commerce")
POST /api/memories/default/recall
Content-Type: application/json
{"query": "order received", "grain_type": "workflow", "limit": 5}
areev recall --query "order received" --grain-type workflow
When should I use Workflow vs. Action?
A Workflow is a plan — a directed graph of steps to be followed. An Action is a record of a single step that was already executed.
A common pattern is to store a Workflow describing the procedure with bindings linking nodes to Action grain hashes, then log individual Action grains as each step completes, linking them back to the workflow via the related_to common field or parent_task_id. This gives you both the intended plan and the actual execution history, which is useful for debugging when outcomes diverge from expectations.
Use Goal to define the objective a workflow is designed to achieve. The three-layer pattern — Goal (what), Workflow (how), Action (did) — provides full traceability from objective through plan to execution.
Related
- Grain Types: Overview of all 10 OMS grain types and shared fields
- Action: For recording individual step executions
- Goal: For the objective a workflow is designed to achieve
- Reasoning: For the inference chain that produced the workflow