Introduction
Invariant is a TypeScript framework for building reliable AI agents and workflows.
It gives AI models room to reason while keeping application state, execution, side effects, and recovery under deterministic control.
const refund = app.workflow("refund")
.step("load-customer", loadCustomer)
.reason("check-policy", {
prompt: ({ state }) =>
`Should this ${state.tier} customer receive a refund?`,
schema: z.object({
approved: z.boolean(),
amount: z.number(),
}),
})
.capability("issue-refund", issueRefund);The model decides whether the refund should happen.
Invariant makes sure the workflow can actually finish reliably.
Models reason. Infrastructure executes.
LLMs are exceptionally useful reasoning engines, but they are not execution engines.
They should not be responsible for remembering where an application is, reconstructing state from conversation history, deciding whether an external operation already happened, or recovering execution after a process disappears.
Invariant separates these responsibilities.
Models reason.
LLMs operate inside controlled reasoning boundaries. In workflows, those boundaries are explicit .reason() steps. In agents, they are individual agent turns constructed from projected session and execution context.
Infrastructure executes.
Invariant owns durable state, workflow transitions, side effects, retries, waiting, idempotency, and recovery.
This separation applies to both predefined workflows and autonomous or conversational agents.
A conversational agent can reason about what should happen next, while Invariant keeps track of the active session, running workflows, expected input, and the actions available at that point in the execution.
The model doesn't need to carry the application in its context.
The runtime already knows where it is.
Why this architecture matters
Production agents tend to encounter three related problems as they grow: context cost, unreliable model behavior, and limited observability.
Invariant addresses all three by moving application responsibility out of the model context and into the runtime.
1. Send less context to the model
A long-running agent can accumulate conversation history, tool results, customer data, workflow progress, previous decisions, and execution metadata.
A conventional agent may repeatedly send large portions of that information back to the model:
Invariant keeps the complete execution state outside the model.
- In a workflow, context projection is explicit: the
promptorcontextfunction selects the state required by a.reason()step. - In a conversational agent, Invariant automatically derives context from the active session and workflow position—including relevant state, expected input, and available runtime actions.
For a sentiment decision, that might be nothing more than:
workflow.reason("classify-sentiment", {
prompt: ({ state }) =>
`Classify message: "${state.userMessage}"`,
schema: z.object({
sentiment: z.enum([
"POSITIVE",
"NEUTRAL",
"NEGATIVE",
]),
score: z.number().min(0).max(1),
}),
});The model doesn't need the entire execution history to classify one message. Less unnecessary context means fewer input tokens, smaller prompts, and a clearer reasoning surface.
2. Constrain hallucinations instead of trusting them
Invariant does not attempt to make probabilistic models deterministic.
Invariant doesn't try to make the model less probabilistic. It makes fewer application guarantees depend on probabilistic reasoning.
The model can make a decision:
{
"approved": true,
"amount": 75
}The model should not be responsible for answering infrastructure questions:
- "Did I already charge the card?"
- "Which workflow node am I in?"
- "Did that API call succeed?"
- "Should I retry this operation?"
- "What state should I mutate?"
Its output is validated against a schema and returned to the deterministic runtime.
For conversational agents, the runtime exposes only the actions relevant to the current state. The model reasons within those boundaries instead of controlling arbitrary execution.
This does not eliminate hallucinations—it constrains their blast radius.
3. Observe decisions and execution separately
When reasoning, tool calls, state mutation, and application control all happen inside an agent loop, understanding why something happened becomes difficult.
Invariant makes those boundaries explicit.
An execution can be reconstructed as a sequence such as:
This creates two distinct kinds of observability:
- Reasoning observability: What context did the model receive? Which model was used? What structured decision did it produce? How many tokens were consumed?
- Execution observability: Which state transition happened? Which capability was executed? Was it retried? Where did an execution fail?
Two ways to build
Agents and workflows are not competing abstractions. Workflows define reliable execution paths; agents can decide when and how to drive them. Both run on the same durable runtime.
1. Durable workflows
Use workflows when the execution path should be explicit.
app.workflow("refund")
.step(...)
.reason(...)
.capability(...)
.wait(...);Deterministic computation, probabilistic reasoning, external effects, and durable waiting have explicit boundaries.
2. Agents & Sessions
Use agents when the model should decide what happens next.
app.agent("support", {
workflows: [
refundWorkflow,
cancelSubscriptionWorkflow,
updateAccountWorkflow,
],
});Sessions give agents continuity across turns, channels, and workflow executions. A session can outlive any individual workflow run and provides the durable context from which each agent turn is projected.
On every turn, Invariant projects the context relevant to the current execution position instead of replaying the entire application state into the model.
Built for failure
AI applications interact with unreliable things: models time out, APIs fail, workers restart, users disappear for hours, and processes crash between external side effects.
Invariant is designed around those conditions.
Executions are persisted as durable events. State transitions are deterministic. External effects cross explicit execution boundaries. Work can be resumed after interruption without asking the model to reconstruct what happened from a conversation transcript.
The result is an architecture where probabilistic reasoning can remain probabilistic without making the rest of your application probabilistic.
Start building
Continue with the Mental Model to understand the core architecture: Application → Workflow → Agent → Session → Execution → Capability.
Or jump directly into the Quick Start and build your first durable AI workflow.