@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
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/andreyryabov/ZeneraNeo/main/docs/imgs/banner-neo-dark.svg">
4
- <img src="https://raw.githubusercontent.com/andreyryabov/ZeneraNeo/main/docs/imgs/banner-neo-light.svg" alt="ZENERA NEO" width="720">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/andreyryabov/ZeneraNeo/main/docs/imgs/banner-cli-dark.svg">
4
+ <img src="https://raw.githubusercontent.com/andreyryabov/ZeneraNeo/main/docs/imgs/banner-cli-light.svg" alt="ZENERA CLI" width="720">
5
5
  </picture>
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/@zenera/cli.svg)](https://www.npmjs.com/package/@zenera/cli)
@@ -12,23 +12,27 @@
12
12
 
13
13
  # @zenera/cli
14
14
 
15
- **`zen` — build specialist agents. Share them. Run them from the command line.**
15
+ **`zen` - build specialist agents. Share them. Run them from the command line.**
16
16
 
17
- Not one general assistant that is passable at everything — a team built for the
17
+ `@zenera/cli` is the command-line package in the
18
+ [ZeneraNeo](https://github.com/andreyryabov/ZeneraNeo) toolkit. It creates,
19
+ runs, tests and improves the specialized agent systems defined by a project.
20
+
21
+ Not one general assistant that is passable at everything - a team built for the
18
22
  work you actually keep doing, under a name you can type:
19
23
 
20
24
  ```sh
21
- zen run accountant "Q3 — match the receipts drawer to the ledger, then update the return"
22
- zen run accountant "this MSA against our playbook — redlines, and what I must not sign"
23
- zen run analyst "why churn doubled in the EU accounts — the exports are in this folder"
25
+ zen run accountant "Q3 - match the receipts drawer to the ledger, then update the return"
26
+ zen run accountant "this MSA against our playbook - redlines, and what I must not sign"
27
+ zen run analyst "why churn doubled in the EU accounts - the exports are in this folder"
24
28
  zen run analyst "what changed in EU battery regulation this year, with sources"
25
- zen run devops "this week's advisories — which of them actually reach our code"
26
- zen run devops "the 03:12 outage — timeline, contributing factors, owners"
29
+ zen run devops "this week's advisories - which of them actually reach our code"
30
+ zen run devops "the 03:12 outage - timeline, contributing factors, owners"
27
31
  ```
28
32
 
29
33
  Three agents there, six things asked of them: an agent you have built is not a
30
34
  script with one job, it is a specialist you keep going back to. And it is work
31
- that comes back — every quarter, every sprint, every deal — which is exactly the
35
+ that comes back - every quarter, every sprint, every deal - which is exactly the
32
36
  work nobody has shipped you a product for.
33
37
 
34
38
  Once the agent exists it is a command: it works on the files you are standing
@@ -37,25 +41,25 @@ records every token it spent doing it.
37
41
 
38
42
  Getting there is three beats:
39
43
 
40
- 1. **Describe it.** You write `SPECIFICATION.md` — what the system is for,
44
+ 1. **Describe it.** You write `SPECIFICATION.md` - what the system is for,
41
45
  which specialists it needs, what each may reach for, what _done_ means. The
42
46
  rest of the folder is built to implement it.
43
47
  2. **Test it.** `zen check` validates the project and every file it names,
44
48
  `zen run` exercises it for real, `zen inspect` opens the record of what it
45
49
  actually did. When it comes out wrong you fix the specification, not the
46
50
  prompts, and go round again.
47
- 3. **Share it.** It is a folder — commit it, review it in a pull request, send
51
+ 3. **Share it.** It is a folder - commit it, review it in a pull request, send
48
52
  it. One `zen init <dir>` on a project that arrived by clone registers it
49
53
  without touching a thing, and it is their command now too.
50
54
 
51
55
  > Part of [ZeneraNeo](https://github.com/andreyryabov/ZeneraNeo). This is an
52
- > open-source side project for experimentation and chore work — **not** the
56
+ > open-source side project for experimentation and chore work - **not** the
53
57
  > official Zenera AI Platform. It carries no support or stability promises.
54
58
 
55
59
  ## What you build
56
60
 
57
61
  Half a page of specification turns into a system like one of these. Nothing here
58
- ships with the CLI — each is a folder somebody wrote, and could send you.
62
+ ships with the CLI - each is a folder somebody wrote, and could send you.
59
63
 
60
64
  | Project | The team inside it |
61
65
  | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -63,37 +67,37 @@ ships with the CLI — each is a folder somebody wrote, and could send you.
63
67
  | **analyst** | A planner that splits the question into branches; researchers that run in parallel over your files and the web; a statistician that writes and runs Python in the sandbox; an editor that joins it into one answer where every claim carries its source. |
64
68
  | **devops** | A gatherer that pulls advisories, logs, alerts and deploys into one picture; a tracer that works out whether a vulnerable path is reachable at all, or which change actually broke it; an engineer that plans the fix, applies it a step at a time, and stops the moment a check fails. |
65
69
 
66
- Build one, commit it, and it runs the same on anyone else's machine — on
70
+ Build one, commit it, and it runs the same on anyone else's machine - on
67
71
  whichever models they prefer, and without carrying your keys.
68
72
 
69
73
  ## What makes it different
70
74
 
71
- A coding agent with custom instructions can already play several roles, and a
72
- framework can already wire agents together. What neither gives you:
73
-
74
- - **A system that outlives the session.** Custom instructions and subagents live
75
- in a chat that ends. Here the system is a directory — versioned, reviewable,
76
- diffable, sendable. Improving it is a commit, not a paste.
77
- - **A specification that is enforced, not decorative.** `SPECIFICATION.md` is
78
- the source; where it and the files disagree, it wins. `/sync-with-spec`
79
- reconciles the two in both directions and `zen check` fails the project when
80
- they drift — with a code, a location and a fix per finding. A prose document
81
- nobody checks is a README; this one is checked.
82
- - **No application to build.** Frameworks hand you a library and leave you
83
- owning a program: graph code, state plumbing, retries, transport. Here an
84
- agent is an instruction, a model, tools, skills, who it may hand work to, and
85
- how it fans out. That is the whole list, and it is YAML. There is no glue code
86
- to maintain because there is no glue.
87
- - **A complete record, by default.** Every run writes its input, output and
88
- state, plus a self-contained `report.html` — the graph, every request, every
89
- token, every cost. Not a tracing vendor you sign up for; a file in the folder.
90
- - **Your keys stay yours.** They live in `~/.zenera`, never in the project. What
91
- you share is the system; the recipient runs it on their own credentials and
92
- their own choice of vendor.
75
+ Most tools give you one agent, or a framework and an empty file. This is a
76
+ factory: it designs the system for you, then keeps it honest.
77
+
78
+ - **You state the problem; a meta-agent designs the system.** Specialists,
79
+ prompts, tool grants, hand-offs, where it fans out - all of it drawn from what
80
+ you wrote, and checked before it ever runs.
81
+ - **A self-improving loop, not a one-off build.** Build, run, read the record,
82
+ change what was wrong, run again - and the system can drive that loop on
83
+ itself. Failures come back as findings with a cause and a fix, so the next
84
+ version is written rather than debugged.
85
+ - **It watches itself work.** Every run is recorded against the architecture it
86
+ declared - the agent nobody called, the skill that never fired, where the
87
+ tokens went. Nothing to instrument, nothing to sign up for.
88
+ - **Customisable all the way down.** Live in the specification and never look
89
+ lower. Or set the model, tools and memory of a single agent. Or take the
90
+ kernel itself and manage the trajectory turn by turn. No layer is sealed.
91
+ - **Your documents, searchable.** Hybrid retrieval over your files and your API
92
+ descriptions, plus a memory that is a graph rather than a bucket of rows - so
93
+ what an agent learned in March is still there in September.
94
+ - **Integrations it writes itself.** No MCP server to find, no connector to wait
95
+ for. If it has to reach your ERP, your database or a twenty-year-old SOAP
96
+ endpoint, it writes the call and runs it in a sandbox.
93
97
 
94
98
  ## Install
95
99
 
96
- Node.js 24+. One command — the OpenAI, Anthropic, Google and OpenRouter SDKs
100
+ Node.js 24+. One command - the OpenAI, Anthropic, Google and OpenRouter SDKs
97
101
  all ship with the CLI, so any provider works out of the box.
98
102
 
99
103
  ```sh
@@ -108,19 +112,28 @@ npx @zenera/cli --help
108
112
 
109
113
  ## Quickstart
110
114
 
111
- Four commands, from nothing to an answer:
115
+ From nothing to a specialized agent system:
112
116
 
113
117
  ```sh
114
118
  npm i -g @zenera/cli # every vendor SDK comes with it
115
119
  zen key add openai # asks for the key without showing it; stored in ~/.zenera
116
120
  zen init my-project # scaffolds a project and registers it
117
- zen run my-project "introduce yourself"
121
+ zen open my-project # open the specification and project in your editor
122
+ ```
123
+
124
+ In the editor, describe the job in `SPECIFICATION.md`, then send this in the
125
+ agent chat:
126
+
127
+ ```
128
+ /sync-with-spec
118
129
  ```
119
130
 
120
- The name works from anywhere after that, and the directory you are standing in
121
- is what it works on:
131
+ It creates the specialists, responsibilities, tool access and handoffs the job
132
+ needs. Back in the terminal, validate the generated system and run it against a
133
+ real workspace:
122
134
 
123
135
  ```sh
136
+ zen check my-project
124
137
  cd ~/code/some-repo
125
138
  zen run my-project "summarise this repo and write NOTES.md"
126
139
  ```
@@ -142,9 +155,8 @@ Giving a prompt on the command line skips every question: it starts a fresh
142
155
  session and uses the current directory as the workspace, with write access.
143
156
  `--session`, `--workspace` and `--read-only` override that.
144
157
 
145
- To change what the system does, open the project in your editor with
146
- `zen open`, edit `SPECIFICATION.md` to say what you actually want built, and
147
- send `/sync-with-spec` in the editor's chat. That is the next section.
158
+ To change what the system does, update `SPECIFICATION.md` and send
159
+ `/sync-with-spec` again. The next section explains that workflow in detail.
148
160
 
149
161
  ## You write the specification; a coding agent writes the system
150
162
 
@@ -152,7 +164,7 @@ send `/sync-with-spec` in the editor's chat. That is the next section.
152
164
  implements it. Where the two disagree the specification wins, so a change to
153
165
  what the system does starts there and not in `agents.yaml`.
154
166
 
155
- The one `zen init` writes is not a heading list — it is a true specification of
167
+ The one `zen init` writes is not a heading list - it is a true specification of
156
168
  the project just scaffolded, so you can read it against the files beside it
157
169
  before changing a word:
158
170
 
@@ -166,7 +178,7 @@ nobody to hand work to, because there is no second job to hand on.
166
178
 
167
179
  - The change asked for is in the workspace, or the question is answered from
168
180
  what is actually in it.
169
- - Everything the agent claims a command did, that command actually did — it was
181
+ - Everything the agent claims a command did, that command actually did - it was
170
182
  run, and its output was read.
171
183
  - The reply names what changed, file by file, and says what it deliberately did
172
184
  not do.
@@ -174,7 +186,7 @@ nobody to hand work to, because there is no second job to hand on.
174
186
 
175
187
  ### How you actually edit it
176
188
 
177
- `SPECIFICATION.md` is ordinary Markdown, so any editor will do — but the loop is
189
+ `SPECIFICATION.md` is ordinary Markdown, so any editor will do - but the loop is
178
190
  meant to be driven from a coding agent's chat, and `zen init` installs the
179
191
  prompts that make each step a single command:
180
192
 
@@ -188,14 +200,17 @@ or IntelliJ it can find. `--editor <cmd>` names one outright.
188
200
 
189
201
  In the window that opens:
190
202
 
191
- 1. **Edit `SPECIFICATION.md`** — what the system is for, which agents exist,
203
+ 1. **Edit `SPECIFICATION.md`** - what the system is for, which agents exist,
192
204
  what each may reach for, and what _done_ means.
193
205
  2. **Open the chat panel and send `/sync-with-spec`.** It reads the
194
206
  specification and every file implementing it, works out the difference in
195
207
  both directions, and changes the smallest thing that closes each gap.
196
- 3. **Read `SPECIFICATION-FEEDBACK.md`**, which it writes for anything it could
197
- not do without guessing. Answer its questions by editing `SPECIFICATION.md`
198
- — not by editing prompts — and send `/sync-with-spec` again.
208
+ 3. **Answer `SPECIFICATION-FEEDBACK.md`**, which it writes for anything it could
209
+ not do without guessing. Every question carries two to four written-out
210
+ answers, each with a `[ ]` box: tick one, delete the ones you do not want, or
211
+ write your own in their place.
212
+ 4. **Send `/update-spec-from-feedback`.** It folds the answers you chose into
213
+ `SPECIFICATION.md` - never into a prompt - and then `/sync-with-spec` again.
199
214
 
200
215
  Back in the terminal: `zen check`, then `zen run`.
201
216
 
@@ -204,40 +219,53 @@ Back in the terminal: `zen check`, then `zen run`.
204
219
 
205
220
  They are prompt files under `.github/prompts/`, which VS Code and its forks
206
221
  offer as chat slash-commands. Both `zen init` and `zen open` write them fresh,
207
- so they never go stale — and edits to them do not survive.
222
+ so they never go stale - and edits to them do not survive.
208
223
 
209
- | In chat | Does |
210
- | ----------------- | ----------------------------------------------------------- |
211
- | `/sync-with-spec` | Makes every file match `SPECIFICATION.md`, both directions. |
212
- | `/review-project` | Reads the project as a reviewer would, and reports. |
213
- | `/new-agent` | Adds an agent — prompt, wiring and hand-offs. |
214
- | `/new-skill` | Adds a skill under `agents/skills/`. |
224
+ | In chat | Does |
225
+ | ---------------------------- | ---------------------------------------------------------------- |
226
+ | `/sync-with-spec` | Makes every file match `SPECIFICATION.md`, both directions. |
227
+ | `/update-spec-from-feedback` | Folds your answers in `SPECIFICATION-FEEDBACK.md` into the spec. |
228
+ | `/review-project` | Reads the project as a reviewer would, and reports. |
229
+ | `/new-agent` | Adds an agent - prompt, wiring and hand-offs. |
230
+ | `/new-skill` | Adds a skill under `agents/skills/`. |
215
231
 
216
232
  In an editor that does not support prompt files, paste the contents of
217
- `.github/prompts/sync-with-spec.prompt.md` into its chat instead — it is only a
233
+ `.github/prompts/sync-with-spec.prompt.md` into its chat instead - it is only a
218
234
  prompt. Alongside them, `.github/copilot-instructions.md` is the standing brief
219
235
  that explains this runtime to whatever agent is reading, and
220
236
  `.github/skills/zen-cli/` is the CLI's own reference for it.
221
237
 
222
238
  </details>
223
239
 
224
- ### The loop
240
+ ### The self-improving loop
225
241
 
226
242
  ```
227
- edit SPECIFICATION.md → /sync-with-spec → zen check → scripts/_setup.sh
228
- ↑ ↓
229
- └──────────────── read the report ←──────── zen run ─────┘
243
+ edit SPECIFICATION.md → /sync-with-spec → zen check → zen run
244
+ ↑ ↓
245
+ └───── refine the spec <-──── zen inspect <-───────┘
230
246
  ```
231
247
 
232
- The last turn is the one that matters. When a run comes out wrong, the fix is
233
- the sentence that was missing from the specification; the prompt edit follows
248
+ `zen inspect` makes the record visible: the run trace, timing and token
249
+ statistics, agent architecture, and memory used during the run.
250
+
251
+ ![Run inspection: trace, agent architecture, and memory](https://raw.githubusercontent.com/andreyryabov/ZeneraNeo/main/docs/imgs/0910_480.gif)
252
+
253
+ Every step is a command, and everything each one reads or writes is a plain
254
+ file: the specification, the findings `zen check` prints with a code, a location
255
+ and a fix, the record `zen inspect` renders of what the run actually did. So the
256
+ loop does not need you standing in it. Hand the whole cycle to the agent in your
257
+ editor and it runs on the system it just built - test it, read the failure,
258
+ change the sentence in the specification that caused it, rebuild, run again.
259
+ "Fix my project" is one instruction. (The first time round, `scripts/_setup.sh`
260
+ prepares the container the tools run in.)
261
+
262
+ The last turn is the one that matters. When a run comes out wrong the fix is the
263
+ sentence that was missing from the specification, and the prompt edit follows
234
264
  from that. Prompts patched directly drift away from the document meant to
235
265
  describe them, and a project whose specification is no longer true is a project
236
266
  with no specification.
237
267
 
238
- You are not expected to hand-author any of this. `zen check` is written to be
239
- read by a model as much as by a person — every finding carries a code, a
240
- location and its fix — so "fix my project" is one instruction. Full guide:
268
+ Full guide:
241
269
  [docs/specification.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/specification.md).
242
270
 
243
271
  ## A worked example
@@ -249,7 +277,7 @@ zen init repo-notes && cd repo-notes
249
277
  zen open # opens this folder in your editor
250
278
  ```
251
279
 
252
- Replace `SPECIFICATION.md` with what you want. This is the whole input — no
280
+ Replace `SPECIFICATION.md` with what you want. This is the whole input - no
253
281
  YAML, no prompt files:
254
282
 
255
283
  ```markdown
@@ -261,9 +289,9 @@ Read a codebase and leave a short written note about it in the workspace.
261
289
 
262
290
  ## Agents
263
291
 
264
- - `reader` — explores the workspace and forms a picture of it. May read files
292
+ - `reader` - explores the workspace and forms a picture of it. May read files
265
293
  and list directories, and nothing else. Hands off to `writer`.
266
- - `writer` — turns that picture into `NOTES.md`. May write to the workspace.
294
+ - `writer` - turns that picture into `NOTES.md`. May write to the workspace.
267
295
 
268
296
  ## Done means
269
297
 
@@ -271,7 +299,7 @@ Read a codebase and leave a short written note about it in the workspace.
271
299
  - Every claim in it comes from a file that was actually read.
272
300
  ```
273
301
 
274
- Send `/sync-with-spec` in the editor's chat. It writes `agents.yaml` — who
302
+ Send `/sync-with-spec` in the editor's chat. It writes `agents.yaml` - who
275
303
  exists, and what each may reach for:
276
304
 
277
305
  ```yaml
@@ -292,7 +320,7 @@ agents:
292
320
  handoffs: [reader] # a hand-off does not return by itself; give it a way back
293
321
  ```
294
322
 
295
- — and one prompt file per agent.
323
+ - and one prompt file per agent.
296
324
 
297
325
  <details>
298
326
  <summary>The prompt files it writes</summary>
@@ -320,15 +348,15 @@ lines. Then say where you put it and stop.
320
348
  | Key | Is |
321
349
  | ------------- | --------------------------------------------------------------------- |
322
350
  | `name` | how everything else refers to this agent |
323
- | `description` | what it is for — read by the _other_ agents when deciding to hand off |
351
+ | `description` | what it is for - read by the _other_ agents when deciding to hand off |
324
352
  | `system` | its own brief, in prose, at `agents/prompts/<name>.md` |
325
353
  | `model` | this agent's model; the top-level one otherwise |
326
- | `tools` | what it may reach for — `workspace:*`, `sandbox:*`, a named tool |
354
+ | `tools` | what it may reach for - `workspace:*`, `sandbox:*`, a named tool |
327
355
  | `handoffs` | who it may pass the work to |
328
356
  | `skills` | knowledge pulled in mid-run instead of carried in every prompt |
329
357
 
330
358
  The file is validated strictly at load: an unknown tool, a handoff to nobody, a
331
- missing prompt file — each fails immediately, naming the offending key, rather
359
+ missing prompt file - each fails immediately, naming the offending key, rather
332
360
  than surfacing three turns into a run as a confused model. Full reference:
333
361
  [docs/agents-yaml.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/agents-yaml.md).
334
362
 
@@ -345,29 +373,33 @@ zen inspect --project repo-notes --open # what it actually did
345
373
 
346
374
  That is the end of it: `repo-notes` is now a command like any other, in any
347
375
  directory, for as long as the folder exists. Commit the folder and whoever
348
- clones it types `zen init repo-notes` once — a directory that is already a
349
- project is registered, not rebuilt, and nothing in it is touched — and the name
376
+ clones it types `zen init repo-notes` once - a directory that is already a
377
+ project is registered, not rebuilt, and nothing in it is touched - and the name
350
378
  is a command on their machine too.
351
379
 
352
380
  ## A project is a folder
353
381
 
354
- Prompts, agent wiring, skills and tool selections are all files — Markdown and
355
- YAML — rather than code buried inside an application. So the folder can be
382
+ Prompts, agent wiring, skills and tool selections are all files - Markdown and
383
+ YAML - rather than code buried inside an application. So the folder can be
356
384
  committed, copied to another machine, reviewed in a pull request, and handed to
357
- someone else who runs it with one command. Credentials live in `$HOME`, never in
358
- the project, so there is no secret to strip before sharing it.
385
+ someone else who runs it with one command. Model credentials live in `$HOME`,
386
+ never in the project, and anything the project itself needs goes in a
387
+ git-ignored `.env` - so there is no secret to strip before sharing it.
359
388
 
360
389
  ```
361
390
  my-project/
362
- SPECIFICATION.md what this is for — the intent
363
- INSTRUCTIONS.md house rules, prepended to every agent
391
+ SPECIFICATION.md what this is for - the intent
364
392
  agents.yaml who exists, what they may reach for
365
393
  agents/
394
+ instructions.md house rules, prepended to every agent
395
+ <topic>-instructions.md more of them, one subject at a time
366
396
  prompts/<name>.md each agent's own brief
367
397
  skills/<name>/ knowledge loaded on demand, not always-on
368
398
  assets/ reference material, read-only at /assets
369
399
  sandbox/Dockerfile the container commands run in
370
400
  scripts/_setup.sh the one command that initialises the project
401
+ .spec-sync/ what the last sync with the spec applied
402
+ .env this project's environment - git-ignored
371
403
  sessions/ one workspace, memory and trajectory each
372
404
  <id>/
373
405
  workspace/ what the agents can read and write
@@ -379,29 +411,50 @@ happened when it ran. Nothing here is tied to the machine it was written on,
379
411
  which is the point of the CLI: it makes agentic systems shareable the way
380
412
  repositories are shareable.
381
413
 
382
- `zen init` also writes `.vscode/` and a `.github/` tree — a standing brief that
414
+ `zen init` also writes `.vscode/` and a `.github/` tree - a standing brief that
383
415
  explains this runtime to whatever coding agent you open the folder with, plus
384
416
  the prompts and skills it needs to keep the project matching its specification.
385
417
 
386
418
  ## Concepts
387
419
 
388
- - **Project** — a named directory holding a complete agent definition and the
420
+ - **Project** - a named directory holding a complete agent definition and the
389
421
  sessions that have run against it. It is self-describing: `agents.yaml` is
390
422
  what makes a directory a project, so moving or cloning it loses nothing.
391
- - **Session** — a context that persists across runs: one workspace, one memory,
423
+ - **Session** - a context that persists across runs: one workspace, one memory,
392
424
  one store for large files, and a record of everything that happened, added to
393
425
  as it goes. Resumable.
394
- - **Run** — one prompt in, one answer out, inside a session. Recorded in full,
426
+ - **Run** - one prompt in, one answer out, inside a session. Recorded in full,
395
427
  whether or not you were watching.
396
- - **Workspace** — the directory the agents may read and write. A prompt given on
428
+ - **Workspace** - the directory the agents may read and write. A prompt given on
397
429
  the command line uses the current directory; the TUI offers the session's own
398
430
  empty folder instead, and asks before using anything outside it.
399
- - **Keyring** — `~/.zenera/neo`, readable only by you. See
431
+ - **Keyring** - `~/.zenera/neo`, readable only by you. See
400
432
  [Credentials](#credentials).
401
- - **Cache** — `~/.zenera/neo/cache`, one place for work already done: vectors,
433
+ - **Cache** - `~/.zenera/neo/cache`, one place for work already done: vectors,
402
434
  parses, model listings, generated mocks. Shared by every project on the
403
435
  machine, and never emptied by anything but you. See [Cache](#cache--work-you-have-already-paid-for).
404
436
 
437
+ ## Sandbox commands
438
+
439
+ Agents use an isolated container when a project grants them command-line tools.
440
+ `zen run` prepares it automatically before the first command, but these commands
441
+ make setup, diagnostics and cleanup explicit - useful on a new machine or when
442
+ you want to validate a project's execution environment before a run.
443
+
444
+ ```sh
445
+ zen sandbox status # engine, project image and active containers
446
+ zen sandbox up # prepare the execution environment for this project
447
+ zen sandbox pull # pull or build this project's image only
448
+ zen sandbox status --project my-app # inspect a named project from anywhere
449
+ zen sandbox disk # storage used by the engine and known projects
450
+ zen sandbox clean # remove containers created by zen
451
+ ```
452
+
453
+ `status`, `up` and `pull` use the project in the current directory, or accept
454
+ `--project <name|dir>`. `--image <ref>` selects an image explicitly. `clean` and
455
+ `disk` are machine-wide operations, so use them when you mean to inspect or
456
+ remove resources beyond the current project.
457
+
405
458
  ## Commands
406
459
 
407
460
  | Command | Does |
@@ -409,11 +462,11 @@ the prompts and skills it needs to keep the project matching its specification.
409
462
  | `init` | Creates a project here, or in `<dir>`, and registers it. |
410
463
  | `list` | Every known project: sessions, last run, whether one is live. |
411
464
  | `open` | Opens a project in your editor. |
412
- | `key` | The credential keyring — add, check, switch, remove. |
413
- | `models` | What this machine can use — list, search, test, pick. |
414
- | `run` | Runs the project — the TUI on a terminal, a single answer otherwise. |
465
+ | `key` | The credential keyring - add, check, switch, remove. |
466
+ | `models` | What this machine can use - list, search, test, pick. |
467
+ | `run` | Runs the project - the TUI on a terminal, a single answer otherwise. |
415
468
  | `inspect` | Opens or rebuilds a run's `report.html`. |
416
- | `memory` | What the agents remember — size, listing, one node, or a whole page. |
469
+ | `memory` | What the agents remember - size, listing, one node, or a whole page. |
417
470
  | `check` | Validates the project and every file it names, and asks the models. |
418
471
  | `sandbox` | Checks and prepares the container that command-line tools run in. |
419
472
  | `cache` | What work has been kept, and getting rid of it. |
@@ -433,17 +486,36 @@ an installed one costs nothing until it is used.
433
486
  | `faker` | `@zenera/faker` | A mock API from an openapi/swagger document. |
434
487
  | `rag` | `@zenera/rag` | Search an openapi/swagger document as a graph. |
435
488
 
489
+ **`zen faker`** turns an OpenAPI or Swagger description into a working mock
490
+ server. It generates behavior for each route, checks the result against the
491
+ response contract, and reuses the generated implementation on later requests.
492
+
436
493
  ```sh
437
494
  npm i -g @zenera/faker
438
495
  zen faker serve api/openapi.yaml --port 8787 # a working mock, bodies written by a model
439
496
 
497
+ curl -s localhost:8787/users/12324
498
+ # { "user_id": 12324, "email": "brooke.hoffman@example.org", … }
499
+ ```
500
+
501
+ **`zen rag`** adds advanced retrieval for the knowledge an agent needs to work
502
+ from: documentation and API schemas. Document indexes support semantic,
503
+ full-text and hybrid search with passages returned alongside their source lines.
504
+ Schema indexes add graph-aware retrieval across operations, types, fields,
505
+ requests and responses, so an answer can include the connected API context
506
+ rather than an isolated match.
507
+
508
+ ```sh
440
509
  npm i -g @zenera/rag
441
510
  zen rag schema index --embedding openai:text-embedding-3-small ./specs/*.yaml
442
511
  zen rag schema search --output-property "user billing history" --format ts
512
+
513
+ zen rag docs index ./handbook --embedding openai:text-embedding-3-small
514
+ zen rag docs search "how does failover work when the primary is unreachable"
443
515
  ```
444
516
 
445
- They use this keyring and these credentials, so there is nothing new to
446
- configure. Details:
517
+ Use [@zenera/rag](https://github.com/andreyryabov/ZeneraNeo/blob/main/packages/rag/README.md)
518
+ for its complete retrieval capabilities and examples. Details:
447
519
  [@zenera/faker](https://github.com/andreyryabov/ZeneraNeo/blob/main/packages/faker/README.md)
448
520
  ·
449
521
  [@zenera/rag](https://github.com/andreyryabov/ZeneraNeo/blob/main/packages/rag/README.md).
@@ -455,7 +527,7 @@ The binary is installed under three names: `zen`, `zn` and `zenera`.
455
527
  Global flags: `-h/--help`, `-v/--version`, `--json`, `-C <dir>`.
456
528
 
457
529
  `stdout` carries the answer and `stderr` carries the narration, and `--json`
458
- works on every command — so `zen run … | jq` is a supported way to use this, not
530
+ works on every command - so `zen run … | jq` is a supported way to use this, not
459
531
  an accident.
460
532
 
461
533
  | Exit code | Meaning |
@@ -479,7 +551,7 @@ zen key add <provider> < key.txt # or pipe it in
479
551
 
480
552
  The value is never passed as an argument. A command line is visible to anyone
481
553
  listing running processes, is saved in your shell history and is captured in CI
482
- logs — so the hidden prompt and piping it in are the only two ways.
554
+ logs - so the hidden prompt and piping it in are the only two ways.
483
555
 
484
556
  Entries live in `~/.zenera/neo/keys.json`, in a file only you can read. They are
485
557
  copied into the environment just before a run, which has two consequences worth
@@ -490,14 +562,14 @@ checked out on a machine without `zen` still runs.
490
562
  | ------------ | ------------------------------------- | -------------------------------- |
491
563
  | `openai` | a secret | `OPENAI_API_KEY` |
492
564
  | `anthropic` | a secret | `ANTHROPIC_API_KEY` |
493
- | `google` | a secret — AI Studio | `GEMINI_API_KEY` |
565
+ | `google` | a secret - AI Studio | `GEMINI_API_KEY` |
494
566
  | `vertex` | a path to a service-account JSON file | `GOOGLE_APPLICATION_CREDENTIALS` |
495
567
  | `openrouter` | a secret | `OPENROUTER_API_KEY` |
496
- | `exa` | a secret — for the search tool | `EXA_API_KEY` |
568
+ | `exa` | a secret - for the search tool | `EXA_API_KEY` |
497
569
 
498
570
  `zen key add` verifies the credential against the provider before it finishes,
499
- but stores it either way: a key that cannot be checked right now — offline,
500
- behind a proxy — is not a key that is wrong. `--no-check` skips the call.
571
+ but stores it either way: a key that cannot be checked right now - offline,
572
+ behind a proxy - is not a key that is wrong. `--no-check` skips the call.
501
573
 
502
574
  ### Which key a model uses
503
575
 
@@ -533,12 +605,12 @@ been one does a short built-in list stand in.
533
605
  `zen models test` separates three kinds of failure, because each calls for a
534
606
  different action:
535
607
 
536
- - **refused** — the provider rejected the credential. Fix or replace the key.
537
- - **blocked** — the credential was accepted and the account then said no: an API
608
+ - **refused** - the provider rejected the credential. Fix or replace the key.
609
+ - **blocked** - the credential was accepted and the account then said no: an API
538
610
  switched off, an empty balance, a model this key was never granted. The key is
539
611
  fine; the account needs changing, and the command that changes it is printed
540
612
  with the error.
541
- - **unknown** — the question never arrived (offline, proxy, timeout). Nothing is
613
+ - **unknown** - the question never arrived (offline, proxy, timeout). Nothing is
542
614
  wrong with the key; try again.
543
615
 
544
616
  ```
@@ -559,11 +631,11 @@ zen rag schema index --embedding "$(zen models pick --embedding)" ./specs/*.yaml
559
631
 
560
632
  ### Setting up each provider
561
633
 
562
- The shape is the same everywhere — `zen key add <provider>`, then answer the
634
+ The shape is the same everywhere - `zen key add <provider>`, then answer the
563
635
  prompt. Open the one you need for its specifics.
564
636
 
565
637
  <details>
566
- <summary><strong>OpenAI</strong> — one secret, exported as <code>OPENAI_API_KEY</code></summary>
638
+ <summary><strong>OpenAI</strong> - one secret, exported as <code>OPENAI_API_KEY</code></summary>
567
639
 
568
640
  ```sh
569
641
  zen key add openai
@@ -575,7 +647,7 @@ zen key add openai
575
647
  </details>
576
648
 
577
649
  <details>
578
- <summary><strong>Anthropic</strong> — one secret, exported as <code>ANTHROPIC_API_KEY</code></summary>
650
+ <summary><strong>Anthropic</strong> - one secret, exported as <code>ANTHROPIC_API_KEY</code></summary>
579
651
 
580
652
  ```sh
581
653
  zen key add anthropic
@@ -585,7 +657,7 @@ zen run --model anthropic:claude-sonnet-4-5 "summarise this repo"
585
657
  </details>
586
658
 
587
659
  <details>
588
- <summary><strong>OpenRouter</strong> — one secret, exported as <code>OPENROUTER_API_KEY</code></summary>
660
+ <summary><strong>OpenRouter</strong> - one secret, exported as <code>OPENROUTER_API_KEY</code></summary>
589
661
 
590
662
  One credential for many vendors' models. The model id keeps its own vendor
591
663
  prefix, after the `openrouter:` one:
@@ -599,7 +671,7 @@ zen run --model openrouter:anthropic/claude-haiku-4.5 "summarise this repo"
599
671
  </details>
600
672
 
601
673
  <details>
602
- <summary><strong>Google AI Studio</strong> — one secret, exported as <code>GEMINI_API_KEY</code></summary>
674
+ <summary><strong>Google AI Studio</strong> - one secret, exported as <code>GEMINI_API_KEY</code></summary>
603
675
 
604
676
  One key and nothing else to configure: the shortest way to a working Gemini
605
677
  model.
@@ -610,7 +682,7 @@ zen check # google:gemini-3.5-flash now resolves
610
682
  ```
611
683
 
612
684
  The same Gemini models are also served by Vertex AI, under a different
613
- credential. Both can be configured at once — they are separate entries for
685
+ credential. Both can be configured at once - they are separate entries for
614
686
  separate services, and the prefix on the model reference decides which is used:
615
687
 
616
688
  ```sh
@@ -621,12 +693,12 @@ zen run --model vertex:gemini-3.5-flash "summarise this repo"
621
693
  </details>
622
694
 
623
695
  <details>
624
- <summary><strong>Vertex AI</strong> — a service-account file, or an express-mode key</summary>
696
+ <summary><strong>Vertex AI</strong> - a service-account file, or an express-mode key</summary>
625
697
 
626
698
  Vertex accepts two kinds of credential, and you never declare which one you are
627
699
  giving: if the value is a path to a file that exists it is treated as a
628
700
  service-account key, otherwise as an API key. The name you give the entry has no
629
- bearing on this — `vertex/express` is just an entry called `express`, exactly as
701
+ bearing on this - `vertex/express` is just an entry called `express`, exactly as
630
702
  `vertex/prod` is one called `prod`, and either name can hold either kind.
631
703
 
632
704
  **A service-account JSON file** is the usual one, and what production normally
@@ -638,7 +710,7 @@ zen key add vertex --gcp-location us-central1
638
710
  # Paste the key, or a path to the file: /Users/you/keys/vertex-sa.json
639
711
  ```
640
712
 
641
- The prompt is read by `zen`, not by your shell, so give a full path there — `~`
713
+ The prompt is read by `zen`, not by your shell, so give a full path there - `~`
642
714
  is not expanded. In a script, pipe the path in instead:
643
715
 
644
716
  ```sh
@@ -657,7 +729,7 @@ moving or cleaning up the original later cannot break it.
657
729
  - Which models a location serves varies per model and is not guessable. In one
658
730
  project, `gemini-embedding-2` answered at `us` but 404'd at `us-central1`,
659
731
  while `gemini-2.5-flash` did the opposite. New models often reach `global`,
660
- `us` and `eu` first. `zen models test vertex:<model>` is what settles it —
732
+ `us` and `eu` first. `zen models test vertex:<model>` is what settles it -
661
733
  `zen key add` only establishes that the credential itself works.
662
734
  - `--gcp-project <id>` is only needed when the `project_id` inside the file is
663
735
  not the project you want to bill:
@@ -686,7 +758,7 @@ keyring, so it is always visible which credential a run will actually use.
686
758
  </details>
687
759
 
688
760
  <details>
689
- <summary><strong>Exa</strong> — one secret, exported as <code>EXA_API_KEY</code></summary>
761
+ <summary><strong>Exa</strong> - one secret, exported as <code>EXA_API_KEY</code></summary>
690
762
 
691
763
  Not a model provider: this is what backs the search tool an agent reaches for
692
764
  when it has to look something up on the web.
@@ -706,7 +778,7 @@ Entries are named, so a provider can hold several, one of which is active:
706
778
  zen key add openai/work # a second entry
707
779
  zen key use openai/work # the one that runs will use
708
780
  zen key ls --check # everything stored, and whether it still works
709
- zen key show vertex/default # masked — --reveal prints the secret
781
+ zen key show vertex/default # masked - --reveal prints the secret
710
782
  zen key env openai # shell exports, for other tools
711
783
  zen key rm openai/work
712
784
  ```
@@ -722,12 +794,12 @@ zen key use vertex/dev # which one the next run uses
722
794
  ```
723
795
 
724
796
  `zen key ls` marks the active entry with `*`, and anything it found outside the
725
- keyring — in your environment, or in a `gcloud` login — with `~`, so it is always
797
+ keyring - in your environment, or in a `gcloud` login - with `~`, so it is always
726
798
  clear where a working provider actually comes from.
727
799
 
728
800
  </details>
729
801
 
730
- ## Cache — work you have already paid for
802
+ ## Cache - work you have already paid for
731
803
 
732
804
  Embedding a paragraph, parsing a document, asking a provider what it serves: all
733
805
  of these are slow or costly, and all of them give the same answer every time. So
@@ -756,7 +828,7 @@ time.
756
828
  ## The library underneath
757
829
 
758
830
  This is a shell over
759
- [`@zenera/neo`](https://www.npmjs.com/package/@zenera/neo) — agents, models,
831
+ [`@zenera/neo`](https://www.npmjs.com/package/@zenera/neo) - agents, models,
760
832
  tools, skills, memory and a running record of everything that happened. Use it
761
833
  directly when you want the runtime inside your own application rather than on a
762
834
  terminal:
@@ -765,19 +837,19 @@ terminal:
765
837
  ## Documentation
766
838
 
767
839
  - [docs/specification.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/specification.md)
768
- — writing the specification the project implements.
840
+ - writing the specification the project implements.
769
841
  - [docs/projects.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/projects.md)
770
- — what the project folder contains, file by file.
842
+ - what the project folder contains, file by file.
771
843
  - [docs/agents-yaml.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/agents-yaml.md)
772
- — every key in the configuration file.
844
+ - every key in the configuration file.
773
845
  - [docs/knowledge.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/knowledge.md)
774
- — building a searchable document index.
846
+ - building a searchable document index.
775
847
  - [docs/integrations.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/integrations.md)
776
- — making an API description searchable and mockable.
848
+ - making an API description searchable and mockable.
777
849
  - [docs/memory.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/memory.md)
778
- — what agents keep between sessions.
850
+ - what agents keep between sessions.
779
851
 
780
852
  ## License
781
853
 
782
- Early days and moving fast — issues, questions and pull requests are welcome.
854
+ Early days and moving fast - issues, questions and pull requests are welcome.
783
855
  [MIT](LICENSE).