Workflows
A workflow is a plain async function marked
'use workflow'that orchestrates'use step'units. Each step runs once, persists its result, and retries on failure. The whole run survives crashes and redeploys, so it can pause for minutes, days, or months and resume where it stopped.
An agent holds an open-ended conversation. A workflow runs a fixed, auditable pipeline: validate, call a model, write a side effect. Stackbone takes the durability from the upstream Workflow SDK (the same engine behind Vercel Workflows) and runs it on a per-install Redis-backed runtime.
The execution model
- Two directives do the work.
'use workflow'on the function makes it durable and replayable.'use step'on a sub-function makes that unit run once, persist its result, and retry on failure. Every side effect belongs in a step. - The body must be deterministic, because the runtime replays it on every crash-resume. Keep it free of clocks, randomness, and direct I/O. Steps hold the real work, and the runtime replays their recorded results instead of re-running them.
- Only a step may touch the platform client. The body runs in an isolated
sandbox with no Node.js access, so reference
stackbone.*only inside a'use step'function. Onestackbone.*reference in the body, or in a helper the body calls, fails every workflow in the workspace at run time. - Sibling
inputSchemaandoutputSchemaZod exports are the workflow's typed contract. The runtime validates the input before a run starts. - Discovery is by convention. The runtime picks up any
workflows/<name>.workflow.ts, and the exported function is the camelCase name plusWorkflow. - One step has a time ceiling. It runs inside a single delivery to the
runtime, capped at 15 minutes by default. The runtime abandons a step that runs
past the ceiling and does not retry it. The abandoned copy may still be
running, and a retry would start a second one beside it. Raise
WORKFLOW_HTTP_TIMEOUT_MSon the deployment when a step needs longer, such as one long model call over a large input.
import { z } from '@stackbone/sdk';
export const inputSchema = z.object({ email: z.email(), company: z.string() });
export const outputSchema = z.object({ score: z.number(), qualified: z.boolean() });
export async function qualifyLeadWorkflow(input: z.infer<typeof inputSchema>) {
'use workflow';
const score = await scoreLead(input.company); // a durable step
return { score, qualified: score >= 60 };
}
async function scoreLead(company: string) {
'use step';
return company.length * 5;
}Kill the runtime mid-run and it resumes from the last completed step instead of replaying everything.
Where to go next
- Getting started: scaffold, trigger, and observe your first workflow, including long waits and approvals.
- Examples: an onboarding pipeline, a refund with a human approval, and a scheduled digest.
- Serial execution: make a workflow run one at a time, in arrival order, when two copies must never overlap.
- Workflow agents: let a step delegate to an agent.
- Human-in-the-loop: pause a run for a person to approve.