mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
docs: add child runs guide
Document child-run orchestration as a first-class execution concept and link the related MCP, UI, and API surfaces back to it.
This commit is contained in:
parent
2a2b410802
commit
879969cf54
10 changed files with 245 additions and 8 deletions
|
|
@ -228,12 +228,12 @@ export default function RunChildren() {
|
|||
description="When you launch another run with this run as its parent, it will appear here."
|
||||
action={
|
||||
<a
|
||||
href="https://docs.fabro.sh/reference/cli#fabro-parent-link"
|
||||
href="https://docs.fabro.sh/execution/child-runs"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={SECONDARY_BUTTON_CLASS}
|
||||
>
|
||||
Learn about parent links
|
||||
Learn about child runs
|
||||
</a>
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ MCP ([Model Context Protocol](https://modelcontextprotocol.io/)) lets you connec
|
|||
|
||||
Fabro can also run as an MCP server. MCP clients can use Fabro's run-management tools to create, inspect, control, wait for, and read events from workflow runs through the authenticated `fabro` CLI.
|
||||
|
||||
Workflow agents can opt in to that same run-management tool catalog with `[run.agent] fabro_tools = true`. This is not the same as configuring external MCP servers for the agent, and it does not change the agent's normal workspace permissions. When a workflow agent calls `fabro_run_create`, created runs are always children of the current run; an explicit `parent_id` must match the current run ID.
|
||||
Workflow agents can opt in to that same run-management tool catalog with `[run.agent] fabro_tools = true`. This is not the same as configuring external MCP servers for the agent, and it does not change the agent's normal workspace permissions. When a workflow agent calls `fabro_run_create`, created runs are always [child runs](/execution/child-runs) of the current run; an explicit `parent_id` must match the current run ID.
|
||||
|
||||
## Fabro as an MCP server
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ Use the object form when you need create options:
|
|||
|
||||
Use `goal` for inline goal text or `goal_file` to read the run goal from a file. They are mutually exclusive. Relative `goal_file` paths resolve from the run's `cwd`, or from the MCP server working directory when `cwd` is omitted.
|
||||
|
||||
Run summaries returned by the MCP server include parent metadata. Use `parent_id` on `fabro_run_create` to create a child run, `parent_id` on `fabro_run_search` to list direct children, and the `link_parent` or `unlink_parent` actions on `fabro_run_interact` to change an existing run's parent.
|
||||
Run summaries returned by the MCP server include parent metadata. Use `parent_id` on `fabro_run_create` to create a child run, `parent_id` on `fabro_run_search` to list direct children, and the `link_parent` or `unlink_parent` actions on `fabro_run_interact` to change an existing run's parent. See [Child Runs](/execution/child-runs) for the orchestration model.
|
||||
|
||||
Use `fabro_run_pair` when an MCP client needs to pair with an active API-mode agent stage. The tool can inspect current pair status, start a pair session for a selected stage, send messages, end the session, and read transcript entries.
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ Sub-agents are most useful for:
|
|||
- **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 with no turn limit by default. Pass `max_turns` when you want predictable cost or time bounds. All active sub-agents are cleaned up automatically when the parent session closes.
|
||||
</Note>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
"icon": "play",
|
||||
"pages": [
|
||||
"execution/run-configuration",
|
||||
"execution/child-runs",
|
||||
"execution/environments",
|
||||
"execution/context",
|
||||
"execution/checkpoints",
|
||||
|
|
@ -185,7 +186,11 @@
|
|||
"GET /api/v1/runs",
|
||||
"POST /api/v1/runs",
|
||||
"GET /api/v1/runs/{id}",
|
||||
"PUT /api/v1/runs/{id}/parent",
|
||||
"DELETE /api/v1/runs/{id}/parent",
|
||||
"POST /api/v1/runs/{id}/start",
|
||||
"POST /api/v1/runs/{id}/approve",
|
||||
"POST /api/v1/runs/{id}/deny",
|
||||
"POST /api/v1/runs/{id}/cancel",
|
||||
"POST /api/v1/runs/{id}/pause",
|
||||
"POST /api/v1/runs/{id}/unpause",
|
||||
|
|
|
|||
226
docs/public/execution/child-runs.mdx
Normal file
226
docs/public/execution/child-runs.mdx
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
---
|
||||
title: "Child Runs"
|
||||
description: "Spawn and supervise additional Fabro runs from a parent run"
|
||||
---
|
||||
|
||||
A Fabro run can orchestrate other Fabro runs. An agent in the parent run can create child runs, inspect them, wait for them, and control them while the parent continues coordinating the larger job.
|
||||
|
||||
Child runs are full workflow runs. Each child has its own run ID, workflow, lifecycle, sandbox, events, checkpoints, artifacts, and outputs. The parent-child relationship gives Fabro a durable way to show, query, and manage the orchestration tree.
|
||||
|
||||
## When to use child runs
|
||||
|
||||
Use child runs when the unit of work is large enough to deserve its own workflow run:
|
||||
|
||||
- **Parallel workstreams** - launch implementation, review, migration, or validation runs at the same time.
|
||||
- **Specialized workflows** - delegate to purpose-built workflows for different repos, services, or review types.
|
||||
- **Long-running work** - let the parent keep coordinating while children run independently.
|
||||
- **Manager patterns** - build a parent workflow that creates workers, watches progress, gathers results, and decides what happens next.
|
||||
- **Variants and attempts** - run multiple approaches as separate durable runs with separate outputs.
|
||||
|
||||
For small subtasks inside one agent stage, use [sub-agents](/agents/subagents). For reusable workflow structure inside one run, use [sub-workflows](/tutorials/sub-workflow) or [imports](/workflows/imports).
|
||||
|
||||
## Enable run tools
|
||||
|
||||
Workflow agents can create and manage runs when the parent run opts in to Fabro's run-management tool catalog:
|
||||
|
||||
```toml title="run.toml"
|
||||
[run.agent]
|
||||
fabro_tools = true
|
||||
```
|
||||
|
||||
This exposes the same Fabro run tools available through [MCP](/agents/mcp):
|
||||
|
||||
| Tool | Purpose |
|
||||
|---|---|
|
||||
| `fabro_run_create` | Create one or more child runs, starting them by default |
|
||||
| `fabro_run_search` | Search runs, including direct children by `parent_id` |
|
||||
| `fabro_run_get` | Inspect a run without mutating it |
|
||||
| `fabro_run_interact` | Start, message, interrupt, cancel, archive, unarchive, link, unlink, inspect, or answer questions |
|
||||
| `fabro_run_gather` | Wait for runs to reach terminal states |
|
||||
| `fabro_run_events` | Read stored events for a run |
|
||||
| `fabro_run_pair` | Pair with an active API-mode agent stage |
|
||||
|
||||
<Note>
|
||||
When a workflow agent calls `fabro_run_create`, Fabro always parents the created runs to the current run. If the agent supplies `parent_id`, it must match the current run ID.
|
||||
</Note>
|
||||
|
||||
## Create child runs
|
||||
|
||||
The simplest `fabro_run_create` call names a workflow:
|
||||
|
||||
```json
|
||||
{
|
||||
"runs": ["implement-and-test"]
|
||||
}
|
||||
```
|
||||
|
||||
Use the object form to pass run options:
|
||||
|
||||
```json
|
||||
{
|
||||
"runs": [
|
||||
{
|
||||
"workflow": "implement-and-test",
|
||||
"goal": "Implement the checkout page refactor and run the test suite.",
|
||||
"labels": {
|
||||
"lane": "checkout",
|
||||
"source": "parent-run"
|
||||
},
|
||||
"start": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The parent can create several children in one call:
|
||||
|
||||
```json
|
||||
{
|
||||
"runs": [
|
||||
{
|
||||
"workflow": "implementation",
|
||||
"goal_file": "plans/api.md",
|
||||
"labels": { "lane": "api" }
|
||||
},
|
||||
{
|
||||
"workflow": "implementation",
|
||||
"goal_file": "plans/web.md",
|
||||
"labels": { "lane": "web" }
|
||||
},
|
||||
{
|
||||
"workflow": "review",
|
||||
"goal": "Review the current branch for security and data-integrity risks.",
|
||||
"labels": { "lane": "review" }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
By default, `fabro_run_create` requests start for each created run. Set `"start": false` when the parent should create the child now and start it later.
|
||||
|
||||
## Start and approval
|
||||
|
||||
Child run creation and child run execution are separate steps:
|
||||
|
||||
1. **Create** - `fabro_run_create` creates a durable run record with the current run as parent.
|
||||
2. **Start request** - if `start` is true, Fabro requests execution for the child.
|
||||
3. **Approval if required** - parent-generated child runs may enter `pending` with `approval_required`.
|
||||
4. **Schedule** - after approval, the child becomes `runnable` and the scheduler starts it when capacity is available.
|
||||
5. **Execute** - the child runs its own workflow and writes its own events, checkpoints, artifacts, and outputs.
|
||||
|
||||
The approval step prevents a workflow agent from recursively launching executing runs without an operator checkpoint. Approve or deny pending child runs from the web UI or through the run lifecycle API.
|
||||
|
||||
## Supervise children
|
||||
|
||||
A parent run can keep track of the children it creates.
|
||||
|
||||
List direct children:
|
||||
|
||||
```json
|
||||
{
|
||||
"parent_id": "01KRTKP5DJJ4EV6T7QSB081Z1N"
|
||||
}
|
||||
```
|
||||
|
||||
Wait for children to finish:
|
||||
|
||||
```json
|
||||
{
|
||||
"run_ids": [
|
||||
"01KRTM8V3WQ6E9M2A2R6B3G8HK",
|
||||
"01KRTM91N7W9S6BP2RZ6SXX4FR"
|
||||
],
|
||||
"timeout_seconds": 1800
|
||||
}
|
||||
```
|
||||
|
||||
Inspect a child:
|
||||
|
||||
```json
|
||||
{
|
||||
"run_id": "01KRTM8V3WQ6E9M2A2R6B3G8HK"
|
||||
}
|
||||
```
|
||||
|
||||
Cancel a child that is no longer useful:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "cancel",
|
||||
"run_id": "01KRTM8V3WQ6E9M2A2R6B3G8HK"
|
||||
}
|
||||
```
|
||||
|
||||
Read a child's events:
|
||||
|
||||
```json
|
||||
{
|
||||
"run_id": "01KRTM8V3WQ6E9M2A2R6B3G8HK",
|
||||
"limit": 100
|
||||
}
|
||||
```
|
||||
|
||||
Child listings are direct. To walk a larger tree, list each child as a parent and repeat.
|
||||
|
||||
## Web UI
|
||||
|
||||
Run detail pages include a **Children** tab. It lists runs whose `parent_id` is the current run, shows a count badge on the tab, supports refresh, filtering, sorting, and archived-run visibility, and uses the same run list layout as the main runs page.
|
||||
|
||||
Use this tab when you want to see the work a manager run delegated, jump into a child run, inspect child output, or verify that a child has finished.
|
||||
|
||||
## CLI and API
|
||||
|
||||
You can also create and organize child runs outside a workflow agent.
|
||||
|
||||
Create a run under an existing parent:
|
||||
|
||||
```bash
|
||||
fabro run child.fabro --parent parent-run
|
||||
fabro create child.fabro --parent parent-run
|
||||
```
|
||||
|
||||
List direct children:
|
||||
|
||||
```bash
|
||||
fabro ps --parent parent-run
|
||||
```
|
||||
|
||||
Repair or reorganize relationships:
|
||||
|
||||
```bash
|
||||
fabro parent link child-run parent-run
|
||||
fabro parent unlink child-run
|
||||
```
|
||||
|
||||
The HTTP API exposes the same model:
|
||||
|
||||
| Operation | Purpose |
|
||||
|---|---|
|
||||
| `POST /api/v1/runs` with `parent_id` | Create a run under a parent |
|
||||
| `GET /api/v1/runs?parent_id=...` | List direct children |
|
||||
| `PUT /api/v1/runs/{id}/parent` | Link or replace a run's parent |
|
||||
| `DELETE /api/v1/runs/{id}/parent` | Remove a run's parent link |
|
||||
| `POST /api/v1/runs/{id}/approve` | Approve a pending child run |
|
||||
| `POST /api/v1/runs/{id}/deny` | Deny a pending child run |
|
||||
|
||||
## Relationship rules
|
||||
|
||||
Parent-child links are orchestration metadata:
|
||||
|
||||
- A run can have one parent and any number of direct children.
|
||||
- Creating or linking a child requires the parent run to exist.
|
||||
- Self-parenting and cycles are rejected.
|
||||
- Parent links can be changed for active, terminal, and archived runs.
|
||||
- A child can keep its historical parent reference even if the parent run is later removed.
|
||||
- Parent-child links are not fork or rewind lineage. Fork and rewind use separate source fields.
|
||||
|
||||
## Related concepts
|
||||
|
||||
| Concept | Runtime boundary | Use it for |
|
||||
|---|---|---|
|
||||
| Child runs | Separate durable runs connected by `parent_id` | Orchestrating independent workflows |
|
||||
| Sub-agents | Separate LLM sessions inside one agent stage | Delegating small agent subtasks without creating runs |
|
||||
| Sub-workflows | A child workflow engine inside the same run | Reusing a workflow with runtime isolation but one parent run |
|
||||
| Imports | Parse-time graph expansion | Reusing graph structure without a runtime boundary |
|
||||
| Forks and rewinds | New runs from an existing checkpoint | Exploring or replacing execution from prior run state |
|
||||
| Parallel branches | Concurrent branches inside one workflow run | Splitting work within a single graph |
|
||||
|
|
@ -428,7 +428,7 @@ fabro_tools = true
|
|||
|
||||
`fabro_tools` defaults to `false`. Set it to `true` only for runs whose agents should be able to use the same Fabro run-management MCP tool catalog exposed to human MCP clients: create, search, get, interact, gather, events, and pair.
|
||||
|
||||
One workflow-agent exception is intentional: `fabro_run_create` always creates child runs parented to the current run. If an agent supplies `parent_id`, it must match the current run ID.
|
||||
One workflow-agent exception is intentional: `fabro_run_create` always creates [child runs](/execution/child-runs) parented to the current run. If an agent supplies `parent_id`, it must match the current run ID.
|
||||
|
||||
This setting is separate from normal agent `permissions` and from MCP server configuration. `permissions` controls workspace tool access, while `[run.agent.mcps]` configures external MCP servers available to the agent.
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ Key server config options:
|
|||
### Run lifecycle
|
||||
|
||||
1. **Submit** — `POST /api/v1/runs` with a Graphviz workflow source. The run is created with status `submitted` and the response returns immediately with the run ID.
|
||||
2. **Start request** — `POST /api/v1/runs/{id}/start` moves normal runs to `runnable`. Parent-generated child runs may move to `pending` with `approval_required`.
|
||||
2. **Start request** — `POST /api/v1/runs/{id}/start` moves normal runs to `runnable`. Parent-generated [child runs](/execution/child-runs) may move to `pending` with `approval_required`.
|
||||
3. **Approve if needed** — `POST /api/v1/runs/{id}/approve` moves an approval-gated run to `runnable`; `deny` fails it with `approval_denied`.
|
||||
4. **Schedule** — A background scheduler promotes `runnable` runs to `running` in FIFO order, up to the concurrency limit.
|
||||
5. **Execute** — The engine walks the graph, streaming events to all subscribers.
|
||||
|
|
|
|||
|
|
@ -61,12 +61,12 @@ Workflows are submitted via the REST API and executed in the background. The exa
|
|||
curl -X POST http://localhost:3000/api/v1/runs
|
||||
```
|
||||
|
||||
The server returns immediately with a run ID. After a start request, a background scheduler promotes `runnable` runs to `running` in FIFO order, up to the concurrency limit. Parent-generated child runs can remain `pending` until a user approves them.
|
||||
The server returns immediately with a run ID. After a start request, a background scheduler promotes `runnable` runs to `running` in FIFO order, up to the concurrency limit. Parent-generated [child runs](/execution/child-runs) can remain `pending` until a user approves them.
|
||||
|
||||
## Run lifecycle
|
||||
|
||||
1. **Submit** — `POST /api/v1/runs` creates the run with status `submitted`.
|
||||
2. **Start request** — `POST /api/v1/runs/{id}/start` makes normal runs `runnable`; parent-generated child runs may become `pending` with `approval_required`.
|
||||
2. **Start request** — `POST /api/v1/runs/{id}/start` makes normal runs `runnable`; parent-generated [child runs](/execution/child-runs) may become `pending` with `approval_required`.
|
||||
3. **Approve if needed** — Approving a pending child run makes it `runnable`; denying it fails with `approval_denied`.
|
||||
4. **Schedule** — The scheduler picks up `runnable` runs up to `max_concurrent_runs`.
|
||||
5. **Execute** — The engine walks the graph, streaming events to all subscribers.
|
||||
|
|
|
|||
|
|
@ -121,6 +121,8 @@ Sub-workflows are most valuable when:
|
|||
|
||||
For simpler cases, just add more nodes to a single workflow. Sub-workflows add a layer of indirection — use them when the benefits of reuse or encapsulation justify it.
|
||||
|
||||
Use [child runs](/execution/child-runs) instead when the delegated work should be a separate durable run that can be listed, approved, cancelled, retried, inspected, and supervised independently.
|
||||
|
||||
## What you've learned
|
||||
|
||||
- **Sub-workflow nodes** (`shape=house`) run a child workflow inside a parent
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ A workflow can pull in another `.fabro` file as a reusable subgraph. Use imports
|
|||
|
||||
Imports are resolved at parse time: the imported graph is merged into the parent's graph, with node IDs prefixed to avoid collisions. There is no runtime "sub-workflow" boundary; once merged, an imported node behaves like any other node in the run.
|
||||
|
||||
If you need runtime delegation to separate durable runs, use [child runs](/execution/child-runs) instead.
|
||||
|
||||
## Basic example
|
||||
|
||||
Place a node in the parent graph with an `import` attribute pointing at the file to splice in:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue