feat(agent): delegate by default in proactive mode
The proactive prompt makes the primary an orchestrator: substantial work goes to subagents, small edits stay local, blocking work is delegated with required:true, and routing repeats for each request. It adds parallelism planning, a feature-branch sub-worktree workflow, and worktree cleanup. The lifecycle addendum is shorter.
- commit
- 2c1ebcbcc04e9c51ac76b1dafde0716dd9ad9f6d
- author
- brice · · 2026-10-18 17:58 UTC
- parent
- 5b5f89f
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
7 files · +84 -56
M README.md +3 -3
| @@ -271,7 +271,7 @@ Print-mode stats contain `provider`, `model`, `prompt_tokens`, `reasoning_tokens | |||
| 271 | 271 | - `ast`: search or rewrite source code structurally with an [ast-grep](https://ast-grep.github.io/) pattern. Prefer it when the operation depends on code syntax; use `grep`/`edit` for plain text. `language` is optional; when omitted, ast-grep infers it from each file's extension. Zut starts an installed `ast-grep` executable, or `sg` when it identifies itself as ast-grep, directly without a shell. Searches return compact `path:line` matches. Rewrites are planned in memory, shown as a diff for confirmation, checked against the active filesystem scope, verified against the files' current contents, written through a temporary file and rename with file permissions preserved, and followed by bounded diagnostics. When `grep` is given a regex that looks like a call or definition search and `ast` is available, its result includes a short `ast` suggestion. Install ast-grep separately; the tool returns a clear error when it is not available. | |
| 272 | 272 | - `bash`: run a command in the session cwd with merged stdout/stderr. Every call must include a positive integer `timeout` in seconds; calls without it or with `timeout <= 0` are rejected, and the deadline is always enforced. On Unix, zut uses `/bin/bash -c` when available, then `bash -c` from `PATH`, and falls back to POSIX `/bin/sh -c` when Bash is unavailable. On Windows, it uses `cmd /C`. macOS ships Bash 3.2 by default, so newer Bash features may be unavailable. | |
| 273 | 273 | - `python`: execute inline Python 3 code with an existing interpreter, never installing one. Every call must include nonblank `code` and a positive integer `timeout` in seconds (shared by interpreter discovery and execution). Each call runs a fresh stateless subprocess directly (`-u -B -`, code on stdin) in the session cwd with merged stdout/stderr; there is no persistent interpreter state, no script file, and no bytecode cache. Interactive input is unsupported (stdin observes EOF). Output is bounded (50 KiB, 2,000 lines) with explicit truncation marks; truncated results persist the byte-capped buffer to a temp file referenced as `full output` with its path in `full_output_path`, mirroring `bash`. Discovery order: `python_interpreter` in `$ZUT_HOME/config.json` (one executable path; relative paths resolve against the session cwd), then the active `VIRTUAL_ENV`, then `./.venv`, then `python3`/`python` on `PATH`. On Windows, Store aliases, `py` launchers, and install-manager entrypoints are rejected; only positively identified installed interpreters run. Missing packages fail with the ordinary import traceback. Tool arguments and output are recorded in the session like other tools; files the code deliberately writes persist. Save reusable scripts with `write`/`edit` instead of using `python` as an opaque file-edit path. Unavailable to packaged agents, and rejected while jailed (see below). | |
| 274 | - | - `worktree`: manage Git worktrees with the `create`, `list`, and `cleanup` actions. Creation checks out a new branch under `$ZUT_HOME/worktrees/<repo-id>`; an absolute local Git setting, `zut.worktrees.path`, overrides that root per repository. Listing inventories registered worktrees. Cleanup requires exact paths, confirmation through the normal preview gate, and revalidation immediately before removal. It refuses the primary worktree, dirty or detached checkouts, and commits not merged into the current branch. It removes neither local branches nor unmerged work. | |
| 274 | + | - `worktree`: manage Git worktrees with the `create`, `list`, and `cleanup` actions. Creation checks out a new branch under `$ZUT_HOME/worktrees/<repo-id>`, starting from the current HEAD or from `base` (a branch, tag, or commit); an absolute local Git setting, `zut.worktrees.path`, overrides that root per repository. Listing inventories registered worktrees. Cleanup requires exact paths, confirmation through the normal preview gate, and revalidation immediately before removal. It refuses the primary worktree, dirty or detached checkouts, and commits not merged into the current branch, or into `into` when given. With `delete_branch`, it also deletes each removed worktree's local branch, only while the branch is still at the inspected commit; it never deletes the merge target or a branch checked out in another worktree, and it reports a branch-deletion failure while keeping the removed worktrees removed. It never removes unmerged work. For a feature-branch workflow, create `feat/x` from main, then create sub-worktrees with `base: "feat/x"` (for example `feat/x-api`). After committing on each sub-branch and merging it into `feat/x`, clean up with `into: "feat/x"` and `delete_branch: true`. `list` also accepts `into` to check eligibility against that branch. | |
| 275 | 275 | - `lsp`: query configured language servers and linters for diagnostics, definitions, references, hover information, symbols, renames, code actions, capabilities, and raw protocol requests. LSP servers use stdio JSON-RPC; project `lsp.json` files can add or override servers and CLI linters. Diagnostics are bounded, sorted, deduplicated by path/severity/code/start position, and repeated issues are grouped before they reach the model. Successful native edits, writes, renames, and applied code actions automatically attach bounded diagnostics when available. See [docs/lsp.md](docs/lsp.md). | |
| 276 | 276 | - `web_search`: search DuckDuckGo HTML and return bounded source titles, URLs, snippets, and opaque references. `web_open` opens either a complete public URL or a referenced page, while `web_find` and `web_click` respectively find literal text in an opened page and follow a displayed link. The four tools are enabled together by default for normal CLI sessions and unavailable to bot, default SDK, and packaged-agent runs. See [docs/web-search.md](docs/web-search.md). | |
| 277 | 277 | - `update_goal`: let the main agent start its own mission when none is active, set the next bounded goal within an active mission, pause work while a decision is pending, resume it once settled, mark the active goal `done` or `blocked`, or atomically supersede an invalid goal with a necessary in-mission replacement. Users can also pause and resume through `/goal`; clearing remains user-controlled. | |
| @@ -457,7 +457,7 @@ Each child runs without a cumulative token budget or step cap: it inherits the p | |||
| 457 | 457 | ||
| 458 | 458 | Worktree isolation captures a patch and changed-file list without applying it. Shared children use the host checkout. The available logical references are `subagent://<id>`, `subagent://<id>/history`, `subagent://<id>/result`, and `subagent://<id>/patch`. | |
| 459 | 459 | ||
| 460 | - | **Proactive delegation.** With `/settings` → **proactive delegation** on (or `/orchestrator`), the interactive primary remains the owner and implementer of the task. Process start reveals neither the task nor which workers it needs, so it routes when the user states the request: the reply that starts the work names the parts it keeps on the critical path and the profile that owns each delegable part, before implementing or spawning anything. It delegates only concrete sidecars that can progress while the primary performs a preselected non-overlapping task; immediate blockers and tightly coupled work stay local. An active worker owns its scope until completion, so the primary does not repeat that investigation, review, testing, or implementation. If an explicit user request or workflow hands blocking work to a child, the primary yields for the host completion update instead. The canonical resident `subagent` tool remains available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll the status action or journal files solely to wait for completion. | |
| 460 | + | **Proactive delegation.** With `/settings` → **proactive delegation** on (or `/orchestrator`), the interactive primary acts as an orchestrator and delegates by default. Implementation, debugging, testing, review, and broad research go to workers; answers, quick lookups, edits of a few lines, and integration stay local. For each new request, the reply that starts the work names each part, its owner, and the profile for each delegated part. The primary maps dependencies, runs independent parts in parallel, and for multi-part features gives each worker a sub-worktree based on a feature branch, gates each result with a review before merging, and removes merged worktrees and branches when done. Blocking work is spawned with `required: true` and the primary yields for the host completion update. An active worker owns its scope until completion, so the primary does not repeat that investigation, review, testing, or implementation. The canonical resident `subagent` tool remains available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll the status action or journal files solely to wait for completion. | |
| 461 | 461 | ||
| 462 | 462 | ### Named subagent profiles | |
| 463 | 463 | ||
| @@ -471,7 +471,7 @@ Opens a dialog with every persistent setting. `up`/`down` to navigate, `enter` o | |||
| 471 | 471 | - **render images when supported** — draw screenshots / `read`-returned images inline using the terminal's image protocol, or fall back to a text placeholder. Auto-detected from `TERM_PROGRAM`; the toggle overrides the detection. The row is greyed out and forced off on terminals that don't speak any image protocol. | |
| 472 | 472 | - **terminal alerts** — emit a terminal bell when the main session stops with work that may need attention, or when an extension raises a structured alert. Enabled by default; changes apply immediately and persist as `terminal_alerts_enabled`. Terminal emulators may render the bell audibly, visually, or not at all. | |
| 473 | 473 | - **AI terminal titles** — after the first real prompt of a fresh interactive session, make one small hidden request to the active model and set the terminal title to `zut: <title>`. The title is limited to 40 Unicode characters, persisted with the session, restored on resume, and never added to the conversation. Enabled by default; disable it to avoid the extra model request. The toggle applies immediately, but title generation still waits for the first real prompt and never starts from startup context, resumed history, or slash commands. Persists as `terminal_title_enabled`. | |
| 474 | - | - **proactive delegation** — let the interactive primary delegate concrete, bounded sidecars while it keeps ownership of the critical path. Because the task and the workers it needs are unknown until the user states them, the primary routes at that point: the reply that starts the work names the parts it keeps on the critical path and the profile that owns each delegable part, and it states when nothing is worth delegating instead of forcing workers. Before spawning, it identifies useful local work and gives the child a non-overlapping question, responsibility, package, or file set. Immediate blockers and tightly coupled work stay local; after spawning, the worker owns its scope until completion and the primary continues only its preselected independent task. If a user request or active workflow explicitly delegates blocking work, the primary yields rather than reproducing it. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion and required-work state are host-driven through `[auto-subagents update]` and `[required-subagents update]` messages; required work stays asynchronous, persists its outcome, and prevents the terminal parent response until a successful completion. If launch-time restrictions prevent spawning, the interactive primary continues locally. Explicit headless `--orchestrate` remains a separate strict manager-only mode and reports unavailable delegation rather than implementing directly. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. | |
| 474 | + | - **proactive delegation** — make the interactive primary an orchestrator that delegates substantial work by default and keeps small edits, lookups, and integration local. See **Proactive delegation** above. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion and required-work state are host-driven through `[auto-subagents update]` and `[required-subagents update]` messages; required work stays asynchronous, persists its outcome, and prevents the terminal parent response until a successful completion. If launch-time restrictions prevent spawning, the interactive primary continues locally. Explicit headless `--orchestrate` remains a separate strict manager-only mode and reports unavailable delegation rather than implementing directly. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. | |
| 475 | 475 | - **fast mode** — request the provider's fast tier where supported. It currently uses OpenAI's Fast service tier for OpenAI, OpenAI Responses, and OpenAI Codex models. Off by default; toggle it with `/fast` or `/settings`; changes apply on the next model call and persist as `fast_mode`. When a model profile is active, the value is saved in that profile and restored when switching profiles. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account. | |
| 476 | 476 | - **lsp in main session** — enable the built-in `lsp` tool and code diagnostics for the main agent. Enabled by default; changes persist as `lsp_enabled`. | |
| 477 | 477 | - **lsp in sub-agents** — allow newly spawned background sub-agents to use the built-in `lsp` tool. Enabled by default; changes persist as `subagent_lsp_enabled` and apply when a child starts. | |
| @@ -271,7 +271,7 @@ Print-mode stats contain `provider`, `model`, `prompt_tokens`, `reasoning_tokens | |||||
| 271 | - `ast`: search or rewrite source code structurally with an [ast-grep](https://ast-grep.github.io/) pattern. Prefer it when the operation depends on code syntax; use `grep`/`edit` for plain text. `language` is optional; when omitted, ast-grep infers it from each file's extension. Zut starts an installed `ast-grep` executable, or `sg` when it identifies itself as ast-grep, directly without a shell. Searches return compact `path:line` matches. Rewrites are planned in memory, shown as a diff for confirmation, checked against the active filesystem scope, verified against the files' current contents, written through a temporary file and rename with file permissions preserved, and followed by bounded diagnostics. When `grep` is given a regex that looks like a call or definition search and `ast` is available, its result includes a short `ast` suggestion. Install ast-grep separately; the tool returns a clear error when it is not available. | 271 | - `ast`: search or rewrite source code structurally with an [ast-grep](https://ast-grep.github.io/) pattern. Prefer it when the operation depends on code syntax; use `grep`/`edit` for plain text. `language` is optional; when omitted, ast-grep infers it from each file's extension. Zut starts an installed `ast-grep` executable, or `sg` when it identifies itself as ast-grep, directly without a shell. Searches return compact `path:line` matches. Rewrites are planned in memory, shown as a diff for confirmation, checked against the active filesystem scope, verified against the files' current contents, written through a temporary file and rename with file permissions preserved, and followed by bounded diagnostics. When `grep` is given a regex that looks like a call or definition search and `ast` is available, its result includes a short `ast` suggestion. Install ast-grep separately; the tool returns a clear error when it is not available. | ||
| 272 | - `bash`: run a command in the session cwd with merged stdout/stderr. Every call must include a positive integer `timeout` in seconds; calls without it or with `timeout <= 0` are rejected, and the deadline is always enforced. On Unix, zut uses `/bin/bash -c` when available, then `bash -c` from `PATH`, and falls back to POSIX `/bin/sh -c` when Bash is unavailable. On Windows, it uses `cmd /C`. macOS ships Bash 3.2 by default, so newer Bash features may be unavailable. | 272 | - `bash`: run a command in the session cwd with merged stdout/stderr. Every call must include a positive integer `timeout` in seconds; calls without it or with `timeout <= 0` are rejected, and the deadline is always enforced. On Unix, zut uses `/bin/bash -c` when available, then `bash -c` from `PATH`, and falls back to POSIX `/bin/sh -c` when Bash is unavailable. On Windows, it uses `cmd /C`. macOS ships Bash 3.2 by default, so newer Bash features may be unavailable. | ||
| 273 | - `python`: execute inline Python 3 code with an existing interpreter, never installing one. Every call must include nonblank `code` and a positive integer `timeout` in seconds (shared by interpreter discovery and execution). Each call runs a fresh stateless subprocess directly (`-u -B -`, code on stdin) in the session cwd with merged stdout/stderr; there is no persistent interpreter state, no script file, and no bytecode cache. Interactive input is unsupported (stdin observes EOF). Output is bounded (50 KiB, 2,000 lines) with explicit truncation marks; truncated results persist the byte-capped buffer to a temp file referenced as `full output` with its path in `full_output_path`, mirroring `bash`. Discovery order: `python_interpreter` in `$ZUT_HOME/config.json` (one executable path; relative paths resolve against the session cwd), then the active `VIRTUAL_ENV`, then `./.venv`, then `python3`/`python` on `PATH`. On Windows, Store aliases, `py` launchers, and install-manager entrypoints are rejected; only positively identified installed interpreters run. Missing packages fail with the ordinary import traceback. Tool arguments and output are recorded in the session like other tools; files the code deliberately writes persist. Save reusable scripts with `write`/`edit` instead of using `python` as an opaque file-edit path. Unavailable to packaged agents, and rejected while jailed (see below). | 273 | - `python`: execute inline Python 3 code with an existing interpreter, never installing one. Every call must include nonblank `code` and a positive integer `timeout` in seconds (shared by interpreter discovery and execution). Each call runs a fresh stateless subprocess directly (`-u -B -`, code on stdin) in the session cwd with merged stdout/stderr; there is no persistent interpreter state, no script file, and no bytecode cache. Interactive input is unsupported (stdin observes EOF). Output is bounded (50 KiB, 2,000 lines) with explicit truncation marks; truncated results persist the byte-capped buffer to a temp file referenced as `full output` with its path in `full_output_path`, mirroring `bash`. Discovery order: `python_interpreter` in `$ZUT_HOME/config.json` (one executable path; relative paths resolve against the session cwd), then the active `VIRTUAL_ENV`, then `./.venv`, then `python3`/`python` on `PATH`. On Windows, Store aliases, `py` launchers, and install-manager entrypoints are rejected; only positively identified installed interpreters run. Missing packages fail with the ordinary import traceback. Tool arguments and output are recorded in the session like other tools; files the code deliberately writes persist. Save reusable scripts with `write`/`edit` instead of using `python` as an opaque file-edit path. Unavailable to packaged agents, and rejected while jailed (see below). | ||
| 274 | - | - `worktree`: manage Git worktrees with the `create`, `list`, and `cleanup` actions. Creation checks out a new branch under `$ZUT_HOME/worktrees/<repo-id>`; an absolute local Git setting, `zut.worktrees.path`, overrides that root per repository. Listing inventories registered worktrees. Cleanup requires exact paths, confirmation through the normal preview gate, and revalidation immediately before removal. It refuses the primary worktree, dirty or detached checkouts, and commits not merged into the current branch. It removes neither local branches nor unmerged work. | 274 | + | - `worktree`: manage Git worktrees with the `create`, `list`, and `cleanup` actions. Creation checks out a new branch under `$ZUT_HOME/worktrees/<repo-id>`, starting from the current HEAD or from `base` (a branch, tag, or commit); an absolute local Git setting, `zut.worktrees.path`, overrides that root per repository. Listing inventories registered worktrees. Cleanup requires exact paths, confirmation through the normal preview gate, and revalidation immediately before removal. It refuses the primary worktree, dirty or detached checkouts, and commits not merged into the current branch, or into `into` when given. With `delete_branch`, it also deletes each removed worktree's local branch, only while the branch is still at the inspected commit; it never deletes the merge target or a branch checked out in another worktree, and it reports a branch-deletion failure while keeping the removed worktrees removed. It never removes unmerged work. For a feature-branch workflow, create `feat/x` from main, then create sub-worktrees with `base: "feat/x"` (for example `feat/x-api`). After committing on each sub-branch and merging it into `feat/x`, clean up with `into: "feat/x"` and `delete_branch: true`. `list` also accepts `into` to check eligibility against that branch. |
| 275 | - `lsp`: query configured language servers and linters for diagnostics, definitions, references, hover information, symbols, renames, code actions, capabilities, and raw protocol requests. LSP servers use stdio JSON-RPC; project `lsp.json` files can add or override servers and CLI linters. Diagnostics are bounded, sorted, deduplicated by path/severity/code/start position, and repeated issues are grouped before they reach the model. Successful native edits, writes, renames, and applied code actions automatically attach bounded diagnostics when available. See [docs/lsp.md](docs/lsp.md). | 275 | - `lsp`: query configured language servers and linters for diagnostics, definitions, references, hover information, symbols, renames, code actions, capabilities, and raw protocol requests. LSP servers use stdio JSON-RPC; project `lsp.json` files can add or override servers and CLI linters. Diagnostics are bounded, sorted, deduplicated by path/severity/code/start position, and repeated issues are grouped before they reach the model. Successful native edits, writes, renames, and applied code actions automatically attach bounded diagnostics when available. See [docs/lsp.md](docs/lsp.md). | ||
| 276 | - `web_search`: search DuckDuckGo HTML and return bounded source titles, URLs, snippets, and opaque references. `web_open` opens either a complete public URL or a referenced page, while `web_find` and `web_click` respectively find literal text in an opened page and follow a displayed link. The four tools are enabled together by default for normal CLI sessions and unavailable to bot, default SDK, and packaged-agent runs. See [docs/web-search.md](docs/web-search.md). | 276 | - `web_search`: search DuckDuckGo HTML and return bounded source titles, URLs, snippets, and opaque references. `web_open` opens either a complete public URL or a referenced page, while `web_find` and `web_click` respectively find literal text in an opened page and follow a displayed link. The four tools are enabled together by default for normal CLI sessions and unavailable to bot, default SDK, and packaged-agent runs. See [docs/web-search.md](docs/web-search.md). | ||
| 277 | - `update_goal`: let the main agent start its own mission when none is active, set the next bounded goal within an active mission, pause work while a decision is pending, resume it once settled, mark the active goal `done` or `blocked`, or atomically supersede an invalid goal with a necessary in-mission replacement. Users can also pause and resume through `/goal`; clearing remains user-controlled. | 277 | - `update_goal`: let the main agent start its own mission when none is active, set the next bounded goal within an active mission, pause work while a decision is pending, resume it once settled, mark the active goal `done` or `blocked`, or atomically supersede an invalid goal with a necessary in-mission replacement. Users can also pause and resume through `/goal`; clearing remains user-controlled. | ||
| @@ -457,7 +457,7 @@ Each child runs without a cumulative token budget or step cap: it inherits the p | |||||
| 457 | 457 | ||||
| 458 | Worktree isolation captures a patch and changed-file list without applying it. Shared children use the host checkout. The available logical references are `subagent://<id>`, `subagent://<id>/history`, `subagent://<id>/result`, and `subagent://<id>/patch`. | 458 | Worktree isolation captures a patch and changed-file list without applying it. Shared children use the host checkout. The available logical references are `subagent://<id>`, `subagent://<id>/history`, `subagent://<id>/result`, and `subagent://<id>/patch`. | ||
| 459 | 459 | ||||
| 460 | - | **Proactive delegation.** With `/settings` → **proactive delegation** on (or `/orchestrator`), the interactive primary remains the owner and implementer of the task. Process start reveals neither the task nor which workers it needs, so it routes when the user states the request: the reply that starts the work names the parts it keeps on the critical path and the profile that owns each delegable part, before implementing or spawning anything. It delegates only concrete sidecars that can progress while the primary performs a preselected non-overlapping task; immediate blockers and tightly coupled work stay local. An active worker owns its scope until completion, so the primary does not repeat that investigation, review, testing, or implementation. If an explicit user request or workflow hands blocking work to a child, the primary yields for the host completion update instead. The canonical resident `subagent` tool remains available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll the status action or journal files solely to wait for completion. | 460 | + | **Proactive delegation.** With `/settings` → **proactive delegation** on (or `/orchestrator`), the interactive primary acts as an orchestrator and delegates by default. Implementation, debugging, testing, review, and broad research go to workers; answers, quick lookups, edits of a few lines, and integration stay local. For each new request, the reply that starts the work names each part, its owner, and the profile for each delegated part. The primary maps dependencies, runs independent parts in parallel, and for multi-part features gives each worker a sub-worktree based on a feature branch, gates each result with a review before merging, and removes merged worktrees and branches when done. Blocking work is spawned with `required: true` and the primary yields for the host completion update. An active worker owns its scope until completion, so the primary does not repeat that investigation, review, testing, or implementation. The canonical resident `subagent` tool remains available for user-requested delegation when the setting is off, subject to launch-time permissions. Do not poll the status action or journal files solely to wait for completion. |
| 461 | 461 | ||||
| 462 | ### Named subagent profiles | 462 | ### Named subagent profiles | ||
| 463 | 463 | ||||
| @@ -471,7 +471,7 @@ Opens a dialog with every persistent setting. `up`/`down` to navigate, `enter` o | |||||
| 471 | - **render images when supported** — draw screenshots / `read`-returned images inline using the terminal's image protocol, or fall back to a text placeholder. Auto-detected from `TERM_PROGRAM`; the toggle overrides the detection. The row is greyed out and forced off on terminals that don't speak any image protocol. | 471 | - **render images when supported** — draw screenshots / `read`-returned images inline using the terminal's image protocol, or fall back to a text placeholder. Auto-detected from `TERM_PROGRAM`; the toggle overrides the detection. The row is greyed out and forced off on terminals that don't speak any image protocol. | ||
| 472 | - **terminal alerts** — emit a terminal bell when the main session stops with work that may need attention, or when an extension raises a structured alert. Enabled by default; changes apply immediately and persist as `terminal_alerts_enabled`. Terminal emulators may render the bell audibly, visually, or not at all. | 472 | - **terminal alerts** — emit a terminal bell when the main session stops with work that may need attention, or when an extension raises a structured alert. Enabled by default; changes apply immediately and persist as `terminal_alerts_enabled`. Terminal emulators may render the bell audibly, visually, or not at all. | ||
| 473 | - **AI terminal titles** — after the first real prompt of a fresh interactive session, make one small hidden request to the active model and set the terminal title to `zut: <title>`. The title is limited to 40 Unicode characters, persisted with the session, restored on resume, and never added to the conversation. Enabled by default; disable it to avoid the extra model request. The toggle applies immediately, but title generation still waits for the first real prompt and never starts from startup context, resumed history, or slash commands. Persists as `terminal_title_enabled`. | 473 | - **AI terminal titles** — after the first real prompt of a fresh interactive session, make one small hidden request to the active model and set the terminal title to `zut: <title>`. The title is limited to 40 Unicode characters, persisted with the session, restored on resume, and never added to the conversation. Enabled by default; disable it to avoid the extra model request. The toggle applies immediately, but title generation still waits for the first real prompt and never starts from startup context, resumed history, or slash commands. Persists as `terminal_title_enabled`. | ||
| 474 | - | - **proactive delegation** — let the interactive primary delegate concrete, bounded sidecars while it keeps ownership of the critical path. Because the task and the workers it needs are unknown until the user states them, the primary routes at that point: the reply that starts the work names the parts it keeps on the critical path and the profile that owns each delegable part, and it states when nothing is worth delegating instead of forcing workers. Before spawning, it identifies useful local work and gives the child a non-overlapping question, responsibility, package, or file set. Immediate blockers and tightly coupled work stay local; after spawning, the worker owns its scope until completion and the primary continues only its preselected independent task. If a user request or active workflow explicitly delegates blocking work, the primary yields rather than reproducing it. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion and required-work state are host-driven through `[auto-subagents update]` and `[required-subagents update]` messages; required work stays asynchronous, persists its outcome, and prevents the terminal parent response until a successful completion. If launch-time restrictions prevent spawning, the interactive primary continues locally. Explicit headless `--orchestrate` remains a separate strict manager-only mode and reports unavailable delegation rather than implementing directly. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. | 474 | + | - **proactive delegation** — make the interactive primary an orchestrator that delegates substantial work by default and keeps small edits, lookups, and integration local. See **Proactive delegation** above. Off by default. When off, the permitted canonical subagent tools and profile manifest remain available for user-requested delegation or when an active skill workflow requires it. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion and required-work state are host-driven through `[auto-subagents update]` and `[required-subagents update]` messages; required work stays asynchronous, persists its outcome, and prevents the terminal parent response until a successful completion. If launch-time restrictions prevent spawning, the interactive primary continues locally. Explicit headless `--orchestrate` remains a separate strict manager-only mode and reports unavailable delegation rather than implementing directly. Do not poll or inspect dashboards, metadata, event logs, or files solely to wait. See `/subagents` and [docs/subagents.md](docs/subagents.md) for details. |
| 475 | - **fast mode** — request the provider's fast tier where supported. It currently uses OpenAI's Fast service tier for OpenAI, OpenAI Responses, and OpenAI Codex models. Off by default; toggle it with `/fast` or `/settings`; changes apply on the next model call and persist as `fast_mode`. When a model profile is active, the value is saved in that profile and restored when switching profiles. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account. | 475 | - **fast mode** — request the provider's fast tier where supported. It currently uses OpenAI's Fast service tier for OpenAI, OpenAI Responses, and OpenAI Codex models. Off by default; toggle it with `/fast` or `/settings`; changes apply on the next model call and persist as `fast_mode`. When a model profile is active, the value is saved in that profile and restored when switching profiles. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account. | ||
| 476 | - **lsp in main session** — enable the built-in `lsp` tool and code diagnostics for the main agent. Enabled by default; changes persist as `lsp_enabled`. | 476 | - **lsp in main session** — enable the built-in `lsp` tool and code diagnostics for the main agent. Enabled by default; changes persist as `lsp_enabled`. | ||
| 477 | - **lsp in sub-agents** — allow newly spawned background sub-agents to use the built-in `lsp` tool. Enabled by default; changes persist as `subagent_lsp_enabled` and apply when a child starts. | 477 | - **lsp in sub-agents** — allow newly spawned background sub-agents to use the built-in `lsp` tool. Enabled by default; changes persist as `subagent_lsp_enabled` and apply when a child starts. | ||
M docs/subagents.md +25 -17
| @@ -189,23 +189,31 @@ retries it automatically. | |||
| 189 | 189 | ||
| 190 | 190 | ## Delegation ownership | |
| 191 | 191 | ||
| 192 | - | Interactive proactive delegation keeps the primary agent on the critical path. | |
| 193 | - | Process start says nothing about the task, and the workers it needs only become | |
| 194 | - | knowable once the user states the request. Routing therefore happens then: the | |
| 195 | - | reply that starts the work names the parts the primary keeps on the critical | |
| 196 | - | path and the profile that owns each delegable part, before it implements or | |
| 197 | - | spawns anything. It states plainly when nothing is worth delegating rather than | |
| 198 | - | forcing a worker. The routing guidance is part of the prompt only when | |
| 199 | - | launch-time policy exposes the spawn action. | |
| 200 | - | Before spawning, it selects useful local work and delegates only a concrete, | |
| 201 | - | bounded sidecar with a non-overlapping question, responsibility, package, or | |
| 202 | - | file set. Immediate blockers and tightly coupled work stay local. While a child | |
| 203 | - | is active, it owns that scope; the primary continues only its preselected | |
| 204 | - | independent work instead of repeating the investigation, review, testing, or | |
| 205 | - | implementation. If an explicit user request or active workflow hands blocking | |
| 206 | - | work to a child, the primary yields for the completion update. Once a worktree | |
| 207 | - | child succeeds, the primary may apply and verify its captured patch without | |
| 208 | - | redoing the delegated task. | |
| 192 | + | Interactive proactive delegation makes the primary agent an orchestrator that | |
| 193 | + | delegates by default. Implementation, debugging, testing, review, and broad | |
| 194 | + | research go to workers; answers, quick lookups, edits of a few lines, and | |
| 195 | + | integration of worker results stay local. Blocking work is delegated too: the | |
| 196 | + | primary spawns it with `required: true` and yields for the completion update. | |
| 197 | + | ||
| 198 | + | Routing happens for each new request, not at process start: the reply that | |
| 199 | + | starts the work names each part, its owner, and the profile for each delegated | |
| 200 | + | part. The routing guidance is part of the prompt only when launch-time policy | |
| 201 | + | exposes the spawn action. | |
| 202 | + | ||
| 203 | + | Before spawning, the primary maps dependencies, runs independent parts in | |
| 204 | + | parallel, and gives every worker a self-contained task with a disjoint scope. | |
| 205 | + | For a multi-part feature it creates a feature worktree branch, then one | |
| 206 | + | sub-worktree per worker with `worktree` `create` and `base` set to the feature | |
| 207 | + | branch. It reviews each result, commits on the sub-branch, and merges it into | |
| 208 | + | the feature branch. It then removes merged sub-worktrees and their branches | |
| 209 | + | with `worktree` `cleanup`, `into` set to the feature branch and | |
| 210 | + | `delete_branch: true`, and checks with `list` that none are left behind. | |
| 211 | + | ||
| 212 | + | While a child is active, it owns that scope; the primary does not repeat its | |
| 213 | + | investigation, review, testing, or implementation. Once an | |
| 214 | + | `isolation: "worktree"` child succeeds, the primary may apply and verify its | |
| 215 | + | captured patch without redoing the task, then stop the idle child so its | |
| 216 | + | temporary worktree is removed. | |
| 209 | 217 | ||
| 210 | 218 | Explicit headless `--orchestrate` remains manager-only. Its primary divides the | |
| 211 | 219 | request into disjoint worker scopes, coordinates active children, and yields | |
| @@ -189,23 +189,31 @@ retries it automatically. | |||||
| 189 | 189 | ||||
| 190 | ## Delegation ownership | 190 | ## Delegation ownership | ||
| 191 | 191 | ||||
| 192 | - | Interactive proactive delegation keeps the primary agent on the critical path. | 192 | + | Interactive proactive delegation makes the primary agent an orchestrator that |
| 193 | - | Process start says nothing about the task, and the workers it needs only become | 193 | + | delegates by default. Implementation, debugging, testing, review, and broad |
| 194 | - | knowable once the user states the request. Routing therefore happens then: the | 194 | + | research go to workers; answers, quick lookups, edits of a few lines, and |
| 195 | - | reply that starts the work names the parts the primary keeps on the critical | 195 | + | integration of worker results stay local. Blocking work is delegated too: the |
| 196 | - | path and the profile that owns each delegable part, before it implements or | 196 | + | primary spawns it with `required: true` and yields for the completion update. |
| 197 | - | spawns anything. It states plainly when nothing is worth delegating rather than | 197 | + | |
| 198 | - | forcing a worker. The routing guidance is part of the prompt only when | 198 | + | Routing happens for each new request, not at process start: the reply that |
| 199 | - | launch-time policy exposes the spawn action. | 199 | + | starts the work names each part, its owner, and the profile for each delegated |
| 200 | - | Before spawning, it selects useful local work and delegates only a concrete, | 200 | + | part. The routing guidance is part of the prompt only when launch-time policy |
| 201 | - | bounded sidecar with a non-overlapping question, responsibility, package, or | 201 | + | exposes the spawn action. |
| 202 | - | file set. Immediate blockers and tightly coupled work stay local. While a child | 202 | + | |
| 203 | - | is active, it owns that scope; the primary continues only its preselected | 203 | + | Before spawning, the primary maps dependencies, runs independent parts in |
| 204 | - | independent work instead of repeating the investigation, review, testing, or | 204 | + | parallel, and gives every worker a self-contained task with a disjoint scope. |
| 205 | - | implementation. If an explicit user request or active workflow hands blocking | 205 | + | For a multi-part feature it creates a feature worktree branch, then one |
| 206 | - | work to a child, the primary yields for the completion update. Once a worktree | 206 | + | sub-worktree per worker with `worktree` `create` and `base` set to the feature |
| 207 | - | child succeeds, the primary may apply and verify its captured patch without | 207 | + | branch. It reviews each result, commits on the sub-branch, and merges it into |
| 208 | - | redoing the delegated task. | 208 | + | the feature branch. It then removes merged sub-worktrees and their branches |
| 209 | + | with `worktree` `cleanup`, `into` set to the feature branch and | |||
| 210 | + | `delete_branch: true`, and checks with `list` that none are left behind. | |||
| 211 | + | ||||
| 212 | + | While a child is active, it owns that scope; the primary does not repeat its | |||
| 213 | + | investigation, review, testing, or implementation. Once an | |||
| 214 | + | `isolation: "worktree"` child succeeds, the primary may apply and verify its | |||
| 215 | + | captured patch without redoing the task, then stop the idle child so its | |||
| 216 | + | temporary worktree is removed. | |||
| 209 | 217 | ||||
| 210 | Explicit headless `--orchestrate` remains manager-only. Its primary divides the | 218 | Explicit headless `--orchestrate` remains manager-only. Its primary divides the | ||
| 211 | request into disjoint worker scopes, coordinates active children, and yields | 219 | request into disjoint worker scopes, coordinates active children, and yields | ||
M packages/agent/modes/interactive_settings.go +1 -1
| @@ -284,7 +284,7 @@ func (i *Interactive) openSettingsDialog() { | |||
| 284 | 284 | { | |
| 285 | 285 | key: "auto_subagents_enabled", | |
| 286 | 286 | label: "proactive delegation", | |
| 287 | - | desc: "delegate independent sidecar work while keeping the critical path local", | |
| 287 | + | desc: "delegate substantial work to subagents; keep small edits local", | |
| 288 | 288 | value: autoSubagents, | |
| 289 | 289 | disabled: autoSubagentsDisabled, | |
| 290 | 290 | hint: autoSubagentsHint, | |
| @@ -284,7 +284,7 @@ func (i *Interactive) openSettingsDialog() { | |||||
| 284 | { | 284 | { | ||
| 285 | key: "auto_subagents_enabled", | 285 | key: "auto_subagents_enabled", | ||
| 286 | label: "proactive delegation", | 286 | label: "proactive delegation", | ||
| 287 | - | desc: "delegate independent sidecar work while keeping the critical path local", | 287 | + | desc: "delegate substantial work to subagents; keep small edits local", |
| 288 | value: autoSubagents, | 288 | value: autoSubagents, | ||
| 289 | disabled: autoSubagentsDisabled, | 289 | disabled: autoSubagentsDisabled, | ||
| 290 | hint: autoSubagentsHint, | 290 | hint: autoSubagentsHint, | ||
M packages/agent/settings_store.go +38 -25
| @@ -276,28 +276,41 @@ func AutoSubagentsEnabled() bool { | |||
| 276 | 276 | // ProactiveSubagentsRoutingAddendum is prepended to the interactive | |
| 277 | 277 | // collaboration contract only when launch-time policy exposes the spawn | |
| 278 | 278 | // action: naming a profile is meaningless when the primary cannot dispatch. | |
| 279 | - | const ProactiveSubagentsRoutingAddendum = `Route before you work: | |
| 280 | - | - Process start tells you nothing about the task or the workers it needs; routing happens when the user states the request you are about to work on. | |
| 281 | - | - Name the parts you keep on the critical path and the [subagents_list] profile that owns each delegable part, before you implement or spawn. | |
| 282 | - | - State that routing once, in the reply that starts the work, and let the tool calls that follow speak for themselves instead of narrating them. | |
| 283 | - | - Say plainly when nothing is worth delegating instead of inventing sidecars, and spawn a clearly described general worker when no profile matches a scope.` | |
| 284 | - | ||
| 285 | - | // ProactiveSubagentsSystemAddendum keeps the interactive primary agent on the | |
| 286 | - | // critical path and reserves delegation for genuinely parallel sidecar work. | |
| 287 | - | const ProactiveSubagentsSystemAddendum = `Proactive subagent delegation is enabled. You remain the primary owner and implementer of the user's task. | |
| 288 | - | ||
| 289 | - | Before delegating: | |
| 290 | - | - Form a short high-level plan and identify the immediate next task you will perform locally. | |
| 291 | - | - Delegate only a concrete, bounded sidecar that can progress independently while you perform useful local work. | |
| 292 | - | - Keep urgent, tightly coupled, or immediate blocking work local. If your next action depends on a result, do that work yourself instead of spawning and waiting for it. | |
| 293 | - | - Divide ownership by distinct question, responsibility, package, or disjoint file set. Give every worker a self-contained task. | |
| 294 | - | - If you cannot name useful non-overlapping local work, do not delegate. | |
| 295 | - | ||
| 296 | - | After delegating: | |
| 297 | - | - The worker owns its delegated scope until it completes. Continue only with the non-overlapping local task selected before delegation. | |
| 298 | - | - Do not search, read, test, review, edit, or otherwise reproduce the worker's task. You may dispatch additional workers only for genuinely distinct scopes. | |
| 299 | - | - If the user or an active workflow explicitly requires a worker to own blocking work, delegate it with required:true and end or yield your turn instead of duplicating it. | |
| 300 | - | - Integrate and, when appropriate, verify completed worker results before answering. You may apply a completed worktree patch without redoing the delegated task.` | |
| 279 | + | const ProactiveSubagentsRoutingAddendum = `Route every new task before you work: | |
| 280 | + | - Routing happens when the user states a request, not at process start. Re-route each new request, even late in a long session. | |
| 281 | + | - In the reply that starts the work, name each part, who owns it, and the [subagents_list] profile for each delegated part. Then spawn; do not narrate the tool calls that follow. | |
| 282 | + | - Spawn a clearly described general worker when no profile matches a scope. | |
| 283 | + | - Keep a task fully local only when it is small: an answer, a quick lookup, or an edit of a few lines. Say so in one line instead of forcing a worker.` | |
| 284 | + | ||
| 285 | + | // ProactiveSubagentsSystemAddendum makes the interactive primary agent an | |
| 286 | + | // orchestrator by default: substantial work goes to workers, while small | |
| 287 | + | // edits, exploration, and integration stay local. | |
| 288 | + | const ProactiveSubagentsSystemAddendum = `Proactive subagent delegation is enabled. You are the orchestrator of the user's task: delegate by default and keep work local by exception. | |
| 289 | + | ||
| 290 | + | Delegate: | |
| 291 | + | - Implementation, debugging, test writing and running, and code review that spans more than a few lines or more than one file. | |
| 292 | + | - Research that needs many reads or searches across packages or repositories. | |
| 293 | + | - Blocking work too. If your next step depends on a worker's result, spawn it with required:true and end or yield your turn; waiting for a worker is expected, not a reason to work locally. | |
| 294 | + | ||
| 295 | + | Keep local: | |
| 296 | + | - Answers, quick lookups, and the short exploration needed to write precise worker tasks. | |
| 297 | + | - Edits of a few lines in one file, and integrating, applying, or verifying worker results. | |
| 298 | + | ||
| 299 | + | Plan parallelism before spawning: | |
| 300 | + | - Map dependencies first: which parts are independent, which must run in order, and which files each part touches. Run independent parts in parallel and order dependent parts. | |
| 301 | + | - Split work by distinct question, responsibility, package, or disjoint file set, and give every worker a self-contained task with acceptance checks. | |
| 302 | + | - One worker editing code: shared workspace is fine. Several workers editing code at once: give each its own tree. | |
| 303 | + | - For a multi-part feature, create a feature worktree branch, then one sub-worktree per worker with the worktree tool's create action and base set to the feature branch, and tell each worker its exact path. Review each worker's result as a gate, commit on its branch, and merge it into the feature branch. | |
| 304 | + | - Use isolation:"worktree" for a throwaway parallel attempt whose patch you apply yourself. | |
| 305 | + | ||
| 306 | + | Clean up as soon as a worker's result is integrated: | |
| 307 | + | - Remove merged sub-worktrees and their branches with the worktree tool's cleanup action, setting into to the feature branch and delete_branch to true. | |
| 308 | + | - Stop idle isolation:"worktree" workers once their patch is applied so their temporary worktree is removed. | |
| 309 | + | - Before your final answer, check with the worktree tool's list action that no worktree you created is left behind unless the user should keep it. | |
| 310 | + | ||
| 311 | + | When you delegate: | |
| 312 | + | - A worker owns its scope until it completes. Do not search, read, test, review, edit, or otherwise reproduce it; only coordinate, dispatch disjoint work, or yield. | |
| 313 | + | - Integrate and verify completed results before answering. You may apply a completed worktree patch without redoing the delegated task.` | |
| 301 | 314 | ||
| 302 | 315 | // StrictOrchestratorSystemAddendum is used only by explicit headless | |
| 303 | 316 | // orchestration. The parent coordinates workers and never becomes an | |
| @@ -312,11 +325,11 @@ const StrictOrchestratorSystemAddendum = `Strict subagent orchestration is enabl | |||
| 312 | 325 | ||
| 313 | 326 | const subagentLifecycleAddendum = `Workers start without this conversation's context. Shared-worktree workers edit the same working directory, so coordinate dependent work and avoid conflicting edits. Use isolation:"worktree" for parallel coding when workers need separate trees; its changes are returned as a patch and never applied automatically. Do not invent feature scope beyond the user's request. Child workers cannot recursively spawn more sub-agents in v1. | |
| 314 | 327 | ||
| 315 | - | Use required:true whenever your answer or a declared workflow depends on that worker, especially for required validation or finalization. Required workers remain asynchronous unless you explicitly set the wait field on a spawn or resume action: without it, manager calls return immediately, the parent stays free to coordinate or perform policy-permitted non-overlapping work, and the host delivers terminal outcomes through completion updates. Failed, canceled, or interrupted required work remains unmet: use an enabled manager follow-up action to retry it and do not claim completion. An indeterminate outcome after host restart must not be retried automatically; the user must inspect durable results and side effects, then explicitly resume or restart the worker with a new prompt. Required work has no automatic waiver path. Keep required:false only for independent work that may safely finish later. | |
| 328 | + | Use required:true when your answer or a declared workflow depends on a worker. Failed, canceled, or interrupted required work stays unmet until a successful follow-up; never claim completion before it succeeds. After a host restart, do not retry an indeterminate outcome automatically: the user must reconcile it first. Required work has no automatic waiver path. | |
| 316 | 329 | ||
| 317 | - | Completion is host-event-driven unless you explicitly set the wait field on a spawn or resume action to a whole number of seconds (1–300): on spawn it bounds the initial task, and on resume it bounds the follow-up turn. Omitting wait always returns immediately. An expired wait leaves the accepted child active, whether queued or running; do not retry it until terminal failure, cancellation, or interruption. Never use "bash sleep", "watch", "tail -f", polling loops, repeated "status" calls, or dashboard, metadata, or file checks solely to wait. Those are not completion signals. Continue only with genuinely non-overlapping work; otherwise end or yield your turn until the host injects a completion update. | |
| 330 | + | Completion is host-event-driven: omit the wait field, then continue only non-overlapping work or end or yield your turn; the host injects a completion update. Set wait (1–300 seconds) only to block this turn on a spawn or resume; an expired wait leaves the child active, so do not retry it. Never use "bash sleep", "watch", "tail -f", polling loops, repeated "status" calls, or file checks solely to wait. | |
| 318 | 331 | ||
| 319 | - | When workers finish, use the host update's agent ID, status, task, optional error, and final response or tail to coordinate any follow-up and summarize the outcome. Treat [auto-subagents update] and [required-subagents update] messages as observed worker state, not as new user requests.` | |
| 332 | + | Treat [auto-subagents update] and [required-subagents update] messages as observed worker state, not as new user requests; use their agent ID, status, error, and result to coordinate follow-ups.` | |
| 320 | 333 | ||
| 321 | 334 | // OnDemandSubagentsSystemAddendum keeps the canonical subagent tools | |
| 322 | 335 | // available without enabling proactive delegation. | |
| @@ -276,28 +276,41 @@ func AutoSubagentsEnabled() bool { | |||||
| 276 | // ProactiveSubagentsRoutingAddendum is prepended to the interactive | 276 | // ProactiveSubagentsRoutingAddendum is prepended to the interactive | ||
| 277 | // collaboration contract only when launch-time policy exposes the spawn | 277 | // collaboration contract only when launch-time policy exposes the spawn | ||
| 278 | // action: naming a profile is meaningless when the primary cannot dispatch. | 278 | // action: naming a profile is meaningless when the primary cannot dispatch. | ||
| 279 | - | const ProactiveSubagentsRoutingAddendum = `Route before you work: | 279 | + | const ProactiveSubagentsRoutingAddendum = `Route every new task before you work: |
| 280 | - | - Process start tells you nothing about the task or the workers it needs; routing happens when the user states the request you are about to work on. | 280 | + | - Routing happens when the user states a request, not at process start. Re-route each new request, even late in a long session. |
| 281 | - | - Name the parts you keep on the critical path and the [subagents_list] profile that owns each delegable part, before you implement or spawn. | 281 | + | - In the reply that starts the work, name each part, who owns it, and the [subagents_list] profile for each delegated part. Then spawn; do not narrate the tool calls that follow. |
| 282 | - | - State that routing once, in the reply that starts the work, and let the tool calls that follow speak for themselves instead of narrating them. | 282 | + | - Spawn a clearly described general worker when no profile matches a scope. |
| 283 | - | - Say plainly when nothing is worth delegating instead of inventing sidecars, and spawn a clearly described general worker when no profile matches a scope.` | 283 | + | - Keep a task fully local only when it is small: an answer, a quick lookup, or an edit of a few lines. Say so in one line instead of forcing a worker.` |
| 284 | - | 284 | + | ||
| 285 | - | // ProactiveSubagentsSystemAddendum keeps the interactive primary agent on the | 285 | + | // ProactiveSubagentsSystemAddendum makes the interactive primary agent an |
| 286 | - | // critical path and reserves delegation for genuinely parallel sidecar work. | 286 | + | // orchestrator by default: substantial work goes to workers, while small |
| 287 | - | const ProactiveSubagentsSystemAddendum = `Proactive subagent delegation is enabled. You remain the primary owner and implementer of the user's task. | 287 | + | // edits, exploration, and integration stay local. |
| 288 | - | 288 | + | const ProactiveSubagentsSystemAddendum = `Proactive subagent delegation is enabled. You are the orchestrator of the user's task: delegate by default and keep work local by exception. | |
| 289 | - | Before delegating: | 289 | + | |
| 290 | - | - Form a short high-level plan and identify the immediate next task you will perform locally. | 290 | + | Delegate: |
| 291 | - | - Delegate only a concrete, bounded sidecar that can progress independently while you perform useful local work. | 291 | + | - Implementation, debugging, test writing and running, and code review that spans more than a few lines or more than one file. |
| 292 | - | - Keep urgent, tightly coupled, or immediate blocking work local. If your next action depends on a result, do that work yourself instead of spawning and waiting for it. | 292 | + | - Research that needs many reads or searches across packages or repositories. |
| 293 | - | - Divide ownership by distinct question, responsibility, package, or disjoint file set. Give every worker a self-contained task. | 293 | + | - Blocking work too. If your next step depends on a worker's result, spawn it with required:true and end or yield your turn; waiting for a worker is expected, not a reason to work locally. |
| 294 | - | - If you cannot name useful non-overlapping local work, do not delegate. | 294 | + | |
| 295 | - | 295 | + | Keep local: | |
| 296 | - | After delegating: | 296 | + | - Answers, quick lookups, and the short exploration needed to write precise worker tasks. |
| 297 | - | - The worker owns its delegated scope until it completes. Continue only with the non-overlapping local task selected before delegation. | 297 | + | - Edits of a few lines in one file, and integrating, applying, or verifying worker results. |
| 298 | - | - Do not search, read, test, review, edit, or otherwise reproduce the worker's task. You may dispatch additional workers only for genuinely distinct scopes. | 298 | + | |
| 299 | - | - If the user or an active workflow explicitly requires a worker to own blocking work, delegate it with required:true and end or yield your turn instead of duplicating it. | 299 | + | Plan parallelism before spawning: |
| 300 | - | - Integrate and, when appropriate, verify completed worker results before answering. You may apply a completed worktree patch without redoing the delegated task.` | 300 | + | - Map dependencies first: which parts are independent, which must run in order, and which files each part touches. Run independent parts in parallel and order dependent parts. |
| 301 | + | - Split work by distinct question, responsibility, package, or disjoint file set, and give every worker a self-contained task with acceptance checks. | |||
| 302 | + | - One worker editing code: shared workspace is fine. Several workers editing code at once: give each its own tree. | |||
| 303 | + | - For a multi-part feature, create a feature worktree branch, then one sub-worktree per worker with the worktree tool's create action and base set to the feature branch, and tell each worker its exact path. Review each worker's result as a gate, commit on its branch, and merge it into the feature branch. | |||
| 304 | + | - Use isolation:"worktree" for a throwaway parallel attempt whose patch you apply yourself. | |||
| 305 | + | ||||
| 306 | + | Clean up as soon as a worker's result is integrated: | |||
| 307 | + | - Remove merged sub-worktrees and their branches with the worktree tool's cleanup action, setting into to the feature branch and delete_branch to true. | |||
| 308 | + | - Stop idle isolation:"worktree" workers once their patch is applied so their temporary worktree is removed. | |||
| 309 | + | - Before your final answer, check with the worktree tool's list action that no worktree you created is left behind unless the user should keep it. | |||
| 310 | + | ||||
| 311 | + | When you delegate: | |||
| 312 | + | - A worker owns its scope until it completes. Do not search, read, test, review, edit, or otherwise reproduce it; only coordinate, dispatch disjoint work, or yield. | |||
| 313 | + | - Integrate and verify completed results before answering. You may apply a completed worktree patch without redoing the delegated task.` | |||
| 301 | 314 | ||||
| 302 | // StrictOrchestratorSystemAddendum is used only by explicit headless | 315 | // StrictOrchestratorSystemAddendum is used only by explicit headless | ||
| 303 | // orchestration. The parent coordinates workers and never becomes an | 316 | // orchestration. The parent coordinates workers and never becomes an | ||
| @@ -312,11 +325,11 @@ const StrictOrchestratorSystemAddendum = `Strict subagent orchestration is enabl | |||||
| 312 | 325 | ||||
| 313 | const subagentLifecycleAddendum = `Workers start without this conversation's context. Shared-worktree workers edit the same working directory, so coordinate dependent work and avoid conflicting edits. Use isolation:"worktree" for parallel coding when workers need separate trees; its changes are returned as a patch and never applied automatically. Do not invent feature scope beyond the user's request. Child workers cannot recursively spawn more sub-agents in v1. | 326 | const subagentLifecycleAddendum = `Workers start without this conversation's context. Shared-worktree workers edit the same working directory, so coordinate dependent work and avoid conflicting edits. Use isolation:"worktree" for parallel coding when workers need separate trees; its changes are returned as a patch and never applied automatically. Do not invent feature scope beyond the user's request. Child workers cannot recursively spawn more sub-agents in v1. | ||
| 314 | 327 | ||||
| 315 | - | Use required:true whenever your answer or a declared workflow depends on that worker, especially for required validation or finalization. Required workers remain asynchronous unless you explicitly set the wait field on a spawn or resume action: without it, manager calls return immediately, the parent stays free to coordinate or perform policy-permitted non-overlapping work, and the host delivers terminal outcomes through completion updates. Failed, canceled, or interrupted required work remains unmet: use an enabled manager follow-up action to retry it and do not claim completion. An indeterminate outcome after host restart must not be retried automatically; the user must inspect durable results and side effects, then explicitly resume or restart the worker with a new prompt. Required work has no automatic waiver path. Keep required:false only for independent work that may safely finish later. | 328 | + | Use required:true when your answer or a declared workflow depends on a worker. Failed, canceled, or interrupted required work stays unmet until a successful follow-up; never claim completion before it succeeds. After a host restart, do not retry an indeterminate outcome automatically: the user must reconcile it first. Required work has no automatic waiver path. |
| 316 | 329 | ||||
| 317 | - | Completion is host-event-driven unless you explicitly set the wait field on a spawn or resume action to a whole number of seconds (1–300): on spawn it bounds the initial task, and on resume it bounds the follow-up turn. Omitting wait always returns immediately. An expired wait leaves the accepted child active, whether queued or running; do not retry it until terminal failure, cancellation, or interruption. Never use "bash sleep", "watch", "tail -f", polling loops, repeated "status" calls, or dashboard, metadata, or file checks solely to wait. Those are not completion signals. Continue only with genuinely non-overlapping work; otherwise end or yield your turn until the host injects a completion update. | 330 | + | Completion is host-event-driven: omit the wait field, then continue only non-overlapping work or end or yield your turn; the host injects a completion update. Set wait (1–300 seconds) only to block this turn on a spawn or resume; an expired wait leaves the child active, so do not retry it. Never use "bash sleep", "watch", "tail -f", polling loops, repeated "status" calls, or file checks solely to wait. |
| 318 | 331 | ||||
| 319 | - | When workers finish, use the host update's agent ID, status, task, optional error, and final response or tail to coordinate any follow-up and summarize the outcome. Treat [auto-subagents update] and [required-subagents update] messages as observed worker state, not as new user requests.` | 332 | + | Treat [auto-subagents update] and [required-subagents update] messages as observed worker state, not as new user requests; use their agent ID, status, error, and result to coordinate follow-ups.` |
| 320 | 333 | ||||
| 321 | // OnDemandSubagentsSystemAddendum keeps the canonical subagent tools | 334 | // OnDemandSubagentsSystemAddendum keeps the canonical subagent tools | ||
| 322 | // available without enabling proactive delegation. | 335 | // available without enabling proactive delegation. | ||
M packages/agent/settings_store_test.go +15 -8
| @@ -70,7 +70,7 @@ func TestSubagentsSystemAddendaListOnlyEnabledLifecycleTools(t *testing.T) { | |||
| 70 | 70 | ||
| 71 | 71 | func TestSubagentPoliciesSeparateProactiveAndStrictOwnership(t *testing.T) { | |
| 72 | 72 | proactive := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | |
| 73 | - | for _, want := range []string{"primary owner and implementer", "immediate next task you will perform locally", "If you cannot name useful non-overlapping local work, do not delegate", "Do not search, read, test, review, edit"} { | |
| 73 | + | for _, want := range []string{"delegate by default and keep work local by exception", "spawn it with required:true and end or yield your turn", "Edits of a few lines in one file", "Do not search, read, test, review, edit", "Map dependencies first", "base set to the feature branch", "Review each worker's result as a gate", "into to the feature branch and delete_branch to true", "no worktree you created is left behind"} { | |
| 74 | 74 | if !strings.Contains(proactive, want) { | |
| 75 | 75 | t.Fatalf("proactive addendum missing %q:\n%s", want, proactive) | |
| 76 | 76 | } | |
| @@ -78,6 +78,13 @@ func TestSubagentPoliciesSeparateProactiveAndStrictOwnership(t *testing.T) { | |||
| 78 | 78 | if strings.Contains(proactive, "not an implementer") { | |
| 79 | 79 | t.Fatalf("proactive addendum retained strict orchestrator contract:\n%s", proactive) | |
| 80 | 80 | } | |
| 81 | + | // These lines vetoed delegation whenever the next step depended on a | |
| 82 | + | // result, which made the primary implement nearly every task itself. | |
| 83 | + | for _, unwanted := range []string{"primary owner and implementer", "do that work yourself instead of spawning", "do not delegate"} { | |
| 84 | + | if strings.Contains(proactive, unwanted) { | |
| 85 | + | t.Fatalf("proactive addendum kept delegation veto %q:\n%s", unwanted, proactive) | |
| 86 | + | } | |
| 87 | + | } | |
| 81 | 88 | ||
| 82 | 89 | strict := StrictOrchestratorSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | |
| 83 | 90 | for _, want := range []string{"not an implementer", "non-overlapping worker scopes", "Once a worker is active", "Only coordinate workers"} { | |
| @@ -90,11 +97,11 @@ func TestSubagentPoliciesSeparateProactiveAndStrictOwnership(t *testing.T) { | |||
| 90 | 97 | func TestProactiveAddendumRoutesBeforeWorkOnlyWhenSpawningIsAvailable(t *testing.T) { | |
| 91 | 98 | proactive := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | |
| 92 | 99 | for _, want := range []string{ | |
| 93 | - | "Route before you work:", | |
| 94 | - | "routing happens when the user states the request you are about to work on", | |
| 95 | - | "the [subagents_list] profile that owns each delegable part", | |
| 96 | - | "let the tool calls that follow speak for themselves", | |
| 97 | - | "Say plainly when nothing is worth delegating", | |
| 100 | + | "Route every new task before you work:", | |
| 101 | + | "Re-route each new request, even late in a long session", | |
| 102 | + | "the [subagents_list] profile for each delegated part", | |
| 103 | + | "do not narrate the tool calls that follow", | |
| 104 | + | "Keep a task fully local only when it is small", | |
| 98 | 105 | } { | |
| 99 | 106 | if !strings.Contains(proactive, want) { | |
| 100 | 107 | t.Fatalf("proactive addendum missing %q:\n%s", want, proactive) | |
| @@ -115,7 +122,7 @@ func TestProactiveAddendumRoutesBeforeWorkOnlyWhenSpawningIsAvailable(t *testing | |||
| 115 | 122 | } { | |
| 116 | 123 | t.Run(tc.name, func(t *testing.T) { | |
| 117 | 124 | got := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: false, Stop: tc.stop, Resume: tc.resume}) | |
| 118 | - | for _, unwanted := range []string{"Route before you work:", "[subagents_list]", "spawn a clearly described general worker"} { | |
| 125 | + | for _, unwanted := range []string{"Route every new task before you work:", "[subagents_list]", "Spawn a clearly described general worker"} { | |
| 119 | 126 | if strings.Contains(got, unwanted) { | |
| 120 | 127 | t.Fatalf("spawn-withheld addendum kept %q:\n%s", unwanted, got) | |
| 121 | 128 | } | |
| @@ -138,7 +145,7 @@ func TestProactiveAddendumRoutesBeforeWorkOnlyWhenSpawningIsAvailable(t *testing | |||
| 138 | 145 | // Routing is the interactive collaboration step; the headless strict | |
| 139 | 146 | // contract divides scopes itself and must not inherit it. | |
| 140 | 147 | strict := StrictOrchestratorSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | |
| 141 | - | if strings.Contains(strict, "Route before you work:") || strings.Contains(strict, "[subagents_list]") { | |
| 148 | + | if strings.Contains(strict, "Route every new task before you work:") || strings.Contains(strict, "[subagents_list]") { | |
| 142 | 149 | t.Fatalf("strict orchestrator inherited interactive routing guidance:\n%s", strict) | |
| 143 | 150 | } | |
| 144 | 151 | } | |
| @@ -70,7 +70,7 @@ func TestSubagentsSystemAddendaListOnlyEnabledLifecycleTools(t *testing.T) { | |||||
| 70 | 70 | ||||
| 71 | func TestSubagentPoliciesSeparateProactiveAndStrictOwnership(t *testing.T) { | 71 | func TestSubagentPoliciesSeparateProactiveAndStrictOwnership(t *testing.T) { | ||
| 72 | proactive := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | 72 | proactive := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | ||
| 73 | - | for _, want := range []string{"primary owner and implementer", "immediate next task you will perform locally", "If you cannot name useful non-overlapping local work, do not delegate", "Do not search, read, test, review, edit"} { | 73 | + | for _, want := range []string{"delegate by default and keep work local by exception", "spawn it with required:true and end or yield your turn", "Edits of a few lines in one file", "Do not search, read, test, review, edit", "Map dependencies first", "base set to the feature branch", "Review each worker's result as a gate", "into to the feature branch and delete_branch to true", "no worktree you created is left behind"} { |
| 74 | if !strings.Contains(proactive, want) { | 74 | if !strings.Contains(proactive, want) { | ||
| 75 | t.Fatalf("proactive addendum missing %q:\n%s", want, proactive) | 75 | t.Fatalf("proactive addendum missing %q:\n%s", want, proactive) | ||
| 76 | } | 76 | } | ||
| @@ -78,6 +78,13 @@ func TestSubagentPoliciesSeparateProactiveAndStrictOwnership(t *testing.T) { | |||||
| 78 | if strings.Contains(proactive, "not an implementer") { | 78 | if strings.Contains(proactive, "not an implementer") { | ||
| 79 | t.Fatalf("proactive addendum retained strict orchestrator contract:\n%s", proactive) | 79 | t.Fatalf("proactive addendum retained strict orchestrator contract:\n%s", proactive) | ||
| 80 | } | 80 | } | ||
| 81 | + | // These lines vetoed delegation whenever the next step depended on a | |||
| 82 | + | // result, which made the primary implement nearly every task itself. | |||
| 83 | + | for _, unwanted := range []string{"primary owner and implementer", "do that work yourself instead of spawning", "do not delegate"} { | |||
| 84 | + | if strings.Contains(proactive, unwanted) { | |||
| 85 | + | t.Fatalf("proactive addendum kept delegation veto %q:\n%s", unwanted, proactive) | |||
| 86 | + | } | |||
| 87 | + | } | |||
| 81 | 88 | ||||
| 82 | strict := StrictOrchestratorSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | 89 | strict := StrictOrchestratorSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | ||
| 83 | for _, want := range []string{"not an implementer", "non-overlapping worker scopes", "Once a worker is active", "Only coordinate workers"} { | 90 | for _, want := range []string{"not an implementer", "non-overlapping worker scopes", "Once a worker is active", "Only coordinate workers"} { | ||
| @@ -90,11 +97,11 @@ func TestSubagentPoliciesSeparateProactiveAndStrictOwnership(t *testing.T) { | |||||
| 90 | func TestProactiveAddendumRoutesBeforeWorkOnlyWhenSpawningIsAvailable(t *testing.T) { | 97 | func TestProactiveAddendumRoutesBeforeWorkOnlyWhenSpawningIsAvailable(t *testing.T) { | ||
| 91 | proactive := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | 98 | proactive := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | ||
| 92 | for _, want := range []string{ | 99 | for _, want := range []string{ | ||
| 93 | - | "Route before you work:", | 100 | + | "Route every new task before you work:", |
| 94 | - | "routing happens when the user states the request you are about to work on", | 101 | + | "Re-route each new request, even late in a long session", |
| 95 | - | "the [subagents_list] profile that owns each delegable part", | 102 | + | "the [subagents_list] profile for each delegated part", |
| 96 | - | "let the tool calls that follow speak for themselves", | 103 | + | "do not narrate the tool calls that follow", |
| 97 | - | "Say plainly when nothing is worth delegating", | 104 | + | "Keep a task fully local only when it is small", |
| 98 | } { | 105 | } { | ||
| 99 | if !strings.Contains(proactive, want) { | 106 | if !strings.Contains(proactive, want) { | ||
| 100 | t.Fatalf("proactive addendum missing %q:\n%s", want, proactive) | 107 | t.Fatalf("proactive addendum missing %q:\n%s", want, proactive) | ||
| @@ -115,7 +122,7 @@ func TestProactiveAddendumRoutesBeforeWorkOnlyWhenSpawningIsAvailable(t *testing | |||||
| 115 | } { | 122 | } { | ||
| 116 | t.Run(tc.name, func(t *testing.T) { | 123 | t.Run(tc.name, func(t *testing.T) { | ||
| 117 | got := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: false, Stop: tc.stop, Resume: tc.resume}) | 124 | got := ProactiveSubagentsSystemAddendumFor(SubagentActions{Spawn: false, Stop: tc.stop, Resume: tc.resume}) | ||
| 118 | - | for _, unwanted := range []string{"Route before you work:", "[subagents_list]", "spawn a clearly described general worker"} { | 125 | + | for _, unwanted := range []string{"Route every new task before you work:", "[subagents_list]", "Spawn a clearly described general worker"} { |
| 119 | if strings.Contains(got, unwanted) { | 126 | if strings.Contains(got, unwanted) { | ||
| 120 | t.Fatalf("spawn-withheld addendum kept %q:\n%s", unwanted, got) | 127 | t.Fatalf("spawn-withheld addendum kept %q:\n%s", unwanted, got) | ||
| 121 | } | 128 | } | ||
| @@ -138,7 +145,7 @@ func TestProactiveAddendumRoutesBeforeWorkOnlyWhenSpawningIsAvailable(t *testing | |||||
| 138 | // Routing is the interactive collaboration step; the headless strict | 145 | // Routing is the interactive collaboration step; the headless strict | ||
| 139 | // contract divides scopes itself and must not inherit it. | 146 | // contract divides scopes itself and must not inherit it. | ||
| 140 | strict := StrictOrchestratorSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | 147 | strict := StrictOrchestratorSystemAddendumFor(SubagentActions{Spawn: true, Stop: false, Resume: false}) | ||
| 141 | - | if strings.Contains(strict, "Route before you work:") || strings.Contains(strict, "[subagents_list]") { | 148 | + | if strings.Contains(strict, "Route every new task before you work:") || strings.Contains(strict, "[subagents_list]") { |
| 142 | t.Fatalf("strict orchestrator inherited interactive routing guidance:\n%s", strict) | 149 | t.Fatalf("strict orchestrator inherited interactive routing guidance:\n%s", strict) | ||
| 143 | } | 150 | } | ||
| 144 | } | 151 | } | ||
M packages/agent/tools/resident_tools_test.go +1 -1
| @@ -108,7 +108,7 @@ func TestResidentToolsUseManagerOnly(t *testing.T) { | |||
| 108 | 108 | ||
| 109 | 109 | func TestSubagentSpawnGuidanceRequiresIndependentOwnership(t *testing.T) { | |
| 110 | 110 | facade := &SubagentTool{} | |
| 111 | - | for _, want := range []string{"independent sidecar", "keep immediate blockers local", "never duplicate it in the parent", "end or yield the parent turn"} { | |
| 111 | + | for _, want := range []string{"self-contained task", "never duplicate it in the parent", "end or yield the parent turn"} { | |
| 112 | 112 | if got := facade.Description(); !strings.Contains(got, want) { | |
| 113 | 113 | t.Fatalf("description missing %q: %s", want, got) | |
| 114 | 114 | } | |
| @@ -108,7 +108,7 @@ func TestResidentToolsUseManagerOnly(t *testing.T) { | |||||
| 108 | 108 | ||||
| 109 | func TestSubagentSpawnGuidanceRequiresIndependentOwnership(t *testing.T) { | 109 | func TestSubagentSpawnGuidanceRequiresIndependentOwnership(t *testing.T) { | ||
| 110 | facade := &SubagentTool{} | 110 | facade := &SubagentTool{} | ||
| 111 | - | for _, want := range []string{"independent sidecar", "keep immediate blockers local", "never duplicate it in the parent", "end or yield the parent turn"} { | 111 | + | for _, want := range []string{"self-contained task", "never duplicate it in the parent", "end or yield the parent turn"} { |
| 112 | if got := facade.Description(); !strings.Contains(got, want) { | 112 | if got := facade.Description(); !strings.Contains(got, want) { | ||
| 113 | t.Fatalf("description missing %q: %s", want, got) | 113 | t.Fatalf("description missing %q: %s", want, got) | ||
| 114 | } | 114 | } | ||
M packages/agent/tools/subagent.go +1 -1
| @@ -26,7 +26,7 @@ type SubagentTool struct { | |||
| 26 | 26 | // subagentSpawnGuidance is the operational contract for delegation. It is the | |
| 27 | 27 | // facade description tail and the internal spawn tool description, so the text | |
| 28 | 28 | // cannot drift between them. | |
| 29 | - | const subagentSpawnGuidance = "Delegate a concrete, bounded scope to a resident sub-agent. For proactive delegation, use an independent sidecar only when the parent has useful non-overlapping work; keep immediate blockers local. A worker owns its scope until completion, so never duplicate it in the parent. If delegation owns the blocking task, end or yield the parent turn. Omit wait to return immediately and receive completion through [auto-subagents update]; set wait to an explicit 1–300 second value only when this turn should wait for the initial task. Set required=true when the outcome is mandatory before the parent's terminal response; failures remain recoverable through the resume action. Do not use resume solely to wait for an existing task or request its result again; yield for the automatic completion update instead. Resume requires a real new instruction; queue schedules a separate turn and another completion. Never use bash sleep, watch, tail -f, polling loops, repeated status calls, dashboard, metadata, or file checks solely to wait." | |
| 29 | + | const subagentSpawnGuidance = "Delegate a concrete, bounded scope to a resident sub-agent with a self-contained task. A worker owns its scope until completion, so never duplicate it in the parent. If delegation owns the blocking task, end or yield the parent turn. Omit wait to return immediately and receive completion through [auto-subagents update]; set wait to an explicit 1–300 second value only when this turn should wait for the initial task. Set required=true when the outcome is mandatory before the parent's terminal response; failures remain recoverable through the resume action. Do not use resume solely to wait for an existing task or request its result again; yield for the automatic completion update instead. Resume requires a real new instruction; queue schedules a separate turn and another completion. Never use bash sleep, watch, tail -f, polling loops, repeated status calls, dashboard, metadata, or file checks solely to wait." | |
| 30 | 30 | ||
| 31 | 31 | // subagentSchema merges the action schemas into the flat, model-facing schema | |
| 32 | 32 | // the project keeps for provider compatibility. Every property is annotated | |
| @@ -26,7 +26,7 @@ type SubagentTool struct { | |||||
| 26 | // subagentSpawnGuidance is the operational contract for delegation. It is the | 26 | // subagentSpawnGuidance is the operational contract for delegation. It is the | ||
| 27 | // facade description tail and the internal spawn tool description, so the text | 27 | // facade description tail and the internal spawn tool description, so the text | ||
| 28 | // cannot drift between them. | 28 | // cannot drift between them. | ||
| 29 | - | const subagentSpawnGuidance = "Delegate a concrete, bounded scope to a resident sub-agent. For proactive delegation, use an independent sidecar only when the parent has useful non-overlapping work; keep immediate blockers local. A worker owns its scope until completion, so never duplicate it in the parent. If delegation owns the blocking task, end or yield the parent turn. Omit wait to return immediately and receive completion through [auto-subagents update]; set wait to an explicit 1–300 second value only when this turn should wait for the initial task. Set required=true when the outcome is mandatory before the parent's terminal response; failures remain recoverable through the resume action. Do not use resume solely to wait for an existing task or request its result again; yield for the automatic completion update instead. Resume requires a real new instruction; queue schedules a separate turn and another completion. Never use bash sleep, watch, tail -f, polling loops, repeated status calls, dashboard, metadata, or file checks solely to wait." | 29 | + | const subagentSpawnGuidance = "Delegate a concrete, bounded scope to a resident sub-agent with a self-contained task. A worker owns its scope until completion, so never duplicate it in the parent. If delegation owns the blocking task, end or yield the parent turn. Omit wait to return immediately and receive completion through [auto-subagents update]; set wait to an explicit 1–300 second value only when this turn should wait for the initial task. Set required=true when the outcome is mandatory before the parent's terminal response; failures remain recoverable through the resume action. Do not use resume solely to wait for an existing task or request its result again; yield for the automatic completion update instead. Resume requires a real new instruction; queue schedules a separate turn and another completion. Never use bash sleep, watch, tail -f, polling loops, repeated status calls, dashboard, metadata, or file checks solely to wait." |
| 30 | 30 | ||||
| 31 | // subagentSchema merges the action schemas into the flat, model-facing schema | 31 | // subagentSchema merges the action schemas into the flat, model-facing schema | ||
| 32 | // the project keeps for provider compatibility. Every property is annotated | 32 | // the project keeps for provider compatibility. Every property is annotated | ||