Skip to Content

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

AttributeTypeDescription
objectivestringWhat the task should accomplish
depends_onlistTasks that must complete first
agentslistOverride mission-level agents (optional)
outputblockStructured output schema (optional)
routerblockConditional routing — LLM picks a branch after task completes (optional)
send_tolistUnconditional 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:

  1. Receives the objective
  2. Breaks the task into subtasks using set_subtasks
  3. Works through each subtask, delegating to agents using call_agent
  4. Calls submit_output if the task has an output schema
  5. Calls task_complete when 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

TypeDescription
stringText value
numberNumeric value (float)
integerWhole number
booleanTrue/false
listArray of values — element type specified via list(type)
mapKey-value pairs — keys are always strings, value type specified via map(type)
objectStructured 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_on and build a static DAG. Reach for router only when the LLM must choose a branch, and send_to only 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: router and send_to are mutually exclusive on a task. Dynamic targets (tasks reachable via router or send_to) cannot have depends_on.

See Also

Last updated on