Code Flow
Code Flow is one of Orvanta’s flow authoring models, alongside the node-based DAG Flow canvas and BPMN Flow. Instead of wiring nodes on a canvas, you write a single orchestration function in Python or TypeScript and mark it and its steps with a small set of decorators/wrappers. Orvanta checkpoints each step so the function can suspend, hand its worker slot back, and resume exactly where it left off.
The core API
Section titled “The core API”-
Mark the orchestration function
Python uses the
@workflowdecorator; TypeScript wraps the function withworkflow().from orvanta import workflow, task@taskasync def extract(url: str):...@workflowasync def main(url: str):data = await extract(url)return dataimport { workflow, task } from "orvanta";const extract = task(async (url: string) => {// ...});export const main = workflow(async (url: string) => {const data = await extract(url);return data;}); -
Mark each unit of work
Python uses
@task(or@task(path=..., timeout=..., tag=..., ...)for options); TypeScript usestask(fn, options?). A task called from inside a workflow dispatches as a checkpointed step rather than running inline. -
Call other runnables as tasks
task_script(path, ...)/taskScript(path, options?)dispatch to an existing Orvanta script by path.task_flow(path, ...)/taskFlow(path, options?)dispatch to an existing flow. Both return a callable you invoke like any other task inside the workflow.
Determinism and replay
Section titled “Determinism and replay”A @workflow/workflow() function must be deterministic: given the same inputs, it must call tasks in the same order on every replay. Branching on a task’s result is fine — results are served from the checkpoint on replay. Branching on external state (the current time, randomness, an uncheckpointed API call) is not, because the replay would see different values than the original run and diverge from the recorded step sequence.
To checkpoint a plain value without spawning a task, use step(name, fn). It runs fn inline once, stores the result in the checkpoint, and on replay returns the cached value without re-running fn.
Execution model
Section titled “Execution model”Each task runs as a separate job, with its own logs and its own entry in the run’s timeline — the same visibility you get from a node in a DAG Flow, not a single merged log stream for the whole function.
Between dispatching a task and receiving its result, the parent workflow suspends and releases its worker slot. It doesn’t hold a worker idle while a task runs; it resumes (replaying completed steps from the checkpoint) once the task completes. This is what lets a Code Flow orchestrate long-running or highly parallel work without pinning a worker for the whole duration.
Other primitives follow the same suspend/checkpoint model:
sleep(seconds)— suspends the workflow for a duration without holding a worker, then auto-resumes.wait_for_approval(...)/waitForApproval(...)— suspends until an external approval is recorded.parallel(items, fn, concurrency?)— dispatchesfn(a task) over a list of items in concurrency-limited batches.
When to use Code Flow instead of DAG Flow
Section titled “When to use Code Flow instead of DAG Flow”Reach for Code Flow when the orchestration logic is easier to express as a program than as a graph — dynamic branching, loops with non-trivial exit conditions, or dispatching a variable number of tasks computed at runtime. Reach for DAG Flow when the shape of the flow is fixed and the visual canvas is the more legible representation.
Code Flow still produces the same kind of durable artifact described in Flows as artifacts — the difference is how you author it, not whether it’s version-controlled or reviewable.
See also
Section titled “See also”- Choosing a flow authoring model: DAG Flow vs BPMN Flow vs Code Flow, compared.
- Flows as artifacts: The artifact model every flow — DAG, BPMN, or Code Flow — compiles to.
- Workflows: DAG Flow’s node-based structure.
- Jobs and runs: How individual task jobs show up in a run’s timeline.