Native Tasks and Await¶
Use > task when the program decides which child to call. Unlike model-driven
delegate_task, this does not require a parent model request to choose a tool.
The selected parent profile must explicitly declare that direct child.
Start Work and Read Typed Results¶
This program starts two independent reviews before waiting for either one:
> profile: reviewer:
> adapter: pydantic
> model: openai:gpt-5.6-luna
> instructions: Review only the supplied change. Separate evidence from assumptions.
> profile: coordinator:
> adapter: pydantic
> subagent: reviewer
> max_agents: 2
> use: coordinator
[change] = Add an export endpoint; unit tests pass, integration tests have not run.
> task [review_job]: reviewer:
>> The main risk in <change> is [issue: str].
The recommended next step is [recommendation: str].
> task [test_job]: reviewer:
>> The missing verification for <change> is [verification: str].
> await [review]: review_job
> await [tests]: test_job
> show: `review.output.recommendation`
= `tests.output.verification`
Install the selected provider dependency and supply its credentials to run this
example. Only the child invokes the model; the coordinator needs no model for
these native statements. Each task starts at its declaration. Waiting for
review_job first does not prevent test_job from running.
One Template, One Result¶
The task body contains exactly one >> template block. Continuation lines belong
to that block: issue and recommendation above are two fields of one child
result, not two child runs. A second >> block or arbitrary statements in the
task body are rejected.
review is a SubagentResult. Its output is a validated Pydantic model, not a
dictionary: use review.output.recommendation. The capture names do not become
parent bindings. review.task_summary contains the child's text summary;
review.run_id and review.subagent identify the run and child.
| Task template | Child profile | Result |
|---|---|---|
| Contains captures | No > output: |
output uses the template capture schema |
| No captures | Declares > output: Type |
output is an instance of that type |
| No captures | No > output: |
output is None; read task_summary |
| Contains captures | Declares > output: Type |
Rejected: two competing output schemas |
The child receives only the rendered task and its own profile. Parent history,
tools, and local bindings are not implicitly shared. Substitute every input the
child needs, as with <change> above.
Await and Ownership¶
Use > await [result]: job to bind the completed result, or > await: job to
observe completion and propagate errors without binding it. Awaiting the same
handle again observes the same run; it does not generate another answer.
A handle belongs to the invocation that started it. It cannot escape to another invocation or survive an interactive session boundary as live work. Every started task must be observed before its owner completes. Unawaited work is cancelled and the invocation fails, even if a child happened to finish in the background. Failure and cancellation clean up owned children; cancelling a wait is not a guarantee that application-owned synchronous side effects can be undone.
Capacity and Ready-First Processing¶
For additional evidence or a change of scope while a task is running, see
Task Input and Redirection. > send preserves active
work; > interrupt replaces the current attempt without changing the handle.
max_agents limits admitted descendant starts. It does not increase concurrent
capacity. The separate compile_program(subagent_max_concurrency=...) limit rejects
excess starts rather than silently queueing them. See
Limits, Isolation and Safety for configuration and defaults.
Root and child model requests also share any declared run budget.
Ordinary awaits execute in source order. To process whichever result becomes ready first, use Concurrent Result Processing. For Python-owned tasks and explicit cancellation, see Python Embedding.