@zenera/cli 1.1.16 → 1.1.18

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 (71) hide show
  1. package/README.md +110 -19
  2. package/dist/banner.d.ts +19 -0
  3. package/dist/banner.js +12 -9
  4. package/dist/catalog.js +19 -20
  5. package/dist/command.d.ts +3 -0
  6. package/dist/commands/check.js +5 -1
  7. package/dist/commands/index.js +4 -1
  8. package/dist/commands/init.js +42 -7
  9. package/dist/commands/inspect.js +77 -13
  10. package/dist/commands/key.js +49 -1
  11. package/dist/commands/memory.js +16 -3
  12. package/dist/commands/meta.d.ts +3 -0
  13. package/dist/commands/meta.js +596 -0
  14. package/dist/commands/run.js +64 -35
  15. package/dist/engine.d.ts +15 -0
  16. package/dist/engine.js +26 -1
  17. package/dist/env.d.ts +20 -0
  18. package/dist/env.js +65 -0
  19. package/dist/home.d.ts +2 -0
  20. package/dist/home.js +2 -0
  21. package/dist/keys.d.ts +2 -0
  22. package/dist/keys.js +2 -0
  23. package/dist/main.js +1 -1
  24. package/dist/meta.d.ts +221 -0
  25. package/dist/meta.js +695 -0
  26. package/dist/podman.js +64 -2
  27. package/dist/projects.d.ts +9 -1
  28. package/dist/projects.js +19 -2
  29. package/dist/resolve.js +7 -1
  30. package/dist/sandbox.d.ts +11 -0
  31. package/dist/sandbox.js +24 -4
  32. package/dist/scaffold.d.ts +6 -0
  33. package/dist/scaffold.js +56 -15
  34. package/dist/session.d.ts +10 -0
  35. package/dist/session.js +19 -1
  36. package/dist/term.d.ts +7 -0
  37. package/dist/term.js +8 -1
  38. package/dist/tui/app.js +33 -5
  39. package/dist/tui/wrap.d.ts +1 -1
  40. package/dist/tui/wrap.js +1 -1
  41. package/dist/validate.js +57 -15
  42. package/package.json +3 -2
  43. package/templates/editor/.github/copilot-instructions.md +313 -94
  44. package/templates/editor/.github/prompts/project-review.prompt.md +74 -0
  45. package/templates/editor/.github/prompts/spec-apply-feedback.prompt.md +142 -0
  46. package/templates/editor/.github/prompts/spec-sync-project.prompt.md +392 -0
  47. package/templates/editor/.github/skills/zen-cli/references/check.md +6 -3
  48. package/templates/editor/.github/skills/zen-cli/references/frame.md +5 -3
  49. package/templates/editor/.github/skills/zen-cli/references/inspect.md +4 -3
  50. package/templates/editor/.github/skills/zen-cli/references/memory.md +14 -0
  51. package/templates/editor/.github/skills/zen-cli/references/projects.md +19 -2
  52. package/templates/editor/.github/skills/zen-cli/references/run.md +75 -16
  53. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +6 -0
  54. package/templates/editor/.github/skills/zen-memory/SKILL.md +153 -33
  55. package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +115 -0
  56. package/templates/editor/.github/skills/zen-review/SKILL.md +123 -0
  57. package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +119 -0
  58. package/templates/editor/.github/skills/zen-review/scripts/review.sh +104 -0
  59. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +197 -0
  60. package/templates/editor/.github/skills/zen-spec-sync/scripts/snapshot.sh +200 -0
  61. package/templates/editor/.vscode/settings.json +44 -4
  62. package/templates/parts/memory-terms.yaml.tmpl +16 -0
  63. package/templates/parts/memory.yaml.tmpl +12 -0
  64. package/templates/project/SPECIFICATION.md.tmpl +32 -2
  65. package/templates/project/agents/memory-instructions.md +278 -0
  66. package/templates/project/agents.yaml.tmpl +12 -3
  67. package/templates/project/env +28 -0
  68. package/templates/project/gitignore +4 -4
  69. package/templates/editor/.github/prompts/review-project.prompt.md +0 -36
  70. package/templates/editor/.github/prompts/sync-with-spec.prompt.md +0 -205
  71. /package/templates/project/{INSTRUCTIONS.md → agents/instructions.md} +0 -0
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: zen-review
3
+ description: Checking a project before committing - the four mechanical checks `/project-review` makes before any judgement (`zen check`, the §2.5 path sweep, the memory house-rules copy, the spec-sync record), what each one owns, what their exit codes mean, and what deliberately has no check because no tool can make it. Load before running `/project-review`, before saying a project is ready, and whenever a review finding needs verifying rather than restating.
4
+ ---
5
+
6
+ # Reviewing a project
7
+
8
+ A review of an agent project is two jobs wearing one name. One half is
9
+ decidable - a schema is valid or it is not, a path resolves or it does not, a
10
+ copy matches its reference or it does not - and a human doing it by hand gets it
11
+ wrong in the same three places every time. The other half is judgement: whether
12
+ an agent has one job, whether a description routes, whether a number is in the
13
+ wrong file.
14
+
15
+ This skill owns the first half, so the prompt can be all of the second.
16
+
17
+ ## The one command
18
+
19
+ From the project root, or anywhere at all:
20
+
21
+ ```sh
22
+ .github/skills/zen-review/scripts/review.sh
23
+ ```
24
+
25
+ It runs four checks in the order a reviewer needs them and prints a summary:
26
+
27
+ | Step | Runs | Owns |
28
+ | ----------- | ------------------------------------------ | -------------------------------------------- |
29
+ | `zen check` | the CLI | everything decidable about the configuration |
30
+ | `paths` | `zen-review/scripts/check-paths.sh` | paths a running agent cannot open - §2.5 |
31
+ | `memory` | `zen-memory/scripts/check-instructions.sh` | the house-rules copy, byte for byte - §5.3 |
32
+ | `spec-sync` | `zen-spec-sync/scripts/snapshot.sh status` | whether the record of the last pass is sound |
33
+
34
+ Every step runs even when an earlier one fails, because a review that stops at
35
+ the first problem is one somebody has to run four times. The exit code is `1` if
36
+ any step wants attention and `0` if none does. `review.sh fast` passes
37
+ `--no-models --no-sandbox` to `zen check`, which is the right call while
38
+ iterating and the wrong one before committing - a key that authenticates says
39
+ nothing about the model id it is spent on.
40
+
41
+ Nothing below matters while `zen check` fails. Report what it said and fix that
42
+ first.
43
+
44
+ ## The two scripts this skill ships
45
+
46
+ ### `check-paths.sh` - the §2.5 sweep
47
+
48
+ A running agent's whole world is four paths: `/workspace`, `/assets`, `/skills`
49
+ and `/memory`. Every path-shaped token in `agents/*instructions.md`,
50
+ `agents/prompts/*.md` and a skill's markdown is read by a model as an
51
+ instruction to open something, so anything outside those four is an instruction
52
+ to open a file that is not there.
53
+
54
+ ```sh
55
+ .github/skills/zen-review/scripts/check-paths.sh # each candidate, with file and line
56
+ .github/skills/zen-review/scripts/check-paths.sh raw # the tokens alone, unfiltered
57
+ ```
58
+
59
+ It exits `1` whenever it prints a candidate, because the list is meant to be
60
+ emptied or explained rather than skimmed. It strips urls before tokenising, skips
61
+ a handful of English constructions that contain a slash, and leaves
62
+ `agents/memory-instructions.md` out entirely - that file is worked examples by
63
+ design, and `check-instructions.sh` is the check it actually needs.
64
+
65
+ Everything it does print is either noise the script has not learned yet or a
66
+ real finding. There is no third case. A candidate that is genuinely noise is a
67
+ one-line addition to `NOISE` in the script - **upstream**, see below, not in the
68
+ copy sitting in this project.
69
+
70
+ `raw` is the sweep with nothing filtered, for when you suspect the filter.
71
+
72
+ ### `check-instructions.sh` - the memory house rules
73
+
74
+ Lives in the `zen-memory` skill, because it is about memory and it is read at
75
+ the moment that skill is:
76
+
77
+ ```sh
78
+ .github/skills/zen-memory/scripts/check-instructions.sh # the verdict
79
+ .github/skills/zen-memory/scripts/check-instructions.sh diff # and every differing line
80
+ .github/skills/zen-memory/scripts/check-instructions.sh fix # copy the reference over
81
+ ```
82
+
83
+ `agents/memory-instructions.md` must be a byte-identical copy of the `zen-memory`
84
+ skill's `references/memory-instructions.md`, and the reference is rewritten by
85
+ every `zen init` and `zen open`, so the copy goes stale without anyone touching
86
+ it. It drifts by **trailing whitespace inside tables**, which is invisible on
87
+ screen - this is the check no one should be asked to make by eye. When the
88
+ difference is whitespace alone the script says so, because that is the usual
89
+ cause and the least believable finding.
90
+
91
+ `fix` is the one-line `cp` and nothing else. Project policy belongs in
92
+ `agents/memory-policy-instructions.md`, which filename order puts directly after
93
+ the copy - see the `zen-memory` skill.
94
+
95
+ ## What has no check, on purpose
96
+
97
+ Not because it would be hard, but because the answer would be wrong:
98
+
99
+ - **Whether an agent has one job.** Read the prompt.
100
+ - **Whether a description routes.** Two overlapping descriptions both parse.
101
+ - **Whether a fact belongs in a skill.** A threshold in a prompt is valid YAML.
102
+ - **Whether a tool grant is justified.** `zen check` confirms the selector
103
+ resolves, never that the agent needs it.
104
+ - **Whether the newest spec-sync history entry is honest.** A pass can claim
105
+ anything; only reading the diff says whether it did it.
106
+
107
+ That list is `/project-review`, and §9 of the copilot instructions is the long
108
+ form. Run the script first so the prompt is spent on this.
109
+
110
+ ## Where these scripts live, and why edits to them vanish
111
+
112
+ `zen init` and `zen open` rewrite the whole `.github/` tree from the version of
113
+ `zen` in hand. These scripts arrive with it, so a change made to the copy in a
114
+ project is gone at the next `open`. A filter that should hold for every project
115
+ belongs in the distribution - `packages/cli/templates/editor/.github/skills/` in
116
+ the @zenera/neo repository - and reaches this project the next time the tree is
117
+ written.
118
+
119
+ Do not confuse these with a project's own scripts. `agents/skills/<name>/scripts/`
120
+ is run by **the project's agents**, inside the sandbox, at
121
+ `/skills/<name>/scripts/…`. `.github/skills/<name>/scripts/` is run by **the
122
+ editor's assistant**, on the host, at a workspace path. The two have different
123
+ readers and neither can see the other.
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Every path-shaped token a running agent would be told to open, minus the ones
4
+ # that exist. The §2.5 sweep, as a script rather than a command to retype.
5
+ #
6
+ # check-paths.sh each candidate, with the file and line it is on
7
+ # check-paths.sh raw the tokens alone, unfiltered — the sweep itself
8
+ #
9
+ # A running agent sees four paths: /workspace, /assets, /skills and /memory.
10
+ # Everything else printed here is either noise this script has not learned yet
11
+ # or an instruction to open a file that is not there. There is no third case,
12
+ # which is why this exits non-zero whenever it prints one: the list is meant to
13
+ # be emptied or explained, not skimmed.
14
+ #
15
+ # Run it from anywhere; it finds the project root from its own location.
16
+
17
+ set -eu
18
+ cd "$(dirname "$0")/../../../.."
19
+
20
+ # What a path looks like in prose. §2.5 of the copilot instructions describes
21
+ # the sweep and sends you here for it, so this is the only copy of the pattern.
22
+ # Every segment after the first is taken too: matched one segment at a time,
23
+ # `/skills/house_style/examples.md` comes back as a mount that resolves *and* a
24
+ # stray `/examples.md`, and that fragment is noise on every run of every project.
25
+ TOKEN='[~.]?/?[A-Za-z0-9_.-]*(/[A-Za-z0-9_.*-]+)+'
26
+
27
+ # The four mounts, and only those: a token under one of them is a path that
28
+ # resolves.
29
+ MOUNTS='^/(workspace|assets|skills|memory)(/|$)'
30
+
31
+ # English that happens to contain a slash, and the placeholder paths of a
32
+ # worked example. Add to this rather than teaching a reviewer to skip the same
33
+ # line every run.
34
+ NOISE='^(and/or|he/she|his/her|input/output|read/write|w/o|n/a|N/A|24/7|km/h)$|^(path|foo)/'
35
+
36
+ # A url, stripped before tokenising rather than filtered after it — the token
37
+ # regex reads `https://acme.dev/docs` as `//acme.dev` *and* `/docs`, and the
38
+ # second half is indistinguishable from a real absolute path once it is alone.
39
+ strip_urls() {
40
+ sed -E 's#[a-zA-Z][a-zA-Z0-9+.-]*://[^][ )"'"'"'`>]*##g' "$1"
41
+ }
42
+
43
+ # The three trees §2.5 names, prose only: a skill's own script is code the
44
+ # sandbox runs, not text rendered into a prompt, and its paths are its own.
45
+ #
46
+ # `agents/memory-instructions.md` is left out on purpose. It is a copy of the
47
+ # reference, full of worked examples, so it fails this sweep by design and
48
+ # every run of it — and it has a check of its own that a sweep cannot make:
49
+ # .github/skills/zen-memory/scripts/check-instructions.sh
50
+ files() {
51
+ {
52
+ if [ -d agents/prompts ]; then find agents/prompts -type f -name '*.md'; fi
53
+ if [ -d agents/skills ]; then find agents/skills -type f -name '*.md'; fi
54
+ for file in agents/*instructions.md; do
55
+ if [ -f "$file" ]; then echo "$file"; fi
56
+ done
57
+ } | grep -v '^agents/memory-instructions\.md$' | sort -u
58
+ }
59
+
60
+ # Every token in those files, urls removed first, and a sentence's full stop
61
+ # trimmed off the end — no path ends in a dot, and `/workspace.` would
62
+ # otherwise read as a mount that does not exist.
63
+ sweep() {
64
+ while IFS= read -r file; do
65
+ if [ -n "$file" ]; then
66
+ strip_urls "$file"
67
+ fi
68
+ done <<EOF
69
+ $(files)
70
+ EOF
71
+ }
72
+
73
+ tokens() {
74
+ sweep | grep -Eoh "$TOKEN" | sed 's/\.*$//' | sort -u
75
+ }
76
+
77
+ candidates() {
78
+ tokens | grep -Ev "$MOUNTS" | grep -Ev "$NOISE" || true
79
+ }
80
+
81
+ # Where a token came from, so a finding names a file and a line rather than
82
+ # sending someone back to grep for it.
83
+ where() {
84
+ while IFS= read -r file; do
85
+ if [ -n "$file" ]; then
86
+ grep -nF -- "$1" "$file" | sed "s|^| $file:|" | cut -d: -f1,2
87
+ fi
88
+ done <<EOF
89
+ $(files)
90
+ EOF
91
+ }
92
+
93
+ report() {
94
+ found=0
95
+ while IFS= read -r token; do
96
+ if [ -n "$token" ]; then
97
+ found=$((found + 1))
98
+ echo "path: $token"
99
+ where "$token"
100
+ fi
101
+ done <<EOF
102
+ $(candidates)
103
+ EOF
104
+ if [ "$found" -eq 0 ]; then
105
+ echo "ok: every path in the three trees is under a mount"
106
+ return 0
107
+ fi
108
+ echo "candidates: $found to explain or fix"
109
+ return 1
110
+ }
111
+
112
+ case "${1:-report}" in
113
+ report) report ;;
114
+ raw) tokens ;;
115
+ *)
116
+ echo "usage: check-paths.sh [report|raw]" >&2
117
+ exit 2
118
+ ;;
119
+ esac
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Every check a review can make without judgement, in the order it makes them.
4
+ #
5
+ # review.sh zen check, then paths, memory, and the spec-sync record
6
+ # review.sh fast the same, with `zen check --no-models --no-sandbox`
7
+ #
8
+ # What it prints is findings. What it cannot see — whether an agent has one job,
9
+ # whether a description is a condition, whether a fact belongs in a skill — is
10
+ # the rest of /project-review, and the reason that prompt still exists.
11
+ #
12
+ # Every step runs even when an earlier one fails: a review that stops at the
13
+ # first problem is one somebody has to run four times. The exit code is 1 if
14
+ # anything wants attention, 0 if nothing does.
15
+ #
16
+ # Run it from anywhere; it finds the project root from its own location.
17
+
18
+ set -u
19
+ cd "$(dirname "$0")/../../../.."
20
+
21
+ SKILLS=.github/skills
22
+ CHECK_FLAGS=""
23
+
24
+ case "${1:-full}" in
25
+ full) ;;
26
+ fast) CHECK_FLAGS="--no-models --no-sandbox" ;;
27
+ *)
28
+ echo "usage: review.sh [full|fast]" >&2
29
+ exit 2
30
+ ;;
31
+ esac
32
+
33
+ SUMMARY=""
34
+ WORST=0
35
+
36
+ # Records one step's verdict for the summary, and remembers the worst of them.
37
+ verdict() {
38
+ SUMMARY="$SUMMARY$1: $2
39
+ "
40
+ if [ "$3" -ne 0 ]; then
41
+ WORST=1
42
+ fi
43
+ }
44
+
45
+ step() {
46
+ printf '\n--- %s ---\n' "$1"
47
+ }
48
+
49
+ step 'zen check'
50
+ if command -v zen >/dev/null 2>&1; then
51
+ # Unquoted on purpose: empty means no flags rather than one empty argument.
52
+ # shellcheck disable=SC2086
53
+ zen check $CHECK_FLAGS
54
+ rc=$?
55
+ if [ "$rc" -eq 0 ]; then
56
+ verdict 'zen check' 'ok' 0
57
+ else
58
+ verdict 'zen check' "exit $rc — nothing below matters until this passes" 1
59
+ fi
60
+ else
61
+ echo "zen is not on PATH — install it, or run the other three alone"
62
+ verdict 'zen check' 'not run' 1
63
+ fi
64
+
65
+ step 'paths'
66
+ "$SKILLS/zen-review/scripts/check-paths.sh"
67
+ rc=$?
68
+ if [ "$rc" -eq 0 ]; then
69
+ verdict 'paths' 'ok' 0
70
+ else
71
+ verdict 'paths' 'candidates to explain or fix' 1
72
+ fi
73
+
74
+ step 'memory'
75
+ "$SKILLS/zen-memory/scripts/check-instructions.sh"
76
+ rc=$?
77
+ if [ "$rc" -eq 0 ]; then
78
+ verdict 'memory' 'ok' 0
79
+ else
80
+ verdict 'memory' 'the house rules are missing or stale' 1
81
+ fi
82
+
83
+ step 'spec-sync'
84
+ if [ -f SPECIFICATION.md ]; then
85
+ # `status` reports a tampered baseline rather than failing on one, so the
86
+ # verdict has to read what it said.
87
+ state="$("$SKILLS/zen-spec-sync/scripts/snapshot.sh" status)"
88
+ rc=$?
89
+ printf '%s\n' "$state"
90
+ if [ "$rc" -ne 0 ]; then
91
+ verdict 'spec-sync' "exit $rc" 1
92
+ elif printf '%s' "$state" | grep -q 'mode: tampered'; then
93
+ verdict 'spec-sync' 'the baseline does not match its own manifest' 1
94
+ else
95
+ verdict 'spec-sync' "$(printf '%s' "$state" | sed -n 's/^mode: /mode /p')" 0
96
+ fi
97
+ else
98
+ echo "no SPECIFICATION.md — this project keeps no spec-sync record"
99
+ verdict 'spec-sync' 'not applicable' 0
100
+ fi
101
+
102
+ step 'summary'
103
+ printf '%s' "$SUMMARY"
104
+ exit "$WORST"
@@ -0,0 +1,197 @@
1
+ ---
2
+ name: zen-spec-sync
3
+ description: Running `/spec-sync-project` as an incremental pass - the committed `.spec-sync` baseline of what the last pass applied, how to scope a pass from the specification and feedback diffs and from what moved in the project itself, the four checks a narrow pass may never skip, the iteration history format, and why the baseline is written last. Load before every `/spec-sync-project`, including the first one on a project that has no baseline yet.
4
+ ---
5
+
6
+ # Syncing a project with its specification, one change at a time
7
+
8
+ `SPECIFICATION.md` is the intent and the files are the implementation, so
9
+ bringing the two together is a pass over the whole project. Done from nothing
10
+ every time, that pass re-reads every prompt, re-derives every decision the last
11
+ one already made, and re-raises questions someone has already answered.
12
+
13
+ A pass is worth repeating cheaply, so it keeps a record of **what it applied**.
14
+ The next pass diffs the specification against that record and works the
15
+ difference. What it must not do is confuse a narrow diff with a narrow
16
+ obligation: the record scopes what you _read and edit_, never what you _verify_.
17
+
18
+ ## What this owns
19
+
20
+ Everything is committed. `.spec-sync/` is a record, not scratch - `.tmp/` is
21
+ scratch.
22
+
23
+ ```
24
+ .spec-sync/
25
+ ├── baseline/
26
+ │ ├── SPECIFICATION.md the spec the last completed pass applied
27
+ │ ├── SPECIFICATION-FEEDBACK.md the questions it had open, if any
28
+ │ ├── agents.yaml the wiring it left behind
29
+ │ ├── agents/ and every instruction, prompt and skill
30
+ │ ├── applied.txt the history entry this baseline belongs to
31
+ │ └── manifest.txt sha256 of every file above
32
+ └── history/
33
+ └── 2026-09-13T104500Z.md one file per pass, never edited after
34
+ ```
35
+
36
+ The baseline mirrors the paths it records, so `baseline/agents/skills/x/SKILL.md`
37
+ is that skill as the last completed pass left it. Both sides are there on
38
+ purpose: the specification and the feedback say what was **asked for**, the
39
+ wiring and the `agents/` tree say what was **built**, and a pass has to know
40
+ which of the two moved.
41
+
42
+ The baseline is **not a copy of the current specification**. It is the
43
+ specification as the last completed pass left it, which is what makes the
44
+ difference between the two mean "work nobody has done yet".
45
+
46
+ `zen init` creates `baseline/` and `history/` empty, and git does not carry an
47
+ empty directory, so **the presence of `.spec-sync/` proves nothing**. The
48
+ manifest is the signal: no `manifest.txt` means no pass has ever completed.
49
+
50
+ ## Deciding the size of the pass
51
+
52
+ Run this first, from the project root:
53
+
54
+ ```sh
55
+ .github/skills/zen-spec-sync/scripts/snapshot.sh status
56
+ ```
57
+
58
+ It prints one `mode:` line, the `applied:` stamp the baseline belongs to, and a
59
+ `changed:` line per file that differs - specification, feedback, `agents.yaml`
60
+ or anything under `agents/`:
61
+
62
+ | Mode | Means | Do |
63
+ | ------------- | ------------------------------------------ | ------------------------------------------------------------------------------------- |
64
+ | `full` | no manifest - no pass has ever completed | the whole prompt as written, then write the first baseline |
65
+ | `incremental` | a baseline is there and the files differ | scope from the four inputs below |
66
+ | `tampered` | a baseline file does not match its own sha | treat as `full`, and say in the chat which file and that the baseline was not trusted |
67
+
68
+ `tampered` is either a baseline edited by hand or a pass that died between
69
+ copying the files and writing the manifest. Both mean the record is not
70
+ evidence. Do not rewrite `manifest.txt` to make the message go away - that
71
+ asserts a pass happened that did not.
72
+
73
+ `snapshot.sh diff` then prints the unified diffs, and is where the pass
74
+ actually starts.
75
+
76
+ ## The four scope inputs
77
+
78
+ An incremental pass is scoped by the union of these. Write the union down before
79
+ editing anything, and report it in the chat as the pass's scope.
80
+
81
+ 1. **The `SPECIFICATION.md` diff.** The primary input: added, changed and
82
+ deleted requirements. A deleted requirement is work too - what implemented it
83
+ is now an **extra**, to be reported under `➕` rather than quietly deleted.
84
+ 2. **The `SPECIFICATION-FEEDBACK.md` diff.** The file is a questionnaire the
85
+ human answers by ticking one answer's `[ ]` box or deleting the answers they
86
+ do not want. A question that has moved under `✅ Answered` was folded into the
87
+ specification by `/spec-apply-feedback`, and its **Still to implement**
88
+ line is the work. A question with a box marked `[x]`, or one answer left
89
+ under it, and no `✅` entry was answered and never folded in - implement it,
90
+ put its text into `SPECIFICATION.md`, and say so. A new question someone else
91
+ raised is work too. Close what this pass resolves rather than re-raising it.
92
+ 3. **What the last pass left open.** The `Still open` section of the entry named
93
+ by `applied:`, in `.spec-sync/history/`. A specification line that has not
94
+ changed since the baseline is **not therefore implemented**: the baseline
95
+ records what the pass applied, and a pass can complete with items open. This
96
+ is the only place that says which.
97
+ 4. **The implementation diff.** `agents.yaml` and every file under `agents/` -
98
+ instructions, prompts and skills. This side is what was built rather than
99
+ what was asked for, so it never narrows a pass: it says what moved under you
100
+ since the last one. An agent, tool grant, handoff, model, house rule, prompt
101
+ or skill edited outside a pass **widens** the pass to everything that names
102
+ what changed, and the edit is itself an item - either the specification
103
+ covers it, and you say which line, or it does not, and it is an **extra**
104
+ reported under `➕`.
105
+
106
+ ## The four checks a narrow pass may never skip
107
+
108
+ However small the diff:
109
+
110
+ 1. **`zen check` passes.** Run it before the first edit and again after the
111
+ last.
112
+ 2. **`scripts/_setup.sh` has run to completion in this session, and re-runs
113
+ clean.** A one-line specification change can still break a setup step, and a
114
+ pass that did not run it does not know.
115
+ 3. **§9 of the copilot instructions, worked as a checklist**, group by group.
116
+ 4. **The capability obligations in §0.1.** For every capability the project has
117
+ turned on, load that capability's skill and re-check what it requires - in
118
+ particular that `agents/memory-instructions.md` is still byte-identical to
119
+ `.github/skills/zen-memory/references/memory-instructions.md`. `zen init` and
120
+ `zen open` rewrite the reference, so this drifts without anybody editing the
121
+ project.
122
+
123
+ A narrow diff narrows reading and editing. It does not narrow verification.
124
+
125
+ ## What else an incremental pass still owes
126
+
127
+ The reverse pass of §2 - reading each line and naming the specification item it
128
+ serves - runs over every file this pass touched, plus every file the
129
+ implementation diff named. It is the only pass that finds a line contradicting
130
+ another file, and an edit made this session, or made by hand since the last
131
+ pass, is exactly where a new contradiction comes from.
132
+
133
+ ## The history entry
134
+
135
+ One file per pass, `.spec-sync/history/<stamp>.md`, where the stamp is UTC and
136
+ filename-safe: `date -u +%Y-%m-%dT%H%M%SZ`. Never edit a file that is already
137
+ there; a pass that did nothing still writes one saying so.
138
+
139
+ These headings, in this order, because the next pass reads them:
140
+
141
+ ```markdown
142
+ # Sync pass 2026-09-13T104500Z
143
+
144
+ - **Mode** - incremental
145
+ - **Spec sha** - 3f9a… (`shasum -a 256 SPECIFICATION.md`)
146
+
147
+ ## Scope
148
+
149
+ What drove the pass: the diff hunks, the feedback entries, what the last pass
150
+ left open. `full` if it was a full pass.
151
+
152
+ ## Changed
153
+
154
+ One row per file changed, and the specification item it closes.
155
+
156
+ ## Feedback
157
+
158
+ Entries opened and entries closed, by number.
159
+
160
+ ## Still open
161
+
162
+ Every specification item this pass did **not** close, with its
163
+ `SPECIFICATION-FEEDBACK.md` anchor. Empty means empty - this is what the next
164
+ pass trusts.
165
+
166
+ ## Checks
167
+
168
+ `zen check`, each `scripts/_setup.sh` step, and the §9 groups: pass or fail.
169
+ ```
170
+
171
+ ## Write the baseline last
172
+
173
+ The one rule that must not be got wrong.
174
+
175
+ ```sh
176
+ .github/skills/zen-spec-sync/scripts/snapshot.sh commit
177
+ ```
178
+
179
+ runs **after** `zen check` passes, **after** `scripts/_setup.sh` has completed,
180
+ and **after** the history file is on disk. It takes the newest entry in
181
+ `.spec-sync/history/` - the stamps sort chronologically by name - records it in
182
+ `applied.txt`, and writes `manifest.txt` last of all. It refuses to run when
183
+ there is no history file, and when the newest one is the entry `applied.txt`
184
+ already names: that means this pass wrote no entry of its own.
185
+
186
+ A pass that moves the baseline early and then fails records a specification as
187
+ applied that was never applied - and the next pass diffs against it, sees
188
+ nothing, and skips the work for good. Failing with the baseline unmoved costs
189
+ one repeated pass; failing with it moved costs a requirement that is never
190
+ implemented and that nothing will report. Say in the chat which history file was
191
+ written and that the baseline moved.
192
+
193
+ ## The first pass on a project that has no baseline
194
+
195
+ `mode: full`, so run the prompt as written, end to end. Then write the history
196
+ file and commit the baseline exactly as any other pass does - a project only
197
+ becomes incremental by having completed one full pass.