@zenera/cli 1.1.16 → 1.1.17

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 (39) hide show
  1. package/README.md +20 -12
  2. package/dist/catalog.js +19 -20
  3. package/dist/commands/check.js +5 -1
  4. package/dist/commands/init.js +41 -6
  5. package/dist/commands/run.js +4 -0
  6. package/dist/engine.js +6 -0
  7. package/dist/env.d.ts +20 -0
  8. package/dist/env.js +65 -0
  9. package/dist/keys.d.ts +2 -0
  10. package/dist/keys.js +2 -0
  11. package/dist/sandbox.d.ts +9 -0
  12. package/dist/sandbox.js +23 -3
  13. package/dist/scaffold.d.ts +6 -0
  14. package/dist/scaffold.js +56 -15
  15. package/dist/validate.js +57 -15
  16. package/package.json +2 -2
  17. package/templates/editor/.github/copilot-instructions.md +256 -91
  18. package/templates/editor/.github/prompts/review-project.prompt.md +53 -14
  19. package/templates/editor/.github/prompts/sync-with-spec.prompt.md +208 -21
  20. package/templates/editor/.github/prompts/update-spec-from-feedback.prompt.md +142 -0
  21. package/templates/editor/.github/skills/zen-cli/references/check.md +6 -3
  22. package/templates/editor/.github/skills/zen-cli/references/frame.md +5 -3
  23. package/templates/editor/.github/skills/zen-cli/references/projects.md +19 -2
  24. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +6 -0
  25. package/templates/editor/.github/skills/zen-memory/SKILL.md +102 -30
  26. package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +115 -0
  27. package/templates/editor/.github/skills/zen-review/SKILL.md +123 -0
  28. package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +119 -0
  29. package/templates/editor/.github/skills/zen-review/scripts/review.sh +104 -0
  30. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +197 -0
  31. package/templates/editor/.github/skills/zen-spec-sync/scripts/snapshot.sh +200 -0
  32. package/templates/editor/.vscode/settings.json +44 -4
  33. package/templates/parts/memory-terms.yaml.tmpl +16 -0
  34. package/templates/parts/memory.yaml.tmpl +12 -0
  35. package/templates/project/SPECIFICATION.md.tmpl +7 -0
  36. package/templates/project/agents/memory-instructions.md +278 -0
  37. package/templates/project/agents.yaml.tmpl +9 -0
  38. package/templates/project/env +22 -0
  39. /package/templates/project/{INSTRUCTIONS.md → agents/instructions.md} +0 -0
@@ -7,9 +7,10 @@
7
7
  >
8
8
  > It describes the Zenera Neo runtime, not this particular project, and `zen`
9
9
  > rewrites the whole tree on `init` and `open` - so put this project's own
10
- > conventions in `INSTRUCTIONS.md`, where they will survive. The runtime's own
11
- > reference is `docs/agents-yaml.md`, `docs/projects.md` and `DESIGN.md` in the
12
- > @zenera/neo repository - where they disagree with this file, they win.
10
+ > conventions in `agents/instructions.md`, where they will survive. The
11
+ > runtime's own reference is `docs/agents-yaml.md`, `docs/projects.md` and
12
+ > `DESIGN.md` in the @zenera/neo repository - where they disagree with this
13
+ > file, they win.
13
14
 
14
15
  ---
15
16
 
@@ -34,13 +35,23 @@ programmed: what an agent knows, which model answers, and which of the tools
34
35
  6. Every change must still load: `agents.yaml` is validated strictly at load,
35
36
  and `zen check` says so before a model is ever called.
36
37
 
37
- ### 0.1 Copilot is the meta-agent: CLI and RAG
38
+ ### 0.1 Copilot is the meta-agent: load the skill for every capability in use
38
39
 
39
40
  Copilot is always the meta-agent that creates and changes target projects. Load
40
41
  the editor's `zen-cli` skill before deciding how a target project should run,
41
42
  be validated, or use command-line capabilities. It is the command contract; do
42
43
  not reconstruct `zen` arguments from memory or call `--help` to discover them.
43
44
 
45
+ **Every runtime capability a project turns on carries obligations that are not
46
+ visible in `agents.yaml` and that `zen check` does not report.** Before
47
+ reviewing or changing a project, list the capabilities it has turned on and load
48
+ the editor skill for each one - `zen-memory` for a `memory:` block, `zen-rag-
49
+ schema` or `zen-rag-docs` for an index, `zen-cli` always. A capability that is
50
+ already configured and already passing `zen check` is exactly the case that
51
+ looks finished and is not: the obligation lives in the skill, so a review that
52
+ never opens the skill cannot find what is missing. This applies whatever
53
+ prompted the change - a task scoped to `SPECIFICATION.md` does not narrow it.
54
+
44
55
  First determine whether the target project uses RAG: a `zen rag` command in an
45
56
  agent prompt or skill, RAG tools supplied by its host, or a documentation or
46
57
  schema index it is expected to consult all count. When it does, also load the
@@ -68,6 +79,42 @@ target project. Grant the agents that need CLI RAG the necessary `sandbox:*`
68
79
  tool access; give tool-based RAG users the configured RAG tools instead. Run
69
80
  `zen check` after adding or changing the skill.
70
81
 
82
+ Memory has one such obligation and it is absolute: **a project with a `memory:`
83
+ block carries the `zen-memory` skill's `references/memory-instructions.md` in its
84
+ own `agents/memory-instructions.md`.** `zen init` writes both, since it scaffolds
85
+ memory on; what needs watching is a project that deleted the file, or one whose
86
+ copy has fallen behind the reference. Do not read the two files against each
87
+ other - they drift by trailing whitespace inside tables, which is invisible.
88
+ The skill ships the check:
89
+
90
+ ```sh
91
+ .github/skills/zen-memory/scripts/check-instructions.sh # the verdict
92
+ .github/skills/zen-memory/scripts/check-instructions.sh fix # copy the reference over
93
+ ```
94
+
95
+ It is a copy, never a transcription - the reference ships inside the project,
96
+ because `zen init` and `zen open` write this whole `.github/` tree, so `fix` is
97
+ just `cp` from one to the other.
98
+
99
+ Nothing else tells a running agent how the store works, so without it nothing
100
+ forbids an agent from pointing `grep` or `cat` at `/memory` - a read that
101
+ bypasses the audience mask and serves superseded nodes as current. Keep the copy
102
+ byte-identical and put this project's own memory policy in a second topic file,
103
+ `agents/memory-policy-instructions.md`, which is read straight after it: then the
104
+ copy can be re-run after any `zen init` or `zen open` refreshes the reference,
105
+ without losing anything. Never paraphrase the reference into prose of your own.
106
+ See §5.3.
107
+
108
+ A project with a `SPECIFICATION.md` carries one more: **`.spec-sync/` records
109
+ what the last `/sync-with-spec` pass applied**, and the `zen-spec-sync` skill is
110
+ loaded before running that prompt, whether or not a baseline exists yet. The
111
+ state is committed, because a record only the last machine has is not a record.
112
+ Two things to watch for, neither of which `zen check` reports: a baseline that
113
+ moved without a history entry to match it, which is a pass claiming work it did
114
+ not do, and a `.spec-sync/baseline/` whose `manifest.txt` no longer matches its
115
+ files. Both are reported, not quietly repaired - rewriting the manifest asserts
116
+ a pass that never happened.
117
+
71
118
  ---
72
119
 
73
120
  ## 1. Mental model
@@ -76,12 +123,12 @@ tool access; give tool-based RAG users the configured RAG tools instead. Run
76
123
 
77
124
  An agent is four things and nothing more:
78
125
 
79
- | Part | Where it lives | What it decides |
80
- | --------------- | ---------------------------------------------- | ----------------------------- |
81
- | **Instruction** | `INSTRUCTIONS.md` + `agents/prompts/<name>.md` | How it behaves |
82
- | **Model** | `agents.yaml` → `model:` | How well and how expensively |
83
- | **Tools** | `agents.yaml` → `tools:` | What it can _do_ |
84
- | **Knowledge** | `agents/skills/*` + memory | What it can _know_, on demand |
126
+ | Part | Where it lives | What it decides |
127
+ | --------------- | ------------------------------------------------------ | ----------------------------- |
128
+ | **Instruction** | `agents/*instructions.md` + `agents/prompts/<name>.md` | How it behaves |
129
+ | **Model** | `agents.yaml` → `model:` | How well and how expensively |
130
+ | **Tools** | `agents.yaml` → `tools:` | What it can _do_ |
131
+ | **Knowledge** | `agents/skills/*` + memory | What it can _know_, on demand |
85
132
 
86
133
  Plus two relations: **handoffs** - which other agents it may transfer control to
87
134
 
@@ -116,7 +163,7 @@ is deciding **what is in that sequence and in what order**.
116
163
  ```
117
164
  ┌─────────────────────────────────────────────┐
118
165
  │ tool schemas fixed at load │ ← stable, cacheable
119
- │ INSTRUCTIONS.md shared by all agents │ ← stable, cacheable
166
+ │ agents/*instructions shared by all agents │ ← stable, cacheable
120
167
  │ agent prompt this agent's brief │ ← stable per agent
121
168
  │ skill index names + descriptions │ ← stable per agent
122
169
  │ preloaded skills activated turn 0 │ ← stable, in the cached prefix
@@ -159,10 +206,12 @@ my-project/
159
206
  │ ├── copilot-instructions.md this file
160
207
  │ ├── prompts/*.prompt.md tasks you invoke by name
161
208
  │ └── skills/*/SKILL.md reference the editor loads on demand
162
- ├── .env credentials - NEVER committed
163
- ├── INSTRUCTIONS.md house rules, prepended to every agent
209
+ ├── .env this project's environment - NEVER committed
210
+ ├── .spec-sync/ what the last /sync-with-spec applied - §0.1
164
211
  ├── agents.yaml who exists, what they may reach for
165
212
  ├── agents/
213
+ │ ├── instructions.md house rules, prepended to every agent
214
+ │ ├── memory-instructions.md more of them - any `<topic>-instructions.md`
166
215
  │ ├── prompts/
167
216
  │ │ ├── intake.md one agent's own brief
168
217
  │ │ └── adjuster.md
@@ -185,13 +234,18 @@ Only `agents.yaml` is required, and only `agents:` is required inside it.
185
234
  The config is found by name, in order: `agents.yaml`, `agents.yml`,
186
235
  `agents/agents.yaml`, `agents/agents.yml`.
187
236
 
237
+ The house rules are `agents/instructions.md` plus every
238
+ `agents/<topic>-instructions.md`, read in filename order and prepended to every
239
+ agent (§3.2). A project written before the move keeps its `INSTRUCTIONS.md` in
240
+ the root; that still loads, and `zen check` says to move it.
241
+
188
242
  ### 2.2 Variants
189
243
 
190
244
  **Single agent, knowledge-heavy** - the most under-used shape. One agent, one
191
245
  prompt, a large skill catalog. Prefer this until routing is genuinely needed.
192
246
 
193
247
  ```
194
- INSTRUCTIONS.md · agents.yaml · agents/prompts/assistant.md · agents/skills/** (20 skills)
248
+ agents.yaml · agents/instructions.md · agents/prompts/assistant.md · agents/skills/** (20 skills)
195
249
  ```
196
250
 
197
251
  **Router + specialists** - a cheap intake agent that classifies and hands off.
@@ -236,10 +290,10 @@ dots.
236
290
  There are two sets of instructions in this repository and they are not for the
237
291
  same reader. Keeping them apart is the single easiest thing to get wrong.
238
292
 
239
- | Tree | Read by | About |
240
- | ---------------------------- | ------------------------------------------ | ----------------------------------- |
241
- | `INSTRUCTIONS.md`, `agents/` | the **project's** agents, at run time | the domain this system works in |
242
- | `.github/` | the **editor's** assistant, while you edit | how a project of this kind is built |
293
+ | Tree | Read by | About |
294
+ | ------------------------ | ------------------------------------------ | ----------------------------------- |
295
+ | `agents.yaml`, `agents/` | the **project's** agents, at run time | the domain this system works in |
296
+ | `.github/` | the **editor's** assistant, while you edit | how a project of this kind is built |
243
297
 
244
298
  The `.github/` tree follows the same progressive-disclosure discipline the
245
299
  agents do, for the same reason - it is a prefix somebody pays for:
@@ -258,7 +312,8 @@ agents do, for the same reason - it is a prefix somebody pays for:
258
312
 
259
313
  `zen init` and `zen open` rewrite this whole tree from the version of `zen` in
260
314
  hand, so **edits inside `.github/` do not survive**. Project-specific conventions
261
- belong in `INSTRUCTIONS.md` and the agent prompts, which are never overwritten.
315
+ belong in `agents/instructions.md` and the agent prompts, which are never
316
+ overwritten.
262
317
 
263
318
  ### 2.5 What a running agent can actually see
264
319
 
@@ -276,10 +331,10 @@ Commands run inside the container `sandbox:` describes (§3.7): the same
276
331
  `/workspace`, and whatever the image ships.
277
332
 
278
333
  Everything else in the project directory is **invisible at run time** -
279
- `agents.yaml`, `INSTRUCTIONS.md`, `agents/prompts/`, `agents/skills/` under that
280
- name, `sandbox/Dockerfile`, `.env`, `.github/`, `sessions/`, and the project
281
- root itself. `zen` reads them to build the run; they are never a path an agent
282
- can open.
334
+ `agents.yaml`, `agents/instructions.md`, `agents/prompts/`, `agents/skills/`
335
+ under that name, `sandbox/Dockerfile`, `.env`, `.github/`, `sessions/`, and the
336
+ project root itself. `zen` reads them to build the run; they are never a path an
337
+ agent can open.
283
338
 
284
339
  Two consequences:
285
340
 
@@ -298,13 +353,13 @@ prose**, in the prompt - never sent to read the file that configured it.
298
353
 
299
354
  #### Checklist - no path an agent cannot open
300
355
 
301
- Run this over `INSTRUCTIONS.md`, every `agents/prompts/*.md` and every
302
- `agents/skills/*/SKILL.md` after editing any of them. Every path-shaped token in
303
- those files is read by a model as an instruction to open something:
356
+ Run this over every `agents/*instructions.md`, every `agents/prompts/*.md` and
357
+ every `agents/skills/*/SKILL.md` after editing any of them. Every path-shaped
358
+ token in those files is read by a model as an instruction to open something:
304
359
 
305
360
  - [ ] Every absolute path begins `/workspace`, `/assets`, `/skills` or
306
361
  `/memory`. Nothing else exists.
307
- - [ ] No project file is named: `agents.yaml`, `INSTRUCTIONS.md`,
362
+ - [ ] No project file is named: `agents.yaml`, `agents/instructions.md`,
308
363
  `agents/prompts/…`, `agents/skills/…`, `sandbox/Dockerfile`, `.env`,
309
364
  `.github/…`, `sessions/…`, `SPECIFICATION.md`, `README.md`, `docs/…`.
310
365
  - [ ] Nothing escapes a mount: no `../`, no `~`, no host path (`/Users/…`,
@@ -327,13 +382,17 @@ Finding the candidates, from the project root - every path-shaped token in the
327
382
  three trees, minus the ones under a mount:
328
383
 
329
384
  ```sh
330
- grep -Eohr '[~.]?/?[A-Za-z0-9_.-]*/[A-Za-z0-9_.*-]+' \
331
- INSTRUCTIONS.md agents/prompts agents/skills \
332
- | sort -u | grep -Ev '^/(workspace|assets|skills|memory)(/|$)'
385
+ .github/skills/zen-review/scripts/check-paths.sh
333
386
  ```
334
387
 
335
- Everything it prints is either a false positive (a url, a `path/to` in a
336
- sentence, `and/or`) or a path the agent cannot open. There is no third case.
388
+ It prints each candidate with the file and line it is on, and exits non-zero
389
+ while any remain. Everything it prints is either a path the agent cannot open or
390
+ noise the script has not learned yet - a url, a `path/to` in a sentence, an
391
+ `and/or` - and there is no third case. It strips the noise it does know about,
392
+ so a candidate that survives is one to explain or fix rather than one to skim
393
+ past. `check-paths.sh raw` is the sweep with nothing filtered, for when the
394
+ filter itself is the suspect. The `zen-review` skill says what it covers and
395
+ what it cannot.
337
396
 
338
397
  ---
339
398
 
@@ -410,7 +469,7 @@ provider with a missing key does not fail loading.
410
469
  - `agents[].handoffs` naming an unknown agent, or the agent itself
411
470
  - `agents[].skills.provider` / `.allow` / `.preload` naming something absent
412
471
  - a `preload:` entry missing from `allow:`
413
- - `agents[].fork.agents` naming an unknown agent, or being empty; `maxBranches` below 2
472
+ - `agents[].fork.agents` naming an unknown agent, or being empty; `maxBranches` below 1
414
473
  - `system:` pointing at a missing file, or outside the project root
415
474
 
416
475
  **Not caught at load** - a model id whose prefix is missing and so resolves to the
@@ -499,14 +558,26 @@ hide that. `maxBatch` therefore defaults to `1`; raise it only for a
499
558
  `zen check` reports every declared embedding beside the models, with the
500
559
  credential each one would need.
501
560
 
502
- ### 3.2 `INSTRUCTIONS.md`
561
+ ### 3.2 `agents/instructions.md` and friends
503
562
 
504
- House rules, read **once** and prepended to every agent's system prompt. It is
505
- the stable head of the cached prefix, so it should change rarely. The name is
563
+ House rules, read **once** and prepended to every agent's system prompt. They are
564
+ the stable head of the cached prefix, so they should change rarely. The name is
506
565
  deliberately not `AGENTS.md` - that one belongs to the coding assistant reading
507
566
  this file, and these rules address the project's own agents.
508
567
 
509
- Put here only what is true for **every** agent:
568
+ There may be more than one. `agents/instructions.md` is the base; every
569
+ `agents/<topic>-instructions.md` is read after it, in filename order, and every
570
+ agent gets all of them. Each arrives as its own block tagged with the file it
571
+ came from - `<house_rules src="agents/memory-instructions.md">` - so the model
572
+ can tell one document from the next.
573
+
574
+ Split a topic out when it is true for every agent but belongs to **one
575
+ capability**: the memory usage rules (§5.3) are the standard case - they arrive
576
+ when `memory:` is turned on and are deleted when it is turned off, which is a
577
+ whole file rather than a section somebody has to find. Do not split by author,
578
+ by date, or to keep a file short; that is what a skill is for.
579
+
580
+ Put in them only what is true for **every** agent:
510
581
 
511
582
  - identity and domain ("You work the property claims desk")
512
583
  - non-negotiable prohibitions (regulatory, legal, safety)
@@ -533,13 +604,13 @@ follow. So:
533
604
  - Anything only one agent needs goes in that agent's prompt instead. If you find
534
605
  yourself writing "if you are the router…", you are in the wrong file.
535
606
 
536
- Target 20–60 lines. If it exceeds ~100, split the stable half out into a
607
+ Target 20–60 lines each. If one exceeds ~100, split the stable half out into a
537
608
  preloaded skill.
538
609
 
539
610
  ### 3.3 `agents/prompts/<name>.md`
540
611
 
541
612
  Plain Markdown, no frontmatter. This is the agent's _job description_, appended
542
- after `INSTRUCTIONS.md`.
613
+ after the house rules.
543
614
 
544
615
  Structure that works:
545
616
 
@@ -574,8 +645,8 @@ literally; it states the boundary ("you do not have them") with the _reason_; it
574
645
  forbids the specific failure that agent actually exhibits.
575
646
 
576
647
  Write it as a prompt, under the rules in §4.2 - **instructive and concise**. It
577
- tells one agent what to do; it never explains the system (`INSTRUCTIONS.md`
578
- already did, §3.2), never repeats a house rule, and never describes the runtime.
648
+ tells one agent what to do; it never explains the system (the house rules
649
+ already did, §3.2), never repeats one of them, and never describes the runtime.
579
650
  Every line should be an instruction the model can act on or a boundary it can
580
651
  check itself against.
581
652
 
@@ -808,23 +879,34 @@ sandbox:
808
879
  env: [HTTPS_PROXY, NO_PROXY] # host variables to forward, by NAME
809
880
  ```
810
881
 
811
- | Field | Default | Meaning |
812
- | --------- | --------------------------------------------- | -------------------------------------------- |
813
- | `image` | `docker.io/library/python:3.14-slim-bookworm` | The base image commands run in |
814
- | `build` | none | A Dockerfile to build instead |
815
- | `cpus` | the host's | Fractional cores |
816
- | `memory` | the host's | MiB |
817
- | `network` | `bridge` | `bridge` / `none` / `host` |
818
- | `workdir` | `/workspace` | Mount point and default cwd |
819
- | `timeout` | `120` | Seconds per command |
820
- | `user` | the image's | uid, name, or `uid:gid` |
821
- | `persist` | `false` - **set it to `true`** | Keep the container between runs of a session |
822
- | `env` | none | Host variables to forward, **names** |
882
+ | Field | Default | Meaning |
883
+ | --------- | --------------------------------------------- | --------------------------------------------- |
884
+ | `image` | `docker.io/library/python:3.14-slim-bookworm` | The base image commands run in |
885
+ | `build` | none | A Dockerfile to build instead |
886
+ | `cpus` | the host's | Fractional cores |
887
+ | `memory` | the host's | MiB |
888
+ | `network` | `bridge` | `bridge` / `none` / `host` |
889
+ | `workdir` | `/workspace` | Mount point and default cwd |
890
+ | `timeout` | `120` | Seconds per command |
891
+ | `user` | the image's | uid, name, or `uid:gid` |
892
+ | `persist` | `false` - **set it to `true`** | Keep the container between runs of a session |
893
+ | `env` | none | Host variables to forward, **names** |
894
+ | `keys` | `true` | Whether model credentials reach the container |
823
895
 
824
896
  `env:` takes **names, never values** - a value here would be a secret in the
825
897
  repository - and anything credential-shaped (`KEY`, `TOKEN`, `SECRET`,
826
898
  `PASSWORD`, `CREDENTIAL`) is refused at load.
827
899
 
900
+ **Model credentials are already inside the container** (`keys:`, default
901
+ `true`). Every provider key the run holds is forwarded by name, and a Vertex
902
+ service-account file is bind-mounted read-only at `/run/zenera/keys` with
903
+ `GOOGLE_APPLICATION_CREDENTIALS` rewritten to point there - wherever it sits on
904
+ the host, keyring included. So a `zen` command that embeds (`zen rag … search`)
905
+ works in the sandbox: do not assume otherwise, do not route around it, and
906
+ never copy a key file into the project to "reach" the container. Only
907
+ `keys: false` / `zen run --no-keys` withholds them, and `network: none` is what
908
+ stops the call going out.
909
+
828
910
  **`build:`, when no published image fits.** A project that needs two runtimes,
829
911
  or a pinned toolchain, names a Dockerfile instead of an image - `zen init`
830
912
  writes one at `sandbox/Dockerfile` with Python and Node in it:
@@ -1041,13 +1123,14 @@ is a different project, not a different key.
1041
1123
  ### 4.1 Composition order
1042
1124
 
1043
1125
  ```
1044
- 1. INSTRUCTIONS.md (shared, once, all agents)
1045
- 2. agents/prompts/<n>.md (this agent)
1046
- 3. skill index (rendered by the runtime - do not hand-write it)
1047
- 4. preloaded skills (activated before the first call)
1126
+ 1. agents/instructions.md (shared, once, all agents)
1127
+ 2. agents/*-instructions.md (shared too, filename order)
1128
+ 3. agents/prompts/<n>.md (this agent)
1129
+ 4. skill index (rendered by the runtime - do not hand-write it)
1130
+ 5. preloaded skills (activated before the first call)
1048
1131
  ```
1049
1132
 
1050
- Never duplicate `INSTRUCTIONS.md` content into an agent prompt; never hand-render
1133
+ Never duplicate house-rules content into an agent prompt; never hand-render
1051
1134
  a list of skills into a prompt (the runtime does it, and a hand-written one goes
1052
1135
  stale silently).
1053
1136
 
@@ -1089,8 +1172,8 @@ When behaviour is wrong, in this order:
1089
1172
 
1090
1173
  1. **Read the actual assembled prompt**, not the file. Use the inspect report.
1091
1174
  2. Is the instruction _present_? (Missed skill load, wrong agent, compaction.)
1092
- 3. Is it _contradicted_ by `INSTRUCTIONS.md` or a skill? Adjacent contradictions
1093
- win over distant ones; later text usually wins over earlier.
1175
+ 3. Is it _contradicted_ by a house-rules file or a skill? Adjacent
1176
+ contradictions win over distant ones; later text usually wins over earlier.
1094
1177
  4. Is it _specific enough to be checkable_? Rewrite as a testable assertion.
1095
1178
  5. Only then consider a stronger model.
1096
1179
 
@@ -1105,15 +1188,15 @@ it forever.
1105
1188
 
1106
1189
  The decision for every piece of knowledge:
1107
1190
 
1108
- | Where | Cost | Use when |
1109
- | ------------------- | ----------------------- | ----------------------------------------------------- |
1110
- | `INSTRUCTIONS.md` | every call, every agent | true always, for everyone |
1111
- | agent prompt | every call, one agent | true always, for this job |
1112
- | **preloaded skill** | every call, one agent | always needed, but versioned/shared separately |
1113
- | **indexed skill** | one line until loaded | needed _sometimes_, model can tell when from one line |
1114
- | **searched skill** | nothing until searched | catalog too large to index (>~30 entries) |
1115
- | **tool** | schema only | needs live data, exact arithmetic, or a side effect |
1116
- | **memory** | recall block when hit | learned across runs, not authored |
1191
+ | Where | Cost | Use when |
1192
+ | ------------------------- | ----------------------- | ----------------------------------------------------- |
1193
+ | `agents/*instructions.md` | every call, every agent | true always, for everyone |
1194
+ | agent prompt | every call, one agent | true always, for this job |
1195
+ | **preloaded skill** | every call, one agent | always needed, but versioned/shared separately |
1196
+ | **indexed skill** | one line until loaded | needed _sometimes_, model can tell when from one line |
1197
+ | **searched skill** | nothing until searched | catalog too large to index (>~30 entries) |
1198
+ | **tool** | schema only | needs live data, exact arithmetic, or a side effect |
1199
+ | **memory** | recall block when hit | learned across runs, not authored |
1117
1200
 
1118
1201
  ### 5.2 Skill bindings
1119
1202
 
@@ -1166,6 +1249,39 @@ Every node carries an **audience**, and an agent's `sees` is the set it reads:
1166
1249
  one graph, masked per agent, never one graph each. The four `memory_*` tools are
1167
1250
  derived from `access` and are never listed in `tools:`.
1168
1251
 
1252
+ **Memory comes on.** `zen init` writes the block above, `memory: true` on the
1253
+ default agent, and the half nobody would guess was part of it:
1254
+ `agents/memory-instructions.md`, a copy of the `zen-memory` skill's
1255
+ `references/memory-instructions.md`, which the project already holds. Adding
1256
+ memory to a project that has none is both of those edits, and a copy that was
1257
+ lost or went stale is one command:
1258
+
1259
+ ```sh
1260
+ .github/skills/zen-memory/scripts/check-instructions.sh fix
1261
+ ```
1262
+
1263
+ It is what tells the agent that the store is reached only through the tools, that
1264
+ `memory_search` clips a node's text and `memory_load` reads it whole, that a
1265
+ remembered file's path comes from `memory_load` and not from listing `/memory`,
1266
+ what a node must carry to be worth having, and that a correction is a
1267
+ `SUPERSEDES` edge rather than an edit. It is its own file rather than a section of
1268
+ `agents/instructions.md` because it arrives with the `memory:` block and leaves
1269
+ with it.
1270
+
1271
+ **Leave that file as a pure copy.** Anything this project decides for itself -
1272
+ which audience holds what, what must never be written down, what an agent is
1273
+ expected to commit at the end of a job - goes in
1274
+ `agents/memory-policy-instructions.md`. Topic files are read in filename order,
1275
+ so the policy lands directly after the rules it qualifies, and the copy stays
1276
+ re-runnable: the reference is rewritten by every `zen init` and `zen open`, and
1277
+ keeping up with it is then the same one-line command rather than a hand-patch.
1278
+
1279
+ `zen check` validates the `memory:` block and says nothing about the rules'
1280
+ absence, so this is checked every time, by
1281
+ `.github/skills/zen-memory/scripts/check-instructions.sh` and never by reading
1282
+ the two files against each other: they drift by trailing whitespace inside a
1283
+ table, and the script is what can see that.
1284
+
1169
1285
  Do not treat memory as a database. It is for things learned that should
1170
1286
  persist. Anything authoritative - a rate, a policy clause, a procedure - belongs
1171
1287
  in a skill, where it is versioned and reviewable.
@@ -1179,12 +1295,12 @@ in front of a `zen rag` index - is in the `zen-memory` skill.
1179
1295
  Rules that follow directly from "stable prefix = cache hit":
1180
1296
 
1181
1297
  - Do not reorder `agents.yaml` for cosmetic reasons - tool order is prompt order.
1182
- - Do not put timestamps, run ids, or "today is …" in `INSTRUCTIONS.md` or a
1298
+ - Do not put timestamps, run ids, or "today is …" in a house-rules file or a
1183
1299
  prompt. A changing prefix is a permanent cache miss. Put volatile facts in a
1184
1300
  tool result.
1185
1301
  - Prefer `preload` over an instruction telling the model to load a skill first.
1186
1302
  - Keep the volatile half of an instruction in the agent prompt and the stable
1187
- half in `INSTRUCTIONS.md`, not the reverse.
1303
+ half in the house rules, not the reverse.
1188
1304
 
1189
1305
  ---
1190
1306
 
@@ -1269,7 +1385,8 @@ interchangeable:
1269
1385
  - The other agent should **own the conversation from here** → `handoffs:`, and
1270
1386
  something on the far side has to lead back.
1271
1387
  - This agent needs **an answer and then carries on** → `fork:`. Never a handoff:
1272
- a handoff spends the conversation to get the answer.
1388
+ a handoff spends the conversation to get the answer. One branch is enough -
1389
+ a fork of one is exactly "ask the specialist and continue".
1273
1390
 
1274
1391
  But the return is **condensed**: `A → fork → B` rejoins as one tool result
1275
1392
  holding B's answer, so A never sees the steps B took - no tool calls, no files
@@ -1297,7 +1414,7 @@ agents:
1297
1414
  | Field | Default | Meaning |
1298
1415
  | ------------- | -------------------- | ------------------------------------- |
1299
1416
  | `agents` | every declared agent | Which agents a branch may run |
1300
- | `maxBranches` | unlimited | Cap on branches per call; minimum `2` |
1417
+ | `maxBranches` | unlimited | Cap on branches per call; minimum `1` |
1301
1418
 
1302
1419
  The **model** decides the split: it names N branches, each with self-contained
1303
1420
  instructions. They run truly concurrently and rejoin as **one tool call and one
@@ -1310,8 +1427,10 @@ Rules worth knowing before you write the key:
1310
1427
  is not an error, and one role fanned out over ten items is the common shape.
1311
1428
  The list reaches the model as an `enum`, so a name outside it cannot even be
1312
1429
  decoded.
1313
- - A fork always needs **at least two** branches. A one-branch call is refused
1314
- with a message telling the model to do the work itself instead.
1430
+ - A fork of **one** branch is delegation, and it is valid: one assignment run
1431
+ elsewhere, its conclusion returned, its transcript left out of this
1432
+ conversation. Use it when another agent suits the job better, or when the job
1433
+ would fill the caller's context with material it has no use for afterwards.
1315
1434
  - **Branches cannot talk to each other.** If branch B needs branch A's answer,
1316
1435
  it is a sequence, not a fork - keep it in one conversation.
1317
1436
  - Nesting is capped by the run's `maxForkDepth` (2 by default), so a branch may
@@ -1330,10 +1449,12 @@ agent's prompt which one this work wants:
1330
1449
  - `none` - system prompt plus instructions only. Cheapest; for independent
1331
1450
  lookups.
1332
1451
 
1333
- Declaring `fork:` only makes the tool available. Say in the agent's prompt when
1334
- to reach for it, in the terms of this domain - _"When the request covers more
1335
- than one region, fork one branch per region and merge their findings"_ - or a
1336
- weaker model will work through the list serially and never call it.
1452
+ Declaring `fork:` only makes the tool available. What a fork costs and what
1453
+ survives the join is explained to the model by the runtime, in the system prompt
1454
+ of every agent holding the key. What is left to you is _when_, in the terms of
1455
+ this domain - _"When the request covers more than one region, fork one branch
1456
+ per region and merge their findings"_ - or a weaker model will work through the
1457
+ list serially and never call it.
1337
1458
 
1338
1459
  ### 6.5 Termination
1339
1460
 
@@ -1736,6 +1857,16 @@ ok, `1` failed, `2` usage, `3` invalid project, `4` no usable credential.
1736
1857
 
1737
1858
  ## 9. Review checklist
1738
1859
 
1860
+ Four of these are decidable, and are one command - `zen check`, the path sweep,
1861
+ the memory copy, the spec-sync record, in that order:
1862
+
1863
+ ```sh
1864
+ .github/skills/zen-review/scripts/review.sh
1865
+ ```
1866
+
1867
+ Run it first and read what it says. Everything else below is judgement, which is
1868
+ why it is still a list. The `zen-review` skill has the detail.
1869
+
1739
1870
  Before finishing any change here:
1740
1871
 
1741
1872
  **Structure**
@@ -1750,16 +1881,24 @@ Before finishing any change here:
1750
1881
 
1751
1882
  **Prompts**
1752
1883
 
1753
- - [ ] `INSTRUCTIONS.md` carries the shared architecture and nothing agent-specific
1754
- - [ ] Nothing duplicated between `INSTRUCTIONS.md` and an agent prompt
1884
+ - [ ] `agents/instructions.md` carries the shared architecture and nothing
1885
+ agent-specific
1886
+ - [ ] Nothing duplicated between a house-rules file and an agent prompt
1887
+ - [ ] Each `agents/<topic>-instructions.md` is about one capability, and is true
1888
+ of every agent
1755
1889
  - [ ] Every tool and agent referenced by its exact name
1756
1890
  - [ ] Failure paths stated for every instruction that can fail
1757
1891
  - [ ] No facts, rates or figures embedded in a prompt
1758
1892
  - [ ] No hedging, no meta-talk about the runtime
1893
+ - [ ] If any agent has `memory:`,
1894
+ `.github/skills/zen-memory/scripts/check-instructions.sh` exits zero -
1895
+ `agents/memory-instructions.md` is the reference byte for byte - and
1896
+ anything project-specific is in `agents/memory-policy-instructions.md` - §5.3
1759
1897
 
1760
- **Paths (§2.5 - run its checklist over the three trees)**
1898
+ **Paths (§2.5 - `.github/skills/zen-review/scripts/check-paths.sh` finds the
1899
+ candidates; these are the judgements to make about each one)**
1761
1900
 
1762
- - [ ] Every absolute path in `INSTRUCTIONS.md`, `agents/prompts/*.md` and
1901
+ - [ ] Every absolute path in `agents/*instructions.md`, `agents/prompts/*.md` and
1763
1902
  `agents/skills/*/SKILL.md` is under `/workspace`, `/assets`, `/skills` or
1764
1903
  `/memory`
1765
1904
  - [ ] No prompt or skill names a project file - `agents.yaml`, a prompt path, a
@@ -1807,14 +1946,29 @@ Before finishing any change here:
1807
1946
  - [ ] No key literal in YAML, prompt, skill or log - `${VAR}` only
1808
1947
  - [ ] `.env` is git-ignored
1809
1948
 
1949
+ **Specification** (only where the project has a `SPECIFICATION.md`)
1950
+
1951
+ - [ ] `.github/skills/zen-spec-sync/scripts/snapshot.sh status` does not say
1952
+ `tampered` - the baseline matches its own `manifest.txt`
1953
+ - [ ] `.spec-sync/baseline/applied.txt` names the newest file in
1954
+ `.spec-sync/history/`; a baseline ahead of the history is a pass that
1955
+ claimed work it did not finish
1956
+ - [ ] The newest history entry's `Still open` is what the next pass will trust,
1957
+ and says so honestly - an unchanged specification line is not evidence
1958
+ that anything implements it
1959
+ - [ ] No question in `SPECIFICATION-FEEDBACK.md` has a box marked `[x]`, or
1960
+ exactly one answer left under it, without a matching `✅ Answered` entry -
1961
+ that is an answer given and never folded into the specification
1962
+ - [ ] `.spec-sync/` is committed and `.tmp/` is not
1963
+
1810
1964
  ---
1811
1965
 
1812
1966
  ## 10. Where to change what
1813
1967
 
1814
1968
  | Symptom | Change this |
1815
1969
  | --------------------------------------------- | ------------------------------------------------------------------- |
1816
- | Wrong tone, wrong format, wrong length | `INSTRUCTIONS.md` (all agents) or the agent prompt |
1817
- | Says something forbidden | `INSTRUCTIONS.md` prohibition, stated specifically |
1970
+ | Wrong tone, wrong format, wrong length | The house rules (all agents) or the agent prompt |
1971
+ | Says something forbidden | A house-rules prohibition, stated specifically |
1818
1972
  | Ignores a rule that only applies sometimes | Move the rule into a skill with a sharp description |
1819
1973
  | Never loads the skill it should | The skill's `description`; or `preload` it |
1820
1974
  | Loads too much, answers slowly | `allow:`, `maxIndexEntries:`, or `discovery: search` |
@@ -1841,6 +1995,8 @@ Before finishing any change here:
1841
1995
  | Fails only on genuinely hard cases | Promote that agent's tier, or split the hard path out |
1842
1996
  | Shows no reasoning while it works | Turn summaries on for that model - §7.6 |
1843
1997
  | Forgets across conversations | Continue the session rather than starting a new one |
1998
+ | Greps `/memory` or reads `graph.json` | `agents/memory-instructions.md` is missing the block - §5.3 |
1999
+ | Recalls a note it cannot check or continue | Same block: it is what requires provenance on every node - §5.3 |
1844
2000
  | Breaks at load with a named path | Read the message - it names the exact key |
1845
2001
 
1846
2002
  ---
@@ -1850,16 +2006,23 @@ Before finishing any change here:
1850
2006
  - **The mega-prompt.** 300 lines covering twelve scenarios. Split into skills.
1851
2007
  - **Agent sprawl.** Eight agents that share one model, one tool set and one
1852
2008
  prompt style. Collapse into one with a catalog.
1853
- - **Facts in prompts.** A fee schedule inside `INSTRUCTIONS.md`. It cannot be
1854
- versioned, cannot be shared, and is paid for on every call.
2009
+ - **Facts in prompts.** A fee schedule inside `agents/instructions.md`. It cannot
2010
+ be versioned, cannot be shared, and is paid for on every call.
1855
2011
  - **The bare skill file.** `agents/skills/<name>.md` instead of a folder. It can
1856
2012
  never grow the table or script the next revision of the rule will want - §3.4.
1857
2013
  - **Pointing an agent at the project.** A prompt or skill naming `agents.yaml`,
1858
- `INSTRUCTIONS.md`, `agents/skills/<name>/…` or `sandbox/Dockerfile`. None of
1859
- them are on any path the agent can open, so the instruction fails on the turn
1860
- that follows it - §2.5.
2014
+ `agents/instructions.md`, `agents/skills/<name>/…` or `sandbox/Dockerfile`.
2015
+ None of them are on any path the agent can open, so the instruction fails on
2016
+ the turn that follows it - §2.5.
1861
2017
  - **Arithmetic in prose.** A skill that walks the model through a calculation it
1862
2018
  will get wrong, in a folder that could have held the script - §3.4.1.
2019
+ - **The unguarded store.** `memory:` turned on and the skill's
2020
+ `references/memory-instructions.md` never copied to
2021
+ `agents/memory-instructions.md`, so nothing tells the agent the store is
2022
+ reached only through the tools - and `zen check` passes throughout - §5.3.
2023
+ - **Reviewing a capability without its skill.** A project whose memory, index or
2024
+ sandbox was configured by an earlier pass looks finished because it loads. The
2025
+ obligations are in the editor skill, not in `agents.yaml` - §0.1.
1863
2026
  - **Politeness padding.** "Please try your best to be helpful." Costs tokens,
1864
2027
  changes nothing.
1865
2028
  - **Commented implementation notes.** `agents.yaml` explaining how skill
@@ -1875,7 +2038,7 @@ Before finishing any change here:
1875
2038
  branch needs the first branch's answer is a sequence wearing a fork's clothes.
1876
2039
  - **Installing the toolchain every run.** A prompt that begins with `apt-get
1877
2040
  install` is an `image:` that was never set - §3.7.
1878
- - **Volatile prefix.** "Current date: …" in `INSTRUCTIONS.md`. Permanent cache
2041
+ - **Volatile prefix.** "Current date: …" in the house rules. Permanent cache
1879
2042
  miss.
1880
2043
 
1881
2044
  ---
@@ -1894,6 +2057,8 @@ Update it when:
1894
2057
  - a vendor trap is discovered - add it to §7.7
1895
2058
  - a recurring review comment appears twice - turn it into a checklist line in §9
1896
2059
  - a runtime capability is added - describe it here, or it will not be used
2060
+ - an editor skill starts requiring a block in the target project - name the
2061
+ requirement in §0.1 and the check for it in §9, or it will be missed
1897
2062
 
1898
2063
  Do not let it grow without pruning. When a section is only true of one agent, it
1899
2064
  belongs in that agent's prompt, not here.