Quick Start
Build and run your first durable AI workflow in a few minutes.
1. Install
Install the core Invariant packages:
npm install @invariant/sdk @invariant/runtime @invariant/postgres @invariant/anthropic zodStart PostgreSQL locally with Docker:
docker run \
--name invariant-postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=invariant \
-p 5432:5432 \
-d postgres:17Set your environment variables:
export DATABASE_URL=postgres://postgres:postgres@localhost:5432/invariant
export ANTHROPIC_API_KEY=your_anthropic_api_key2. Create the Runtime
Initialize invariant with a storage adapter and model provider configuration:
// src/runtime.ts
import { invariant } from "@invariant/sdk";
import { postgres } from "@invariant/postgres";
import { anthropic } from "@invariant/anthropic";
export const app = invariant({
store: postgres({
connectionString: process.env.DATABASE_URL!,
}),
models: {
default: anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
model: "claude-sonnet-4-5",
}),
},
});Invariant is model-agnostic. The default model is automatically used by .reason() boundaries unless a step explicitly chooses another configured model.
3. Define a Workflow
Define a Support Ticket Workflow. Workflows declared via app.workflow() are automatically bound to the application instance:
// src/ticket.ts
import { z } from "zod";
import { app } from "./runtime";
export const supportWorkflow = app
.workflow("support-ticket", {
inputSchema: z.object({
message: z.string(),
userTier: z.enum(["STANDARD", "VIP"]),
}),
})
// 1. Probabilistic Reasoning (AI)
.reason("classify-ticket", {
prompt: ({ input }) =>
`Classify this support message: "${input.message}"`,
schema: z.object({
category: z.enum(["BILLING", "TECHNICAL", "ACCOUNT", "OTHER"]),
sentiment: z.enum(["POSITIVE", "NEUTRAL", "NEGATIVE"]),
}),
})
// 2. Deterministic Application Logic (Code)
.step("set-priority", ({ state, input }) => ({
priority:
input.userTier === "VIP" || state.sentiment === "NEGATIVE"
? "HIGH"
: "NORMAL",
}))
// 3. Controlled Side-Effect (External Action)
.capability("create-ticket", {
idempotencyKey: ({ execution }) => `ticket:${execution.id}`,
handler: async ({ state, input }) => {
console.log(`🎫 Creating ticket [${state.priority}] (${state.category})`);
return {
ticketId: `tkt_${Date.now()}`,
status: "OPEN",
assignedTeam: state.category === "BILLING" ? "Finance" : "Support",
};
},
});The three primitives represent a clear execution sequence:
reason() Probabilistic interpretation ──► "What does this mean?"
step() Deterministic application logic ──► "What should our code derive from it?"
capability() Controlled external effect ──► "Do something in the external world"4. Start the Runtime & Run
Start the background worker loop and execute your workflow:
// src/index.ts
import { app } from "./runtime";
import { supportWorkflow } from "./ticket";
async function main() {
await app.start();
const run = await supportWorkflow.start({
message: "I was double charged on my subscription and need an urgent refund!",
userTier: "VIP",
});
console.log(`🚀 Started workflow run: ${run.id}`);
const result = await run.result();
console.log("Execution Result:", result);
await app.stop();
}
main().catch(console.error);Run it using npx tsx:
npx tsx src/index.tsWhat Just Happened?
User message
│
reason() ──► classify-ticket (AI interprets sentiment & category)
│
step() ──► set-priority (Code calculates priority based on VIP tier & sentiment)
│
capability() ──► create-ticket (External system creates ticket)You just combined probabilistic reasoning, deterministic application logic, and an external side effect in one durable execution.
.reason()asked the model one bounded semantic question..step()applied deterministic application logic without model involvement..capability()crossed into the external world through a transactional outbox.- Invariant preserved execution state durably between every boundary.
Next Steps
- Mental Model — Understand how Workflows, Agents, and Executions fit together.
- Agents & Actions — Learn how an
app.agent()can evaluate user intent to drive workflows automatically. - Crash Recovery Example — Test what happens when you kill a worker process mid-execution.