@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.
- package/README.md +110 -19
- package/dist/banner.d.ts +19 -0
- package/dist/banner.js +12 -9
- package/dist/catalog.js +19 -20
- package/dist/command.d.ts +3 -0
- package/dist/commands/check.js +5 -1
- package/dist/commands/index.js +4 -1
- package/dist/commands/init.js +42 -7
- package/dist/commands/inspect.js +77 -13
- package/dist/commands/key.js +49 -1
- package/dist/commands/memory.js +16 -3
- package/dist/commands/meta.d.ts +3 -0
- package/dist/commands/meta.js +596 -0
- package/dist/commands/run.js +64 -35
- package/dist/engine.d.ts +15 -0
- package/dist/engine.js +26 -1
- package/dist/env.d.ts +20 -0
- package/dist/env.js +65 -0
- package/dist/home.d.ts +2 -0
- package/dist/home.js +2 -0
- package/dist/keys.d.ts +2 -0
- package/dist/keys.js +2 -0
- package/dist/main.js +1 -1
- package/dist/meta.d.ts +221 -0
- package/dist/meta.js +695 -0
- package/dist/podman.js +64 -2
- package/dist/projects.d.ts +9 -1
- package/dist/projects.js +19 -2
- package/dist/resolve.js +7 -1
- package/dist/sandbox.d.ts +11 -0
- package/dist/sandbox.js +24 -4
- package/dist/scaffold.d.ts +6 -0
- package/dist/scaffold.js +56 -15
- package/dist/session.d.ts +10 -0
- package/dist/session.js +19 -1
- package/dist/term.d.ts +7 -0
- package/dist/term.js +8 -1
- package/dist/tui/app.js +33 -5
- package/dist/tui/wrap.d.ts +1 -1
- package/dist/tui/wrap.js +1 -1
- package/dist/validate.js +57 -15
- package/package.json +3 -2
- package/templates/editor/.github/copilot-instructions.md +313 -94
- package/templates/editor/.github/prompts/project-review.prompt.md +74 -0
- package/templates/editor/.github/prompts/spec-apply-feedback.prompt.md +142 -0
- package/templates/editor/.github/prompts/spec-sync-project.prompt.md +392 -0
- package/templates/editor/.github/skills/zen-cli/references/check.md +6 -3
- package/templates/editor/.github/skills/zen-cli/references/frame.md +5 -3
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +4 -3
- package/templates/editor/.github/skills/zen-cli/references/memory.md +14 -0
- package/templates/editor/.github/skills/zen-cli/references/projects.md +19 -2
- package/templates/editor/.github/skills/zen-cli/references/run.md +75 -16
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +6 -0
- package/templates/editor/.github/skills/zen-memory/SKILL.md +153 -33
- package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +115 -0
- package/templates/editor/.github/skills/zen-review/SKILL.md +123 -0
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +119 -0
- package/templates/editor/.github/skills/zen-review/scripts/review.sh +104 -0
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +197 -0
- package/templates/editor/.github/skills/zen-spec-sync/scripts/snapshot.sh +200 -0
- package/templates/editor/.vscode/settings.json +44 -4
- package/templates/parts/memory-terms.yaml.tmpl +16 -0
- package/templates/parts/memory.yaml.tmpl +12 -0
- package/templates/project/SPECIFICATION.md.tmpl +32 -2
- package/templates/project/agents/memory-instructions.md +278 -0
- package/templates/project/agents.yaml.tmpl +12 -3
- package/templates/project/env +28 -0
- package/templates/project/gitignore +4 -4
- package/templates/editor/.github/prompts/review-project.prompt.md +0 -36
- package/templates/editor/.github/prompts/sync-with-spec.prompt.md +0 -205
- /package/templates/project/{INSTRUCTIONS.md → agents/instructions.md} +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Review the project against the checklist before committing.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Review this project the way a maintainer would, then report. Read
|
|
6
|
+
`agents.yaml`, every `agents/*instructions.md`, every file under
|
|
7
|
+
`agents/prompts/` and the skill descriptions under `agents/skills/` before
|
|
8
|
+
saying anything.
|
|
9
|
+
|
|
10
|
+
**Run the mechanical checks first, and report what they say:**
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
.github/skills/zen-review/scripts/review.sh
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
That is `zen check`, the §2.5 path sweep, the memory house-rules copy and the
|
|
17
|
+
spec-sync record, in the order they matter. Load the `zen-review` skill for what
|
|
18
|
+
each one owns and how to read its output. Do not re-verify by hand anything it
|
|
19
|
+
already decided, and do not go further while `zen check` fails - nothing below
|
|
20
|
+
matters until it passes.
|
|
21
|
+
|
|
22
|
+
**Then list the capabilities this project turns on** — a `memory:` block, a
|
|
23
|
+
`zen rag` index, a sandbox, a `SPECIFICATION.md` — and load the editor skill
|
|
24
|
+
for each before judging it. The obligations live in the skill, not in
|
|
25
|
+
`agents.yaml`, and `zen check` reports none of them. A capability that is
|
|
26
|
+
already configured and already passing is exactly the case that looks finished
|
|
27
|
+
and is not.
|
|
28
|
+
|
|
29
|
+
Everything that follows is what no tool can see:
|
|
30
|
+
|
|
31
|
+
- **One job each.** Can you state every agent's job in one sentence? If not,
|
|
32
|
+
say which agent and what the two jobs are.
|
|
33
|
+
- **Prompts.** Second person, imperative, failure paths stated, no hedging, no
|
|
34
|
+
politeness padding, no meta-talk about the runtime. Nothing in the house rules
|
|
35
|
+
that is true of only one agent, and nothing in `agents/instructions.md` that
|
|
36
|
+
belongs in a `<topic>-instructions.md` of its own because it only applies when
|
|
37
|
+
one capability is on.
|
|
38
|
+
- **Facts.** Any number, threshold, fee or date living in a prompt is in the
|
|
39
|
+
wrong file. Name it and say which skill it belongs in.
|
|
40
|
+
- **Paths.** For each candidate `check-paths.sh` printed: is it a path the
|
|
41
|
+
agent cannot open, or noise? Say which, and for a real one say what it should
|
|
42
|
+
have been. Judge the rest of the §2.5 checklist yourself — that no instruction
|
|
43
|
+
assumes the workspace is this directory, that every `/assets/…` and
|
|
44
|
+
`/skills/<name>/…` names a committed file, and that the agent holding the
|
|
45
|
+
prompt has the tool the path implies.
|
|
46
|
+
- **Memory.** Anything this project decides for itself belongs in
|
|
47
|
+
`agents/memory-policy-instructions.md`, not in the copy — and it should say
|
|
48
|
+
something. Audiences that exist because an agent would be _misled_ by the
|
|
49
|
+
other slice, not merely because it does not need it.
|
|
50
|
+
- **Skill descriptions.** Each one a condition, not a title; no two overlapping.
|
|
51
|
+
Every skill a folder with a `SKILL.md`, and a skill that ships a script writes
|
|
52
|
+
its `/skills/<name>/…` path.
|
|
53
|
+
- **Tools.** Every grant justified by the agent's job; nothing mutating held by
|
|
54
|
+
an agent that only reads; every granted tool mentioned by the prompt. An agent
|
|
55
|
+
with no `skills:` key indexes the whole catalog - check that every agent can
|
|
56
|
+
actually follow the skills it is offered.
|
|
57
|
+
- **Sandbox.** `persist: true` unless a throwaway rootfs is wanted on purpose.
|
|
58
|
+
What the work always needs is in the image, not installed by a prompt on every
|
|
59
|
+
run.
|
|
60
|
+
- **Control flow.** Whichever this project uses. A handoff moves the
|
|
61
|
+
conversation and must have a path back; a fork returns by itself and condenses
|
|
62
|
+
to one result, so whatever the caller needs must be in the branch's answer.
|
|
63
|
+
Wanting one lookup and spending the conversation on it is a fork, not a
|
|
64
|
+
handoff. No router that answers.
|
|
65
|
+
- **Models.** Each agent on the cheapest tier that is right, not the safest.
|
|
66
|
+
- **Cache.** Nothing volatile - dates, ids, counts - in the stable prefix.
|
|
67
|
+
- **Secrets.** No key inlined anywhere; `.env` ignored, `sessions/` ignored.
|
|
68
|
+
- **Specification.** Where a `SPECIFICATION.md` exists, `review.sh` reported the
|
|
69
|
+
record's mode. Judge the rest: the newest history entry's "Still open" is
|
|
70
|
+
honest, its baseline names that entry, and `.spec-sync/` is committed.
|
|
71
|
+
|
|
72
|
+
Report as a list of findings, each naming the file and the line, ordered by how
|
|
73
|
+
much it will cost to leave. Say plainly if you find nothing worth changing.
|
|
74
|
+
Do not edit anything unless I ask.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Fold the answers left in SPECIFICATION-FEEDBACK.md back into SPECIFICATION.md, and mark each answered question as answered.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
`SPECIFICATION-FEEDBACK.md` is a questionnaire. Each question carries two to
|
|
6
|
+
four written-out answers, each with a `[ ]` box in its heading, and the reader
|
|
7
|
+
answers by **marking one box `[x]`, deleting the answers they do not want, or
|
|
8
|
+
both**. Your job is to take the answer they chose under each question, put its
|
|
9
|
+
text into `SPECIFICATION.md` where it says it goes, and mark the question
|
|
10
|
+
answered.
|
|
11
|
+
|
|
12
|
+
You change two files and no others: `SPECIFICATION.md` and
|
|
13
|
+
`SPECIFICATION-FEEDBACK.md`. You implement nothing - not a prompt, not a skill,
|
|
14
|
+
not `agents.yaml`. Making the project match the specification is
|
|
15
|
+
`/spec-sync-project`, which runs after this.
|
|
16
|
+
|
|
17
|
+
## 1. Read both files before editing either
|
|
18
|
+
|
|
19
|
+
Read `SPECIFICATION-FEEDBACK.md` end to end, then `SPECIFICATION.md` end to end,
|
|
20
|
+
and only then edit. The second read is what tells you whether an answer's text
|
|
21
|
+
still fits where it is going.
|
|
22
|
+
|
|
23
|
+
If there is no `SPECIFICATION-FEEDBACK.md`, say so in the chat and stop - there
|
|
24
|
+
is nothing to fold in.
|
|
25
|
+
|
|
26
|
+
## 2. Decide the state of every question
|
|
27
|
+
|
|
28
|
+
Go through the questions in order and sort each into one of these, by what is
|
|
29
|
+
left under it. Say in the chat how many fell into each before you edit anything.
|
|
30
|
+
|
|
31
|
+
**Answered** - apply it:
|
|
32
|
+
|
|
33
|
+
- exactly one answer has its box marked `[x]`, whatever else is still there
|
|
34
|
+
- exactly one `####` answer is left, box marked or not
|
|
35
|
+
- the reader wrote prose of their own in place of the answers, or edited the
|
|
36
|
+
answer they kept - then apply what they wrote, word for word
|
|
37
|
+
|
|
38
|
+
**Open** - leave it exactly as it is:
|
|
39
|
+
|
|
40
|
+
- two or more answers are left and none is marked
|
|
41
|
+
- two or more boxes are marked `[x]` - that is not a choice, and the chat report
|
|
42
|
+
is where you say so
|
|
43
|
+
|
|
44
|
+
**Rejected** - leave it, and ask in the chat:
|
|
45
|
+
|
|
46
|
+
- no answers at all are left under the question
|
|
47
|
+
|
|
48
|
+
**Done** - leave it alone:
|
|
49
|
+
|
|
50
|
+
- it is already under `✅`
|
|
51
|
+
|
|
52
|
+
A question with every answer deleted is the reader saying none of them fit.
|
|
53
|
+
**Do not invent a fifth.** Say in the chat which question it was and ask what
|
|
54
|
+
would fit; if they tell you, write their words in under the question as the
|
|
55
|
+
answer and apply it in this same pass.
|
|
56
|
+
|
|
57
|
+
A question with two or more answers still standing and no box marked is **not
|
|
58
|
+
answered**. Never choose between them, never pick the `_(built)_` one because it
|
|
59
|
+
is already true, and never break a tie by reading the implementation.
|
|
60
|
+
|
|
61
|
+
## 3. Put the text into `SPECIFICATION.md`
|
|
62
|
+
|
|
63
|
+
For each answered question, take the fenced block under its surviving answer and
|
|
64
|
+
put it where the line above the block says it goes.
|
|
65
|
+
|
|
66
|
+
- **The line number is a hint, not an address.** Every paste moves every line
|
|
67
|
+
below it, and the reader has been editing too. Anchor on the text quoted under
|
|
68
|
+
**Where it comes from**; if that text is gone, use the section it names. If
|
|
69
|
+
neither is there any more, do not guess: leave the question open and report it
|
|
70
|
+
as not applied, with what you looked for.
|
|
71
|
+
- **Paste it verbatim.** Do not reword it, do not improve it, do not reflow it
|
|
72
|
+
to your own idea of the line width. The block was written in the
|
|
73
|
+
specification's voice for exactly this.
|
|
74
|
+
- **A `<placeholder>` is filled in only with a value the reader supplied** - in
|
|
75
|
+
the block, in prose next to it, or in the chat. An unfilled placeholder means
|
|
76
|
+
the question is not answered yet; leave it open and say so.
|
|
77
|
+
- **Keep the document consistent around the paste.** Heading level, list style,
|
|
78
|
+
tense and the words the specification already uses for things. If the new text
|
|
79
|
+
makes a neighbouring sentence false, or contradicts another section, fix that
|
|
80
|
+
too - and report each such edit on its own line, because it is a change no
|
|
81
|
+
answer asked for.
|
|
82
|
+
- Work one question at a time, top to bottom, and re-read the file between
|
|
83
|
+
edits rather than trusting the line numbers you read at the start.
|
|
84
|
+
|
|
85
|
+
Nothing outside `SPECIFICATION.md` changes here. If an answer's text implies an
|
|
86
|
+
agent, a tool grant, a script or a skill, that is the next `/spec-sync-project`
|
|
87
|
+
pass's work, and saying so is all you do about it.
|
|
88
|
+
|
|
89
|
+
## 4. Mark the question answered
|
|
90
|
+
|
|
91
|
+
Move the whole `###` block of each answered question to the end of the file,
|
|
92
|
+
under:
|
|
93
|
+
|
|
94
|
+
```markdown
|
|
95
|
+
## ✅ Answered - folded into the specification
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Keep its number and its original emoji, so a link to it still resolves and the
|
|
99
|
+
number is never reused. Replace everything under the heading with, in this
|
|
100
|
+
order:
|
|
101
|
+
|
|
102
|
+
- **Answered** - the chosen answer's line, verbatim, without its `[ ]` box, or
|
|
103
|
+
the reader's own words where they wrote their own.
|
|
104
|
+
- **In the specification** - a link to the line it now occupies,
|
|
105
|
+
`[SPECIFICATION.md#L66](SPECIFICATION.md#L66)`, and the new text quoted as a
|
|
106
|
+
blockquote.
|
|
107
|
+
- **Still to implement** - one line saying what has to change in the project for
|
|
108
|
+
the specification to be true again, or `Nothing - the project already does
|
|
109
|
+
this.`
|
|
110
|
+
|
|
111
|
+
That last line is what the next `/spec-sync-project` works from, so write it as
|
|
112
|
+
work, not as a summary.
|
|
113
|
+
|
|
114
|
+
Then bring the top of the file back into step: the opening paragraph's count of
|
|
115
|
+
open questions, and the contents list - an answered line keeps its link and
|
|
116
|
+
shows the answer that won in place of what was built. Drop a heading that has no
|
|
117
|
+
questions left under it, and add no markdown tables to this file.
|
|
118
|
+
|
|
119
|
+
## 5. You are the typist, not the reader
|
|
120
|
+
|
|
121
|
+
Do not answer a question yourself, do not soften a chosen answer because you
|
|
122
|
+
would have chosen another, and do not add a requirement nobody asked for. An
|
|
123
|
+
answer you think is wrong is still the answer; say why in the chat and leave the
|
|
124
|
+
text alone.
|
|
125
|
+
|
|
126
|
+
Do not run `zen check`, `scripts/_setup.sh` or anything under `.spec-sync/`. The
|
|
127
|
+
baseline moves at the end of a `/spec-sync-project` pass and nowhere else -
|
|
128
|
+
committing it here would record a specification as applied that nothing has
|
|
129
|
+
implemented yet.
|
|
130
|
+
|
|
131
|
+
## 6. Report
|
|
132
|
+
|
|
133
|
+
In the chat:
|
|
134
|
+
|
|
135
|
+
- each question you answered, and which answer won
|
|
136
|
+
- every line of `SPECIFICATION.md` that changed, and what it says now
|
|
137
|
+
- every edit you made that no answer asked for, and what made it necessary
|
|
138
|
+
- what is still open, split into: more than one answer left, more than one box
|
|
139
|
+
marked, every answer rejected, and could not be applied because the place it
|
|
140
|
+
names is gone
|
|
141
|
+
- then, in one line: send `/spec-sync-project` to make the project match the
|
|
142
|
+
specification you have just changed.
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Bring the project into compliance with SPECIFICATION.md, and record every open question in SPECIFICATION-FEEDBACK.md.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Make this project match `SPECIFICATION.md`. The specification is the intent;
|
|
6
|
+
the files are the implementation. Where they disagree, the specification wins -
|
|
7
|
+
except where it is ambiguous, contradictory or impossible, which is what
|
|
8
|
+
`SPECIFICATION-FEEDBACK.md` is for.
|
|
9
|
+
|
|
10
|
+
## 0. Decide the size of this pass
|
|
11
|
+
|
|
12
|
+
Load the `zen-spec-sync` skill first, before anything else and whatever state
|
|
13
|
+
the project is in - a project with no baseline is the one that needs it most,
|
|
14
|
+
because this pass has to make the first. Then, from the project root:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
.github/skills/zen-spec-sync/scripts/snapshot.sh status
|
|
18
|
+
.github/skills/zen-spec-sync/scripts/snapshot.sh diff
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`status` answers `full`, `incremental` or `tampered`. Say which in the chat
|
|
22
|
+
before reading anything, and on an incremental pass state the scope you drew
|
|
23
|
+
from the diffs - the skill says how. `full` and `tampered` both mean the whole
|
|
24
|
+
prompt as written below, from nothing.
|
|
25
|
+
|
|
26
|
+
The diff covers both sides. `SPECIFICATION.md` and `SPECIFICATION-FEEDBACK.md`
|
|
27
|
+
say what has been **asked for** since the last pass; `agents.yaml` and every
|
|
28
|
+
file under `agents/` say what has been **built or hand-edited** since then. The
|
|
29
|
+
first narrows the pass to the work nobody has done; the second only widens it,
|
|
30
|
+
because a prompt or skill someone changed outside a pass still has to be
|
|
31
|
+
accounted for against the specification.
|
|
32
|
+
|
|
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
|
|
35
|
+
pass, however small the diff.
|
|
36
|
+
|
|
37
|
+
## 1. Read before changing anything
|
|
38
|
+
|
|
39
|
+
Read, in this order, and do not edit until all of it is read:
|
|
40
|
+
|
|
41
|
+
1. `SPECIFICATION.md` - what the system is meant to be.
|
|
42
|
+
2. `agents.yaml` - providers, models, embeddings, agents, tools, handoffs,
|
|
43
|
+
skills, sandbox.
|
|
44
|
+
3. Every `agents/*instructions.md` and every file under `agents/prompts/`.
|
|
45
|
+
4. Every `agents/skills/*/SKILL.md`, plus what each skill folder ships.
|
|
46
|
+
5. `assets/`, `sandbox/Dockerfile` and every script under `scripts/`, starting
|
|
47
|
+
with `scripts/_setup.sh`.
|
|
48
|
+
6. `SPECIFICATION-FEEDBACK.md`, if it exists - do not re-raise something already
|
|
49
|
+
open there.
|
|
50
|
+
|
|
51
|
+
On an incremental pass this list narrows to the artefacts the scope implicates,
|
|
52
|
+
and to the changed hunks of the specification rather than all of it. The
|
|
53
|
+
narrowing is a claim: name what you skipped and why the diff does not reach it.
|
|
54
|
+
|
|
55
|
+
Run `zen check` first and record what it said. A project that does not load is
|
|
56
|
+
the first thing to fix.
|
|
57
|
+
|
|
58
|
+
## 2. Build the difference
|
|
59
|
+
|
|
60
|
+
Produce a difference list before touching a file. For every item in the
|
|
61
|
+
specification, decide which of these it is:
|
|
62
|
+
|
|
63
|
+
- **present and correct** - leave it alone
|
|
64
|
+
- **missing** - the specification asks for it and nothing implements it
|
|
65
|
+
- **divergent** - implemented, but not as specified
|
|
66
|
+
- **extra** - implemented, and the specification does not ask for it
|
|
67
|
+
- **unclear** - the specification does not say enough to implement it
|
|
68
|
+
|
|
69
|
+
Check at least: the model and embedding ids and which agent uses which; that
|
|
70
|
+
every agent named in the specification exists with that job and no second job;
|
|
71
|
+
handoff edges and fork permissions; the tools each agent holds; every skill the
|
|
72
|
+
specification implies; and every setup step, index or asset it depends on.
|
|
73
|
+
|
|
74
|
+
Then build the difference the other way, because the list above can only find
|
|
75
|
+
what the specification asked for and nothing implements. Read every
|
|
76
|
+
`agents/*instructions.md`, each `agents/prompts/*.md` and each `SKILL.md` **line
|
|
77
|
+
by line**, and for every line name the specification item it serves. A line
|
|
78
|
+
serving none is an **extra** - the category covers a single sentence in a prompt,
|
|
79
|
+
not only a whole file. Three things to look for while reading, none of which the
|
|
80
|
+
forward pass can see:
|
|
81
|
+
|
|
82
|
+
- **A line that contradicts another file.** One prompt against another, a prompt
|
|
83
|
+
against the house rules, or a prompt against `agents.yaml` - an instruction
|
|
84
|
+
to use a tool the agent does not hold, to hand to an agent that is not in its
|
|
85
|
+
`handoffs:`, or to load a skill outside its `allow:`.
|
|
86
|
+
- **A line that asks for something the system already supplies.** A question put
|
|
87
|
+
to the user about a value that arrives from the environment, a file or an
|
|
88
|
+
earlier step is unanswerable, and the answer would be discarded.
|
|
89
|
+
- **A line the agent cannot carry out** - naming a path it cannot reach, a tool
|
|
90
|
+
it was not granted, or an agent it cannot transfer to.
|
|
91
|
+
|
|
92
|
+
These are bugs whatever the specification says: fix them in place and report each
|
|
93
|
+
one. An extra that is merely unspecified is reported under `➕`, not removed.
|
|
94
|
+
|
|
95
|
+
On an incremental pass this reverse reading covers every file this pass touched
|
|
96
|
+
plus every file the implementation diff in §0 named - an edit made in this
|
|
97
|
+
session, or made by hand since the last pass, is exactly where a fresh
|
|
98
|
+
contradiction comes from. On a full pass it is the whole tree, as above.
|
|
99
|
+
|
|
100
|
+
## 3. Change the smallest thing that closes the gap
|
|
101
|
+
|
|
102
|
+
Apply the fixes in the order the copilot instructions prefer: a prompt or skill
|
|
103
|
+
edit over a new skill, a new skill over a new agent, a tool grant over asking
|
|
104
|
+
the model to compute or remember. Specifically:
|
|
105
|
+
|
|
106
|
+
- A behaviour gap is a prompt or skill edit, not a new agent.
|
|
107
|
+
- A fact, rate, threshold or command surface goes in a skill, never in a prompt.
|
|
108
|
+
- Arithmetic or a fixed transformation goes in a script under the skill folder,
|
|
109
|
+
called by its absolute `/skills/<name>/…` path.
|
|
110
|
+
- A capability gap is a `tools:` grant plus the prompt line that says when to
|
|
111
|
+
use it. A granted tool no prompt mentions is not implemented.
|
|
112
|
+
- A toolchain the work always needs goes in `sandbox/Dockerfile`, not in a
|
|
113
|
+
prompt that installs it every run.
|
|
114
|
+
- If the project has a `sandbox/Dockerfile`, pin `@zenera/cli` and `@zenera/rag`
|
|
115
|
+
in it to the version of `zen` in hand. Read that version with `zen --version`
|
|
116
|
+
and write it into the `npm install -g` line, so the CLI an agent runs inside
|
|
117
|
+
the container is the same one that built it. An unpinned name drifts away from
|
|
118
|
+
the host on the next image build; a stale pin is a mismatch nothing reports.
|
|
119
|
+
|
|
120
|
+
Never delete an **extra** without saying so. Report it, say why the
|
|
121
|
+
specification does not cover it, and leave it unless I tell you to remove it.
|
|
122
|
+
|
|
123
|
+
Do not invent a value the specification does not state - a model id, a limit, a
|
|
124
|
+
retry count, a file path. That is an entry in `SPECIFICATION-FEEDBACK.md`, not a
|
|
125
|
+
guess.
|
|
126
|
+
|
|
127
|
+
## 4. Every setup step is a script
|
|
128
|
+
|
|
129
|
+
Anything the project needs done before it can run - building an index, fetching
|
|
130
|
+
a document, generating a file, warming the sandbox image - is a shell script,
|
|
131
|
+
not a paragraph of instructions for a human.
|
|
132
|
+
|
|
133
|
+
- One step per file, under `scripts/`, named after the step:
|
|
134
|
+
`scripts/build-schema-index.sh`, `scripts/fetch-api-docs.sh`.
|
|
135
|
+
- `scripts/_setup.sh` is the **only** entry point - the leading underscore is
|
|
136
|
+
what separates the runner from the steps it runs. It runs the steps in the
|
|
137
|
+
order they depend on each other and is the single command that initialises the
|
|
138
|
+
project. `zen init` writes it; adding a step is adding `scripts/<name>.sh` and
|
|
139
|
+
its name to the `STEPS` list at the top of it. Consolidate any setup script
|
|
140
|
+
that lives elsewhere into this shape, including one left at the project root.
|
|
141
|
+
- Every script starts `set -eu`, works from any working directory
|
|
142
|
+
(`cd "$(dirname "$0")/.."` first), needs no arguments, and exits non-zero on
|
|
143
|
+
failure so `scripts/_setup.sh` stops rather than continuing on a broken step.
|
|
144
|
+
- **Re-entrancy is required.** Running `scripts/_setup.sh` a second time must be
|
|
145
|
+
safe. A step whose output is present and newer than its inputs prints that it
|
|
146
|
+
is up to date and exits **3**, which is how the runner tells `skipped` from
|
|
147
|
+
`ok`; otherwise it redoes the work idempotently, writing
|
|
148
|
+
to a temporary path and moving it into place so an interrupted run never leaves
|
|
149
|
+
a half-built artefact behind. `scripts/_setup.sh --force` redoes everything,
|
|
150
|
+
and reaches each step as `$FORCE=1`.
|
|
151
|
+
- **It must be watchable.** `scripts/_setup.sh` tees each step's output to
|
|
152
|
+
`.tmp/logs/setup-<step>.log`, prints a heartbeat line while a long step runs,
|
|
153
|
+
and finishes with one line per step: `ok`, `skipped`, or `failed`.
|
|
154
|
+
- **Everything transient goes under `.tmp/`** - logs, scratch files, downloads,
|
|
155
|
+
test output, and the temporary path a step writes to before moving its
|
|
156
|
+
artefact into place. Nothing else in the tree is a scratch directory, and
|
|
157
|
+
`.tmp/` is git-ignored: add it to `.gitignore` if it is not there already.
|
|
158
|
+
Deleting `.tmp/` must leave the project runnable and `scripts/_setup.sh`
|
|
159
|
+
re-runnable.
|
|
160
|
+
- Steps that need credentials run on the host, not in the sandbox. Read keys
|
|
161
|
+
from the environment or `.env`; never inline one into a script.
|
|
162
|
+
- Anything the sandbox always needs belongs in `sandbox/Dockerfile`, not in a
|
|
163
|
+
setup script that installs it again on every run.
|
|
164
|
+
|
|
165
|
+
## 5. Write `SPECIFICATION-FEEDBACK.md`
|
|
166
|
+
|
|
167
|
+
Create or update `SPECIFICATION-FEEDBACK.md` at the project root whenever
|
|
168
|
+
anything in the
|
|
169
|
+
specification is unclear, contradictory, impossible, or wrong. If there is
|
|
170
|
+
nothing to raise, say so in the chat and do not create the file.
|
|
171
|
+
|
|
172
|
+
**It is a questionnaire, and answering it must take one gesture.** Every
|
|
173
|
+
question carries two to four written-out answers, each with a `[ ]` box in its
|
|
174
|
+
heading. The reader marks the box of the one they want - `[x]` - and deletes the
|
|
175
|
+
others, then sends `/spec-apply-feedback`, which folds what survived into
|
|
176
|
+
`SPECIFICATION.md`. Either gesture alone is enough, and the file says so in
|
|
177
|
+
every question.
|
|
178
|
+
|
|
179
|
+
Two rules that come before everything else in this section:
|
|
180
|
+
|
|
181
|
+
- **No markdown tables anywhere in this file.** A table is unreadable the moment
|
|
182
|
+
a pane is narrow or a cell wraps, and this is a file people read in a side
|
|
183
|
+
panel. Every list is a list.
|
|
184
|
+
- **Never write a question the reader has to do work to answer.** No paragraph
|
|
185
|
+
ending in "is that what you meant?", nothing that requires reading the
|
|
186
|
+
implementation, and no answer phrased as a decision still to be made. If you
|
|
187
|
+
cannot write two answers a reader could pick between, you have not understood
|
|
188
|
+
the problem well enough to ask about it yet.
|
|
189
|
+
|
|
190
|
+
The file opens with one short paragraph: how many questions are open, and how to
|
|
191
|
+
answer them - put an `x` in the box of the answer you want, delete the answers
|
|
192
|
+
you do not want, or replace them all with a sentence of your own, then send
|
|
193
|
+
`/spec-apply-feedback`. Then a contents list, one line per question: its
|
|
194
|
+
number as an anchor link, the question in under ten words, and what is built in
|
|
195
|
+
the meantime. Then the questions, grouped under these headings, omitting any
|
|
196
|
+
heading with no questions. The file is scanned before it is read, so keep the
|
|
197
|
+
emoji on every heading:
|
|
198
|
+
|
|
199
|
+
```markdown
|
|
200
|
+
# Feedback on SPECIFICATION.md
|
|
201
|
+
|
|
202
|
+
## 🛑 Blocking - cannot implement without an answer
|
|
203
|
+
|
|
204
|
+
## ❓ Ambiguous - implemented one way, confirm the choice
|
|
205
|
+
|
|
206
|
+
## ⚡ Contradictions
|
|
207
|
+
|
|
208
|
+
## ✏️ Errors and typos
|
|
209
|
+
|
|
210
|
+
## ➕ Out of scope - implemented but unspecified
|
|
211
|
+
|
|
212
|
+
## ✅ Answered - folded into the specification
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
`✅` is written by `/spec-apply-feedback`, not by you. Leave what is there
|
|
216
|
+
alone except to strike an entry this pass has actually implemented, and say in
|
|
217
|
+
the chat which ones you closed.
|
|
218
|
+
|
|
219
|
+
### The shape of one question
|
|
220
|
+
|
|
221
|
+
Each question is its own `###` heading - the emoji of its section, `Q` and a
|
|
222
|
+
number, then the question itself, ending in a question mark. Under it, in this
|
|
223
|
+
order:
|
|
224
|
+
|
|
225
|
+
- **Where it comes from** - the specification text quoted as a blockquote,
|
|
226
|
+
introduced by a link to the exact line,
|
|
227
|
+
`[SPECIFICATION.md#L66](SPECIFICATION.md#L66)`, plus the section name. Link
|
|
228
|
+
every line you quote; a reader must reach it in one click. For a question
|
|
229
|
+
about something the specification does not say at all, link the section it
|
|
230
|
+
would belong to and say that it is silent there.
|
|
231
|
+
- **Why it is a problem** - two or three sentences on what goes wrong, in terms
|
|
232
|
+
of behaviour: what an agent does, what a run produces, what breaks. Not
|
|
233
|
+
"unclear" or "ambiguous", which describe the sentence rather than the damage.
|
|
234
|
+
- **Built in the meantime** - what the implementation does now, and the one fact
|
|
235
|
+
that made it the default. Or "Nothing - blocked."
|
|
236
|
+
- **To answer** - the same sentence on every question, word for word: put an `x`
|
|
237
|
+
in one box below and delete the other answers, either one is enough.
|
|
238
|
+
|
|
239
|
+
Then two to four answers, each its own `####` heading of the form
|
|
240
|
+
`#### [ ] A. <the answer in one line, as the reader would say it>`. The one that
|
|
241
|
+
is implemented comes first and is marked `_(built)_`, so the file reads as "this
|
|
242
|
+
is what happens if you change nothing"; mark one `_(recommended)_` where it is
|
|
243
|
+
better for a reason the reader can check. Under each answer heading:
|
|
244
|
+
|
|
245
|
+
- **What it changes** - one or two sentences on the consequence of choosing it:
|
|
246
|
+
what the system would then do differently, and what it costs.
|
|
247
|
+
- **The specification text**, in a fenced block, introduced by where it goes -
|
|
248
|
+
"replace line 66", "add after line 21", "delete lines 30-32". Written in the
|
|
249
|
+
specification's own voice and format so it can be pasted without editing.
|
|
250
|
+
|
|
251
|
+
Every answer carries its own box and its own text. They are alternatives that
|
|
252
|
+
will be read alone, so nothing may be shared between them and nothing may refer
|
|
253
|
+
to a sibling ("as above", "same as A"). Where an answer needs a value only the
|
|
254
|
+
reader has, put a `<placeholder>` in the block and say in **What it changes**
|
|
255
|
+
what to substitute.
|
|
256
|
+
|
|
257
|
+
Two rules on the answers themselves:
|
|
258
|
+
|
|
259
|
+
- **An answer is a real alternative**, not a restatement of the question or a
|
|
260
|
+
hedge. "Decide later" is not an answer; "leave it unspecified, and the
|
|
261
|
+
reviewer keeps using whatever the default agent uses" is.
|
|
262
|
+
- **Never write only one answer.** A question with nothing to choose between is
|
|
263
|
+
not a question. Even an `✏️` typo has two: the correction, and leaving it as
|
|
264
|
+
written with a line saying what stays wrong.
|
|
265
|
+
|
|
266
|
+
Under `➕` the two answers are fixed: keep it, whose block is the specification
|
|
267
|
+
text that would cover what was built, and remove it, whose **What it changes**
|
|
268
|
+
says what removing it would cost and which files would go.
|
|
269
|
+
|
|
270
|
+
### One question, written out
|
|
271
|
+
|
|
272
|
+
Copy this shape exactly - the outer fence is four backticks only so the example
|
|
273
|
+
can contain its own:
|
|
274
|
+
|
|
275
|
+
````markdown
|
|
276
|
+
### ❓ Q4. Do the three agents share one memory, or keep their own?
|
|
277
|
+
|
|
278
|
+
**Where it comes from** - [SPECIFICATION.md#L14](SPECIFICATION.md#L14), _Common
|
|
279
|
+
memory strategies_:
|
|
280
|
+
|
|
281
|
+
> use memory to save plans of answering what was delegated to what
|
|
282
|
+
|
|
283
|
+
**Why it is a problem** - the specification says what each agent writes and
|
|
284
|
+
never says who may read it. Memory is one graph with an audience on every node,
|
|
285
|
+
so this decides whether the orchestrator can plan from what a specialist
|
|
286
|
+
resolved last week, or re-derives it every time.
|
|
287
|
+
|
|
288
|
+
**Built in the meantime** - one shared slice: `memory: true` on all three, so
|
|
289
|
+
anything one agent writes, another can recall. Chosen because nothing in the
|
|
290
|
+
specification separates them.
|
|
291
|
+
|
|
292
|
+
**To answer** - put an `x` in one box below and delete the other answers. Either
|
|
293
|
+
one is enough.
|
|
294
|
+
|
|
295
|
+
#### [ ] A. All three agents share one memory _(built)_
|
|
296
|
+
|
|
297
|
+
**What it changes** - a lookup is paid for once for the whole system, and every
|
|
298
|
+
agent's recall competes with every other agent's notes for the same few slots.
|
|
299
|
+
|
|
300
|
+
Add under _Common memory strategies_, after line 17:
|
|
301
|
+
|
|
302
|
+
```markdown
|
|
303
|
+
All three agents read and write one shared memory: whatever one of them
|
|
304
|
+
discovers is recallable by the others.
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### [ ] B. Each agent keeps its own memory
|
|
308
|
+
|
|
309
|
+
**What it changes** - recall gets sharper and cheaper because an agent only ever
|
|
310
|
+
sees its own kind of note, and the same lookup is repeated by whoever did not do
|
|
311
|
+
it first.
|
|
312
|
+
|
|
313
|
+
Add under _Common memory strategies_, after line 17:
|
|
314
|
+
|
|
315
|
+
```markdown
|
|
316
|
+
Each agent reads and writes only its own memory. A finding one agent needs from
|
|
317
|
+
another travels as part of the hand-off, not through the store.
|
|
318
|
+
```
|
|
319
|
+
````
|
|
320
|
+
|
|
321
|
+
Use no emoji except the one on each heading. Keep the prose short. Do not
|
|
322
|
+
editorialise about the specification's quality, do not restate the runtime, and
|
|
323
|
+
do not copy a whole section in.
|
|
324
|
+
|
|
325
|
+
Append to the existing file rather than rewriting it, keeping the numbering and
|
|
326
|
+
the contents list in step. Numbers are never reused: a struck question's number
|
|
327
|
+
retires with it.
|
|
328
|
+
|
|
329
|
+
Read the feedback diff from §0 before writing: a question the human answered
|
|
330
|
+
since the last pass is work to close, not a question to ask again. If a question
|
|
331
|
+
has a box marked `[x]`, or one answer left under it, and no `✅` entry, the
|
|
332
|
+
reader answered it and never ran `/spec-apply-feedback` - implement that
|
|
333
|
+
answer, fold its text into `SPECIFICATION.md` yourself, and say so in the chat.
|
|
334
|
+
|
|
335
|
+
## 6. Run `scripts/_setup.sh` and watch it finish
|
|
336
|
+
|
|
337
|
+
After `zen check` passes, run `scripts/_setup.sh` yourself. A pass is not done
|
|
338
|
+
until it has run to completion in this session.
|
|
339
|
+
|
|
340
|
+
It is slow - an embedding index is minutes, not seconds - so start it in the
|
|
341
|
+
background and follow the logs instead of waiting blind:
|
|
342
|
+
|
|
343
|
+
- Tail `.tmp/logs/setup-*.log` and check the output artefact is still growing.
|
|
344
|
+
- **Wait in a loop, never in one long sleep.** Sleep at most 30 seconds at a
|
|
345
|
+
time, then check the log and say what it shows, and repeat until the step
|
|
346
|
+
finishes. A single long block makes the run unwatchable and hides a failure
|
|
347
|
+
that happened in the first ten seconds.
|
|
348
|
+
- Report progress as you go: which step is running, how long it has been going,
|
|
349
|
+
what the last log line said.
|
|
350
|
+
- Do not kill a quiet step. Confirm the process is dead or the log and the
|
|
351
|
+
output have both stopped growing before calling it stuck.
|
|
352
|
+
- On failure, read that step's log, fix the cause, and run `scripts/_setup.sh`
|
|
353
|
+
again - re-running is the fix path, not a reset. If the same step fails twice
|
|
354
|
+
for the same reason, stop and raise it in `SPECIFICATION-FEEDBACK.md`.
|
|
355
|
+
- Prove re-entrancy: once it has succeeded, run `scripts/_setup.sh` once more and
|
|
356
|
+
check that every step reports `skipped` rather than rebuilding.
|
|
357
|
+
|
|
358
|
+
## 7. Verify and report
|
|
359
|
+
|
|
360
|
+
Run `zen check` again and fix whatever it names rather than working around it.
|
|
361
|
+
It validates structure and says nothing about the prose, so work §9 of the
|
|
362
|
+
copilot instructions as a checklist afterwards and report each group pass or
|
|
363
|
+
fail. Then report in the chat:
|
|
364
|
+
|
|
365
|
+
- what changed, file by file, and which specification item each change closes
|
|
366
|
+
- every prompt or skill line that served no specification item, and what became
|
|
367
|
+
of it - corrected, or reported and left alone
|
|
368
|
+
- the outcome of every `scripts/_setup.sh` step, and what each one produced
|
|
369
|
+
- what is still open, with a pointer to its `SPECIFICATION-FEEDBACK.md` entry
|
|
370
|
+
- anything you found that the specification does not cover at all
|
|
371
|
+
|
|
372
|
+
## 8. Record the pass
|
|
373
|
+
|
|
374
|
+
Last, and only once §6 and §7 have actually passed. Write
|
|
375
|
+
`.spec-sync/history/<stamp>.md` in the format the `zen-spec-sync` skill gives -
|
|
376
|
+
including `Still open`, which is the only place the next pass learns that an
|
|
377
|
+
unchanged specification line is not yet implemented - and then:
|
|
378
|
+
|
|
379
|
+
```sh
|
|
380
|
+
.github/skills/zen-spec-sync/scripts/snapshot.sh commit
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
In that order, never the other way. Moving the baseline before the pass has
|
|
384
|
+
finished records a specification as applied that was not: the next pass diffs
|
|
385
|
+
against it, sees nothing to do, and the work is never done by anybody. A pass
|
|
386
|
+
that fails with the baseline unmoved costs one repeat.
|
|
387
|
+
|
|
388
|
+
A pass that changed nothing still writes a history file and still commits. Say
|
|
389
|
+
in the chat which history file you wrote and that the baseline moved.
|
|
390
|
+
|
|
391
|
+
Do not report a specification item as done unless the file that implements it
|
|
392
|
+
exists, `zen check` passes, and `scripts/_setup.sh` completed every step it owns.
|
|
@@ -31,15 +31,18 @@ checked too. A word that is neither is a usage error (exit 2), not a report.
|
|
|
31
31
|
|
|
32
32
|
- `agents.yaml` parses and satisfies the schema, with unknown keys reported
|
|
33
33
|
rather than ignored.
|
|
34
|
-
- Every file the configuration names is on disk and non-empty:
|
|
35
|
-
each agent's prompt, each skill's `SKILL.md`, each asset glob.
|
|
34
|
+
- Every file the configuration names is on disk and non-empty: the house rules
|
|
35
|
+
under `agents/`, each agent's prompt, each skill's `SKILL.md`, each asset glob.
|
|
36
|
+
A root `INSTRUCTIONS.md` is still read, and reported as something to move to
|
|
37
|
+
`agents/instructions.md`.
|
|
36
38
|
- Hand-offs and forks name agents that exist, and no agent hands off to itself.
|
|
37
39
|
- Tool selectors resolve against the real tool set, including a skill's own
|
|
38
40
|
`tools:` frontmatter.
|
|
39
41
|
- Skills bind to a catalog that holds them, and every declared skill is
|
|
40
42
|
reachable from some agent.
|
|
41
43
|
- Every declared model and embedding resolves to a provider, and that provider
|
|
42
|
-
has a credential on this machine.
|
|
44
|
+
has a credential on this machine. The project's `.env` is read first, exactly
|
|
45
|
+
as `zen run` reads it, so the verdict is the one a run would reach.
|
|
43
46
|
- Unless `--no-models`, every model that has a credential is **asked to answer**
|
|
44
47
|
once. A key that authenticates says nothing about the id it is spent on, so
|
|
45
48
|
this is the only way to catch a misspelt, retired or ungranted model. A refusal
|
|
@@ -107,10 +107,12 @@ A real environment variable always beats the keyring.
|
|
|
107
107
|
|
|
108
108
|
<project>/
|
|
109
109
|
zenera.json { version, name }
|
|
110
|
-
INSTRUCTIONS.md house rules, prepended to every agent's prompt
|
|
111
110
|
agents.yaml the configuration
|
|
112
|
-
agents/
|
|
113
|
-
|
|
111
|
+
agents/
|
|
112
|
+
instructions.md house rules, prepended to every agent's prompt
|
|
113
|
+
*-instructions.md more house rules, in filename order
|
|
114
|
+
prompts/ one .md per agent
|
|
115
|
+
skills/ one directory per skill, each with SKILL.md
|
|
114
116
|
sandbox/Dockerfile the image commands run in, when the project builds one
|
|
115
117
|
sessions/ run state, memory, blobs, reports - never committed
|
|
116
118
|
```
|
|
@@ -7,12 +7,13 @@ zen inspect [run] [--session <id>] [--open] [--rebuild] [--serve [port]]
|
|
|
7
7
|
Alias: `report`.
|
|
8
8
|
|
|
9
9
|
Renders the trajectory of a run: every message, tool call, skill activation and
|
|
10
|
-
hand-off, in order, with what each one cost. With no arguments it
|
|
11
|
-
|
|
10
|
+
hand-off, in order, with what each one cost. With no arguments it asks which
|
|
11
|
+
session and which run; where there is nothing to ask on — a script, `--json`,
|
|
12
|
+
an agent — it takes the newest run of the newest session that has one.
|
|
12
13
|
|
|
13
14
|
| Flag | Meaning |
|
|
14
15
|
| ---------------- | ------------------------------------------------------- |
|
|
15
|
-
| `[run]` | A run id
|
|
16
|
+
| `[run]` | A run id, in whichever session holds it |
|
|
16
17
|
| `--session <id>` | Which session the run belongs to |
|
|
17
18
|
| `--open` | Open the report in a browser |
|
|
18
19
|
| `--rebuild` | Rebuild `report.html` from the recorded state |
|