The store is Aether’s single source of truth. Every phase transition, input resolution, output merge, and timeout deadline is written throughDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/BabySid/aether/llms.txt
Use this file to discover all available pages before exploring further.
store.Store. The engine never caches state locally — it reads what it needs, mutates through the store, and trusts that the store’s version of reality is authoritative. This makes the engine restartable and, in distributed deployments, replaceable behind any consistent backend.
The Store interface
store.Store is an aggregated interface that composes four focused sub-interfaces plus a lifecycle method:
Sentinel errors
Two sentinel errors signal expected, non-exceptional conditions:fmt.Errorf("...: %w", store.ErrNotFound)) so callers can use errors.Is to distinguish them from infrastructure failures.
Optimistic concurrency: the Token model
All mutable records carry an opaqueuint64 field called Token. The framework passes the token it read from the last Get call into every subsequent Update call unchanged. The store implementation decides what this means:
- A monotonic counter (e.g. increment on every write) gives strict optimistic locking — mismatched tokens return
ErrTokenMismatch. - A no-op (always accept) is valid for single-threaded or test implementations.
MemoryStore uses a monotonic counter, incrementing Token on every successful update and returning ErrTokenMismatch if the token passed by the caller does not match the current stored value.
The token is opaque to the engine: it never interprets the numeric value. Your implementation defines the semantics — the engine only guarantees that it echoes back whatever token it last received.
WorkflowRunStore
Manages the lifecycle of workflow run records.Stores the initial workflow run record.
RunID must be unique; duplicates should return an error. Workflow (the raw JSON) and CreatedAt are set here and never modified again.Retrieves a workflow run by ID. Returns
ErrNotFound (wrapped) if missing. Return a copy — the caller may mutate the returned struct.Persists mutable fields. Only non-nil pointer fields in
run are written; nil fields are left unchanged (nil-field partial update convention). Must check run.Token against the stored token and return ErrTokenMismatch on mismatch. Returns the post-update state.Returns all non-terminal workflow runs that have a
Deadline set. Used by the timeout watchdog to detect overdue workflows.Removes a workflow run and all its associated
TaskRun records. Returns ErrNotFound if the run does not exist. Implementations must cascade-delete child task runs.Returns all
WorkflowRun records created by the given CronWorkflow. Used by the cron controller for concurrency policy checks and history cleanup.The WorkflowRun persistent model
TaskRunStore
Manages individual task execution records.CreateTaskRun idempotency contract
CreateTaskRun is idempotent by composite key: (workflowRunID, parentRunID, scope, taskName). If a task run with the same four-field key already exists, the implementation must return nil rather than an error or a duplicate. The engine relies on this contract for concurrent-safe scheduling — the scheduler may attempt to create the same task run multiple times under concurrent completion events.
The Scope field is part of the key because loop iterations share the same TaskName (the body template) but each receives a unique scope string (e.g. "poll-job.loop[0]/", "poll-job.loop[1]/").
Returns task runs sharing the same parent container.
parentRunID="" returns top-level tasks. This is the core scheduling query: advanceScope calls it to enumerate siblings within a single DAG or loop scope.Returns all non-terminal task runs (including pending ones) that have a
Deadline set. Pending tasks are included because the deadline is written at dispatch time, before OnTaskStarted transitions the run to Running.The TaskRun persistent model
TaskRun records form a parent-child tree via ParentRunID that mirrors the template nesting structure. This tree enables scoped scheduling (advanceScope only looks at sibling TaskRuns), variable isolation (each scope sees only its own sibling outputs), and upward propagation (when all children of a container complete, the container is finalized).
SchemaStore
Persists executor schemas for crash-recovery and distributed schema propagation.UpsertSchema inserts or overwrites a schema. workerID="" denotes an orphan record loaded during recovery. DeleteSchema accepts optional execType and workerID filters (empty = no restriction), combined with AND semantics — allowing GC eviction of stale executor types or cleanup when a worker goes offline.
CronWorkflowStore
Manages persistent records for scheduled (cron-based) workflows.ListCronWorkflows is called during engine.Start() to re-register all cron schedules after a crash or restart.
The nil-field partial update convention
BothUpdateWorkflowRun and UpdateTaskRun apply a nil-means-skip rule: only pointer fields that are non-nil in the update struct are written to the store. Nil fields are left unchanged. This avoids accidental overwrites when only a subset of mutable fields need updating.
Example (from MemoryStore):
Engine option
WithStore is required. The engine will panic at New() time if no store is provided.
Reference implementation: MemoryStore
The playgroundMemoryStore is a fully compliant, thread-safe in-memory implementation. It demonstrates every contract described above and is suitable for unit tests and single-process deployments.
MemoryStore:
Tokenis incremented on every successfulUpdatecall (existing.Token++).UpdateWorkflowRunandUpdateTaskRuncheckexisting.Token != run.Tokenand returnstore.ErrTokenMismatchon mismatch.CreateTaskRuncallstaskExistsLockedto check the composite key before inserting, returningnil(no error) on a duplicate.- All
Getmethods return copies of stored structs, including deep copies of pointer fields, to prevent callers from mutating internal state. DeleteWorkflowRuncascade-deletes allTaskRunrecords for the workflow run from bothtaskRuns,taskIndex, andparentIndex.
MemoryStore also records a full-state Snapshot after every mutating operation, enabling the playground’s HTML report to replay store history step-by-step — a useful pattern for debugging and audit logging.