@zenera/cli 1.1.24 → 1.1.25

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 (167) hide show
  1. package/README.md +53 -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 +11 -1
  7. package/dist/catalog.js +80 -7
  8. package/dist/commands/inspect.d.ts +47 -1
  9. package/dist/commands/inspect.js +167 -18
  10. package/dist/commands/memory.js +128 -29
  11. package/dist/commands/meta.js +311 -21
  12. package/dist/commands/models.js +96 -12
  13. package/dist/commands/open.js +4 -4
  14. package/dist/commands/run.js +38 -4
  15. package/dist/commands/sandbox.js +76 -14
  16. package/dist/engine.d.ts +5 -0
  17. package/dist/engine.js +1 -0
  18. package/dist/eventlog.d.ts +59 -0
  19. package/dist/eventlog.js +146 -0
  20. package/dist/liveness.d.ts +7 -0
  21. package/dist/liveness.js +15 -1
  22. package/dist/meta/editor.d.ts +9 -0
  23. package/dist/meta/editor.js +60 -0
  24. package/dist/meta/finetune/children.d.ts +8 -0
  25. package/dist/meta/finetune/children.js +76 -0
  26. package/dist/meta/finetune/command.d.ts +30 -0
  27. package/dist/meta/finetune/command.js +338 -0
  28. package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
  29. package/dist/meta/finetune/dataset/anchors.js +239 -0
  30. package/dist/meta/finetune/dataset/changes.d.ts +36 -0
  31. package/dist/meta/finetune/dataset/changes.js +319 -0
  32. package/dist/meta/finetune/dataset/command.d.ts +17 -0
  33. package/dist/meta/finetune/dataset/command.js +1011 -0
  34. package/dist/meta/finetune/dataset/drift.d.ts +33 -0
  35. package/dist/meta/finetune/dataset/drift.js +71 -0
  36. package/dist/meta/finetune/dataset/export.d.ts +26 -0
  37. package/dist/meta/finetune/dataset/export.js +51 -0
  38. package/dist/meta/finetune/dataset/index.d.ts +2 -0
  39. package/dist/meta/finetune/dataset/index.js +2 -0
  40. package/dist/meta/finetune/dataset/sample.d.ts +50 -0
  41. package/dist/meta/finetune/dataset/sample.js +197 -0
  42. package/dist/meta/finetune/dataset/schema.d.ts +33 -0
  43. package/dist/meta/finetune/dataset/schema.js +216 -0
  44. package/dist/meta/finetune/dataset/store.d.ts +35 -0
  45. package/dist/meta/finetune/dataset/store.js +177 -0
  46. package/dist/meta/finetune/dataset/types.d.ts +125 -0
  47. package/dist/meta/finetune/dataset/types.js +39 -0
  48. package/dist/meta/finetune/failure.d.ts +15 -0
  49. package/dist/meta/finetune/failure.js +26 -0
  50. package/dist/meta/finetune/feedback.d.ts +45 -0
  51. package/dist/meta/finetune/feedback.js +85 -0
  52. package/dist/meta/finetune/improvements.d.ts +51 -0
  53. package/dist/meta/finetune/improvements.js +244 -0
  54. package/dist/meta/finetune/index.d.ts +2 -0
  55. package/dist/meta/finetune/index.js +2 -0
  56. package/dist/meta/finetune/journal.d.ts +35 -0
  57. package/dist/meta/finetune/journal.js +135 -0
  58. package/dist/meta/finetune/live.d.ts +74 -0
  59. package/dist/meta/finetune/live.js +226 -0
  60. package/dist/meta/finetune/loop.d.ts +3 -0
  61. package/dist/meta/finetune/loop.js +114 -0
  62. package/dist/meta/finetune/memories.d.ts +47 -0
  63. package/dist/meta/finetune/memories.js +154 -0
  64. package/dist/meta/finetune/report.d.ts +33 -0
  65. package/dist/meta/finetune/report.js +1284 -0
  66. package/dist/meta/finetune/retry.d.ts +24 -0
  67. package/dist/meta/finetune/retry.js +96 -0
  68. package/dist/meta/finetune/sampler.d.ts +18 -0
  69. package/dist/meta/finetune/sampler.js +41 -0
  70. package/dist/meta/finetune/system.d.ts +27 -0
  71. package/dist/meta/finetune/system.js +132 -0
  72. package/dist/meta/finetune/train.d.ts +39 -0
  73. package/dist/meta/finetune/train.js +391 -0
  74. package/dist/meta/finetune/tui.d.ts +16 -0
  75. package/dist/meta/finetune/tui.js +291 -0
  76. package/dist/meta/finetune/tuning.d.ts +167 -0
  77. package/dist/meta/finetune/tuning.js +289 -0
  78. package/dist/meta/finetune/usage.d.ts +62 -0
  79. package/dist/meta/finetune/usage.js +225 -0
  80. package/dist/meta/host.d.ts +14 -0
  81. package/dist/meta/host.js +20 -0
  82. package/dist/meta/index.d.ts +11 -0
  83. package/dist/meta/index.js +11 -0
  84. package/dist/meta/launch.d.ts +81 -0
  85. package/dist/meta/launch.js +286 -0
  86. package/dist/meta/model.d.ts +44 -0
  87. package/dist/meta/model.js +119 -0
  88. package/dist/meta/prompts.d.ts +18 -0
  89. package/dist/meta/prompts.js +61 -0
  90. package/dist/meta/relay.d.ts +20 -0
  91. package/dist/meta/relay.js +123 -0
  92. package/dist/meta/tokens.d.ts +52 -0
  93. package/dist/meta/tokens.js +226 -0
  94. package/dist/meta/window.d.ts +61 -0
  95. package/dist/meta/window.js +198 -0
  96. package/dist/meta/wire.d.ts +42 -0
  97. package/dist/meta/wire.js +129 -0
  98. package/dist/modelref.d.ts +16 -0
  99. package/dist/modelref.js +41 -0
  100. package/dist/narrate.js +5 -2
  101. package/dist/podman.d.ts +26 -0
  102. package/dist/podman.js +83 -3
  103. package/dist/projects.d.ts +0 -5
  104. package/dist/projects.js +2 -15
  105. package/dist/sandbox.d.ts +2 -0
  106. package/dist/sandbox.js +10 -3
  107. package/dist/scaffold.d.ts +15 -6
  108. package/dist/scaffold.js +5 -60
  109. package/dist/session.js +4 -29
  110. package/dist/term.d.ts +2 -0
  111. package/dist/term.js +11 -2
  112. package/dist/trace.js +53 -2
  113. package/dist/tui/models.d.ts +33 -0
  114. package/dist/tui/models.js +389 -0
  115. package/dist/tui/wrap.d.ts +5 -0
  116. package/dist/tui/wrap.js +12 -0
  117. package/dist/usage.d.ts +78 -0
  118. package/dist/usage.js +51 -0
  119. package/package.json +3 -2
  120. package/templates/editor/.github/copilot-instructions.md +31 -102
  121. package/templates/editor/.github/prompts/analyze.prompt.md +31 -0
  122. package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
  123. package/templates/editor/.github/prompts/finetune-apply.prompt.md +91 -0
  124. package/templates/editor/.github/prompts/finetune.prompt.md +691 -198
  125. package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
  126. package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
  127. package/templates/editor/.github/prompts/project-review.prompt.md +4 -3
  128. package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +483 -0
  129. package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -1
  130. package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
  131. package/templates/editor/.github/skills/zen-cli/references/finetune.md +77 -0
  132. package/templates/editor/.github/skills/zen-cli/references/inspect.md +47 -9
  133. package/templates/editor/.github/skills/zen-cli/references/memory.md +33 -10
  134. package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
  135. package/templates/editor/.github/skills/zen-cli/references/models.md +5 -1
  136. package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
  137. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +10 -1
  138. package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
  139. package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
  140. package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
  141. package/templates/editor/.github/skills/zen-finetune/SKILL.md +1449 -658
  142. package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
  143. package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
  144. package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
  145. package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
  146. package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
  147. package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
  148. package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
  149. package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
  150. package/templates/editor/.github/skills/zen-inspect/SKILL.md +60 -25
  151. package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +270 -0
  152. package/templates/editor/.github/skills/zen-memory/SKILL.md +18 -14
  153. package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
  154. package/templates/editor/.github/skills/zen-review/SKILL.md +5 -3
  155. package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -4
  156. package/templates/editor/.github/skills/zen-sandbox/SKILL.md +7 -3
  157. package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -2
  158. package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
  159. package/templates/editor/.vscode/settings.json +1 -0
  160. package/templates/project/agents/files-instructions.md +29 -20
  161. package/templates/project/agents/memory-instructions.md +31 -32
  162. package/templates/project/agents/tools-instructions.md +7 -4
  163. package/templates/project/gitignore +2 -0
  164. package/dist/meta.d.ts +0 -221
  165. package/dist/meta.js +0 -684
  166. package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +0 -432
  167. package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +0 -199
@@ -0,0 +1,77 @@
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
+ [--class <c>] [--id <glob>] [--rubric yes|no] [--limit <n>] [--force]
9
+ zen meta finetune [status]
10
+ zen meta finetune stop
11
+ zen meta finetune session <case>
12
+ ```
13
+
14
+ ## What one case goes through
15
+
16
+ ```
17
+ without memory, up to --tries times:
18
+ zen run (empty memory) -> /analyze -> done? go on : park until the next apply
19
+ with memory, up to --mem-tries times, from the memory the passing run wrote:
20
+ zen run -> /analyze -> done? completed : park until the next apply
21
+ tries used up -> difficult
22
+ ```
23
+
24
+ - **N workers**, each training one case at a time. Cases come in the dataset's
25
+ own order: classes taking turns, cases with a rubric first, then seeded
26
+ random. Cases added to the dataset are picked up as it goes.
27
+ - **A parked case gives its worker back**, so another case runs while it waits
28
+ for an apply; once woken, it takes a worker before any new case does.
29
+ - **Applies are batched.** Parked cases' improvement requests are applied
30
+ together by `/finetune-apply` once **M** cases are parked, or once nothing is
31
+ running and no case is left to start. No run starts during an apply; runs in flight finish
32
+ first. `zen check` must pass afterwards, or the edit is undone and tried once
33
+ more; a second failure stops the tuning. Each apply gets its own
34
+ `applies/<NNN>/APPLY.md`: every request and improvement, what was decided for
35
+ each, the apply agent's account of what it changed and why, every file
36
+ changed with its diff, and the `zen check` result.
37
+ - **No run shares a memory.** Every try runs on its own private directory:
38
+ empty without memory, a copy of the case's passing memory with it. A case
39
+ whose with-memory run passes keeps a copy in `memories/submitted/`; every
40
+ `--merge-every` kept memories are merged, with the last merge, into
41
+ `memories/merged/mNN/` - numbered, never rewritten, each listing the cases it
42
+ holds. Whatever is left is merged when the tuning ends.
43
+ - **Each case keeps one analyze session**, so every analysis of it remembers
44
+ the earlier tries. `session <case>` prints the command to resume it.
45
+ - **Stop and resume freely.** `stop` (or Ctrl-C once) lets the steps in flight
46
+ finish, then exits; Ctrl-C twice kills them. `start` again carries on: every
47
+ step's result is on disk, and nothing finished is repeated.
48
+ - `start` refuses a dataset that has drifted from its sources - run `/dataset`
49
+ first, or pass `--force`.
50
+
51
+ ## What it leaves
52
+
53
+ ```
54
+ finetune/
55
+ STATUS.md the whole tuning: summary (spend per phase, tuning and memory
56
+ effect), workers, queue, applies, cases - generated
57
+ loop.json the settings; flags on start update it
58
+ events.jsonl every step, in order
59
+ cases/<id>/
60
+ FEEDBACK.md that case: rubric, latest analysis, decisions, history, metrics
61
+ of every try and how they moved - generated
62
+ r<rev>/session its analyze session
63
+ r<rev>/result.json completed or difficult, once it ends
64
+ r<rev>/<NN>-<nomem|mem>/ one try: request.json, run.json, memory/,
65
+ feedback.json, analysis.md, run.log, analyze.log
66
+ applies/<NNN>/ APPLY.md (generated), inputs.json, apply.log, check.log, changes.md,
67
+ decisions.json, diff.patch
68
+ memories/ submissions.jsonl, merges.jsonl, submitted/<case>@r<rev>/, merged/mNN/
69
+ systems/ systems.jsonl + a copy of agents.yaml and agents/ per version
70
+ ```
71
+
72
+ Open `STATUS.md` first; every row links to the detail behind it. Its Summary
73
+ says whether the tuning is working: the fixes, as a case's first try without
74
+ memory against its passing one, and memory, as the passing try without memory
75
+ against the passing try with it - tokens, calls, tool errors and time, totalled
76
+ over the same cases. A case's `FEEDBACK.md` has the same metrics per try and per
77
+ 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,6 +27,7 @@ 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 |
31
33
  | `--open` | report | Open the report in a browser |
@@ -39,10 +41,13 @@ session that has one. "Newest" means the newest session that actually recorded a
39
41
  run, not simply the newest session: a session exists before its first run, so
40
42
  the latest one is routinely empty.
41
43
 
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.
44
+ **Neither `node` nor `ask` has room for a positional run.** Every positional
45
+ `node` takes is a node id, and every positional `ask` takes is the id followed
46
+ by the question, so name the run with `--run`, `--session` or `--dir`.
47
+ `zen inspect node <run> n13` reads the run id as an id and fails. `ask`
48
+ without a question is the interactive mode (below) and needs a terminal; a
49
+ script, `--json` call or agent passes the id and the question and never sees a
50
+ prompt.
46
51
 
47
52
  For `report` and `graph` the positional is a run id unless it contains a `/`, in
48
53
  which case it is read as a run directory. A run id is a stamp and never has a
@@ -100,13 +105,13 @@ zen inspect graph --dir "$(zen run --json 'fix the tests' | jq -r .run.dir)"
100
105
  %% n24 joins docs (researcher, ok), tests (researcher, ok)
101
106
  %% compacted 3 nodes are marked "hidden by" a later summary
102
107
  %% they still ran; the model simply stopped seeing them
103
- %%
108
+ %% ---
104
109
  %% reading nN is a node id · t+ counts from the start of the turn
105
110
  %% dotted edges are fork/join and calls answered out of order
106
111
  %% nodes are declared in run order; every edge is in one block below
107
112
  %% detail zen inspect node n1 n2 n5..n9 --dir <run dir>
108
113
  %% why zen inspect ask n5 "why did you do that?" --dir <run dir>
109
- %%
114
+ %% ---
110
115
  flowchart TD
111
116
  n11["n11 llm claude-opus-5 · 4.2k in 310 out · calls run_command · t+32.7s"]
112
117
  n12["n12 run_command npm test -- --run · t+34.7s · took 3.0s"]
@@ -214,10 +219,43 @@ ready to paste.
214
219
 
215
220
  `node` shows what a model was given. `ask` asks the model what it made of it.
216
221
 
222
+ `ask` has two modes, and which one runs is decided by one thing: whether the
223
+ question is given.
224
+
225
+ | Mode | Trigger | For | Behaviour |
226
+ | ----------- | ------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------ |
227
+ | 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 |
228
+ | Interactive | no question | a person at a terminal | asks for whatever is not named - session, run, `llm_call` - then the question; a conversation |
229
+
230
+ One-shot never reads the terminal, even when there is one: an unnamed run is
231
+ the newest, not a picker, so name it with `--dir`, `--run` or `--session`.
232
+ Interactive without a terminal is a usage error, never a wait.
233
+
217
234
  ```sh
218
235
  zen inspect ask n11 "why run python -c when the skill says npm test?" --dir <run dir>
219
236
  ```
220
237
 
238
+ In the interactive mode only calls with a recorded request appear in the node
239
+ list. Each question and Markdown answer is drawn in its own labelled panel, with
240
+ the model and token counts on stderr. It keeps asking on the same node,
241
+ retaining earlier exchanges as context, until an empty question is submitted.
242
+
243
+ ```sh
244
+ zen inspect ask # pick everything
245
+ zen inspect ask n11 --dir <run dir> # straight to the questions
246
+ ```
247
+
248
+ A question with quotes, apostrophes, backticks, `$` or more than one line goes
249
+ in a file, so no shell parses it. The file is the whole question; `-` reads it
250
+ from stdin. Words on the line as well are an error.
251
+
252
+ ```sh
253
+ zen inspect ask n11 --question-file .tmp/ask/<run-id>/n11-tests.md --dir <run dir>
254
+ ```
255
+
256
+ Do not build the question with `"$(cat <<'EOF' ... )"`: macOS `/bin/bash` 3.2
257
+ misparses a heredoc inside `$( )` when its body holds an apostrophe.
258
+
221
259
  The `llm_call` node named by the id is replayed: its recorded system prompt, its
222
260
  messages and its tool schemas, exactly as the provider received them, with the
223
261
  answer it gave put back as its own turn and your question as one more after
@@ -247,8 +285,8 @@ command says so on stderr, because an answer from a different model is a second
247
285
  opinion rather than the model examining itself. Either way the run's full system
248
286
  prompt goes to that provider.
249
287
 
250
- `graph`, `node` and `ask` print no banner. Their stdout is the answer, whole and
251
- ready to paste.
288
+ `graph`, `node` and non-interactive `ask` print no banner. Their stdout is the
289
+ answer, whole and ready to paste.
252
290
 
253
291
  ## Where it comes from
254
292
 
@@ -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
@@ -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
@@ -119,7 +119,16 @@ distinguishes the two cases: a broken Dockerfile is an error, a laptop with no
119
119
  Podman is a warning.
120
120
 
121
121
  `zen sandbox clean` removes every container this CLI created - the way out of a
122
- container left on a bad rootfs.
122
+ container left on a bad rootfs. `--idle` removes only what no live run is using:
123
+ stopped containers, and running ones whose run was killed before stopping them
124
+ (`zen sandbox status` marks those `orphaned`).
125
+
126
+ `could not create container … exceeded num_locks (2048)` means the engine is out
127
+ of locks: every container holds one, stopped ones included, and `persist: true`
128
+ leaves one stopped per session. `zen run` and `zen run batch` check this before
129
+ the first model call and exit `5` when the engine cannot hold them (a batch needs
130
+ one per item it runs at once). `zen sandbox status` shows a `locks` row when few
131
+ are left; `zen sandbox clean --idle` frees them.
123
132
 
124
133
  For complete container architecture, the `sandbox:*` tools, mount rules, and
125
134
  hardening details, load the `zen-sandbox` skill (`.github/skills/zen-sandbox/SKILL.md`).
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: zen-code-python
3
+ description: Code an agent writes must be a reusable tool that can be remembered and re-run, never a one-off. Holds the coding rules (`references/code_python.md`) and decides where they go in the target project - a section of a dedicated code agent's system prompt, or a coding skill for generic agents that sometimes run code - how to adapt them, and what a prompt or skill for a code-writing agent must never say. Load before writing, editing or reviewing any agent prompt, skill or house rule for an agent that writes or runs code - any agent holding `sandbox:*` or `run_command` - and before shipping a script inside a skill.
4
+ ---
5
+
6
+ # Code an agent writes is a tool
7
+
8
+ A script an agent writes is worth more than the answer it printed. Written
9
+ generically - every changing value an argument, a name that says what it does -
10
+ it can be committed to memory as a `file` node and found again by the next
11
+ similar question, which runs it instead of writing it again. Written as a
12
+ one-off - this customer's id, this month, this path, as literals - it can only
13
+ ever answer the question that produced it, and memory fills up with near-copies
14
+ that never fold together.
15
+
16
+ Nothing in the runtime enforces this, and `zen check` does not report it. The
17
+ rules reach an agent only through what you write into the target project.
18
+
19
+ ## The reference
20
+
21
+ `references/code_python.md` is the rule set, in wording that has been tested on
22
+ models. It is a source to build from, not a file to copy. Start from its
23
+ sentences - copying and then editing them works; rewriting them from scratch in
24
+ your own words loses the mechanical phrasing that makes them obeyed.
25
+
26
+ **Keep in substance, and never soften:**
27
+
28
+ - every value that would change for the next similar question is a named
29
+ argument, never a literal
30
+ - the file is named for what it does, and describes itself through `--help`
31
+ - the result goes to stdout, a produced file to an `--output` path
32
+ - the script is written to a file and the file is run - no `python -c`, no
33
+ heredoc
34
+ - before using the output, the script is checked against a different question
35
+ of the same kind
36
+ - with memory: search before writing, commit the working script after
37
+
38
+ **Adapt to the project:**
39
+
40
+ - the interpreter and language, if the sandbox image runs something other than
41
+ Python
42
+ - where scripts are written - `/workspace/scripts/` unless the project already
43
+ has a place
44
+ - libraries the image carries and the agent should prefer, and the output
45
+ format the project expects (JSON, CSV, a table)
46
+ - an example invocation from this project's own domain, values passed as
47
+ arguments
48
+ - the memory steps: keep them when the agent holds `memory_search` /
49
+ `memory_commit`, drop them when it never will. In a skill several agents may
50
+ load, keep them gated on the tool, as the reference does
51
+
52
+ ## Decide where the rules go
53
+
54
+ List the agents that hold `sandbox:*` or `run_command`, and read each one's
55
+ prompt for what its job is. Then:
56
+
57
+ | The project has | Write |
58
+ | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
59
+ | A **dedicated code agent** - a runner, an executor, an analyst whose answers are scripts | A `## Writing code` section in that agent's `agents/prompts/<name>.md` |
60
+ | **No dedicated code agent** - generic agents that sometimes run code | A coding skill, `agents/skills/code_python/SKILL.md` |
61
+ | Both | The prompt section, and the generic agents hand the code work to that agent rather than writing it - see below |
62
+ | No agent that writes or runs code | Nothing |
63
+
64
+ **A dedicated code agent gets the rules in its system prompt.** It writes code
65
+ on nearly every turn, so the rules are part of its job description: a skill
66
+ would cost a load on every case, and preloading one is the same text in the
67
+ prefix with an extra file to keep in step. Put the section after the agent's
68
+ identity and procedure, before its prohibitions.
69
+
70
+ **Generic agents get a skill.** Most of their turns write no code, so the rules
71
+ should cost nothing until one does. The `description` is the routing key - name
72
+ the condition, not the topic:
73
+
74
+ ```yaml
75
+ description: Before writing, changing or running any Python script - how to write it as a reusable tool rather than a one-off.
76
+ ```
77
+
78
+ Leave it in the agent's index; do not preload it. If `allow` is used, add
79
+ `code_python` to it for every agent holding `sandbox:*`.
80
+
81
+ **With both, one copy.** Generic agents that can reach a code agent should
82
+ `fork:` to it for an answer, or hand off to it, rather than writing code
83
+ themselves - then the rules have one home and the scripts one author. Grant
84
+ them no `sandbox:*` for code work. If they must keep a shell of their own, they
85
+ need the skill too, and its rules are the same sentences as the prompt section:
86
+ a second wording is how one copy ends up softer than the other, and the softer
87
+ one is the one obeyed.
88
+
89
+ Run `zen check` after any change to `agents.yaml` or a skill.
90
+
91
+ ## Writing anything else around it
92
+
93
+ - **One home per agent.** Once an agent has the rules - in its prompt or in its
94
+ skill - no house rule, other skill or prompt line restates them. A prompt that
95
+ needs to point at the skill names it: _"Follow `code_python` for every
96
+ script."_
97
+ - **Never add an exemption.** _"Hard-coding is fine for a quick one-off check"_
98
+ is a permission: every probe is a one-off by construction, so the exception
99
+ admits exactly what the rule forbids. The same goes for `python -c`.
100
+ - **Never show a one-off as an example.** A prompt or skill that shows
101
+ `python -c "..."`, or a script with a literal id, date or path in its body,
102
+ teaches the shape the rule forbids. Every example invocation passes its values
103
+ as named arguments:
104
+ `python /workspace/scripts/list_overdue_invoices.py --customer-id 42`.
105
+ - **Scripts shipped inside a skill** (`agents/skills/<name>/scripts/`, §3.4.1 of
106
+ the copilot instructions) follow the same rules: named arguments, a `--help`,
107
+ the result on stdout, an `--output` path under `/workspace` for any file,
108
+ since `/skills` is read-only.
109
+ - **Memory is what makes the reuse happen.** A code-writing agent without
110
+ memory still writes reusable scripts, but cannot find them in a later session.
111
+ Say so if the project expects reuse and that agent has no `memory:`.
112
+
113
+ ## Review
114
+
115
+ - [ ] Every agent that writes or runs code has the rules - a prompt section for
116
+ a dedicated code agent, the `code_python` skill reachable for the others
117
+ - [ ] Every rule under _Keep in substance_ is there, none softened, and the
118
+ memory steps match whether the agent holds the memory tools
119
+ - [ ] Generic agents beside a dedicated code agent hand code work to it, or
120
+ carry the same wording - not a second paraphrase
121
+ - [ ] No other prompt, skill or house rule restates the rules, adds an
122
+ exemption, or shows `python -c` or a script with literal values
123
+ - [ ] Every script shipped in a skill takes its values as named arguments
@@ -0,0 +1,48 @@
1
+ # Writing Python scripts
2
+
3
+ Every script you write is a tool for the next question like this one, not an
4
+ answer to this one. Write it once, generically, so it can be remembered and run
5
+ again unchanged.
6
+
7
+ ## Before writing
8
+
9
+ If you hold `memory_search`, search for a script that already answers this kind
10
+ of question, and load the best match with `memory_load`. If it fits, run it with
11
+ this question's arguments and write nothing new. If it needs a change, change
12
+ it the way the rest of this skill says - usually by adding an argument - and
13
+ commit the new version as superseding the old one.
14
+
15
+ ## Writing
16
+
17
+ 1. **Solve the kind of question, not this one.** Anything that would differ the
18
+ next time - inputs, ids, names, paths, urls, dates and date ranges, filters,
19
+ thresholds, limits, the output path - is a named `argparse` argument such as
20
+ `--resource-id`, never a literal in the code. A default is allowed only for a
21
+ value that is the same for every question.
22
+ 2. **Name the file for what it does**, verb first: `list_overdue_invoices.py`,
23
+ `compare_quarterly_revenue.py`. Never `script.py`, `test.py`, `tmp.py` or a
24
+ name that only makes sense in this conversation.
25
+ 3. **Describe it.** Line one is a docstring saying what question it answers. The
26
+ same sentence is the `argparse` description, and every argument has a
27
+ `help=`, so `--help` is all a later reader needs.
28
+ 4. **Print the result to stdout** and anything else to stderr. Exit non-zero
29
+ with a message saying what failed when it cannot answer. A file it produces
30
+ goes to the path given by `--output`.
31
+ 5. **Take credentials from environment variables by name.** Never write a key,
32
+ token or password into the code or an argument default.
33
+ 6. **Use only what the sandbox image already has.** Do not `pip install` from
34
+ the script or before running it.
35
+ 7. **Write it to a file and run the file**:
36
+ `python /workspace/scripts/<name>.py --resource-id 42`. Never run Python
37
+ with `python -c` or a heredoc.
38
+
39
+ ## Before using its output
40
+
41
+ - Run it, and fix the script - not the output - when it fails or prints
42
+ something wrong.
43
+ - Read your own code against a different question of the same kind. If
44
+ answering it would mean editing the script rather than passing other
45
+ arguments, a value is still hard-coded: make it an argument and run again.
46
+ - If you hold `memory_commit`, commit the working script as a `file` node. Its
47
+ text says what kind of question it answers and names its arguments, so that a
48
+ later search for a similar question finds it.