Tasks
Tasks are the building blocks of missions. Each task has an objective and can depend on other tasks.
Basic Task
task "analyze" {
objective = "Analyze the data and identify trends"
}Task with Dependencies
task "summarize" {
objective = "Summarize the analysis results"
depends_on = [tasks.analyze]
}Attributes
| Attribute | Type | Description |
|---|---|---|
objective | string | What the task should accomplish |
depends_on | list | Tasks that must complete first |
agents | list | Override mission-level agents (optional) |
output | block | Structured output schema (optional) |
router | block | Conditional routing — LLM picks a branch after task completes (optional) |
send_to | list | Unconditional routing — activate target tasks on completion (optional) |
Dependencies
Tasks can depend on multiple tasks:
task "combine" {
objective = "Combine results from both sources"
depends_on = [tasks.fetch_source_a, tasks.fetch_source_b]
}Dependencies are specified using tasks.<task_name>.
Task-Level Agents
Override the mission’s agents for specific tasks:
mission "pipeline" {
agents = [agents.general]
task "code_review" {
objective = "Review the code changes"
agents = [agents.coder] # Use specialized agent
}
}Dynamic Objectives
Use variables and inputs in objectives:
mission "report" {
input "topic" {
type = "string"
}
task "research" {
objective = "Research the topic: ${inputs.topic}"
}
}Commander Behavior
Each task gets a commander that:
- Receives the objective
- Breaks the task into subtasks using
set_subtasks - Works through each subtask, delegating to agents using
call_agent - Calls
submit_outputif the task has an output schema - Calls
task_completewhen all work is done
Context from Dependencies
When a task completes, the commander provides a summary in task_complete. This summary is automatically passed as context to all dependent tasks — no extra LLM calls needed.
Commanders can also query structured data from dependencies using query_task_output, and ask follow-up questions to previous commanders using ask_commander if the summary doesn’t have enough detail.
task "step_2" {
objective = "Continue based on step 1 results"
depends_on = [tasks.step_1]
}The step_2 commander can query step_1’s structured output and ask its commander clarifying questions.
Structured Output
Tasks can define a structured output schema. When defined, the commander must call submit_output with data matching the schema:
task "analyze_sales" {
objective = "Analyze Q4 sales data"
depends_on = [tasks.fetch_sales]
output {
field "total_revenue" {
type = "number"
description = "Total revenue in USD"
required = true
}
field "top_product" {
type = "string"
description = "Best-selling product name"
required = true
}
field "growth_rate" {
type = "number"
}
}
}Field Types
| Type | Description |
|---|---|
string | Text value |
number | Numeric value (float) |
integer | Whole number |
boolean | True/false |
list | Array of values — element type specified via list(type) |
map | Key-value pairs — keys are always strings, value type specified via map(type) |
object | Structured data with named fields — properties specified via object({...}) |
Shorthand Schema Syntax
Instead of field blocks you can use a single output = { ... } attribute with schema helper functions:
task "analyze_sales" {
objective = "Analyze Q4 sales data"
depends_on = [tasks.fetch_sales]
output = {
total_revenue = number("Total revenue in USD", true)
top_product = string("Best-selling product name", true)
growth_rate = number("Growth rate as decimal")
categories = list(string, "Product categories found")
metadata = map(string, "Additional key-value data")
breakdown = object({
online = number("Online revenue", true)
instore = number("In-store revenue", true)
}, "Revenue breakdown by channel", true)
}
}Nested types are fully supported — lists can contain objects, objects can contain lists, etc. The commander’s system prompt will display the full nested schema so the LLM knows the exact structure expected.
See Functions for the complete reference on all helper functions and type references.
Structured output is automatically captured and stored. Downstream tasks can query it using the query_task_output tool (see Internal Tools).
Routing
Tasks can route to other tasks (or missions) after they complete. See Routing for full details, including when to use depends_on vs router vs send_to.
Rule of thumb: prefer
depends_onand build a static DAG. Reach forrouteronly when the LLM must choose a branch, andsend_toonly for fan-out or conditional fan-in to a shared task.
Conditional Routing
A router block lets the LLM choose which branch to activate:
task "classify" {
objective = "Classify the request"
router {
route {
target = tasks.handle_billing
condition = "The request is about billing"
}
route {
target = tasks.handle_support
condition = "The request is technical support"
}
}
}Unconditional Routing
send_to activates target tasks immediately — no LLM decision:
task "fetch" {
objective = "Fetch data"
send_to = [tasks.process_a, tasks.process_b]
}Note:
routerandsend_toare mutually exclusive on a task. Dynamic targets (tasks reachable viarouterorsend_to) cannot havedepends_on.
See Also
- Routing - Conditional and unconditional routing
- Missions Overview - Mission structure
- Internal Tools - Commander and agent tools