@zenera/cli 1.1.20 → 1.1.22

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 (50) hide show
  1. package/README.md +3 -3
  2. package/dist/banner.d.ts +41 -20
  3. package/dist/banner.js +32 -5
  4. package/dist/commands/check.js +1 -0
  5. package/dist/commands/init.js +1 -0
  6. package/dist/commands/inspect.js +1 -0
  7. package/dist/commands/key.js +1 -0
  8. package/dist/commands/list.js +1 -0
  9. package/dist/commands/memory.js +1 -0
  10. package/dist/commands/models.js +1 -0
  11. package/dist/commands/open.js +1 -0
  12. package/dist/commands/run.js +3 -0
  13. package/dist/commands/sandbox.js +1 -0
  14. package/dist/commands/version.js +1 -0
  15. package/dist/lib.d.ts +3 -2
  16. package/dist/lib.js +3 -2
  17. package/dist/meta.d.ts +1 -1
  18. package/dist/meta.js +5 -28
  19. package/dist/resolve.js +19 -12
  20. package/dist/sandbox.js +1 -0
  21. package/dist/scaffold.js +3 -1
  22. package/dist/term.d.ts +2 -0
  23. package/dist/term.js +2 -0
  24. package/dist/tui/markdown.d.ts +16 -0
  25. package/dist/tui/markdown.js +259 -0
  26. package/dist/tui/theme.js +1 -1
  27. package/dist/tui/wrap.d.ts +1 -1
  28. package/dist/validate.js +82 -3
  29. package/package.json +2 -2
  30. package/templates/editor/.github/copilot-instructions.md +62 -33
  31. package/templates/editor/.github/prompts/spec-sync-project.prompt.md +31 -1
  32. package/templates/editor/.github/skills/zen-cli/SKILL.md +15 -15
  33. package/templates/editor/.github/skills/zen-cli/references/projects.md +1 -0
  34. package/templates/editor/.github/skills/zen-cli/references/rag.md +37 -3
  35. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +30 -2
  36. package/templates/editor/.github/skills/zen-instructions/SKILL.md +232 -0
  37. package/templates/editor/.github/skills/zen-memory-warmup/SKILL.md +554 -0
  38. package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +56 -23
  39. package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +55 -28
  40. package/templates/editor/.github/skills/zen-review/SKILL.md +17 -1
  41. package/templates/editor/.github/skills/zen-sandbox/SKILL.md +257 -0
  42. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +15 -3
  43. package/templates/editor/.vscode/agents.schema.json +8 -3
  44. package/templates/project/SPECIFICATION.md.tmpl +2 -1
  45. package/templates/project/agents/files-instructions.md +86 -0
  46. package/templates/project/agents/fork-instructions.md +17 -0
  47. package/templates/project/agents/memory-instructions.md +37 -0
  48. package/templates/project/agents.yaml.tmpl +3 -3
  49. package/templates/project/gitignore +12 -1
  50. package/templates/project/scripts/_setup.sh +19 -4
@@ -31,7 +31,7 @@ because a prompt or skill someone changed outside a pass still has to be
31
31
  accounted for against the specification.
32
32
 
33
33
  The scope decides what you **read and edit**. It never decides what you
34
- **verify**: §6, §7 and the four checks in the skill run at full size on every
34
+ **verify**: §6, §7 and the five checks in the skill run at full size on every
35
35
  pass, however small the diff.
36
36
 
37
37
  ## 1. Read before changing anything
@@ -148,6 +148,31 @@ not a paragraph of instructions for a human.
148
148
  to a temporary path and moving it into place so an interrupted run never leaves
149
149
  a half-built artefact behind. `scripts/_setup.sh --force` redoes everything,
150
150
  and reaches each step as `$FORCE=1`.
151
+ - **A step's "already done" test must name something that survives a clone.**
152
+ Git-ignored output does not. A rag index commits its `manifest.json` and
153
+ ignores `lance/`, so `[ -f "$OUT/manifest.json" ]` is true on a fresh checkout
154
+ that cannot search at all - every step reports `skipped` and the failure
155
+ surfaces much later, as a search error nobody connects to setup. Ask the tool
156
+ rather than guessing at files: `zen rag docs ready --dir "$OUT" --quiet` exits
157
+ 0 when the index can answer and 3 when it cannot, and
158
+ `zen rag docs restore --dir "$OUT"` re-embeds it from the copies it already
159
+ holds instead of indexing the documents again. A step that builds an index
160
+ looks like this:
161
+
162
+ ```sh
163
+ if [ "${FORCE:-0}" = 0 ] && zen rag docs ready --dir "$OUT" --quiet; then
164
+ echo "$OUT is already built"
165
+ exit 3
166
+ fi
167
+ if [ "${FORCE:-0}" = 0 ] && [ -f "$OUT/manifest.json" ]; then
168
+ zen rag docs restore --dir "$OUT" # committed index, ignored vectors
169
+ exit 0
170
+ fi
171
+ rm -rf .tmp/docs-db
172
+ zen rag docs index assets/docs --embedding <ref> --out .tmp/docs-db
173
+ rm -rf "$OUT" && mv .tmp/docs-db "$OUT"
174
+ ```
175
+
151
176
  - **It must be watchable.** `scripts/_setup.sh` tees each step's output to
152
177
  `.tmp/logs/setup-<step>.log`, prints a heartbeat line while a long step runs,
153
178
  and finishes with one line per step: `ok`, `skipped`, or `failed`.
@@ -354,6 +379,11 @@ background and follow the logs instead of waiting blind:
354
379
  for the same reason, stop and raise it in `SPECIFICATION-FEEDBACK.md`.
355
380
  - Prove re-entrancy: once it has succeeded, run `scripts/_setup.sh` once more and
356
381
  check that every step reports `skipped` rather than rebuilding.
382
+ - **`skipped` on a machine that has never built it is a bug, not a pass.** A
383
+ step that tests for a committed file skips on a fresh clone and leaves the
384
+ project unusable. For every index the project builds, check it can actually
385
+ answer - `zen rag docs ready --dir <dir>` - and fix the step's test if the
386
+ answer disagrees with what setup reported.
357
387
 
358
388
  ## 7. Verify and report
359
389
 
@@ -29,8 +29,8 @@ zen sandbox [status|up|pull|clean|disk] [options]
29
29
  zen version
30
30
 
31
31
  zen faker <serve|build|cache> [spec...]
32
- zen rag schema <index|search|list|grep|trace|show|stats> [spec...]
33
- zen rag docs <index|search|list|grep|show|stats> [path...]
32
+ zen rag schema <index|restore|ready|search|list|grep|trace|show|stats> [spec...]
33
+ zen rag docs <index|restore|ready|search|list|grep|show|stats> [path...]
34
34
  ```
35
35
 
36
36
  ## Read the reference before answering
@@ -39,19 +39,19 @@ The full reference lives next to this file, one document per part of the command
39
39
  line. **Read the one that covers the question before answering it** - do not
40
40
  guess a flag, and do not read them all.
41
41
 
42
- | The question is about | Read |
43
- | ------------------------------------------------------------------- | --------------------------------------- |
44
- | Global flags, `--json`, exit codes, environment, where files live | [frame.md](./references/frame.md) |
45
- | Creating, finding or opening a project | [projects.md](./references/projects.md) |
46
- | Running: the TUI, one-shot answers, sessions, workspaces, overrides | [run.md](./references/run.md) |
47
- | Validating: `zen check`, what it can and cannot see | [check.md](./references/check.md) |
48
- | API keys, providers, the keyring, "no credential" errors | [keys.md](./references/keys.md) |
49
- | Which models exist, whether one works, recovering from a refusal | [models.md](./references/models.md) |
50
- | The container shell commands run in, images, `persist` | [sandbox.md](./references/sandbox.md) |
51
- | Run reports, trajectories, what a session directory holds | [inspect.md](./references/inspect.md) |
52
- | What the agents remember, why something was recalled, forgetting | [memory.md](./references/memory.md) |
53
- | `zen faker` - a mock API from an OpenAPI/Swagger document | [faker.md](./references/faker.md) |
54
- | `zen rag` - searching an API description, or a pile of markdown | [rag.md](./references/rag.md) |
42
+ | The question is about | Read |
43
+ | ------------------------------------------------------------------- | --------------------------------------------------------------- |
44
+ | Global flags, `--json`, exit codes, environment, where files live | [frame.md](./references/frame.md) |
45
+ | Creating, finding or opening a project | [projects.md](./references/projects.md) |
46
+ | Running: the TUI, one-shot answers, sessions, workspaces, overrides | [run.md](./references/run.md) |
47
+ | Validating: `zen check`, what it can and cannot see | [check.md](./references/check.md) |
48
+ | API keys, providers, the keyring, "no credential" errors | [keys.md](./references/keys.md) |
49
+ | Which models exist, whether one works, recovering from a refusal | [models.md](./references/models.md) |
50
+ | The container shell commands run in, images, `persist` | [sandbox.md](./references/sandbox.md) (and `zen-sandbox` skill) |
51
+ | Run reports, trajectories, what a session directory holds | [inspect.md](./references/inspect.md) |
52
+ | What the agents remember, why something was recalled, forgetting | [memory.md](./references/memory.md) |
53
+ | `zen faker` - a mock API from an OpenAPI/Swagger document | [faker.md](./references/faker.md) |
54
+ | `zen rag` - searching an API description, or a pile of markdown | [rag.md](./references/rag.md) |
55
55
 
56
56
  ## The short version
57
57
 
@@ -21,6 +21,7 @@ What it writes:
21
21
  zenera.json { version, name }
22
22
  agents.yaml the configuration
23
23
  agents/instructions.md house rules, prepended to every agent
24
+ agents/files-instructions.md more of them, for agents that work with files
24
25
  agents/fork-instructions.md more of them, for agents that can fork
25
26
  agents/memory-instructions.md more of them, for agents with the memory store
26
27
  agents/tools-instructions.md more of them, about how tools are called
@@ -1,7 +1,7 @@
1
1
  # API search - `zen rag`
2
2
 
3
3
  ```
4
- zen rag schema <index|search|list|grep|trace|show|stats> [spec...]
4
+ zen rag schema <index|restore|ready|search|list|grep|trace|show|stats> [spec...]
5
5
  ```
6
6
 
7
7
  Provided by `@zenera/rag` - `npm i -g @zenera/rag` if `zen rag` says it is not
@@ -51,6 +51,36 @@ lance/ the vector and full-text indexes
51
51
  The manifest records the embedding ref **and** the embedder's own id, so a
52
52
  search with a different model is refused rather than quietly returning nonsense.
53
53
 
54
+ ## `ready` and `restore`
55
+
56
+ ```
57
+ zen rag <docs|schema> ready [-d <dir>] [--quiet] [--json]
58
+ zen rag <docs|schema> restore [-d <dir>] [--embedding <ref>] [--dimensions <n>]
59
+ ```
60
+
61
+ `lance/` is binary and rebuildable, so a project commits the index and
62
+ git-ignores the vectors. A clone then holds an index that looks built and cannot
63
+ search. `ready` is the question "can this answer", and the answer is the **exit
64
+ code**: 0 searchable, 3 absent or missing its vectors. It needs no embedder and
65
+ no credential.
66
+
67
+ `restore` re-embeds the index from the copies in its own `sources/`, so nothing
68
+ has to be fetched or found again. It is also how an index changes model:
69
+ `--embedding <ref>` re-embeds everything and rewrites the manifest. The rebuild
70
+ is staged beside the index and renamed into place, so a failure leaves the old
71
+ one intact - and needs room for both meanwhile. A schema index built with
72
+ `--no-sources` has nothing to restore from and is refused.
73
+
74
+ In a setup step, in this order:
75
+
76
+ ```sh
77
+ if [ "${FORCE:-0}" = 0 ] && zen rag docs ready --dir "$OUT" --quiet; then exit 3; fi
78
+ if [ "${FORCE:-0}" = 0 ] && [ -f "$OUT/manifest.json" ]; then
79
+ zen rag docs restore --dir "$OUT"; exit 0
80
+ fi
81
+ # … otherwise index it from the documents
82
+ ```
83
+
54
84
  ## Which index gets read
55
85
 
56
86
  Every reading command takes `-d`, `--dir`. Without one:
@@ -331,7 +361,7 @@ They share the group `schema`, so an agent takes them with `schema:*` in its
331
361
  # Document search - `zen rag docs`
332
362
 
333
363
  ```
334
- zen rag docs <index|search|list|grep|show|stats> [args...]
364
+ zen rag docs <index|restore|ready|search|list|grep|show|stats> [args...]
335
365
  ```
336
366
 
337
367
  The second subject of the same command. Where `schema` reads an API description
@@ -364,12 +394,16 @@ relative to the common root of everything indexed, which is what keeps
364
394
 
365
395
  ```
366
396
  docs-db/
367
- manifest.json written last; its presence means the index is complete
397
+ manifest.json written last; its presence means the build finished
368
398
  outline.json every heading and table, with the lines they cover
369
399
  sources/ the documents, verbatim
370
400
  lance/ one row per chunk: two texts, one vector, the filter columns
371
401
  ```
372
402
 
403
+ The manifest means the build finished, not that the index can answer here:
404
+ `lance/` is usually git-ignored. `ready` and `restore` above are the pair that
405
+ closes the difference, for both subjects.
406
+
373
407
  ## `search`
374
408
 
375
409
  ```
@@ -83,8 +83,33 @@ that tag is absent, which is safe precisely because the tag follows the content.
83
83
 
84
84
  ## Hardening
85
85
 
86
- `no-new-privileges`, an init process, a pid limit, no restart policy. Not
87
- `--cap-drop=ALL` (it breaks `apt` and `pip`) and never `--privileged`.
86
+ Every container gets the same floor: `no-new-privileges`, an init process, a
87
+ pid limit of 1024, resource limits (`cpus: 4`, `memory: 4096`), no restart
88
+ policy, podman's own seccomp profile (never turned off), and never
89
+ `--privileged`.
90
+
91
+ `hardening: standard` (the default) stops there. `--cap-drop=ALL` breaks `apt`
92
+ and `pip`, and installing a package is the ordinary use of a shell - so the
93
+ container is the boundary and nothing inside it is taken away.
94
+
95
+ ```yaml
96
+ sandbox:
97
+ hardening: strict
98
+ ```
99
+
100
+ `strict` is for running code nobody has read. It drops every capability,
101
+ mounts the root filesystem read-only with `/tmp` as a 64 MiB
102
+ `noexec,nosuid,nodev` tmpfs, runs as your own unprivileged uid via
103
+ `--userns keep-id`, and defaults `network` to `none` and `cpus`/`memory` to
104
+ `2`/`2048`. Name any of those keys yourself and your value wins.
105
+
106
+ Two consequences: nothing can be installed at run time, so a strict project
107
+ bakes its dependencies into the image with `build:`; and it needs rootless
108
+ podman, which is also what makes an escape land on an unprivileged host
109
+ account. Set `user:` explicitly to opt out of `keep-id`.
110
+
111
+ `/workspace` stays writable either way - `strict` shrinks what a command can
112
+ reach, not what the agent is there to edit.
88
113
 
89
114
  ## When it goes wrong
90
115
 
@@ -95,3 +120,6 @@ Podman is a warning.
95
120
 
96
121
  `zen sandbox clean` removes every container this CLI created - the way out of a
97
122
  container left on a bad rootfs.
123
+
124
+ For complete container architecture, the `sandbox:*` tools, mount rules, and
125
+ hardening details, load the `zen-sandbox` skill (`.github/skills/zen-sandbox/SKILL.md`).
@@ -0,0 +1,232 @@
1
+ ---
2
+ name: zen-instructions
3
+ description: The house rules - `agents/instructions.md` and every `agents/<topic>-instructions.md` prepended to every agent's system prompt. How the set is discovered and ordered, the `requires:` frontmatter and its closed vocabulary (`files`, `files-write`, `fork`, `memory`, `memory-write`, `memory-forget`), which four documents are `zen`'s own and are replaced by `zen check --fix`, how a project writes its own customisable topic prompts beside them (`files-policy-instructions.md`, `memory-policy-instructions.md`, `fork-<topic>-instructions.md`, `tools-<topic>-instructions.md`) without losing the copy, what belongs in a house rule as against an agent prompt or a skill, and every `zen check` finding these files can produce. Load before creating, editing, reviewing or deleting any `agents/*instructions.md`, before adding a capability whose rules arrive as one, and whenever `rules.stale`, `rules.unreached`, `files.uninstructed`, `memory.uninstructed` or `fork.uninstructed` is reported.
4
+ ---
5
+
6
+ # House rules
7
+
8
+ An agent's prompt is assembled, not written. The house rules are the part every
9
+ agent gets, whoever is answering:
10
+
11
+ ```
12
+ 1. agents/instructions.md the project's own, unconditional
13
+ 2. agents/<topic>-instructions.md every one of them, in filename order
14
+ 3. agents/prompts/<name>.md the agent's own job, or `system:`
15
+ ```
16
+
17
+ Each document arrives as its own block tagged with the file it came from -
18
+ `<house_rules src="agents/memory-instructions.md">` - so the model can tell one
19
+ from the next and a report can say which file a rule was in. The documents are
20
+ read **once** and the same objects are given to every agent, which is why
21
+ `zen inspect` says "one document, five prompts" instead of showing five
22
+ identical blobs.
23
+
24
+ They are also the stable head of the cached prefix. A line here is paid for on
25
+ every call by every agent, and a line added here invalidates that prefix for all
26
+ of them. Change them rarely and deliberately.
27
+
28
+ ## The set is a glob, not a list
29
+
30
+ There is **no key in `agents.yaml`** naming these files and no per-agent subset.
31
+ The loader takes `agents/instructions.md` first, then every file in `agents/`
32
+ whose name ends `-instructions.md`, sorted by filename. Directly inside
33
+ `agents/` only - `agents/prompts/style-instructions.md` is not one - and all of
34
+ it is optional: a one-agent project whose whole prompt is its role file needs
35
+ none of them.
36
+
37
+ Two consequences worth holding on to:
38
+
39
+ - **Adding a file is the whole wiring.** Nothing else has to be edited, and
40
+ nothing reports a file you meant to add and did not.
41
+ - **Order is the filename's**, because it is the only order that is the same on
42
+ every machine and is visible without opening anything. `agents/instructions.md`
43
+ does not end in `-instructions.md`, so it can never be counted twice.
44
+
45
+ ## Conditioning a document: `requires:`
46
+
47
+ A document about one capability says so in its own frontmatter, and then reaches
48
+ only the agents that have it:
49
+
50
+ ```markdown
51
+ ---
52
+ requires: [memory]
53
+ ---
54
+
55
+ # Memory
56
+
57
+ ...
58
+ ```
59
+
60
+ The condition lives on the document rather than in `agents.yaml` because the
61
+ condition and the prose it guards are one edit.
62
+
63
+ | Capability | Reaches an agent when |
64
+ | --------------- | -------------------------------------------------------------- |
65
+ | `files` | it declares file tools (`files:*` or individual file tools) |
66
+ | `files-write` | it declares file write tools (`apply_patch`, `write_file`, …) |
67
+ | `fork` | it declares `fork:` - and, at run time, is under the depth cap |
68
+ | `memory` | it declares `memory:` in any form |
69
+ | `memory-write` | its memory `access` is `read-write` or `full` |
70
+ | `memory-forget` | its memory `access` is `full` |
71
+
72
+ Legacy aliases `workspace` and `workspace-write` match `files` and `files-write`.
73
+
74
+ The vocabulary is **closed**. A name outside it is a load error
75
+ (`rules.requires.unknown`), not a rule that silently never fires. A list means
76
+ _all of it_ has to hold. There is no `not`: a rule for agents _without_ a
77
+ capability is a rule about the rest of the project, which is what
78
+ `agents/instructions.md` is for. No frontmatter means unconditional, which is
79
+ the usual case.
80
+
81
+ `fork` carries a run-time half as well - the tool is withdrawn at the fork depth
82
+ cap, and a rule about a tool the model does not have is a rule it can only be
83
+ confused by.
84
+
85
+ ## Two owners, in the same directory
86
+
87
+ | File | Whose | `requires:` | Is |
88
+ | --------------------------------------- | --------- | ----------- | --------------------------------------------------------- |
89
+ | `agents/instructions.md` | project's | - | identity, shared model of the system, global constraints |
90
+ | `agents/tools-instructions.md` | **ours** | - | how tools are called: narrate, batch the independent ones |
91
+ | `agents/files-instructions.md` | **ours** | `files` | how files are read, searched and patched; safety, mounts |
92
+ | `agents/memory-instructions.md` | **ours** | `memory` | how the graph is reached, what to commit, how to correct |
93
+ | `agents/fork-instructions.md` | **ours** | `fork` | what a branch is, what returns, when it is worth it |
94
+ | `agents/tools-<topic>-instructions.md` | project's | yours | **this project's** tool policy |
95
+ | `agents/files-<topic>-instructions.md` | project's | `files` | **this project's** file policy |
96
+ | `agents/memory-<topic>-instructions.md` | project's | `memory` | **this project's** memory policy |
97
+ | `agents/fork-<topic>-instructions.md` | project's | `fork` | **this project's** forking policy |
98
+
99
+ The four marked **ours** describe _this version of `zen`_ - how the memory
100
+ graph works, how its tools are called, what survives a join, how files are safely
101
+ handled. They land under `agents/` only because that is where a document has to
102
+ be to reach a prompt. They are not the project's to maintain:
103
+
104
+ - `zen check --fix` **replaces all four** with the bytes this `zen` ships.
105
+ - A copy that differs - edited in place, or scaffolded by an older `zen` - is
106
+ reported as `rules.stale`, because prose about a runtime that has since moved
107
+ reads exactly as authoritative as the version that is true.
108
+ - So an edit made in one of them is lost at the next `--fix`, and a rule that
109
+ mattered is gone without a diff to show for it.
110
+
111
+ They arrive whether or not the project uses the capability; their `requires:` is
112
+ what keeps an inert one out of every prompt.
113
+
114
+ ## The project's own topic prompts
115
+
116
+ This is the customisation point, and it is a **file beside**, never an edit
117
+ inside. Anything this project decides for itself on a subject one of ours
118
+ covers - which audience holds what, what must never be written down, how wide a
119
+ fan-out may go, which tools are off limits here - is its own document:
120
+
121
+ | Instead of editing | Write |
122
+ | ------------------------ | -------------------------------------- |
123
+ | `files-instructions.md` | `agents/files-policy-instructions.md` |
124
+ | `memory-instructions.md` | `agents/memory-policy-instructions.md` |
125
+ | `fork-instructions.md` | `agents/fork-policy-instructions.md` |
126
+ | `tools-instructions.md` | `agents/tools-policy-instructions.md` |
127
+
128
+ `<topic>` is yours; `policy` is the convention and needs no explaining. Then a
129
+ `zen check --fix`, a `zen init` or a `zen open` refreshes our copy and takes
130
+ nothing of yours with it.
131
+
132
+ Three things to get right:
133
+
134
+ 1. **`requires:` is not inherited.** A `memory-policy-instructions.md` with no
135
+ frontmatter reaches every agent, including ones with no store. Copy the
136
+ condition from the document it qualifies - usually the same line.
137
+ 2. **Filename order decides what qualifies what.** A policy meant to be read
138
+ after our rules needs a topic word that sorts after `instructions`:
139
+ `memory-policy-…` lands after `memory-instructions.md` (`p` > `i`), and
140
+ `memory-audience-…` lands **before** it (`a` < `i`), qualifying prose the
141
+ model has not read yet.
142
+ 3. **It is a prompt, not a note.** Second person, imperative, failure paths
143
+ stated. Everything §4.2 of the copilot instructions says applies in full.
144
+
145
+ ## What belongs in a house rule
146
+
147
+ Only what is true for **every** agent the document reaches:
148
+
149
+ - identity and domain - _"You work the property claims desk"_
150
+ - non-negotiable prohibitions: regulatory, legal, safety
151
+ - global format and tone constraints
152
+ - domain vocabulary and identifier formats
153
+ - the shared model of the system: what the agents are collectively for, and how
154
+ work moves between them, in terms they can act on - _"the adjuster owns
155
+ coverage decisions; you do not"_ - not in terms of files or YAML keys
156
+
157
+ Not here:
158
+
159
+ | That | Goes in |
160
+ | --------------------------------------------- | --------------------------------- |
161
+ | Anything one agent needs and another does not | `agents/prompts/<name>.md` |
162
+ | Long reference data, procedures, tables | a skill, loaded when it is needed |
163
+ | Anything that changes weekly | a skill, or `assets/` |
164
+ | A tour of the codebase | nowhere - it is not a README |
165
+
166
+ If you find yourself writing _"if you are the router…"_, you are in the wrong
167
+ file. Target 20-60 lines per document; past ~100, split the stable half into a
168
+ preloaded skill.
169
+
170
+ Split a topic out of `agents/instructions.md` when it is true for every agent
171
+ but belongs to **one capability** - it then arrives when the capability is
172
+ turned on and is deleted when it is turned off, which is a whole file rather
173
+ than a section somebody has to find. Do not split by author, by date, or to keep
174
+ a file short.
175
+
176
+ ## Paths
177
+
178
+ Every path-shaped token in these files is read by a model as an instruction to
179
+ open something, and a running agent sees four: `/workspace`, `/assets`,
180
+ `/skills`, `/memory`. The sweep is in the `zen-review` skill:
181
+
182
+ ```sh
183
+ .github/skills/zen-review/scripts/check-paths.sh
184
+ ```
185
+
186
+ It reads `agents/*instructions.md` and exits `1` on any candidate.
187
+ `agents/memory-instructions.md` is exempt: it is worked examples by design, and
188
+ `check-instructions.sh` is the check it actually needs.
189
+
190
+ ## What `zen check` reports
191
+
192
+ | Finding | Severity | Means |
193
+ | ------------------------ | -------- | ---------------------------------------------------------------- |
194
+ | `rules.requires.unknown` | error | `requires:` names no capability - the loader refuses the project |
195
+ | `files.uninstructed` | error | an agent has file tools and `files-instructions.md` is absent |
196
+ | `memory.uninstructed` | error | memory is on and `memory-instructions.md` is missing or empty |
197
+ | `fork.uninstructed` | error | an agent can fork and `fork-instructions.md` is missing or empty |
198
+ | `rules.stale` | warning | one of ours is not the copy this `zen` ships |
199
+ | `house-rules.empty` | warning | a document contributes nothing but a prompt section |
200
+ | `rules.unreached` | note | a document of **yours** whose `requires:` no agent satisfies |
201
+ | `house-rules.missing` | note | no house rules at all, which is allowed |
202
+
203
+ `zen check --fix` answers the first five between them: it rewrites all four of
204
+ ours and the whole `.github/` tree, then validates, so the report and its exit
205
+ code describe the repaired project.
206
+
207
+ Two silences to know about. **There is no `tools.uninstructed`** - that document
208
+ is unconditional and its absence is not reported, so a project that deleted it
209
+ is quietly a project whose agents were never told how to call a tool. And
210
+ `rules.unreached` deliberately never fires for ours, because they land in every
211
+ project whether the capability is used or not.
212
+
213
+ The memory copy has a check of its own, byte for byte, because the two files
214
+ drift by trailing whitespace inside tables and that is invisible on screen:
215
+
216
+ ```sh
217
+ .github/skills/zen-memory/scripts/check-instructions.sh # the verdict
218
+ .github/skills/zen-memory/scripts/check-instructions.sh diff # every differing line
219
+ .github/skills/zen-memory/scripts/check-instructions.sh fix # copy the reference over
220
+ ```
221
+
222
+ Never read the two against each other by eye, and never paraphrase the reference
223
+ into prose of your own.
224
+
225
+ ## Related
226
+
227
+ - `zen-memory` - what `memory-instructions.md` says, and how to design a policy
228
+ to put beside it
229
+ - `zen-review` - the path sweep and the rest of the mechanical review
230
+ - `zen-cli` - `zen check`, `zen check --fix`, `zen init`, `zen open`
231
+ - §3.2 and §5.3 of `.github/copilot-instructions.md` - the short form of all of
232
+ the above