Multi-Agent Orchestration¶
Minibot supports multi-agent orchestration with specialist AI agents, tool scoping, and
delegation. Agent definitions live in ./agents/*.md as markdown files with YAML
frontmatter followed by a system prompt body. The main agent discovers and delegates to
specialists at runtime.
Delegation Tools¶
fetch_agent_info— inspect a specialist’s name, description, defaults and system prompt. Always enabled when specialist definitions exist.delegate— hand work to a specialist by exactagent_namewhen the main agent needs the result to keep working. The result comes back as a new turn. Requires[tasks].enabled(on by default; the SQLite backend needs no broker). See Async Tasks.spawn_task— the same hand-off, but the worker’s answer is the final deliverable and goes straight to the user. Registered only with[tasks] delegation_mode = "auto"(the default).
Delegation is asynchronous: both tools return a task_id and the main agent does not wait inside the
turn. With spawn_task the worker’s answer, including any files it produced, is sent straight to the
conversation as a later message (fire and forget). A short notice with the agent, the task id and the outcome
is also recorded in the conversation history as a user message, so the main agent knows the task finished and
can call get_task for its result on the user’s next message. The worker’s output itself is never written
to the history. Use delegate when the main agent needs the result to keep working, such as a second step
that depends on it or a comparison: the result then comes back as a new turn, saved to the conversation
history, and the main agent answers from it instead of the raw worker text. Failures and timeouts come back
the same way, so the agent can explain or retry. Worker output reaches the model marked as untrusted data.
One turn can start at most three delegations, and a chain of delegated tasks is limited to three levels; past
either limit delegate is rejected with task:continuation_limit and the model answers the user or uses
spawn_task. [tasks] delegation_mode = "delegate" registers only delegate (no spawn_task), so
every task continues the turn; past the limits it falls back to fire and forget instead of failing, and its
result reports "continue_turn": false. The default, "auto", leaves the choice to the model through the
tool it calls. The removed continue_turn_mode = "always" is now delegation_mode = "delegate", and
continue_turn_default is gone. A rate-limit retry notice still goes straight to the user, and a
delegated task that is cancelled does not report back. Use get_task to retrieve a result, list_tasks
to see what is running, and cancel_task to stop one.
Two switches decide whether any of this exists. [orchestration.specialists].enabled (default
true) is the one for specialists themselves: with it off, the roster, fetch_agent_info and
named delegation all disappear, and delegate and spawn_task still run a generic worker. [tasks].enabled
(default true) is the execution backend, so the default follows it: with tasks off and the key
omitted the roster is disabled. An explicit [orchestration.specialists].enabled = true with
[tasks].enabled = false is a config error rather than a roster nothing can act on. Turning
[tasks] off turns multi-agent orchestration off as well: the specialist roster is dropped from
the system prompt along with the tool that could act on it.
Runtime Agent Management¶
Runtime management is separate and off by default. [orchestration.agent_management]
reload = true exposes reload_agents so an owner can hand-edit agents/*.md and re-read
them without a restart; write = true additionally exposes controlled create_agent,
update_agent and delete_agent tools for model-authored definitions. Neither switch changes
how existing owner-authored agents run.
The four modes, all reachable by config alone:
Mode |
Config |
What exists |
|---|---|---|
No specialists |
|
No roster, no |
Owner-only (default) |
both management switches false |
The roster and delegation, from files you write. No management tools or skill at all. |
Reload only |
|
Adds |
Managed agents |
|
Adds |
A managed definition is never more powerful than the ceiling in
[orchestration.agent_management]. It may not use tools_deny, must grant exact tool names,
claims MCP servers through mcp_servers, and may only target a provider the owner listed. Owner
files are not subject to the ceiling, so the two trust levels stay distinct. The loader records
which directory each definition was read from; a symlink in the managed directory remains managed,
including when the worker applies model overrides. Creating or updating a managed definition whose
name collides with an enabled owner-authored agent is rejected before writing. See Configuration Reference for
the field reference.
Runtime definition reads and managed writes run off the event loop. Reload prepares and validates candidate definitions in a worker thread, then applies the roster and tool changes on the event-loop thread. Cancelling a managed write waits for its filesystem operation to finish before releasing the management lock; cancellation does not roll back a completed write.
That ceiling bounds what an agent may be told to do; it is not a sandbox. A managed agent granted
bash or the managed-file tools can reach anything the daemon’s OS user can, exactly as an owner-authored
one can. See Security & Sandboxing.
Main-agent visibility is a separate thing from the managed ceiling. [orchestration.main_agent]
and tool_ownership_mode decide what the main agent sees; they never widen or narrow what a
specialist may be granted, and a specialist may deliberately own a tool the main agent is denied.
Agent Definitions¶
Minimal example:
---
name: workspace_manager_agent
description: Handles workspace file operations
mode: agent
model_provider: openai_responses
model: gpt-5.6-luna
temperature: 0.1
tools_allow:
- list_files
- file_info
- write_file
- move_file
- delete_file
- send_file
- glob_files
- read_file
- self_insert_artifact
---
You manage files in the workspace safely and precisely.
Frontmatter fields: name, description, mode (always "agent"), enabled
(default true), model_provider, model, temperature, max_new_tokens,
omit_temperature (send no temperature at all, for models that reject the parameter),
reasoning_effort, max_tool_iterations, timeout_seconds (per-agent wall-clock budget; it is the
default when a spawn_task or delegate call names no timeout_seconds of its own, capped by
[tasks].worker_timeout_seconds), tools_allow,
tools_deny, mcp_servers.
Tool Scoping¶
tools_allow and tools_deny are mutually exclusive. Wildcards (fnmatch) are supported:
tools_allow: ["mcp_dice_cli__*"]tools_deny: ["mcp_dice_cli__roll_dice"]
Behavior rules:
If neither is set, local (non-MCP) tools are not exposed to the agent.
mcp_serverslimits MCP tools to the listed server names; tools from other servers are excluded.In
tools_allowmode: allowed local tools + allowed MCP-server tools are exposed.In
tools_denymode: all local tools except denied + allowed MCP-server tools are exposed.A local-only agent: use
tools_deny: ["mcp*"]with nomcp_servers.
Main-agent tool policy is set under [orchestration.main_agent]:
[orchestration.main_agent]
tools_allow = ["memory_*", "schedule_prompt", "http_request"]
tool_ownership_mode under [orchestration] controls sharing:
shared(default) — all agents share tools.exclusive— specialist-owned tools are removed from the main agent.exclusive_mcp— only specialist-owned MCP tools are removed from the main agent.
shared_mcp_servers lists MCP servers that stay visible to the main agent in both exclusive modes,
even when a specialist also claims them — for example a read-only web search server that both the
main agent and a research specialist use. The [orchestration.main_agent] tools_allow and
tools_deny policy still applies first, so tools_deny = ["mcp*"] hides a shared server too:
[orchestration]
tool_ownership_mode = "exclusive_mcp"
shared_mcp_servers = ["exa"]
Assigning an MCP server to an agent:
---
name: dice_agent
description: Dice-rolling specialist
mode: agent
model_provider: openai_responses
model: gpt-5.6-luna
mcp_servers:
- dice_cli
---
Use the dice tools to roll and report results.
Browser Automation¶
Browser automation is not MCP-based: the specialist drives the playwright-cli
binary directly through the bash tool, guided by a skill rather than a remote
MCP server. See agents/browser_agent.md for the canonical setup — its
tools_allow lists bash, list_files, read_file, grep, http_request,
pre_response, and wait (no mcp_servers entry).
Agent Skills¶
Skills are reusable instruction packs the model loads on demand, and they are shared with the
main agent rather than being an orchestration feature. The browser_agent above is driven by a
skill rather than an MCP server.
With tools_allow, a specialist gets skill tools only when listed: activate_skill, plus
list_skills if it should discover skills on its own. A tools_deny specialist gets both
(and wait, when enabled) unless it denies them. Unlike the main
agent, a specialist receives no skill catalog in its prompt, so without list_skills its prompt
must name the skill to activate. install_skill is never available to a specialist.
See Agent Skills for the format, discovery order, and configuration.
OpenRouter Custom Params per Agent¶
For agents running on OpenRouter, override provider-routing params in frontmatter using
openrouter_provider_<field_name> keys:
---
name: browser_agent
description: Browser automation specialist
mode: agent
model_provider: openrouter
model: x-ai/grok-4.3
openrouter_provider_only:
- openai
- anthropic
openrouter_provider_sort: price
openrouter_provider_allow_fallbacks: true
---
Use browser tools to navigate, inspect, and extract results.
Supported keys mirror [llm.openrouter.provider] fields (only, sort, order,
allow_fallbacks, max_price, etc.). Agent-level values override global provider config
for matching fields. Keep credentials in [providers.openrouter] — never in agent files.
Choosing a Model¶
Run minibot configure and it queries your configured provider for the models it currently
serves, then offers them as a list — which beats any set of names written down here, since those go
stale as providers retire and rename models. The model IDs in the examples above are illustrative
only; use whatever your provider lists.
reasoning_effort is unset by default, which leaves the provider’s own default in place. Set it
per agent when you want to steer that: higher for agents that plan multi-step work, lower for agents
that mostly call one tool and summarize.
Retargeting One Call¶
The frontmatter above is the agent’s default, not a fixed binding. spawn_task and delegate accept
model_provider, model and reasoning_effort for a single task, so the main agent can
honour a request like “run that on the deepseek subagent, high effort” without a config change or
a restart. The specialist’s prompt, tool scope and timeouts are unchanged; only the target model is.
fetch_agent_info is the discovery surface: besides the specialist’s prompt it returns that
agent’s own defaults and the providers that actually have credentials configured, with their
api_format, base_url and advisory models list (see Named providers). A provider
that is not on that list is rejected before the task is queued, because a provider without a key
would otherwise answer with MiniBot’s local echo fallback.
A retargeted task keeps its budget: the context window and output cap are re-derived from the target model’s own limits rather than inherited from the agent’s frontmatter, so mid-run compaction stays armed. A model that models.dev does not list has no known window and runs without compaction.