Agent orchestration with one lead, a team of specialists and one bill
Your lead agent decides at runtime who reviews, who tests and who researches, and can run them in parallel. Every specialist’s spend lands in the lead’s total, and its verified-or-not verdict feeds the lead’s done-gate.
curl -fsSL https://octomind.run/install.sh | bash octomind -c supervisor.learning.enabled=false -c max_session_spending_threshold=0.40 run lead --name orch-demo --format jsonl < ../task.txt {"type":"tool_use","tool":"agent_reviewer","tool_id":"call_723d5cc6733c45e98ea34d77","server":"agent","params":{"task":"Review the file pricing.py in /private/tmp/claude-usecases/agent-orchestration/work/project for bugs, logic errors, and code quality issues. Return findings as file:line references with brief explanations."},"session_id":"orch-demo"}
{"type":"tool_use","tool":"agent_tester","tool_id":"call_c4904262eece407b983fa999","server":"agent","params":{"task":"Analyze pricing.py in /private/tmp/claude-usecases/agent-orchestration/work/project and list concrete inputs or edge cases that would break it (crashes, wrong results, unhandled exceptions). Return specific failing input examples."},"session_id":"orch-demo"}
…
How it works
Define your specialists
A specialist is a role plus an
[[agents]]entry. Thecommandstarts that role as an ACP child, so it gets its own prompt, model and tool list.~/.local/share/octomind/config/agents.toml# ~/.local/share/octomind/config/agents.toml # Every *.toml in the config dir is merged into config.toml. [[mcp.servers]] name = "filesystem" type = "stdio" command = "octofs" args = ["mcp"] timeout_seconds = 30 tools = [] [[roles]] name = "reviewer" welcome = "" system = "You review code for bugs. Report file:line, the bug, and the fix." [roles.mcp] server_refs = ["filesystem"] allowed_tools = ["filesystem:view"] [[roles]] name = "tester" welcome = "" system = "You design test cases. List the inputs that would break the code." [roles.mcp] server_refs = ["filesystem"] allowed_tools = ["filesystem:view"] [[agents]] name = "reviewer" description = "Reviews code for bugs and returns file:line findings." command = "octomind acp reviewer" [[agents]] name = "tester" description = "Lists inputs that would break the given code." command = "octomind acp tester"Give the orchestrator agent its tools
Grant the lead the
agentserver and every[[agents]]entry shows up as anagent_<name>tool. Addorchestration:tapand it can also start background specialists from your tap registry.~/.local/share/octomind/config/lead.toml[[roles]] name = "lead" welcome = "" system = """ You lead a small team. Hand focused work to your specialists with the agent_* tools, read what they return, and give the user one answer. """ [roles.mcp] server_refs = ["agent", "orchestration", "filesystem"] allowed_tools = ["agent:*", "orchestration:tap", "filesystem:view"]Run the lead and let it delegate
Ask for the outcome, not the plan. The lead picks which specialists to call and how many, at runtime. Set a session spend threshold: child spend counts toward it, and a non-interactive run stops when it is crossed.
octomind config # writes config.toml on first run octomind config --validate # checks your roles and agents octomind -c max_session_spending_threshold=0.40 run lead
What you get
Each specialist is a tool the lead calls, sync or async
Every
src/mcp/agent/functions.rs:90[[agents]]entry becomesagent_<name>. Sync (the default) blocks until the child answers.async=truereturns at once and injects the result as a message when the child finishes.Background specialists from your tap registry
src/mcp/orchestration/tap.rs:584tap(action="run", role="developer:general", prompt="…")startsoctomind acp <role>in the background and returns an id. Passsession=<id>to continue the same specialist;listandstopmanage runs.One bill: child spend rolls up recursively
Each child reports its running session cost, which already includes anything it delegated. The parent banks only the increment, so every dollar lands in your total once, and spend thresholds see it.
src/mcp/agent/functions.rs:912One verdict: the child’s check feeds the lead’s done-gate
A finished child reports whether its own trajectory verified. The lead’s gate reads that verdict. A child that failed, was cancelled or reported nothing counts as unverified.
src/mcp/agent/functions.rs:727Clean handoffs, small returns
A child starts with zero context: it sees only the task text. Every task gets a return contract: a summary of at most 2,000 tokens plus the exact file paths, never raw dumps into the lead’s context.
src/mcp/agent/functions.rs:128
A real run: one lead, two specialists in parallel
Captured on octomind 0.58.8 with the config above and a 10-line pricing.py. The lead called agent_reviewer and agent_tester in the same turn; each child read the file with its own tools, and a specialist’s findings stream back into the lead’s log. The run was stopped before the final cost frame, so this capture shows the fan-out, not the rollup total.
octomind -c supervisor.learning.enabled=false -c max_session_spending_threshold=0.40 run lead --name orch-demo --format jsonl < ../task.txt {"type":"tool_use","tool":"agent_reviewer","tool_id":"call_723d5cc6733c45e98ea34d77","server":"agent","params":{"task":"Review the file pricing.py in /private/tmp/claude-usecases/agent-orchestration/work/project for bugs, logic errors, and code quality issues. Return findings as file:line references with brief explanations."},"session_id":"orch-demo"}
{"type":"tool_use","tool":"agent_tester","tool_id":"call_c4904262eece407b983fa999","server":"agent","params":{"task":"Analyze pricing.py in /private/tmp/claude-usecases/agent-orchestration/work/project and list concrete inputs or edge cases that would break it (crashes, wrong results, unhandled exceptions). Return specific failing input examples."},"session_id":"orch-demo"}
{"type":"tool_use","tool":"view","tool_id":"call_-7144385489364051723","server":"","params":{"path":"/private/tmp/claude-usecases/agent-orchestration/work/project/pricing.py"},"session_id":"orch-demo"}
{"type":"tool_result","tool":"","tool_id":"call_-7144385489364051723","server":"","content":"1:ce|def apply_discount(price, percent):\n2:70| \"\"\"Return price after a percent discount, never below zero.\"\"\"\n3:86| if percent > 100:\n4:50| percent = 100\n5:61| return price - price * percent / 100\n6:c5|\n7:c5|\n8:61|def split_bill(total, people):\n9:29| \"\"\"Split a bill evenly, rounded to cents.\"\"\"\n10:6b| return round(total / people, 2)","success":true,"session_id":"orch-demo"}
…
{"type":"assistant","content":"Findings for `/private/tmp/claude-usecases/agent-orchestration/work/project/pricing.py`:\n\n1. **pricing.py:3-5** — Docstring promises \"never below zero\" but a negative `price` input returns a more negative result, and a negative `percent` increases the price. Fix: clamp `price = max(price, 0)` and `percent = max(percent, 0)` (or validate and raise).\n\n2. **pricing.py:5** — Percent > 100 is clamped, but the clamp runs after use of unchecked input elsewhere isn't an issue here; however clamping silently hides caller errors — raising `ValueError` for out-of-range percents would be cleaner.\n\n3. **pricing.py:10** — `split_bill` divides by `people` with no guard: `people=0` raises `ZeroDivisionError`, and negative `people` silently returns a nonsensical negative split. Fix: validate `people >= 1`.\n\n4. **pricing.py:10** — `round()` uses banker's rounding (0.005 rounds down), so per-person splits can be off by a cent inconsistently; also no indication of how the remainder cent is handled. Consider `decimal.Decimal` with `ROUND_HALF_UP` and distributing the remainder.\n\n5. **Code quality** — No type hints, no input validation for non-numeric types; `percent` expected as 0–100 but the API doesn't reject 0.5 being mistaken for a fraction.","session_id":"orch-demo"}
…
What it doesn't do
No recursion depth limit
Nothing stops a role from calling itself, directly or through another agent. Keep each role’s agent tool list acyclic: specialists should not get the
agentserver. Docs →No cap on concurrent tap runs
The lead can start as many
tap runspecialists as it decides to. Setmax_session_spending_threshold: child spend counts toward it, and a non-interactive run stops when it is crossed.No filesystem isolation between children
Children share the working tree. Give parallel writers distinct paths, a separate
workdir, or their own git worktree. Docs →Async agent calls are capped at your CPU core count
Past the cap an
async=truecall returns "Async job limit reached". Split the work into batches or call some specialists sync.No fixed order of steps
The lead decides at runtime, so two runs of the same request can delegate differently. When every run must take the same steps, write a TOML workflow instead. Docs →
Questions
What is agent orchestration?
Agent orchestration is a lead agent deciding at runtime which specialist handles which part of a job, then merging the results into one answer. In octomind the lead is any role, and the specialists are [[agents]] entries or tap roles it calls as tools.
What is an orchestrator agent?
It is the agent that plans and delegates instead of doing every step itself. In octomind it is a normal role that has been granted the agent and orchestration tool servers.
Do I need a multi agent orchestration framework?
Not for this. Roles and agents are TOML entries in your config directory, and each specialist runs as an octomind acp <role> child, so there is no SDK or Python code to write.
How do I see what the specialists cost?
Their spend is folded into the lead session’s total, including spend from anything they delegated in turn. /status agents shows per-run usage and cost where the runtime reports it.
How many agents can run in parallel?
Async agent_* calls are capped at your CPU core count, with 4 as the fallback. Background tap run specialists have no cap, so put a session spend threshold on the lead.
Should I use agent orchestration or a workflow?
Use a workflow when you know the steps in advance: a fixed TOML pipeline with parallel, loop and best-of-N steps. Use orchestration when the lead should decide at runtime who does what and how many specialists to start.
Other ways to run octomind
- Self-hosted agent An agent on your own box that takes work from webhooks, timers and your shell.
- Agentic workflows Multi-step agent pipelines in one TOML file: parallel, loop until it passes, fan-out.
- MCP client Plug any stdio or HTTP MCP server into a terminal agent, and add more mid-session.
- Self-improving agent Correct the agent once. It saves the fix as a file and recalls it next session.
- Agent backend Your app talks to one WebSocket. octomind runs the agent, its tools and the bill per user.
Start with one command
Apache-2.0 and any model. Install it, then run step one above.
curl -fsSL https://octomind.run/install.sh | bash