@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.
- package/README.md +53 -0
- package/dist/ask.js +28 -5
- package/dist/banner.js +2 -2
- package/dist/batch.d.ts +6 -0
- package/dist/batch.js +76 -1
- package/dist/catalog.d.ts +11 -1
- package/dist/catalog.js +80 -7
- package/dist/commands/inspect.d.ts +47 -1
- package/dist/commands/inspect.js +167 -18
- package/dist/commands/memory.js +128 -29
- package/dist/commands/meta.js +311 -21
- package/dist/commands/models.js +96 -12
- package/dist/commands/open.js +4 -4
- package/dist/commands/run.js +38 -4
- package/dist/commands/sandbox.js +76 -14
- package/dist/engine.d.ts +5 -0
- package/dist/engine.js +1 -0
- package/dist/eventlog.d.ts +59 -0
- package/dist/eventlog.js +146 -0
- package/dist/liveness.d.ts +7 -0
- package/dist/liveness.js +15 -1
- package/dist/meta/editor.d.ts +9 -0
- package/dist/meta/editor.js +60 -0
- package/dist/meta/finetune/children.d.ts +8 -0
- package/dist/meta/finetune/children.js +76 -0
- package/dist/meta/finetune/command.d.ts +30 -0
- package/dist/meta/finetune/command.js +338 -0
- package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
- package/dist/meta/finetune/dataset/anchors.js +239 -0
- package/dist/meta/finetune/dataset/changes.d.ts +36 -0
- package/dist/meta/finetune/dataset/changes.js +319 -0
- package/dist/meta/finetune/dataset/command.d.ts +17 -0
- package/dist/meta/finetune/dataset/command.js +1011 -0
- package/dist/meta/finetune/dataset/drift.d.ts +33 -0
- package/dist/meta/finetune/dataset/drift.js +71 -0
- package/dist/meta/finetune/dataset/export.d.ts +26 -0
- package/dist/meta/finetune/dataset/export.js +51 -0
- package/dist/meta/finetune/dataset/index.d.ts +2 -0
- package/dist/meta/finetune/dataset/index.js +2 -0
- package/dist/meta/finetune/dataset/sample.d.ts +50 -0
- package/dist/meta/finetune/dataset/sample.js +197 -0
- package/dist/meta/finetune/dataset/schema.d.ts +33 -0
- package/dist/meta/finetune/dataset/schema.js +216 -0
- package/dist/meta/finetune/dataset/store.d.ts +35 -0
- package/dist/meta/finetune/dataset/store.js +177 -0
- package/dist/meta/finetune/dataset/types.d.ts +125 -0
- package/dist/meta/finetune/dataset/types.js +39 -0
- package/dist/meta/finetune/failure.d.ts +15 -0
- package/dist/meta/finetune/failure.js +26 -0
- package/dist/meta/finetune/feedback.d.ts +45 -0
- package/dist/meta/finetune/feedback.js +85 -0
- package/dist/meta/finetune/improvements.d.ts +51 -0
- package/dist/meta/finetune/improvements.js +244 -0
- package/dist/meta/finetune/index.d.ts +2 -0
- package/dist/meta/finetune/index.js +2 -0
- package/dist/meta/finetune/journal.d.ts +35 -0
- package/dist/meta/finetune/journal.js +135 -0
- package/dist/meta/finetune/live.d.ts +74 -0
- package/dist/meta/finetune/live.js +226 -0
- package/dist/meta/finetune/loop.d.ts +3 -0
- package/dist/meta/finetune/loop.js +114 -0
- package/dist/meta/finetune/memories.d.ts +47 -0
- package/dist/meta/finetune/memories.js +154 -0
- package/dist/meta/finetune/report.d.ts +33 -0
- package/dist/meta/finetune/report.js +1284 -0
- package/dist/meta/finetune/retry.d.ts +24 -0
- package/dist/meta/finetune/retry.js +96 -0
- package/dist/meta/finetune/sampler.d.ts +18 -0
- package/dist/meta/finetune/sampler.js +41 -0
- package/dist/meta/finetune/system.d.ts +27 -0
- package/dist/meta/finetune/system.js +132 -0
- package/dist/meta/finetune/train.d.ts +39 -0
- package/dist/meta/finetune/train.js +391 -0
- package/dist/meta/finetune/tui.d.ts +16 -0
- package/dist/meta/finetune/tui.js +291 -0
- package/dist/meta/finetune/tuning.d.ts +167 -0
- package/dist/meta/finetune/tuning.js +289 -0
- package/dist/meta/finetune/usage.d.ts +62 -0
- package/dist/meta/finetune/usage.js +225 -0
- package/dist/meta/host.d.ts +14 -0
- package/dist/meta/host.js +20 -0
- package/dist/meta/index.d.ts +11 -0
- package/dist/meta/index.js +11 -0
- package/dist/meta/launch.d.ts +81 -0
- package/dist/meta/launch.js +286 -0
- package/dist/meta/model.d.ts +44 -0
- package/dist/meta/model.js +119 -0
- package/dist/meta/prompts.d.ts +18 -0
- package/dist/meta/prompts.js +61 -0
- package/dist/meta/relay.d.ts +20 -0
- package/dist/meta/relay.js +123 -0
- package/dist/meta/tokens.d.ts +52 -0
- package/dist/meta/tokens.js +226 -0
- package/dist/meta/window.d.ts +61 -0
- package/dist/meta/window.js +198 -0
- package/dist/meta/wire.d.ts +42 -0
- package/dist/meta/wire.js +129 -0
- package/dist/modelref.d.ts +16 -0
- package/dist/modelref.js +41 -0
- package/dist/narrate.js +5 -2
- package/dist/podman.d.ts +26 -0
- package/dist/podman.js +83 -3
- package/dist/projects.d.ts +0 -5
- package/dist/projects.js +2 -15
- package/dist/sandbox.d.ts +2 -0
- package/dist/sandbox.js +10 -3
- package/dist/scaffold.d.ts +15 -6
- package/dist/scaffold.js +5 -60
- package/dist/session.js +4 -29
- package/dist/term.d.ts +2 -0
- package/dist/term.js +11 -2
- package/dist/trace.js +53 -2
- package/dist/tui/models.d.ts +33 -0
- package/dist/tui/models.js +389 -0
- package/dist/tui/wrap.d.ts +5 -0
- package/dist/tui/wrap.js +12 -0
- package/dist/usage.d.ts +78 -0
- package/dist/usage.js +51 -0
- package/package.json +3 -2
- package/templates/editor/.github/copilot-instructions.md +31 -102
- package/templates/editor/.github/prompts/analyze.prompt.md +31 -0
- package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
- package/templates/editor/.github/prompts/finetune-apply.prompt.md +91 -0
- package/templates/editor/.github/prompts/finetune.prompt.md +691 -198
- package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
- package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
- package/templates/editor/.github/prompts/project-review.prompt.md +4 -3
- package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +483 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -1
- package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
- package/templates/editor/.github/skills/zen-cli/references/finetune.md +77 -0
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +47 -9
- package/templates/editor/.github/skills/zen-cli/references/memory.md +33 -10
- package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
- package/templates/editor/.github/skills/zen-cli/references/models.md +5 -1
- package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +10 -1
- package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
- package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
- package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
- package/templates/editor/.github/skills/zen-finetune/SKILL.md +1449 -658
- package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
- package/templates/editor/.github/skills/zen-inspect/SKILL.md +60 -25
- package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +270 -0
- package/templates/editor/.github/skills/zen-memory/SKILL.md +18 -14
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
- package/templates/editor/.github/skills/zen-review/SKILL.md +5 -3
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -4
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +7 -3
- package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -2
- package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
- package/templates/editor/.vscode/settings.json +1 -0
- package/templates/project/agents/files-instructions.md +29 -20
- package/templates/project/agents/memory-instructions.md +31 -32
- package/templates/project/agents/tools-instructions.md +7 -4
- package/templates/project/gitignore +2 -0
- package/dist/meta.d.ts +0 -221
- package/dist/meta.js +0 -684
- package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +0 -432
- package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +0 -199
|
@@ -1,114 +1,313 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Fine-tune this project against a training set
|
|
2
|
+
description: Fine-tune this project against a training set, a batch at a time - every batch first with no memory, fixing the instructions, then with the memory it just built, making the same work cheaper - starting from a 3-case smoke test and doubling each smooth batch, until every case is used and no difficult case is open.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
Tune this project against real queries. Nothing here touches model weights:
|
|
6
|
-
|
|
7
|
-
and the evidence is the trajectories the
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
`zen-
|
|
12
|
-
|
|
13
|
-
easy to get wrong.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
or
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
5
|
+
Tune this project against real queries. Nothing here touches model weights: what
|
|
6
|
+
changes is the prose the project is made of - the agent prompts, the skills and
|
|
7
|
+
the house rules under `agents/` - and the evidence is the trajectories the
|
|
8
|
+
queries produce.
|
|
9
|
+
|
|
10
|
+
**Load the `zen-finetune` skill before anything else**, and load `zen-inspect`,
|
|
11
|
+
`zen-analyze-run`, `zen-topology` and `zen-inspect-ask` before you grade, and
|
|
12
|
+
`zen-instructions` before you write a policy file. This prompt is the order of the work; the skill
|
|
13
|
+
is how each step is done, and it holds the rules that are easy to get wrong. If
|
|
14
|
+
loading a skill fails, read `.github/skills/<name>/SKILL.md` with your file tool
|
|
15
|
+
before going on - never carry on without it.
|
|
16
|
+
|
|
17
|
+
**Read runs and memories through commands, never by code.** Do not open
|
|
18
|
+
`output.json`, `batch.json`, `state.json`, `graph.json` or `manifest.json` with
|
|
19
|
+
`node -e`, `python -c`, `jq` or a script of your own - every question has a
|
|
20
|
+
command:
|
|
21
|
+
|
|
22
|
+
| Question | Command |
|
|
23
|
+
| -------------------------------------------- | ----------------------------------------------------------------- |
|
|
24
|
+
| each case's trajectory directory | `report.mjs -d "$RUN/batch" paths [id...]` |
|
|
25
|
+
| what each case answered, under its rubric | `report.mjs -d "$RUN/batch" answers [id...]` |
|
|
26
|
+
| what each case committed to memory | `report.mjs -d "$RUN/batch" commits [id...]` |
|
|
27
|
+
| every recall and memory tool step | `report.mjs -d "$RUN/batch" recalls [id...]` |
|
|
28
|
+
| one memory node in full | `zen memory show <node-id> --dir "$RUN/batch/<id>/memory"` |
|
|
29
|
+
| a whole memory, or what one added to another | `zen memory ls --dir <dir>`, `zen memory diff <base> --dir <dir>` |
|
|
30
|
+
|
|
31
|
+
This prompt is **reentrant**. Tuning is long and gets interrupted - a run dies, a
|
|
32
|
+
session ends, I stop you mid-batch. Every step leaves its result on disk under
|
|
33
|
+
`finetune/`, so a second invocation does not start over: it reads that state,
|
|
34
|
+
works out where the work stopped, says so, and carries on from there unless I
|
|
35
|
+
tell you otherwise.
|
|
36
|
+
|
|
37
|
+
## Words used here
|
|
38
|
+
|
|
39
|
+
Use these words, and only these, in everything you write - findings, README,
|
|
40
|
+
reports to me. Two words for one thing is how a reader loses the thread.
|
|
41
|
+
|
|
42
|
+
| Word | Means |
|
|
43
|
+
| -------------------- | -------------------------------------------------------------------------------------------- |
|
|
44
|
+
| **case** | one query from the training set, with its rubric if it has one |
|
|
45
|
+
| **dataset** | every case in the training set, `finetune/dataset.json` - never cut down |
|
|
46
|
+
| **limit** | how many cases this tuning uses - the whole dataset, unless I gave a smaller number |
|
|
47
|
+
| **selection** | those cases, evenly by class, rubric and complex first, `finetune/selection.json` |
|
|
48
|
+
| **batch** | the cases worked on together until they pass without memory and then with it |
|
|
49
|
+
| **batch size** | how many new cases a batch takes - 3 for batch 1, doubling after each smooth batch, to a max |
|
|
50
|
+
| **recheck cases** | cases from earlier batches, run again - difficult ones first, then complex ones |
|
|
51
|
+
| **run** | one execution of a batch's cases - a no-memory run or a with-memory run |
|
|
52
|
+
| **no-memory run** | every case starts from an empty memory and writes its own: tunes the instructions |
|
|
53
|
+
| **with-memory run** | every case starts from its own copy of the candidate memory: tunes the memory policy |
|
|
54
|
+
| **proposal** | one improvement a case's grading suggests - merged with the others before anything is edited |
|
|
55
|
+
| **passed** | a run where every case is right AND its review found nothing left to cut |
|
|
56
|
+
| **concurrency** | how many cases execute at the same time inside a run - 16 at most, halved on OOM |
|
|
57
|
+
| **trajectory** | what one case did in one run - its graph |
|
|
58
|
+
| **difficult case** | a case that caused real trouble - listed in `finetune/difficult.json`, retested until fixed |
|
|
59
|
+
| **candidate memory** | the last good memory plus what the batch's passing no-memory run committed |
|
|
60
|
+
| **last good memory** | every passed batch's candidate, in turn; always whole on disk |
|
|
61
|
+
|
|
62
|
+
Run directories are `finetune/runs/batch<NN>-<nomem|mem>-run<N>/` -
|
|
63
|
+
`batch03-nomem-run2` is batch 3's second run without memory, `batch03-mem-run1`
|
|
64
|
+
its first with memory. Each holds a `batch/` folder: that is `zen run batch`'s
|
|
65
|
+
own output for that run, named by the command, not by this method.
|
|
66
|
+
|
|
67
|
+
## What a batch is
|
|
68
|
+
|
|
69
|
+
The selection is not run all at once. After one big run there is too much to
|
|
70
|
+
read, and after one big edit nobody can say which change helped. So it is
|
|
71
|
+
worked a **batch** at a time, and each batch is decided when it is needed:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
size = 3 for batch 1 - a smoke test
|
|
75
|
+
= twice the last batch, up to maxBatch, if it went smoothly
|
|
76
|
+
(at most 2 runs of each kind, no case put on the difficult list)
|
|
77
|
+
= the same as the last batch otherwise
|
|
78
|
+
next batch = that many new cases (not used yet: classes taking turns,
|
|
79
|
+
rubric and complex cases first)
|
|
80
|
+
+ up to recheck earlier cases (open difficult first, then fixed
|
|
81
|
+
difficult, then complex, then the rest)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then every case of the batch goes through the same fifteen steps:
|
|
85
|
+
|
|
86
|
+
**Without memory**
|
|
87
|
+
|
|
88
|
+
1. **Run** the batch with no memory.
|
|
89
|
+
2. **Analyze** every trajectory: right? what did it cost? where is it
|
|
90
|
+
suboptimal? `zen inspect ask` the model at each critical point.
|
|
91
|
+
3. **See what it committed** to memory - durable facts, or live readings?
|
|
92
|
+
4. **Propose** improvements, per case.
|
|
93
|
+
5. **Merge** the proposals of every case into patterns.
|
|
94
|
+
6. **Update** prompts, skills, house rules, policies - create what is missing.
|
|
95
|
+
7. **Run again**, no memory, the same cases.
|
|
96
|
+
8. **See** whether the edits worked and fixed everything. If not, back to 2 -
|
|
97
|
+
at most 4 no-memory runs. When every case is right and nothing is left to
|
|
98
|
+
cut, the run **passes**.
|
|
99
|
+
|
|
100
|
+
**With memory**
|
|
101
|
+
|
|
102
|
+
9. **Build the candidate**: the last good memory plus what every case of the
|
|
103
|
+
passing run committed, merged - what the graph already held is folded, not
|
|
104
|
+
added.
|
|
105
|
+
10. **Run** the batch with memory: **every case gets its own copy** of the
|
|
106
|
+
candidate.
|
|
107
|
+
11. **Analyze the memory use** - recall, savings, re-commits - with
|
|
108
|
+
`zen inspect ask` and the other tools.
|
|
109
|
+
12. **Merge** the proposals.
|
|
110
|
+
13. **Update** the memory policy.
|
|
111
|
+
14. **Run again** from the same candidate. Back to 11 until it passes - at most
|
|
112
|
+
4 with-memory runs.
|
|
113
|
+
15. **Keep it**: the candidate becomes the last good memory, and the next batch
|
|
114
|
+
is built, with the difficult and complex cases tracked for rechecks.
|
|
115
|
+
|
|
116
|
+
A run whose cases are all correct has **not** passed: that is exactly when the
|
|
117
|
+
cost work starts. Being right is the entry ticket; the tuning is making it
|
|
118
|
+
cheap - first without memory, then with it.
|
|
119
|
+
|
|
120
|
+
The recheck cases are there to fail - a rule written for batch 3 is read on every
|
|
121
|
+
query, and the case it breaks is usually in batch 1.
|
|
122
|
+
|
|
123
|
+
### Difficult cases, and why the number of batches is not fixed
|
|
124
|
+
|
|
125
|
+
Some cases cause most of the trouble. Put each on the difficult list the moment
|
|
126
|
+
grading shows it - `difficult.mjs add` - and it keeps coming back:
|
|
127
|
+
|
|
128
|
+
- **Open difficult cases come first** in every later batch's rechecks, until
|
|
129
|
+
fixed.
|
|
130
|
+
- **Fixed ones stay ahead of the other rechecks**, because what was hard once
|
|
131
|
+
breaks again first.
|
|
132
|
+
- **A batch that added one does not grow the next.**
|
|
133
|
+
- **When the selection is used up**, a batch is made of open difficult cases
|
|
134
|
+
only. So the tuning takes as many batches as it needs.
|
|
135
|
+
- **Stuck is reported, not looped.** A case still open after `maxRetries`
|
|
136
|
+
batches since it was added (default 3) is `stuck` - the model's ceiling or a
|
|
137
|
+
bad rubric - and stops being picked.
|
|
138
|
+
|
|
139
|
+
The tuning is over when **every case in the selection has been used and no
|
|
140
|
+
difficult case is open** - then comes the final check.
|
|
141
|
+
|
|
142
|
+
### The memory
|
|
143
|
+
|
|
144
|
+
When a no-memory run passes, `memory.mjs candidate <run>` copies the last good
|
|
145
|
+
memory into a new directory and merges in what each of that run's cases
|
|
146
|
+
committed. Every with-memory run of the batch starts from that candidate, a
|
|
147
|
+
copy per case, so no case's commits reach another case or the candidate. When a
|
|
148
|
+
with-memory run passes, `memory.mjs checkpoint <run>` makes the candidate the
|
|
149
|
+
last good memory - switching only when it is complete. So whenever the tuning
|
|
150
|
+
stops - finished, or killed mid-run - `memory.mjs path` names a whole graph
|
|
151
|
+
holding everything the passed batches learned, ready to promote into `memory/`.
|
|
152
|
+
|
|
153
|
+
## No memory first, then memory - in every batch
|
|
154
|
+
|
|
155
|
+
Never run them together, and never run a batch with memory before it passed
|
|
156
|
+
without. Say which kind of run you are in at the top of every report.
|
|
157
|
+
|
|
158
|
+
**No-memory runs.** Every case starts from an empty memory, so a right answer is
|
|
159
|
+
the instructions' doing and not something remembered. Here you tune agent
|
|
160
|
+
prompts, `agents/instructions.md`, the project's skills and policy files -
|
|
161
|
+
creating or updating them. The runs still _write_ memory, each into its own
|
|
162
|
+
throwaway graph, and what they write is graded too: commits must be durable,
|
|
163
|
+
generalisable facts, not cached live readings - because the candidate is built
|
|
164
|
+
from them. These runs optimise **correctness** first, then the cost of getting
|
|
165
|
+
there - fewer llm calls, then better fan-out with forks, then fewer things
|
|
166
|
+
discovered that could have been known.
|
|
167
|
+
|
|
168
|
+
**With-memory runs.** The same cases, from the candidate. They optimise **memory
|
|
169
|
+
use and memory correctness**, and the expected result is a dramatic drop in
|
|
170
|
+
tokens and wall clock with no verdict changed - and **no commit of anything the
|
|
171
|
+
memory already held**: every such commit is a call spent on nothing. The only
|
|
172
|
+
prose they edit is the memory policy - `agents/memory-policy-instructions.md`,
|
|
173
|
+
or the memory paragraph a `why` line names. A finding that needs any other
|
|
174
|
+
prose is an open problem whose cases go on the difficult list; the next batch's
|
|
175
|
+
no-memory runs fix it.
|
|
176
|
+
|
|
177
|
+
## The README
|
|
178
|
+
|
|
179
|
+
`finetune/README.md` is the page I read to know what is going on. **You write
|
|
180
|
+
it**, by hand, for a person who has never seen this project - not a log dump.
|
|
181
|
+
Start from `.github/skills/zen-finetune/references/readme-template.md`.
|
|
182
|
+
|
|
183
|
+
- **Before the first run**, write it whole: what is being tuned and why, the
|
|
184
|
+
dataset by class, the limit and how the cases were chosen, what a batch is and
|
|
185
|
+
how it grows, its two halves, the settings - and a mermaid **map** from the
|
|
186
|
+
dataset to the final check, with the batches the growth rule gives if every
|
|
187
|
+
batch is smooth drawn ahead, each with its no-memory and with-memory half.
|
|
188
|
+
- **After every step** - a run finishing, a run graded, edits applied, a
|
|
189
|
+
candidate built, a batch passing - patch it: "Where we are", the map (move
|
|
190
|
+
nodes between the `done` / `now` / `ahead` / `failed` classes, update their
|
|
191
|
+
labels, add a node when a batch the plan did not foresee is built), the
|
|
192
|
+
batch's row, "Difficult cases", a log entry, "Results so far" when a batch
|
|
193
|
+
passes, and "Next".
|
|
194
|
+
|
|
195
|
+
The map is the first thing I look at: it must always show exactly one `now` node,
|
|
196
|
+
everything behind it as done, and everything ahead of it as ahead, with a line
|
|
197
|
+
saying what is left - unused cases and open difficult ones. Link me to the README
|
|
198
|
+
in your reports instead of re-typing it.
|
|
43
199
|
|
|
44
200
|
## Where you are - work this out before anything else
|
|
45
201
|
|
|
46
|
-
Do this every time this prompt runs, including the first
|
|
47
|
-
never been tuned it costs one `ls` and tells you to start at section 0.
|
|
202
|
+
Do this every time this prompt runs, including the first:
|
|
48
203
|
|
|
49
204
|
```sh
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
|
205
|
+
.github/skills/zen-finetune/scripts/next.mjs
|
|
206
|
+
.github/skills/zen-finetune/scripts/batch.mjs # progress: used, left, next size, difficult
|
|
207
|
+
.github/skills/zen-finetune/scripts/memory.mjs # the candidate and the last good memory
|
|
58
208
|
```
|
|
59
209
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `batch
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
76
|
-
|
|
210
|
+
`next.mjs` reads the whole `finetune/` tree and prints the next step. Do not
|
|
211
|
+
re-derive the state from an `ls`. Map what it says onto this prompt:
|
|
212
|
+
|
|
213
|
+
| What `next.mjs` says | Go to |
|
|
214
|
+
| ---------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
215
|
+
| `first: patch finetune/README.md ...` | patch the README, then act on the next line |
|
|
216
|
+
| `note: limit N of T cases ...` | unless I asked for a cut: section 2, raise the limit and re-select, then carry on |
|
|
217
|
+
| `build finetune/dataset.json ...` | section 0, then 1 |
|
|
218
|
+
| `write finetune/config.json ...` | section 2 |
|
|
219
|
+
| `choose the cases: select.mjs ...` | section 2 |
|
|
220
|
+
| `write finetune/README.md: the plan ...` | section 2, the README step |
|
|
221
|
+
| `build batch 1: batch.mjs next ...` | section 3 |
|
|
222
|
+
| `... not run yet - zen run batch ...` | run exactly that, then section 4 (no memory) or 7 (with memory) |
|
|
223
|
+
| `... the run never finished ...` | the run is **void** - see below, then re-run |
|
|
224
|
+
| `batchNN-nomem-runN: not graded yet - report.mjs ... oom ...` | section 4 |
|
|
225
|
+
| `batchNN-mem-runN: not graded yet - report.mjs ... oom ...` | section 7, analyze |
|
|
226
|
+
| `... void - out of memory at concurrency C: set ...` | do exactly that - halve it, re-run the cases |
|
|
227
|
+
| `... void - ... the floor ...` | stop and tell me - the only machine stop |
|
|
228
|
+
| `... says PASSED but has no "## Cost review" ...` | section 4, the cost review |
|
|
229
|
+
| `... says PASSED but has no "## Memory review" ...` | section 7, the memory review |
|
|
230
|
+
| `batchNN-nomem-runN: graded, nothing applied ...` | section 5 |
|
|
231
|
+
| `batchNN-mem-runN: graded, nothing applied ...` | section 7, merge and update |
|
|
232
|
+
| `edits applied - confirm them: ... zen run batch ...` | run exactly that, then section 6 (no memory) or 7 (with memory) |
|
|
233
|
+
| `... says PASSED but applied edits ...` | confirm them with another run of the same kind |
|
|
234
|
+
| `batch N has had 4 ... runs - stop tuning it ...` | section 6 or 7, the run cap |
|
|
235
|
+
| `... passed without memory - build the candidate memory: ...` | section 6, the candidate |
|
|
236
|
+
| `batch N passed without memory and the candidate is built - ...` | section 7 |
|
|
237
|
+
| `batch N passed with memory - keep its memory first: ...` | section 7, the checkpoint |
|
|
238
|
+
| `batch N passed (...) - build batch N+1: batch.mjs next ...` | section 3 for the new batch |
|
|
239
|
+
| `every case used, none open ... run the final check ...` | section 8 |
|
|
240
|
+
| `done - ...` | nothing left to tune - report and stop |
|
|
241
|
+
|
|
242
|
+
Read the latest run's `findings.md` for the verdict and its `changes.md` for what
|
|
243
|
+
was already applied. Two things `next.mjs` cannot see, so check them by hand:
|
|
77
244
|
|
|
78
245
|
- **Uncommitted edits under `agents/` with no `changes.md` to explain them.** An
|
|
79
246
|
apply was interrupted part-way. Read `git status --short agents/` and the diff,
|
|
80
247
|
finish writing `changes.md` from what is actually on disk, then re-run - do not
|
|
81
248
|
layer new edits on top of edits you have not recorded.
|
|
82
249
|
- **`zen check` before you resume anything.** A project left broken mid-edit
|
|
83
|
-
fails every
|
|
84
|
-
|
|
85
|
-
A
|
|
86
|
-
rather than grading
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
`cases.json`
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
250
|
+
fails every case identically and looks like a catastrophic regression.
|
|
251
|
+
|
|
252
|
+
A run whose `batch/` never got a `batch.json` produced no evidence. Move it aside
|
|
253
|
+
rather than grading or deleting it - `mv finetune/runs/<run>/batch
|
|
254
|
+
finetune/runs/<run>/batch.partial` - and re-run from the same `cases.json`.
|
|
255
|
+
|
|
256
|
+
A run `report.mjs oom` calls void (any exit 137) is out of memory. Write
|
|
257
|
+
`## VOID` in its `findings.md`, halve `concurrency` in `finetune/config.json` -
|
|
258
|
+
never below 4 - and run a copy of its `cases.json` as the next run. A void run is
|
|
259
|
+
not graded and does not count toward the run cap. Void at concurrency 4 means
|
|
260
|
+
the machine cannot run the batch: stop and tell me.
|
|
261
|
+
|
|
262
|
+
Resuming never re-selects and never rebuilds a batch. `minBatch`, `maxBatch`,
|
|
263
|
+
`recheck` and `seed` in `finetune/config.json` are frozen once batch 1 has run.
|
|
264
|
+
Every later run of a batch - no memory or with memory - re-uses **its first
|
|
265
|
+
run's `cases.json`, copied** - never rebuilt, because the rechecks depend on the
|
|
266
|
+
difficult list, which moves. `findings.md`, `changes.md`, `difficult.json` and
|
|
267
|
+
the README are the record; read them rather than remembering.
|
|
268
|
+
|
|
269
|
+
Then tell me, in three lines before you do any work: which batch and which half
|
|
270
|
+
(no memory or with memory) you are resuming at and the limit as
|
|
271
|
+
`limit N of T cases`, which step of the fifteen, and what you are about to run -
|
|
272
|
+
and then **keep going**. If I named a batch or a run, do that instead of what
|
|
273
|
+
the state says.
|
|
274
|
+
|
|
275
|
+
### Run to the end
|
|
276
|
+
|
|
277
|
+
Once started, run the whole tuning - every batch, both halves, the final check -
|
|
278
|
+
**without stopping to ask**. Between runs, between halves and between batches,
|
|
279
|
+
report and carry on. `next.mjs` printing `done - ...` is the only normal end.
|
|
280
|
+
|
|
281
|
+
**Never end your turn to wait for a command.** A `zen run batch` outlasts the
|
|
282
|
+
wait of the tool that started it. When a tool says the command is still running,
|
|
283
|
+
read its output again in your next call (`read_bash` with a delay, or your
|
|
284
|
+
terminal's equivalent), and repeat until it has completed.
|
|
285
|
+
|
|
286
|
+
Stop and wait for me only when:
|
|
287
|
+
|
|
288
|
+
- **The machine cannot run the batch** - it ran out of memory at concurrency 4.
|
|
289
|
+
- **I asked you to pause** - after each batch, or anywhere else.
|
|
290
|
+
|
|
291
|
+
Everything that used to be a question is now a note that does not stop the work:
|
|
292
|
+
|
|
293
|
+
- **A structural finding** - the fix needs `agents.yaml`. Do not edit it; write
|
|
294
|
+
the finding under "Open problems" in the README, put the cases it blocks on the
|
|
295
|
+
difficult list, and carry on. It is in the final report.
|
|
296
|
+
- **A with-memory finding that needs other prose.** Note it under "Open
|
|
297
|
+
problems", put its cases on the difficult list, finish the batch; the next
|
|
298
|
+
batch's no-memory runs fix it.
|
|
299
|
+
|
|
300
|
+
When a batch passes, post a short note - batch, size, runs of each kind, cases
|
|
301
|
+
right, llm calls and tokens without memory first run to last and with memory
|
|
302
|
+
against without, re-commits, what changed, what is left - patch the README, and
|
|
303
|
+
build the next batch straight away. Never end your turn with "proposed next
|
|
304
|
+
step" or "ready to proceed upon your confirmation"; take the step.
|
|
305
|
+
|
|
306
|
+
`finetune/USAGE.md` is the token bill - project agents, you, and every
|
|
307
|
+
`zen inspect ask` - by model, batch, run and stage. `next.mjs` rewrites
|
|
308
|
+
it; never edit it, and link it rather than copying its numbers.
|
|
309
|
+
|
|
310
|
+
## 0. Before the first run
|
|
112
311
|
|
|
113
312
|
Name the training set. If I have not given you one, ask - a specification
|
|
114
313
|
section, a file of examples, a transcript, a CSV. Fewer than about eight queries
|
|
@@ -122,60 +321,236 @@ zen check
|
|
|
122
321
|
.github/skills/zen-review/scripts/check-paths.sh
|
|
123
322
|
```
|
|
124
323
|
|
|
125
|
-
A project that does not load fails every
|
|
126
|
-
|
|
324
|
+
A project that does not load fails every case for one reason. Do not start until
|
|
325
|
+
`zen check` passes.
|
|
326
|
+
|
|
327
|
+
## 1. Dataset - all of it
|
|
328
|
+
|
|
329
|
+
Build `finetune/dataset.json` if it is not there, and read it if it is. **Read
|
|
330
|
+
the whole training set and write every case into it** - no limit, no sampling,
|
|
331
|
+
no "the first twenty". The dataset is the record of what the project is meant to
|
|
332
|
+
handle; the limit is applied later, when cases are selected, and only there.
|
|
333
|
+
|
|
334
|
+
Read the source yourself and write the structure out - do not write a parser.
|
|
335
|
+
Rubrics are copied **verbatim**, one entry per bullet. Classify only the
|
|
336
|
+
distinctions the source already makes, and rate complexity by the trajectory the
|
|
337
|
+
query demands, not by the length of the sentence. Keep ids stable across
|
|
338
|
+
re-extractions. Report the count per class when you are done.
|
|
339
|
+
|
|
340
|
+
## 2. Settings, selection, README
|
|
341
|
+
|
|
342
|
+
**Settings.** You now know the dataset size. Set the limit, propose the batch
|
|
343
|
+
sizes, recheck and concurrency, say what each costs, and write them to
|
|
344
|
+
`finetune/config.json` - every script reads its defaults from there:
|
|
345
|
+
|
|
346
|
+
```json
|
|
347
|
+
{
|
|
348
|
+
"datasetSize": 64,
|
|
349
|
+
"limit": 64,
|
|
350
|
+
"minBatch": 3,
|
|
351
|
+
"maxBatch": 10,
|
|
352
|
+
"recheck": 3,
|
|
353
|
+
"concurrency": 13,
|
|
354
|
+
"seed": 1,
|
|
355
|
+
"maxRetries": 3
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
- **limit** - **equal to `datasetSize`**: every case in the dataset is tuned
|
|
360
|
+
against. Write a smaller number only when I gave you one. Never cut it on your
|
|
361
|
+
own to save cost or time - a limit below the dataset silently drops cases the
|
|
362
|
+
project is meant to handle.
|
|
363
|
+
- **minBatch** - new cases in batch 1, the smoke test. 3.
|
|
364
|
+
- **maxBatch** - the most new cases a batch grows to. Small enough that you will
|
|
365
|
+
actually read every trajectory; 8-12 is the usable range. `batch.mjs` doubles
|
|
366
|
+
from `minBatch` towards it after each smooth batch - you do not size batches
|
|
367
|
+
by hand. **Not the same as concurrency.**
|
|
368
|
+
- **recheck** - earlier cases re-run in each batch. 2-4. Zero means no
|
|
369
|
+
regression guard and no retesting of difficult cases.
|
|
370
|
+
- **concurrency** - the most cases running at once: `min(maxBatch + recheck, 16)`.
|
|
371
|
+
Do not size it any other way. On an out-of-memory run (exit 137) halve it,
|
|
372
|
+
never below 4, and re-run the same cases. The only setting that changes
|
|
373
|
+
mid-way.
|
|
374
|
+
- **maxRetries** - batches a difficult case gets after it is added before it is
|
|
375
|
+
`stuck`. 3.
|
|
376
|
+
|
|
377
|
+
**Selection.** Choose the cases:
|
|
378
|
+
|
|
379
|
+
```sh
|
|
380
|
+
.github/skills/zen-finetune/scripts/select.mjs -o finetune/selection.json
|
|
381
|
+
```
|
|
127
382
|
|
|
128
|
-
|
|
383
|
+
It takes the limit from the **whole** dataset, evenly by class - one case from
|
|
384
|
+
each class in turn; inside a class, cases with a rubric first, and the most
|
|
385
|
+
complex first - and that order is the order batches take new cases in, so the
|
|
386
|
+
first small batches hold the hard, graded cases. It prints chosen-versus-available
|
|
387
|
+
per class; report that table to me. A class with fewer cases than its share gives
|
|
388
|
+
all it has.
|
|
129
389
|
|
|
130
|
-
|
|
131
|
-
|
|
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.
|
|
390
|
+
**README.** Write `finetune/README.md` now, before anything runs - see "The
|
|
391
|
+
README" above.
|
|
135
392
|
|
|
136
|
-
##
|
|
393
|
+
## 3. Build a batch, run it without memory (step 1)
|
|
137
394
|
|
|
138
395
|
```sh
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
zen
|
|
142
|
-
|
|
396
|
+
RUN=finetune/runs/batch01-nomem-run1
|
|
397
|
+
C=$(node -p 'require("./finetune/config.json").concurrency')
|
|
398
|
+
.github/skills/zen-finetune/scripts/batch.mjs next -o "$RUN/cases.json"
|
|
399
|
+
zen run batch --input "$RUN/cases.json" \
|
|
400
|
+
--batch-dir "$RUN/batch" --memory finetune/empty --concurrency "$C"
|
|
143
401
|
```
|
|
144
402
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
403
|
+
`--concurrency` is always the value in `finetune/config.json` - read it fresh
|
|
404
|
+
for every run, since an out-of-memory run halves it.
|
|
405
|
+
|
|
406
|
+
`batch.mjs next` prints the size and why, which cases are new and which are
|
|
407
|
+
rechecks, and writes the same into `plan.json` beside `cases.json` - put that in
|
|
408
|
+
the README's batch row. Then patch the README: the map's `now` node, the row, a
|
|
409
|
+
log line.
|
|
410
|
+
|
|
411
|
+
Batch 1 is a smoke test. If its cases crash - the project, the sandbox, a key -
|
|
412
|
+
that is not the prose: fix it and run the three again before grading anything.
|
|
413
|
+
|
|
414
|
+
Every no-memory run has no memory. A graph with content lets a run succeed by
|
|
415
|
+
recall instead of by instruction. `finetune/empty` is never created - naming a
|
|
416
|
+
directory that does not exist is what gives each case an empty memory.
|
|
149
417
|
|
|
150
|
-
|
|
418
|
+
Never hand-write a `cases.json`, and never re-select mid-way. Build a batch once,
|
|
419
|
+
for its first no-memory run, with `batch.mjs next`; every later run of that
|
|
420
|
+
batch - no memory or with memory - gets a **copy** of that file, which is what
|
|
421
|
+
makes one run comparable to the next.
|
|
151
422
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
423
|
+
## 4. Grade without memory (steps 2-4)
|
|
424
|
+
|
|
425
|
+
`report.mjs oom` first - a run with any exit 137 is void, is not graded, and its
|
|
426
|
+
tokens are compared to nothing. Then read the answers (`report.mjs answers`) and
|
|
427
|
+
the graphs before the numbers. Grade
|
|
428
|
+
every case against all eight criteria in the skill: rubric compliance,
|
|
155
429
|
optimality, memory hygiene, fork, delegation, tools and skills, grounding,
|
|
156
430
|
failure handling. **Cite a node id for every finding.** A finding you cannot
|
|
157
431
|
point at in the graph did not happen.
|
|
158
432
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
433
|
+
Where a node shows **what** went wrong but not **why** - memory not searched,
|
|
434
|
+
lookups not forked, a skill not followed, a tool misused - ask the model at the
|
|
435
|
+
call that made the choice, once per pattern: `zen inspect ask`, worded as
|
|
436
|
+
**zen-inspect-ask** says. Load that skill before the first ask of the run, even
|
|
437
|
+
if you loaded it in an earlier run. A rule written in section 5 without the
|
|
438
|
+
sentence an ask named is a guess.
|
|
439
|
+
|
|
440
|
+
Grade in this order, because they are not equally urgent:
|
|
441
|
+
|
|
442
|
+
1. **The recheck cases.** A recheck that passed before and fails now means a
|
|
443
|
+
rule written since broke it, and that outranks every other failure in the
|
|
444
|
+
run - nothing else is worth grading until it is resolved.
|
|
445
|
+
2. **Correctness of the new cases.** Rubric compliance gates everything.
|
|
446
|
+
3. **The cost of getting there** - as soon as correctness holds, and in the same
|
|
447
|
+
run. llm calls first - read straight off the graph header - then fan-out, then
|
|
448
|
+
discovery the run should not have needed because something authoritative
|
|
449
|
+
could have told it.
|
|
450
|
+
|
|
451
|
+
**The cost review is not optional.** Every `findings.md` of a run where all cases
|
|
452
|
+
are right has a `## Cost review` section - `next.mjs` refuses a `PASSED` without
|
|
453
|
+
one. It contains:
|
|
454
|
+
|
|
455
|
+
- the llm calls per case, the batch's median, and every case above 1.5x the
|
|
456
|
+
median with the reason it cost that much, citing nodes;
|
|
457
|
+
- **repeated work** - the same call with the same arguments twice, a loop, a
|
|
458
|
+
search made as four calls that could have been one: the pattern, or `none`;
|
|
459
|
+
- **missed forks** - independent calls or sub-tasks run one after another: the
|
|
460
|
+
pattern, or `none`;
|
|
461
|
+
- **unneeded discovery** - listing, probing or reading to learn something a
|
|
462
|
+
prompt or skill could simply have stated: the pattern, or `none`;
|
|
463
|
+
- **excess prose** - every paragraph, example, table row, skill and skill
|
|
464
|
+
binding the agents carried this run that no trajectory needed: a rule nothing
|
|
465
|
+
in the run tested, a second wording of a rule stated elsewhere, a rationale
|
|
466
|
+
the model does not act on, a preloaded skill no case used, a skill bound to an
|
|
467
|
+
agent that never needs it. Grep the assembled prefix - prompt, house rules,
|
|
468
|
+
every preloaded and loaded skill - and list each with its file and lines, or
|
|
469
|
+
`none`. Every token of it is paid on every call of every case.
|
|
470
|
+
|
|
471
|
+
`none` needs the evidence for it - the trajectory you checked, not the absence
|
|
472
|
+
of a look. A case averaging 40+ llm calls almost never has `none` on all three.
|
|
473
|
+
|
|
474
|
+
**See what each case committed** (step 3), as seriously as the answer it gave.
|
|
475
|
+
Start from `report.mjs -d "$RUN/batch" memory` for the counts, then
|
|
476
|
+
`report.mjs -d "$RUN/batch" commits` for every node each case committed: every
|
|
477
|
+
commit should be an operation, a pointer, a shape or a
|
|
478
|
+
rule that is still true next week. A cached live reading poisons every future
|
|
479
|
+
run, and committing nothing after learning something durable throws the run
|
|
480
|
+
away. The candidate memory is built from exactly these commits, so commit
|
|
481
|
+
policy is fixed here, without memory, while the cause is still attributable.
|
|
482
|
+
|
|
483
|
+
**End every case with its proposals** (step 4): what that case alone says should
|
|
484
|
+
change - criterion, file, the sentence its `why` line named, the edit. They are
|
|
485
|
+
not edits yet; section 5 merges them.
|
|
486
|
+
|
|
487
|
+
Write `$RUN/findings.md`: the verdict heading first - `PROGRESS`, `NO CHANGE`,
|
|
488
|
+
`REGRESSION`, `MIXED`, `CORRECT`, `PASSED` or `VOID` - the `memory:` and
|
|
489
|
+
`machine:` lines as printed, and the `report.mjs compare` table with the recheck
|
|
490
|
+
cases marked; then the cost review; then the per-case grading, each case ending
|
|
491
|
+
in its proposals. The title names the run and says `NO MEMORY` or
|
|
492
|
+
`WITH MEMORY`. Then patch the README.
|
|
493
|
+
|
|
494
|
+
`CORRECT` means every case is right but the cost review found something worth
|
|
495
|
+
changing - apply it and run again. `PASSED` means every case is right **and** the
|
|
496
|
+
cost review found nothing worth changing, so this run applies no edits. It is
|
|
497
|
+
load-bearing: `next.mjs` reads it to move on, and refuses it on a run with a
|
|
498
|
+
`changes.md` or without a cost review. Never write it on a run that merely
|
|
499
|
+
improved, and never on a run you are about to edit after.
|
|
500
|
+
|
|
501
|
+
**Then update the difficult list** - mechanically, every graded run:
|
|
170
502
|
|
|
171
|
-
|
|
503
|
+
```sh
|
|
504
|
+
D=.github/skills/zen-finetune/scripts/difficult.mjs
|
|
505
|
+
$D add <id> --why wrong --run <run> --note "<what goes wrong>" # wrong after a run that tried to fix it
|
|
506
|
+
$D add <id> --why regressed --run <run> # a recheck case that failed
|
|
507
|
+
$D add <id> --why flaky --run <run> # right before, wrong now, no rule aimed at it
|
|
508
|
+
$D add <id> --why memory --run <run> --note "<what goes wrong>" # with memory: wrong, no cheaper, or re-commits, after a fix
|
|
509
|
+
$D add <id> --why costly --run <run> # over 2x the median llm calls in a passing run
|
|
510
|
+
$D fix <id> --run <run> # a difficult case right, in a PASSED run
|
|
511
|
+
$D # the list
|
|
512
|
+
```
|
|
172
513
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
514
|
+
A case wrong on run 1 is not difficult yet - that is what the batch is for. It
|
|
515
|
+
is difficult when it is **still** wrong after a run that tried to fix it.
|
|
516
|
+
|
|
517
|
+
## 5. Merge the proposals, then apply (steps 5-6)
|
|
518
|
+
|
|
519
|
+
If a recheck case failed, stop here and revert or narrow the rule that broke it.
|
|
520
|
+
Find it in the earlier batches' `changes.md`, undo or qualify it, record the
|
|
521
|
+
over-reach, and go straight to the next run. Adding a rule on top of a rule that
|
|
522
|
+
over-reached is how a tuning ends with prose nobody can unpick.
|
|
523
|
+
|
|
524
|
+
Otherwise: collect every case's proposals into one table before writing a word
|
|
525
|
+
of instruction - wrong answers and cost findings alike - and write it into
|
|
526
|
+
`findings.md` under `## Proposals, merged`, one row per pattern with the cases
|
|
527
|
+
and nodes behind it. Two proposals saying the same thing in different words are
|
|
528
|
+
one pattern; two proposing opposite edits to one sentence are a conflict, and
|
|
529
|
+
the conflict is the finding. A cost pattern is a rule
|
|
530
|
+
just as a correctness pattern is: "these three cases each listed the directory
|
|
531
|
+
to find a file the skill could name" becomes a line in that skill; "these ran
|
|
532
|
+
four independent lookups in sequence" becomes a fan-out rule in the prompt. The
|
|
533
|
+
unit of change is a pattern across proposals, not a proposal: three cases missing
|
|
534
|
+
the same beat is a rule, one case is a note in `findings.md`. The three do not
|
|
535
|
+
have to be in this batch - grep the earlier runs' findings before calling
|
|
536
|
+
something an anecdote. Each cost or behaviour pattern carries the sentence its
|
|
537
|
+
`zen inspect ask` named - verified by grep in the recorded request - or
|
|
538
|
+
`no instruction`: that sentence is what the rule edits. For a difficult case, read its notes (`difficult.mjs`)
|
|
539
|
+
and every earlier `findings.md` that names it first: the rules already tried and
|
|
540
|
+
failed are the most useful thing you know about it. Write the rule one level up
|
|
541
|
+
from the case that produced it; a rule that names the dataset's own endpoints
|
|
542
|
+
makes the eval pass and the product fail. Prefer mechanical wording, and
|
|
543
|
+
remember that a prohibition with a self-judged exemption is a permission.
|
|
544
|
+
|
|
545
|
+
**Cut as well as add.** Every apply also removes what the excess-prose review
|
|
546
|
+
found: delete duplicated rules (keep one copy, in the place the routing below
|
|
547
|
+
names), collapse paragraphs to the sentence the model acts on, drop examples
|
|
548
|
+
and rationale no trajectory used, and delete skill sections no case needed. A
|
|
549
|
+
skill binding or preload no case needed lives in `agents.yaml` - record it as
|
|
550
|
+
an open problem, do not edit it. A rule written in an earlier run that no case has tested since is a
|
|
551
|
+
candidate too. An apply that only adds is suspect: say in `changes.md` what was
|
|
552
|
+
cut and how many lines each file lost or gained. Cuts are confirmed like any
|
|
553
|
+
edit - a cut that makes a case wrong is restored, nothing else.
|
|
179
554
|
|
|
180
555
|
Route each rule by what kind of thing it is: one agent's behaviour to its prompt,
|
|
181
556
|
a fact or a procedure to a skill - update an existing one or create a new one, a
|
|
@@ -185,67 +560,185 @@ standing rule to `agents/instructions.md`, a rule about one capability to a new
|
|
|
185
560
|
You may edit prompts, skills, house rules and new policy files. You may not edit
|
|
186
561
|
`agents/memory-instructions.md`, `agents/fork-instructions.md`,
|
|
187
562
|
`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.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
the
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
563
|
+
--fix` overwrites them. You may not change a rubric to make a run pass. Do not
|
|
564
|
+
change `agents.yaml`: a finding that needs it is structural - record it as an
|
|
565
|
+
open problem and carry on.
|
|
566
|
+
|
|
567
|
+
Record every edit and the merged pattern behind it in `$RUN/changes.md`, then
|
|
568
|
+
run `zen check` and patch the README.
|
|
569
|
+
|
|
570
|
+
## 6. Confirm without memory, build the candidate (steps 7-9)
|
|
571
|
+
|
|
572
|
+
An edit is a guess until the same cases have run against it. Run the same batch
|
|
573
|
+
again as the next run - a copy of its cases, new prose, still no memory:
|
|
574
|
+
|
|
575
|
+
```sh
|
|
576
|
+
PREV=finetune/runs/batch01-nomem-run1
|
|
577
|
+
RUN=finetune/runs/batch01-nomem-run2
|
|
578
|
+
mkdir -p "$RUN" && cp finetune/runs/batch01-nomem-run1/cases.json "$RUN/cases.json"
|
|
579
|
+
C=$(node -p 'require("./finetune/config.json").concurrency')
|
|
580
|
+
zen run batch --input "$RUN/cases.json" \
|
|
581
|
+
--batch-dir "$RUN/batch" --memory finetune/empty --concurrency "$C"
|
|
582
|
+
.github/skills/zen-finetune/scripts/report.mjs -d "$RUN/batch" -p "$PREV/batch" compare
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
Same queries, same machine, same memory, exactly one thing changed. The verdict
|
|
586
|
+
column decides first: a cost edit that makes any case wrong is reverted, whatever
|
|
587
|
+
it saved. Then the cost columns: a cost edit that did not cut llm calls or tokens
|
|
588
|
+
in the cases it was aimed at by more than the noise floor is reverted too - prose
|
|
589
|
+
that does not pay is a cost on every future run. Read the recheck cases first,
|
|
590
|
+
then the cases the rule was written for, then the ones it was not about. Cost
|
|
591
|
+
growth concentrated in the cases the rule touches is its price; growth spread
|
|
592
|
+
evenly across all of them is prose leaking into every agent, and that is a
|
|
593
|
+
regression even when every case still passes. If the instruction files grew by a
|
|
594
|
+
third and one case moved, revert and say so.
|
|
595
|
+
|
|
596
|
+
Then grade this run exactly as in section 4 - cost review, commits, proposals
|
|
597
|
+
and difficult list included. If every case is right and the cost review finds
|
|
598
|
+
nothing more worth changing, write `PASSED`, then **build the candidate memory**
|
|
599
|
+
from it before anything else (step 9):
|
|
600
|
+
|
|
601
|
+
```sh
|
|
602
|
+
M=.github/skills/zen-finetune/scripts/memory.mjs
|
|
603
|
+
$M candidate batch01-nomem-run2
|
|
604
|
+
zen memory stats --dir "$($M path --candidate)"
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
It copies the last good memory and merges in what each case of this run
|
|
608
|
+
committed - what the graph already held is folded, not added. A candidate of 0
|
|
609
|
+
nodes means nothing was committed: a commit-policy finding, and the with-memory
|
|
610
|
+
runs will measure nothing. Then patch the README and go straight to section 7.
|
|
611
|
+
If the review finds more, it is `CORRECT`: back to section 5.
|
|
612
|
+
|
|
613
|
+
The no-memory runs get **at most 4** per batch. After the 4th, stop tuning:
|
|
614
|
+
revert whatever it did not confirm, add every case still wrong to the difficult
|
|
615
|
+
list, and write `PASSED` on it. If a case is still wrong, the map shows the
|
|
616
|
+
batch `failed`, not `done` - the case comes back first in the next batches.
|
|
617
|
+
|
|
618
|
+
**Never compare two different batches.** They hold different cases, so the
|
|
619
|
+
difference between them is the cases and not the prose. Compare run to run
|
|
620
|
+
within one batch and kind, or a with-memory run against the no-memory run that
|
|
621
|
+
passed the same batch.
|
|
622
|
+
|
|
623
|
+
## 7. With memory (steps 10-15)
|
|
624
|
+
|
|
625
|
+
Run the **same cases** from the candidate - every case gets **its own copy** of
|
|
626
|
+
it, recalls from the copy and commits into the copy, so nothing one case writes
|
|
627
|
+
reaches another case or the candidate:
|
|
628
|
+
|
|
629
|
+
```sh
|
|
630
|
+
M=.github/skills/zen-finetune/scripts/memory.mjs
|
|
631
|
+
RUN=finetune/runs/batch01-mem-run1
|
|
632
|
+
mkdir -p "$RUN" && cp finetune/runs/batch01-nomem-run1/cases.json "$RUN/cases.json"
|
|
633
|
+
C=$(node -p 'require("./finetune/config.json").concurrency')
|
|
634
|
+
zen run batch --input "$RUN/cases.json" \
|
|
635
|
+
--batch-dir "$RUN/batch" --memory "$($M path --candidate)" --concurrency "$C"
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
Do not use `--memory-read-only`: it removes the commit tool and changes the
|
|
639
|
+
memory prose, which makes a with-memory run differ from its no-memory baseline
|
|
640
|
+
in two ways instead of one.
|
|
641
|
+
|
|
642
|
+
**Analyze the memory use** (step 11). `report.mjs oom` first, then
|
|
643
|
+
`report.mjs memory` - recalls, memory reads, commits and `known` per case - then
|
|
644
|
+
`report.mjs recalls` - what each recall put in front of the model and every
|
|
645
|
+
memory tool step - and `report.mjs commits` - each case against the candidate:
|
|
646
|
+
what it committed, which of those the candidate already held, and which nodes
|
|
647
|
+
it loaded - then
|
|
648
|
+
`compare` against **the no-memory run that passed the same batch**, and from
|
|
649
|
+
run 2 on also against the previous with-memory run. Read the trajectories, and
|
|
650
|
+
`zen inspect ask` at the critical points - the first research call that ignored
|
|
651
|
+
a recall, the call right after a recall that redid the work, the call that
|
|
652
|
+
committed what it had just recalled - once per pattern, worded as
|
|
653
|
+
**zen-inspect-ask** says.
|
|
654
|
+
|
|
655
|
+
The target is reuse: recall should replace the discovery the no-memory runs
|
|
656
|
+
repeated every time, so the run is dramatically cheaper in tokens, calls and
|
|
657
|
+
wall clock with no verdict changed. A run that costs about the same, or more,
|
|
658
|
+
means memory was carried and not used - a recall-timing finding, not a reason
|
|
659
|
+
for more memory. A run that is much cheaper still needs one trajectory opened
|
|
660
|
+
to confirm the saving is recall replacing _discovery_ and not recall replacing a
|
|
661
|
+
_live reading_. The recheck cases, recalling what earlier batches committed,
|
|
662
|
+
are where that shows up first.
|
|
663
|
+
|
|
664
|
+
**Do not commit what memory already holds.** Every commit of a fact the graph
|
|
665
|
+
had - `known` above 0 in `report.mjs memory`, `ALREADY HELD` in
|
|
666
|
+
`report.mjs commits`, or a near-copy of a node it just
|
|
667
|
+
recalled - is an llm turn and a tool call that bought nothing, in every future
|
|
668
|
+
run. The target is `known` 0, and commits only of what the run genuinely
|
|
669
|
+
learned. A correction committed without `SUPERSEDES` beside the stale node it
|
|
670
|
+
contradicts is worse than a duplicate.
|
|
671
|
+
|
|
672
|
+
Write `findings.md` titled `WITH MEMORY`, with a `## Memory review` straight
|
|
673
|
+
after the verdict block - `next.mjs` refuses a `PASSED` without one: the saving
|
|
674
|
+
against the no-memory run, per case and in total; whether recall replaced
|
|
675
|
+
discovery, citing nodes; any live reading replaced by a recall; re-commits; and
|
|
676
|
+
corrections - each the pattern or `none` with the evidence. Then the per-case
|
|
677
|
+
grading, each case ending in its proposals.
|
|
678
|
+
|
|
679
|
+
**Merge and update** (steps 12-13) exactly as in section 5, into
|
|
680
|
+
`agents/memory-policy-instructions.md` - or the memory paragraph of a prompt or
|
|
681
|
+
skill where a `why` line names one: when to recall, when to trust a recalled
|
|
682
|
+
fact, when to go and look anyway, when **not** to commit because memory already
|
|
683
|
+
holds it. A pattern that cannot be written as one of those is a no-memory
|
|
684
|
+
finding that escaped: note it under "Open problems", put its cases on the
|
|
685
|
+
difficult list, do not edit the prose - the next batch's no-memory runs fix it.
|
|
686
|
+
A live reading sitting in the candidate is a commit-policy rule, and its nodes
|
|
687
|
+
may be removed with `zen memory forget --dir "$($M path --candidate)" <id>...`,
|
|
688
|
+
recorded in `changes.md`. Never edit the candidate otherwise, and never merge a
|
|
689
|
+
with-memory run's copies back into it.
|
|
690
|
+
|
|
691
|
+
**Run again** (step 14) from the **same candidate** - `batch01-mem-run2`, a copy
|
|
692
|
+
of the same cases. At most 4 with-memory runs. A case memory makes wrong or no
|
|
693
|
+
cheaper, still, after a run that tried to fix it, goes on the difficult list
|
|
694
|
+
`--why memory`.
|
|
695
|
+
|
|
696
|
+
**Keep it and move on** (step 15). When no verdict regressed, the saving is
|
|
697
|
+
obvious next to the noise floor, every large saving is explained, and nothing
|
|
698
|
+
was committed that memory already held, write `PASSED` and keep the candidate
|
|
699
|
+
before anything else:
|
|
700
|
+
|
|
701
|
+
```sh
|
|
702
|
+
.github/skills/zen-finetune/scripts/memory.mjs checkpoint batch01-mem-run1
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
Then mark difficult cases right in both passing runs `fixed`, patch the README
|
|
706
|
+
(the batch turns `done` on the map, the next one `now`), and build the next
|
|
707
|
+
batch as `next.mjs` says - section 3 - straight away. It grows on its own if
|
|
708
|
+
this one went smoothly.
|
|
709
|
+
|
|
710
|
+
## 8. The final check
|
|
711
|
+
|
|
712
|
+
When every case in the selection has been used and no difficult case is open -
|
|
713
|
+
`next.mjs` says so - run the whole selection as one run - the last good memory,
|
|
714
|
+
the same flags, the same machine - into `finetune/runs/final-check/`. It is the
|
|
715
|
+
only run that measures every case under the final prose and the final memory at
|
|
716
|
+
once. Grade it, and
|
|
717
|
+
write `findings.md` with the heading `VERIFIED` if no verdict regressed and the
|
|
718
|
+
saving holds. Change nothing. If something did regress, write it up as a finding
|
|
719
|
+
and under "Open problems" - which batch's rules are the suspect and why. Patch the README
|
|
720
|
+
to its final state - every node `done` or `failed`, "Results so far" as the
|
|
721
|
+
summary of the whole tuning, and every `stuck` difficult case and open problem
|
|
722
|
+
listed with what was tried.
|
|
723
|
+
|
|
724
|
+
Then, and only then, report to me: the final summary, the open problems, and a
|
|
725
|
+
link to the README. That is the end of the tuning.
|
|
726
|
+
|
|
727
|
+
## If the tuning stops for good
|
|
728
|
+
|
|
729
|
+
Whenever it stops - finished, abandoned, or killed mid-run - the prose under
|
|
730
|
+
`agents/` is whatever the last confirmed run left, and the memory worth keeping
|
|
731
|
+
is `memory.mjs path`: every passed batch's candidate, whole on disk, never
|
|
732
|
+
the graph a half-finished merge was writing. If the project will ship with a
|
|
733
|
+
memory, that is the one to promote into `memory/` - read `zen-memory-warmup`
|
|
734
|
+
first.
|
|
735
|
+
|
|
736
|
+
## Housekeeping
|
|
737
|
+
|
|
738
|
+
Commit `dataset.json`, `config.json`, `selection.json`, `difficult.json`,
|
|
739
|
+
`README.md`, `USAGE.md`, `usage.json`, every `cases.json`, `plan.json`, `findings.md` and `changes.md` - they are the
|
|
740
|
+
eval history, and they are what a resumed session reads to find its place. Write
|
|
741
|
+
each as its step ends rather than at the end of the batch, so an interruption
|
|
742
|
+
never costs more than the step it lands in. Add `finetune/runs/*/batch/`,
|
|
743
|
+
`finetune/memory/`, `finetune/empty/` and `finetune/usage/` to `.gitignore` - `batch/` folders are
|
|
744
|
+
large and may hold live API responses, and the memory graphs are built from them.
|