Overview
This page collects guidelines for structuring workflows. They are not requirements — a workflow that ignores all of them will still run — but following them makes workflows easier to operate, debug, and change.Keep Steps Small and Focused
Steps are the unit of retries, error handling, and observability. When a step fails, the whole step re-runs — so a step that performs one external action (one API call, one SQL write, one email) is much easier to retry safely than a step that performs five. Prefer:send-letter retries only the send — it does not regenerate the
letter or refetch the order.
Make Steps Safe to Re-run
Steps re-run in two situations: when they are retried after a failure, and when they resume after a suspension. Design step bodies so running them twice does not cause duplicate side effects:- Start steps that suspend with the resume guard:
if ctx.resume_data: return ctx.resume_data - Do reads and computation first; save external side effects (emails, faxes, database writes) for the end of the step — or better, their own step.
- For database writes, prefer upserts (
INSERT ... ON CONFLICT ... DO UPDATE) over plain inserts so a retried step does not create duplicate rows.
Pass Small Values Between Steps, Store Large State Elsewhere
Step outputs are stored and passed between steps as JSON (see Step Outputs). Keep them small and meaningful: IDs, statuses, and the few fields later steps actually need.- For documents, pass the document
idandfileNamerather than file contents. - For state that outlives the run (processing history, cross-run deduplication, reporting), use the database and pass row identifiers between steps.
Choose the Right Boundary Between Automation and Review
Screen steps are for judgment calls; normal steps are for everything else. A useful pattern is to compute a recommendation in an automated step, then let the screen present it for confirmation — rather than asking the user to do the analysis themselves. If a screen is approving the same thing every time, consider replacing it with a condition and only routing exceptional cases to a screen using conditionals.Split Large Automations into Multiple Workflows
A single workflow run works best when it represents a single unit of work — one order, one fax, one claim. When a process spans many records or stages, split it up:- Use an emitter workflow on a cron schedule to fan records out to a processor workflow — see Emitter Workflows.
- Use events to chain stages together, so each stage shows up as its own run with its own status and task list.
Organize Workflow Code as It Grows
The workflow template starts with everything insrc/workflow.py. As a
workflow grows, split it into modules and keep workflow.py focused on the
step graph itself:
workflow.py, which makes the workflow definition read like an outline of the
process.