Skip to content

Core Concepts

Invariant is built on eight foundational building blocks. Understanding these concepts will help you build reliable, event-sourced AI applications that scale without infrastructure brittleness.

1. workflow

A Workflow is a compiled, directed acyclic or looping graph that defines a business process or AI agent pipeline.

  • Immutability: Workflows compile down to an Invariant IR (Intermediate Representation) JSON schema v2.1. Once compiled, workflow logic cannot mutate mid-flight.
  • Identifiable: Identified by a unique string name (e.g., "customer-onboarding").

2. .step() (Deterministic Transformation)

A .step() represents pure, deterministic data manipulation.

  • Semantics: Must be pure functions (transforming state or input).
  • Execution Boundary: Evaluated directly in memory during ExecutionEngine.transition().
  • Constraint: Zero I/O allowed. No network calls, no database mutations, no random numbers or system clocks.
  • Replay Safety: Because .step() is pure, it can be re-evaluated 1,000 times during event log replay without side effects.
ts
workflow.step("calculate-total", async ({ state }) => {
  const subtotal = state.items.reduce((sum, item) => sum + item.price, 0);
  const tax = subtotal * 0.08;
  return { total: subtotal + tax };
});

3. .reason() (Probabilistic AI Boundary)

A .reason() step delegates a decision or structured generation to an LLM.

  • Semantics: Probabilistic computation.
  • Execution Boundary: The runtime emits a ReasonCommand. The LLM is invoked outside the state machine, and its structured JSON output re-enters as a durable CAPABILITY_COMPLETED event.
  • Schema Validation: Outputs are strictly validated against a Zod / TypeBox schema before state reduction occurs.
ts
workflow.reason("classify-sentiment", {
  prompt: ({ state }) => `Analyze customer message: "${state.userMessage}"`,
  schema: z.object({
    sentiment: z.enum(["POSITIVE", "NEUTRAL", "NEGATIVE"]),
    urgencyScore: z.number().min(1).max(5),
  }),
});

4. .capability() (Durable Side Effect Boundary)

A .capability() executes external I/O (Stripe API, SendGrid emails, SQL writes, vector searches, MCP tools).

  • Semantics: Imperative side effect crossing an execution boundary.
  • Execution Boundary: Transactional Outbox. Commands are written to workflow_outbox in the exact same DB transaction as the state update.
  • Idempotency: Every capability specifies an idempotencyKey formula (execution.id + step.id) to guarantee at-least-once execution safety.
ts
workflow.capability("send-slack-alert", {
  idempotencyKey: ({ execution }) => `slack-alert:${execution.id}`,
  handler: async ({ state }) => {
    return await slack.postMessage({
      channel: "#vip-alerts",
      text: `VIP User ${state.userId} requested assistance.`,
    });
  },
});

5. .wait() (Durable Suspension)

A .wait() step pauses workflow execution until an external condition or RuntimeEvent is received.

  • Semantics: Durable suspension boundary.
  • Execution Boundary: The engine sets run status to 'suspended' and releases all memory and CPU resources.
  • Resume Mechanism: Re-activated when an external event (webhook, user action, timer) matches the wait condition.
ts
workflow.wait("await-approval", {
  timeout: "48h", // Auto-triggers TIMER_FIRED if timeout expires
});

6. RuntimeEvent

An immutable record of something that happened in the world.

  • Durable Event Log: Events are appended sequentially with a monotonic integer seq per workflow run.
  • Public Domain Events: Examples include RUN_CREATED, INPUT_RECEIVED, CAPABILITY_COMPLETED, CAPABILITY_FAILED, TIMER_FIRED.
  • Note: RuntimeEvents are distinct from internal reducer operations (SET, MERGE, DELETE).

7. ExecutionState

The complete, accumulated state of a workflow run at a specific revision.

  • Derived: State is not arbitrarily edited; it is derived by reducing RuntimeEvents sequentially through state-reducer.ts.
  • Versioned: Every state commit increments revision monotonically (revision = expectedRevision + 1).

8. Execution (Workflow Run)

An active or completed instance of a workflow.

  • Run ID: Unique UUID (runId) identifying the single execution instance.
  • Lease Managed: Controlled by LeaseStore (worker_id, lease_expires_at) to guarantee single-worker concurrency and crash recovery.

Invariant Durable Execution Engine.