detached e5afabc

Merge pull request #95 from bnema/feat/subagent-orchestrator-toggle

feat(agent): add subagent orchestrator toggle
commit
e5afabcabe81f50f1fd505fa5840d13218331b8d
author
bnema · · 2026-08-09 12:24 UTC
committer
GitHub · · 2026-08-09 12:24 UTC
merge of
a04f503 + 953e5a9 · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
6 files · +69 -9
M README.md +4 -3
@@ -294,6 +294,7 @@ Slash command names are case-insensitive in the TUI and messaging backends; argu
294294 | `/model` | Pick a model from a list (or `/model <id>` to set directly). |
295295 | `/reasoning` | Set the reasoning level for subsequent model calls. |
296296 | `/fast` | Toggle fast mode for subsequent model calls. |
297+| `/orchestrator` | Toggle automatic subagent orchestration. When disabled, subagent tools remain available for explicit delegation. |
297298 | `/llama` | Connect to the configured llama.cpp router, load, unload, or remove cached models, and search/download GGUF models from Hugging Face with live progress. Shown after llama.cpp login is configured. |
298299 | `/sessions` | Resume a previous session for this directory. The picker omits branches created only for tree navigation. |
299300 | `/fork` | Pick a previous user message and fork the current session after that turn. The selected turn becomes branch context and no provider turn starts during the checkout. |
@@ -308,7 +309,7 @@ Slash command names are case-insensitive in the TUI and messaging backends; argu
308309 | `/unjail` | Allow tools to touch paths outside again. |
309310 | `/reload-ext` | Hot-reload all extensions (re-read manifests, respawn subprocesses, rebuild tool registry). |
310311 | `/telegram` | Connect, disconnect, or show status of the Telegram bridge (takes `connect` / `disconnect` / `status` as an optional argument; opens a picker without one). When connected, DMs from the paired user become prompts in the running session and the assistant's replies are mirrored back to Telegram. Alias: `/tg`. |
311-| `/settings` | Change persistent settings, including web search, inline images, terminal alerts, AI terminal titles, auto-subagents, Ponytail coding mode, fast mode, main/sub-agent LSP access, and the auto-compact threshold. `/fast` is a shortcut for the fast-mode toggle. Saved to `$ZUT_HOME/config.json`; setting changes apply without a restart, while AI title generation waits for the first real prompt. |
312+| `/settings` | Change persistent settings, including web search, inline images, terminal alerts, AI terminal titles, Subagent Orchestrator, Ponytail coding mode, fast mode, main/sub-agent LSP access, and the auto-compact threshold. `/fast` and `/orchestrator` are shortcuts for their corresponding toggles. Saved to `$ZUT_HOME/config.json`; setting changes apply without a restart, while AI title generation waits for the first real prompt. |
312313 | `/clear` | Clear the chat transcript. |
313314 | `/exit` | Exit zut. |
314315
@@ -401,7 +402,7 @@ Background subagents that run alongside your main session. Each one is a separat
401402
402403 **`/session export` does NOT bundle subagents.** A `.zutsession` is just the main chat transcript; per-agent state (session file, unix-socket inbox) is machine-local and doesn't round-trip through a JSONL file. To share what an agent said, copy it out of the transcript view manually.
403404
404-**Auto-subagents.** With `/settings` -> auto-subagents on, the interactive primary agent enters strict orchestrator mode and gets whichever of the canonical `subagent_spawn` and `subagent_status` tools are permitted by launch-time policy. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. It must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches itself. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize results. Give workers self-contained tasks: shared-worktree workers edit the same working directory and need coordination, while `isolation:"worktree"` is for parallel coding in separate trees; a worktree patch must be integrated by a worker rather than applied by the primary agent. Child workers cannot recursively spawn more sub-agents in v1. The `subagent_status` tool accepts an optional `agent_id`: omit it to list visible workers, or pass a full id / unique prefix to query one without waiting for completion. It returns privacy-safe JSON metadata with the worker id, lifecycle state (`starting`, `running`, `completed`, `failed`, `cancelled`, or `detached`), underlying process/turn state, timestamps, a bounded first-line task summary, and terminal-result metadata when available; it does not return prompts, transcripts, result output, credentials, provider settings, or filesystem paths. The spawn tool returns the child id and initial state immediately; completion is a durable `turn.result` with a `subagent://<id>/result` reference. It accepts named profiles, timeout, `max_turns`, and shared/worktree isolation. Omit `max_turns` to use the supervisor policy; the default ceiling is 3 and `subagents.max_turns` changes it. Global concurrency limits apply equally to slash commands, tool calls, and batches. Completion is host-event-driven: wait for the host-injected `[auto-subagents update]`, the only completion signal. Never use `bash sleep`, `watch`, `tail -f`, polling loops, repeated `subagent_status`, or dashboard/metadata/event-log/file checks solely to wait; work on unrelated independent tasks or end/yield your turn. Legitimate waits inside user-requested commands, provider flows, extensions, or tests remain allowed. Off by default; toggle from `/settings`. 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 primary otherwise performs work itself without the strict orchestrator contract.
405+**Subagent Orchestrator.** With `/settings` → **Subagent Orchestrator** on (or `/orchestrator`), the interactive primary agent enters strict orchestrator mode and gets whichever of the canonical `subagent_spawn` and `subagent_status` tools are permitted by launch-time policy. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. It must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches itself. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize results. Give workers self-contained tasks: shared-worktree workers edit the same working directory and need coordination, while `isolation:"worktree"` is for parallel coding in separate trees; a worktree patch must be integrated by a worker rather than applied by the primary agent. Child workers cannot recursively spawn more sub-agents in v1. The `subagent_status` tool accepts an optional `agent_id`: omit it to list visible workers, or pass a full id / unique prefix to query one without waiting for completion. It returns privacy-safe JSON metadata with the worker id, lifecycle state (`starting`, `running`, `completed`, `failed`, `cancelled`, or `detached`), underlying process/turn state, timestamps, a bounded first-line task summary, and terminal-result metadata when available; it does not return prompts, transcripts, result output, credentials, provider settings, or filesystem paths. The spawn tool returns the child id and initial state immediately; completion is a durable `turn.result` with a `subagent://<id>/result` reference. It accepts named profiles, timeout, `max_turns`, and shared/worktree isolation. Omit `max_turns` to use the supervisor policy; the default ceiling is 3 and `subagents.max_turns` changes it. Global concurrency limits apply equally to slash commands, tool calls, and batches. Completion is host-event-driven: wait for the host-injected `[auto-subagents update]`, the only completion signal. Never use `bash sleep`, `watch`, `tail -f`, polling loops, repeated `subagent_status`, or dashboard/metadata/event-log/file checks solely to wait; work on unrelated independent tasks or end/yield your turn. Legitimate waits inside user-requested commands, provider flows, extensions, or tests remain allowed. Off by default; toggle with `/orchestrator` or from `/settings`. 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 primary otherwise performs work itself without the strict orchestrator contract.
405406
406407 ### Named subagent profiles
407408
@@ -415,7 +416,7 @@ Opens a dialog with every persistent setting. `up`/`down` to navigate, `enter` o
415416 - **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.
416417 - **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.
417418 - **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`.
418-- **auto-subagents** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent coordinates but does not make direct implementation changes. It can spawn background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. 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 primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, timeout, turn limits, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven: `[auto-subagents update]` completion updates are the only signal; 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.
419+- **Subagent Orchestrator** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent coordinates but does not make direct implementation changes. It can spawn background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. 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 primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, timeout, turn limits, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven: `[auto-subagents update]` completion updates are the only signal; 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.
419420 - **Ponytail coding mode** — include compact engineering guidance in each resolved system prompt; the guidance tells the model to apply it to coding, debugging, and review work rather than ordinary conversation. It favors understanding the real flow, small validated changes, reuse, and preserving safety checks. Enabled by default; changes apply to the next model call and persist as `ponytail_enabled` in `$ZUT_HOME/config.json`. It is included by interactive, print, stream, JSON, RPC, subagent, bot, SDK, and Zutfile agents.
420421 - **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`. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account.
421422 - **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`.
@@ -294,6 +294,7 @@ Slash command names are case-insensitive in the TUI and messaging backends; argu
294 | `/model` | Pick a model from a list (or `/model <id>` to set directly). |294 | `/model` | Pick a model from a list (or `/model <id>` to set directly). |
295 | `/reasoning` | Set the reasoning level for subsequent model calls. |295 | `/reasoning` | Set the reasoning level for subsequent model calls. |
296 | `/fast` | Toggle fast mode for subsequent model calls. |296 | `/fast` | Toggle fast mode for subsequent model calls. |
297+| `/orchestrator` | Toggle automatic subagent orchestration. When disabled, subagent tools remain available for explicit delegation. |
297 | `/llama` | Connect to the configured llama.cpp router, load, unload, or remove cached models, and search/download GGUF models from Hugging Face with live progress. Shown after llama.cpp login is configured. |298 | `/llama` | Connect to the configured llama.cpp router, load, unload, or remove cached models, and search/download GGUF models from Hugging Face with live progress. Shown after llama.cpp login is configured. |
298 | `/sessions` | Resume a previous session for this directory. The picker omits branches created only for tree navigation. |299 | `/sessions` | Resume a previous session for this directory. The picker omits branches created only for tree navigation. |
299 | `/fork` | Pick a previous user message and fork the current session after that turn. The selected turn becomes branch context and no provider turn starts during the checkout. |300 | `/fork` | Pick a previous user message and fork the current session after that turn. The selected turn becomes branch context and no provider turn starts during the checkout. |
@@ -308,7 +309,7 @@ Slash command names are case-insensitive in the TUI and messaging backends; argu
308 | `/unjail` | Allow tools to touch paths outside again. |309 | `/unjail` | Allow tools to touch paths outside again. |
309 | `/reload-ext` | Hot-reload all extensions (re-read manifests, respawn subprocesses, rebuild tool registry). |310 | `/reload-ext` | Hot-reload all extensions (re-read manifests, respawn subprocesses, rebuild tool registry). |
310 | `/telegram` | Connect, disconnect, or show status of the Telegram bridge (takes `connect` / `disconnect` / `status` as an optional argument; opens a picker without one). When connected, DMs from the paired user become prompts in the running session and the assistant's replies are mirrored back to Telegram. Alias: `/tg`. |311 | `/telegram` | Connect, disconnect, or show status of the Telegram bridge (takes `connect` / `disconnect` / `status` as an optional argument; opens a picker without one). When connected, DMs from the paired user become prompts in the running session and the assistant's replies are mirrored back to Telegram. Alias: `/tg`. |
311-| `/settings` | Change persistent settings, including web search, inline images, terminal alerts, AI terminal titles, auto-subagents, Ponytail coding mode, fast mode, main/sub-agent LSP access, and the auto-compact threshold. `/fast` is a shortcut for the fast-mode toggle. Saved to `$ZUT_HOME/config.json`; setting changes apply without a restart, while AI title generation waits for the first real prompt. |312+| `/settings` | Change persistent settings, including web search, inline images, terminal alerts, AI terminal titles, Subagent Orchestrator, Ponytail coding mode, fast mode, main/sub-agent LSP access, and the auto-compact threshold. `/fast` and `/orchestrator` are shortcuts for their corresponding toggles. Saved to `$ZUT_HOME/config.json`; setting changes apply without a restart, while AI title generation waits for the first real prompt. |
312 | `/clear` | Clear the chat transcript. |313 | `/clear` | Clear the chat transcript. |
313 | `/exit` | Exit zut. |314 | `/exit` | Exit zut. |
314 315
@@ -401,7 +402,7 @@ Background subagents that run alongside your main session. Each one is a separat
401 402
402 **`/session export` does NOT bundle subagents.** A `.zutsession` is just the main chat transcript; per-agent state (session file, unix-socket inbox) is machine-local and doesn't round-trip through a JSONL file. To share what an agent said, copy it out of the transcript view manually.403 **`/session export` does NOT bundle subagents.** A `.zutsession` is just the main chat transcript; per-agent state (session file, unix-socket inbox) is machine-local and doesn't round-trip through a JSONL file. To share what an agent said, copy it out of the transcript view manually.
403 404
404-**Auto-subagents.** With `/settings` -> auto-subagents on, the interactive primary agent enters strict orchestrator mode and gets whichever of the canonical `subagent_spawn` and `subagent_status` tools are permitted by launch-time policy. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. It must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches itself. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize results. Give workers self-contained tasks: shared-worktree workers edit the same working directory and need coordination, while `isolation:"worktree"` is for parallel coding in separate trees; a worktree patch must be integrated by a worker rather than applied by the primary agent. Child workers cannot recursively spawn more sub-agents in v1. The `subagent_status` tool accepts an optional `agent_id`: omit it to list visible workers, or pass a full id / unique prefix to query one without waiting for completion. It returns privacy-safe JSON metadata with the worker id, lifecycle state (`starting`, `running`, `completed`, `failed`, `cancelled`, or `detached`), underlying process/turn state, timestamps, a bounded first-line task summary, and terminal-result metadata when available; it does not return prompts, transcripts, result output, credentials, provider settings, or filesystem paths. The spawn tool returns the child id and initial state immediately; completion is a durable `turn.result` with a `subagent://<id>/result` reference. It accepts named profiles, timeout, `max_turns`, and shared/worktree isolation. Omit `max_turns` to use the supervisor policy; the default ceiling is 3 and `subagents.max_turns` changes it. Global concurrency limits apply equally to slash commands, tool calls, and batches. Completion is host-event-driven: wait for the host-injected `[auto-subagents update]`, the only completion signal. Never use `bash sleep`, `watch`, `tail -f`, polling loops, repeated `subagent_status`, or dashboard/metadata/event-log/file checks solely to wait; work on unrelated independent tasks or end/yield your turn. Legitimate waits inside user-requested commands, provider flows, extensions, or tests remain allowed. Off by default; toggle from `/settings`. 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 primary otherwise performs work itself without the strict orchestrator contract.405+**Subagent Orchestrator.** With `/settings` → **Subagent Orchestrator** on (or `/orchestrator`), the interactive primary agent enters strict orchestrator mode and gets whichever of the canonical `subagent_spawn` and `subagent_status` tools are permitted by launch-time policy. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. It must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches itself. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize results. Give workers self-contained tasks: shared-worktree workers edit the same working directory and need coordination, while `isolation:"worktree"` is for parallel coding in separate trees; a worktree patch must be integrated by a worker rather than applied by the primary agent. Child workers cannot recursively spawn more sub-agents in v1. The `subagent_status` tool accepts an optional `agent_id`: omit it to list visible workers, or pass a full id / unique prefix to query one without waiting for completion. It returns privacy-safe JSON metadata with the worker id, lifecycle state (`starting`, `running`, `completed`, `failed`, `cancelled`, or `detached`), underlying process/turn state, timestamps, a bounded first-line task summary, and terminal-result metadata when available; it does not return prompts, transcripts, result output, credentials, provider settings, or filesystem paths. The spawn tool returns the child id and initial state immediately; completion is a durable `turn.result` with a `subagent://<id>/result` reference. It accepts named profiles, timeout, `max_turns`, and shared/worktree isolation. Omit `max_turns` to use the supervisor policy; the default ceiling is 3 and `subagents.max_turns` changes it. Global concurrency limits apply equally to slash commands, tool calls, and batches. Completion is host-event-driven: wait for the host-injected `[auto-subagents update]`, the only completion signal. Never use `bash sleep`, `watch`, `tail -f`, polling loops, repeated `subagent_status`, or dashboard/metadata/event-log/file checks solely to wait; work on unrelated independent tasks or end/yield your turn. Legitimate waits inside user-requested commands, provider flows, extensions, or tests remain allowed. Off by default; toggle with `/orchestrator` or from `/settings`. 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 primary otherwise performs work itself without the strict orchestrator contract.
405 406
406 ### Named subagent profiles407 ### Named subagent profiles
407 408
@@ -415,7 +416,7 @@ Opens a dialog with every persistent setting. `up`/`down` to navigate, `enter` o
415 - **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.416 - **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.
416 - **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.417 - **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.
417 - **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`.418 - **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`.
418-- **auto-subagents** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent coordinates but does not make direct implementation changes. It can spawn background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. 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 primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, timeout, turn limits, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven: `[auto-subagents update]` completion updates are the only signal; 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.419+- **Subagent Orchestrator** — enable strict primary-agent orchestrator mode: delegate implementation, debugging/testing, and code-review work to named or general workers; the primary agent coordinates but does not make direct implementation changes. It can spawn background sub-agents via `subagent_spawn` and query live state via `subagent_status` when those tools are permitted. If delegation is unavailable because of launch-time restrictions, the contract remains active, profile metadata is withheld, and the primary reports the limitation rather than implementing directly. 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 primary otherwise works directly without the strict orchestrator contract. The tools accept named profiles, reasoning, per-spawn fast-mode overrides, timeout, turn limits, and shared/worktree isolation where applicable; lifecycle and result references are persisted. Completion is host-event-driven: `[auto-subagents update]` completion updates are the only signal; 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.
419 - **Ponytail coding mode** — include compact engineering guidance in each resolved system prompt; the guidance tells the model to apply it to coding, debugging, and review work rather than ordinary conversation. It favors understanding the real flow, small validated changes, reuse, and preserving safety checks. Enabled by default; changes apply to the next model call and persist as `ponytail_enabled` in `$ZUT_HOME/config.json`. It is included by interactive, print, stream, JSON, RPC, subagent, bot, SDK, and Zutfile agents.420 - **Ponytail coding mode** — include compact engineering guidance in each resolved system prompt; the guidance tells the model to apply it to coding, debugging, and review work rather than ordinary conversation. It favors understanding the real flow, small validated changes, reuse, and preserving safety checks. Enabled by default; changes apply to the next model call and persist as `ponytail_enabled` in `$ZUT_HOME/config.json`. It is included by interactive, print, stream, JSON, RPC, subagent, bot, SDK, and Zutfile agents.
420 - **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`. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account.421 - **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`. Other providers currently return an unsupported-provider error. Fast mode may cost more and depends on the selected model/account.
421 - **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`.422 - **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`.
M docs/subagents.md +2 -2
@@ -68,9 +68,9 @@ Output follows the selected existing mode. Print writes only the final synthesis
6868
6969 ## Selecting a profile
7070
71-When **auto-subagents** is enabled in `/settings`, the interactive primary agent runs in strict orchestrator mode. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. The primary agent must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize their results.
71+When **Subagent Orchestrator** is enabled in `/settings` or with `/orchestrator`, the interactive primary agent runs in strict orchestrator mode. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. The primary agent must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize their results.
7272
73-When auto-subagents is disabled, the canonical subagent tools remain available subject to launch-time policy. The primary may use them when the user requests delegation or an active skill workflow requires delegation. It continues to perform work itself otherwise and does not receive the strict orchestrator contract. The setting changes orchestration prompting, not tool or profile availability.
73+When Subagent Orchestrator is disabled, the canonical subagent tools remain available subject to launch-time policy. The primary may use them when the user requests delegation or an active skill workflow requires delegation. It continues to perform work itself otherwise and does not receive the strict orchestrator contract. The setting changes orchestration prompting, not tool or profile availability.
7474
7575 When `subagent_spawn` is available, the primary agent receives a compact `[subagents_list]` section in its system prompt and should select the profile whose description best matches each worker task. If launch-time policy withholds `subagent_spawn`, strict orchestrator guidance remains active, profile metadata is omitted, and the primary must report that delegation is unavailable rather than implementing directly. If no profile fits when spawning is available, omit `agent` to use a general worker:
7676
@@ -68,9 +68,9 @@ Output follows the selected existing mode. Print writes only the final synthesis
68 68
69 ## Selecting a profile69 ## Selecting a profile
70 70
71-When **auto-subagents** is enabled in `/settings`, the interactive primary agent runs in strict orchestrator mode. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. The primary agent must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize their results.71+When **Subagent Orchestrator** is enabled in `/settings` or with `/orchestrator`, the interactive primary agent runs in strict orchestrator mode. It must delegate all implementation, debugging/testing, and code-review work to an appropriately named profile, or to a clearly described general worker when no profile fits. The primary agent must not write or edit code, make direct implementation tool calls, inspect or review code, or apply worker patches. It may decompose requests, select and spawn workers, check status, coordinate follow-ups, and synthesize their results.
72 72
73-When auto-subagents is disabled, the canonical subagent tools remain available subject to launch-time policy. The primary may use them when the user requests delegation or an active skill workflow requires delegation. It continues to perform work itself otherwise and does not receive the strict orchestrator contract. The setting changes orchestration prompting, not tool or profile availability.73+When Subagent Orchestrator is disabled, the canonical subagent tools remain available subject to launch-time policy. The primary may use them when the user requests delegation or an active skill workflow requires delegation. It continues to perform work itself otherwise and does not receive the strict orchestrator contract. The setting changes orchestration prompting, not tool or profile availability.
74 74
75 When `subagent_spawn` is available, the primary agent receives a compact `[subagents_list]` section in its system prompt and should select the profile whose description best matches each worker task. If launch-time policy withholds `subagent_spawn`, strict orchestrator guidance remains active, profile metadata is omitted, and the primary must report that delegation is unavailable rather than implementing directly. If no profile fits when spawning is available, omit `agent` to use a general worker:75 When `subagent_spawn` is available, the primary agent receives a compact `[subagents_list]` section in its system prompt and should select the profile whose description best matches each worker task. If launch-time policy withholds `subagent_spawn`, strict orchestrator guidance remains active, profile metadata is omitted, and the primary must report that delegation is unavailable rather than implementing directly. If no profile fits when spawning is available, omit `agent` to use a general worker:
76 76
M packages/agent/modes/auto_subagents_policy_test.go +45 -0
@@ -83,6 +83,51 @@ func TestAutoSubagentsToggleRollsBackInMemoryStateWhenPersistenceFails(t *testin
8383 }
8484 }
8585
86+func TestOrchestratorSlashTogglesAutoSubagents(t *testing.T) {
87+ allowed := true
88+ enabled := false
89+ supervisor := subagents.New(subagents.Config{Root: t.TempDir(), RepoRoot: t.TempDir()})
90+ t.Cleanup(supervisor.StopAll)
91+ store := &failingAutoSubagentsSettingsStore{}
92+ agent := core.NewAgent(nil, "test-model", "base system", core.Registry{})
93+ interactive := NewInteractive(InteractiveConfig{
94+ Agent: agent,
95+ Supervisor: supervisor,
96+ AutoSubagentsEnabled: &enabled,
97+ AutoSubagentsToolAllowed: &allowed,
98+ AutoSubagentsSystemAddendum: "orchestrator guidance",
99+ SettingsStore: store,
100+ })
101+ interactive.rend = nil
102+
103+ if interactive.runSlash(context.Background(), "/ORCHESTRATOR") {
104+ t.Fatal("/orchestrator requested exit")
105+ }
106+ if interactive.cfg.AutoSubagentsEnabled == nil || !*interactive.cfg.AutoSubagentsEnabled {
107+ t.Fatal("/orchestrator did not enable orchestration")
108+ }
109+ if store.calls != 1 || interactive.statusOK != "subagent orchestrator enabled" {
110+ t.Fatalf("enable persistence/status = calls=%d status=%q", store.calls, interactive.statusOK)
111+ }
112+ if system, _ := agent.PromptConfig(); !strings.Contains(system, "orchestrator guidance") {
113+ t.Fatalf("enabled system prompt = %q, want orchestrator guidance", system)
114+ }
115+
116+ interactive.runSlash(context.Background(), "/orchestrator")
117+ if interactive.cfg.AutoSubagentsEnabled == nil || *interactive.cfg.AutoSubagentsEnabled {
118+ t.Fatal("/orchestrator did not disable orchestration")
119+ }
120+ if store.calls != 2 || interactive.statusOK != "subagent orchestrator disabled" {
121+ t.Fatalf("disable persistence/status = calls=%d status=%q", store.calls, interactive.statusOK)
122+ }
123+ if system, _ := agent.PromptConfig(); strings.Contains(system, "orchestrator guidance") {
124+ t.Fatalf("disabled system prompt still contains orchestrator guidance: %q", system)
125+ }
126+ if _, ok := agent.ToolsSnapshot()["subagent_spawn"]; !ok {
127+ t.Fatal("disabling orchestration removed subagent_spawn")
128+ }
129+}
130+
86131 func TestAutoSubagentsSettingsDisableUnavailablePolicy(t *testing.T) {
87132 trueValue := true
88133 falseValue := false
@@ -83,6 +83,51 @@ func TestAutoSubagentsToggleRollsBackInMemoryStateWhenPersistenceFails(t *testin
83 }83 }
84 }84 }
85 85
86+func TestOrchestratorSlashTogglesAutoSubagents(t *testing.T) {
87+ allowed := true
88+ enabled := false
89+ supervisor := subagents.New(subagents.Config{Root: t.TempDir(), RepoRoot: t.TempDir()})
90+ t.Cleanup(supervisor.StopAll)
91+ store := &failingAutoSubagentsSettingsStore{}
92+ agent := core.NewAgent(nil, "test-model", "base system", core.Registry{})
93+ interactive := NewInteractive(InteractiveConfig{
94+ Agent: agent,
95+ Supervisor: supervisor,
96+ AutoSubagentsEnabled: &enabled,
97+ AutoSubagentsToolAllowed: &allowed,
98+ AutoSubagentsSystemAddendum: "orchestrator guidance",
99+ SettingsStore: store,
100+ })
101+ interactive.rend = nil
102+
103+ if interactive.runSlash(context.Background(), "/ORCHESTRATOR") {
104+ t.Fatal("/orchestrator requested exit")
105+ }
106+ if interactive.cfg.AutoSubagentsEnabled == nil || !*interactive.cfg.AutoSubagentsEnabled {
107+ t.Fatal("/orchestrator did not enable orchestration")
108+ }
109+ if store.calls != 1 || interactive.statusOK != "subagent orchestrator enabled" {
110+ t.Fatalf("enable persistence/status = calls=%d status=%q", store.calls, interactive.statusOK)
111+ }
112+ if system, _ := agent.PromptConfig(); !strings.Contains(system, "orchestrator guidance") {
113+ t.Fatalf("enabled system prompt = %q, want orchestrator guidance", system)
114+ }
115+
116+ interactive.runSlash(context.Background(), "/orchestrator")
117+ if interactive.cfg.AutoSubagentsEnabled == nil || *interactive.cfg.AutoSubagentsEnabled {
118+ t.Fatal("/orchestrator did not disable orchestration")
119+ }
120+ if store.calls != 2 || interactive.statusOK != "subagent orchestrator disabled" {
121+ t.Fatalf("disable persistence/status = calls=%d status=%q", store.calls, interactive.statusOK)
122+ }
123+ if system, _ := agent.PromptConfig(); strings.Contains(system, "orchestrator guidance") {
124+ t.Fatalf("disabled system prompt still contains orchestrator guidance: %q", system)
125+ }
126+ if _, ok := agent.ToolsSnapshot()["subagent_spawn"]; !ok {
127+ t.Fatal("disabling orchestration removed subagent_spawn")
128+ }
129+}
130+
86 func TestAutoSubagentsSettingsDisableUnavailablePolicy(t *testing.T) {131 func TestAutoSubagentsSettingsDisableUnavailablePolicy(t *testing.T) {
87 trueValue := true132 trueValue := true
88 falseValue := false133 falseValue := false
M packages/agent/modes/interactive.go +7 -4
@@ -4614,8 +4614,8 @@ func (i *Interactive) openSettingsDialog() {
46144614 },
46154615 {
46164616 key: "auto_subagents_enabled",
4617- label: "auto-subagents",
4618- desc: "let the agent spawn background sub-agents and query their live state",
4617+ label: "Subagent Orchestrator",
4618+ desc: "automatically delegate coding work to sub-agents; tools stay available when disabled",
46194619 value: autoSubagents,
46204620 disabled: autoSubagentsDisabled,
46214621 hint: autoSubagentsHint,
@@ -5236,7 +5236,7 @@ func (i *Interactive) applySettingToggle(key string, value bool) {
52365236 if value && !i.autoSubagentsAvailable() {
52375237 i.mu.Lock()
52385238 i.statusOK = ""
5239- i.statusErr = "auto-subagents unavailable: " + i.autoSubagentsUnavailableHint()
5239+ i.statusErr = "subagent orchestrator unavailable: " + i.autoSubagentsUnavailableHint()
52405240 i.mu.Unlock()
52415241 return
52425242 }
@@ -5265,7 +5265,7 @@ func (i *Interactive) applySettingToggle(key string, value bool) {
52655265 // should orchestrate proactively or delegate only on user request.
52665266 i.applyAutoSubagentsSystemPrompt(value)
52675267 i.mu.Lock()
5268- i.statusOK = "auto-subagents " + onOff(value)
5268+ i.statusOK = "subagent orchestrator " + onOff(value)
52695269 i.statusErr = ""
52705270 i.mu.Unlock()
52715271 case "fast_mode":
@@ -5994,6 +5994,9 @@ func (i *Interactive) runSlash(ctx context.Context, cmd string) (done bool) {
59945994 case "/fast":
59955995 enabled := i.cfg.FastMode == nil || !*i.cfg.FastMode
59965996 i.applySettingToggle("fast_mode", enabled)
5997+ case "/orchestrator":
5998+ enabled := i.cfg.AutoSubagentsEnabled == nil || !*i.cfg.AutoSubagentsEnabled
5999+ i.applySettingToggle("auto_subagents_enabled", enabled)
59976000 case "/settings":
59986001 i.openSettingsDialog()
59996002 case "/sessions":
@@ -4614,8 +4614,8 @@ func (i *Interactive) openSettingsDialog() {
4614 },4614 },
4615 {4615 {
4616 key: "auto_subagents_enabled",4616 key: "auto_subagents_enabled",
4617- label: "auto-subagents",4617+ label: "Subagent Orchestrator",
4618- desc: "let the agent spawn background sub-agents and query their live state",4618+ desc: "automatically delegate coding work to sub-agents; tools stay available when disabled",
4619 value: autoSubagents,4619 value: autoSubagents,
4620 disabled: autoSubagentsDisabled,4620 disabled: autoSubagentsDisabled,
4621 hint: autoSubagentsHint,4621 hint: autoSubagentsHint,
@@ -5236,7 +5236,7 @@ func (i *Interactive) applySettingToggle(key string, value bool) {
5236 if value && !i.autoSubagentsAvailable() {5236 if value && !i.autoSubagentsAvailable() {
5237 i.mu.Lock()5237 i.mu.Lock()
5238 i.statusOK = ""5238 i.statusOK = ""
5239- i.statusErr = "auto-subagents unavailable: " + i.autoSubagentsUnavailableHint()5239+ i.statusErr = "subagent orchestrator unavailable: " + i.autoSubagentsUnavailableHint()
5240 i.mu.Unlock()5240 i.mu.Unlock()
5241 return5241 return
5242 }5242 }
@@ -5265,7 +5265,7 @@ func (i *Interactive) applySettingToggle(key string, value bool) {
5265 // should orchestrate proactively or delegate only on user request.5265 // should orchestrate proactively or delegate only on user request.
5266 i.applyAutoSubagentsSystemPrompt(value)5266 i.applyAutoSubagentsSystemPrompt(value)
5267 i.mu.Lock()5267 i.mu.Lock()
5268- i.statusOK = "auto-subagents " + onOff(value)5268+ i.statusOK = "subagent orchestrator " + onOff(value)
5269 i.statusErr = ""5269 i.statusErr = ""
5270 i.mu.Unlock()5270 i.mu.Unlock()
5271 case "fast_mode":5271 case "fast_mode":
@@ -5994,6 +5994,9 @@ func (i *Interactive) runSlash(ctx context.Context, cmd string) (done bool) {
5994 case "/fast":5994 case "/fast":
5995 enabled := i.cfg.FastMode == nil || !*i.cfg.FastMode5995 enabled := i.cfg.FastMode == nil || !*i.cfg.FastMode
5996 i.applySettingToggle("fast_mode", enabled)5996 i.applySettingToggle("fast_mode", enabled)
5997+ case "/orchestrator":
5998+ enabled := i.cfg.AutoSubagentsEnabled == nil || !*i.cfg.AutoSubagentsEnabled
5999+ i.applySettingToggle("auto_subagents_enabled", enabled)
5997 case "/settings":6000 case "/settings":
5998 i.openSettingsDialog()6001 i.openSettingsDialog()
5999 case "/sessions":6002 case "/sessions":
M packages/agent/modes/slash_suggest.go +1 -0
@@ -52,6 +52,7 @@ var slashCatalog = []slashCommand{
5252 {Name: "/model", Desc: "pick a model (or /model <id>)"},
5353 {Name: "/reasoning", Desc: "set the reasoning level"},
5454 {Name: "/fast", Desc: "toggle fast mode"},
55+ {Name: "/orchestrator", Desc: "toggle automatic subagent orchestration"},
5556 {Name: "/llama", Desc: "manage llama.cpp router models"},
5657 {Name: "/sessions", Desc: "resume a previous session for this directory"},
5758 {Name: "/fork", Desc: "pick a user message and fork the current session"},
@@ -52,6 +52,7 @@ var slashCatalog = []slashCommand{
52 {Name: "/model", Desc: "pick a model (or /model <id>)"},52 {Name: "/model", Desc: "pick a model (or /model <id>)"},
53 {Name: "/reasoning", Desc: "set the reasoning level"},53 {Name: "/reasoning", Desc: "set the reasoning level"},
54 {Name: "/fast", Desc: "toggle fast mode"},54 {Name: "/fast", Desc: "toggle fast mode"},
55+ {Name: "/orchestrator", Desc: "toggle automatic subagent orchestration"},
55 {Name: "/llama", Desc: "manage llama.cpp router models"},56 {Name: "/llama", Desc: "manage llama.cpp router models"},
56 {Name: "/sessions", Desc: "resume a previous session for this directory"},57 {Name: "/sessions", Desc: "resume a previous session for this directory"},
57 {Name: "/fork", Desc: "pick a user message and fork the current session"},58 {Name: "/fork", Desc: "pick a user message and fork the current session"},
M packages/agent/modes/slash_suggest_test.go +10 -0
@@ -54,6 +54,16 @@ func TestSlashSuggesterHasFastModeToggle(t *testing.T) {
5454 }
5555 }
5656
57+func TestSlashSuggesterHasOrchestratorToggle(t *testing.T) {
58+ s := newSlashSuggester()
59+ if got := commandNames(s.matches("/orc")); !contains(got, "/orchestrator") {
60+ t.Fatalf("/orchestrator missing from suggestions, got %v", got)
61+ }
62+ if !isKnownSlashCommand("/ORCHESTRATOR") {
63+ t.Fatal("/ORCHESTRATOR was not recognized as a built-in command")
64+ }
65+}
66+
5767 func TestSlashCommandsAreCaseInsensitive(t *testing.T) {
5868 s := newSlashSuggester()
5969 if got := commandNames(s.matches("/EX")); !contains(got, "/exit") {
@@ -54,6 +54,16 @@ func TestSlashSuggesterHasFastModeToggle(t *testing.T) {
54 }54 }
55 }55 }
56 56
57+func TestSlashSuggesterHasOrchestratorToggle(t *testing.T) {
58+ s := newSlashSuggester()
59+ if got := commandNames(s.matches("/orc")); !contains(got, "/orchestrator") {
60+ t.Fatalf("/orchestrator missing from suggestions, got %v", got)
61+ }
62+ if !isKnownSlashCommand("/ORCHESTRATOR") {
63+ t.Fatal("/ORCHESTRATOR was not recognized as a built-in command")
64+ }
65+}
66+
57 func TestSlashCommandsAreCaseInsensitive(t *testing.T) {67 func TestSlashCommandsAreCaseInsensitive(t *testing.T) {
58 s := newSlashSuggester()68 s := newSlashSuggester()
59 if got := commandNames(s.matches("/EX")); !contains(got, "/exit") {69 if got := commandNames(s.matches("/EX")); !contains(got, "/exit") {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close