@zenera/cli 1.1.24 → 1.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +65 -0
  2. package/dist/ask.js +28 -5
  3. package/dist/banner.js +2 -2
  4. package/dist/batch.d.ts +6 -0
  5. package/dist/batch.js +76 -1
  6. package/dist/catalog.d.ts +31 -1
  7. package/dist/catalog.js +140 -7
  8. package/dist/commands/index.js +2 -0
  9. package/dist/commands/inspect.d.ts +52 -2
  10. package/dist/commands/inspect.js +220 -31
  11. package/dist/commands/memory.js +156 -32
  12. package/dist/commands/meta.js +333 -24
  13. package/dist/commands/models.js +97 -12
  14. package/dist/commands/open.js +4 -4
  15. package/dist/commands/run.js +38 -4
  16. package/dist/commands/sandbox.js +148 -16
  17. package/dist/commands/view.d.ts +8 -0
  18. package/dist/commands/view.js +114 -0
  19. package/dist/engine.d.ts +8 -1
  20. package/dist/engine.js +7 -0
  21. package/dist/eventlog.d.ts +64 -0
  22. package/dist/eventlog.js +170 -0
  23. package/dist/liveness.d.ts +7 -0
  24. package/dist/liveness.js +35 -3
  25. package/dist/main.js +0 -0
  26. package/dist/meta/editor.d.ts +9 -0
  27. package/dist/meta/editor.js +43 -0
  28. package/dist/meta/finetune/analyze-brief.d.ts +26 -0
  29. package/dist/meta/finetune/analyze-brief.js +131 -0
  30. package/dist/meta/finetune/apply-brief.d.ts +23 -0
  31. package/dist/meta/finetune/apply-brief.js +247 -0
  32. package/dist/meta/finetune/brief.d.ts +45 -0
  33. package/dist/meta/finetune/brief.js +158 -0
  34. package/dist/meta/finetune/children.d.ts +8 -0
  35. package/dist/meta/finetune/children.js +76 -0
  36. package/dist/meta/finetune/command.d.ts +30 -0
  37. package/dist/meta/finetune/command.js +516 -0
  38. package/dist/meta/finetune/cost.d.ts +46 -0
  39. package/dist/meta/finetune/cost.js +105 -0
  40. package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
  41. package/dist/meta/finetune/dataset/anchors.js +239 -0
  42. package/dist/meta/finetune/dataset/changes.d.ts +36 -0
  43. package/dist/meta/finetune/dataset/changes.js +319 -0
  44. package/dist/meta/finetune/dataset/command.d.ts +17 -0
  45. package/dist/meta/finetune/dataset/command.js +1011 -0
  46. package/dist/meta/finetune/dataset/drift.d.ts +33 -0
  47. package/dist/meta/finetune/dataset/drift.js +71 -0
  48. package/dist/meta/finetune/dataset/export.d.ts +26 -0
  49. package/dist/meta/finetune/dataset/export.js +51 -0
  50. package/dist/meta/finetune/dataset/index.d.ts +2 -0
  51. package/dist/meta/finetune/dataset/index.js +2 -0
  52. package/dist/meta/finetune/dataset/sample.d.ts +50 -0
  53. package/dist/meta/finetune/dataset/sample.js +197 -0
  54. package/dist/meta/finetune/dataset/schema.d.ts +33 -0
  55. package/dist/meta/finetune/dataset/schema.js +216 -0
  56. package/dist/meta/finetune/dataset/store.d.ts +35 -0
  57. package/dist/meta/finetune/dataset/store.js +177 -0
  58. package/dist/meta/finetune/dataset/types.d.ts +127 -0
  59. package/dist/meta/finetune/dataset/types.js +39 -0
  60. package/dist/meta/finetune/failure.d.ts +15 -0
  61. package/dist/meta/finetune/failure.js +26 -0
  62. package/dist/meta/finetune/feedback.d.ts +57 -0
  63. package/dist/meta/finetune/feedback.js +104 -0
  64. package/dist/meta/finetune/guard.d.ts +29 -0
  65. package/dist/meta/finetune/guard.js +104 -0
  66. package/dist/meta/finetune/improvements.d.ts +98 -0
  67. package/dist/meta/finetune/improvements.js +501 -0
  68. package/dist/meta/finetune/index.d.ts +2 -0
  69. package/dist/meta/finetune/index.js +2 -0
  70. package/dist/meta/finetune/journal.d.ts +35 -0
  71. package/dist/meta/finetune/journal.js +135 -0
  72. package/dist/meta/finetune/live.d.ts +84 -0
  73. package/dist/meta/finetune/live.js +272 -0
  74. package/dist/meta/finetune/loop.d.ts +3 -0
  75. package/dist/meta/finetune/loop.js +163 -0
  76. package/dist/meta/finetune/memories.d.ts +47 -0
  77. package/dist/meta/finetune/memories.js +154 -0
  78. package/dist/meta/finetune/recheck.d.ts +58 -0
  79. package/dist/meta/finetune/recheck.js +311 -0
  80. package/dist/meta/finetune/report.d.ts +40 -0
  81. package/dist/meta/finetune/report.js +1397 -0
  82. package/dist/meta/finetune/retry.d.ts +24 -0
  83. package/dist/meta/finetune/retry.js +96 -0
  84. package/dist/meta/finetune/sampler.d.ts +18 -0
  85. package/dist/meta/finetune/sampler.js +47 -0
  86. package/dist/meta/finetune/system.d.ts +27 -0
  87. package/dist/meta/finetune/system.js +132 -0
  88. package/dist/meta/finetune/train.d.ts +43 -0
  89. package/dist/meta/finetune/train.js +425 -0
  90. package/dist/meta/finetune/tui.d.ts +16 -0
  91. package/dist/meta/finetune/tui.js +316 -0
  92. package/dist/meta/finetune/tuning.d.ts +193 -0
  93. package/dist/meta/finetune/tuning.js +308 -0
  94. package/dist/meta/finetune/usage.d.ts +66 -0
  95. package/dist/meta/finetune/usage.js +260 -0
  96. package/dist/meta/finetune/view.d.ts +9 -0
  97. package/dist/meta/finetune/view.js +27 -0
  98. package/dist/meta/host.d.ts +15 -0
  99. package/dist/meta/host.js +21 -0
  100. package/dist/meta/index.d.ts +11 -0
  101. package/dist/meta/index.js +11 -0
  102. package/dist/meta/launch.d.ts +81 -0
  103. package/dist/meta/launch.js +286 -0
  104. package/dist/meta/model.d.ts +44 -0
  105. package/dist/meta/model.js +119 -0
  106. package/dist/meta/prompts.d.ts +18 -0
  107. package/dist/meta/prompts.js +61 -0
  108. package/dist/meta/relay.d.ts +20 -0
  109. package/dist/meta/relay.js +123 -0
  110. package/dist/meta/tokens.d.ts +52 -0
  111. package/dist/meta/tokens.js +226 -0
  112. package/dist/meta/window.d.ts +61 -0
  113. package/dist/meta/window.js +198 -0
  114. package/dist/meta/wire.d.ts +42 -0
  115. package/dist/meta/wire.js +129 -0
  116. package/dist/meta.d.ts +71 -1
  117. package/dist/meta.js +303 -6
  118. package/dist/modelref.d.ts +16 -0
  119. package/dist/modelref.js +41 -0
  120. package/dist/narrate.js +5 -2
  121. package/dist/podman.d.ts +26 -0
  122. package/dist/podman.js +83 -3
  123. package/dist/projects.d.ts +0 -5
  124. package/dist/projects.js +2 -15
  125. package/dist/resources.d.ts +215 -0
  126. package/dist/resources.js +856 -0
  127. package/dist/sandbox.d.ts +2 -0
  128. package/dist/sandbox.js +10 -3
  129. package/dist/scaffold.d.ts +15 -7
  130. package/dist/scaffold.js +24 -67
  131. package/dist/session.js +4 -29
  132. package/dist/term.d.ts +2 -0
  133. package/dist/term.js +11 -2
  134. package/dist/trace.d.ts +5 -0
  135. package/dist/trace.js +107 -7
  136. package/dist/tui/app.js +19 -5
  137. package/dist/tui/links.d.ts +27 -0
  138. package/dist/tui/links.js +142 -0
  139. package/dist/tui/models.d.ts +35 -0
  140. package/dist/tui/models.js +447 -0
  141. package/dist/tui/sandbox.d.ts +10 -0
  142. package/dist/tui/sandbox.js +131 -0
  143. package/dist/tui/wrap.d.ts +5 -0
  144. package/dist/tui/wrap.js +12 -0
  145. package/dist/usage.d.ts +78 -0
  146. package/dist/usage.js +51 -0
  147. package/package.json +4 -2
  148. package/templates/editor/.github/copilot-instructions.md +60 -145
  149. package/templates/editor/.github/prompts/analyze.prompt.md +33 -0
  150. package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
  151. package/templates/editor/.github/prompts/finetune-apply.prompt.md +270 -0
  152. package/templates/editor/.github/prompts/finetune.prompt.md +691 -198
  153. package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
  154. package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
  155. package/templates/editor/.github/prompts/project-review.prompt.md +5 -4
  156. package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +588 -0
  157. package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -1
  158. package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
  159. package/templates/editor/.github/skills/zen-cli/references/finetune.md +137 -0
  160. package/templates/editor/.github/skills/zen-cli/references/inspect.md +63 -11
  161. package/templates/editor/.github/skills/zen-cli/references/memory.md +33 -10
  162. package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
  163. package/templates/editor/.github/skills/zen-cli/references/models.md +5 -1
  164. package/templates/editor/.github/skills/zen-cli/references/projects.md +4 -6
  165. package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
  166. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +35 -14
  167. package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
  168. package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
  169. package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
  170. package/templates/editor/.github/skills/zen-finetune/SKILL.md +1492 -660
  171. package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
  172. package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
  173. package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
  174. package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
  175. package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
  176. package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
  177. package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
  178. package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
  179. package/templates/editor/.github/skills/zen-inspect/SKILL.md +74 -26
  180. package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +271 -0
  181. package/templates/editor/.github/skills/zen-instructions/SKILL.md +4 -12
  182. package/templates/editor/.github/skills/zen-memory/SKILL.md +82 -53
  183. package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
  184. package/templates/editor/.github/skills/zen-review/SKILL.md +8 -31
  185. package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -5
  186. package/templates/editor/.github/skills/zen-review/scripts/review.sh +3 -12
  187. package/templates/editor/.github/skills/zen-sandbox/SKILL.md +9 -4
  188. package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -2
  189. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +2 -4
  190. package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
  191. package/templates/editor/.vscode/settings.json +1 -0
  192. package/templates/project/agents/files-instructions.md +29 -20
  193. package/templates/project/agents/fork-instructions.md +78 -28
  194. package/templates/project/agents/memory-instructions.md +222 -494
  195. package/templates/project/agents/tools-instructions.md +14 -4
  196. package/templates/project/gitignore +2 -0
  197. package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +0 -432
  198. package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +0 -199
  199. package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +0 -116
@@ -0,0 +1,283 @@
1
+ ---
2
+ name: zen-topology
3
+ description: 'Use when designing, reviewing or auditing how a Zenera project divides work between agents - whether to hand off, fork one branch to delegate, fan out several branches, or keep the work in one conversation; which fork `context` to pick; what each choice costs in tokens, prompt cache and elapsed time; and how to read a recorded run for topology mistakes (missed fan-out, a forked sequence, an early or looping hand-off, a delegation that cost more than it saved). Load before adding or changing `handoffs:` or `fork:` in agents.yaml, before writing a prompt line that says when to delegate, and before grading Delegation or Forking in a run audit.'
4
+ ---
5
+
6
+ # Agent topology
7
+
8
+ Work moves between agents in exactly two ways, and both are tools the model
9
+ calls: a **hand-off** (`transfer_to_<name>`) gives the conversation away, a
10
+ **fork** (`fork`) sends work out and gets answers back. Everything else is one
11
+ agent working in its own conversation. Both are opt-in per agent in
12
+ `agents.yaml` - `handoffs:` and `fork:`, described key by key in §8.
13
+
14
+ Whether a second agent should exist at all is copilot-instructions §6.1 - this
15
+ skill starts once it does. The rules an agent reads at run time about forking
16
+ are zen's own `agents/fork-instructions.md`; this skill is for whoever designs
17
+ the project or judges a run against it, and never repeats that file's prose.
18
+
19
+ ## 1. The four shapes
20
+
21
+ | Shape | Control | The other side sees | Comes back | Use it when |
22
+ | -------------- | ---------------------------- | ---------------------------------------- | ----------------------------- | --------------------------------------------------------------------------- |
23
+ | Keep it here | stays | - | - | steps depend on each other, one call does it, or you want to steer the work |
24
+ | Hand-off | moves, and **stays moved** | the whole transcript | nothing, unless it hands back | another agent should own the conversation from now on |
25
+ | Fork, 1 branch | returns to the forking agent | what `context` gives it + its assignment | that branch's answer only | you want an answer from someone better suited, or to keep noise out |
26
+ | Fork, N | returns to the forking agent | the same, per branch | N answers in one tool result | N independent parts of one task, done at the same time |
27
+
28
+ ## 2. What a hand-off carries
29
+
30
+ When the model calls `transfer_to_<name>`, the kernel records a `handoff` node
31
+ (`from`, `to`, the optional `reason` argument), switches the current agent,
32
+ appends a fresh `system_prompt` for the target, and rebuilds the tool list for
33
+ it - its own tools, its hand-offs, its memory and skill tools, its `fork`.
34
+
35
+ - **The target sees the entire transcript**, every tool call and result the
36
+ previous agent made included. The runtime can collapse the outgoing agent's
37
+ turns with a hand-off policy, but `zen` sets none, so nothing is summarised.
38
+ Do not write a prompt that assumes the target starts clean.
39
+ - Only the newest system prompt is sent. The previous agent's role and house
40
+ rules are gone from the request; its words are not.
41
+ - The target's `description:` is the whole of what the caller reads when
42
+ deciding, so it is a routing condition, not a title.
43
+ - **Auto-recall fires again** for the target, with its own memory mask, against
44
+ the last user input - not against the `reason`.
45
+ - Preloaded skills are applied for the target; the outgoing agent's skill tools
46
+ are not the target's.
47
+ - **Nothing hands control back.** The target answers every later turn until it
48
+ hands off itself, which is why `zen check` warns `handoff.one-way` on any edge
49
+ with no path home.
50
+ - A memory commit is due from the agent that did the work, **before** its
51
+ hand-off. The target holds only the transcript of it - see **zen-memory**.
52
+
53
+ ## 3. What a fork carries
54
+
55
+ The model calls `fork` with `branches: [{name, instructions, agent?}]` and one
56
+ `context` for the whole call. The agent must declare `fork:`; `fork.agents`
57
+ reaches the model as an `enum`, and `fork.maxBranches` caps the array.
58
+
59
+ **What a branch starts from:**
60
+
61
+ | `context` | The branch begins with |
62
+ | ------------------- | --------------------------------------------------------------------------- |
63
+ | `inherit` (default) | the parent's visible history up to the fork call, then its assignment |
64
+ | `compact` | the same minus every `tool_call`, `tool_result` and `memory_recall` |
65
+ | `none` | nothing: its agent's system prompt, then its instructions as a user message |
66
+
67
+ Under `inherit` and `compact` the assignment arrives as the result of the
68
+ inherited `fork` call, opening `You are branch "<name>" of the fork above`,
69
+ naming its siblings. Skills another agent loaded are dropped from an inherited
70
+ prefix, so a branch never reads instructions for tools it does not hold.
71
+
72
+ **What comes back:** one tool result, holding each branch's final answer and
73
+ status in declared order, never completion order. The branch's own steps are
74
+ kept inside the `join` node for audit and are never shown to the parent. A
75
+ failed branch is a row with `status: error`, not a failed run.
76
+
77
+ **What outlives the branch:** files it wrote (branches share the workspace with
78
+ the parent and each other) and anything it committed to memory. Nothing else.
79
+
80
+ **Depth:** a branch may fork again while under the run's `maxForkDepth` (2 by
81
+ default). At the cap the `fork` tool is withdrawn and so is
82
+ `agents/fork-instructions.md`.
83
+
84
+ ## 4. What it costs - tokens, cache, time
85
+
86
+ A provider caches the longest **repeated prefix** of a request - tool schemas,
87
+ system prompt, then messages - and bills a cached token below an uncached one.
88
+ The runtime keeps that prefix still: house rules first, the role file second,
89
+ the tool array fixed for the agent's life, preloads at the head, auto-recall
90
+ only at the start of a turn. So the question for every shape is: **are the
91
+ first bytes the same as a request the provider has already seen?**
92
+
93
+ | Shape | Tokens sent | Prompt cache | Elapsed |
94
+ | ---------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------- |
95
+ | Keep it here | the transcript, growing every call | hits on all of it but the newest tail | the sum of the steps |
96
+ | Hand-off | the whole transcript, on every call the target makes | **misses on the target's first call** - new system prompt and tools, so nothing after them matches | serial |
97
+ | Hand-off back | the same | the original agent's prefix up to its hand-off may still hit, within the provider's cache lifetime | serial |
98
+ | Fork, `inherit`, same agent | per branch: the parent's history + brief + its own work | the inherited prefix is byte-identical up to the fork call, so it can hit | the slowest branch |
99
+ | Fork, `inherit`, other agent | the same | misses: a different system prompt, so the whole history is paid uncached, once per branch | the slowest branch |
100
+ | Fork, `compact` | less history: decisions without tool traffic | same agent: hits only up to the first dropped tool call; other agent: misses | the slowest branch |
101
+ | Fork, `none` | its agent's prompt + instructions + its own work | nothing to share with the parent; same-agent branches share the system prompt with each other | the slowest branch |
102
+ | The parent after a join | two messages more: the call and one result | unchanged - declared order makes the join deterministic | - |
103
+
104
+ What follows from the table:
105
+
106
+ - **A fan-out buys time, not tokens.** N branches together usually send more
107
+ than doing the N parts in series, because every branch pays its own start.
108
+ The saving is the elapsed time of all but the slowest branch, and the
109
+ parent's context staying N answers long instead of N transcripts.
110
+ - **A one-branch fork costs a whole conversation's start** to save the caller
111
+ some context. Worth it for a long, noisy job with a short verdict; a loss for
112
+ one read, one search or one command.
113
+ - **Agents passing the conversation back and forth pay a cache miss on every
114
+ switch**, plus a recall each time, on a transcript that only grows.
115
+ - **`inherit` versus `compact` is a trade, not a rule.** `compact` sends less;
116
+ `inherit` on the same agent can be served from cache. When most of the
117
+ history is tool traffic, `compact` wins; when it is mostly decided
118
+ conversation, `inherit` on the same agent can be cheaper. On a different
119
+ agent there is no cache to win, so the smaller prefix wins.
120
+ - **Cached tokens are not shown in the run graph.** `zen inspect`'s `tokens`
121
+ row and each `llm` node's `in` count cached tokens as input. Reason about the
122
+ cache from the structure above; never report a hit or a miss as measured.
123
+
124
+ ## 5. Choosing - in this order
125
+
126
+ Ask each question of the piece of work in front of you and stop at the first
127
+ yes.
128
+
129
+ 1. **Does any part need another part's result?** Keep that sequence here. A
130
+ branch cannot see its siblings, cannot ask, and cannot be steered.
131
+ 2. **Is it one call, or one call that takes a list?** Keep it here. Pass the
132
+ list.
133
+ 3. **Should another agent answer the user from now on** - over several turns,
134
+ on its own model or tools? Hand off, and make sure a path leads back.
135
+ 4. **Do you want an answer and then carry on?** Fork one branch on the agent
136
+ that suits the job. Never a hand-off: that spends the conversation to get
137
+ the answer.
138
+ 5. **Are there N independent parts?** Fork N branches - one per item, or one
139
+ per trade, each on the agent that fits.
140
+
141
+ Then pick `context`, cheapest first:
142
+
143
+ 1. `none`, when everything the branch needs can be written into its
144
+ instructions - paths included. Write it in and take `none`.
145
+ 2. `compact`, when it needs the plan and the decisions but not how they were
146
+ found, or when the branch runs a **different** agent.
147
+ 3. `inherit`, when it must see the work as it stands - reviewing what was just
148
+ written, continuing an investigation - and preferably on the **same** agent.
149
+
150
+ ## 6. Where each rule goes
151
+
152
+ | Rule | Goes in |
153
+ | ----------------------------------------------------------------- | ----------------------------------------------------------------- |
154
+ | who may hand off to whom; who may fork, to which agents, how wide | `agents.yaml` - `handoffs:`, `fork: { agents, maxBranches }` (§8) |
155
+ | what a hand-off target is for | `agents.yaml` - the target's `description:`, as a condition |
156
+ | **when** to fork or hand off, in this domain's terms | the deciding agent's prompt |
157
+ | which `context` this work wants | the deciding agent's prompt |
158
+ | what a branch must return, and in which file | the forking agent's prompt, so it writes it into `instructions` |
159
+ | which hand-off ends a specialist's turn | the specialist's prompt |
160
+ | a forking policy for the whole project | `agents/fork-<topic>-instructions.md` - load **zen-instructions** |
161
+
162
+ The domain-terms line is the one most often missing, and without it a weaker
163
+ model works through a list serially and never calls `fork`: _"When the request
164
+ covers more than one region, fork one branch per region with `context: none`,
165
+ and tell each branch to return the region, the total and the top three
166
+ findings."_
167
+
168
+ Never edit `agents/fork-instructions.md` - it is zen's copy, `zen check --fix`
169
+ replaces it, and an edit there is reported as `rules.stale`.
170
+
171
+ ## 7. Reading a run for topology
172
+
173
+ Where the topology shows in `zen inspect graph` (load **zen-inspect** for the
174
+ format):
175
+
176
+ - `%% agent <last> · started as <first>` - a hand-off happened.
177
+ - `@<agent>` on a node - the first node that agent owns.
178
+ - `handoff <from> to <to>` - open it for `reason`.
179
+ - `fork (<context> context) <branch>, <branch>` - the mode it chose.
180
+ - the branch subgraphs, one marked `slowest`, and `join <branch>=ok, ...`.
181
+ - `%% branches` - which join waited for which branches, with status.
182
+ - `%% tools` - `fork xN` and how many research calls ran around it.
183
+
184
+ | The graph shows | Finding | Fix goes in | Next run should show |
185
+ | ----------------------------------------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------- |
186
+ | research calls in series, none using an earlier result, `fork` in the agent's tools | missed fan-out | the agent's prompt: the domain trigger of §6 | one `fork` with a branch per item |
187
+ | the same, `fork` not in the agent's tools | missed fan-out | `agents.yaml`: `fork:` on that agent | the same |
188
+ | a branch's instructions name a sibling's result, or read a file a sibling writes | a sequence was forked | the forking agent's prompt | those steps in the trunk |
189
+ | a one-branch fork whose branch made one or two calls | delegation that cost more than it saved | the forking agent's prompt | the call made in the trunk |
190
+ | after the join, the parent repeats calls a branch already made | the branch was not told what to return | the forking agent's prompt: what each branch must return | no repeat after the join |
191
+ | a branch not `ok` | an assignment missing a fact it could not ask for | the forking agent's prompt | that branch `ok` |
192
+ | `slowest` far behind its siblings | an uneven division | the forking agent's prompt: split that part | branch durations close together |
193
+ | two branches with the same calls on the same subjects | overlap, paid for twice | the forking agent's prompt: divide by subject | disjoint subjects |
194
+ | a wide fan-out to **another** agent with `inherit` and a long history | the history paid uncached, once per branch | the forking agent's prompt: `compact` or `none` | `fork (compact context)` or `(none context)` |
195
+ | a `handoff` before the agent's own part was done | an early hand-off | the outgoing agent's prompt | its own calls, then the hand-off |
196
+ | `handoff` A to B, then B to A, then A to B | a loop - two prompts claim the same job | both prompts, so one owns it | one hand-off, or none |
197
+ | a hand-off for one question, then the target writes the final answer | wanted an answer, spent the conversation | the outgoing agent's prompt, and `fork:` in `agents.yaml` | a one-branch `fork` to that agent |
198
+ | a specialist exists in `agents.yaml`, and the agent did that job inline | the prompt never said when to delegate | the deciding agent's prompt | a `fork` or `handoff` to the specialist |
199
+
200
+ Price each finding honestly. A missed fan-out costs the elapsed time of every
201
+ branch but the slowest - not tokens, which a fork usually raises. A forked
202
+ sequence or an overlap costs the duplicated calls and their tokens. A
203
+ needless hand-off or one-branch fork costs one conversation's start, uncached.
204
+
205
+ To learn **why** the model chose the shape, ask the `llm` node that carries
206
+ `calls transfer_to_<name>` or `calls fork`, or the first call of a serial run -
207
+ load **zen-inspect-ask** for how to word it. First rule out the cheap causes:
208
+ `fork` not in that call's tools (depth cap, or no `fork:`),
209
+ `fork-instructions.md` not in its `system_prompt`, a specialist not in its
210
+ `enum`.
211
+
212
+ ## 8. The keys in `agents.yaml`
213
+
214
+ Both keys are per agent, and both only make a tool available. When the model
215
+ uses it is the prompt's business (§6).
216
+
217
+ ### `handoffs:`
218
+
219
+ ```yaml
220
+ agents:
221
+ - name: intake
222
+ description: Takes the first message and routes the case to the right desk.
223
+ handoffs: [billing, technical]
224
+ - name: billing
225
+ description: Answers invoice and refund questions from the written policy.
226
+ handoffs: [intake] # the way home
227
+ - name: technical
228
+ description: Diagnoses faults from the logs and says what to do next.
229
+ handoffs: [intake]
230
+ ```
231
+
232
+ - A list of bare agent names. There is no object form and no per-edge
233
+ configuration.
234
+ - Each name becomes one tool on this agent, `transfer_to_<name>`, described by
235
+ the **target's** `description:`. With none, the model gets a generic sentence
236
+ and `zen check` warns `agent.no-description`. Write it as a routing
237
+ condition, not a title: _"Applies the written peril policies to a claim and
238
+ explains the outcome"_, never _"The adjuster agent"_.
239
+ - `handoff.unknown` (an agent not declared) and `handoff.self` are load errors.
240
+ - `handoff.one-way` is a warning: an edge `A → B` with no path from B back to
241
+ A. Indirect counts - `B → C → A` is a way home - so every edge must lie on a
242
+ cycle. Without one, the first routed question is the last one routed.
243
+
244
+ ### `fork:`
245
+
246
+ ```yaml
247
+ agents:
248
+ - name: trunk
249
+ fork: true # any declared agent, any number of branches
250
+
251
+ - name: sweep
252
+ fork:
253
+ agents: [sweep, prober] # who a branch may run - itself included
254
+ maxBranches: 6
255
+
256
+ - name: asker
257
+ fork: { agents: [prober], maxBranches: 1 } # delegation, never a fan-out
258
+ ```
259
+
260
+ | Written | Means |
261
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------- |
262
+ | absent, or `false` | no `fork` tool, and `agents/fork-instructions.md` never reaches this agent |
263
+ | `true`, or `{}` | the tool, any declared agent, no cap |
264
+ | `agents: [a, b]` | a branch may run only these. The list is an `enum` on each branch's `agent` field, so another name cannot be decoded |
265
+ | `maxBranches: n` | at most `n` branches per call. `1` allows delegation and refuses fan-out |
266
+
267
+ - `agents` **may name the forking agent itself** - one role fanned out over
268
+ many items is the common shape, and unlike `handoffs:` it is not an error.
269
+ - A branch that leaves `agent` out runs the forking agent - but only when the
270
+ forking agent is in `agents`. When it is not, the model must name one.
271
+ - **A branch runs as its agent**: that agent's prompt, tools, memory binding,
272
+ skills, hand-offs and its own `fork:`. A hand-off inside a branch moves the
273
+ branch's conversation, never the parent's.
274
+ - Depth is not a key here. `maxForkDepth` (2 by default) is a run option; at
275
+ the cap the `fork` tool is withdrawn, and `agents/fork-instructions.md` with
276
+ it.
277
+ - Refused at load: `agents: []`, `maxBranches: 0`, and an `agents` entry not
278
+ declared (`fork.unknown`).
279
+ - `fork.uninstructed` is an error: an agent can fork and
280
+ `agents/fork-instructions.md` is missing or empty. `zen check --fix` writes it
281
+ back. That file is zen's - an edit in it is reported as `rules.stale` and lost
282
+ at the next `--fix`; project policy on forking goes in
283
+ `agents/fork-<topic>-instructions.md` (load **zen-instructions**).
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "chat.useNestedAgentsMdFiles": false,
3
+ "chat.agent.maxRequests": 250,
3
4
  "terminal.integrated.tabs.description": "Agent",
4
5
  "yaml.schemas": {
5
6
  "./.vscode/agents.schema.json": [
@@ -16,23 +16,35 @@ Check which tools you actually have:
16
16
  - If `write_file` and `apply_patch` are available, you may create and edit files
17
17
  under `/workspace`.
18
18
 
19
- ## Discovery before assumption
19
+ ## Finding files
20
20
 
21
- Never guess a file's name, location, or contents.
21
+ Never guess a file's name, location, or contents. Pick the tool by what you know:
22
22
 
23
- - Use `list_dir` to see directory contents and formats before opening files.
24
- - Use `find_files` to locate files by substring when the layout is unfamiliar.
25
- - Check whether a target file already exists before writing to it.
23
+ - **The directory** → `list_dir { path }`. One level, not recursive. Each file shows
24
+ `format`, `bytes` and, for text, `lines`, so you can decide what to read and how much
25
+ without opening it. Omit `path` (or give `/`) to list the mounted trees.
26
+ - **Part of the path** → `find_files { pattern, path? }`. `pattern` is **required**: a
27
+ plain, case-insensitive substring, never a glob or regex (`*.ts` matches nothing; write
28
+ `.ts`). It is matched against the path with its mount name (`/workspace`, `/assets`, …)
29
+ removed: `/workspace/src/a.ts` is matched as `src/a.ts`, so `src/` matches and
30
+ `/workspace/src` does not. To limit the search to one tree, pass it as `path`. Matches
31
+ come back as absolute paths.
32
+ - **Neither** → `list_dir` the root, then descend.
33
+
34
+ `find_files` matches paths, not contents. Both tools stop at 500 results and set
35
+ `truncated`: narrow the `pattern` or `path` rather than repeating the call.
26
36
 
27
37
  ## Reading files
28
38
 
29
- - Use `read_file` to read text files.
30
- - For files longer than a few dozen lines, pass `start_line` and `end_line` (1-based, inclusive)
31
- to read only the relevant section.
32
- - When `read_file` returns `truncated: true`, the read hit the size limit or range boundary.
33
- Resume reading from `end_line + 1` if you need the remainder.
34
- - Non-text files (images, binaries, archives) cannot be read as text; `list_dir` reports
35
- their format.
39
+ - `read_file { path, start_line?, end_line? }`; lines are 1-based and inclusive. Read a
40
+ short file whole; for a long one (see `lines` from `list_dir`), read the range you need.
41
+ - The result gives the file's total `lines` and the `start_line`/`end_line` returned.
42
+ `truncated: true` means more follows `end_line` (your range or the 256 KB cap); continue
43
+ from `end_line + 1` only if you need it.
44
+ - A non-text file fails with its `format`. Do not retry; `copy_file` can still copy it.
45
+ - Check whether a target exists before writing to it.
46
+
47
+ When a tool returns `error` with a `hint`, act on the hint instead of repeating the call.
36
48
 
37
49
  ## Modifying files
38
50
 
@@ -71,14 +83,11 @@ Never use `write_file` to update an existing file when only a few lines need to
71
83
 
72
84
  ### Copying: `copy_file`
73
85
 
74
- Use `copy_file` to duplicate a file rather than reading it and writing it back out.
75
- The bytes go straight from one path to the other without passing through the
76
- conversation, so the size cap on `read_file` does not apply and a binary arrives
77
- intact.
86
+ Use `copy_file` to duplicate a file, never `read_file` + `write_file`. The bytes skip the
87
+ conversation, so there is no size cap and binaries arrive intact.
78
88
 
79
- - The source may be in a read-only mount; only the destination has to be writable.
80
- This is how something under `/assets`, `/skills` or `/memory` is brought into
81
- `/workspace`.
89
+ - The source may be in a read-only mount; only the destination must be writable.
90
+ This is how something under `/assets`, `/skills` or `/memory` reaches `/workspace`.
82
91
  - Set `overwrite: true` only when intentionally replacing an existing destination.
83
92
  - Copying a directory and its contents requires `recursive: true`.
84
93
 
@@ -96,4 +105,4 @@ All file operations are confined to mounted trees:
96
105
  (such as `/workspace/src/main.ts`) are where project files reside.
97
106
  - `/assets`, `/skills`, `/memory`: Read-only mounts. You may read, list, and search them,
98
107
  but you cannot write, move, or delete files inside them.
99
- - Any attempt to reach outside these mounts fails with an containment error.
108
+ - Any attempt to reach outside these mounts fails with a containment error.
@@ -45,34 +45,31 @@ Every `fork` call takes an array under `branches`, even for a single branch:
45
45
  Never pass branch fields (`name`, `instructions`, `agent`) at the top level of
46
46
  the tool call.
47
47
 
48
- Do not fork a sequence. Branches run at once and can exchange nothing, so a step
49
- that needs the step before it has to stay in this conversation.
50
-
51
48
  ## When the assignment is yours
52
49
 
53
50
  These rules reach a branch as well as the agent that forked it, and a branch
54
- arrives in the middle of someone else's sentence. Your assignment comes to you
55
- as the result of a `fork` call, because that is how the runtime delivers it —
56
- and that is indistinguishable, in a transcript, from a fork you made yourself
57
- coming back with an answer.
51
+ arrives in the middle of someone else's sentence. Under `inherit` or `compact`
52
+ your assignment comes to you as the result of a `fork` call, because that is how
53
+ the runtime delivers it — and that is indistinguishable, in a transcript, from a
54
+ fork you made yourself coming back with an answer.
58
55
 
59
56
  It is not one. When a message begins "You are branch ... of the fork above", you
60
- are that branch and that text is your assignment:
57
+ are that branch and that text is your assignment. Under `none` there is no such
58
+ message, only the instructions as the first message of the conversation; when
59
+ they say you are a branch, the same holds:
61
60
 
62
61
  - **Nothing has run yet.** There is no result in it and nothing to verify. The
63
62
  fork it names is above in the conversation you were forked out of, which is
64
63
  not the one you are in — yours begins with that message.
65
- - **Do the work yourself.** Never fork a branch to carry out the assignment you
66
- were handed: that branch is you one level down holding the same instructions,
64
+ - **Do the work yourself.** Never fork one branch holding your whole
65
+ assignment: that branch is you one level down holding the same instructions,
67
66
  it will read them the same way, and each level spends a whole system prompt to
68
67
  arrive back where it started. At the depth cap the tool is withdrawn and the
69
- work comes back undone.
68
+ work comes back undone. If the assignment names two or more independent
69
+ deliverables, fork one branch for each, or do them all yourself.
70
70
  - **Do not go looking for proof it was already done.** An empty workspace is
71
71
  what an unstarted job looks like, not a sign that something failed upstream.
72
72
 
73
- Fork from inside a branch only for work that is genuinely divisible further and
74
- that you were not handed already divided.
75
-
76
73
  ## When it is worth it
77
74
 
78
75
  One question decides it: **could this be finished by someone who cannot ask you
@@ -82,7 +79,7 @@ no, the work stays here.
82
79
  | The work in front of you | What it is |
83
80
  | -------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
84
81
  | The same question asked of twenty things — files, endpoints, regions, candidate fixes | A fan-out: one branch each, merged by you |
85
- | One task whose parts need different skills and none of them the others | A fan-out too: each branch on the agent that fits |
82
+ | One task whose parts need different skills and no part needs another's result to start | A fan-out too: each branch on the agent that fits |
86
83
  | A job another agent is plainly better at | Delegation: one branch, on that agent |
87
84
  | Long and noisy with a short verdict — a build loop, a bisect, a survey that may find nothing | Delegation: you get the verdict, not the noise |
88
85
  | Find the config, then change it, then test it | Not a fork. Each step needs the one before it |
@@ -92,6 +89,36 @@ no, the work stays here.
92
89
  | The assignment you were handed, whole | Not a fork. It is yours — see above |
93
90
  | Two jobs that would write the same file | Not a fork until they write different files — see below |
94
91
 
92
+ Do not fork a sequence. Branches run at once and can exchange nothing, so a step
93
+ that needs the step before it has to stay in this conversation. A step depends
94
+ on another only when it cannot be _written_ without that result. When that
95
+ result can only be one of a few values known in advance, it is not a
96
+ dependency: fork the step now for all of them, have it return its result keyed
97
+ by value, and keep the one that applies after the join.
98
+
99
+ Before a one-branch `fork`, list what the request asks you to hand back. If two
100
+ or more of those items are independent — none needs another's result, and each
101
+ takes more than one call — give each its own branch in the same call.
102
+
103
+ ## Hand-off or fork
104
+
105
+ Both reach another agent; they differ in who holds the conversation afterwards.
106
+
107
+ | | `transfer_to_<agent>` | `fork` |
108
+ | ----------------- | --------------------------------------------------------------------- | -------------------------------------------------- |
109
+ | Control | moves to the other agent and stays there; it answers every later turn | comes back to you at the join |
110
+ | What it sees | this whole conversation, every tool result included | what `context` gives it, plus your instructions |
111
+ | What you get back | nothing; you are done | its final message |
112
+ | Parallel | no, one agent at a time | yes, one branch per part |
113
+ | Cost | the whole transcript on every call it makes from now on; no merge | each branch's own context, plus your turn to merge |
114
+
115
+ Hand off when the rest of the conversation belongs to the other agent: the
116
+ user's next question will be in its domain too, and you have nothing to add to
117
+ its answer. Fork when you need the result back — to combine it with other parts,
118
+ check it, or keep the conversation yourself. A request with two or more
119
+ independent deliverables is a fork, even when one agent could do all of them: a
120
+ hand-off cannot fan out and cannot come back.
121
+
95
122
  ## Fanning out
96
123
 
97
124
  Branches run at the same time, so a fan-out costs about as long as its slowest
@@ -139,30 +166,54 @@ whatever that branch needs, because a sibling's finding will never reach it.
139
166
  ## Choosing `context`
140
167
 
141
168
  `context` decides what each branch starts from. It is one setting for the whole
142
- call, chosen per call:
169
+ call, chosen per call; leave it out and you get `inherit`, the most expensive:
143
170
 
144
171
  - `inherit` — everything said here so far. For work that only makes sense
145
172
  against the case as it stands: reviewing what has just been written here,
146
173
  continuing an investigation whose earlier findings are the thing being built
147
174
  on.
148
- - `compact` — the same, without the tool traffic: what was decided, not how it
149
- was found out. The usual choice for a wide fan-out, where branches need the
150
- case and the plan but not the fifty reads that produced them.
175
+ - `compact` — the same, without tool calls, tool results or memory recalls:
176
+ what was decided, not how it was found out. The usual choice for a wide
177
+ fan-out, where branches need the case and the plan but not the fifty reads
178
+ that produced them.
151
179
  - `none` — nothing but its own instructions. The cheapest, and the honest one
152
180
  when the assignment is self-contained: a lookup, one file summarised, a
153
181
  command run elsewhere. Everything the branch needs must then be written out in
154
182
  the instructions, paths included.
155
183
 
156
- When two modes seem possible, write the missing facts into the instructions and
157
- take the cheaper one. Instructions are exact; an inherited transcript is only
158
- approximately about the branch's job.
184
+ | What the branch starts with | `inherit` | `compact` | `none` |
185
+ | -------------------------------------------------- | ------------------------------------ | --------- | ------------------------------------------- |
186
+ | Its own agent's system prompt and tools | yes | yes | yes |
187
+ | The user's request and the messages here | yes | yes | no |
188
+ | Tool calls, tool results, memory recalls | yes | no | no |
189
+ | Results of earlier forks | yes | yes | no |
190
+ | Skills loaded here | only if it runs on your agent | the same | no |
191
+ | Your whole `fork` call, siblings' instructions too | yes | yes | no |
192
+ | A fresh memory recall on its instructions | no | no | if its agent recalls automatically |
193
+ | How its assignment arrives | "You are branch ...", siblings named | the same | your instructions alone, as a plain message |
194
+
195
+ A `none` branch is never told it is a branch. Its instructions must say so, what
196
+ to return, and that only its final message comes back.
197
+
198
+ When two modes seem possible, or branches would each want a different one, write
199
+ the missing facts into the instructions and take the cheaper one. Instructions
200
+ are exact; an inherited transcript is only approximately about the branch's job.
201
+
202
+ Under `inherit` or `compact` a branch sees the user's whole request and will
203
+ take all of it as its own. When it gets only part, its instructions must name
204
+ the parts it does not own.
159
205
 
160
206
  ## What comes back, and what stays
161
207
 
162
- Only the answer comes back, and it is prose. Everything else a branch does is
163
- real and outlasts it: branches share this workspace with you and with each
164
- other, so a file one of them writes is a file you can read after the join, and
165
- anything committed to memory is there for every later run.
208
+ Everything a branch does besides its answer is real and outlasts it: branches
209
+ share this workspace with you and with each other, so a file one of them writes
210
+ is a file you can read after the join, and anything committed to memory is there
211
+ for every later run.
212
+
213
+ The join is one result for your `fork` call: a `### name (status)` block per
214
+ branch, in the order you declared them, each holding that branch's last message
215
+ or, if it failed, its error. Anything a branch said before its last message is
216
+ not in it.
166
217
 
167
218
  So decide, for each branch, which of the two carries its result:
168
219
 
@@ -187,8 +238,7 @@ builds, two branches reformatting the same tree.
187
238
 
188
239
  ## When a branch comes back wrong
189
240
 
190
- Each branch reports under its own name, with its status, and a failed one says
191
- why. What the final answer is remains your decision, not the join's.
241
+ What the final answer is remains your decision, not the join's.
192
242
 
193
243
  A branch rarely fails at random; the usual cause is an assignment missing
194
244
  something it could not ask for. Re-running the same instructions gets the same