Concepts: State & Durability
Invariant treats execution state as durable infrastructure, not ephemeral model memory.
"The model may forget. The runtime must not."
1. Execution State
Execution State (state) represents the accumulated progress of a single Workflow run.
Invariant persists that progress durably so later nodes—and recovered workers—continue from committed state rather than attempting to reconstruct context from model memory:
const workflow = app.workflow("refund", {
inputSchema: z.object({
orderId: z.string(),
}),
})
.capability("load-order", loadOrder)
.step("check-policy", ({ state }) => ({
eligible: state.order.ageDays <= 30,
}))
.capability("issue-refund", ({ state }) => {
// state.order and state.eligible came from previous node outputs
});input (orderId)
│
▼
load-order
│
├── state.order
▼
check-policy
│
├── state.eligible
▼
issue-refund2. Execution State Accumulates Through Node Outputs
Execution state is built incrementally as each graph node returns data:
.step("normalize-payload", () => ({
normalized: true,
}))
.step("calculate-totals", ({ state }) => {
// state.normalized is automatically typed and available
return { total: 100.00 };
})Node outputs accumulate into Execution State. Unlike initial parameters (input), which remain immutable throughout execution, state extends sequentially with every node execution.
3. Session Context vs. Execution State
It is essential to keep long-lived session context separate from workflow execution state:
| Feature | Session Context (session.context) | Execution State (state) |
|---|---|---|
| Scope | Across related activity & runs | One workflow run (runId) |
| Defined by | contextSchema & hydrate() | Workflow node outputs |
| Purpose | Durable continuity | Durable progress |
Canonical Home: For hydration, rehydration, and Session Context semantics, see Sessions & Hydration.
4. How State Becomes Durable (Event Reduction)
Execution State is not stored merely as a mutable database row. Invariant records the immutable facts (events) that produced it:
WORKFLOW_STARTED
│
▼
CAPABILITY_COMPLETED
{ order: { ageDays: 14 } }
│
▼
STEP_COMPLETED
{ eligible: true }
│
▼
CAPABILITY_COMPLETED
{ refundId: "rf_99" }
│
▼
WORKFLOW_COMPLETED
│ reduce (pure reducer)
▼
Materialized Execution State
{
order: { ageDays: 14 },
eligible: true,
refundId: "rf_99"
}State is derived deterministically by passing historical execution events through pure reducers.
5. Execution Event History
Every execution-relevant fact is represented durably in the execution history with a strictly monotonic sequence number (seq = 1..n):
WORKFLOW_STARTEDCAPABILITY_REQUESTEDCAPABILITY_COMPLETEDSTEP_COMPLETEDREASON_COMPLETEDWAIT_ENTEREDINPUT_RECEIVEDWORKFLOW_COMPLETED
Event History Properties
- Append-Only Execution History: Committed execution events are not rewritten as part of normal runtime execution. Payload retention or redaction may be governed separately by storage policy.
- Monotonic Ordering: Events within an execution have strictly increasing sequence numbers (
seq). - Data Provenance: Events preserve the execution facts and metadata required for auditing and replay, subject to configured payload retention or redaction policy.
6. Materialization & Storage Decoupling
Invariant decouples execution fact persistence from state materialization:
- Execution Event History — The immutable source of execution facts.
- Materialized Execution State — Current derived state persisted for fast runtime access.
- Snapshots / Checkpoints — Optional storage optimizations for long event histories to accelerate worker recovery without altering the event log.
7. State & External Effects (Idempotency)
The state transition and the intent to perform an external effect are committed atomically. The effect itself executes afterward through the Outbox worker:
Atomic Transaction (BEGIN...COMMIT)
├── Execution State
├── Execution Event
└── Capability Intent
│
▼
Outbox Worker
│
▼
External SystemAt-Least-Once Dispatch
│
▼
Stable Idempotency Key (e.g. `refund:${execution.id}`)
│
▼
External System Honors Key?
┌────┴────┐
yes no
│ │
▼ ▼
Effectively At-Least-Once
Once InvocationCapabilities supply stable idempotency keys across retries. Invariant guarantees repeatable intent, but effectively-once external side effects require the target API to honor idempotency keys.
"Invariant guarantees repeatable intent, not exactly-once effects in systems it does not control."
8. Crash Recovery Without AI Memory Reconstruction
When a worker crashes, Invariant does not ask the LLM to reconstruct execution history or re-run already committed reasoning results. Pending external effects may be retried according to their durable Outbox state and idempotency policy:
Worker Crash / Process Restart
│
▼
Read Event History facts
│
▼
Reconstruct Execution State
│
▼
Resume from last committed execution stateWorker recovery resumes execution directly from committed durable facts.
Go Deeper
- Durability Guarantees — Explore the 7 core invariants of the runtime engine.
- Execution Model — Inspect the durable event-driven loop and transactional outbox pipeline.
- Sessions & Hydration — Learn how long-lived application context is hydrated.