@zenera/cli 1.1.22 → 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 (73) hide show
  1. package/README.md +72 -2
  2. package/dist/archive.d.ts +139 -0
  3. package/dist/archive.js +376 -0
  4. package/dist/ask.d.ts +51 -0
  5. package/dist/ask.js +143 -0
  6. package/dist/batch.d.ts +77 -0
  7. package/dist/batch.js +338 -0
  8. package/dist/command.d.ts +6 -0
  9. package/dist/commands/export.d.ts +3 -0
  10. package/dist/commands/export.js +255 -0
  11. package/dist/commands/import.d.ts +3 -0
  12. package/dist/commands/import.js +173 -0
  13. package/dist/commands/index.d.ts +5 -1
  14. package/dist/commands/index.js +13 -1
  15. package/dist/commands/inspect.d.ts +11 -0
  16. package/dist/commands/inspect.js +388 -89
  17. package/dist/commands/list.js +128 -19
  18. package/dist/commands/memory.js +453 -16
  19. package/dist/commands/models.js +14 -2
  20. package/dist/commands/run.js +139 -34
  21. package/dist/commands/sandbox.js +72 -1
  22. package/dist/engine.d.ts +19 -0
  23. package/dist/engine.js +60 -8
  24. package/dist/liveness.js +6 -3
  25. package/dist/main.js +5 -2
  26. package/dist/podman.d.ts +16 -0
  27. package/dist/podman.js +115 -2
  28. package/dist/progress.d.ts +33 -0
  29. package/dist/progress.js +402 -0
  30. package/dist/request.d.ts +45 -0
  31. package/dist/request.js +300 -0
  32. package/dist/sandbox.js +10 -0
  33. package/dist/scaffold.d.ts +8 -0
  34. package/dist/scaffold.js +4 -1
  35. package/dist/session.d.ts +26 -1
  36. package/dist/session.js +42 -3
  37. package/dist/term.d.ts +3 -0
  38. package/dist/term.js +17 -1
  39. package/dist/trace.d.ts +84 -0
  40. package/dist/trace.js +686 -0
  41. package/dist/validate.js +93 -4
  42. package/package.json +12 -6
  43. package/templates/editor/.github/copilot-instructions.md +11 -6
  44. package/templates/editor/.github/prompts/finetune.prompt.md +251 -0
  45. package/templates/editor/.github/prompts/spec-sync-project.prompt.md +25 -2
  46. package/templates/editor/.github/skills/zen-cli/SKILL.md +14 -3
  47. package/templates/editor/.github/skills/zen-cli/references/check.md +13 -5
  48. package/templates/editor/.github/skills/zen-cli/references/export.md +107 -0
  49. package/templates/editor/.github/skills/zen-cli/references/inspect.md +262 -21
  50. package/templates/editor/.github/skills/zen-cli/references/memory.md +123 -15
  51. package/templates/editor/.github/skills/zen-cli/references/models.md +1 -1
  52. package/templates/editor/.github/skills/zen-cli/references/projects.md +12 -5
  53. package/templates/editor/.github/skills/zen-cli/references/rag.md +6 -0
  54. package/templates/editor/.github/skills/zen-cli/references/run.md +201 -4
  55. package/templates/editor/.github/skills/zen-finetune/SKILL.md +1000 -0
  56. package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +432 -0
  57. package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +199 -0
  58. package/templates/editor/.github/skills/zen-inspect/SKILL.md +396 -0
  59. package/templates/editor/.github/skills/zen-memory/SKILL.md +74 -28
  60. package/templates/editor/.github/skills/zen-memory-warmup/SKILL.md +370 -408
  61. package/templates/editor/.github/skills/zen-sandbox/SKILL.md +19 -0
  62. package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +334 -0
  63. package/templates/editor/.github/skills/zen-sandbox-capacity/references/loadtest.md +181 -0
  64. package/templates/editor/.github/skills/zen-sandbox-capacity/scripts/preflight_sandbox.sh +457 -0
  65. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +6 -5
  66. package/templates/editor/.vscode/agents.schema.json +1 -1
  67. package/templates/editor/.vscode/settings.json +1 -0
  68. package/templates/project/SPECIFICATION.md.tmpl +2 -0
  69. package/templates/project/agents/files-instructions.md +13 -0
  70. package/templates/project/agents/fork-instructions.md +27 -0
  71. package/templates/project/agents/memory-instructions.md +80 -7
  72. package/templates/project/gitignore +3 -0
  73. package/templates/project/scripts/_setup.sh +49 -7
@@ -1,138 +1,212 @@
1
1
  ---
2
2
  name: zen-memory-warmup
3
- description: Pre-populating an agent project's memory graph through warm-up queries before production or deployment — isolating scratch memory and workspaces in timestamped .tmp directories, using stronger reasoning models, validating machine-readable JSON output, categorizing queries with limits, shuffling, and dry-run execution, inspecting the graph with zen memory stats/ls, atomic promotion into the project, and generating automated population scripts in scripts/memory_warmup.sh.
3
+ description: Pre-populating an agent project's memory graph before production by running a curated file of seed queries through `zen run batch` — one parallel batch instead of a hand-rolled fan-out, with per-item workspaces and per-item memories the command makes for you, choosing the source graph with --memory, bounding the parallelism with --concurrency, warming with a stronger --model, reading what each query learned from batch.json and per-item output.json, folding it all back with zen memory merge, validating with zen memory stats, atomic promotion into the project, and generating the population script in scripts/memory_warmup.sh.
4
4
  ---
5
5
 
6
6
  # Memory Warmup
7
7
 
8
- Memory warmup is the process of pre-populating an agent project's knowledge graph
9
- before deploying it or exposing it to end users.
8
+ Memory warmup is the process of pre-populating an agent project's knowledge
9
+ graph before deploying it or exposing it to end users.
10
10
 
11
- In Zenera Neo, an agent's memory graph (`memory/`) starts completely empty. A cold
12
- start means early runs cannot recall prior approaches, domain facts, verified
13
- plans, or tool schemas. Warming up the memory addresses this by executing a
14
- curated set of representative domain queries ahead of time, allowing agents to
15
- synthesize, connect, and commit high-value knowledge nodes.
11
+ In Zenera Neo an agent's memory graph (`memory/`) starts empty. A cold start
12
+ means early runs cannot recall prior approaches, domain facts, verified plans
13
+ or tool schemas. Warming up addresses this by asking a curated set of
14
+ representative domain questions ahead of time, so the agents synthesise, link
15
+ and commit high-value knowledge nodes before a user is waiting on them.
16
+
17
+ Warmup is one command: **`zen run batch`**. A file of questions goes in, a
18
+ directory of memories comes out, and `zen memory merge` folds them into one.
16
19
 
17
20
  ---
18
21
 
19
22
  ## Why Warm Up Memory?
20
23
 
21
- 1. **Eliminate Cold Starts**: Instead of failing or struggling through initial
22
- discovery, the agent recalls established patterns, known schemas, and
23
- proven plans on its very first user-facing turn.
24
- 2. **Higher-Quality Graph via Stronger Models**: You can run warmup turns using
25
- a more capable reasoning model (`--model`) than your day-to-day runtime
26
- model. A smarter model creates cleaner abstractions, links causal relations
27
- accurately, and produces superior plans.
28
- 3. **Consistency & Alignment**: Foundational conventions, domain boundaries,
29
- and operational rules are seeded as durable `fact` and `plan` nodes rather
30
- than rediscovered inconsistently across random user sessions.
24
+ 1. **Eliminate cold starts.** Instead of struggling through initial discovery,
25
+ the agent recalls established patterns, known schemas and proven plans on
26
+ its very first user-facing turn.
27
+ 2. **A better graph, from a stronger model.** Warmup runs are infrequent, so
28
+ they can afford a flagship reasoning model (`--model`) that the day-to-day
29
+ runtime model cannot. The superior structure it leaves behind is then
30
+ recalled by the cheaper model.
31
+ 3. **Consistency and alignment.** Conventions, domain boundaries and operating
32
+ rules are seeded as durable `fact` and `plan` nodes, rather than being
33
+ rediscovered inconsistently across random user sessions.
31
34
 
32
35
  ---
33
36
 
34
- ## Core Architecture & Safety Rules
37
+ ## What the Command Already Does
38
+
39
+ Warmup used to be a script's problem: a memory per run because the lock is per
40
+ directory, a fresh workspace per run, a bounded number of background jobs, and
41
+ a merge at the end. `zen run batch` is that fan-out made into a command, so
42
+ none of it is the script's problem any more.
43
+
44
+ | What warmup needs | What `zen run batch` does |
45
+ | :----------------------------------- | :-------------------------------------------------------------------------- |
46
+ | A memory no other run is writing | Each item gets its own copy at `<batch-dir>/<id>/memory` |
47
+ | The project's own graph left alone | It is the source to copy from, and is never written |
48
+ | A clean working directory per query | Each item gets `<batch-dir>/<id>/workspace` |
49
+ | Parallelism the machine can stand | `--concurrency <n>`, default 16, ceiling 32 |
50
+ | One bad query not costing the others | The failure is written to its `output.json`; the rest still answer |
51
+ | A record of what happened | `batch.json`, the index: every item, whether it worked, where its answer is |
52
+ | The fold back | It prints the `zen memory merge <batch-dir>/*/memory` line when it is done |
53
+
54
+ What is left for the warmup script is the part that is actually about warmup:
55
+ **which questions to ask, which graph to start from, which model to ask with,
56
+ and whether the result is good enough to promote.**
57
+
58
+ ---
35
59
 
36
- Warmup is an offline staging process. It must adhere to five safety rules:
60
+ ## Core Safety Rules
37
61
 
38
- ### 1. Never warm up directly into the project's active `memory/`
62
+ ### 1. Never warm up into the project's active `memory/`
39
63
 
40
- If a warmup query fails, hallucinates, or aborts mid-turn, committing directly
41
- to the project's memory directory corrupts the knowledge graph. Always point
42
- `zen run` to a timestamped staging directory in `.tmp/` via `--memory` so that
43
- repeated or concurrent runs never collide:
64
+ A batch never writes the source graph - it copies it - so the default is
65
+ already safe. Keep the whole staging tree in `.tmp/` under a timestamp so that
66
+ repeated or concurrent warmups cannot collide, and so a failed one can be read
67
+ afterwards rather than being lost:
44
68
 
45
69
  ```sh
46
70
  STAMP="$(date +%Y%m%d-%H%M%S)"
47
- --memory ".tmp/warmup-$STAMP/memory"
71
+ zen run batch --input cases.json --batch-dir ".tmp/warmup-$STAMP/batch"
48
72
  ```
49
73
 
50
- ### 2. Isolate workspaces in `.tmp/` with per-run timestamps
51
-
52
- Warmup queries often instruct agents to investigate repositories, write test
53
- scripts, or run commands. Running them in the actual project or repository
54
- working directory risks modifying tracked files or creating untracked clutter.
55
-
56
- Always isolate the workspace per run into a fresh, timestamped subdirectory
57
- under `.tmp/`:
74
+ Without `--batch-dir` the batch picks `<project>/batches/<stamp>` and prints
75
+ the path on stdout, which is the other way to write it:
58
76
 
59
77
  ```sh
60
- --workspace ".tmp/warmup-$STAMP/workspaces/run-01-$(date +%s)"
78
+ DIR="$(zen run batch --input cases.json)"
61
79
  ```
62
80
 
63
- Using timestamps on both the root staging directory and each individual run
64
- workspace ensures:
81
+ ### 2. Choose the graph every item starts from
82
+
83
+ `--memory <dir>` names the source. There are two warmups, and they differ only
84
+ in what they point it at:
65
85
 
66
- - Concurrent or repeated warmup attempts never overwrite each other's state.
67
- - Stale or corrupted files from an earlier failed run cannot leak into subsequent
68
- queries.
69
- - Every turn begins from a completely pristine, deterministic working directory.
86
+ | Warmup | Source | Every item starts from |
87
+ | :------------------------ | :-------------------------------- | :-------------------------- |
88
+ | Building on what is known | the project's `memory/` (default) | a copy of the current graph |
89
+ | From nothing | a directory that does not exist | an empty graph |
70
90
 
71
- ### 3. Use stronger models during population
91
+ A source that is not there yet is not an error in the copying mode: a project
92
+ declares its memory directory and the first run makes it, so a cold project is
93
+ warmed by copying from nothing, and nothing is what each item gets.
94
+
95
+ **`--memory-read-only` is not a warmup flag.** It means nobody writes, which is
96
+ exactly what a warmup is for. It is for asking a batch of questions _of_ a
97
+ warmed graph afterwards - sixteen runs recalling from the one memory, changing
98
+ nothing.
99
+
100
+ ### 3. Use a stronger model during population
72
101
 
73
102
  Day-to-day execution might use a fast, cost-effective model (e.g.
74
- `google:gemini-2.5-flash` or `anthropic:claude-3-5-haiku`). Warmup runs are
75
- performed infrequently, so it makes sense to use a flagship reasoning model
76
- (e.g. `anthropic:claude-sonnet-4-5`, `openai:gpt-5`, or
77
- `google:gemini-3.5-flash`):
103
+ `google:gemini-2.5-flash` or `anthropic:claude-3-5-haiku`). Warm up with a
104
+ flagship reasoning model instead:
78
105
 
79
106
  ```sh
80
107
  --model anthropic:claude-sonnet-4-5
81
108
  ```
82
109
 
83
- The superior graph structure created by the flagship model is then recalled and
84
- utilized by the runtime model.
85
-
86
- ### 4. Execute non-interactively with `--json`
110
+ It applies to every item in the batch.
87
111
 
88
- Using `--json` guarantees:
112
+ ### 4. Read the result before promoting it
89
113
 
90
- - Interactive TUI and confirmation prompts are disabled (assumes `--yes`).
91
- - Progress narration on stderr is silenced.
92
- - Machine-readable JSON output on stdout containing `stopReason`, `usage`,
93
- `mounts`, run artifact paths (`run.dir`, `run.output`), and the answer.
94
- - The population script can programmatically verify whether the run finished
95
- successfully (`stopReason === "final"`).
114
+ The staging graph is inspected with `zen memory stats --dir ...`, and nothing
115
+ overwrites the project's `memory/` until it holds what it should. Because each
116
+ item kept its own memory, this can be done **per query** as well as in total -
117
+ see below.
96
118
 
97
- ### 5. Validate before promotion
119
+ ### 5. Promote atomically, and keep the old graph
98
120
 
99
- Track graph accumulation by inspecting `zen memory stats --dir ...` in between
100
- warmup queries, and do not overwrite the project's `memory/` until the final
101
- graph in `.tmp/warmup-<timestamp>/memory` has been verified to contain expected
102
- nodes and vector embeddings.
121
+ Back the current `memory/` up under a timestamp and move the staging graph into
122
+ place. A warmup that turns out to have been a bad idea is then one `mv` away
123
+ from being undone.
103
124
 
104
125
  ---
105
126
 
106
- ## The Warmup Cycle
127
+ ## The Shape of a Warmup
128
+
129
+ ```mermaid
130
+ flowchart LR
131
+ Q["scripts/warmup-queries.json"] --> S["select: category, shuffle, limit"]
132
+ S --> C["cases.json"]
133
+ C --> B["zen run batch --concurrency 4 --model <flagship>"]
134
+ B --> I1["batch/architecture-01/memory"]
135
+ B --> I2["batch/workflows-01/memory"]
136
+ B --> I3["batch/.../memory"]
137
+ I1 --> M["zen memory merge batch/*/memory --dir memory"]
138
+ I2 --> M
139
+ I3 --> M
140
+ M --> V["zen memory stats --dir memory"]
141
+ V --> P["back up and promote to memory/"]
142
+ ```
107
143
 
108
144
  ```mermaid
109
145
  flowchart TD
110
- A[Curated Seed Queries] --> B["Initialize .tmp/warmup-<timestamp>/memory"]
111
- B --> C["For each query: Create fresh .tmp/warmup-<timestamp>/workspaces/run-N-<timestamp>"]
112
- C --> D["zen run --memory .tmp/warmup-<timestamp>/memory --workspace .tmp/.../run-N-<timestamp> --model <model> --json"]
113
- D --> E{Check stopReason & exit code}
114
- E -- Success --> F[Accumulate nodes in staging graph]
115
- E -- Failure --> G[Log error & abort or retry]
116
- F --> T["Log timing: query duration & total elapsed"]
117
- T --> S["Inspect progress: zen memory stats --dir .tmp/warmup-<timestamp>/memory"]
118
- S --> H{More queries?}
119
- H -- Yes --> C
120
- H -- No --> I["Validate: zen memory stats --dir .tmp/warmup-<timestamp>/memory"]
121
- I --> J{Graph healthy?}
122
- J -- Yes --> K["Backup existing memory & promote .tmp/warmup-<timestamp>/memory to memory/"]
123
- J -- No --> L[Inspect with zen memory ls / export & discard]
146
+ A["Curated seed queries"] --> B["Select: --category / --shuffle / --limit"]
147
+ B --> C{"--dry-run?"}
148
+ C -- Yes --> D["Print the cases file and the command, write nothing, exit 0"]
149
+ C -- No --> E["Write .tmp/warmup-<stamp>/cases.json"]
150
+ E --> F["zen run batch --input cases.json --batch-dir .tmp/warmup-<stamp>/batch"]
151
+ F --> G{"Exit code"}
152
+ G -- Non-zero --> H["Name the failed ids from batch.json, promote nothing"]
153
+ G -- Zero --> I["zen memory merge batch/*/memory --dir .tmp/warmup-<stamp>/memory"]
154
+ I --> J["zen memory stats --dir .tmp/warmup-<stamp>/memory"]
155
+ J --> K{"Graph healthy?"}
156
+ K -- No --> L["Inspect per item, or with zen memory ls / export, and discard"]
157
+ K -- Yes --> M["Back up memory/ and promote"]
124
158
  ```
125
159
 
126
160
  ---
127
161
 
128
- ## Query Categories, Sampling & Dry-Run Preview
162
+ ## The Queries File
163
+
164
+ Keep the seed queries in the repository, in the shape the command already
165
+ reads, so warmup is reproducible across environments and model upgrades:
166
+
167
+ ```json
168
+ {
169
+ "batch": [
170
+ {
171
+ "id": "architecture-layout",
172
+ "input": "Investigate the project architecture and summarize the main components and data flow."
173
+ },
174
+ {
175
+ "id": "architecture-boundaries",
176
+ "input": "Analyze module boundaries, dependency graphs, and core interfaces."
177
+ },
178
+ {
179
+ "id": "workflows-triage",
180
+ "input": "Formulate standard operational plans for triaging and resolving common domain tasks."
181
+ },
182
+ {
183
+ "id": "integrations-services",
184
+ "input": "Identify external services, APIs, and key credential dependencies."
185
+ },
186
+ {
187
+ "id": "errors-handling",
188
+ "input": "Analyze error handling strategies, recovery routines, and failure modes."
189
+ },
190
+ {
191
+ "id": "conventions-house-rules",
192
+ "input": "Document project-specific coding standards, house rules, and commit policies."
193
+ }
194
+ ]
195
+ }
196
+ ```
197
+
198
+ An item takes `input`, an optional `id` and an optional `workspace`, and
199
+ nothing else. `memory`, `model` and `project` belong to the whole batch, so
200
+ they are flags on the line rather than keys in the file.
129
201
 
130
- Warmup suites should be organized across distinct domain categories rather than
131
- an unstructured flat list of ad-hoc prompts.
202
+ **The `id` is the category.** It names the directory the item's answer and
203
+ memory land in, so `architecture-layout` makes `batch/architecture-layout/` -
204
+ readable in a directory listing, greppable in `batch.json`, and selectable by
205
+ prefix. That is the whole of the category mechanism; no extra key is needed.
132
206
 
133
207
  ### Recommended Categories
134
208
 
135
- | Category | Objective | Example Prompt |
209
+ | Category | Objective | Example prompt |
136
210
  | :------------- | :----------------------------------------------------------- | :------------------------------------------------------------------------- |
137
211
  | `architecture` | Map high-level layout, component boundaries, and data flow | "Investigate project architecture and summarize component flow." |
138
212
  | `workflows` | Formulate multi-step operational plans for common tasks | "Formulate standard operational plans for triaging common tasks." |
@@ -140,415 +214,303 @@ an unstructured flat list of ad-hoc prompts.
140
214
  | `errors` | Capture error handling, recovery routines, and failure modes | "Analyze error handling strategies, recovery routines, and failure modes." |
141
215
  | `conventions` | Record coding styles, house rules, and constraints | "Document project-specific coding standards and house rules." |
142
216
 
143
- ### Why Sampling, Shuffling, and Limits Matter
217
+ ### Why Selection Still Matters
218
+
219
+ Everything runs at once now, so ordering no longer decides what gets asked -
220
+ but a budget still does.
221
+
222
+ 1. **Balanced coverage.** A 20-query suite cut to the first four with a limit
223
+ would warm `architecture` and leave `workflows` and `integrations` cold.
224
+ Shuffle before limiting so a partial budget draws a cross-section.
225
+ 2. **`--category <name>`** re-warms one subsystem after it changes - the
226
+ `integrations` queries alone once a new API is wired up - without paying for
227
+ the rest.
228
+ 3. **`--limit <n>`** caps what a verification pass costs. With sixteen in
229
+ flight the wall clock stops being the thing that limits you, so the cap has
230
+ to be deliberate.
231
+ 4. **`--dry-run`** prints the selected cases file and the exact command, writes
232
+ nothing, creates nothing, and bills nothing. Frontier models are expensive
233
+ enough that the plan is worth reading first.
234
+
235
+ ---
236
+
237
+ ## Reading What Each Query Learned
238
+
239
+ Because every item kept its own memory, a warmup is auditable per question -
240
+ which a sequential run into one graph never was.
144
241
 
145
- 1. **Balanced Graph Coverage**: If a warmup suite contains 20+ queries, running
146
- them sequentially with a limit (e.g. `--limit 4`) would only execute the
147
- first category (`architecture`), leaving workflows and integrations
148
- completely cold.
149
- 2. **`--shuffle`**: Randomizes the query sequence before limits are applied,
150
- ensuring that a limited budget run draws an even cross-section across
151
- different categories.
152
- 3. **`--category <name>`**: Enables focused warmup on a single subsystem (e.g.
153
- warming up only `integrations` after adding new API capabilities).
154
- 4. **`--limit <n>`**: Prevents unintended token expenditure by capping the total
155
- number of queries executed during test or verification passes.
242
+ ```sh
243
+ DIR=".tmp/warmup-$STAMP/batch"
244
+
245
+ # Which items worked, and what each was asked
246
+ jq -r '.batch_results[] | "\(.id)\t\(if .ok then "ok" else "FAILED" end)"' "$DIR/batch.json"
247
+
248
+ # What one query actually committed
249
+ zen memory stats --dir "$DIR/architecture-layout/memory"
250
+ zen memory ls --dir "$DIR/architecture-layout/memory"
156
251
 
157
- ### Dry Run Mode (`--dry-run`)
252
+ # What one query answered, and what it cost
253
+ jq '.stopReason, .usage' "$DIR/architecture-layout/output.json"
254
+ ```
158
255
 
159
- Warming up memory with frontier reasoning models (`--model`) can be resource
160
- intensive. A `--dry-run` flag is essential for:
256
+ A query that taught the graph nothing useful is excluded by leaving its
257
+ directory out of the merge. Nothing else has to be re-run.
161
258
 
162
- - Verifying resolved staging paths and backup targets.
163
- - Inspecting which queries and categories were selected after filtering,
164
- shuffling, and limits.
165
- - Checking the exact `zen run ...` commands that would be executed.
166
- - Guaranteeing that zero files are written, zero directories are created, and
167
- zero model tokens are billed.
259
+ An item that committed nothing leaves no `memory/` at all, so
260
+ `<batch-dir>/*/memory` never names a directory `merge` would refuse.
168
261
 
169
262
  ---
170
263
 
171
264
  ## Generating the Warmup Script in `scripts/`
172
265
 
173
- A project should maintain a dedicated warmup script located in `scripts/`
174
- (e.g. `scripts/memory_warmup.sh` or `scripts/memory-warmup.sh`).
175
-
176
- The script should automate the entire pipeline:
177
-
178
- 1. Accept command-line flags:
179
- - `--dry-run`: Preview selected queries, categories, and commands without executing.
180
- - `--limit <n>`: Run at most $n$ queries.
181
- - `--shuffle`: Randomize query order before applying limits.
182
- - `--category <name>`: Filter queries to a specific category.
183
- - `--model <provider:model>`: Override model with a reasoning flagship.
184
- - `--incremental`: Copy existing project memory into staging before warming up.
185
- - `-y`, `--yes`: Promote memory without interactive confirmation.
186
- 2. Create timestamped staging paths under `.tmp/` (e.g.
187
- `.tmp/warmup-$(date +%Y%m%d-%H%M%S)/`) and timestamped per-query workspaces.
188
- 3. Filter, shuffle, and sample from categorized query definitions.
189
- 4. If `--dry-run` is active, print the execution plan and exit 0 before touching disk.
190
- 5. Invoke `zen run` with `--memory`, `--workspace`, `--model`, and `--json`.
191
- 6. Parse each outcome with `jq`, halt if a turn fails, and report per-query execution time and total elapsed time since start.
192
- 7. Print graph statistics via `zen memory stats --dir ...` between queries to track graph growth, followed by a final validation.
193
- 8. Safely backup and replace the project's `memory/` directory with the warmed graph.
266
+ A project should keep its warmup under version control as two files:
194
267
 
195
- ### Recommended Script Template (`scripts/memory_warmup.sh`)
268
+ - `scripts/warmup-queries.json` - the curated seed queries, in the shape above.
269
+ - `scripts/memory_warmup.sh` - selection, one batch, merge, validate, promote.
270
+
271
+ The script should:
196
272
 
197
- When generating a warmup script for a project, use the following production-ready
198
- pattern:
273
+ 1. Accept `--category`, `--limit`, `--shuffle`, `--concurrency`, `--model`,
274
+ `--fresh`, `--dry-run` and `-y/--yes`.
275
+ 2. Select from the queries file and write the selection to a timestamped
276
+ staging directory under `.tmp/`.
277
+ 3. Stop before touching disk under `--dry-run`, having printed the plan.
278
+ 4. Run **one** `zen run batch`, letting it own the parallelism, the per-item
279
+ workspaces and the per-item memories.
280
+ 5. Refuse to promote anything if any item failed, naming the ids from
281
+ `batch.json` and leaving the staging tree for inspection.
282
+ 6. Merge the item memories, print `zen memory stats`, then back up and promote.
283
+
284
+ ### Recommended Script Template (`scripts/memory_warmup.sh`)
199
285
 
200
286
  ```bash
201
287
  #!/usr/bin/env bash
202
288
  #
203
- # scripts/memory_warmup.sh — Pre-populate project memory using curated seed queries.
289
+ # scripts/memory_warmup.sh — Warm this project's memory with one parallel batch.
204
290
  #
205
291
  # Usage:
206
292
  # ./scripts/memory_warmup.sh [options]
207
293
  #
208
294
  # Options:
209
- # --dry-run Preview selected queries and commands without executing
210
- # --limit <n> Maximum number of queries to run
211
- # --shuffle Randomize query order before applying limits
212
- # --category <name> Filter queries to a specific category
213
- # --model <ref> Override model (e.g. anthropic:claude-sonnet-4-5)
214
- # --incremental Seed staging memory with current memory/ before runs
215
- # -y, --yes Assume yes for memory promotion
216
- # -h, --help Show this help
295
+ # --category <name> Only queries whose id starts with "<name>-"
296
+ # --limit <n> Run at most n queries
297
+ # --shuffle Randomize order before applying --limit
298
+ # --concurrency <n> How many at a time (default 4; zen allows up to 32)
299
+ # --model <ref> Warm up with a stronger model than the runtime one
300
+ # --fresh Start every item from an empty graph, not from memory/
301
+ # --dry-run Print the plan and exit; write nothing, bill nothing
302
+ # -y, --yes Promote without asking
303
+ # -h, --help Show this help
217
304
  #
218
305
  # Examples:
219
306
  # ./scripts/memory_warmup.sh --dry-run
220
- # ./scripts/memory_warmup.sh --dry-run --category workflows --limit 2
307
+ # ./scripts/memory_warmup.sh --category integrations
221
308
  # ./scripts/memory_warmup.sh --shuffle --limit 5 --model anthropic:claude-sonnet-4-5
222
- # ./scripts/memory_warmup.sh --incremental
309
+ # ./scripts/memory_warmup.sh --fresh -y
223
310
  #
224
311
 
225
312
  set -euo pipefail
226
313
 
227
- # Find project root regardless of invocation directory
228
314
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
229
315
  cd "$ROOT"
230
316
 
231
- # Default configuration
232
- MODEL="${ZEN_WARMUP_MODEL:-}"
233
- INCREMENTAL=false
234
- ASSUME_YES=false
235
- DRY_RUN=false
317
+ QUERIES="scripts/warmup-queries.json"
318
+ PROJECT_MEM="memory"
319
+
320
+ CATEGORY=""
236
321
  LIMIT=0
237
322
  SHUFFLE=false
238
- CATEGORY_FILTER=""
239
-
240
- # Helper to format seconds as human-readable duration
241
- format_duration() {
242
- local total_sec=$1
243
- local hours=$((total_sec / 3600))
244
- local mins=$(((total_sec % 3600) / 60))
245
- local secs=$((total_sec % 60))
246
- if [ $hours -gt 0 ]; then
247
- echo "${hours}h ${mins}m ${secs}s"
248
- elif [ $mins -gt 0 ]; then
249
- echo "${mins}m ${secs}s"
250
- else
251
- echo "${secs}s"
252
- fi
323
+ CONCURRENCY=4
324
+ MODEL="${ZEN_WARMUP_MODEL:-}"
325
+ FRESH=false
326
+ DRY_RUN=false
327
+ ASSUME_YES=false
328
+
329
+ usage() {
330
+ sed -n '2,25p' "$0" | sed 's/^# \{0,1\}//'
253
331
  }
254
332
 
255
- # Parse arguments
256
333
  while [[ $# -gt 0 ]]; do
257
334
  case "$1" in
258
- --dry-run)
259
- DRY_RUN=true
260
- shift
261
- ;;
262
- --limit)
263
- LIMIT="$2"
264
- shift 2
265
- ;;
266
- --shuffle)
267
- SHUFFLE=true
268
- shift
269
- ;;
270
- --category)
271
- CATEGORY_FILTER="$2"
272
- shift 2
273
- ;;
274
- --model)
275
- MODEL="$2"
276
- shift 2
277
- ;;
278
- --incremental)
279
- INCREMENTAL=true
280
- shift
281
- ;;
282
- -y|--yes)
283
- ASSUME_YES=true
284
- shift
285
- ;;
286
- -h|--help)
287
- echo "Usage: ./scripts/memory_warmup.sh [options]"
288
- echo ""
289
- echo "Options:"
290
- echo " --dry-run Preview selected queries and commands without executing"
291
- echo " --limit <n> Maximum number of queries to run"
292
- echo " --shuffle Randomize query order before applying limits"
293
- echo " --category <name> Filter queries to a specific category"
294
- echo " --model <ref> Override model (e.g. anthropic:claude-sonnet-4-5)"
295
- echo " --incremental Seed staging memory with current memory/ before runs"
296
- echo " -y, --yes Assume yes for memory promotion"
297
- echo " -h, --help Show this help"
298
- exit 0
299
- ;;
300
- *)
301
- echo "Error: Unknown option $1" >&2
302
- exit 2
303
- ;;
335
+ --category) CATEGORY="$2"; shift 2 ;;
336
+ --limit) LIMIT="$2"; shift 2 ;;
337
+ --shuffle) SHUFFLE=true; shift ;;
338
+ --concurrency) CONCURRENCY="$2"; shift 2 ;;
339
+ --model) MODEL="$2"; shift 2 ;;
340
+ --fresh) FRESH=true; shift ;;
341
+ --dry-run) DRY_RUN=true; shift ;;
342
+ -y|--yes) ASSUME_YES=true; shift ;;
343
+ -h|--help) usage; exit 0 ;;
344
+ *) echo "Error: unknown option $1" >&2; exit 2 ;;
304
345
  esac
305
346
  done
306
347
 
307
- STAMP="$(date +%Y%m%d-%H%M%S)"
308
- SCRATCH_DIR=".tmp/warmup-$STAMP"
309
- STAGING_MEM="$SCRATCH_DIR/memory"
310
- WORKSPACES_DIR="$SCRATCH_DIR/workspaces"
311
- PROJECT_MEM="memory"
312
-
313
- # Define curated seed queries structured by category ("category|prompt")
314
- ALL_QUERIES=(
315
- "architecture|Investigate the project architecture and summarize the main components and data flow."
316
- "architecture|Analyze module boundaries, dependency graphs, and core interfaces."
317
- "workflows|Formulate standard operational plans for triaging and resolving common domain tasks."
318
- "workflows|Trace the end-to-end user request lifecycle and hand-off points."
319
- "integrations|Identify external services, APIs, and key credential dependencies."
320
- "integrations|Verify database and storage schemas, access patterns, and persistence rules."
321
- "errors|Analyze error handling strategies, recovery routines, and failure modes."
322
- "errors|Identify retry policies, rate limits, and fallback behaviors."
323
- "conventions|Document project-specific coding standards, house rules, and commit policies."
324
- )
325
-
326
- # 1. Filter by category if requested
327
- FILTERED=()
328
- for item in "${ALL_QUERIES[@]}"; do
329
- cat="${item%%|*}"
330
- if [ -z "$CATEGORY_FILTER" ] || [ "$cat" = "$CATEGORY_FILTER" ]; then
331
- FILTERED+=("$item")
332
- fi
333
- done
348
+ command -v jq >/dev/null 2>&1 || { echo "Error: jq is required." >&2; exit 1; }
349
+ [ -f "$QUERIES" ] || { echo "Error: $QUERIES not found." >&2; exit 1; }
334
350
 
335
- if [ ${#FILTERED[@]} -eq 0 ]; then
336
- echo "Error: No queries matched category '$CATEGORY_FILTER'." >&2
337
- exit 1
338
- fi
351
+ # --- Select -----------------------------------------------------------------
352
+ # One compact JSON object per line, so ordering and limiting are line work.
353
+ SELECTED="$(jq -c --arg cat "$CATEGORY" \
354
+ '.batch[] | select($cat == "" or (.id // "" | startswith($cat + "-")))' \
355
+ "$QUERIES")"
339
356
 
340
- # 2. Shuffle if requested
341
357
  if [ "$SHUFFLE" = true ]; then
342
- TEMP=()
343
- if command -v python3 >/dev/null 2>&1; then
344
- while IFS= read -r line; do
345
- [ -n "$line" ] && TEMP+=("$line")
346
- done < <(printf '%s\n' "${FILTERED[@]}" | python3 -c 'import sys, random; lines = [l for l in sys.stdin.read().splitlines() if l]; random.shuffle(lines); print("\n".join(lines))')
347
- elif command -v shuf >/dev/null 2>&1; then
348
- while IFS= read -r line; do
349
- [ -n "$line" ] && TEMP+=("$line")
350
- done < <(printf '%s\n' "${FILTERED[@]}" | shuf)
351
- elif sort -R </dev/null >/dev/null 2>&1; then
352
- while IFS= read -r line; do
353
- [ -n "$line" ] && TEMP+=("$line")
354
- done < <(printf '%s\n' "${FILTERED[@]}" | sort -R)
358
+ if command -v shuf >/dev/null 2>&1; then
359
+ SELECTED="$(printf '%s\n' "$SELECTED" | shuf)"
355
360
  else
356
- TEMP=("${FILTERED[@]}")
361
+ SELECTED="$(printf '%s\n' "$SELECTED" | sort -R)"
357
362
  fi
358
- FILTERED=("${TEMP[@]}")
359
363
  fi
360
364
 
361
- # 3. Apply limit if requested
362
- SELECTED=()
363
- if [ "$LIMIT" -gt 0 ] && [ "$LIMIT" -lt "${#FILTERED[@]}" ]; then
364
- for ((i = 0; i < LIMIT; i++)); do
365
- SELECTED+=("${FILTERED[i]}")
366
- done
367
- else
368
- SELECTED=("${FILTERED[@]}")
365
+ # awk rather than head: head closes the pipe early, and a SIGPIPE inside a
366
+ # command substitution takes the whole script down under `set -e`.
367
+ if [ "$LIMIT" -gt 0 ]; then
368
+ SELECTED="$(printf '%s\n' "$SELECTED" | awk -v n="$LIMIT" 'NR <= n')"
369
+ fi
370
+
371
+ COUNT="$(printf '%s\n' "$SELECTED" | awk 'NF { n++ } END { print n + 0 }')"
372
+ if [ "$COUNT" -eq 0 ]; then
373
+ echo "Error: no queries matched${CATEGORY:+ category '$CATEGORY'}." >&2
374
+ exit 1
375
+ fi
376
+ CASES="$(printf '%s\n' "$SELECTED" | jq -s '{ batch: . }')"
377
+
378
+ STAMP="$(date +%Y%m%d-%H%M%S)"
379
+ STAGE=".tmp/warmup-$STAMP"
380
+ BATCH_DIR="$STAGE/batch"
381
+ STAGING_MEM="$STAGE/memory"
382
+ CASES_FILE="$STAGE/cases.json"
383
+
384
+ CMD=(zen run batch --input "$CASES_FILE" --batch-dir "$BATCH_DIR"
385
+ --concurrency "$CONCURRENCY")
386
+ if [ -n "$MODEL" ]; then
387
+ CMD+=(--model "$MODEL")
388
+ fi
389
+ if [ "$FRESH" = true ]; then
390
+ # A source that does not exist yet: every item starts from an empty graph
391
+ # instead of a copy of what the project already knows.
392
+ CMD+=(--memory "$STAGE/from-nothing")
369
393
  fi
370
394
 
371
- # 4. Handle Dry Run mode
395
+ # --- Dry run ----------------------------------------------------------------
372
396
  if [ "$DRY_RUN" = true ]; then
373
- echo "=== DRY RUN: Previewing Warmup Plan ==="
374
- echo "Project root: $ROOT"
375
- echo "Staging memory: $STAGING_MEM"
376
- echo "Target memory: $PROJECT_MEM"
377
- echo "Model override: ${MODEL:-<default>}"
378
- echo "Category filter: ${CATEGORY_FILTER:-<all>}"
379
- echo "Shuffled: $SHUFFLE"
380
- echo "Limit: ${LIMIT:-none}"
381
- echo "Selected queries: ${#SELECTED[@]} of ${#ALL_QUERIES[@]}"
382
- echo ""
383
- echo "Planned queries:"
384
- for item in "${SELECTED[@]}"; do
385
- cat="${item%%|*}"
386
- q="${item#*|}"
387
- printf ' [%-14s] %s\n' "$cat" "$q"
388
- done
397
+ echo "=== DRY RUN: warmup plan ==="
398
+ echo "Project root: $ROOT"
399
+ echo "Staging: $STAGE"
400
+ echo "Target memory: $PROJECT_MEM"
401
+ echo "Model: ${MODEL:-<project default>}"
402
+ echo "Category: ${CATEGORY:-<all>}"
403
+ echo "Shuffled: $SHUFFLE"
404
+ echo "Limit: $([ "$LIMIT" -gt 0 ] && echo "$LIMIT" || echo none)"
405
+ echo "Concurrency: $CONCURRENCY"
406
+ echo "Starting from: $([ "$FRESH" = true ] && echo "an empty graph" || echo "a copy of $PROJECT_MEM")"
407
+ echo "Queries: $COUNT"
389
408
  echo ""
390
- echo "Sample command that would execute:"
391
- SAMPLE_Q="${SELECTED[0]#*|}"
392
- echo " zen run --memory \"$STAGING_MEM\" --workspace \"$WORKSPACES_DIR/run-1-<timestamp>\" ${MODEL:+--model \"$MODEL\" }--json \"$SAMPLE_Q\""
393
- echo " zen memory stats --dir \"$STAGING_MEM\""
409
+ printf '%s\n' "$CASES" | jq -r '.batch[] | " [\(.id)] \(.input)"'
394
410
  echo ""
395
- echo "Post-run validation that would run:"
396
- echo " zen memory stats --dir \"$STAGING_MEM\""
411
+ echo "Would run:"
412
+ printf ' '; printf '%q ' "${CMD[@]}"; echo ""
413
+ echo " zen memory merge $BATCH_DIR/*/memory --dir $STAGING_MEM --yes"
414
+ echo " zen memory stats --dir $STAGING_MEM"
397
415
  echo ""
398
- echo "Dry run complete. No files created, no commands executed."
416
+ echo "Dry run complete. Nothing created, nothing billed."
399
417
  exit 0
400
418
  fi
401
419
 
402
- WARMUP_START=$(date +%s)
420
+ # --- Run --------------------------------------------------------------------
421
+ mkdir -p "$STAGE"
422
+ printf '%s\n' "$CASES" >"$CASES_FILE"
403
423
 
404
- echo "=== Zenera Neo Memory Warmup ==="
405
- echo "Project root: $ROOT"
406
- echo "Staging directory: $SCRATCH_DIR"
407
- if [ -n "$MODEL" ]; then
408
- echo "Model override: $MODEL"
409
- fi
410
- echo "Selected queries: ${#SELECTED[@]}"
424
+ echo "=== Zenera Neo memory warmup ==="
425
+ echo "Staging: $STAGE"
426
+ echo "Queries: $COUNT, $CONCURRENCY at a time"
411
427
  echo ""
412
428
 
413
- # Cleanup scratch on trap unless preserved for inspection on failure
414
- cleanup() {
415
- local rc=$?
416
- if [ $rc -ne 0 ]; then
417
- echo "" >&2
418
- echo "Warmup FAILED (exit code $rc)." >&2
419
- echo "Staging files preserved for inspection at: $SCRATCH_DIR" >&2
420
- fi
421
- }
422
- trap cleanup EXIT
423
-
424
- # Prepare staging memory
425
- mkdir -p "$STAGING_MEM" "$WORKSPACES_DIR"
426
-
427
- if [ "$INCREMENTAL" = true ] && [ -d "$PROJECT_MEM" ]; then
428
- echo "Copying existing memory for incremental warmup..."
429
- cp -R "$PROJECT_MEM/." "$STAGING_MEM/"
429
+ # The batch prints its directory on stdout; we chose it, so we do not need it
430
+ # repeated. Progress and per-item results are on stderr and stay visible.
431
+ if ! "${CMD[@]}" >/dev/null; then
432
+ echo "" >&2
433
+ echo "Some queries failed; nothing was promoted." >&2
434
+ jq -r '.batch_results[] | select(.ok | not) | " \(.id): \(.error.message)"' \
435
+ "$BATCH_DIR/batch.json" >&2
436
+ echo "Staging left for inspection at: $STAGE" >&2
437
+ exit 1
430
438
  fi
431
439
 
432
- echo "Running ${#SELECTED[@]} warmup queries..."
433
- echo "----------------------------------------"
434
-
435
- COUNT=0
436
- for item in "${SELECTED[@]}"; do
437
- COUNT=$((COUNT + 1))
438
- CATEGORY="${item%%|*}"
439
- QUERY="${item#*|}"
440
-
441
- RUN_STAMP="$(date +%s)"
442
- RUN_WORKSPACE="$WORKSPACES_DIR/run-$COUNT-$RUN_STAMP"
443
- mkdir -p "$RUN_WORKSPACE"
444
-
445
- echo "[$COUNT/${#SELECTED[@]}] [$CATEGORY] \"$QUERY\""
446
- echo " -> Workspace: $RUN_WORKSPACE"
447
-
448
- # Assemble arguments
449
- CMD=(zen run --memory "$STAGING_MEM" --workspace "$RUN_WORKSPACE" --json)
450
- if [ -n "$MODEL" ]; then
451
- CMD+=(--model "$MODEL")
452
- fi
453
- CMD+=("$QUERY")
454
-
455
- QUERY_START=$(date +%s)
456
-
457
- # Run query and capture JSON output
458
- JSON_OUT="$("${CMD[@]}")"
459
- EXIT_CODE=$?
460
-
461
- QUERY_END=$(date +%s)
462
- QUERY_DURATION=$((QUERY_END - QUERY_START))
463
- TOTAL_ELAPSED=$((QUERY_END - WARMUP_START))
464
-
465
- if [ $EXIT_CODE -ne 0 ]; then
466
- echo " -> Command exited with code $EXIT_CODE (query: $(format_duration $QUERY_DURATION), total elapsed: $(format_duration $TOTAL_ELAPSED))" >&2
467
- exit $EXIT_CODE
468
- fi
469
-
470
- # Parse outcome via jq if available
471
- if command -v jq >/dev/null 2>&1; then
472
- STOP_REASON=$(echo "$JSON_OUT" | jq -r '.stopReason // empty')
473
- AGENT=$(echo "$JSON_OUT" | jq -r '.agent // empty')
474
- echo " -> Completed: agent=$AGENT stopReason=$STOP_REASON"
475
-
476
- if [ "$STOP_REASON" != "final" ]; then
477
- echo " -> Unexpected stop reason: $STOP_REASON" >&2
478
- exit 1
479
- fi
480
- else
481
- echo " -> Turn completed successfully."
482
- fi
483
-
484
- echo " -> Timing: query took $(format_duration $QUERY_DURATION) | elapsed since start: $(format_duration $TOTAL_ELAPSED)"
485
-
486
- # Print memory stats between queries to track graph growth
487
- if [ -f "$STAGING_MEM/manifest.json" ]; then
488
- echo ""
489
- echo "Memory stats after query $COUNT:"
490
- zen memory stats --dir "$STAGING_MEM"
491
- else
492
- echo " -> Memory stats: No memories committed yet."
493
- fi
494
- echo ""
440
+ # --- Merge ------------------------------------------------------------------
441
+ # An item that committed nothing leaves no memory behind, so this glob only
442
+ # ever names real graphs.
443
+ MERGE=()
444
+ for mem in "$BATCH_DIR"/*/memory; do
445
+ [ -d "$mem" ] && MERGE+=("$mem")
495
446
  done
496
447
 
497
- echo "----------------------------------------"
498
- TOTAL_RUN_TIME=$(( $(date +%s) - WARMUP_START ))
499
- echo "All warmup queries finished successfully in $(format_duration $TOTAL_RUN_TIME)."
448
+ if [ ${#MERGE[@]} -eq 0 ]; then
449
+ echo "No query committed anything to memory; nothing to promote." >&2
450
+ echo "Answers are still at: $BATCH_DIR" >&2
451
+ exit 1
452
+ fi
453
+
500
454
  echo ""
455
+ echo "Merging ${#MERGE[@]} memories into $STAGING_MEM..."
456
+ zen memory merge "${MERGE[@]}" --dir "$STAGING_MEM" --yes
501
457
 
502
- # Validate staging memory
503
- echo "Validating staging memory graph:"
458
+ echo ""
459
+ echo "Warmed graph:"
504
460
  zen memory stats --dir "$STAGING_MEM"
505
461
  echo ""
506
462
 
507
- # Confirmation and promotion
463
+ # --- Promote ----------------------------------------------------------------
508
464
  if [ "$ASSUME_YES" = false ]; then
509
- read -r -p "Promote staging memory to '$PROJECT_MEM'? [y/N] " CONFIRM
465
+ read -r -p "Promote this graph to '$PROJECT_MEM'? [y/N] " CONFIRM
510
466
  if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
511
- echo "Warmup cancelled. Staging files left in $SCRATCH_DIR."
467
+ echo "Not promoted. Staging left at $STAGE."
512
468
  exit 0
513
469
  fi
514
470
  fi
515
471
 
516
- # Backup existing project memory if present
517
472
  if [ -d "$PROJECT_MEM" ]; then
518
- BACKUP_MEM="memory.bak.$(date +%Y%m%d-%H%M%S)"
519
- echo "Backing up current memory to $BACKUP_MEM..."
520
- mv "$PROJECT_MEM" "$BACKUP_MEM"
473
+ BACKUP="memory.bak.$STAMP"
474
+ echo "Backing up current memory to $BACKUP..."
475
+ mv "$PROJECT_MEM" "$BACKUP"
521
476
  fi
522
477
 
523
- # Promote staging memory to project root
524
- echo "Promoting warmed memory to $PROJECT_MEM..."
525
478
  mv "$STAGING_MEM" "$PROJECT_MEM"
479
+ rm -rf "$STAGE"
526
480
 
527
- # Clean up remaining scratch workspaces
528
- rm -rf "$SCRATCH_DIR"
529
-
530
- echo "Warmup complete! Project memory is ready."
481
+ echo "Warmup complete. Project memory is ready."
531
482
  ```
532
483
 
533
484
  ---
534
485
 
486
+ ## When Not to Batch
487
+
488
+ A batch gives every item its own graph, so no item can recall what another one
489
+ just learned. When the queries genuinely build on each other - a later question
490
+ that only makes sense once an earlier one has committed its answer - run those
491
+ few in sequence with plain `zen run --memory`, and batch the rest.
492
+
493
+ `merge` gives back everything except that cross-query recall. Reach for the
494
+ sequence only where the recall is the point; it costs the wall clock that
495
+ warming in parallel is for.
496
+
497
+ ---
498
+
535
499
  ## Best Practices for Seed Queries
536
500
 
537
- When authoring or generating queries for the warmup script:
538
-
539
- 1. **Group by Category**:
540
- - Organize queries into clear domain categories (`architecture`, `workflows`,
541
- `integrations`, `errors`, `conventions`) so test runs can be sampled or
542
- targeted easily.
543
- 2. **Use `--dry-run` First**:
544
- - Always verify candidate queries, model overrides, and category distribution
545
- with `--dry-run` before initiating a live warmup.
546
- 3. **Prompts That Induce Plan Formation**:
547
- - Instruct the agent to "analyze and determine the recommended pattern for..." so
548
- it stores durable `plan` and `fact` nodes rather than transient output.
549
- 4. **Verify Node Vectorisation**:
550
- - Confirm in `zen memory stats --dir ...` that vector count equals node count
551
- (ensuring your embedding model is configured and active).
552
- 5. **Keep Seed Queries Under Version Control**:
553
- - Store the seed prompts inside the script or an adjacent `scripts/warmup-queries.txt`
554
- so warmup is reproducible across environments and model upgrades.
501
+ 1. **Name ids by category.** `architecture-layout`, `workflows-triage`. The id
502
+ is the directory name, the selector, and the label in every report.
503
+ 2. **Dry-run first.** Verify the selection, the model and the source graph
504
+ before spending a flagship model on twenty questions at once.
505
+ 3. **Write prompts that induce plan formation.** "Analyze and determine the
506
+ recommended pattern for..." stores durable `plan` and `fact` nodes; "list
507
+ the files in src/" stores nothing worth keeping.
508
+ 4. **Verify vectorisation.** In `zen memory stats`, the vector count should
509
+ equal the node count. If it does not, the embedding model is not configured
510
+ and recall will fall back to text alone.
511
+ 5. **Keep the queries under version control.** `scripts/warmup-queries.json` is
512
+ the record of what the project's memory was built from, and the thing to
513
+ re-run after a model upgrade.
514
+ 6. **Warm in one batch, not many.** A second batch cannot see what the first
515
+ learned unless it has been merged and promoted first - so either merge in
516
+ between, or ask everything at once.