@zenera/cli 1.1.15 → 1.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +201 -129
  2. package/dist/banner.d.ts +5 -1
  3. package/dist/banner.js +2 -2
  4. package/dist/catalog.js +19 -20
  5. package/dist/command.d.ts +5 -0
  6. package/dist/commands/check.js +5 -1
  7. package/dist/commands/init.js +41 -6
  8. package/dist/commands/run.js +4 -0
  9. package/dist/engine.js +6 -0
  10. package/dist/env.d.ts +20 -0
  11. package/dist/env.js +65 -0
  12. package/dist/keys.d.ts +2 -0
  13. package/dist/keys.js +2 -0
  14. package/dist/main.js +10 -6
  15. package/dist/sandbox.d.ts +9 -0
  16. package/dist/sandbox.js +23 -3
  17. package/dist/scaffold.d.ts +6 -0
  18. package/dist/scaffold.js +56 -15
  19. package/dist/validate.js +57 -15
  20. package/package.json +2 -2
  21. package/templates/editor/.github/copilot-instructions.md +501 -301
  22. package/templates/editor/.github/prompts/new-agent.prompt.md +6 -6
  23. package/templates/editor/.github/prompts/new-skill.prompt.md +7 -7
  24. package/templates/editor/.github/prompts/review-project.prompt.md +54 -15
  25. package/templates/editor/.github/prompts/sync-with-spec.prompt.md +229 -42
  26. package/templates/editor/.github/prompts/update-spec-from-feedback.prompt.md +142 -0
  27. package/templates/editor/.github/skills/zen-cli/SKILL.md +62 -6
  28. package/templates/editor/.github/skills/zen-cli/references/check.md +9 -6
  29. package/templates/editor/.github/skills/zen-cli/references/faker.md +14 -14
  30. package/templates/editor/.github/skills/zen-cli/references/frame.md +11 -9
  31. package/templates/editor/.github/skills/zen-cli/references/inspect.md +3 -3
  32. package/templates/editor/.github/skills/zen-cli/references/keys.md +9 -9
  33. package/templates/editor/.github/skills/zen-cli/references/memory.md +11 -11
  34. package/templates/editor/.github/skills/zen-cli/references/models.md +8 -8
  35. package/templates/editor/.github/skills/zen-cli/references/projects.md +23 -6
  36. package/templates/editor/.github/skills/zen-cli/references/rag.md +191 -56
  37. package/templates/editor/.github/skills/zen-cli/references/run.md +3 -3
  38. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +14 -8
  39. package/templates/editor/.github/skills/zen-memory/SKILL.md +144 -72
  40. package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +115 -0
  41. package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +71 -48
  42. package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +67 -67
  43. package/templates/editor/.github/skills/zen-review/SKILL.md +123 -0
  44. package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +119 -0
  45. package/templates/editor/.github/skills/zen-review/scripts/review.sh +104 -0
  46. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +197 -0
  47. package/templates/editor/.github/skills/zen-spec-sync/scripts/snapshot.sh +200 -0
  48. package/templates/editor/.vscode/settings.json +46 -3
  49. package/templates/parts/memory-terms.yaml.tmpl +16 -0
  50. package/templates/parts/memory.yaml.tmpl +12 -0
  51. package/templates/project/SPECIFICATION.md.tmpl +7 -0
  52. package/templates/project/{INSTRUCTIONS.md → agents/instructions.md} +1 -1
  53. package/templates/project/agents/memory-instructions.md +278 -0
  54. package/templates/project/agents.yaml.tmpl +9 -0
  55. package/templates/project/assets/README.md +1 -1
  56. package/templates/project/env +22 -0
  57. package/templates/project/sandbox/Dockerfile.tmpl +3 -0
@@ -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
+ `/sync-with-spec`, 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 `/sync-with-spec`
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 `/sync-with-spec` 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 `/sync-with-spec` 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 `/sync-with-spec` to make the project match the
142
+ specification you have just changed.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: zen-cli
3
- description: How to drive this project from the terminal with `zen` — running it, validating it, credentials, the sandbox, run reports, and the `faker` and `rag` modules.
3
+ description: How to drive this project from the terminal with `zen` - running it, validating it, credentials, the sandbox, run reports, and the `faker` and `rag` modules.
4
4
  ---
5
5
 
6
6
  # The `zen` command line
@@ -36,7 +36,7 @@ zen rag docs <index|search|list|grep|show|stats> [path...]
36
36
  ## Read the reference before answering
37
37
 
38
38
  The full reference lives next to this file, one document per part of the command
39
- line. **Read the one that covers the question before answering it** — do not
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
42
  | The question is about | Read |
@@ -50,8 +50,8 @@ guess a flag, and do not read them all.
50
50
  | The container shell commands run in, images, `persist` | [sandbox.md](./references/sandbox.md) |
51
51
  | Run reports, trajectories, what a session directory holds | [inspect.md](./references/inspect.md) |
52
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) |
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
 
@@ -67,6 +67,62 @@ zen models test <ref> whether one model actually answers
67
67
  zen models pick --embedding the first embedder that does, on stdout
68
68
  ```
69
69
 
70
+ ## Searching documents without help
71
+
72
+ Use `zen rag docs` for a directory of Markdown or text, and put the index path
73
+ in `-d <index-dir>` when it is not beside the working directory. These commands
74
+ are enough to discover the corpus and retrieve evidence; do not spend a turn on
75
+ `--help` first:
76
+
77
+ ```sh
78
+ zen rag docs list files -d <index-dir>
79
+ zen rag docs list sections -d <index-dir> --file "<path-pattern>"
80
+ zen rag docs search -d <index-dir> "<question in natural language>"
81
+ zen rag docs search -d <index-dir> --file "<path-pattern>" --section "<heading>" "<question>"
82
+ zen rag docs grep -d <index-dir> "<exact string>" --file "<path-pattern>"
83
+ zen rag docs show -d <index-dir> "<file>" --section "<heading>"
84
+ ```
85
+
86
+ Start with one ordinary hybrid question. It is the best default for concepts and
87
+ open questions. Search returns candidates, not proof: read the quoted lines,
88
+ then use `show` or `grep` before claiming a fact is present or absent.
89
+
90
+ When the first answer is from the wrong product area, version, file, or heading,
91
+ ask the same question again with `--file` and then `--section`. A bare `--file`
92
+ value is a substring; `*` and `?` make it a glob. Use `--kind table` or
93
+ `--kind table_row` for limits and matrices, `--mode text` for a known exact
94
+ phrase, and `--exclude-id <id>` to continue past an already-read passage.
95
+
96
+ `--file` is the primary scope control: repeat it to admit several document
97
+ families, and use `--exclude-file` to remove a noisy family. Both are resolved
98
+ before ranking, so a result cannot come from an excluded document. `--section`
99
+ then keeps only a matching heading and its nested headings within those files.
100
+ For example, search two manual families but exclude archived releases:
101
+
102
+ ```sh
103
+ zen rag docs search -d <index-dir> --file "manual-*/**" --file "guide-*/**" \
104
+ --exclude-file "*-archive/**" --section "Operations" "<question>"
105
+ ```
106
+
107
+ Hybrid is not a vector reranker. It retrieves a candidate list from full-text
108
+ search and another from vector similarity, then fuses their ranks. Full-text
109
+ finds literal terms; vector search finds passages with the same meaning even
110
+ when their wording differs. `--mode text` or `--mode vector` runs only one leg;
111
+ ordinary hybrid runs both and is normally the right choice.
112
+
113
+ Use `--text-query` with `--vector-query` only when one wording cannot serve both
114
+ retrievers: a distinctive corpus term or command for the text leg, and the full
115
+ question for the vector leg. For example:
116
+
117
+ ```sh
118
+ zen rag docs search -d <index-dir> --text-query "exact identifier" \
119
+ --vector-query "what it means and how to use it"
120
+ ```
121
+
122
+ This is not a general upgrade over hybrid search. Generic product names and
123
+ common nouns make weak text legs that can displace better semantic results. The
124
+ two flags replace positional text and `--mode`; give neither alongside them.
125
+
70
126
  Run `zen check` after any edit to `agents.yaml`, a prompt or a skill: it reads
71
127
  the project the way a run does, reports everything wrong at once, and calls no
72
128
  model. It is the cheapest possible test.
@@ -75,7 +131,7 @@ When behaviour is wrong and the prompt looks right, open the run report. It
75
131
  shows what the model was actually given, which is rarely what you assumed.
76
132
 
77
133
  Flags always beat the file: the repository states intent, the invocation
78
- overrides it. Failure messages name the offending key or file — a load error
79
- names the exact path, as in `agents.yaml: agents[1].skills.discovery — …` — so
134
+ overrides it. Failure messages name the offending key or file - a load error
135
+ names the exact path, as in `agents.yaml: agents[1].skills.discovery - …` - so
80
136
  read it rather than guessing. The loader is strict on purpose, and an unknown
81
137
  key is an error rather than a value quietly ignored.
@@ -1,4 +1,4 @@
1
- # Validating — `zen check`
1
+ # Validating - `zen check`
2
2
 
3
3
  It reads the project without running it, and spends a few tokens asking each
4
4
  model to answer once; `--no-models` gives an answer that costs nothing at all.
@@ -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: `INSTRUCTIONS.md`,
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
@@ -47,7 +50,7 @@ checked too. A word that is neither is a usage error (exit 2), not a report.
47
50
  is a warning (`.unreachable`), because that is the network's problem and not
48
51
  the project's.
49
52
  - The sandbox: paths stay inside the project, the Dockerfile and its context
50
- exist, and — unless `--no-sandbox` — the image **builds** and one command runs
53
+ exist, and - unless `--no-sandbox` - the image **builds** and one command runs
51
54
  in it, against a temporary directory rather than your workspace. No container
52
55
  engine at all is a warning, not an error.
53
56
 
@@ -71,7 +74,7 @@ embedding.refused embedding.unreachable embedding.unusable
71
74
  credential.* service.credential
72
75
  ```
73
76
 
74
- The report goes to **stdout** — it is the answer. `--json` gives the same
77
+ The report goes to **stdout** - it is the answer. `--json` gives the same
75
78
  findings as data.
76
79
 
77
80
  Exit codes: `0` nothing wrong, `3` at least one error, or with `--strict` at
@@ -1,10 +1,10 @@
1
- # Mock APIs — `zen faker`
1
+ # Mock APIs - `zen faker`
2
2
 
3
3
  ```
4
4
  zen faker <serve|build|cache> [spec...]
5
5
  ```
6
6
 
7
- Alias: `zen mock`. Provided by `@zenera/faker` — `npm i -g @zenera/faker` if
7
+ Alias: `zen mock`. Provided by `@zenera/faker` - `npm i -g @zenera/faker` if
8
8
  `zen faker` says it is not installed.
9
9
 
10
10
  Serves a mock API from one or more OpenAPI/Swagger documents. For each
@@ -39,16 +39,16 @@ front and exits non-zero, with a table, if any could not be written.
39
39
  | `--model <ref>` | project default | Which model writes the generators |
40
40
  | `--image <ref>` | a baked image | Skip the baked image and use this one |
41
41
  | `--cache <dir>` | `~/.zenera/neo/faker` | Where generators live |
42
- | `--seed <n>` | — | Answer the same request the same way every time |
42
+ | `--seed <n>` | - | Answer the same request the same way every time |
43
43
  | `--attempts <n>` | `3` | Tries per generator before giving up |
44
44
  | `--concurrency <n>` | `4` | Generators written at once |
45
45
  | `--timeout <s>` | `30` | Seconds one generator may take |
46
46
  | `--max-body <n>` | 1 MB | Largest request body accepted, in bytes |
47
- | `--rebuild` | — | Ignore what is cached and write it again |
48
- | `--no-cache` | — | Do not record what is written |
49
- | `--quiet` | — | No narration |
47
+ | `--rebuild` | - | Ignore what is cached and write it again |
48
+ | `--no-cache` | - | Do not record what is written |
49
+ | `--quiet` | - | No narration |
50
50
 
51
- Credentials come from the `zen` keyring — see [keys.md](keys.md).
51
+ Credentials come from the `zen` keyring - see [keys.md](keys.md).
52
52
 
53
53
  ## Serving
54
54
 
@@ -66,19 +66,19 @@ Response headers:
66
66
  | Header | Meaning |
67
67
  | ------------------- | ----------------------------------------------------- |
68
68
  | `x-faker-operation` | The `operationId` that answered |
69
- | `x-faker-cache` | `hit` or `miss` — whether this call cost a model turn |
69
+ | `x-faker-cache` | `hit` or `miss` - whether this call cost a model turn |
70
70
 
71
71
  Incoming headers are filtered: `authorization`, `cookie` and anything matching
72
72
  `key|token|secret|password|credential` never reach a generator.
73
73
 
74
74
  `--seed` makes each request's seed a hash of the seed, the operation and the
75
- parameters, so the same request answers identically across restarts — which is
75
+ parameters, so the same request answers identically across restarts - which is
76
76
  what makes a mock usable in a test.
77
77
 
78
78
  ## What "correct" means here
79
79
 
80
80
  A generator is judged on two synthetic probes: the body validates against the
81
- response schema, **and** it obeys the **echo rule** — a value given in the path
81
+ response schema, **and** it obeys the **echo rule** - a value given in the path
82
82
  comes back in the answer. `GET /users/12324` must return `user_id: 12324`. A body
83
83
  can validate perfectly and still be about the wrong entity, which is exactly the
84
84
  mock that wastes an afternoon.
@@ -87,16 +87,16 @@ Query parameters are deliberately not enforced: `?source=realtime`, `?page_size`
87
87
  and `?cursor` are controls, and their names collide with unrelated response
88
88
  fields.
89
89
 
90
- Probes are synthetic on purpose — real request bodies never reach a prompt.
90
+ Probes are synthetic on purpose - real request bodies never reach a prompt.
91
91
 
92
92
  ## The cache
93
93
 
94
94
  Generators live in the machine's shared cache, `~/.zenera/neo/cache/faker-generator/`,
95
- keyed by the operation's shape — so the same spec served from two directories is
95
+ keyed by the operation's shape - so the same spec served from two directories is
96
96
  written once, and a spec edit produces a new key rather than a stale answer. A
97
97
  generator that a model gave up on is remembered for the life of the process, so
98
- a hopeless operation is not re-asked on every request; a _transient_ failure — a
99
- 429, a dropped socket — is not, because it is about this minute rather than this
98
+ a hopeless operation is not re-asked on every request; a _transient_ failure - a
99
+ 429, a dropped socket - is not, because it is about this minute rather than this
100
100
  operation.
101
101
 
102
102
  `~/.zenera/neo/faker/` is the container's workspace, and scratch: a cache hit is
@@ -48,7 +48,7 @@ Progress, banners, warnings and the spinner go to stderr. So
48
48
 
49
49
  `--json` applies to every command and prints one machine-readable document on
50
50
  stdout in place of the rendered form. Under `--json` nothing is asked
51
- interactively — the questions a run would ask are taken as answered.
51
+ interactively - the questions a run would ask are taken as answered.
52
52
 
53
53
  The banner is drawn only when stderr is a terminal, so a piped invocation never
54
54
  sees it.
@@ -60,13 +60,13 @@ sees it.
60
60
  | 0 | ok | It worked |
61
61
  | 1 | failed | It ran and did not succeed |
62
62
  | 2 | usage | The command line was wrong |
63
- | 3 | invalid | The project is not valid — bad `agents.yaml`, missing file |
63
+ | 3 | invalid | The project is not valid - bad `agents.yaml`, missing file |
64
64
  | 4 | credentials | No usable credential for what was asked |
65
65
  | 5 | sandbox | No container engine, or the image could not be prepared |
66
66
 
67
67
  A wrong invocation and a wrong answer are deliberately not the same code, which
68
68
  is what a script needs. Failure messages name the offending key or file; a load
69
- error names the exact path, as in `agents.yaml: agents[1].skills.discovery — …`.
69
+ error names the exact path, as in `agents.yaml: agents[1].skills.discovery - …`.
70
70
  Read it rather than guessing: the loader is strict on purpose and an unknown key
71
71
  is an error, not a value quietly ignored.
72
72
 
@@ -74,7 +74,7 @@ is an error, not a value quietly ignored.
74
74
 
75
75
  Most commands operate on a project directory, resolved in this order:
76
76
 
77
- 1. `--project <name|dir>` — a registry name or a path.
77
+ 1. `--project <name|dir>` - a registry name or a path.
78
78
  2. The working directory, if it is a project (or is inside one).
79
79
  3. For `zen run`, a bare first word that names a registered project.
80
80
 
@@ -92,7 +92,7 @@ unregistered directory can still be validated.
92
92
  | `ZENERA_DEBUG` | Print a stack trace when something unexpected escapes |
93
93
  | `VISUAL`, `EDITOR` | Consulted by `zen open` after `ZENERA_EDITOR` |
94
94
  | `COLORFGBG` | Read as a hint when the palette is being detected |
95
- | Provider keys | `OPENAI_API_KEY` and friends — see [keys.md](keys.md) |
95
+ | Provider keys | `OPENAI_API_KEY` and friends - see [keys.md](keys.md) |
96
96
 
97
97
  A real environment variable always beats the keyring.
98
98
 
@@ -107,12 +107,14 @@ 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/prompts/ one .md per agent
113
- agents/skills/ one directory per skill, each with SKILL.md
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
- sessions/ run state, memory, blobs, reports — never committed
117
+ sessions/ run state, memory, blobs, reports - never committed
116
118
  ```
117
119
 
118
120
  Credential files are refused if anyone but the owner can read them, the way
@@ -1,4 +1,4 @@
1
- # Reports — `zen inspect`
1
+ # Reports - `zen inspect`
2
2
 
3
3
  ```
4
4
  zen inspect [run] [--session <id>] [--open] [--rebuild] [--serve [port]]
@@ -29,7 +29,7 @@ was assembled differently from how it looks in the repository: a skill that did
29
29
  not activate, a hand-off that fired early, a tool that was withheld, an asset
30
30
  that was not attached.
31
31
 
32
- The report also draws the architecture — agents, their tools, their hand-offs —
32
+ The report also draws the architecture - agents, their tools, their hand-offs -
33
33
  and falls back to reconstructing the wiring from the trajectory when the run
34
34
  did not record it.
35
35
 
@@ -52,7 +52,7 @@ resolves them back.
52
52
 
53
53
  ## What it prints
54
54
 
55
- The path to `report.html` on stdout — it is the answer, so it pipes. `--json`
55
+ The path to `report.html` on stdout - it is the answer, so it pipes. `--json`
56
56
  gives `{ session, run, report }` instead. A report that is missing is built
57
57
  before either; `--rebuild` builds one that already exists again, which is always
58
58
  safe because the report is derived and `state.json` is the truth. That is also
@@ -1,4 +1,4 @@
1
- # Credentials — `zen key`
1
+ # Credentials - `zen key`
2
2
 
3
3
  ```
4
4
  zen key <ls|add|use|check|rm|show|env> [ref] [options]
@@ -85,7 +85,7 @@ behind, marked `~` and named for the variable rather than for a key:
85
85
  ~ vertex/adc …/application_default_credentials.json
86
86
  ```
87
87
 
88
- These can be listed and checked, not chosen or forgotten — there is nothing to
88
+ These can be listed and checked, not chosen or forgotten - there is nothing to
89
89
  choose between, and nothing of ours to remove. Unset the variable, or
90
90
  `gcloud auth application-default revoke`.
91
91
 
@@ -94,15 +94,15 @@ choose between, and nothing of ours to remove. Unset the variable, or
94
94
  `zen key check` and `zen key ls --check` do one round trip per key and record
95
95
  the verdict:
96
96
 
97
- - **live** — authenticated. A rate-limited answer counts as live, because it
97
+ - **live** - authenticated. A rate-limited answer counts as live, because it
98
98
  proves the credential.
99
- - **dead** — the provider rejected it. A verdict.
100
- - **blocked** — the credential was accepted and the **account** refused: an API
99
+ - **dead** - the provider rejected it. A verdict.
100
+ - **blocked** - the credential was accepted and the **account** refused: an API
101
101
  switched off in the project, an empty balance, a model this key was never
102
102
  granted. Do not rotate the key; a new one is refused identically. The check
103
- carries a `fix` — for a disabled Google API, the exact
103
+ carries a `fix` - for a disabled Google API, the exact
104
104
  `gcloud services enable <api> --project <id>`.
105
- - **unknown** — the provider could not be asked. Says nothing about the key;
105
+ - **unknown** - the provider could not be asked. Says nothing about the key;
106
106
  usually the network.
107
107
 
108
108
  `zen init` uses the same probe to pick which provider to scaffold with, so a
@@ -110,9 +110,9 @@ project is not built around a revoked key.
110
110
 
111
111
  ## When a run says there is no credential
112
112
 
113
- The frame does **not** materialise the keyring for you — each command that needs
113
+ The frame does **not** materialise the keyring for you - each command that needs
114
114
  a credential opens the store itself. If `zen key ls` shows a key as live and a
115
- command still says `provider "openai": no api key — set OPENAI_API_KEY`, the
115
+ command still says `provider "openai": no api key - set OPENAI_API_KEY`, the
116
116
  credential is fine and the command is at fault. Everything that runs a model
117
117
  (`run`, `check`, `models`, `faker`, `rag`) already does this.
118
118
 
@@ -1,4 +1,4 @@
1
- # Memory — `zen memory`
1
+ # Memory - `zen memory`
2
2
 
3
3
  ```
4
4
  zen memory [stats|ls|show|export|forget] [args] [options]
@@ -45,7 +45,7 @@ is masked, ranked and truncated as well, so what an agent gets is never the
45
45
  whole picture.
46
46
 
47
47
  This command ignores all of that. When the mask is the thing that is wrong, the
48
- part that was hidden is exactly the part you need — and this is a person at a
48
+ part that was hidden is exactly the part you need - and this is a person at a
49
49
  terminal in the project directory, not an agent inside a run.
50
50
 
51
51
  It also contacts no model. The store is opened without an embedder, so
@@ -60,12 +60,12 @@ zen memory export --open
60
60
 
61
61
  One self-contained HTML file, three panes:
62
62
 
63
- - **left** — every node, with a search box and filters for kind, audience,
63
+ - **left** - every node, with a search box and filters for kind, audience,
64
64
  files, superseded and unlinked
65
- - **middle** — the graph as a Mermaid diagram, coloured by kind, with pan,
65
+ - **middle** - the graph as a Mermaid diagram, coloured by kind, with pan,
66
66
  zoom, and a hop-focus selector for following one node's neighbourhood
67
- - **right** — whatever you clicked, in full: the text, the metadata, the links,
68
- and **the remembered file's actual content** — rendered as an image when it is
67
+ - **right** - whatever you clicked, in full: the text, the metadata, the links,
68
+ and **the remembered file's actual content** - rendered as an image when it is
69
69
  one, and as text otherwise
70
70
 
71
71
  Clicking a node in either the list or the diagram selects it in both. Above 300
@@ -83,15 +83,15 @@ zen memory forget 01M1YPN0C8QRQS5BCZ03ABQ1G0
83
83
  ```
84
84
 
85
85
  Asks first, unless `--yes`, and refuses outright when there is no terminal to
86
- ask at. A node, its vector row and its remembered file bytes go together —
86
+ ask at. A node, its vector row and its remembered file bytes go together -
87
87
  there is one implementation of that, shared with the agent-facing tool, so the
88
88
  three cannot drift apart.
89
89
 
90
90
  **Forgetting is rarely the right correction.** The agents' own way to fix a
91
91
  wrong memory is to commit the corrected node and supersede the old one, which
92
92
  keeps the record of having been wrong. `zen memory ls --stale` lists what has
93
- been superseded that way. Use `forget` for what should never have been stored —
94
- a secret, a mistake, a pile of noise — not for what merely became untrue.
93
+ been superseded that way. Use `forget` for what should never have been stored -
94
+ a secret, a mistake, a pile of noise - not for what merely became untrue.
95
95
 
96
96
  ## Reading `stats`
97
97
 
@@ -100,8 +100,8 @@ nodes 7
100
100
  edges 6
101
101
  superseded 1
102
102
  files 1 · 640 B
103
- embedding none — recall falls back to term overlap
104
- vectors —
103
+ embedding none - recall falls back to term overlap
104
+ vectors -
105
105
  ```
106
106
 
107
107
  `embedding none` is worth noticing: without an embedder, recall matches on
@@ -1,4 +1,4 @@
1
- # Models — `zen models`
1
+ # Models - `zen models`
2
2
 
3
3
  ```
4
4
  zen models <providers|ls|search|show|test|pick> [ref] [options]
@@ -6,8 +6,8 @@ zen models <providers|ls|search|show|test|pick> [ref] [options]
6
6
 
7
7
  Alias: `model`.
8
8
 
9
- Answers **what can I use**. `zen check` answers the other question — whether one
10
- particular project works — and needs a project to do it. This one needs nothing
9
+ Answers **what can I use**. `zen check` answers the other question - whether one
10
+ particular project works - and needs a project to do it. This one needs nothing
11
11
  but a credential.
12
12
 
13
13
  ## Subcommands
@@ -33,7 +33,7 @@ Filters, on `ls` and `search`: `--chat`, `--embeddings`, `--images`, `--audio`,
33
33
  The providers themselves, cached for a day in `~/.zenera/neo/catalog`. When a
34
34
  provider cannot be asked, the last listing is used and reported as stale; only
35
35
  if there was never one does a short built-in list stand in. Every row says which
36
- it was — `--json` carries `source` per model and `origin` per provider.
36
+ it was - `--json` carries `source` per model and `origin` per provider.
37
37
 
38
38
  `--refresh` bypasses the cache. It is the only thing that does.
39
39
 
@@ -48,7 +48,7 @@ zen models test vertex:gemini-embedding-001 --embedding
48
48
 
49
49
  The role is taken from the flag, else from what the provider says the model is
50
50
  for, else from the id. One minimal call: `ok` for a chat model, one short vector
51
- for an embedder — the embedding's width is reported, which matters because a
51
+ for an embedder - the embedding's width is reported, which matters because a
52
52
  model serving a different number of dimensions is not interchangeable with the
53
53
  one an index was built on.
54
54
 
@@ -84,7 +84,7 @@ openai:text-embedding-3-small
84
84
  ```
85
85
 
86
86
  `pick` tries a short ordered list one at a time and stops at the first that
87
- works. Sequential on purpose — the goal is one working ref, not a survey. The
87
+ works. Sequential on purpose - the goal is one working ref, not a survey. The
88
88
  ref goes to **stdout alone and unstyled**, so it substitutes directly:
89
89
 
90
90
  ```sh
@@ -92,7 +92,7 @@ zen rag schema index --embedding "$(zen models pick --embedding)" ./specs/*.yaml
92
92
  ```
93
93
 
94
94
  `zen models pick --embedding --json` gives `{ref, provider, model, role,
95
- dimensions, ms, tried}` — `tried` lists every candidate and why it was passed
95
+ dimensions, ms, tried}` - `tried` lists every candidate and why it was passed
96
96
  over, so a caller can see _why_ a provider was skipped rather than only that it
97
97
  was.
98
98
 
@@ -101,7 +101,7 @@ When nothing answers, exit `4` and the table of everything tried.
101
101
  ## What it will not do
102
102
 
103
103
  There is no `test --all`. A sweep across every model on the machine is a bill,
104
- not a diagnostic — name the refs you care about, or use `pick`.
104
+ not a diagnostic - name the refs you care about, or use `pick`.
105
105
 
106
106
  There is no ranking. The candidate order in `pick` is cheapest-and-fastest
107
107
  first, which is about how quickly an answer arrives, not about which model is