@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
@@ -31,6 +31,8 @@ zen import <file.zip> [dir] [--name <name>] [--force] [--no-register]
31
31
  zen sandbox [status|up|pull|clean|disk] [options]
32
32
  zen version
33
33
 
34
+ zen meta <run|prompts|resume|model|dataset> [project] [args]
35
+
34
36
  zen faker <serve|build|cache> [spec...]
35
37
  zen rag schema <index|restore|ready|search|list|grep|trace|show|stats> [spec...]
36
38
  zen rag docs <index|restore|ready|search|list|grep|show|stats> [path...]
@@ -55,6 +57,9 @@ guess a flag, and do not read them all.
55
57
  | Run reports, trajectories, what a session directory holds | [inspect.md](./references/inspect.md) |
56
58
  | Reading a run yourself: the node graph, opening a node by id | [inspect.md](./references/inspect.md) (and `zen-inspect` skill) |
57
59
  | What the agents remember, why something was recalled, forgetting | [memory.md](./references/memory.md) |
60
+ | The meta agent: `zen meta run`, stored prompts, its `--json` object | [meta.md](./references/meta.md) |
61
+ | The evaluation dataset: cases, drift, notes, drawing a sample | [dataset.md](./references/dataset.md) (and `zen-dataset` skill) |
62
+ | Tuning the prose on the dataset: workers, applies, STATUS.md | [finetune.md](./references/finetune.md) |
58
63
  | Sharing a project: archives, what travels, importing one safely | [export.md](./references/export.md) |
59
64
  | `zen faker` - a mock API from an OpenAPI/Swagger document | [faker.md](./references/faker.md) |
60
65
  | `zen rag` - searching an API description, or a pile of markdown | [rag.md](./references/rag.md) |
@@ -76,6 +81,7 @@ zen import a.zip unpack one somebody sent, run nothing in i
76
81
  zen key ls --check which credentials still work
77
82
  zen models test <ref> whether one model actually answers
78
83
  zen models pick --embedding the first embedder that does, on stdout
84
+ zen meta run acme /analyze --json > analyze.json a stored prompt, the result as JSON
79
85
  ```
80
86
 
81
87
  ## Searching documents without help
@@ -92,11 +98,13 @@ zen rag docs search -d <index-dir> "<question in natural language>"
92
98
  zen rag docs search -d <index-dir> --file "<path-pattern>" --section "<heading>" "<question>"
93
99
  zen rag docs grep -d <index-dir> "<exact string>" --file "<path-pattern>"
94
100
  zen rag docs show -d <index-dir> "<file>" --section "<heading>"
101
+ zen rag docs show -d <index-dir> "<doc-1>:<a>-<b>" "<doc-2>#<heading>" # several in one call
95
102
  ```
96
103
 
97
104
  Start with one ordinary hybrid question. It is the best default for concepts and
98
105
  open questions. Search returns candidates, not proof: read the quoted lines,
99
- then use `show` or `grep` before claiming a fact is present or absent.
106
+ then use `show` or `grep` before claiming a fact is present or absent. Read
107
+ every passage you will cite with ONE `show` naming them all, not one call each.
100
108
 
101
109
  When the first answer is from the wrong product area, version, file, or heading,
102
110
  ask the same question again with `--file` and then `--section`. A bare `--file`
@@ -0,0 +1,34 @@
1
+ # `zen meta dataset` - the cases a project is evaluated on
2
+
3
+ The project's dataset lives in `dataset/` and only this command writes it. The
4
+ rules for reading cases out of a source, anchors, drift and sampling are in the
5
+ **zen-dataset** skill; this page is the command surface.
6
+
7
+ ```sh
8
+ zen meta dataset [status] # revision, counts, drift summary
9
+ zen meta dataset ls [filters] # one row per case
10
+ zen meta dataset show <id>[@rev]... # whole cases, now or at a revision
11
+ zen meta dataset log [id...] # changes and notes, with their sessions
12
+ zen meta dataset drift [--all] # cases whose source section moved
13
+ zen meta dataset apply <file> --why "…" # write a proposal; --partial, --dry-run
14
+ zen meta dataset update <id> --why "…" # --set k=v, --rubric-add/-edit/-drop, --tag-add/-drop, --override
15
+ zen meta dataset retire|restore <id>... --why "…"
16
+ zen meta dataset reanchor <id> --why "…" # --file, --heading "A > B", --pointer /x/0
17
+ zen meta dataset ignore <file> --why "…" # --heading or --pointer; --drop to undo
18
+ zen meta dataset note <id>... -m "…" # --kind, --run, --verdict, --rubric r1=pass,...
19
+ zen meta dataset sample [filters] # -n, --seed, --by, --weight, --order, --format, -o
20
+ zen meta dataset export [id...] [filters] # --format cases|batch, -o
21
+ ```
22
+
23
+ - The project is the one you are in, `--project <name|dir>`, or
24
+ `zen meta <project> dataset …`.
25
+ - Every verb takes the global `--json`. `sample --format json` is the record
26
+ that reproduces a draw.
27
+ - Writes take `dataset/.lock` and need `--why`. Reads and notes take no lock.
28
+ - `sample --format batch -o <file>` is `zen run batch` input, never with a
29
+ rubric. Media paths are written relative to `-o`.
30
+ - Exit codes: 2 for a wrong invocation (an unknown verb, flag or class),
31
+ 3 for a proposal or anchor that cannot be applied - and then nothing is written.
32
+ - Changes and notes are stamped with the `zen meta` session and prompt that ran
33
+ them (`ZENERA_META_SESSION`, `ZENERA_META_PROMPT`); `log` prints how to
34
+ resume each session this machine still holds.
@@ -0,0 +1,137 @@
1
+ # `zen meta finetune` - tuning the project, one case at a time
2
+
3
+ Trains the project's prose - prompts, skills, house rules - on every case of
4
+ its dataset (`zen meta dataset`). Nothing here touches model weights.
5
+
6
+ ```sh
7
+ zen meta finetune start [-N 4] [-M 4] [--tries 4] [--mem-tries 3] [--merge-every 3] [--seed 1] \
8
+ [--recheck 3] [--budget 1500] [--max-growth 50] \
9
+ [--skill-cap 12000] [--max-skills 10] \
10
+ [--class <c>] [--id <glob>] [--rubric yes|no] [--limit <n>] [--more <n>] [--force]
11
+ zen meta finetune [status]
12
+ zen meta finetune stop
13
+ zen meta finetune session <case>
14
+ zen meta finetune gate <apply dir> # would this apply pass? run by the apply agent
15
+ ```
16
+
17
+ ## What one case goes through
18
+
19
+ ```
20
+ without memory, up to --tries times:
21
+ zen run (empty memory) -> /analyze -> done? go on : park until the next apply
22
+ with memory, up to --mem-tries times, from the memory the passing run wrote:
23
+ zen run -> /analyze -> done? completed : park until the next apply
24
+ tries used up -> difficult
25
+ ```
26
+
27
+ - **N workers**, each training one case at a time. Cases come in the dataset's
28
+ own order: classes taking turns, cases with a rubric first, then seeded
29
+ random. Cases added to the dataset are picked up as it goes.
30
+ - **A parked case gives its worker back**, so another case runs while it waits
31
+ for an apply; once woken, it takes a worker before any new case does.
32
+ - **Applies are batched.** Parked cases' improvement requests are applied
33
+ together by `/finetune-apply` once **M** cases are parked, or once nothing is
34
+ running and no case is left to start. `-M` is at least 2 (`-M 1` needs
35
+ `--force`): one case is an anecdote. No run starts during an apply; runs in
36
+ flight finish first. Each apply gets its own `applies/<NNN>/APPLY.md`: every
37
+ request and improvement, what was decided for each, the apply agent's account
38
+ of what it changed and why, every file changed with its diff, and the gates.
39
+ - **An apply passes two gates, or is undone.** `zen check` must pass. What
40
+ every call reads - house rules, prompts, preloaded skills, the skill index,
41
+ summed over the agents - may grow by at most `--budget` bytes, and by nothing
42
+ once it is `--max-growth` percent over the start; no skill may pass
43
+ `--skill-cap` and no agent see more than `--max-skills`. A failed gate undoes
44
+ the edit and the agent tries once more, told why. A second `zen check`
45
+ failure stops the tuning; a second budget failure only undoes the apply, and
46
+ the parked cases carry on on the prose they had. `gate <apply dir>` runs both
47
+ gates on an apply in progress, against the same numbers, so the agent can cut
48
+ before it finishes.
49
+ - **An apply tidies up after itself.** Every file it touches loses its
50
+ duplicates, contradictions and stacked exceptions in the same edit; the
51
+ bytes that frees count against its budget. `growth.json` tells it which
52
+ files grew most since the tuning began.
53
+ - **Then `--recheck` completed cases run again on the new version** - without
54
+ memory, as ordinary work on a worker, ahead of new cases; nothing waits for
55
+ them. One that fails both of its two tries has regressed: its feedback
56
+ (`<case>@recheck-<apply>`) joins the improvement queue, the next apply
57
+ repairs it, and the case is rechecked first after that. Nothing is undone.
58
+ A case sends at most two such requests; after that a regression is only
59
+ reported, so the tuning ends.
60
+ - **One case adds nothing.** A new rule, or a procedure moved into a skill,
61
+ needs two cases asking for it. With one, the apply may only edit, move or
62
+ delete without growing the prose; anything else is `deferred` and offered to
63
+ every later apply (`deferred.json`) until a second case asks.
64
+ - **Prose cannot fix everything.** When all an apply could say of a request is
65
+ `structural` - a tool, a skill binding, the dataset - the case is difficult
66
+ at once, reason `structural: ...`, instead of trying again on the same prose.
67
+ - **A broken rubric is the dataset's to fix.** The analysis grades a line
68
+ `invalid` when it says how one implementation did it rather than what is
69
+ right, with a `specification` improvement saying how it should read. No
70
+ apply sees those, an `invalid` line never keeps a case from completing, and
71
+ a case whose only findings are `specification` is difficult at once, reason
72
+ `specification: ...`. STATUS.md lists them under **Rubric problems**.
73
+ - **A skill must be loaded.** When an apply makes or changes a skill for a
74
+ case, the case's next run must load it. If it does not, the run says so
75
+ (`missedSkills`), the analysis is told (`missed-skills=`), and the next apply
76
+ fixes the skill's description.
77
+ - **No run shares a memory.** Every try runs on its own private directory:
78
+ empty without memory, a copy of the case's passing memory with it. A case
79
+ whose with-memory run passes keeps a copy in `memories/submitted/`; every
80
+ `--merge-every` kept memories are merged, with the last merge, into
81
+ `memories/merged/mNN/` - numbered, never rewritten, each listing the cases it
82
+ holds. Whatever is left is merged when the tuning ends.
83
+ - **Each analysis starts from a brief.** The loop runs what every analysis
84
+ reads - the case, the graph, the run's files, the prose, the earlier tries
85
+ and the diff since the last one - writes it to the try's `brief.md`, and
86
+ hands it to `/analyze` in the prompt (`zen meta run --prompt-file`). Each try
87
+ is analyzed in a session of its own; `session <case>` prints the command to
88
+ resume the latest one.
89
+ - **So does each apply.** Its `brief.md` holds the requests and held-back
90
+ improvements grouped by the file they name, the editor skills to load, the
91
+ earlier tries of the same cases with their decisions, the budget, and the
92
+ files to edit. An attempt that ends without a decision for every
93
+ improvement is undone (`missing.md`) and tried once more.
94
+ - **Stop and resume freely.** `stop` (or Ctrl-C once) lets the steps in flight
95
+ finish, then exits; Ctrl-C twice kills them. `start` again carries on: every
96
+ step's result is on disk, and nothing finished is repeated.
97
+ - **`--limit` and `--more` are for one start**, never kept in `loop.json`.
98
+ `--limit <n>` cuts the order to its first n cases: once those have a result,
99
+ that start ends. `--more <n>` takes at most n cases of any kind - new,
100
+ part-way or failed - in the order, so `start --more 4` again takes the next
101
+ four.
102
+ - `start` refuses a dataset that has drifted from its sources - run `/dataset`
103
+ first, or pass `--force`.
104
+
105
+ ## What it leaves
106
+
107
+ ```
108
+ finetune/
109
+ STATUS.md the whole tuning: summary (spend per phase, tuning and memory
110
+ effect), workers and what each is doing now, queue, applies,
111
+ cases - generated, rewritten every second while it runs
112
+ loop.json the settings; flags on start update it
113
+ events.jsonl every step, in order
114
+ cases/<id>/
115
+ FEEDBACK.md that case: rubric, latest analysis, decisions, history, metrics
116
+ of every try and how they moved - generated
117
+ r<rev>/result.json completed or difficult, once it ends
118
+ r<rev>/<NN>-<nomem|mem>/ one try: request.json, run.json, memory/,
119
+ brief.md, session, feedback.json, analysis.md,
120
+ run.log, analyze.log
121
+ applies/<NNN>/ APPLY.md (generated), inputs.json, deferred.json, budget.json,
122
+ growth.json, gate.json, brief.md, apply.log, check.log,
123
+ changes.md, decisions.json, diff.patch, cost.md; budget.md
124
+ or missing.md when an attempt was undone
125
+ rechecks.json every recheck: case, apply, state, tries, the request it sent
126
+ rechecks/<NNN>/<id>/<NN>-nomem/ one recheck try, as a case's try
127
+ baseline.json what the agents read when the tuning began
128
+ memories/ submissions.jsonl, merges.jsonl, submitted/<case>@r<rev>/, merged/mNN/
129
+ systems/ systems.jsonl + a copy of agents.yaml and agents/ per version
130
+ ```
131
+
132
+ Open `STATUS.md` first; every row links to the detail behind it. Its Summary
133
+ says whether the tuning is working: the fixes, as a case's first try without
134
+ memory against its passing one, and memory, as the passing try without memory
135
+ against the passing try with it - tokens, calls, tool errors and time, totalled
136
+ over the same cases. A case's `FEEDBACK.md` has the same metrics per try and per
137
+ model, each try against the one before it in its phase.
@@ -13,7 +13,8 @@ Four ways to read one run, for two different readers.
13
13
  | `report` | you | `report.html` - every message, payload and cost |
14
14
  | `graph` | a model | the whole trajectory as one Mermaid flowchart |
15
15
  | `node <id...>` | a model | those nodes in full, payloads resolved |
16
- | `ask <id> <question>` | you | that call replayed to a model, with a question |
16
+ | `ask <id> <question>` | a model | one replayed answer on stdout; never prompts |
17
+ | `ask [<id>]` | you | a conversation with that call, at a terminal |
17
18
 
18
19
  `report` is the default, so `zen inspect` on its own is unchanged.
19
20
 
@@ -26,8 +27,10 @@ Four ways to read one run, for two different readers.
26
27
  | `--dir <dir>` | all | A run directory, as `zen run --json` reports it |
27
28
  | `--memory <dir>` | report, graph | Read this memory instead of the one the run recorded |
28
29
  | `--model <ref>` | ask | Answer with this model instead of the run's own |
30
+ | `--question-file <f>` | ask | Read the question from a file; `-` is stdin |
29
31
  | `--part <name>` | node | Print this part in full. Repeatable, prefix-matched |
30
32
  | `--full` | node | Print every part, the recorded `request` included |
33
+ | `--raw` | node | One `--part` of one node, unframed - for a pipe |
31
34
  | `--open` | report | Open the report in a browser |
32
35
  | `--rebuild` | report | Rebuild `report.html` from the recorded state |
33
36
  | `--no-timing` | graph | Leave the clock off the graph |
@@ -39,10 +42,13 @@ session that has one. "Newest" means the newest session that actually recorded a
39
42
  run, not simply the newest session: a session exists before its first run, so
40
43
  the latest one is routinely empty.
41
44
 
42
- **Neither `node` nor `ask` has room for a run.** Every positional `node` takes is
43
- a node id, and `ask` takes one id and then your question, so name the run with
44
- `--run`, `--session` or `--dir` - `zen inspect node <run> n13` reads the run id
45
- as an id and fails.
45
+ **Neither `node` nor `ask` has room for a positional run.** Every positional
46
+ `node` takes is a node id, and every positional `ask` takes is the id followed
47
+ by the question, so name the run with `--run`, `--session` or `--dir`.
48
+ `zen inspect node <run> n13` reads the run id as an id and fails. `ask`
49
+ without a question is the interactive mode (below) and needs a terminal; a
50
+ script, `--json` call or agent passes the id and the question and never sees a
51
+ prompt.
46
52
 
47
53
  For `report` and `graph` the positional is a run id unless it contains a `/`, in
48
54
  which case it is read as a run directory. A run id is a stamp and never has a
@@ -100,13 +106,13 @@ zen inspect graph --dir "$(zen run --json 'fix the tests' | jq -r .run.dir)"
100
106
  %% n24 joins docs (researcher, ok), tests (researcher, ok)
101
107
  %% compacted 3 nodes are marked "hidden by" a later summary
102
108
  %% they still ran; the model simply stopped seeing them
103
- %%
109
+ %% ---
104
110
  %% reading nN is a node id · t+ counts from the start of the turn
105
111
  %% dotted edges are fork/join and calls answered out of order
106
112
  %% nodes are declared in run order; every edge is in one block below
107
113
  %% detail zen inspect node n1 n2 n5..n9 --dir <run dir>
108
114
  %% why zen inspect ask n5 "why did you do that?" --dir <run dir>
109
- %%
115
+ %% ---
110
116
  flowchart TD
111
117
  n11["n11 llm claude-opus-5 · 4.2k in 310 out · calls run_command · t+32.7s"]
112
118
  n12["n12 run_command npm test -- --run · t+34.7s · took 3.0s"]
@@ -181,10 +187,23 @@ zen inspect node n11 --full --dir <run dir>
181
187
  ```
182
188
 
183
189
  `--part` matches a prefix, so `--part call` catches a part named
184
- `call run_command (toolu_01A…)` without your typing the id. Naming a part the
185
- node does not carry is an error listing the ones it does - nothing is ever
190
+ `call run_command (toolu_01A…)` without your typing the id. A name no node
191
+ carries is reported in a `#` line under the header; when none of the names
192
+ matches it is an error listing the parts the nodes do carry - nothing is ever
186
193
  elided in silence.
187
194
 
195
+ An `llm_call` also carries two parts read out of its request and held back the
196
+ same way: `tools`, the names of the tools that call was offered, and
197
+ `messages`, the conversation it saw, one clipped line per message with its tool
198
+ calls indented under it. `--raw` prints one part of one node and nothing else -
199
+ no `#` header, no frame - so it pipes:
200
+
201
+ ```
202
+ zen inspect node n11 --part tools --dir <run dir>
203
+ zen inspect node n11 --part messages --dir <run dir>
204
+ zen inspect node n11 --part request --raw --dir <run dir> | jq '.tools[].name'
205
+ ```
206
+
188
207
  Two `#` lines come first - which run, how many of its nodes you asked for, and
189
208
  a reminder of what part text is. Then each node is framed, and each payload
190
209
  inside it is framed with its own byte count:
@@ -214,10 +233,43 @@ ready to paste.
214
233
 
215
234
  `node` shows what a model was given. `ask` asks the model what it made of it.
216
235
 
236
+ `ask` has two modes, and which one runs is decided by one thing: whether the
237
+ question is given.
238
+
239
+ | Mode | Trigger | For | Behaviour |
240
+ | ----------- | ------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------ |
241
+ | One-shot | a question on the line, `--question-file`, or `--json` | a script or a model | no banner, no prompt, no picker; one model call, the raw answer on stdout and nothing else, exit |
242
+ | Interactive | no question | a person at a terminal | asks for whatever is not named - session, run, `llm_call` - then the question; a conversation |
243
+
244
+ One-shot never reads the terminal, even when there is one: an unnamed run is
245
+ the newest, not a picker, so name it with `--dir`, `--run` or `--session`.
246
+ Interactive without a terminal is a usage error, never a wait.
247
+
217
248
  ```sh
218
249
  zen inspect ask n11 "why run python -c when the skill says npm test?" --dir <run dir>
219
250
  ```
220
251
 
252
+ In the interactive mode only calls with a recorded request appear in the node
253
+ list. Each question and Markdown answer is drawn in its own labelled panel, with
254
+ the model and token counts on stderr. It keeps asking on the same node,
255
+ retaining earlier exchanges as context, until an empty question is submitted.
256
+
257
+ ```sh
258
+ zen inspect ask # pick everything
259
+ zen inspect ask n11 --dir <run dir> # straight to the questions
260
+ ```
261
+
262
+ A question with quotes, apostrophes, backticks, `$` or more than one line goes
263
+ in a file, so no shell parses it. The file is the whole question; `-` reads it
264
+ from stdin. Words on the line as well are an error.
265
+
266
+ ```sh
267
+ zen inspect ask n11 --question-file .tmp/ask/<run-id>/n11-tests.md --dir <run dir>
268
+ ```
269
+
270
+ Do not build the question with `"$(cat <<'EOF' ... )"`: macOS `/bin/bash` 3.2
271
+ misparses a heredoc inside `$( )` when its body holds an apostrophe.
272
+
221
273
  The `llm_call` node named by the id is replayed: its recorded system prompt, its
222
274
  messages and its tool schemas, exactly as the provider received them, with the
223
275
  answer it gave put back as its own turn and your question as one more after
@@ -247,8 +299,8 @@ command says so on stderr, because an answer from a different model is a second
247
299
  opinion rather than the model examining itself. Either way the run's full system
248
300
  prompt goes to that provider.
249
301
 
250
- `graph`, `node` and `ask` print no banner. Their stdout is the answer, whole and
251
- ready to paste.
302
+ `graph`, `node` and non-interactive `ask` print no banner. Their stdout is the
303
+ answer, whole and ready to paste.
252
304
 
253
305
  ## Where it comes from
254
306
 
@@ -18,16 +18,21 @@ skill.
18
18
 
19
19
  ## Subcommands
20
20
 
21
- | Command | What it does |
22
- | ------------------------- | ------------------------------------------- |
23
- | `zen memory stats` | Size, vocabulary, whether it is embedded |
24
- | `zen memory ls` | Nodes, newest first. Changes nothing |
25
- | `zen memory search <q>` | Recall it, the way an agent does. Ranked |
26
- | `zen memory grep <pat>` | Every node containing it, with the lines |
27
- | `zen memory show <id>` | One node in full, with what it links to |
28
- | `zen memory export [f]` | The whole graph as one HTML page |
29
- | `zen memory merge <dir…>` | Fold other memories into this one |
30
- | `zen memory forget <id…>` | Remove nodes, their vectors and their files |
21
+ | Command | What it does |
22
+ | ------------------------- | --------------------------------------------------- |
23
+ | `zen memory stats` | Size, vocabulary, whether it is embedded |
24
+ | `zen memory ls` | Nodes, newest first: kind, audience, revision, text |
25
+ | `zen memory search <q>` | Recall it, the way an agent does. Ranked |
26
+ | `zen memory grep <pat>` | Every node containing it, with the lines |
27
+ | `zen memory show <id>` | One node in full, with what it links to |
28
+ | `zen memory diff <base>` | What this memory holds that `<base>` did not |
29
+ | `zen memory export [f]` | The whole graph as one HTML page |
30
+ | `zen memory merge <dir…>` | Fold other memories into this one |
31
+ | `zen memory forget <id…>` | Remove nodes, their vectors and their files |
32
+
33
+ `ls` cuts the text to the terminal's width; piped, or run by an agent, it prints
34
+ all of it. Never read `graph.json` directly - `ls --json` is the same nodes in a
35
+ shape that does not change under you.
31
36
 
32
37
  | Flag | Meaning |
33
38
  | ----------------------------- | ---------------------------------------------- |
@@ -99,6 +104,24 @@ remembered file it could not read - too big, binary, missing - is named rather
99
104
  than silently skipped, because a file that went unsearched must not pass for one
100
105
  with no match.
101
106
 
107
+ ## `diff` says what a run did to a copy
108
+
109
+ A run started from a copy of a memory leaves the whole copy behind, so `ls` on
110
+ it shows everything the base held too. `diff` shows only what changed:
111
+
112
+ ```sh
113
+ zen memory diff <candidate> --dir <batch-dir>/<id>/memory
114
+ ```
115
+
116
+ - **added** - each with the nearest node `<base>` held and its score. One
117
+ `merge` would fold onto it is marked a twin: the run said again what the
118
+ memory already held.
119
+ - **revised** - same id, new revision.
120
+ - **used** - nodes `memory_load` returned, and how often: what the run read.
121
+ - **removed**, and new `SUPERSEDES` edges.
122
+
123
+ It reads both sides without the lock, so it works on a memory a run is writing.
124
+
102
125
  Superseded nodes are left out unless you ask: `--all` includes them marked, and
103
126
  `--stale` narrows to them alone.
104
127
 
@@ -0,0 +1,61 @@
1
+ # `zen meta` - the meta agent, on this project
2
+
3
+ ```
4
+ zen meta run [project] "<question>" ask it something
5
+ zen meta run [project] /<name> [words] run .github/prompts/<name>.prompt.md
6
+ zen meta prompts [project] list the stored prompts
7
+ zen meta resume [project] [session] carry on a run that stopped
8
+ zen meta model [ref] show or set the model it uses
9
+ zen meta dataset <verb> see dataset.md
10
+ ```
11
+
12
+ `zen meta --help` has every option.
13
+
14
+ ## `--json`
15
+
16
+ `zen meta run --json` prints ONE object on stdout when the run ends:
17
+
18
+ ```json
19
+ {
20
+ "project": "/path/to/project",
21
+ "provider": "vertex",
22
+ "model": "vertex/gemini-3.8-flash",
23
+ "sessionId": "…",
24
+ "exitCode": 0,
25
+ "resumes": 0,
26
+ "usage": {},
27
+ "tokens": {
28
+ "calls": 12,
29
+ "inputTokens": 0,
30
+ "cachedInputTokens": 0,
31
+ "outputTokens": 0,
32
+ "reasoningTokens": 0
33
+ },
34
+ "answer": "the final answer, as markdown",
35
+ "answerFile": "/path/to/project/.tmp/logs/meta.<when>.md"
36
+ }
37
+ ```
38
+
39
+ `tokens` is summed over every model call of the run; `usage` is the meta
40
+ agent's own end-of-session summary, passed through as it came, and may be absent.
41
+
42
+ - Progress goes to stderr as plain lines: no box, no animation, no status row.
43
+ stdout carries the object and nothing else, so redirect it to keep it:
44
+
45
+ ```
46
+ zen meta run acme /analyze --json > analyze.json
47
+ zen meta run acme /analyze --json > analyze.json 2> analyze.log
48
+ ```
49
+
50
+ - Nothing is asked. A `run` with no question, no `/<name>` and nothing piped
51
+ in is a usage error (exit 2) that lists the prompts, not a menu.
52
+ - A run the meta agent ends in failure still prints the object, then exits 1.
53
+ Check `exitCode`; `sessionId` is what `zen meta resume` takes. A run that
54
+ never starts (no key, bad model) prints no object, only the error.
55
+ - `--dry-run --json` gives `{project, provider, model, from, command, env}`,
56
+ secrets masked, and runs nothing.
57
+ - `zen meta prompts --json` gives `[{name, description, path}]`;
58
+ `zen meta model --json` gives `{model, from, sources}`.
59
+
60
+ The answer is also saved as markdown on every run, with or without `--json`;
61
+ `answerFile` is its path.
@@ -1,7 +1,7 @@
1
1
  # Models - `zen models`
2
2
 
3
3
  ```
4
- zen models <providers|ls|search|show|test|pick> [ref] [options]
4
+ zen models <providers|ls|search|show|test|pick|browse> [ref] [options]
5
5
  ```
6
6
 
7
7
  Alias: `model`.
@@ -21,6 +21,7 @@ but a credential.
21
21
  | `zen models show <ref>` | One model, every field the vendor gave |
22
22
  | `zen models test <ref> …` | One real minimal call per ref, and a verdict |
23
23
  | `zen models pick` | The first ref that answers, printed on stdout |
24
+ | `zen models browse` | Interactive TUI for a person; needs a terminal |
24
25
 
25
26
  Filters, on `ls` and `search`: `--chat`, `--embeddings`, `--images`, `--audio`,
26
27
  `--tools`, `--vision`, `--free`, `--min-context <n>`, `--provider <name>`,
@@ -28,6 +29,9 @@ Filters, on `ls` and `search`: `--chat`, `--embeddings`, `--images`, `--audio`,
28
29
 
29
30
  `pick` requires `--chat` or `--embedding`, and takes `--provider` and `--limit`.
30
31
 
32
+ `browse` is for a person at a terminal and refuses without one (exit 2). An
33
+ agent wants `ls --json`, `search` or `pick` instead.
34
+
31
35
  ## Where the lists come from
32
36
 
33
37
  The providers themselves, cached for a day in `~/.zenera/neo/catalog`. When a
@@ -42,12 +42,10 @@ read too, in filename order, and prepended to every agent - or, with
42
42
  `requires: [<capability>]` in its frontmatter, to every agent that has the
43
43
  capability it is about. A capability that needs standing rules - memory, say -
44
44
  gets its own file rather than another section of `agents/instructions.md`.
45
- Memory's are not written from scratch:
46
- `agents/memory-instructions.md` is the same file as
47
- `.github/skills/zen-memory/references/memory-instructions.md`, which init puts
48
- in the project as well, so a copy that was lost or went stale is restored rather
49
- than rewritten - `.github/skills/zen-memory/scripts/check-instructions.sh` says
50
- which of the two it is, and `… fix` does the copy.
45
+ Memory's are not written from scratch: `agents/memory-instructions.md` is
46
+ shipped by `zen`, so a copy that was lost or went stale is restored rather than
47
+ rewritten - `zen check` reports it (`memory.uninstructed`, `rules.stale`) and
48
+ `zen check --fix` writes it back.
51
49
 
52
50
  The project's own files are never overwritten - `--force` is what allows
53
51
  writing into an occupied directory, and the files already there stay. The
@@ -558,6 +558,7 @@ ordinary hybrid search and narrow by file or section.
558
558
  zen rag docs list <files|sections|tables> [-f <pattern>] [-s <section>]
559
559
  zen rag docs grep <pattern> [-f <pattern>] [--regex] [--case-sensitive]
560
560
  zen rag docs show <file> [--section <name>] [--lines <from-to>]
561
+ zen rag docs show <target>... [--max-lines <n>]
561
562
  ```
562
563
 
563
564
  `list sections` gives every heading with the lines it spans, which is how a
@@ -566,6 +567,23 @@ total even when `--limit` cuts the rows, so unlike a search it can answer
566
567
  whether a string appears at all. `show` prints a document, a named section, or
567
568
  a line range, verbatim.
568
569
 
570
+ ### Reading several passages in one call
571
+
572
+ Name every passage you will read or cite in **one** `show`, as
573
+ `<document>:<a>-<b>`, `<document>:<a>` or `<document>#<heading>` - the form a
574
+ citation is written in, so a citation pastes back unchanged:
575
+
576
+ ```sh
577
+ zen rag docs show -d <index-dir> "<doc-1>:24-60" "<doc-2>:25-40" "<doc-3>#<heading>"
578
+ ```
579
+
580
+ Each target prints under a header that is itself a target, in the order given;
581
+ overlapping ranges in one document print once. A missing document or heading is
582
+ reported in place and the rest still print (exit 1 only when none could be
583
+ read). `--max-lines` (default 400) is shared fairly between targets, and a cut
584
+ block ends with the target that continues it. `--json` returns
585
+ `{results, printed, failed}`. `--section` and `--lines` read one document only.
586
+
569
587
  ### Reading a complete section or table
570
588
 
571
589
  Search finds relevant passages, not necessarily every row of a table. When the
@@ -596,12 +614,12 @@ the answer needs every row.
596
614
 
597
615
  `@zenera/rag/docs/tools` exports four tools in the group `docs`:
598
616
 
599
- | Tool | For |
600
- | ------------- | --------------------------------------------------------------- |
601
- | `search_docs` | The search above, with the same narrowing parameters |
602
- | `list_docs` | The documents, their headings, or their tables - no ranking |
603
- | `grep_docs` | Every matching line, counted in full - the way to prove absence |
604
- | `read_docs` | A section or a line range, verbatim and complete |
617
+ | Tool | For |
618
+ | ------------- | ---------------------------------------------------------------- |
619
+ | `search_docs` | The search above, with the same narrowing parameters |
620
+ | `list_docs` | The documents, their headings, or their tables - no ranking |
621
+ | `grep_docs` | Every matching line, counted in full - the way to prove absence |
622
+ | `read_docs` | A section or a line range, verbatim; several at once via `reads` |
605
623
 
606
624
  Only `search_docs` ranks. Every answer carries line numbers and `read_docs`
607
625
  takes them, which is the loop the subject exists for: find the passage, read
@@ -1,7 +1,7 @@
1
1
  # The sandbox - `zen sandbox`
2
2
 
3
3
  ```
4
- zen sandbox [status|up|pull|clean|disk] [options]
4
+ zen sandbox [status|top|up|pull|clean|disk] [options]
5
5
  ```
6
6
 
7
7
  Shell commands run in a container over the session workspace, never on the
@@ -9,18 +9,30 @@ host. None of this is required: a run does all of it on its own, the first time
9
9
  an agent that can reach a shell is about to start one. These subcommands are for
10
10
  doing it deliberately - before a demo, in CI, or when diagnosing.
11
11
 
12
- | Subcommand | What it does |
13
- | ---------- | -------------------------------------------------------------- |
14
- | `status` | What is installed, running and pulled. Changes nothing |
15
- | `up` | Install if asked, start the machine, pull or build the image |
16
- | `pull` | Just the image: pulled, or built from the project's Dockerfile |
17
- | `clean` | Remove every container this CLI created |
18
- | `disk` | What the engine and every known project occupy |
19
-
20
- | Flag | Meaning |
21
- | ----------------------- | --------------------------------------- |
22
- | `--project <name\|dir>` | Which project the image comes from |
23
- | `--image <ref>` | Use this image instead of the project's |
12
+ | Subcommand | What it does |
13
+ | ---------- | ------------------------------------------------------------------- |
14
+ | `status` | What is installed, running and pulled. Changes nothing |
15
+ | `top` | Memory and cpu: this computer, the machine, every running container |
16
+ | `up` | Install if asked, start the machine, pull or build the image |
17
+ | `pull` | Just the image: pulled, or built from the project's Dockerfile |
18
+ | `clean` | Remove every container this CLI created |
19
+ | `disk` | What the engine and every known project occupy |
20
+
21
+ | Flag | Meaning |
22
+ | ----------------------- | ---------------------------------------------------------- |
23
+ | `--project <name\|dir>` | Which project the image comes from |
24
+ | `--image <ref>` | Use this image instead of the project's |
25
+ | `--once` | `top`: print one report instead of the live screen |
26
+ | `--interval <seconds>` | `top`: how often the live screen refreshes (default 2) |
27
+ | `--brief` | `top`: the figures without the notes saying what they mean |
28
+
29
+ `top` draws a live screen only when a person is at a terminal. From an agent,
30
+ a script or with `--json` it measures twice a second apart (cpu needs an
31
+ interval) and prints once, so `zen sandbox top --json` is the form to read:
32
+ `host.vm` is what the machine costs the computer (`footprint` is Activity
33
+ Monitor's figure on macOS), `machine` is Linux's own split into `used`, `cache`
34
+ and `free`, `containers[]` carries `cpu` (percent of one core), `memory`,
35
+ `limit` and `orphaned`, and `hints[]` says what to do about it.
24
36
 
25
37
  The engine is Podman. On macOS a machine has to exist and be running; `up`
26
38
  offers to install and start one, and its size follows the project's `cpus` and
@@ -119,7 +131,16 @@ distinguishes the two cases: a broken Dockerfile is an error, a laptop with no
119
131
  Podman is a warning.
120
132
 
121
133
  `zen sandbox clean` removes every container this CLI created - the way out of a
122
- container left on a bad rootfs.
134
+ container left on a bad rootfs. `--idle` removes only what no live run is using:
135
+ stopped containers, and running ones whose run was killed before stopping them
136
+ (`zen sandbox status` marks those `orphaned`).
137
+
138
+ `could not create container … exceeded num_locks (2048)` means the engine is out
139
+ of locks: every container holds one, stopped ones included, and `persist: true`
140
+ leaves one stopped per session. `zen run` and `zen run batch` check this before
141
+ the first model call and exit `5` when the engine cannot hold them (a batch needs
142
+ one per item it runs at once). `zen sandbox status` shows a `locks` row when few
143
+ are left; `zen sandbox clean --idle` frees them.
123
144
 
124
145
  For complete container architecture, the `sandbox:*` tools, mount rules, and
125
146
  hardening details, load the `zen-sandbox` skill (`.github/skills/zen-sandbox/SKILL.md`).