···4040Executes local `bash` commands to call existing CLIs, run one-off conversions, execute scripts, or inspect the local environment.
41414242- Key limits: can be disabled via `tools.bash.enabled`; restricted by `deny_paths` and internal deny-token rules; child processes inherit only an allowlisted environment.
4343-- Current subtask behavior: accepts `run_in_subtask=true` for an explicit direct subtask boundary; when the current runtime exposes a stream sink, stdout/stderr chunks can be previewed before the command exits.
4343+- Current isolated-execution behavior: accepts `run_in_subtask=true` and runs the command inside one direct boundary; when the current runtime exposes a stream sink, stdout/stderr chunks can appear in the preview stream before the command exits.
44444545### `url_fetch`
4646···66666767### `spawn`
68686969-Starts a subtask with its own context and an explicit tool whitelist. The parent agent blocks until the child finishes and receives a structured result envelope.
6969+Starts a subagent with its own context and an explicit tool whitelist. The parent agent waits synchronously until the inner run finishes, then receives a structured JSON envelope.
70707171-- Key limits: can be disabled via `tools.spawn.enabled`; the child can use only the tool names passed in `tools`; raw child transcript is not returned to the parent loop by default.
7272-- Current depth limit: the built-in subtask mechanism currently allows only one child layer. A child task cannot spawn another child task.
7171+- Key limits: can be disabled via `tools.spawn.enabled`; the inner agent can use only the tool names passed in `tools`; raw transcript is not returned to the parent loop by default.
7372- Current observer hint: `spawn` accepts an optional `observe_profile` parameter. `default` keeps mid-run previews conservative, `long_shell` is suited to long shell/log output, and `web_extract` suppresses raw noisy output until better stage signals exist.
74737575-For parameter details, result envelope fields, and the difference between `spawn` and `bash.run_in_subtask=true`, see [Subagents and Subtasks](/guide/subagents).
7474+For parameter details, result envelope fields, test prompts, and the difference from `bash.run_in_subtask=true`, see [Subagents](/guide/subagents).
76757776## Runtime Tools
7877
+1-1
web/vitepress/docs/guide/overview.md
···1919- To get running quickly: read [Quickstart (CLI)](/guide/quickstart-cli)
2020- To embed it into a Go project: read [Create Your Own AI Agent in 24 Lines](/guide/build-your-own-agent)
2121- To understand long-running entry points: read [Runtime Modes](/guide/runtime-modes)
2222-- To delegate isolated child work: read [Subagents](/guide/subagents)
2222+- To delegate isolated work: read [Subagents](/guide/subagents)
2323- For pre-production governance: read [Security and Guard](/guide/security-and-guard)
+109-64
web/vitepress/docs/guide/subagents.md
···11---
22-title: Subagents and Subtasks
33-description: "When to use `spawn`, when to use `bash.run_in_subtask`, and what the runtime guarantees."
22+title: Subagents
33+description: "Typical scenarios first, then a high-level overview, then the current implementation details and test prompts."
44---
5566-# Subagents and Subtasks
66+# Subagents
7788-Mistermorph currently has two explicit ways to put work behind a child-task boundary:
88+## Common Scenarios
991010-- `spawn`: starts a child agent with its own LLM loop and an explicit tool whitelist.
1111-- `bash.run_in_subtask=true`: runs one shell command inside a direct subtask boundary without starting a second LLM loop.
1010+Use a subagent boundary mainly in these cases:
12111313-Both paths return the same `SubtaskResult` envelope shape and share the same depth limit.
1212+- A shell command is slow or noisy, and you want its output isolated from the parent loop.
1313+- The work is still multi-step, but you want the inner execution to operate with a narrower tool set.
1414+- You want one compact final result instead of leaking raw intermediate output back to the parent.
14151515-## Which entry to use
1616+Choose the entry like this:
16171717-- Use `spawn` when the child work still needs agent-style tool reasoning, such as `read_file` plus `url_fetch`, or a fetch-then-extract flow.
1818-- Use `bash.run_in_subtask=true` when the work is already one concrete shell command or script.
1919-- Do not use a child task for trivial one-step work that the parent can complete directly.
1818+- Use `bash.run_in_subtask=true` for one concrete shell command.
1919+- Use `spawn` when the inner execution still needs agent-style tool use such as `read_file`, `url_fetch`, or `bash`.
2020+- Do not add an isolated layer for trivial one-step work the parent can finish directly.
20212121-Current status: both paths are synchronous. The parent waits until the child finishes. This is isolation, not background execution.
2222+## Overview
2323+2424+Mistermorph currently exposes two explicit subagent entries:
2525+2626+| Entry | Starts another LLM loop | Best for | Returns |
2727+|---|---|---|---|
2828+| `spawn` | Yes | an inner agent that still needs tools and reasoning | `SubtaskResult` JSON envelope |
2929+| `bash.run_in_subtask=true` | No | one shell command with isolated execution/output | `SubtaskResult` JSON envelope |
22302323-## `spawn`
3131+Shared behavior:
3232+3333+- Both are synchronous. The parent waits until the inner run finishes.
3434+- Both share the same depth limit.
3535+- Both return the same top-level envelope shape.
3636+- Neither path sends the raw inner transcript back into the parent loop by default.
3737+3838+This feature is about isolation and result collection. It is not a background job system yet.
3939+4040+## Current Implementation
4141+4242+### `spawn`
24432525-`spawn` is an engine-scoped tool. It appears when an agent engine is assembled for a run.
4444+`spawn` is an engine-scoped tool. It appears only after an agent engine is assembled for a run.
26452746Parameters:
28472929-- `task`: required child prompt.
3030-- `tools`: required non-empty array of tool names the child may use.
3131-- `model`: optional child model override. Defaults to the parent model.
3232-- `output_schema`: optional contract label for structured output.
4848+- `task`: required prompt for the inner agent.
4949+- `tools`: required non-empty tool-name array.
5050+- `model`: optional model override for the inner agent.
5151+- `output_schema`: optional structured-output label.
3352- `observe_profile`: optional observer hint. Supported values are `default`, `long_shell`, and `web_extract`.
34533535-Runtime behavior:
5454+Current behavior:
5555+5656+- The inner registry is built from the tool names passed in `tools`.
5757+- Unknown or unavailable tool names are ignored.
5858+- If no usable tool remains, the call fails.
5959+- `spawn` is never re-exposed inside the inner agent, even if listed in `tools`.
6060+6161+### `bash.run_in_subtask=true`
6262+6363+This is the lighter isolated-execution path.
6464+6565+- It uses the direct isolated path behind `bash`.
6666+- It does not start a second LLM loop.
6767+- Its `output_schema` is fixed to `subtask.bash.result.v1`.
6868+- Its observer profile is fixed to `long_shell`.
6969+7070+Use it when the inner work is already one concrete shell step and does not need more tool decisions.
7171+7272+### Depth Limit
7373+7474+The current depth limit is `1`.
36753737-- The child registry starts from the `tools` names you pass. Unknown or unavailable names are ignored.
3838-- If none of the requested tool names are available in the parent registry, the call fails.
3939-- `spawn` is never re-exposed inside the child, even if you include it in `tools`.
4040-- The current depth limit is `1`, so a child task cannot start another child task.
4141-- Raw child transcript is not pushed back into the parent loop by default.
7676+- A root run can enter one isolated extra layer.
7777+- A run that is already inside that layer cannot enter another one.
42784343-### About `output_schema`
7979+### `output_schema`
44804545-`output_schema` is a schema identifier, not a built-in JSON Schema registry.
8181+`output_schema` is only a contract label. It is not a built-in JSON Schema registry.
46824747-If you set it:
8383+If you set it for `spawn`:
48844949-- the child is told to produce JSON final output;
8585+- the inner agent is told to produce JSON final output;
5086- the runtime requires the final output to be JSON or JSON-parsable text;
5151-- the same identifier is echoed back in `output_schema`.
8787+- the same identifier is echoed back in the result envelope.
52885353-Mistermorph does not validate the returned object against a real schema definition for you.
8989+Mistermorph does not validate the returned object against a real schema definition.
54905555-## Result Envelope
9191+### Result Envelope
56925757-Both `spawn` and direct subtasks return JSON in this shape:
9393+Both entries return JSON in this shape:
58945995```json
6096{
···68104}
69105```
701067171-Field meanings:
107107+Meaning of the fields:
7210873109- `status`: currently `done` or `failed`.
7474-- `summary`: short status text suitable for parent-side progress or preview.
110110+- `summary`: short status text for the isolated run.
75111- `output_kind`: `text` or `json`.
76112- `output_schema`: empty for plain text output, or the identifier you passed in.
7777-- `output`: child result payload.
7878-- `error`: non-empty only when the child fails.
113113+- `output`: the result payload.
114114+- `error`: set only when the run fails.
115115+116116+For `bash.run_in_subtask=true`, `output` is structured JSON with `exit_code`, truncation flags, `stdout`, and `stderr`.
117117+118118+### Test Prompts
791198080-## `bash.run_in_subtask=true`
120120+These are good smoke tests when `spawn` and `bash` are enabled.
121121+122122+#### Prompt 1: `spawn` + `bash`, return one line
811238282-This is the lighter child-task path.
124124+```text
125125+You must call the spawn tool. Do not answer directly. Allow the inner agent to use only bash. Have it run `printf 'alpha\nbeta\ngamma\n' | sed -n '2p'`. Return only the second line.
126126+```
831278484-- It uses the subtask runner directly and does not start a second LLM loop.
8585-- Its `output_schema` is fixed to `subtask.bash.result.v1`.
8686-- Its observer profile is fixed to `long_shell`.
8787-- The `output` payload contains `exit_code`, truncation flags, `stdout`, and `stderr`.
128128+Expected result: `beta`
881298989-Example payload:
130130+#### Prompt 2: `spawn` + `bash`, return structured JSON
131131+132132+```text
133133+You must call the spawn tool and set output_schema to `subagent.demo.echo.v1`. Allow the inner agent to use only bash. Have it run `echo '{"ok":true,"value":42}'`. Return structured JSON only, with no explanation.
134134+```
135135+136136+Expected result:
9013791138```json
9292-{
9393- "task_id": "sub_456",
9494- "status": "done",
9595- "summary": "bash exited with code 0",
9696- "output_kind": "json",
9797- "output_schema": "subtask.bash.result.v1",
9898- "output": {
9999- "exit_code": 0,
100100- "stdout_truncated": false,
101101- "stderr_truncated": false,
102102- "stdout": "hello\n",
103103- "stderr": ""
104104- },
105105- "error": ""
106106-}
139139+{"ok":true,"value":42}
140140+```
141141+142142+#### Prompt 3: `bash.run_in_subtask=true`
143143+144144+```text
145145+Call the bash tool and set `run_in_subtask` to true. Run `printf 'one\ntwo\nthree\n' | tail -n 1`. Do not explain anything. Return only the last line.
146146+```
147147+148148+Expected result: `three`
149149+150150+#### Prompt 4: longer isolated shell run
151151+152152+```text
153153+Call the bash tool and set `run_in_subtask` to true. Run `sleep 1; echo SUBAGENT_BASH_OK`. Reply with stdout only.
107154```
108155109109-Use this when you want a separate child-task envelope around one shell step, but do not need the child to make more tool calls.
156156+Expected result: `SUBAGENT_BASH_OK`
110157111111-## Config and Embedding
158158+### Config and Embedding
112159113160- `tools.spawn.enabled` controls only the explicit `spawn` tool entry.
114114-- Direct subtasks such as `bash.run_in_subtask=true` still use the subtask runtime even if `tools.spawn.enabled=false`.
115115-- `integration.Config.BuiltinToolNames` can include or omit `spawn`. It is not limited to static tools.
161161+- Direct isolated runs such as `bash.run_in_subtask=true` still work even if `tools.spawn.enabled=false`.
162162+- `integration.Config.BuiltinToolNames` can include or omit `spawn`.
116163- If you build an engine directly with `agent.New(...)`, `spawn` is enabled by default. Disable it with `agent.WithSpawnToolEnabled(false)`.
117164118165Example:
···122169cfg.BuiltinToolNames = []string{"read_file", "url_fetch", "spawn"}
123170cfg.Set("tools.spawn.enabled", true)
124171```
125125-126126-If you omit `spawn` from `BuiltinToolNames`, the agent loses the explicit child-agent tool, but the underlying subtask runtime can still be used by internal callers such as `bash.run_in_subtask=true`.
127172128173See also:
129174