@zenera/cli 1.1.10 → 1.1.12
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 +69 -15
- package/dist/banner.js +69 -47
- package/dist/cache.d.ts +98 -0
- package/dist/cache.js +301 -0
- package/dist/catalog.d.ts +3 -0
- package/dist/catalog.js +35 -11
- package/dist/commands/cache.d.ts +7 -0
- package/dist/commands/cache.js +245 -0
- package/dist/commands/check.js +6 -3
- package/dist/commands/index.js +5 -0
- package/dist/commands/init.js +8 -4
- package/dist/commands/key.js +68 -14
- package/dist/commands/memory.d.ts +3 -0
- package/dist/commands/memory.js +375 -0
- package/dist/commands/models.js +17 -1
- package/dist/commands/run.js +11 -3
- package/dist/commands/sandbox.js +70 -23
- package/dist/engine.js +14 -9
- package/dist/home.d.ts +2 -2
- package/dist/home.js +2 -2
- package/dist/keys.d.ts +22 -0
- package/dist/keys.js +105 -2
- package/dist/lib.d.ts +1 -0
- package/dist/lib.js +1 -0
- package/dist/liveness.js +11 -0
- package/dist/main.js +9 -0
- package/dist/podman.js +43 -9
- package/dist/projects.js +10 -2
- package/dist/resolve.d.ts +4 -0
- package/dist/resolve.js +43 -17
- package/dist/scaffold.js +22 -1
- package/dist/term.d.ts +23 -2
- package/dist/term.js +215 -8
- package/dist/tui/app.d.ts +10 -0
- package/dist/tui/app.js +478 -54
- package/dist/tui/theme.d.ts +13 -2
- package/dist/tui/theme.js +26 -13
- package/dist/tui/wrap.d.ts +92 -0
- package/dist/tui/wrap.js +147 -2
- package/dist/validate.d.ts +2 -0
- package/dist/validate.js +87 -2
- package/package.json +2 -2
- package/templates/editor/.github/copilot-instructions.md +200 -55
- package/templates/editor/.github/prompts/new-agent.prompt.md +5 -2
- package/templates/editor/.github/prompts/review-project.prompt.md +5 -0
- package/templates/editor/.github/prompts/sync-with-spec.prompt.md +11 -4
- package/templates/editor/.github/skills/zen-cli/SKILL.md +3 -0
- package/templates/editor/.github/skills/zen-cli/references/faker.md +18 -8
- package/templates/editor/.github/skills/zen-cli/references/keys.md +7 -7
- package/templates/editor/.github/skills/zen-cli/references/memory.md +113 -0
- package/templates/editor/.github/skills/zen-cli/references/rag.md +2 -2
- package/templates/editor/.github/skills/zen-cli/references/run.md +3 -1
- package/templates/editor/.github/skills/zen-memory/SKILL.md +555 -0
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +575 -0
- package/templates/editor/.github/skills/{api-schema-index → zen-rag-schema}/SKILL.md +4 -4
- package/templates/editor/.vscode/settings.json +4 -2
- package/templates/parts/exa.prompt.md.tmpl +4 -0
- package/templates/parts/exa.spec.md.tmpl +2 -0
- package/templates/project/INSTRUCTIONS.md +8 -0
- package/templates/project/SPECIFICATION.md.tmpl +47 -0
- package/templates/project/agents/prompts/{default.md → default.md.tmpl} +4 -0
- package/templates/project/agents.yaml.tmpl +4 -0
- package/templates/project/gitignore +7 -1
- package/templates/project/scripts/_setup.sh +101 -0
- package/templates/project/SPECIFICATION.md +0 -6
|
@@ -141,8 +141,9 @@ my-project/
|
|
|
141
141
|
│ ├── SKILL.md
|
|
142
142
|
│ └── scripts/calculate.py run at /skills/refund_policy/scripts — §3.4.1
|
|
143
143
|
├── assets/ reference material, read-only at /assets
|
|
144
|
+
├── memory/ the graph agents remember into — §5.3
|
|
144
145
|
├── sandbox/Dockerfile the image commands run in — §3.7
|
|
145
|
-
└── sessions/ run state,
|
|
146
|
+
└── sessions/ run state, whatever the agent wrote
|
|
146
147
|
```
|
|
147
148
|
|
|
148
149
|
Only `agents.yaml` is required, and only `agents:` is required inside it.
|
|
@@ -224,6 +225,81 @@ agents do, for the same reason — it is a prefix somebody pays for:
|
|
|
224
225
|
hand, so **edits inside `.github/` do not survive**. Project-specific conventions
|
|
225
226
|
belong in `INSTRUCTIONS.md` and the agent prompts, which are never overwritten.
|
|
226
227
|
|
|
228
|
+
### 2.5 What a running agent can actually see
|
|
229
|
+
|
|
230
|
+
The tree in §2.1 is the **author's** view. A running agent sees almost none of
|
|
231
|
+
it. Its entire world is the tools it was granted (§3.5) and four paths:
|
|
232
|
+
|
|
233
|
+
| Path | Is | Access |
|
|
234
|
+
| ------------ | ----------------------------------------- | ------------------------------------------------------ |
|
|
235
|
+
| `/workspace` | the session's workspace — the work itself | read/write; `zen run --read-only` withholds the writes |
|
|
236
|
+
| `/assets` | `assets/`, reference material — §3.11 | read-only |
|
|
237
|
+
| `/skills` | the whole skill catalog — §3.4.1 | read-only |
|
|
238
|
+
| `/memory` | files carried by remembered nodes — §5.3 | read-only, and only when `memory:` is configured |
|
|
239
|
+
|
|
240
|
+
Commands run inside the container `sandbox:` describes (§3.7): the same
|
|
241
|
+
`/workspace`, and whatever the image ships.
|
|
242
|
+
|
|
243
|
+
Everything else in the project directory is **invisible at run time** —
|
|
244
|
+
`agents.yaml`, `INSTRUCTIONS.md`, `agents/prompts/`, `agents/skills/` under that
|
|
245
|
+
name, `sandbox/Dockerfile`, `.env`, `.github/`, `sessions/`, and the project
|
|
246
|
+
root itself. `zen` reads them to build the run; they are never a path an agent
|
|
247
|
+
can open.
|
|
248
|
+
|
|
249
|
+
Two consequences:
|
|
250
|
+
|
|
251
|
+
- **The workspace is not the project.** It defaults to the session's own empty
|
|
252
|
+
folder, and is usually some other repository entirely — `--workspace`, or the
|
|
253
|
+
directory the user was standing in. A prompt saying "read `agents.yaml`" or
|
|
254
|
+
"the rules are in `agents/skills/`" names a file that is not there.
|
|
255
|
+
- **Write the mount path, never the repository path.**
|
|
256
|
+
`/skills/refund_policy/rates.csv`, not
|
|
257
|
+
`agents/skills/refund_policy/rates.csv`; `/assets/handbook.md`, not
|
|
258
|
+
`assets/handbook.md`. A relative path resolves against `/workspace`, which is
|
|
259
|
+
the one place the file is not.
|
|
260
|
+
|
|
261
|
+
An agent that must know something about its own configuration is **told it in
|
|
262
|
+
prose**, in the prompt — never sent to read the file that configured it.
|
|
263
|
+
|
|
264
|
+
#### Checklist — no path an agent cannot open
|
|
265
|
+
|
|
266
|
+
Run this over `INSTRUCTIONS.md`, every `agents/prompts/*.md` and every
|
|
267
|
+
`agents/skills/*/SKILL.md` after editing any of them. Every path-shaped token in
|
|
268
|
+
those files is read by a model as an instruction to open something:
|
|
269
|
+
|
|
270
|
+
- [ ] Every absolute path begins `/workspace`, `/assets`, `/skills` or
|
|
271
|
+
`/memory`. Nothing else exists.
|
|
272
|
+
- [ ] No project file is named: `agents.yaml`, `INSTRUCTIONS.md`,
|
|
273
|
+
`agents/prompts/…`, `agents/skills/…`, `sandbox/Dockerfile`, `.env`,
|
|
274
|
+
`.github/…`, `sessions/…`, `SPECIFICATION.md`, `README.md`, `docs/…`.
|
|
275
|
+
- [ ] Nothing escapes a mount: no `../`, no `~`, no host path (`/Users/…`,
|
|
276
|
+
`/home/<someone>`), no `/etc`, `/var` or `/tmp` expected to hold anything
|
|
277
|
+
the project put there.
|
|
278
|
+
- [ ] Each `/assets/…` and `/skills/<name>/…` path names a file that is actually
|
|
279
|
+
committed there — `zen check` lists what every skill folder ships (§3.4.1).
|
|
280
|
+
- [ ] A skill referring to its own sibling file writes the full
|
|
281
|
+
`/skills/<name>/` prefix, not `./rates.csv`: the body is rendered into a
|
|
282
|
+
prompt, not executed from its folder.
|
|
283
|
+
- [ ] `/memory` is named only in prompts for agents that have `memory:` (§5.3),
|
|
284
|
+
and `/assets` only where an `assets/` directory exists.
|
|
285
|
+
- [ ] The agent holding the prompt has the tool the path implies — `read_file`
|
|
286
|
+
to open one, `sandbox:*` to run one (§3.4.1).
|
|
287
|
+
- [ ] Every instruction that opens a file states what to do when it is not there
|
|
288
|
+
(§4.2, rule 6). Workspaces differ between runs; absence is normal.
|
|
289
|
+
- [ ] Relative paths appear only where `/workspace`-relative is what was meant.
|
|
290
|
+
|
|
291
|
+
Finding the candidates, from the project root — every path-shaped token in the
|
|
292
|
+
three trees, minus the ones under a mount:
|
|
293
|
+
|
|
294
|
+
```sh
|
|
295
|
+
grep -Eohr '[~.]?/?[A-Za-z0-9_.-]*/[A-Za-z0-9_.*-]+' \
|
|
296
|
+
INSTRUCTIONS.md agents/prompts agents/skills \
|
|
297
|
+
| sort -u | grep -Ev '^/(workspace|assets|skills|memory)(/|$)'
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Everything it prints is either a false positive (a url, a `path/to` in a
|
|
301
|
+
sentence, `and/or`) or a path the agent cannot open. There is no third case.
|
|
302
|
+
|
|
227
303
|
---
|
|
228
304
|
|
|
229
305
|
## 3. File formats
|
|
@@ -307,6 +383,9 @@ wrong provider (§7.3), and any combination of knobs the vendor rejects at reque
|
|
|
307
383
|
time, such as OpenAI reasoning on chat completions (§7.6). Both surface on the
|
|
308
384
|
first call, so read §7 before writing a `models:` entry.
|
|
309
385
|
|
|
386
|
+
**Caught by `zen check`, not by the loader** — a handoff with no path back
|
|
387
|
+
(`handoff.one-way`, §6.3). The project runs; it just cannot return.
|
|
388
|
+
|
|
310
389
|
**Comments in `agents.yaml`** — this file is the architecture diagram of the
|
|
311
390
|
project, and its comments are read by whoever has to change it next. Write them
|
|
312
391
|
at that level:
|
|
@@ -1028,22 +1107,38 @@ agents:
|
|
|
1028
1107
|
|
|
1029
1108
|
### 5.3 Memory
|
|
1030
1109
|
|
|
1031
|
-
Memory is the read-write twin of skills: written by the run, not authored.
|
|
1032
|
-
**
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
are injected before each call, which is what makes memory work without the
|
|
1036
|
-
model remembering to look, and an agent with write access also gets tools to
|
|
1037
|
-
search, add, update and delete entries.
|
|
1110
|
+
Memory is the read-write twin of skills: written by the run, not authored. It is
|
|
1111
|
+
a **graph** — a node is one thing worth keeping, an edge says how one led to
|
|
1112
|
+
another — so recall returns the connected piece rather than a ranked list, and a
|
|
1113
|
+
remembered script arrives with the request that asked for it.
|
|
1038
1114
|
|
|
1039
|
-
It is
|
|
1040
|
-
|
|
1041
|
-
|
|
1115
|
+
It is configured in `agents.yaml`: a top-level `memory:` block says where the
|
|
1116
|
+
graph lives and what vectorises it, and `agents[].memory` says what each agent
|
|
1117
|
+
may do with it. It lives with the **project**, not the session — a memory that
|
|
1118
|
+
died with the session would be a cache. Recall is automatic on turns that follow
|
|
1119
|
+
new user input, which is what makes memory work without the model remembering to
|
|
1120
|
+
look.
|
|
1121
|
+
|
|
1122
|
+
```yaml
|
|
1123
|
+
memory:
|
|
1124
|
+
embedding: main # without one, recall falls back to term overlap
|
|
1125
|
+
agents:
|
|
1126
|
+
- name: auditor
|
|
1127
|
+
memory: true # read, write, and recall before each new question
|
|
1128
|
+
```
|
|
1129
|
+
|
|
1130
|
+
Every node carries an **audience**, and an agent's `sees` is the set it reads:
|
|
1131
|
+
one graph, masked per agent, never one graph each. The four `memory_*` tools are
|
|
1132
|
+
derived from `access` and are never listed in `tools:`.
|
|
1042
1133
|
|
|
1043
1134
|
Do not treat memory as a database. It is for things learned that should
|
|
1044
1135
|
persist. Anything authoritative — a rate, a policy clause, a procedure — belongs
|
|
1045
1136
|
in a skill, where it is versioned and reviewable.
|
|
1046
1137
|
|
|
1138
|
+
The full treatment — kinds and relations, how ranking and stitching spend their
|
|
1139
|
+
budget, remembered files under `/memory`, audience design, and how to put memory
|
|
1140
|
+
in front of a `zen rag` index — is in the `zen-memory` skill.
|
|
1141
|
+
|
|
1047
1142
|
### 5.4 Cache discipline
|
|
1048
1143
|
|
|
1049
1144
|
Rules that follow directly from "stable prefix = cache hit":
|
|
@@ -1086,18 +1181,20 @@ Do **not** split because:
|
|
|
1086
1181
|
|
|
1087
1182
|
**Router + specialists.** A cheap, fast agent whose only job is classification
|
|
1088
1183
|
and handoff. Its prompt is short, it holds few tools, and it must be forbidden
|
|
1089
|
-
from answering.
|
|
1184
|
+
from answering. Every specialist hands back to it — a handoff does not return on
|
|
1185
|
+
its own, so without that edge the first routed question is the last one routed.
|
|
1090
1186
|
|
|
1091
1187
|
```yaml
|
|
1092
1188
|
agents:
|
|
1093
1189
|
- { name: intake, model: router, handoffs: [billing, technical, escalation] }
|
|
1094
|
-
- { name: billing, model: balanced, skills: { allow: [refund_policy
|
|
1095
|
-
- { name: technical, model: balanced, tools: [search_logs
|
|
1096
|
-
- { name: escalation, model: careful }
|
|
1190
|
+
- { name: billing, model: balanced, handoffs: [intake], skills: { allow: [refund_policy] } }
|
|
1191
|
+
- { name: technical, model: balanced, handoffs: [intake], tools: [search_logs] }
|
|
1192
|
+
- { name: escalation, model: careful, handoffs: [intake] }
|
|
1097
1193
|
```
|
|
1098
1194
|
|
|
1099
1195
|
**Pipeline.** Fixed stages, each handing to the next; only the last answers the
|
|
1100
|
-
user. Encode the order in `handoffs:` so a stage cannot skip ahead
|
|
1196
|
+
user. Encode the order in `handoffs:` so a stage cannot skip ahead — and close
|
|
1197
|
+
the loop, by handing back from the last stage to the first.
|
|
1101
1198
|
|
|
1102
1199
|
**Fan-out / join.** For independent parallel work — ten regions, four review
|
|
1103
1200
|
lenses, six candidate suppliers — declare `fork:` on the agent that owns the
|
|
@@ -1113,12 +1210,39 @@ multi-agent instinct suggests.
|
|
|
1113
1210
|
Write it as a routing condition: _"Applies the written peril policies to a
|
|
1114
1211
|
claim and explains the outcome."_ — not _"The adjuster agent."_
|
|
1115
1212
|
- Handoffs are bare name strings; there is no per-edge configuration.
|
|
1116
|
-
- Self-handoff is a load error.
|
|
1117
|
-
|
|
1213
|
+
- Self-handoff is a load error.
|
|
1214
|
+
- **Every handoff must be returnable.** For every `A → B` there must be a path
|
|
1215
|
+
from `B` back to `A`. Indirect counts — `B → C → A` is a way home — so the
|
|
1216
|
+
rule is that every handoff edge lies on a cycle. `zen check` warns
|
|
1217
|
+
(`handoff.one-way`) on any edge that does not.
|
|
1118
1218
|
- Handoff collapses history by policy: the receiving agent sees a selection, not
|
|
1119
1219
|
the full transcript. Do not assume it saw a detail three turns back; if it
|
|
1120
1220
|
matters, put it in the handoff.
|
|
1121
1221
|
|
|
1222
|
+
**Why the return edge is not optional.** A handoff is a one-way door: control
|
|
1223
|
+
moves and stays moved. Nothing hands it back, so an agent reached by a dead-end
|
|
1224
|
+
edge owns the conversation for the rest of the session — the next question,
|
|
1225
|
+
whatever it is about, is answered by the specialist the router sent the user to.
|
|
1226
|
+
The drawn architecture holds for one turn and then quietly stops being the
|
|
1227
|
+
architecture.
|
|
1228
|
+
|
|
1229
|
+
**Forks are the exception, and the alternative.** A branch runs, answers, and
|
|
1230
|
+
control returns to the agent that forked it; the return is the mechanism, not an
|
|
1231
|
+
edge anyone has to declare. So there are two shapes and they are not
|
|
1232
|
+
interchangeable:
|
|
1233
|
+
|
|
1234
|
+
- The other agent should **own the conversation from here** → `handoffs:`, and
|
|
1235
|
+
something on the far side has to lead back.
|
|
1236
|
+
- This agent needs **an answer and then carries on** → `fork:`. Never a handoff:
|
|
1237
|
+
a handoff spends the conversation to get the answer.
|
|
1238
|
+
|
|
1239
|
+
But the return is **condensed**: `A → fork → B` rejoins as one tool result
|
|
1240
|
+
holding B's answer, so A never sees the steps B took — no tool calls, no files
|
|
1241
|
+
read, no intermediate reasoning. That is what makes fanning out cheap, and it is
|
|
1242
|
+
what to design around: whatever A will need must be _in_ the answer, so say so in
|
|
1243
|
+
B's prompt. Work whose value is the trace rather than the conclusion does not
|
|
1244
|
+
survive a fork.
|
|
1245
|
+
|
|
1122
1246
|
### 6.4 Forking (fan-out / join)
|
|
1123
1247
|
|
|
1124
1248
|
Forking is **opt-in per agent**. Without the key the agent is never offered the
|
|
@@ -1158,7 +1282,9 @@ Rules worth knowing before you write the key:
|
|
|
1158
1282
|
- Nesting is capped by the run's `maxForkDepth` (2 by default), so a branch may
|
|
1159
1283
|
fork again but not without bound.
|
|
1160
1284
|
- Fork vs handoff: a handoff is _one_ conversation changing owner; a fork is the
|
|
1161
|
-
_same_ question asked N times at once and merged.
|
|
1285
|
+
_same_ question asked N times at once and merged. **A fork returns; a handoff
|
|
1286
|
+
does not** — which is why a handoff needs a return path (§6.3) and a fork
|
|
1287
|
+
needs nothing.
|
|
1162
1288
|
|
|
1163
1289
|
Choose `context:` deliberately — the model sets it per call, so say in the
|
|
1164
1290
|
agent's prompt which one this work wants:
|
|
@@ -1237,8 +1363,8 @@ model: balanced # fallback for agents that do not pin their own
|
|
|
1237
1363
|
|
|
1238
1364
|
agents:
|
|
1239
1365
|
- { name: intake, model: router, handoffs: [adjuster] }
|
|
1240
|
-
- { name: adjuster, model: balanced, handoffs: [escalation] }
|
|
1241
|
-
- { name: escalation, model: careful }
|
|
1366
|
+
- { name: adjuster, model: balanced, handoffs: [escalation, intake] }
|
|
1367
|
+
- { name: escalation, model: careful, handoffs: [intake] }
|
|
1242
1368
|
```
|
|
1243
1369
|
|
|
1244
1370
|
### 7.3 Shorthand
|
|
@@ -1567,9 +1693,9 @@ zen models pick --embedding # or --chat; the ref goes to stdout, alone
|
|
|
1567
1693
|
Then re-run `zen check`.
|
|
1568
1694
|
|
|
1569
1695
|
CLI (`zen --help` for the authoritative list): `zen init`, `zen run`, `zen check`,
|
|
1570
|
-
`zen inspect`, `zen key`, `zen models`, `zen list`. **stdout is the
|
|
1571
|
-
is the narration**; every command takes `--json`. Exit codes: `0`
|
|
1572
|
-
`2` usage, `3` invalid project, `4` no usable credential.
|
|
1696
|
+
`zen inspect`, `zen memory`, `zen key`, `zen models`, `zen list`. **stdout is the
|
|
1697
|
+
answer, stderr is the narration**; every command takes `--json`. Exit codes: `0`
|
|
1698
|
+
ok, `1` failed, `2` usage, `3` invalid project, `4` no usable credential.
|
|
1573
1699
|
|
|
1574
1700
|
---
|
|
1575
1701
|
|
|
@@ -1582,7 +1708,7 @@ Before finishing any change here:
|
|
|
1582
1708
|
- [ ] `agents.yaml` still loads; no unknown keys, no dangling names
|
|
1583
1709
|
- [ ] Top-level `default:` names the entry agent explicitly
|
|
1584
1710
|
- [ ] Every agent has a `description:` written as a routing condition
|
|
1585
|
-
- [ ] No self-handoff;
|
|
1711
|
+
- [ ] No self-handoff; every handoff has a path back (`zen check` warns if not)
|
|
1586
1712
|
- [ ] Names match `^[a-z0-9]+(?:[-_][a-z0-9]+)*$`
|
|
1587
1713
|
- [ ] An agent expected to fan out has `fork:`, and its prompt says when to use it
|
|
1588
1714
|
- [ ] Comments explain the design, not the runtime or the key they sit above
|
|
@@ -1596,6 +1722,16 @@ Before finishing any change here:
|
|
|
1596
1722
|
- [ ] No facts, rates or figures embedded in a prompt
|
|
1597
1723
|
- [ ] No hedging, no meta-talk about the runtime
|
|
1598
1724
|
|
|
1725
|
+
**Paths (§2.5 — run its checklist over the three trees)**
|
|
1726
|
+
|
|
1727
|
+
- [ ] Every absolute path in `INSTRUCTIONS.md`, `agents/prompts/*.md` and
|
|
1728
|
+
`agents/skills/*/SKILL.md` is under `/workspace`, `/assets`, `/skills` or
|
|
1729
|
+
`/memory`
|
|
1730
|
+
- [ ] No prompt or skill names a project file — `agents.yaml`, a prompt path, a
|
|
1731
|
+
skill's repository path, `sandbox/Dockerfile`, `.env`, `sessions/`
|
|
1732
|
+
- [ ] No `../`, `~`, or host path; nothing assumes the workspace is the project
|
|
1733
|
+
- [ ] Every `/assets/…` and `/skills/<name>/…` path names a committed file
|
|
1734
|
+
|
|
1599
1735
|
**Skills**
|
|
1600
1736
|
|
|
1601
1737
|
- [ ] Every skill is `<name>/SKILL.md` — no bare `<name>.md` in the catalog
|
|
@@ -1640,34 +1776,37 @@ Before finishing any change here:
|
|
|
1640
1776
|
|
|
1641
1777
|
## 10. Where to change what
|
|
1642
1778
|
|
|
1643
|
-
| Symptom
|
|
1644
|
-
|
|
|
1645
|
-
| Wrong tone, wrong format, wrong length
|
|
1646
|
-
| Says something forbidden
|
|
1647
|
-
| Ignores a rule that only applies sometimes
|
|
1648
|
-
| Never loads the skill it should
|
|
1649
|
-
| Loads too much, answers slowly
|
|
1650
|
-
| Invents a number
|
|
1651
|
-
| A skill in the catalog is never offered
|
|
1652
|
-
| Cannot find a file its own skill names
|
|
1653
|
-
|
|
|
1654
|
-
|
|
|
1655
|
-
|
|
|
1656
|
-
|
|
|
1657
|
-
|
|
|
1658
|
-
|
|
|
1659
|
-
|
|
|
1660
|
-
|
|
|
1661
|
-
|
|
|
1662
|
-
|
|
|
1663
|
-
|
|
|
1664
|
-
|
|
|
1665
|
-
|
|
|
1666
|
-
|
|
|
1667
|
-
|
|
|
1668
|
-
|
|
|
1669
|
-
|
|
|
1670
|
-
|
|
|
1779
|
+
| Symptom | Change this |
|
|
1780
|
+
| --------------------------------------------- | ------------------------------------------------------------------- |
|
|
1781
|
+
| Wrong tone, wrong format, wrong length | `INSTRUCTIONS.md` (all agents) or the agent prompt |
|
|
1782
|
+
| Says something forbidden | `INSTRUCTIONS.md` prohibition, stated specifically |
|
|
1783
|
+
| Ignores a rule that only applies sometimes | Move the rule into a skill with a sharp description |
|
|
1784
|
+
| Never loads the skill it should | The skill's `description`; or `preload` it |
|
|
1785
|
+
| Loads too much, answers slowly | `allow:`, `maxIndexEntries:`, or `discovery: search` |
|
|
1786
|
+
| Invents a number | A skill holding the figure, or a script that computes it — §3.4.1 |
|
|
1787
|
+
| A skill in the catalog is never offered | It is a bare `<name>.md`; move it to `<name>/SKILL.md` — §3.4 |
|
|
1788
|
+
| Cannot find a file its own skill names | Absolute `/skills/<name>/…` path, and `sandbox:*` — §3.4.1 |
|
|
1789
|
+
| Tries to open `agents.yaml` or its own prompt | The prompt names a file no agent can see — §2.5 |
|
|
1790
|
+
| Says a file is missing that is in the project | The workspace is not the project directory — §2.5 |
|
|
1791
|
+
| Rewrites a whole file to change one line | A prompt line preferring `apply_patch` — §3.6 |
|
|
1792
|
+
| Edits files it should only be reading | Subtract the mutating tools, or `zen run --read-only` |
|
|
1793
|
+
| Cannot run the build or the tests | Grant `sandbox:*`; add the toolchain to `sandbox/Dockerfile` |
|
|
1794
|
+
| Installs the same packages on every run | Put them in `sandbox/Dockerfile`, or `sandbox.persist: true` — §3.7 |
|
|
1795
|
+
| Answers from stale knowledge of the world | Grant `web_search` + `web_read`, and say when — §3.8 |
|
|
1796
|
+
| Cites a page it only saw the excerpt of | A prompt line: `web_read` before quoting — §3.8 |
|
|
1797
|
+
| Every web call refuses | No Exa key: `zen key add exa` — `zen check` warns — §3.8 |
|
|
1798
|
+
| A model or embedder refuses every call | `zen models test <ref>` — if `blocked`, `zen models pick` — §8 |
|
|
1799
|
+
| Answers instead of routing | Router prompt prohibition; check `handoffs:` |
|
|
1800
|
+
| Routes to the wrong specialist | The target agents' `description:` fields |
|
|
1801
|
+
| Gets stuck in the agent it routed to | The target needs a handoff back — §6.3 |
|
|
1802
|
+
| Loses a detail after a handoff | Say it in the handoff; check the collapse policy |
|
|
1803
|
+
| Works through N independent items serially | `fork:` on that agent, and a prompt line — §6.4 |
|
|
1804
|
+
| Forks when the steps actually depend | Prompt line: branches cannot see each other |
|
|
1805
|
+
| Slow and expensive on trivial cases | Demote that agent's model tier / reasoning effort |
|
|
1806
|
+
| Fails only on genuinely hard cases | Promote that agent's tier, or split the hard path out |
|
|
1807
|
+
| Shows no reasoning while it works | Turn summaries on for that model — §7.6 |
|
|
1808
|
+
| Forgets across conversations | Continue the session rather than starting a new one |
|
|
1809
|
+
| Breaks at load with a named path | Read the message — it names the exact key |
|
|
1671
1810
|
|
|
1672
1811
|
---
|
|
1673
1812
|
|
|
@@ -1680,6 +1819,10 @@ Before finishing any change here:
|
|
|
1680
1819
|
versioned, cannot be shared, and is paid for on every call.
|
|
1681
1820
|
- **The bare skill file.** `agents/skills/<name>.md` instead of a folder. It can
|
|
1682
1821
|
never grow the table or script the next revision of the rule will want — §3.4.
|
|
1822
|
+
- **Pointing an agent at the project.** A prompt or skill naming `agents.yaml`,
|
|
1823
|
+
`INSTRUCTIONS.md`, `agents/skills/<name>/…` or `sandbox/Dockerfile`. None of
|
|
1824
|
+
them are on any path the agent can open, so the instruction fails on the turn
|
|
1825
|
+
that follows it — §2.5.
|
|
1683
1826
|
- **Arithmetic in prose.** A skill that walks the model through a calculation it
|
|
1684
1827
|
will get wrong, in a folder that could have held the script — §3.4.1.
|
|
1685
1828
|
- **Politeness padding.** "Please try your best to be helpful." Costs tokens,
|
|
@@ -1689,8 +1832,10 @@ Before finishing any change here:
|
|
|
1689
1832
|
- **Fixing prompts with models.** See §4.4.
|
|
1690
1833
|
- **The chatty router.** A router that answers before handing off, because its
|
|
1691
1834
|
prompt never forbade it.
|
|
1692
|
-
- **
|
|
1693
|
-
|
|
1835
|
+
- **The one-way handoff.** A specialist with no way back, so the router routes
|
|
1836
|
+
once and then never sees the conversation again — §6.3.
|
|
1837
|
+
- **Handing off for an answer.** Wanting one lookup and spending the whole
|
|
1838
|
+
conversation on it. That is a `fork:`, which returns by itself — §6.4.
|
|
1694
1839
|
- **Forking a chain.** Branches never see each other, so a fork whose second
|
|
1695
1840
|
branch needs the first branch's answer is a sequence wearing a fork's clothes.
|
|
1696
1841
|
- **Installing the toolchain every run.** A prompt that begins with `apt-get
|
|
@@ -29,8 +29,11 @@ If it is warranted:
|
|
|
29
29
|
3. Add the `agents.yaml` entry. `description:` is written **for the model** — it
|
|
30
30
|
is the whole of what a sibling sees when deciding to hand off. Grant the
|
|
31
31
|
narrowest `tools:` the job needs.
|
|
32
|
-
4. Wire the
|
|
33
|
-
|
|
32
|
+
4. Wire the return edge. A handoff does not come back on its own, so every
|
|
33
|
+
`A → B` needs a path from B back to A — directly, or through another agent.
|
|
34
|
+
`zen check` warns on an edge that has none. If what this agent really wants
|
|
35
|
+
is an _answer_ rather than to give up the conversation, declare `fork:`
|
|
36
|
+
instead: a branch returns by itself.
|
|
34
37
|
5. Add a one-line comment above the entry saying why this agent exists — its
|
|
35
38
|
job or its tier, not what the keys mean.
|
|
36
39
|
|
|
@@ -17,6 +17,11 @@ Work the checklist in §9 of the copilot instructions. In particular:
|
|
|
17
17
|
`INSTRUCTIONS.md` that is true of only one agent.
|
|
18
18
|
- **Facts.** Any number, threshold, fee or date living in a prompt is in the
|
|
19
19
|
wrong file. Name it and say which skill it belongs in.
|
|
20
|
+
- **Paths.** Work the checklist in §2.5 over `INSTRUCTIONS.md`,
|
|
21
|
+
`agents/prompts/*.md` and `agents/skills/*/SKILL.md`. Every absolute path must
|
|
22
|
+
be under `/workspace`, `/assets`, `/skills` or `/memory`; nothing may name a
|
|
23
|
+
project file the agent cannot open, and nothing may assume the workspace is
|
|
24
|
+
this directory.
|
|
20
25
|
- **Skill descriptions.** Each one a condition, not a title; no two overlapping.
|
|
21
26
|
- **Tools.** Every grant justified by the agent's job; nothing mutating held by
|
|
22
27
|
an agent that only reads; every granted tool mentioned by the prompt.
|
|
@@ -98,16 +98,19 @@ not a paragraph of instructions for a human.
|
|
|
98
98
|
- `scripts/_setup.sh` is the **only** entry point — the leading underscore is
|
|
99
99
|
what separates the runner from the steps it runs. It runs the steps in the
|
|
100
100
|
order they depend on each other and is the single command that initialises the
|
|
101
|
-
project.
|
|
102
|
-
|
|
101
|
+
project. `zen init` writes it; adding a step is adding `scripts/<name>.sh` and
|
|
102
|
+
its name to the `STEPS` list at the top of it. Consolidate any setup script
|
|
103
|
+
that lives elsewhere into this shape, including one left at the project root.
|
|
103
104
|
- Every script starts `set -eu`, works from any working directory
|
|
104
105
|
(`cd "$(dirname "$0")/.."` first), needs no arguments, and exits non-zero on
|
|
105
106
|
failure so `scripts/_setup.sh` stops rather than continuing on a broken step.
|
|
106
107
|
- **Re-entrancy is required.** Running `scripts/_setup.sh` a second time must be
|
|
107
108
|
safe. A step whose output is present and newer than its inputs prints that it
|
|
108
|
-
is up to date and
|
|
109
|
+
is up to date and exits **3**, which is how the runner tells `skipped` from
|
|
110
|
+
`ok`; otherwise it redoes the work idempotently, writing
|
|
109
111
|
to a temporary path and moving it into place so an interrupted run never leaves
|
|
110
|
-
a half-built artefact behind. `scripts/_setup.sh --force` redoes everything
|
|
112
|
+
a half-built artefact behind. `scripts/_setup.sh --force` redoes everything,
|
|
113
|
+
and reaches each step as `$FORCE=1`.
|
|
111
114
|
- **It must be watchable.** `scripts/_setup.sh` tees each step's output to
|
|
112
115
|
`.tmp/logs/setup-<step>.log`, prints a heartbeat line while a long step runs,
|
|
113
116
|
and finishes with one line per step: `ok`, `skipped`, or `failed`.
|
|
@@ -170,6 +173,10 @@ It is slow — an embedding index is minutes, not seconds — so start it in the
|
|
|
170
173
|
background and follow the logs instead of waiting blind:
|
|
171
174
|
|
|
172
175
|
- Tail `.tmp/logs/setup-*.log` and check the output artefact is still growing.
|
|
176
|
+
- **Wait in a loop, never in one long sleep.** Sleep at most 30 seconds at a
|
|
177
|
+
time, then check the log and say what it shows, and repeat until the step
|
|
178
|
+
finishes. A single long block makes the run unwatchable and hides a failure
|
|
179
|
+
that happened in the first ten seconds.
|
|
173
180
|
- Report progress as you go: which step is running, how long it has been going,
|
|
174
181
|
what the last log line said.
|
|
175
182
|
- Do not kill a quiet step. Confirm the process is dead or the log and the
|
|
@@ -24,6 +24,7 @@ zen key <ls|add|use|check|rm|show|env> [ref] [options]
|
|
|
24
24
|
zen models <providers|ls|search|show|test|pick> [ref] [options]
|
|
25
25
|
zen check [name|dir] [--project <name|dir>] [--no-sandbox] [--no-models] [--strict] [--quiet]
|
|
26
26
|
zen inspect [run] [--session <id>] [--open] [--rebuild] [--serve [port]]
|
|
27
|
+
zen memory [stats|ls|show|export|forget] [args] [options]
|
|
27
28
|
zen sandbox [status|up|pull|clean|disk] [options]
|
|
28
29
|
zen version
|
|
29
30
|
|
|
@@ -48,6 +49,7 @@ guess a flag, and do not read them all.
|
|
|
48
49
|
| Which models exist, whether one works, recovering from a refusal | [models.md](./references/models.md) |
|
|
49
50
|
| The container shell commands run in, images, `persist` | [sandbox.md](./references/sandbox.md) |
|
|
50
51
|
| Run reports, trajectories, what a session directory holds | [inspect.md](./references/inspect.md) |
|
|
52
|
+
| What the agents remember, why something was recalled, forgetting | [memory.md](./references/memory.md) |
|
|
51
53
|
| `zen faker` — a mock API from an OpenAPI/Swagger document | [faker.md](./references/faker.md) |
|
|
52
54
|
| `zen rag` — searching an API description, or a pile of markdown | [rag.md](./references/rag.md) |
|
|
53
55
|
|
|
@@ -59,6 +61,7 @@ zen check validate everything before spending a turn
|
|
|
59
61
|
zen run the TUI
|
|
60
62
|
zen run "what changed?" one answer, this directory as the workspace
|
|
61
63
|
zen inspect --open what the model was actually given
|
|
64
|
+
zen memory export --open the whole memory graph, as a page
|
|
62
65
|
zen key ls --check which credentials still work
|
|
63
66
|
zen models test <ref> whether one model actually answers
|
|
64
67
|
zen models pick --embedding the first embedder that does, on stdout
|
|
@@ -91,17 +91,27 @@ Probes are synthetic on purpose — real request bodies never reach a prompt.
|
|
|
91
91
|
|
|
92
92
|
## The cache
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
|
96
|
+
written once, and a spec edit produces a new key rather than a stale answer. A
|
|
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
|
|
100
|
+
operation.
|
|
101
|
+
|
|
102
|
+
`~/.zenera/neo/faker/` is the container's workspace, and scratch: a cache hit is
|
|
103
|
+
copied into it, because the container can only run what is under its mount.
|
|
104
|
+
|
|
105
|
+
`zen faker cache ls` lists what has been generated. `zen faker cache clear`
|
|
106
|
+
removes the generators, the workspace and the container together. They have to
|
|
107
|
+
go together: the container's name is a hash of its configuration, so deleting
|
|
108
|
+
the workspace alone would leave a stopped container bind-mounted onto a
|
|
102
109
|
directory that no longer exists, and every generator would fail with
|
|
103
110
|
`python3: can't open file '/workspace/generators/…/gen.py'`.
|
|
104
111
|
|
|
112
|
+
`zen cache ls --kind faker-generator` reaches the same entries from the other
|
|
113
|
+
side, along with everything else this machine has cached.
|
|
114
|
+
|
|
105
115
|
## Documents it accepts
|
|
106
116
|
|
|
107
117
|
Swagger 2 and OpenAPI 3.0/3.1, JSON or YAML, `$ref`s resolved. Several documents
|
|
@@ -25,8 +25,8 @@ keys; one of them is active.
|
|
|
25
25
|
| `zen key show <ref> [--reveal]` | Masked by default |
|
|
26
26
|
| `zen key env [provider …]` | Shell exports, for other tools |
|
|
27
27
|
|
|
28
|
-
`zen key add` also takes `--project` and `--location`, for a Vertex
|
|
29
|
-
account.
|
|
28
|
+
`zen key add` also takes `--gcp-project` and `--gcp-location`, for a Vertex
|
|
29
|
+
service account.
|
|
30
30
|
|
|
31
31
|
```
|
|
32
32
|
zen key add openai # prompts, echo off
|
|
@@ -56,18 +56,18 @@ echo-off prompt and from nowhere else.
|
|
|
56
56
|
|
|
57
57
|
A **service-account file** is absorbed into `~/.zenera/neo/keys/` and
|
|
58
58
|
`GOOGLE_APPLICATION_CREDENTIALS` points at it. It wants a project too, from
|
|
59
|
-
`--project`, or `GOOGLE_CLOUD_PROJECT`, or the `project_id` inside the file,
|
|
60
|
-
a region from `--location` (`global` otherwise). Application Default
|
|
59
|
+
`--gcp-project`, or `GOOGLE_CLOUD_PROJECT`, or the `project_id` inside the file,
|
|
60
|
+
and a region from `--gcp-location` (`global` otherwise). Application Default
|
|
61
61
|
Credentials from `gcloud auth application-default login` work with no entry at
|
|
62
62
|
all.
|
|
63
63
|
|
|
64
64
|
An **express-mode key** is an ordinary secret under `VERTEX_API_KEY`, and
|
|
65
65
|
addresses no project: a key and a project are alternatives, and sending both
|
|
66
|
-
gets a `403` that mentions neither. `--project` and `--location` are
|
|
67
|
-
refused alongside a key.
|
|
66
|
+
gets a `403` that mentions neither. `--gcp-project` and `--gcp-location` are
|
|
67
|
+
therefore refused alongside a key.
|
|
68
68
|
|
|
69
69
|
```
|
|
70
|
-
zen key add vertex --project acme-prod --location europe-west4
|
|
70
|
+
zen key add vertex --gcp-project acme-prod --gcp-location europe-west4
|
|
71
71
|
# paste a path → the file shape
|
|
72
72
|
# paste a key → the express shape
|
|
73
73
|
```
|