Sub-Agents
Sub-agents are child agent instances spawned by the harness to run a scoped task with a restricted toolset. Each runs in its own Zellij pane and communicates with the parent through files on disk.
Source: crates/core/src/subagent.rs, crates/core/src/spawn.rs,
crates/core/src/subagent_config.rs.
How spawning works
The parent calls the built-in spawn_subagent tool. The harness then:
- Writes the task to
prompt.mdand the filtered tool manifest totools.jsonin a new directory under<cowboy_dir>/subagents/. - Spawns a new plugin instance via Zellij’s
load_new_plugin()(a visible pane,load_in_background: false,skip_plugin_cache: true), passing a JSON-encodedSubagentConfigunder thesubagent_configkey. - The child, on its first heartbeat tick, writes a
lockfile and itspane_id, readsprompt.md+tools.json, and processes the prompt as a user message. - When the child finishes, it writes
response.mdand removeslock. - The parent detects completion on its heartbeat poll and injects the response back into its own conversation.
WASM cannot write files directly, so all disk I/O is funneled through shell commands the harness emits and Zellij executes.
Directory layout
Each sub-agent gets a directory named <type>-<short_uuid>:
<cowboy_dir>/subagents/<type>-<id>/
prompt.md # task + metadata, written by parent
tools.json # filtered tool manifest, written by parent
lock # present while running, written by child
pane_id # Zellij pane id, written by child
response.md # final output, written by child on completion
<cowboy_dir> is $HOME on a ranch install and
$XDG_DATA_HOME/cowboy (default ~/.local/share/cowboy) in lite mode.
Sub-agent types
Three types are defined in the SubAgentType enum. Each restricts the tools
the child may call:
| Type | Allowed tools |
|---|---|
| Research | read, search, find, web-search, ls |
| Code | read, write, search, find, bash, ls, __HASHLINE_READ__, __HASHLINE_EDIT__ |
| Review | read, search, find, bash, ls |
Research and Review are read-only with respect to the filesystem; only Code
gets write and the hashline edit tool.
Models
SubagentConfig::cheap_defaults() picks an inexpensive model so sub-agents are
cheap to run. The default per provider:
| Provider | Default sub-agent model |
|---|---|
| OpenAI | gpt-4o-mini |
| OpenRouter | openai/gpt-4o-mini |
| Anthropic | claude-3-5-haiku-latest |
| Ollama | mistral:7b |
The selection falls back to the main harness provider/model, then to the first available keyed provider.
Status
The parent tracks each child with the SubAgentStatus enum:
Starting— directory created, pane spawningRunning—lockpresentCompleted—response.mdpresent,lockremovedFailed(String)—lockremoved without aresponse.md
Polling happens on the heartbeat timer.