output={outputs.someKey} is the canonical schema path. outputs comes from
the same createSmithers(...) call as the workflow, and each value is the exact
Zod schema object you registered. When a Task renders, Smithers uses that object
as the output target, infers outputSchema, passes it to native
structured-output agents, validates the returned row, and persists it to the
matching output table. You only need outputSchema={...} when output is a
custom Drizzle table or string key and Smithers cannot infer the Zod schema.
Three task modes: agent, compute, static
Thechildren shape decides what a Task does. No agent prop is needed for the
compute and static modes.
- Agent (
agent={...}, children is a prompt string or(deps) => string): runs the agent, parses its output against the schema, persists. - Compute (no
agent, children is a function returning a value): runs your code. The function may beasyncand is awaited, so do real work here (run a test command, call an API, read a file). Whatever it returns is validated againstoutputand persisted, exactly like an agent’s parsed JSON. - Static (no
agent, children is a literal value): persists the value as-is.
deps, and works inside <Loop>, <Branch>, <Parallel>, and
<Sequence> just like an agent Task. The only thing it cannot do is be a fork
source (no agent session). Throwing inside a compute function fails the task and
triggers its retry policy.
Dependencies: dependsOn, needs, deps
Three props express upstream dependencies. They compose.dependsOn: string[]: ordering only. The task waits until every listed task id is terminal. No values are passed in.needs: Record<string, string>: named dependencies. Each value is an upstream task id; each key is the name that value is looked up under.deps: Record<string, OutputTarget>: typed render-time outputs. The task gates on each dependency and passes the resolved rows to achildrencallback via{(deps) => ...}.
deps key is treated as the upstream task’s id. deps={{ analyze: outputs.analysis }} depends on a task whose id is analyze. If your dep name differs from the upstream id, remap it with needs:
needs remap, deps={{ summary: ... }} depends on a node id summary that no task produces. The dependency can never resolve, and the run fails with DEPENDENCY_DEADLOCK naming the stuck task. (Previously this hung or finished while silently skipping the task.) needs alone works too when you don’t need the typed children callback.
Across a loop boundary
A task inside a<Loop> can depend on a task outside the loop. The upstream is resolved at its own iteration, not the loop’s, so deps/needs reach it from any iteration:
Fork
Every agent task produces a reusable session snapshot. Usefork to start a new task from any previous task’s context.
<Task id={B} fork={A}> means:
Bdepends onAand cannot run untilAhas completed.Bstarts from a copy ofA’s final agent session context, then submits its own prompt into that copy.Bproduces its own output and its own session snapshot.Ais never mutated.
fork is immutable. It does not continue or mutate the source task; it copies the conversation into a fresh, independent session. Multiple tasks may fork the same source safely, and a forked task may itself be forked.
VERIFY forks IMPLEMENT, which forked PLAN, so VERIFY sees the whole plan → implement conversation.
Parallel branches: fork the same source from sibling tasks; each gets its own copy and they never affect each other:
fork composes with dependsOn, needs, deps, Sequence, Parallel, Branch, and Loop. Inside a loop, fork resolves to the latest completed session snapshot for that task id; there is no iteration selector and no ambiguity.
Error cases
TASK_FORK_SOURCE_NOT_FOUND:forkpoints to a task id not present in the graph (including a source that exists only in an unselected<Branch>).TASK_FORK_CYCLE:forkcreates a cycle, directly or indirectly.TASK_FORK_SESSION_UNAVAILABLE: the forking task is not an agent task, or the source completed but produced no usable session snapshot (e.g. a compute/static source, or a source that was skipped/cancelled).TASK_FORK_SOURCE_NOT_COMPLETE: the source exists but has not completed; the forked task waits and does not run.
Notes
- Three modes by
childrenshape: agent (withagent), compute (function, no agent), static (value, no agent). forkrequires an agent task; the source must be an agent task with a session snapshot. Forking copies the conversation into a new session and never reuses a native session id.- When
outputSchemais set, JSON is extracted from agent text; schema-validation retries don’t consumeretries. - Auth errors short-circuit retries; non-idempotent tool reuse warns on the next attempt.