v0.35.0 21873e8

subagents.md RawHistoryFolder

Resident subagents

V0.x breaking change: zut no longer supports subprocess subagent state. Previous state is ignored rather than read or migrated; remove it when you no longer need it. Existing child jobs are never resumed.

Subagents are independent core.Agent conversations resident in the same zut process as their parent. A child has a stable, private session identity, its own provider client and tool registry, a cancellation boundary, and an authoritative journal. Starting a child never launches another zut executable.

Profiles

Profiles are Markdown files discovered from ~/.agents/agents/*.md and paths in ZUT_AGENT_PROFILES. They are inputs only; zut does not execute them.

---
name: reviewer
description: Read-only code reviewer
tools: [read, grep]
model: openai-codex/gpt-5.6-luna
thinking: high
systemPromptMode: replace
inheritProjectContext: false
inheritSkills: false
fastMode: false
---

Inspect the requested scope and report evidence-backed findings.

tools is a capability boundary. An omitted value inherits the child-safe catalogue, tools: [] grants no tools, and an explicit list replaces the default. The child-safe catalogue contains only tools offered by the parent that are also available in the resolved child runtime; parent-only scheduling and extension tools are never inherited. Names unavailable to the child (including host-only extensions) and tools denied by subagents.allowed_tools are omitted from an explicit list; they never grant the child additional access. model, provider, thinking, the prompt mode, project/skill inheritance, and fastMode are resolved before the child is accepted. Spawn-level model, provider, reasoning, and fast-mode values take precedence where supplied.

Children are always fresh conversations: they receive the delegated task and resolved host/profile context, never the parent transcript or hidden reasoning. They cannot recursively create more children.

Lifecycle and persistence

The manager records each accepted child under its managed state root:

subagents/<child-id>/
  transcript.jsonl  # authoritative accepted turns and finalized messages
  owner.lock        # host-ownership coordination; do not modify or remove
  .transcript-backup-* # retained private pre-repair transcript, when repaired
  metadata.json     # rebuildable bounded state
  result.json       # latest outcome, final summary, artifacts
  patch.diff        # optional worktree capture

Acceptance is durable before subagent_spawn reports success. Finalized user, assistant, tool-call, and tool-result messages are journaled; streamed deltas and hidden reasoning are not exposed as ordinary history. A tool call is stored before execution and reconciliation repairs incomplete call/result pairs.

All children stop when the host exits. On the next start, queued or running turns are marked interrupted; zut never replays their task. Resume only with an explicit new prompt through subagent_resume, the child-session composer, or /subagents resume <id> <prompt>.

Multiple zut processes may share a state root. Each resident journal has one host owner at a time. A process that finds a child owned elsewhere reports it as such and does not inspect, recover, or modify its transcript. Resume that child from its owning host or after the owner exits. On a subsequent safe reconciliation, zut repairs only the known legacy false-recovery sequence; it leaves any ambiguous journal corruption untouched. A repair retains the pre-repair transcript as .transcript-backup-*; it can contain private session data and is intentionally not removed automatically.

subagent_status reports owned_elsewhere: true when another process owns a child. The field is omitted when false. A foreign-owned child cannot be resumed, or have its history or result read, from this process.

The global scheduler admits the oldest eligible accepted prompt, runs at most one turn for each child, and defaults to six concurrent turns. Set subagents.max_concurrent to a positive limit to override it. Queueing is unlimited by default; a positive subagents.queue_timeout cancels an accepted prompt that has not received a slot and records its terminal failure durably. subagents.allowed_tools is an allowlist for child-visible tools and subagents.allowed_roots limits eligible child workspaces. Resident children have no cumulative token budget. Execution stays bounded through a finite per-turn step default: a child whose parent resolution is unlimited runs with MaxSteps=50; an explicit parent limit is preserved. Removed legacy settings, including tui_subagent_position and subagents.budget_ratio, are ignored. Resident journals written by older versions are read with explicit translation (an old budget_exhausted outcome reconciles as failure) or, for unknown versions, left untouched on disk and excluded from automatic discovery. Incompatible journals cannot be resumed; start a new child instead. Other journal recovery errors are still reported.

Compatibility notes: new journals write version 3 and carry no budget fields, baselines, or exhaustion states. Version 2 archives are read with explicit translation and their transcripts are never rewritten by translation. result.json keeps a deprecated handoff field that stays empty for new results and remains readable for archives. subagent_status no longer exposes budget or budget_source fields.

Context reminders

When a child's last-turn prompt reaches 85% of its model context window, the runner injects one non-blocking reminder into the next provider request:

Context usage is at NN% of the model window. Finish the current task, report
results, limits, and remaining verifications, and do not start broad new work.

The reminder fires at most once per child runner and never blocks a turn. It travels as developer context in the live request; the durable transcript keeps only finalized history. Usage is the last-turn prompt size (input plus cache read/write tokens) against the resolved context window; an unknown window never triggers a reminder. The per-turn gauge resets when the host restarts, so a restarted child is reminded again only once fresh usage past the threshold arrives.

Retrieve the saved result without executing a model:

{"agent_id":"<child-id>","include_result":true}

Pass this to subagent_status, then reconcile the history and artifacts before repeating any side effects. Explicit subagent_resume after a terminal failure continues the retained session, workspace, and cumulative cost. It does not automatically retry the task. Ordinary follow-ups continue the existing session.

required: true makes a delegated result an obligation of the parent turn. Failed, cancelled, and interrupted required work remains unresolved until an explicit successful follow-up. Reading a saved result or accepting a recovery prompt does not satisfy the obligation. A host restart never retries it automatically.

Delegation ownership

Interactive proactive delegation keeps the primary agent on the critical path. Before spawning, it selects useful local work and delegates only a concrete, bounded sidecar with a non-overlapping question, responsibility, package, or file set. Immediate blockers and tightly coupled work stay local. While a child is active, it owns that scope; the primary continues only its preselected independent work instead of repeating the investigation, review, testing, or implementation. If an explicit user request or active workflow hands blocking work to a child, the primary yields for the completion update. Once a worktree child succeeds, the primary may apply and verify its captured patch without redoing the delegated task.

Explicit headless --orchestrate remains manager-only. Its primary divides the request into disjoint worker scopes, coordinates active children, and yields rather than implementing or reproducing delegated work. Children do not inherit the parent's strict orchestrator role. Headless orchestration waits for every accepted child before continuing its completion wave; required: true additionally creates a durable obligation. When proactive interactive delegation cannot spawn because of launch-time policy, the primary continues locally; a strict headless orchestrator instead reports the missing required capability.

Tools and slash commands

The model-facing tools retain their logical names:

  • subagent_spawn accepts task, optional agent, model and provider, reasoning, fast_mode, required, wait, and isolation (shared or worktree). wait is an explicit whole-second value from 1 through 300; when omitted, spawning returns immediately. A timed-out wait leaves the accepted child active, whether it is queued or running. Do not retry that task until it reaches a terminal failure, cancellation, or interruption. It returns a logical subagent://<id> reference.
  • subagent_status returns bounded current state for one child or the current set immediately. With agent_id and include_result: true, it also reads the saved terminal result without model execution. Without this option it remains metadata-only; foreign-owned results cannot be read. Result-read errors distinguish foreign ownership, a missing saved result, and permission denial without exposing filesystem paths or saved content.
  • subagent_stop stops one live child.
  • subagent_resume accepts an explicit follow-up prompt for an existing child. After a terminal failure, inspect the saved result before resuming; resume continues the retained session.

Child execution started by subagent_spawn is asynchronous unless it receives an explicit wait value. For an unwaited spawn, completion arrives through the host’s typed completion update; subagent_status returns immediately and does not wait for completion. Do not use sleep loops, repeated status calls, journal files, or terminal UI inspection as a completion signal. In interactive mode, a result received while the primary is busy enters the visible sliding in queue and reaches the model at its next safe boundary, without interrupting a model request or tool call and without waiting for other children. Results already queued are not repeated when the parent turn ends. Undelivered results remain queued after a provider or compaction error for the next turn; they do not automatically retry the failed request. Explicit cancellation clears pending queue entries. The queue is in memory, while the child’s saved result remains available through subagent_status. When the primary is idle, remaining children are collected into one completion wave. Headless orchestration still waits for every accepted child before its next parent turn. Successful completions include the final visible assistant summary, capped at 256 KiB; open the child session for the complete durable transcript.

/subagents opens the resident-child list, ordered by the latest state change. Each row leads with the profile (or model), shows a human terminal state such as completed, a relative update time, and a short ID. Press Down from the main composer to open this list without clearing a draft when a child exists. Use arrows and Enter to open a child session; /subagents new <task> creates a child; /subagents logs <id> opens its history; /subagents result <id> shows the bounded final summary; kill <id> stops it; and resume <id> <prompt> continues it.

The child session uses the same transcript renderer as the main session. Recent history is bounded and loaded asynchronously; PgUp asks for an older page. Up/Down preserves the current reading position, and PgDn returns to the live tail after unread updates accumulate. The screen combines durable finalized history with an immutable in-memory projection of the active turn. Enter submits the local composer only after the manager durably accepts it; Esc closes the session. History may contain task text, tool arguments, tool results, and source-derived output, so treat it as private local session data.

Worktrees and references

Shared children use the host working directory. With isolation: "worktree", zut prepares a detached Git worktree and captures a patch and changed-file list on successful completion or non-cancelled failure. Failed turns retain partial work in the worktree, along with any captured patch and changed-file list. zut never applies a captured patch automatically. Failed or interrupted worktrees are retained for inspection; an idle successful worktree is cleaned when its child is explicitly stopped.

Use subagent_status with agent_id and include_result: true to retrieve the saved result, changed_files, and patch_ref when a patch was captured. The patch bytes are stored in subagents/<child-id>/patch.diff under the managed state root shown above; logical references are identifiers, not filesystem paths. Inspect the retained worktree and patch before resuming or applying partial changes.

New terminal journal records also save the capture metadata, so reconciliation can restore it if result.json is missing or corrupt. Older records remain readable, but cannot reconstruct artifact metadata they never recorded.

Logical references avoid exposing runtime paths:

subagent://<id>
subagent://<id>/history
subagent://<id>/result
subagent://<id>/patch

Provider caching

Each main and child conversation sends a stable logical session ID and a new turn ID per accepted prompt to the provider layer. Provider adapters decide whether and how to use them: OpenAI/Codex translates a supported stable session into its cache key and routing header, while other adapters preserve deterministic request input and use only cache controls their provider/model/endpoint supports. An OpenAI-compatible wire shape is not itself evidence that a cache extension or transport feature is available. Models continue through their declared provider transport; a transport change must not change the logical session or turn identity used by the provider request.

source
1# Resident subagents
2
3> **V0.x breaking change:** zut no longer supports subprocess subagent state.
4> Previous state is ignored rather than read or migrated; remove it when you
5> no longer need it. Existing child jobs are never resumed.
6
7Subagents are independent `core.Agent` conversations resident in the same zut
8process as their parent. A child has a stable, private session identity, its own
9provider client and tool registry, a cancellation boundary, and an authoritative
10journal. Starting a child never launches another zut executable.
11
12## Profiles
13
14Profiles are Markdown files discovered from `~/.agents/agents/*.md` and paths
15in `ZUT_AGENT_PROFILES`. They are inputs only; zut does not execute them.
16
17```markdown
18---
19name: reviewer
20description: Read-only code reviewer
21tools: [read, grep]
22model: openai-codex/gpt-5.6-luna
23thinking: high
24systemPromptMode: replace
25inheritProjectContext: false
26inheritSkills: false
27fastMode: false
28---
29
30Inspect the requested scope and report evidence-backed findings.
31```
32
33`tools` is a capability boundary. An omitted value inherits the child-safe
34catalogue, `tools: []` grants no tools, and an explicit list replaces the
35default. The child-safe catalogue contains only tools offered by the parent
36that are also available in the resolved child runtime; parent-only scheduling
37and extension tools are never inherited. Names unavailable to the child
38(including host-only extensions) and tools denied by `subagents.allowed_tools`
39are omitted from an explicit list; they never grant the child additional
40access. `model`, `provider`, `thinking`,
41the prompt mode, project/skill inheritance, and `fastMode` are resolved before
42the child is accepted. Spawn-level model, provider, reasoning, and fast-mode
43values take precedence where supplied.
44
45Children are always fresh conversations: they receive the delegated task and
46resolved host/profile context, never the parent transcript or hidden reasoning.
47They cannot recursively create more children.
48
49## Lifecycle and persistence
50
51The manager records each accepted child under its managed state root:
52
53```text
54subagents/<child-id>/
55  transcript.jsonl  # authoritative accepted turns and finalized messages
56  owner.lock        # host-ownership coordination; do not modify or remove
57  .transcript-backup-* # retained private pre-repair transcript, when repaired
58  metadata.json     # rebuildable bounded state
59  result.json       # latest outcome, final summary, artifacts
60  patch.diff        # optional worktree capture
61```
62
63Acceptance is durable before `subagent_spawn` reports success. Finalized user,
64assistant, tool-call, and tool-result messages are journaled; streamed deltas
65and hidden reasoning are not exposed as ordinary history. A tool call is stored
66before execution and reconciliation repairs incomplete call/result pairs.
67
68All children stop when the host exits. On the next start, queued or running
69turns are marked `interrupted`; zut never replays their task. Resume only with
70an explicit new prompt through `subagent_resume`, the child-session composer,
71or `/subagents resume <id> <prompt>`.
72
73Multiple zut processes may share a state root. Each resident journal has one
74host owner at a time. A process that finds a child owned elsewhere reports it
75as such and does not inspect, recover, or modify its transcript. Resume that
76child from its owning host or after the owner exits. On a subsequent safe
77reconciliation, zut repairs only the known legacy false-recovery sequence; it
78leaves any ambiguous journal corruption untouched. A repair retains the
79pre-repair transcript as `.transcript-backup-*`; it can contain private session
80data and is intentionally not removed automatically.
81
82`subagent_status` reports `owned_elsewhere: true` when another process owns a
83child. The field is omitted when false. A foreign-owned child cannot be resumed,
84or have its history or result read, from this process.
85
86The global scheduler admits the oldest eligible accepted prompt, runs at most
87one turn for each child, and defaults to six concurrent turns. Set
88`subagents.max_concurrent` to a positive limit to override it. Queueing is
89unlimited by default; a positive `subagents.queue_timeout` cancels an accepted
90prompt that has not received a slot and records its terminal failure durably.
91`subagents.allowed_tools` is an allowlist for child-visible tools and
92`subagents.allowed_roots` limits eligible child workspaces. Resident children
93have no cumulative token budget. Execution stays bounded through a finite
94per-turn step default: a child whose parent resolution is unlimited runs with
95`MaxSteps=50`; an explicit parent limit is preserved. Removed legacy
96settings, including `tui_subagent_position` and `subagents.budget_ratio`, are
97ignored. Resident journals written by older versions are read with explicit
98translation (an old `budget_exhausted` outcome reconciles as failure) or, for
99unknown versions, left untouched on disk and excluded from automatic
100discovery. Incompatible journals cannot be resumed; start a new child
101instead. Other journal recovery errors are still reported.
102
103Compatibility notes: new journals write version 3 and carry no budget
104fields, baselines, or exhaustion states. Version 2 archives are read with
105explicit translation and their transcripts are never rewritten by
106translation. `result.json` keeps a deprecated `handoff` field that stays
107empty for new results and remains readable for archives. `subagent_status`
108no longer exposes `budget` or `budget_source` fields.
109
110### Context reminders
111
112When a child's last-turn prompt reaches 85% of its model context window, the
113runner injects one non-blocking reminder into the next provider request:
114
115```text
116Context usage is at NN% of the model window. Finish the current task, report
117results, limits, and remaining verifications, and do not start broad new work.
118```
119
120The reminder fires at most once per child runner and never blocks a turn.
121It travels as developer context in the live request; the durable transcript
122keeps only finalized history. Usage is the last-turn prompt size (input plus
123cache read/write tokens) against the resolved context window; an unknown
124window never triggers a reminder. The per-turn gauge resets when the host
125restarts, so a restarted child is reminded again only once fresh usage past
126the threshold arrives.
127
128Retrieve the saved result without executing a model:
129
130```json
131{"agent_id":"<child-id>","include_result":true}
132```
133
134Pass this to `subagent_status`, then reconcile the history and artifacts before
135repeating any side effects. Explicit `subagent_resume` after a terminal failure
136continues the retained session, workspace, and cumulative cost. It does not
137automatically retry the task. Ordinary follow-ups continue the existing
138session.
139
140`required: true` makes a delegated result an obligation of the parent turn.
141Failed, cancelled, and interrupted required work remains
142unresolved until an explicit successful follow-up. Reading a saved result or
143accepting a recovery prompt does not satisfy the obligation. A host restart never
144retries it automatically.
145
146## Delegation ownership
147
148Interactive proactive delegation keeps the primary agent on the critical path.
149Before spawning, it selects useful local work and delegates only a concrete,
150bounded sidecar with a non-overlapping question, responsibility, package, or
151file set. Immediate blockers and tightly coupled work stay local. While a child
152is active, it owns that scope; the primary continues only its preselected
153independent work instead of repeating the investigation, review, testing, or
154implementation. If an explicit user request or active workflow hands blocking
155work to a child, the primary yields for the completion update. Once a worktree
156child succeeds, the primary may apply and verify its captured patch without
157redoing the delegated task.
158
159Explicit headless `--orchestrate` remains manager-only. Its primary divides the
160request into disjoint worker scopes, coordinates active children, and yields
161rather than implementing or reproducing delegated work. Children do not inherit
162the parent's strict orchestrator role. Headless orchestration waits for every
163accepted child before continuing its completion wave; `required: true`
164additionally creates a durable obligation. When proactive
165interactive delegation cannot spawn because of launch-time policy, the primary
166continues locally; a strict headless orchestrator instead reports the missing
167required capability.
168
169## Tools and slash commands
170
171The model-facing tools retain their logical names:
172
173- `subagent_spawn` accepts `task`, optional `agent`, `model` and `provider`,
174  `reasoning`, `fast_mode`, `required`, `wait`, and `isolation` (`shared` or
175  `worktree`).
176  `wait` is an explicit whole-second value from 1 through 300; when omitted,
177  spawning returns immediately. A timed-out wait leaves the
178  accepted child active, whether it is queued or running. Do not retry that
179  task until it reaches a terminal failure, cancellation, or interruption. It
180  returns a logical `subagent://<id>` reference.
181- `subagent_status` returns bounded current state for one child or the current
182  set immediately. With `agent_id` and `include_result: true`, it also reads the
183  saved terminal result without model execution. Without this
184  option it remains metadata-only; foreign-owned results cannot be read.
185  Result-read errors distinguish foreign ownership, a missing saved result,
186  and permission denial without exposing filesystem paths or saved content.
187- `subagent_stop` stops one live child.
188- `subagent_resume` accepts an explicit follow-up prompt for an existing child.
189  After a terminal failure, inspect the saved result before resuming; resume
190  continues the retained session.
191
192Child execution started by `subagent_spawn` is asynchronous unless it receives
193an explicit `wait` value. For an unwaited spawn, completion arrives through the
194host’s typed completion update; `subagent_status` returns immediately and does
195not wait for completion. Do not use sleep loops, repeated status calls, journal
196files, or terminal UI inspection as a completion signal.
197In interactive mode, a result received while the primary is busy enters the
198visible **sliding in** queue and reaches the model at its next safe boundary,
199without interrupting a model request or tool call and without waiting for other
200children. Results already queued are not repeated when the parent turn ends.
201Undelivered results remain queued after a provider or compaction error for the
202next turn; they do not automatically retry the failed request. Explicit
203cancellation clears pending queue entries. The queue is in memory, while the
204child’s saved result remains available through `subagent_status`.
205When the primary is idle, remaining children are collected into one completion
206wave. Headless orchestration still waits for every accepted child before its
207next parent turn.
208Successful completions include the final visible assistant summary, capped at
209256 KiB; open the child session for the complete durable transcript.
210
211`/subagents` opens the resident-child list, ordered by the latest state change.
212Each row leads with the profile (or model), shows a human terminal state such
213as `completed`, a relative update time, and a short ID. Press Down from the
214main composer to open this list without clearing a draft when a child exists.
215Use arrows and Enter to open a child session; `/subagents new <task>` creates a child; `/subagents logs <id>`
216opens its history; `/subagents result <id>` shows the bounded final summary;
217`kill <id>` stops it; and `resume <id> <prompt>` continues it.
218
219The child session uses the same transcript renderer as the main session.
220Recent history is bounded and loaded asynchronously; PgUp asks for an older
221page. Up/Down preserves the current reading position, and PgDn returns to the
222live tail after unread updates accumulate. The screen combines durable finalized
223history with an immutable in-memory projection of the active turn. Enter submits
224the local composer only after the manager durably accepts it; Esc closes the session. History may contain task
225text, tool arguments, tool results, and source-derived output, so treat it as
226private local session data.
227
228## Worktrees and references
229
230Shared children use the host working directory. With `isolation: "worktree"`,
231zut prepares a detached Git worktree and captures a patch and changed-file list
232on successful completion or non-cancelled failure. Failed turns retain
233partial work in the worktree, along with any captured patch and changed-file
234list. zut never applies a captured patch automatically. Failed or interrupted
235worktrees are retained for inspection; an idle successful worktree is cleaned
236when its child is explicitly stopped.
237
238Use `subagent_status` with `agent_id` and `include_result: true` to retrieve the
239saved result, `changed_files`, and `patch_ref` when a patch was captured. The
240patch bytes are stored in `subagents/<child-id>/patch.diff` under the managed
241state root shown above; logical references are identifiers, not filesystem
242paths. Inspect the retained worktree and patch before resuming or applying
243partial changes.
244
245New terminal journal records also save the capture metadata, so reconciliation
246can restore it if `result.json` is missing or corrupt. Older records remain
247readable, but cannot reconstruct artifact metadata they never recorded.
248
249Logical references avoid exposing runtime paths:
250
251```text
252subagent://<id>
253subagent://<id>/history
254subagent://<id>/result
255subagent://<id>/patch
256```
257
258## Provider caching
259
260Each main and child conversation sends a stable logical session ID and a new
261turn ID per accepted prompt to the provider layer. Provider adapters decide
262whether and how to use them: OpenAI/Codex translates a supported stable session
263into its cache key and routing header, while other adapters preserve deterministic
264request input and use only cache controls their provider/model/endpoint supports.
265An OpenAI-compatible wire shape is not itself evidence that a cache extension
266or transport feature is available. Models continue through their declared
267provider transport; a transport change must not change the logical session or
268turn identity used by the provider request.

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