Skip to main content
Workflows

Automate agent work that outlives a process.

Durable workflows built on Rivet Actors. Steps record their results, wait for people or systems, and resume after crashes and deploys.

Start the quickstart

run_01JQ6R8T

  1. Issue received

    Recording event input

    Active
  2. Agent edits repository

    Not started

    Pending
  3. Run test suite

    Not started

    Pending
  4. Wait for approval

    Not started

    Pending
  5. Record result

    Not started

    Pending

Workflow is running.

Regular TypeScript, durable progress.

import { actor, setup } from "rivetkit";
import { type WorkflowStepContextOf, workflow } from "rivetkit/workflow";
 
export const invoiceActor = actor({
  state: {
    invoiceId: null as string | null,
    subtotal: 0,
    tax: 0,
    total: 0,
    status: "idle" as "idle" | "complete",
  },
  run: workflow(async (ctx) => {
    const subtotal = await ctx.step("load-subtotal", async (ctx) =>
      loadSubtotal(),
    );
 
    const tax = await ctx.step("calculate-tax", async (ctx) =>
      calculateTax(subtotal),
    );
 
    await ctx.step("save-invoice", async (step) =>
      saveInvoice(step, subtotal, tax),
    );
  }),
  actions: {
    getState: (c) => c.state,
  },
});
 
async function loadSubtotal(): Promise<number> {
  const response = await fetch("https://api.example.com/carts/main");
  if (!response.ok) {
    throw new Error(`load subtotal failed: ${response.status}`);
  }
  const cart = (await response.json()) as { subtotal: number };
  return cart.subtotal;
}
 
async function calculateTax(subtotal: number): Promise<number> {
  const response = await fetch("https://api.example.com/tax/quote", {
    method: "POST",
    headers: {
      "content-type": "application/json",
    },
    body: JSON.stringify({ subtotal }),
  });
  if (!response.ok) {
    throw new Error(`tax quote failed: ${response.status}`);
  }
  const quote = (await response.json()) as { tax: number };
  return quote.tax;
}
 
async function saveInvoice(
  ctx: WorkflowStepContextOf<typeof invoiceActor>,
  subtotal: number,
  tax: number,
): Promise<void> {
  const total = subtotal + tax;
  const response = await fetch("https://api.example.com/invoices", {
    method: "POST",
    headers: {
      "content-type": "application/json",
    },
    body: JSON.stringify({ subtotal, tax, total }),
  });
  if (!response.ok) {
    throw new Error(`save invoice failed: ${response.status}`);
  }
  const invoice = (await response.json()) as { id: string };
  ctx.state.invoiceId = invoice.id;
  ctx.state.subtotal = subtotal;
  ctx.state.tax = tax;
  ctx.state.total = total;
  ctx.state.status = "complete";
}
 
export const registry = setup({ use: { invoiceActor } });

A run per user, session, or agent

Address each workflow by key; every run keeps its own state, queue, and history.

State beside the steps

Steps read and write the run's durable state in-process.

Waiting costs nothing

A run blocked on a queue wait or timer sleeps until the message or deadline arrives.

Progress in realtime

Broadcast step progress to connected clients as it happens.

Wait, branch, and recover.

Pause for approval, fan out, retry. Every step is recorded.

StepWaitApprovedretryStep

Read about queue waits, timers and concurrency, and failure and recovery.

Automate agent work.

The workflow gives an agent a computer and records every step.

Agent’s computer

filesshellnetwork

Every step recorded

Read about agent patterns or view the source.

Evolve running work.

Deploy new code mid-run. Old runs keep their version; new runs take the latest.

deploy v2
Running before the deploy
v1
Started after
v2

Read about versioning.

See the history behind every run.

Step history

Every step's status, from pending through complete or failed.

Timing and retries

Durations, attempt counts, backoff delays, and terminal errors.

Inputs and outputs

The recorded values each step received and returned.

Replay

Re-run eligible steps after the underlying problem is fixed.

Rivet workflow inspector showing a run history with nested steps, statuses, durations, and recorded details

Develop locally. Deploy your way.

Local

Install Workflows and run it locally while you build.

Open the quickstart

Rivet Cloud

Deploy Workflows on Rivet Cloud with managed infrastructure and persisted Actor data.

Open the dashboard

Self-Host

Run the open-source Rivet control plane as a Rust binary or container on your infrastructure.

Read self-hosting docs

Frequently asked questions

Ship a workflow that survives its first restart.

Read the documentation or explore the Apache 2.0 source.