@zenera/cli 1.1.23 → 1.1.24

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 (57) hide show
  1. package/README.md +35 -2
  2. package/dist/ask.d.ts +51 -0
  3. package/dist/ask.js +143 -0
  4. package/dist/batch.d.ts +77 -0
  5. package/dist/batch.js +338 -0
  6. package/dist/command.d.ts +6 -0
  7. package/dist/commands/inspect.d.ts +11 -0
  8. package/dist/commands/inspect.js +388 -89
  9. package/dist/commands/list.js +128 -19
  10. package/dist/commands/memory.js +342 -12
  11. package/dist/commands/models.js +14 -2
  12. package/dist/commands/run.js +139 -34
  13. package/dist/commands/sandbox.js +72 -1
  14. package/dist/engine.d.ts +19 -0
  15. package/dist/engine.js +60 -8
  16. package/dist/liveness.js +6 -3
  17. package/dist/main.js +5 -2
  18. package/dist/podman.d.ts +16 -0
  19. package/dist/podman.js +115 -2
  20. package/dist/progress.d.ts +33 -0
  21. package/dist/progress.js +402 -0
  22. package/dist/request.d.ts +45 -0
  23. package/dist/request.js +300 -0
  24. package/dist/sandbox.js +10 -0
  25. package/dist/session.d.ts +26 -1
  26. package/dist/session.js +42 -3
  27. package/dist/term.d.ts +3 -0
  28. package/dist/term.js +17 -1
  29. package/dist/trace.d.ts +84 -0
  30. package/dist/trace.js +686 -0
  31. package/dist/validate.js +25 -3
  32. package/package.json +2 -2
  33. package/templates/editor/.github/copilot-instructions.md +11 -6
  34. package/templates/editor/.github/prompts/finetune.prompt.md +251 -0
  35. package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -3
  36. package/templates/editor/.github/skills/zen-cli/references/check.md +7 -5
  37. package/templates/editor/.github/skills/zen-cli/references/inspect.md +262 -21
  38. package/templates/editor/.github/skills/zen-cli/references/memory.md +89 -19
  39. package/templates/editor/.github/skills/zen-cli/references/models.md +1 -1
  40. package/templates/editor/.github/skills/zen-cli/references/projects.md +12 -5
  41. package/templates/editor/.github/skills/zen-cli/references/run.md +201 -4
  42. package/templates/editor/.github/skills/zen-finetune/SKILL.md +1000 -0
  43. package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +432 -0
  44. package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +199 -0
  45. package/templates/editor/.github/skills/zen-inspect/SKILL.md +396 -0
  46. package/templates/editor/.github/skills/zen-memory/SKILL.md +74 -29
  47. package/templates/editor/.github/skills/zen-memory-warmup/SKILL.md +363 -531
  48. package/templates/editor/.github/skills/zen-sandbox/SKILL.md +19 -0
  49. package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +334 -0
  50. package/templates/editor/.github/skills/zen-sandbox-capacity/references/loadtest.md +181 -0
  51. package/templates/editor/.github/skills/zen-sandbox-capacity/scripts/preflight_sandbox.sh +457 -0
  52. package/templates/editor/.vscode/agents.schema.json +1 -1
  53. package/templates/editor/.vscode/settings.json +1 -0
  54. package/templates/project/agents/files-instructions.md +13 -0
  55. package/templates/project/agents/fork-instructions.md +27 -0
  56. package/templates/project/agents/memory-instructions.md +80 -7
  57. package/templates/project/gitignore +3 -0
package/dist/validate.js CHANGED
@@ -1,4 +1,4 @@
1
- import { EXA_GROUP, FileSkillProvider, SANDBOX_MOUNT, Sandbox, exaTools, frontmatter, projectRegistry, readProjectConfig, sandboxTools, selectTools, toList, workspaceTools, } from '@zenera/neo';
1
+ import { EXA_GROUP, FileSkillProvider, SANDBOX_MOUNT, Sandbox, exaTools, fileTools, frontmatter, projectRegistry, readProjectConfig, sandboxTools, selectTools, toList, } from '@zenera/neo';
2
2
  import { existsSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
@@ -35,10 +35,17 @@ const FILE_TOOLS = [
35
35
  'find_files',
36
36
  'write_file',
37
37
  'apply_patch',
38
+ 'copy_file',
38
39
  'move_file',
39
40
  'delete_file',
40
41
  ];
41
- const FILE_WRITE_TOOLS = new Set(['write_file', 'apply_patch', 'move_file', 'delete_file']);
42
+ const FILE_WRITE_TOOLS = new Set([
43
+ 'write_file',
44
+ 'apply_patch',
45
+ 'copy_file',
46
+ 'move_file',
47
+ 'delete_file',
48
+ ]);
42
49
  function activeFileTools(selectors) {
43
50
  const active = new Set();
44
51
  if (!selectors?.length) {
@@ -607,7 +614,7 @@ export function availableTools(root, config) {
607
614
  // Constructed, not started: a pool creates its container on the first
608
615
  // command, so naming one here costs nothing and needs no container engine.
609
616
  return [
610
- ...workspaceTools({
617
+ ...fileTools({
611
618
  root,
612
619
  mount: config.sandbox?.workdir ?? SANDBOX_MOUNT,
613
620
  }),
@@ -1543,6 +1550,21 @@ function checkModels(root, config, keys, add, probe = false) {
1543
1550
  if (resolved !== name) {
1544
1551
  report.ref = resolved;
1545
1552
  }
1553
+ // Reported here rather than left to the probe below: a knob for the
1554
+ // wrong vendor is a config mistake that wants naming whether or not
1555
+ // there is a credential to build the model with.
1556
+ if (role === 'model') {
1557
+ for (const stray of registry.knobs(ref)) {
1558
+ add({
1559
+ severity: 'error',
1560
+ code: 'model.knob',
1561
+ where: whereFor(config, role, name, usedBy),
1562
+ message: `\`${stray.knob}\` means nothing to a ${stray.target} model — ` +
1563
+ 'it would never reach the request',
1564
+ fix: `this model takes: ${stray.supported.join(', ')}`,
1565
+ });
1566
+ }
1567
+ }
1546
1568
  }
1547
1569
  catch (err) {
1548
1570
  add({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenera/cli",
3
- "version": "1.1.23",
3
+ "version": "1.1.24",
4
4
  "description": "Command-line front end for @zenera/neo: agentic projects you can run, share and commit.",
5
5
  "keywords": [
6
6
  "agents",
@@ -52,7 +52,7 @@
52
52
  "@google/genai": "^2.18.0",
53
53
  "@inkjs/ui": "^2.0.0",
54
54
  "@openrouter/sdk": "^1.2.80",
55
- "@zenera/neo": "^1.1.23",
55
+ "@zenera/neo": "^1.1.24",
56
56
  "google-auth-library": "^10.0.0",
57
57
  "ink": "^7.1.1",
58
58
  "openai": "^6.0.0",
@@ -47,7 +47,8 @@ visible in `agents.yaml` and that `zen check` does not report.** Before
47
47
  reviewing or changing a project, list the capabilities it has turned on and load
48
48
  the editor skill for each one - `zen-memory` for a `memory:` block,
49
49
  `zen-sandbox` for sandbox configuration or shell tools, `zen-rag-schema` or
50
- `zen-rag-docs` for an index, `zen-cli` always. A capability that is already
50
+ `zen-rag-docs` for an index, `zen-sandbox-capacity` before any `zen run batch`,
51
+ `zen-cli` always. A capability that is already
51
52
  configured and already passing `zen check` is exactly the case that looks
52
53
  finished and is not: the obligation lives in the skill, so a review that never
53
54
  opens the skill cannot find what is missing. This applies whatever prompted the
@@ -810,7 +811,7 @@ committed shows up as a skill with no files.
810
811
  ### 3.5 Tools
811
812
 
812
813
  A tool is what an agent can _do_ rather than say. `zen run` provides three
813
- groups - the workspace tools (§3.6), the sandbox tools (§3.7) and the web tools
814
+ groups - the file tools (§3.6), the sandbox tools (§3.7) and the web tools
814
815
  (§3.8) - and `agents.yaml` decides which agent holds which. Nothing else reaches
815
816
  the machine, so `tools:` is the whole permission model: an agent that does not
816
817
  name a tool cannot use it, whatever its prompt says.
@@ -846,6 +847,7 @@ them cannot see a file at all.
846
847
  | `find_files` | Paths containing a substring, case-insensitive |
847
848
  | `write_file` | Creates or overwrites a whole file, making parent directories |
848
849
  | `apply_patch` | Edits by surrounding context rather than line numbers; several files atomically |
850
+ | `copy_file` | Copies, bytes never touching the context; the source may be a read-only mount |
849
851
  | `move_file` | Moves or renames; refuses to clobber without `overwrite` |
850
852
  | `delete_file` | Deletes; a directory needs `recursive` |
851
853
 
@@ -876,8 +878,8 @@ agents:
876
878
  tools: [files:*]
877
879
 
878
880
  - name: reviewer
879
- # Everything except the four that can change something.
880
- tools: [files:*, -write_file, -apply_patch, -move_file, -delete_file]
881
+ # Everything except the five that can change something.
882
+ tools: [files:*, -write_file, -apply_patch, -copy_file, -move_file, -delete_file]
881
883
  ```
882
884
 
883
885
  Selectors apply in the order written, so a `-` line reads as an exception to the
@@ -1638,7 +1640,9 @@ over one connection.
1638
1640
  | `includeThoughts` | gemini | Thought summaries; default `true` |
1639
1641
  | `routing` / `fallbacks` | openrouter | Upstream provider preferences, and models to fall back to - §7.5 |
1640
1642
 
1641
- Knobs that do not apply to the chosen vendor are ignored, not rejected.
1643
+ Knobs that do not apply to the chosen vendor are rejected, not dropped: the
1644
+ schema accepts every one on every model, and building it fails with `does not
1645
+ read "<knob>"`. `zen check` reports the same thing as `model.knob`.
1642
1646
  `api:` exists only for the OpenAI protocol - naming it on a Gemini or Anthropic
1643
1647
  model is an error.
1644
1648
 
@@ -2012,7 +2016,8 @@ candidates; these are the judgements to make about each one)**
2012
2016
  - [ ] No agent holds `write_file` without `apply_patch`, or `read_file` without
2013
2017
  `list_dir` and `find_files`
2014
2018
  - [ ] An agent that only reads is not holding `write_file`, `apply_patch`,
2015
- `move_file` or `delete_file` - subtract them from `files:*` (or `workspace:*`)
2019
+ `copy_file`, `move_file` or `delete_file` - subtract them from `files:*`
2020
+ (or `workspace:*`)
2016
2021
  - [ ] `sandbox:*` is granted only where a shell is actually needed
2017
2022
  - [ ] `sandbox.persist: true`, unless a throwaway rootfs is wanted on purpose
2018
2023
  - [ ] The `sandbox:` image carries what the work needs, rather than the prompt
@@ -0,0 +1,251 @@
1
+ ---
2
+ description: Fine-tune this project against a training set in two stages - first without memory, tuning the prose; then with memory, tuning recall for speed.
3
+ ---
4
+
5
+ Tune this project against real queries. Nothing here touches model weights: the
6
+ parameters are the agent prompts, the skills and the house rules under `agents/`,
7
+ and the evidence is the trajectories the queries produce.
8
+
9
+ **Load the `zen-finetune` skill before anything else**, and load `zen-inspect`
10
+ before you grade, `zen-instructions` before you write a policy file, and
11
+ `zen-sandbox-capacity` if a batch dies at 137 or 124. This prompt is the order of
12
+ the work; the skill is how each step is done, and it holds the rules that are
13
+ easy to get wrong.
14
+
15
+ This prompt is **reentrant**. Tuning is long and gets interrupted - a batch dies,
16
+ a session ends, I stop you mid-round. Every step leaves its result on disk under
17
+ `.finetune/`, so a second invocation does not start over: it reads that state,
18
+ works out which stage and which step the work stopped at, says so, and carries
19
+ on from there unless I tell you otherwise.
20
+
21
+ ## The two stages
22
+
23
+ This is two stages, run in order, never interleaved. Say which stage you are in
24
+ at the top of every report.
25
+
26
+ **Stage 1 - without memory.** Every batch runs against an empty memory, so every
27
+ run starts from nothing and the result is attributable to the prose. Here you
28
+ tune agent prompts, `agents/instructions.md`, and the project's skills - creating
29
+ or updating them. The runs still _write_ memory, into their own throwaway graphs,
30
+ and what they write is graded too: the commits have to be generalisable, durable
31
+ facts, not cached live readings. Stage 1 optimises **correctness**.
32
+
33
+ **Stage 2 - with memory.** Only once stage 1 is stable and well behaved. The
34
+ prompts, skills and house rules are now frozen; the merged memory from the last
35
+ good cold batch is copied to every item, which reads it and writes into its own
36
+ copy, and the only file you edit is `agents/memory-policy-instructions.md`.
37
+ Stage 2 optimises **memory use and memory correctness**, and the expected result
38
+ is a dramatic drop in tokens and wall clock through reuse, with no verdict
39
+ changed.
40
+
41
+ Do not start stage 2 while any sample still fails cold. Memory will hide the
42
+ defect and it will come back the day the graph is rebuilt.
43
+
44
+ ## Where you are - work this out before anything else
45
+
46
+ Do this every time this prompt runs, including the first - on a project that has
47
+ never been tuned it costs one `ls` and tells you to start at section 0.
48
+
49
+ ```sh
50
+ ls .finetune/dataset.json .finetune/rounds 2>/dev/null
51
+ for r in .finetune/rounds/*/; do
52
+ printf '%s ' "$r"
53
+ for f in cases.json batch/batch.json findings.md changes.md; do
54
+ [ -e "$r$f" ] && printf '%s ' "$f"
55
+ done
56
+ echo
57
+ done
58
+ ```
59
+
60
+ The rounds are ordered by name, so the last one is the live one. Read its
61
+ `findings.md` heading for the stage - it says `COLD` or `WARM` - and its
62
+ `changes.md` for what was already applied. Then resume by the artefacts the round
63
+ is missing:
64
+
65
+ | State of the last round | Where the work stopped | Resume at |
66
+ | --------------------------------------- | ----------------------------------- | -------------------------------------------------------------------------- |
67
+ | no `.finetune/` at all | nothing has been done | section 0, then 1 |
68
+ | `dataset.json`, no `rounds/` | dataset built, never sampled | section 2 (stage 1) |
69
+ | `cases.json` only | sampled, batch never started | preflight, then run the batch into this same round |
70
+ | `batch/` present, no `batch/batch.json` | the batch was interrupted or killed | the round is **void** - see below, then re-run it |
71
+ | `batch/batch.json`, no `findings.md` | the batch finished, nothing graded | section 3 - `collect.sh oom` first |
72
+ | `findings.md`, no `changes.md` | graded, nothing applied yet | section 4 |
73
+ | `findings.md` and `changes.md` | edits applied, never measured | re-run the same cases into a **new** round: section 5 cold, section 6 warm |
74
+ | the last round's heading says `WARM` | stage 2 is in progress | the same rows, read against section 6 |
75
+
76
+ Two things the table does not see, so check them by hand:
77
+
78
+ - **Uncommitted edits under `agents/` with no `changes.md` to explain them.** An
79
+ apply was interrupted part-way. Read `git status --short agents/` and the diff,
80
+ finish writing `changes.md` from what is actually on disk, then re-run - do not
81
+ layer new edits on top of edits you have not recorded.
82
+ - **`zen check` before you resume anything.** A project left broken mid-edit
83
+ fails every item identically and looks like a catastrophic regression.
84
+
85
+ A round whose batch never wrote `batch.json` produced no evidence. Move it aside
86
+ rather than grading it or deleting it - `mv .finetune/rounds/rN/batch
87
+ .finetune/rounds/rN/batch.partial` - and re-run that round from the same
88
+ `cases.json`. The same applies to a round `collect.sh oom` calls void.
89
+
90
+ Resuming never re-samples and never re-merges. Re-use the first round's
91
+ `cases.json` and, in stage 2, the merged graph already sitting in the stage's
92
+ round directory - an interruption is not a reason to change the thing every
93
+ earlier round was measured against. Re-derive nothing from memory of the last
94
+ session either: `findings.md` and `changes.md` are the record, so read them.
95
+
96
+ Then tell me, in three lines before you do any work: which stage, which round and
97
+ step you are resuming at, and what you are about to run. Continue without waiting
98
+ for me up to the next natural checkpoint - the end of a round's report - because
99
+ that is where this prompt already stops and asks. If I named a stage or a round,
100
+ do that instead of what the state says.
101
+
102
+ **If nothing is left to do** - the last round is WARM, it met the stage-2 exit
103
+ criteria, and no prose or policy edit has landed since - do not start another
104
+ tuning round. Run one confirmation round instead: the same `cases.json`, the same
105
+ merged graph, the same flags, the same machine, into
106
+ `.finetune/rounds/rN-verify/`. Grade it, write `findings.md` with the heading
107
+ `VERIFIED` if no verdict regressed and the saving still holds, and change nothing.
108
+ If something did regress, that is a real finding: report it and re-open the stage
109
+ it belongs to.
110
+
111
+ ## 0. Before the first round
112
+
113
+ Name the training set. If I have not given you one, ask - a specification
114
+ section, a file of examples, a transcript, a CSV. Fewer than about eight queries
115
+ is a debugging session, not a tuning loop; say so and read the runs singly
116
+ instead.
117
+
118
+ Then run the mechanical checks and report what they say:
119
+
120
+ ```sh
121
+ zen check
122
+ .github/skills/zen-review/scripts/check-paths.sh
123
+ ```
124
+
125
+ A project that does not load fails every item for one reason. Do not start a
126
+ round until `zen check` passes.
127
+
128
+ ## 1. Dataset
129
+
130
+ Build `.finetune/dataset.json` if it is not there, and read it if it is. Read the
131
+ source yourself and write the structure out - do not write a parser. Rubrics are
132
+ copied **verbatim**, one entry per bullet. Classify only the distinctions the
133
+ source already makes, and rate complexity by the trajectory the query demands,
134
+ not by the length of the sentence. Keep ids stable across re-extractions.
135
+
136
+ ## 2. Stage 1: sample, preflight, run cold
137
+
138
+ ```sh
139
+ .github/skills/zen-finetune/scripts/sample.sh -n 16 --seed 1 -o .finetune/rounds/r1/cases.json
140
+ .github/skills/zen-sandbox-capacity/scripts/preflight_sandbox.sh --concurrency 8
141
+ zen run batch --input .finetune/rounds/r1/cases.json \
142
+ --batch-dir .finetune/rounds/r1/batch --memory .finetune/empty --concurrency 8
143
+ ```
144
+
145
+ Every stage-1 round is cold and every round re-uses the first round's
146
+ `cases.json`. A warm graph lets a run succeed by recall instead of by
147
+ instruction, and a re-sampled batch means a moved score has two causes and you
148
+ cannot tell which.
149
+
150
+ ## 3. Stage 1: grade
151
+
152
+ `collect.sh oom` first - a round with any exit 137 is void, is not graded, and
153
+ its tokens are compared to nothing. Then read the graphs before the numbers.
154
+ Grade every item against all eight criteria in the skill: rubric compliance,
155
+ optimality, memory hygiene, fork, delegation, tools and skills, grounding,
156
+ failure handling. **Cite a node id for every finding.** A finding you cannot
157
+ point at in the graph did not happen.
158
+
159
+ Grade the memory each item _wrote_ as seriously as the answer it gave. Read
160
+ `<id>/memory/` across the batch: every commit should be an operation, a pointer,
161
+ a shape or a rule that is still true next week. A cached live reading poisons
162
+ every future run, and committing nothing after learning something durable throws
163
+ the round away. Commit policy is fixed here, cold, while the cause is still
164
+ attributable - not in stage 2.
165
+
166
+ Write `.finetune/rounds/rN/findings.md`: the verdict block first - `PROGRESS`,
167
+ `NO CHANGE`, `REGRESSION`, `MIXED` or `VOID`, the `memory:` and `machine:` lines
168
+ as printed, and the `compare` table - then the per-sample grading. The heading
169
+ says `COLD` or `WARM`.
170
+
171
+ ## 4. Stage 1: generalise, then apply
172
+
173
+ Collect every finding into one table before writing a word of instruction. The
174
+ unit of change is a pattern across findings, not a finding: three items missing
175
+ the same beat is a rule, one item is a note in `findings.md`. Write the rule one
176
+ level up from the sample that produced it - a rule that names the dataset's own
177
+ endpoints makes the eval pass and the product fail. Prefer mechanical wording,
178
+ and remember that a prohibition with a self-judged exemption is a permission.
179
+
180
+ Route each rule by what kind of thing it is: one agent's behaviour to its prompt,
181
+ a fact or a procedure to a skill - update an existing one or create a new one, a
182
+ standing rule to `agents/instructions.md`, a rule about one capability to a new
183
+ `agents/<topic>-policy-instructions.md`.
184
+
185
+ You may edit prompts, skills, house rules and new policy files. You may not edit
186
+ `agents/memory-instructions.md`, `agents/fork-instructions.md`,
187
+ `agents/tools-instructions.md` or `agents/files-instructions.md` - `zen check
188
+ --fix` overwrites them. You may not change a rubric to make a run pass. Tell me
189
+ before you change `agents.yaml`; that finding is structural.
190
+
191
+ Record every edit and the finding numbers behind it in
192
+ `.finetune/rounds/rN/changes.md`, then run `zen check` again.
193
+
194
+ ## 5. Stage 1: loop, and leave the stage
195
+
196
+ Re-run the same cases into a new round directory and compare per sample and on
197
+ the aggregate. The verdict column decides, not the token column. A sample that
198
+ passed and now fails is the most valuable result in the round and is almost
199
+ always the new instruction. If the instruction files grew by a third and the
200
+ score moved by one sample, revert and say so.
201
+
202
+ Report to me after each round and wait: the verdict block, what you changed, and
203
+ what you propose to change next. Stop when a round produces no generalisable
204
+ pattern - that is the remaining failure being the model's rather than the prose's.
205
+
206
+ Stage 1 ends when, on one cold round, **every sample holds** and **what the runs
207
+ wrote to memory is worth keeping**. Tell me both before proposing stage 2.
208
+
209
+ ## 6. Stage 2: memory
210
+
211
+ Freeze the prompts, the skills and the house rules. Merge the last good cold
212
+ round's memory into one graph, read `zen memory stats`, and run the same cases
213
+ against it with the same flags the cold round used - `--memory <merged graph>`
214
+ and nothing else. Each item copies that graph, recalls from the copy and writes
215
+ back into the copy, so every item starts from the same memory and the source is
216
+ left untouched. Do not use `--memory-read-only`: it removes the commit tool and
217
+ changes the memory prose, which would make the warm round differ from its cold
218
+ baseline in two ways instead of one.
219
+
220
+ Compare against the cold round the memory came from.
221
+
222
+ The target is reuse: recall should replace the discovery the cold runs repeated
223
+ every time, so the warm batch is dramatically cheaper in tokens, calls and wall
224
+ clock with no verdict changed. A warm round that costs about the same, or more,
225
+ means memory was carried and not used - that is a recall-timing finding, not a
226
+ reason for more memory. A warm round that is much cheaper still needs one
227
+ trajectory opened to confirm the saving is recall replacing _discovery_ and not
228
+ recall replacing a _live reading_.
229
+
230
+ Grade what the warm items committed as well as what they recalled - this is the
231
+ one place it can be seen. A node that duplicates something the same run just
232
+ recalled is waste, and a correction committed without `SUPERSEDES` beside the
233
+ stale node it contradicts is worse than waste.
234
+
235
+ In stage 2 the only file you edit is `agents/memory-policy-instructions.md`. Keep
236
+ the merged graph byte-identical for the whole stage: do not re-merge between
237
+ rounds, and never merge a warm round's own copies back into it - either changes
238
+ the memory and the prose at once. If a finding cannot be written as a recall or
239
+ re-commit rule, it is a stage-1 finding that escaped - tell me, and we re-open
240
+ stage 1.
241
+
242
+ Stage 2 ends when no verdict regressed, the saving is obvious next to the noise
243
+ floor, every large saving is explained, and nothing was committed that memory
244
+ already held.
245
+
246
+ Commit `dataset.json`, `cases.json`, `findings.md` and `changes.md` - they are
247
+ the eval history, and they are what a resumed session reads to find out where it
248
+ got to. Write each of them as its step ends rather than at the end of the round,
249
+ so an interruption never costs more than the step it lands in. Add
250
+ `.finetune/rounds/*/batch/` and `.finetune/empty/` to `.gitignore` - the batch
251
+ directories are large and may hold live API responses.
@@ -17,14 +17,15 @@ failed, `2` usage, `3` invalid project, `4` no usable credential, `5` sandbox.
17
17
 
18
18
  ```
19
19
  zen init [dir] [--name <name>] [--model <ref>] [--force]
20
- zen list [--sessions] [--prune]
20
+ zen list [--sessions] [--runs] [--limit <n>] [--prune]
21
21
  zen run [project] [prompt] [options]
22
+ zen run batch --input <file> [--batch-dir <dir>] [--concurrency <n>] [--memory-read-only]
22
23
  zen open [project] [--editor <cmd>] [--wait]
23
24
  zen key <ls|add|use|check|rm|show|env> [ref] [options]
24
25
  zen models <providers|ls|search|show|test|pick> [ref] [options]
25
26
  zen check [name|dir] [--project <name|dir>] [--no-sandbox] [--no-models] [--strict] [--quiet]
26
- zen inspect [run] [--session <id>] [--open] [--rebuild] [--serve [port]]
27
- zen memory [stats|ls|show|export|merge|forget] [args] [options]
27
+ zen inspect [report|graph|node|ask] [run] [--dir <run dir>] [--part <name>] [--full] [--open]
28
+ zen memory [stats|ls|search|grep|show|export|merge|forget] [args] [options]
28
29
  zen export [project] [--out <file>] [--no-vectors] [--no-memory] [--force]
29
30
  zen import <file.zip> [dir] [--name <name>] [--force] [--no-register]
30
31
  zen sandbox [status|up|pull|clean|disk] [options]
@@ -46,11 +47,13 @@ guess a flag, and do not read them all.
46
47
  | Global flags, `--json`, exit codes, environment, where files live | [frame.md](./references/frame.md) |
47
48
  | Creating, finding or opening a project | [projects.md](./references/projects.md) |
48
49
  | Running: the TUI, one-shot answers, sessions, workspaces, overrides | [run.md](./references/run.md) |
50
+ | Many questions at once: `zen run batch`, its file, where answers go | [run.md](./references/run.md) |
49
51
  | Validating: `zen check`, what it can and cannot see | [check.md](./references/check.md) |
50
52
  | API keys, providers, the keyring, "no credential" errors | [keys.md](./references/keys.md) |
51
53
  | Which models exist, whether one works, recovering from a refusal | [models.md](./references/models.md) |
52
54
  | The container shell commands run in, images, `persist` | [sandbox.md](./references/sandbox.md) (and `zen-sandbox` skill) |
53
55
  | Run reports, trajectories, what a session directory holds | [inspect.md](./references/inspect.md) |
56
+ | Reading a run yourself: the node graph, opening a node by id | [inspect.md](./references/inspect.md) (and `zen-inspect` skill) |
54
57
  | What the agents remember, why something was recalled, forgetting | [memory.md](./references/memory.md) |
55
58
  | Sharing a project: archives, what travels, importing one safely | [export.md](./references/export.md) |
56
59
  | `zen faker` - a mock API from an OpenAPI/Swagger document | [faker.md](./references/faker.md) |
@@ -63,7 +66,10 @@ zen init scaffold a project here, pick a model
63
66
  zen check validate everything before spending a turn
64
67
  zen run the TUI
65
68
  zen run "what changed?" one answer, this directory as the workspace
69
+ zen run batch --input cases.json many questions at once, each isolated
66
70
  zen inspect --open what the model was actually given
71
+ zen inspect graph --dir <run dir> the same run as a graph you can read
72
+ zen inspect node n14..n20 --dir <d> the nodes behind the ids, in full
67
73
  zen memory export --open the whole memory graph, as a page
68
74
  zen export the project as a zip you can send
69
75
  zen import a.zip unpack one somebody sent, run nothing in it
@@ -73,9 +73,9 @@ assets.missing assets.overbroad sandbox.dockerfile.missing
73
73
  sandbox.build sandbox.smoke sandbox.start / .unchecked
74
74
  sandbox.pin.stale sandbox.pin.absent
75
75
  provider.invalid model.none model.unresolvable
76
- model.refused model.unreachable model.unusable
77
- embedding.refused embedding.unreachable embedding.unusable
78
- credential.* service.credential
76
+ model.knob model.refused model.unreachable
77
+ model.unusable embedding.refused embedding.unreachable
78
+ embedding.unusable credential.* service.credential
79
79
  ```
80
80
 
81
81
  The report goes to **stdout** - it is the answer. `--json` gives the same
@@ -87,8 +87,10 @@ required it.
87
87
 
88
88
  ### What it cannot catch
89
89
 
90
- Combinations that are only rejected by the provider at the first call. The
91
- known one: **OpenAI reasoning and tools only meet on the responses API.** A
90
+ Combinations that are only rejected by the provider at the first call. A knob
91
+ written for the wrong vendor is no longer one of them - `model.knob` names it,
92
+ and building the model refuses outright. The known one that remains:
93
+ **OpenAI reasoning and tools only meet on the responses API.** A
92
94
  model with `reasoningEffort` and tools on the default chat-completions API is a
93
95
  valid configuration that fails at runtime with _"Function tools with
94
96
  reasoning_effort are not supported … in /v1/chat/completions"_. Set