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, paths in
ZUT_AGENT_PROFILES, and the ~/.pi/agent/agents/*.md compatibility discovery
location. 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. 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. A spawn-level model, provider, reasoning, or fast-mode
override takes 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
metadata.json # rebuildable bounded state
result.json # latest state plus a bounded final assistant summary
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>.
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. Removed legacy
settings, including tui_subagent_position, are ignored.
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. A host restart never retries it automatically.
The model-facing tools retain their logical names:
subagent_spawn accepts task, optional agent, model and provider,
reasoning, fast_mode, required, and isolation (shared or
worktree). It returns a logical subagent://<id> reference.
subagent_status returns bounded state for one child or the current set.
subagent_stop stops one live child.
subagent_resume accepts an explicit follow-up prompt for an existing child.
These calls are asynchronous. Completion arrives through the host’s typed
completion update, not process polling. Do not use sleep loops, repeated
status calls, journal files, or terminal UI inspection as a completion signal.
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, captures a patch and changed-file list on
successful completion, and never applies that patch automatically. Failed or
interrupted worktrees are retained for inspection; an idle successful worktree
is cleaned when its child is explicitly stopped.
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`, paths in
15`ZUT_AGENT_PROFILES`, and the `~/.pi/agent/agents/*.md` compatibility discovery
16location. They are inputs only; zut does not execute them.
17
18```markdown
19---
20name: reviewer
21description: Read-only code reviewer
22tools: [read, grep]
23model: openai-codex/gpt-5.6-luna
24thinking: high
25systemPromptMode: replace
26inheritProjectContext: false
27inheritSkills: false
28fastMode: false
29---
30
31Inspect the requested scope and report evidence-backed findings.
32```
33
34`tools` is a capability boundary. An omitted value inherits the child-safe
35catalogue, `tools: []` grants no tools, and an explicit list replaces the
36default. Names unavailable to the child (including host-only extensions) and
37tools denied by `subagents.allowed_tools` are omitted from an explicit list;
38they never grant the child additional access. `model`, `provider`, `thinking`,
39the prompt mode, project/skill inheritance, and `fastMode` are resolved before
40the child is accepted. A spawn-level model, provider, reasoning, or fast-mode
41override takes precedence where supplied.
42
43Children are always fresh conversations: they receive the delegated task and
44resolved host/profile context, never the parent transcript or hidden reasoning.
45They cannot recursively create more children.
46
47## Lifecycle and persistence
48
49The manager records each accepted child under its managed state root:
50
51```text
52subagents/<child-id>/
53 transcript.jsonl # authoritative accepted turns and finalized messages
54 metadata.json # rebuildable bounded state
55 result.json # latest state plus a bounded final assistant summary
56 patch.diff # optional worktree capture
57```
58
59Acceptance is durable before `subagent_spawn` reports success. Finalized user,
60assistant, tool-call, and tool-result messages are journaled; streamed deltas
61and hidden reasoning are not exposed as ordinary history. A tool call is stored
62before execution and reconciliation repairs incomplete call/result pairs.
63
64All children stop when the host exits. On the next start, queued or running
65turns are marked `interrupted`; zut never replays their task. Resume only with
66an explicit new prompt through `subagent_resume`, the child-session composer,
67or `/subagents resume <id> <prompt>`.
68
69The global scheduler admits the oldest eligible accepted prompt, runs at most
70one turn for each child, and defaults to six concurrent turns. Set
71`subagents.max_concurrent` to a positive limit to override it. Queueing is
72unlimited by default; a positive `subagents.queue_timeout` cancels an accepted
73prompt that has not received a slot and records its terminal failure durably.
74`subagents.allowed_tools` is an allowlist for child-visible tools and
75`subagents.allowed_roots` limits eligible child workspaces. Removed legacy
76settings, including `tui_subagent_position`, are ignored.
77
78`required: true` makes a delegated result an obligation of the parent turn.
79Failed, cancelled, and interrupted required work remains unresolved until an
80explicit successful follow-up. A host restart never retries it automatically.
81
82## Tools and slash commands
83
84The model-facing tools retain their logical names:
85
86- `subagent_spawn` accepts `task`, optional `agent`, `model` and `provider`,
87 `reasoning`, `fast_mode`, `required`, and `isolation` (`shared` or
88 `worktree`). It returns a logical `subagent://<id>` reference.
89- `subagent_status` returns bounded state for one child or the current set.
90- `subagent_stop` stops one live child.
91- `subagent_resume` accepts an explicit follow-up prompt for an existing child.
92
93These calls are asynchronous. Completion arrives through the host’s typed
94completion update, not process polling. Do not use sleep loops, repeated
95status calls, journal files, or terminal UI inspection as a completion signal.
96Successful completions include the final visible assistant summary, capped at
97256 KiB; open the child session for the complete durable transcript.
98
99`/subagents` opens the resident-child list, ordered by the latest state change.
100Each row leads with the profile (or model), shows a human terminal state such
101as `completed`, a relative update time, and a short ID. Press Down from the
102main composer to open this list without clearing a draft when a child exists.
103Use arrows and Enter to open a child session; `/subagents new <task>` creates a child; `/subagents logs <id>`
104opens its history; `/subagents result <id>` shows the bounded final summary;
105`kill <id>` stops it; and `resume <id> <prompt>` continues it.
106
107The child session uses the same transcript renderer as the main session.
108Recent history is bounded and loaded asynchronously; PgUp asks for an older
109page. Up/Down preserves the current reading position, and PgDn returns to the
110live tail after unread updates accumulate. The screen combines durable finalized
111history with an immutable in-memory projection of the active turn. Enter submits
112the local composer only after the manager durably accepts it; Esc closes the session. History may contain task
113text, tool arguments, tool results, and source-derived output, so treat it as
114private local session data.
115
116## Worktrees and references
117
118Shared children use the host working directory. With `isolation: "worktree"`,
119zut prepares a detached Git worktree, captures a patch and changed-file list on
120successful completion, and never applies that patch automatically. Failed or
121interrupted worktrees are retained for inspection; an idle successful worktree
122is cleaned when its child is explicitly stopped.
123
124Logical references avoid exposing runtime paths:
125
126```text
127subagent://<id>
128subagent://<id>/history
129subagent://<id>/result
130subagent://<id>/patch
131```
132
133## Provider caching
134
135Each main and child conversation sends a stable logical session ID and a new
136turn ID per accepted prompt to the provider layer. Provider adapters decide
137whether and how to use them: OpenAI/Codex translates a supported stable session
138into its cache key and routing header, while other adapters preserve deterministic
139request input and use only cache controls their provider/model/endpoint supports.
140An OpenAI-compatible wire shape is not itself evidence that a cache extension
141or transport feature is available. Models continue through their declared
142provider transport; a transport change must not change the logical session or
143turn identity used by the provider request.