Workflow DSL reference
The dialect is Starlark with assignments, if, for, comprehensions, def, lambda, load(), at the top level or inside a def. Every one of them runs at compile time: the compiled plan is a static graph, so a loop in the source unrolls into tasks rather than becoming a cycle.
prompt_file(), schema_file(), and load() are the only file access, all confined below the pack directory, and a loaded module cannot re-export what it loaded. The surface has no processes, network access, clock, or randomness.
For what the engine does with the compiled graph, see Work graphs; for the normative rules, see the implementation contract.
Every lane
Available in every workflow type, playbooks included.
agent()
An agent turn driven by a prompt.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
prompt | str | The turn's prompt. |
harness | str | Agent harness, overriding [agent]. |
model | str | Model, overriding [agent]. |
effort | str | Reasoning effort, overriding [agent]. |
sandbox | str | An [agent.sandbox.<name>]: its image, and only the secrets, relay files, broker reach, and egress it lists. Unset runs in the [agent] sandbox. |
session | session | str | Join a durable conversation. A task in a session cannot be isolated. |
repair | int | Repair turns, up to 3. When a passing turn's output misses a declared field or file, or breaks its type or schema, the same session is resumed with the masked validation notes and asked to fix it in place, then checked again. Repairs share the attempt's timeout and cost. Default 0; refused on command and evaluate. |
depends_on | list[task | optional(task)] | Dependencies. Readiness decides execution order; declaration order does not. |
needs | str | The substrate capability the task needs, such as "decision". The default "any" runs everywhere. A required task whose capability is unavailable truncates the plan before dispatch; an advisory one is skipped with its dependents. |
join | "all" | "passed" | "settled" | Which dependencies must have passed: all every one, passed at least one and only those are forwarded, settled none — it dispatches once every dependency is terminal, whatever it settled as, unless the run has already halted, and forwards each one as {status, note, output, files}. |
required | bool | False makes the task advisory: it blocks dependents but cannot invalidate the run. |
isolated | bool | Run in a disposable worktree. File changes are discarded; only JSON output continues. |
emits | list[str] | dict[str, type] | Result fields the task promises in its JSON output. The dict form also promises each field's type: "string", "integer", "number", "boolean", "list", "object", "link", "links", or a list of labels the value is one of. A passing output missing a field, or holding one of the wrong type, fails the task. Types are checked where the graph reads them: over needs a list, a top_k or grade score a number, and a route(source = ...) question labels it can answer. A link is one http(s) url and links a list of them, each naming a result the task produced outside the run (a pull request, a pushed branch, an issue), which the run and task views then link out to. A schema_file(...) promises a value its JSON Schema admits, and is checked against each consumer exactly: over needs "type": "array" with string items (by type, const or enum), a score a numeric type with no non-number in its enum, and a route a const, enum or boolean whose every value it can answer. A when label such a source can never give is refused. |
emits_files | list[str] | dict[str, schema | None] | Workspace files the task produces. A task is staged with the declared files of every ancestor that passed, not only its direct dependencies, under inputs/<producer>/; a join = "settled" task also gets those of a direct dependency that failed. JSON outputs, unlike files, come from direct dependencies only. The dict form maps a path to schema_file(...) or None; a file with a schema must hold JSON the schema admits when the task passes, or the task fails. |
over | producer.field | Map the task over a dependency's emitted list, one instance per item. |
max_fanout | int | Instance cap for over, within the engine's ceiling of 256. |
keyed | list[producer.field] | Object fields of unmapped dependencies, keyed by item. Each instance receives only its own item's entry in place of the whole field. Needs over. |
revise | task | list[task] | The tasks this task sends back when it settles failing. They run again, in dependency order, with the verdict under revision, then this task does, until this task stops failing or max_rounds is spent. Every task on a path between them and this task must be listed. Playbooks only; not with over. |
max_rounds | int | Round cap for revise, counting the first, from 2 to the engine's ceiling of 5. |
timeout | str | How long one attempt may run, as 90s, 10m, or 2h. At the limit the attempt's whole process group is killed and the task settles failed with a note naming the limit; it is not retried. The run's --max-time bounds every attempt as well, and a playbook refuses a timeout longer than it before dispatching anything. |
stage | "iteration" | "epilogue" | epilogue runs once after the loop concludes, and only if the run kept a candidate. |
history | int | Read this many earlier runs of the launch series, from 1 to the engine's ceiling of 30, under history. A run launched outside a series gets an empty list. Playbooks only. |
when | route.question | Run only on a listed answer to one question of a route() this task depends on. Otherwise the task settles not_taken: no dispatch, no spend, no effect on validity, and every all-join dependent is not taken with it unless it lists the task as optional(...). Rejoin branches with join = "passed" or join = "settled". Playbook and custom workflows only. |
answers | str | list[str] | The answers when accepts: labels the question declares, or "uncertain". Defaults to "yes" for a noul and is required for a choice or a score. A choice whose options come from a field declares none, so only "uncertain". |
otherwise | bool | In place of answers: every answer no other task lists and the question does not drop, "uncertain" included. Expanded at compile time. An unreachable otherwise is an error. On a choice whose options come from a field, it also stands for every option the choice resolves to, and is the only way to route them. |
skill()
An agent turn whose prompt is a skill's instructions plus its arguments.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
skill | str | Skill directory below the pack; its instructions become the prompt. |
args | dict | Arguments appended to the instructions. |
harness | str | Agent harness, overriding [agent]. |
model | str | Model, overriding [agent]. |
effort | str | Reasoning effort, overriding [agent]. |
sandbox | str | An [agent.sandbox.<name>]: its image, and only the secrets, relay files, broker reach, and egress it lists. Unset runs in the [agent] sandbox. |
session | session | str | Join a durable conversation. A task in a session cannot be isolated. |
repair | int | Repair turns, up to 3. When a passing turn's output misses a declared field or file, or breaks its type or schema, the same session is resumed with the masked validation notes and asked to fix it in place, then checked again. Repairs share the attempt's timeout and cost. Default 0; refused on command and evaluate. |
depends_on | list[task | optional(task)] | Dependencies. Readiness decides execution order; declaration order does not. |
needs | str | The substrate capability the task needs, such as "decision". The default "any" runs everywhere. A required task whose capability is unavailable truncates the plan before dispatch; an advisory one is skipped with its dependents. |
join | "all" | "passed" | "settled" | Which dependencies must have passed: all every one, passed at least one and only those are forwarded, settled none — it dispatches once every dependency is terminal, whatever it settled as, unless the run has already halted, and forwards each one as {status, note, output, files}. |
required | bool | False makes the task advisory: it blocks dependents but cannot invalidate the run. |
isolated | bool | Run in a disposable worktree. File changes are discarded; only JSON output continues. |
emits | list[str] | dict[str, type] | Result fields the task promises in its JSON output. The dict form also promises each field's type: "string", "integer", "number", "boolean", "list", "object", "link", "links", or a list of labels the value is one of. A passing output missing a field, or holding one of the wrong type, fails the task. Types are checked where the graph reads them: over needs a list, a top_k or grade score a number, and a route(source = ...) question labels it can answer. A link is one http(s) url and links a list of them, each naming a result the task produced outside the run (a pull request, a pushed branch, an issue), which the run and task views then link out to. A schema_file(...) promises a value its JSON Schema admits, and is checked against each consumer exactly: over needs "type": "array" with string items (by type, const or enum), a score a numeric type with no non-number in its enum, and a route a const, enum or boolean whose every value it can answer. A when label such a source can never give is refused. |
emits_files | list[str] | dict[str, schema | None] | Workspace files the task produces. A task is staged with the declared files of every ancestor that passed, not only its direct dependencies, under inputs/<producer>/; a join = "settled" task also gets those of a direct dependency that failed. JSON outputs, unlike files, come from direct dependencies only. The dict form maps a path to schema_file(...) or None; a file with a schema must hold JSON the schema admits when the task passes, or the task fails. |
over | producer.field | Map the task over a dependency's emitted list, one instance per item. |
max_fanout | int | Instance cap for over, within the engine's ceiling of 256. |
keyed | list[producer.field] | Object fields of unmapped dependencies, keyed by item. Each instance receives only its own item's entry in place of the whole field. Needs over. |
revise | task | list[task] | The tasks this task sends back when it settles failing. They run again, in dependency order, with the verdict under revision, then this task does, until this task stops failing or max_rounds is spent. Every task on a path between them and this task must be listed. Playbooks only; not with over. |
max_rounds | int | Round cap for revise, counting the first, from 2 to the engine's ceiling of 5. |
timeout | str | How long one attempt may run, as 90s, 10m, or 2h. At the limit the attempt's whole process group is killed and the task settles failed with a note naming the limit; it is not retried. The run's --max-time bounds every attempt as well, and a playbook refuses a timeout longer than it before dispatching anything. |
stage | "iteration" | "epilogue" | epilogue runs once after the loop concludes, and only if the run kept a candidate. |
history | int | Read this many earlier runs of the launch series, from 1 to the engine's ceiling of 30, under history. A run launched outside a series gets an empty list. Playbooks only. |
when | route.question | Run only on a listed answer to one question of a route() this task depends on. Otherwise the task settles not_taken: no dispatch, no spend, no effect on validity, and every all-join dependent is not taken with it unless it lists the task as optional(...). Rejoin branches with join = "passed" or join = "settled". Playbook and custom workflows only. |
answers | str | list[str] | The answers when accepts: labels the question declares, or "uncertain". Defaults to "yes" for a noul and is required for a choice or a score. A choice whose options come from a field declares none, so only "uncertain". |
otherwise | bool | In place of answers: every answer no other task lists and the question does not drop, "uncertain" included. Expanded at compile time. An unreachable otherwise is an error. On a choice whose options come from a field, it also stands for every option the choice resolves to, and is the only way to route them. |
command()
A deterministic shell task in the candidate workspace.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
run | str | The command, run through sh -c. |
depends_on | list[task | optional(task)] | Dependencies. Readiness decides execution order; declaration order does not. |
needs | str | The substrate capability the task needs, such as "decision". The default "any" runs everywhere. A required task whose capability is unavailable truncates the plan before dispatch; an advisory one is skipped with its dependents. |
join | "all" | "passed" | "settled" | Which dependencies must have passed: all every one, passed at least one and only those are forwarded, settled none — it dispatches once every dependency is terminal, whatever it settled as, unless the run has already halted, and forwards each one as {status, note, output, files}. |
required | bool | False makes the task advisory: it blocks dependents but cannot invalidate the run. |
isolated | bool | Run in a disposable worktree. File changes are discarded; only JSON output continues. |
emits | list[str] | dict[str, type] | Result fields the task promises in its JSON output. The dict form also promises each field's type: "string", "integer", "number", "boolean", "list", "object", "link", "links", or a list of labels the value is one of. A passing output missing a field, or holding one of the wrong type, fails the task. Types are checked where the graph reads them: over needs a list, a top_k or grade score a number, and a route(source = ...) question labels it can answer. A link is one http(s) url and links a list of them, each naming a result the task produced outside the run (a pull request, a pushed branch, an issue), which the run and task views then link out to. A schema_file(...) promises a value its JSON Schema admits, and is checked against each consumer exactly: over needs "type": "array" with string items (by type, const or enum), a score a numeric type with no non-number in its enum, and a route a const, enum or boolean whose every value it can answer. A when label such a source can never give is refused. |
emits_files | list[str] | dict[str, schema | None] | Workspace files the task produces. A task is staged with the declared files of every ancestor that passed, not only its direct dependencies, under inputs/<producer>/; a join = "settled" task also gets those of a direct dependency that failed. JSON outputs, unlike files, come from direct dependencies only. The dict form maps a path to schema_file(...) or None; a file with a schema must hold JSON the schema admits when the task passes, or the task fails. |
over | producer.field | Map the task over a dependency's emitted list, one instance per item. |
max_fanout | int | Instance cap for over, within the engine's ceiling of 256. |
keyed | list[producer.field] | Object fields of unmapped dependencies, keyed by item. Each instance receives only its own item's entry in place of the whole field. Needs over. |
revise | task | list[task] | The tasks this task sends back when it settles failing. They run again, in dependency order, with the verdict under revision, then this task does, until this task stops failing or max_rounds is spent. Every task on a path between them and this task must be listed. Playbooks only; not with over. |
max_rounds | int | Round cap for revise, counting the first, from 2 to the engine's ceiling of 5. |
timeout | str | How long one attempt may run, as 90s, 10m, or 2h. At the limit the attempt's whole process group is killed and the task settles failed with a note naming the limit; it is not retried. The run's --max-time bounds every attempt as well, and a playbook refuses a timeout longer than it before dispatching anything. |
stage | "iteration" | "epilogue" | epilogue runs once after the loop concludes, and only if the run kept a candidate. |
history | int | Read this many earlier runs of the launch series, from 1 to the engine's ceiling of 30, under history. A run launched outside a series gets an empty list. Playbooks only. |
when | route.question | Run only on a listed answer to one question of a route() this task depends on. Otherwise the task settles not_taken: no dispatch, no spend, no effect on validity, and every all-join dependent is not taken with it unless it lists the task as optional(...). Rejoin branches with join = "passed" or join = "settled". Playbook and custom workflows only. |
answers | str | list[str] | The answers when accepts: labels the question declares, or "uncertain". Defaults to "yes" for a noul and is required for a choice or a score. A choice whose options come from a field declares none, so only "uncertain". |
otherwise | bool | In place of answers: every answer no other task lists and the question does not drop, "uncertain" included. Expanded at compile time. An unreachable otherwise is an error. On a choice whose options come from a field, it also stands for every option the choice resolves to, and is the only way to route them. |
evaluate()
A measurement command. Its last non-empty stdout line is a JSON object; pass = false vetoes the result and numeric score feeds grade() and top_k().
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
run | str | The command, run through sh -c. |
threshold | number | Grade the emitted score against this bound. pass = false fails a score within it; pass cannot pass a score outside it. |
direction | "lower" | "higher" | Which side of the threshold passes. |
depends_on | list[task | optional(task)] | Dependencies. Readiness decides execution order; declaration order does not. |
needs | str | The substrate capability the task needs, such as "decision". The default "any" runs everywhere. A required task whose capability is unavailable truncates the plan before dispatch; an advisory one is skipped with its dependents. |
join | "all" | "passed" | "settled" | Which dependencies must have passed: all every one, passed at least one and only those are forwarded, settled none — it dispatches once every dependency is terminal, whatever it settled as, unless the run has already halted, and forwards each one as {status, note, output, files}. |
required | bool | False makes the task advisory: it blocks dependents but cannot invalidate the run. |
isolated | bool | Run in a disposable worktree. File changes are discarded; only JSON output continues. |
emits | list[str] | dict[str, type] | Result fields the task promises in its JSON output. The dict form also promises each field's type: "string", "integer", "number", "boolean", "list", "object", "link", "links", or a list of labels the value is one of. A passing output missing a field, or holding one of the wrong type, fails the task. Types are checked where the graph reads them: over needs a list, a top_k or grade score a number, and a route(source = ...) question labels it can answer. A link is one http(s) url and links a list of them, each naming a result the task produced outside the run (a pull request, a pushed branch, an issue), which the run and task views then link out to. A schema_file(...) promises a value its JSON Schema admits, and is checked against each consumer exactly: over needs "type": "array" with string items (by type, const or enum), a score a numeric type with no non-number in its enum, and a route a const, enum or boolean whose every value it can answer. A when label such a source can never give is refused. |
emits_files | list[str] | dict[str, schema | None] | Workspace files the task produces. A task is staged with the declared files of every ancestor that passed, not only its direct dependencies, under inputs/<producer>/; a join = "settled" task also gets those of a direct dependency that failed. JSON outputs, unlike files, come from direct dependencies only. The dict form maps a path to schema_file(...) or None; a file with a schema must hold JSON the schema admits when the task passes, or the task fails. |
over | producer.field | Map the task over a dependency's emitted list, one instance per item. |
max_fanout | int | Instance cap for over, within the engine's ceiling of 256. |
keyed | list[producer.field] | Object fields of unmapped dependencies, keyed by item. Each instance receives only its own item's entry in place of the whole field. Needs over. |
revise | task | list[task] | The tasks this task sends back when it settles failing. They run again, in dependency order, with the verdict under revision, then this task does, until this task stops failing or max_rounds is spent. Every task on a path between them and this task must be listed. Playbooks only; not with over. |
max_rounds | int | Round cap for revise, counting the first, from 2 to the engine's ceiling of 5. |
timeout | str | How long one attempt may run, as 90s, 10m, or 2h. At the limit the attempt's whole process group is killed and the task settles failed with a note naming the limit; it is not retried. The run's --max-time bounds every attempt as well, and a playbook refuses a timeout longer than it before dispatching anything. |
stage | "iteration" | "epilogue" | epilogue runs once after the loop concludes, and only if the run kept a candidate. |
history | int | Read this many earlier runs of the launch series, from 1 to the engine's ceiling of 30, under history. A run launched outside a series gets an empty list. Playbooks only. |
when | route.question | Run only on a listed answer to one question of a route() this task depends on. Otherwise the task settles not_taken: no dispatch, no spend, no effect on validity, and every all-join dependent is not taken with it unless it lists the task as optional(...). Rejoin branches with join = "passed" or join = "settled". Playbook and custom workflows only. |
answers | str | list[str] | The answers when accepts: labels the question declares, or "uncertain". Defaults to "yes" for a noul and is required for a choice or a score. A choice whose options come from a field declares none, so only "uncertain". |
otherwise | bool | In place of answers: every answer no other task lists and the question does not drop, "uncertain" included. Expanded at compile time. An unreachable otherwise is an error. On a choice whose options come from a field, it also stands for every option the choice resolves to, and is the only way to route them. |
report()
Publish a rendered template to a controller-configured destination. The workflow selects a destination key, never an endpoint or a credential.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
destination | dict | The sink to publish to, as {"kind": "slack"}. The controller holds its endpoint and credential. |
template | str | Pack file rendered into the card body. Reads verdict, spent_usd, passed, failed, tasks (first 20), run, run_url, and result. Every inserted value is escaped for Slack. |
result | task | The task whose declared fields the card and result.output carry; result.status alone when it did not pass. |
severity_field | str | A declared field of result whose value ("good", "warning", "danger") picks the card accent; any other value is neutral. |
required | bool | False makes the report advisory. |
session()
Declare a durable agent conversation. Tasks that share one run serially under one agent config, across dependency order and loop iterations.
| Argument | Type | Purpose |
|---|---|---|
name | str | Session identity, referenced by session =. |
harness | str | Default harness for tasks in the session. |
model | str | Default model for tasks in the session. |
effort | str | Default effort for tasks in the session. |
param()
Read a launch parameter. The params block must be the source's first statement, and a source that declares one compiles per run. A supplied value may reach a prompt, with + and inside a region marked as external input, or a skill argument; str(), %, .format(), and string methods on it are refused, as is a value carrying the marker text. A command or evaluate task reads it from params in the inputs JSON at CRUCIBLE_INPUTS_FILE instead of its command line.
Takes one positional argument, name.
prompt_file()
Embed a UTF-8 file below the pack directory. Absolute paths, .., symlinks, non-files, and oversized inputs are refused.
Takes one positional argument, path.
schema_file()
Read a JSON Schema (draft 2020-12) below the pack directory, for a field type in emits or a file in emits_files. Its content, not its path, is compiled into the plan. Paths are confined as for prompt_file; a file that is not a valid 2020-12 schema, declares another $schema, or references a remote $ref is refused.
Takes one positional argument, path.
workflow()
The source's final expression: the lane, the tasks that ship, and the result. A task constructed but not listed is a compile error.
Takes one positional argument, tasks.
| Argument | Type | Purpose |
|---|---|---|
type | "autoresearch" | "custom" | "playbook" | The lane, which decides which constructors exist. |
tasks | list[task] | Every task that ships. |
result | task | The task whose output is the workflow's result. |
history_record | task | The task each run records for the later runs of its launch series: its status, and the fields it declares in emits when it passed. Not a mapped task; an epilogue task records even when the main graph failed. Playbooks only. |
Scored lanes only
Available to type = "autoresearch" and type = "custom". A playbook does not have these in scope at all, so naming one is an unknown-name error and a did-you-mean never offers one.
propose()
The loop's candidate-producing agent turn.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
session | session | str | The conversation the turn belongs to. |
depends_on | list[task] | Dependencies. |
apply()
Make the candidate live through the configured world. A failure means unscoreable, not worse.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
depends_on | list[task] | Dependencies. |
measure()
Run the manifest's frozen judge as one opaque measurement task.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
depends_on | list[task] | Dependencies. |
grade()
Fold evaluation evidence into a measurement. Evidence includes tasks that failed or never ran, which is what the score source alone cannot see.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
score | task | The task whose score the decision uses. |
tiebreak | task | Secondary score that breaks primary-score ties. |
evidence | list[task] | Tasks folded into the measurement. |
join | "all" | "passed" | Which evidence must have passed. |
decide()
Apply the engine's keep-or-discard rule to a measurement. An autoresearch workflow must end here.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
measurement | task | The measurement being ruled on. |
depends_on | list[task] | Dependencies, defaulting to the measurement. |
top_k()
Engine-owned reducer: the best k dependency outputs by numeric score.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
k | int | How many dependencies survive. |
direction | "lower" | "higher" | Which score wins. |
depends_on | list[task] | The candidates being reduced. |
required | bool | False makes the reducer advisory. |
default_autoresearch()
Expand the built-in propose/apply/measure/decide loop into visible nodes, plus the tasks passed to it.
Takes one positional argument, extra_tasks.
Playbook and custom lanes only
Available to type = "playbook" and type = "custom". An autoresearch workflow keeps or discards on a frozen measure, so it has neither these nor when.
route()
Engine-owned decision: answers typed questions about its dependencies' outputs and records one label per question, which other tasks branch on with when. Every label of a question some when refers to, "uncertain" included, must be listed by a when or by the question's drop.
| Argument | Type | Purpose |
|---|---|---|
name | str | Task identity, unique within the workflow. |
questions | dict[str, question] | Question id to noul(), choice(), or score(). gate.<id> names one for when. |
min_confidence | number | A decision model answers, through the broker's decision capability. An answer whose probability is below this, in (0, 1], is recorded as "uncertain". Exactly one of min_confidence and source. |
source | task | A dependency's output answers instead: it emits one declared label (or a boolean, for a noul) under each question id. Deterministic, free, and needs no capability. Any other value fails the route. When the dependency types its emits, each question's field must be typed with labels the question answers, or "boolean" for a noul. |
human | bool | True: a person allowed to approve the run answers, from the controller UI, after seeing the dependencies' declared outputs and files. Needs the human capability. Tasks that do not depend on the route keep running while it waits. |
review | path | With human: a Markdown template in the pack, rendered over the evidence (inputs, run, gated) and shown above it. Every inserted value is escaped. |
timeout | duration | With human: how long the request stays open, from when it opens; the run's wall-clock ceiling by default. An unanswered request records every question as "uncertain". |
files | list[str] | Declared JSON files of dependencies the model reads, under files in its state, by dependency and path. Each must be declared by a dependency with a schema_file(...). Not with source. |
over | producer.field | Decide once per item. A task mapped over the same list reads each item's answer with when; one mapped over another list, or not mapped, cannot. |
max_fanout | int | Instance cap for over, within the engine's ceiling of 256. |
keyed | list[producer.field] | Object fields of unmapped dependencies, keyed by item. Each instance receives only its own item's entry in place of the whole field. Needs over. |
depends_on | list[task] | Dependencies. Their outputs are the state the questions are asked about. |
required | bool | False makes the route advisory. |
join | "all" | "passed" | "settled" | Which dependency outputs form the state, as on any task. |
stage | "iteration" | "epilogue" | As on any task. |
when | route.question | Run only on a listed answer to one question of a route() this task depends on. Otherwise the task settles not_taken: no dispatch, no spend, no effect on validity, and every all-join dependent is not taken with it unless it lists the task as optional(...). Rejoin branches with join = "passed" or join = "settled". Playbook and custom workflows only. |
answers | str | list[str] | The answers when accepts: labels the question declares, or "uncertain". Defaults to "yes" for a noul and is required for a choice or a score. A choice whose options come from a field declares none, so only "uncertain". |
otherwise | bool | In place of answers: every answer no other task lists and the question does not drop, "uncertain" included. Expanded at compile time. An unreachable otherwise is an error. On a choice whose options come from a field, it also stands for every option the choice resolves to, and is the only way to route them. |
noul()
A yes/no question for route(). It answers "yes" or "no".
| Argument | Type | Purpose |
|---|---|---|
ask | str | What to decide. |
drop | str | list[str] | Answers that deliberately lead nowhere, so no when has to list them. |
choice()
A one-of-N question for route().
| Argument | Type | Purpose |
|---|---|---|
ask | str | What to decide. |
options | list[str] | dict[str, str | None] | producer.field | At least two distinct identifier labels, optionally each with a description the model sees. "uncertain" is reserved. Or an unmapped dependency's field, read at each decision: the list itself, or, on a route with over, an object keyed by item holding each item's list. Each entry is a label or {"value": label, "description": str}; at most 64, a repeated label keeps its first entry, and fewer than two fails that decision. The answer records the options it chose among. Needs min_confidence. |
multiple | bool | Take one or more labels. Only a human = True route asks it; a when runs if any listed label was chosen. |
drop | str | list[str] | Answers that deliberately lead nowhere, so no when has to list them. |
pick()
A question for a human = True route whose options are a list a dependency produced. The route's output holds the picked values under the question id, so over = gate.question fans out over them. No when routes on it.
| Argument | Type | Purpose |
|---|---|---|
ask | str | What to pick. |
source | producer.field | A list of strings in the output of a task the route depends on, read when the route opens its request. |
multiple | bool | Take one or more values rather than one. |
score()
An ordinal question for route(). It answers its most probable level, the lowest on a tie, and records a score in [0, 1]: the expected level position over the normalized distribution, 0 for the lowest level and 1 for the highest. A source answers one level label, scored by its position, and "uncertain" records no score.
| Argument | Type | Purpose |
|---|---|---|
ask | str | What to decide. |
levels | list[str] | dict[str, str | None] | At least two distinct identifier labels, lowest first in the order written, optionally each with a description the model sees. "uncertain" is reserved. |
drop | str | list[str] | Answers that deliberately lead nowhere, so no when has to list them. |
optional()
Mark an entry of depends_on that may settle not_taken. Under join = "all" the task dispatches past it as though it passed, and its inputs carry no entry for it; one that failed or was blocked still blocks. Refused under another join, on a dependency that can never settle not_taken, and on a task the reviewer revises.
Takes one positional argument, task.
Reserved fields
Names the engine reads and writes for itself. They are not constructor arguments; they appear in a task's own JSON output and in the inputs it receives.
A task's own JSON output
Read out of the object the task returns.
| Field | Type | Meaning |
|---|---|---|
status | "pass" | "fail" | "skipped" | "fail" or "skipped" settles the task that way, whatever its exit status, pass or threshold. "pass" cannot pass a task that exited nonzero or did not pass its grade. Any other value is ignored. |
note | str | Why the task failed or was skipped, recorded as its note when it is a non-blank string: after the exit status in place of the stderr tail when a command exits nonzero, before the threshold and log handles when an evaluation does not pass, and in place of the default note when status is "fail" or "skipped". The control plane shows it as a parked run's reason. Read only from a result that fails or skips. |
complete | bool | true on a passing main-graph command or evaluate task of a playbook ends the run early and valid: nothing else in the main graph dispatches, undispatched tasks stay unsettled, and epilogue tasks still run. The shutdown outcome is complete. Any other task's true is refused on its row and the run continues. A task may not list it in emits. |
reason | str | Why the run completed early, recorded with the shutdown. A task may not list it in emits. |
Inputs the engine writes
Present alongside the dependency entries, never wrapped in one.
| Field | Type | Meaning |
|---|---|---|
history | object | Earlier terminal runs of the launch series, as {"records": [record], "dropped": int}, oldest first by end time, at most the task's history depth. Each record is {"run", "started_at", "ended_at", "outcome", "verdict", "revision", "link", "entry": {"task", "status", "output"}}. dropped counts records the operator's size limit removed from the oldest end. In a task that declares history only; an agent reads it as marked external input. |
item | str | This mapped instance's key, one per item of the list over names. |
kept | object | The kept candidate, in an epilogue task only. |
outcome | object | How the main graph ended and what each of its tasks settled as, as {"exit": str, "tasks": {name: {"status", "note", "output", "files"}}}, in an epilogue task only: each entry is what a settled join receives, per_instance included for a mapped task. files says whether that task's declared files, passing or failing, are staged under inputs/<name>/. |
params | object | Every declared parameter's bound value under its name, in its declared type, and {} where the source declares none, in a command or evaluate task only. |
revision | object | The verdict that sent this task back, as {"round": int, "max_rounds": int, "reviewer": str, "review": {"status", "note", "output", "files"}}, from the second round of a revise loop on. |