fabro/docs/public/agents/subagents.mdx
Bryan Helmkamp 18a3c4741e
Run agent stages, Ask Fabro, and fabro exec on pebble's CodingAgent
Replace fabro's hand-written agent loop with pebble's `CodingAgent` and
delete the `fabro-agent` crate.

Workflow: `PebbleBackend` builds one agent per stage over `RunSandbox`,
binds the stage's hooks as tool middleware, the interviewer as the
human-input provider, and a durable `EventSink` that writes every agent
event through the run event log before the agent goes on. Full-fidelity
threads continue across stages through `export`/`resume_from_export`.
Model failover takes the session record after the failed prompt and
continues it on the next route with `ResumeMode::UseModel`, so no tool
effect repeats. The steering hub targets pebble's control handle, with
a steering lease holding completion open while a human is paired.

Events: `EventBody::Agent` carries pebble's `CodingAgentEvent` envelope;
the per-variant bodies, the transcript projection, and the fabro-only
context-window, tool-summary, and skill types are gone in favor of
pebble's. The OpenAPI schemas, generated Rust and TypeScript clients,
and web readers follow.

Ask Fabro: the session runs a `CodingAgent` under a read-only permission
policy and a system prompt transform. Its conversation lives in a new
`run_session_records` table and resumes on the recorded model with the
event cursor advanced past the run log.

`fabro exec` builds the same agent over a local sandbox with pebble's
permission middleware and an interactive approval service.

The catalog fills in `metadata.agent.profile` for operator providers
that declare none, so pebble's lookup is the one resolution path.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:19:15 -06:00

106 lines
4.3 KiB
Text

---
title: "Sub-agents"
description: "Delegate subtasks to child agent sessions"
---
An agent can spawn **sub-agents** to delegate work to independent child sessions. Each sub-agent gets its own LLM session and tool access, runs concurrently with the parent, and returns its result when finished.
<Note>
Sub-agents are only available with the [API backend](/core-concepts/agents#api-backend-default) (the default). Agents using the [ACP backend](/core-concepts/agents#acp-backend) cannot spawn Fabro sub-agents.
</Note>
## Tools
Sub-agent management is exposed through four built-in tools:
| Tool | Description |
|---|---|
| `spawn_agent` | Create a new sub-agent with a task prompt |
| `send_input` | Send follow-up input to a running or completed sub-agent |
| `wait` | Block until a sub-agent completes and return its result |
| `close_agent` | Close a running or completed sub-agent |
These tools are registered automatically when the session starts. They inherit the parent's permissions.
## Session isolation
Each sub-agent runs in its own session:
- **Own conversation** -- the child starts with a fresh LLM history
- **Own tool access** -- the child can use the same tools as the parent
- **Concurrent execution** -- the parent can continue working before calling `wait`
The parent can spawn multiple sub-agents and synchronize with them later.
## Continue a completed session
A completed sub-agent remains available until the parent closes it. Calling `send_input` starts another turn in the same child session, so the child keeps its conversation history. A message sent while the child is still running is queued for a safe turn boundary instead.
Call `wait` again to receive the new turn's result. Call `close_agent` when the child is no longer needed; a closed child cannot accept more input.
## Depth limits
Sub-agents can themselves spawn sub-agents, creating a hierarchy. The coding agent limits how many child sessions a stage can hold open at once and how deep the tree can grow; the defaults keep one level of children.
If a child tries to exceed the limit, `spawn_agent` returns an error immediately.
## Error handling
Sub-agent failures do not automatically fail the parent stage. The parent receives the failure through `wait` and decides how to respond.
Common cases:
- **Panics or errors** -- returned as a failed `wait` result
- **`spawn_agent` fails** -- returned immediately as a tool result
## Event forwarding
Sub-agent observability now uses **session linkage**, not wrapper events.
Parent-owned lifecycle events:
| Event | When |
|---|---|
| `agent.sub.spawned` | A sub-agent was created |
| `agent.sub.completed` | A sub-agent finished successfully |
| `agent.sub.failed` | A sub-agent failed |
| `agent.sub.closed` | A sub-agent was cancelled |
Forwarded child activity:
- Child tool calls, assistant messages, warnings, and other non-noisy session events are forwarded into the parent run's event stream as normal agent events.
- The forwarded event keeps the child's `session_id`.
- `parent_session_id` points to the child's immediate parent session.
Example envelope:
```json
{
"event": "agent.tool.started",
"session_id": "ses_child",
"parent_session_id": "ses_parent",
"node_id": "code",
"properties": {
"tool_name": "read_file"
}
}
```
Nested sub-agents preserve the immediate parent-child relationship. A grandchild forwarded through multiple parents still carries its own `session_id`, and `parent_session_id` remains set to the grandchild's direct parent rather than the root.
High-volume streaming events such as text deltas and tool output deltas are filtered out of the forwarded stream to reduce noise.
## When to use sub-agents
Sub-agents are most useful for:
- **Parallel research** -- inspect multiple code paths at once
- **Isolation** -- try a risky approach without polluting the parent's context
- **Divide and conquer** -- split an independent task into smaller pieces
- **Context management** -- offload work when the parent session is getting crowded
Use [child runs](/execution/child-runs) instead when the delegated work should be a separate Fabro run with its own workflow, lifecycle, sandbox, checkpoints, and outputs.
<Note>
Sub-agents run until they complete, fail, are cancelled, or hit the session's wall-clock timeout. All active sub-agents are cleaned up automatically when the parent session closes.
</Note>