@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.
- package/README.md +201 -129
- package/dist/banner.d.ts +5 -1
- package/dist/banner.js +2 -2
- package/dist/catalog.js +19 -20
- package/dist/command.d.ts +5 -0
- package/dist/commands/check.js +5 -1
- package/dist/commands/init.js +41 -6
- package/dist/commands/run.js +4 -0
- package/dist/engine.js +6 -0
- package/dist/env.d.ts +20 -0
- package/dist/env.js +65 -0
- package/dist/keys.d.ts +2 -0
- package/dist/keys.js +2 -0
- package/dist/main.js +10 -6
- package/dist/sandbox.d.ts +9 -0
- package/dist/sandbox.js +23 -3
- package/dist/scaffold.d.ts +6 -0
- package/dist/scaffold.js +56 -15
- package/dist/validate.js +57 -15
- package/package.json +2 -2
- package/templates/editor/.github/copilot-instructions.md +501 -301
- package/templates/editor/.github/prompts/new-agent.prompt.md +6 -6
- package/templates/editor/.github/prompts/new-skill.prompt.md +7 -7
- package/templates/editor/.github/prompts/review-project.prompt.md +54 -15
- package/templates/editor/.github/prompts/sync-with-spec.prompt.md +229 -42
- package/templates/editor/.github/prompts/update-spec-from-feedback.prompt.md +142 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +62 -6
- package/templates/editor/.github/skills/zen-cli/references/check.md +9 -6
- package/templates/editor/.github/skills/zen-cli/references/faker.md +14 -14
- package/templates/editor/.github/skills/zen-cli/references/frame.md +11 -9
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +3 -3
- package/templates/editor/.github/skills/zen-cli/references/keys.md +9 -9
- package/templates/editor/.github/skills/zen-cli/references/memory.md +11 -11
- package/templates/editor/.github/skills/zen-cli/references/models.md +8 -8
- package/templates/editor/.github/skills/zen-cli/references/projects.md +23 -6
- package/templates/editor/.github/skills/zen-cli/references/rag.md +191 -56
- package/templates/editor/.github/skills/zen-cli/references/run.md +3 -3
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +14 -8
- package/templates/editor/.github/skills/zen-memory/SKILL.md +144 -72
- package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +115 -0
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +71 -48
- package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +67 -67
- package/templates/editor/.github/skills/zen-review/SKILL.md +123 -0
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +119 -0
- package/templates/editor/.github/skills/zen-review/scripts/review.sh +104 -0
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +197 -0
- package/templates/editor/.github/skills/zen-spec-sync/scripts/snapshot.sh +200 -0
- package/templates/editor/.vscode/settings.json +46 -3
- package/templates/parts/memory-terms.yaml.tmpl +16 -0
- package/templates/parts/memory.yaml.tmpl +12 -0
- package/templates/project/SPECIFICATION.md.tmpl +7 -0
- package/templates/project/{INSTRUCTIONS.md → agents/instructions.md} +1 -1
- package/templates/project/agents/memory-instructions.md +278 -0
- package/templates/project/agents.yaml.tmpl +9 -0
- package/templates/project/assets/README.md +1 -1
- package/templates/project/env +22 -0
- 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`
|
|
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**
|
|
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`
|
|
54
|
-
| `zen rag`
|
|
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
|
|
79
|
-
names the exact path, as in `agents.yaml: agents[1].skills.discovery
|
|
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
|
|
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:
|
|
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
|
|
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**
|
|
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
|
|
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`
|
|
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>` |
|
|
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` |
|
|
48
|
-
| `--no-cache` |
|
|
49
|
-
| `--quiet` |
|
|
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
|
|
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`
|
|
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
|
|
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**
|
|
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
|
|
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
|
|
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
|
|
99
|
-
429, a dropped socket
|
|
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
|
|
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
|
|
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>`
|
|
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
|
|
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/
|
|
113
|
-
|
|
111
|
+
agents/
|
|
112
|
+
instructions.md house rules, prepended to every agent's prompt
|
|
113
|
+
*-instructions.md more house rules, in filename order
|
|
114
|
+
prompts/ one .md per agent
|
|
115
|
+
skills/ one directory per skill, each with SKILL.md
|
|
114
116
|
sandbox/Dockerfile the image commands run in, when the project builds one
|
|
115
|
-
sessions/ run state, memory, blobs, reports
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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**
|
|
97
|
+
- **live** - authenticated. A rate-limited answer counts as live, because it
|
|
98
98
|
proves the credential.
|
|
99
|
-
- **dead**
|
|
100
|
-
- **blocked**
|
|
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`
|
|
103
|
+
carries a `fix` - for a disabled Google API, the exact
|
|
104
104
|
`gcloud services enable <api> --project <id>`.
|
|
105
|
-
- **unknown**
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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**
|
|
63
|
+
- **left** - every node, with a search box and filters for kind, audience,
|
|
64
64
|
files, superseded and unlinked
|
|
65
|
-
- **middle**
|
|
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**
|
|
68
|
-
and **the remembered file's actual content**
|
|
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
|
|
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
|
|
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
|
|
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
|
|
10
|
-
particular project works
|
|
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
|
|
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
|
|
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
|
|
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}`
|
|
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
|
|
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
|