@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: zen-rag-schema
|
|
3
|
-
description: What a schema index is, how it finds the right call inside a large OpenAPI/Swagger document, and how to build and query one with `zen rag schema` (or `npx @zenera/cli`)
|
|
3
|
+
description: What a schema index is, how it finds the right call inside a large OpenAPI/Swagger document, and how to build and query one with `zen rag schema` (or `npx @zenera/cli`) - searching it by meaning, listing and grepping it exactly instead of reaching for shell `grep`/`rg`, tracing a field up to the operations that carry it, giving it to an agent as tools, and writing the project skill that a wired-in index requires. For a pile of markdown instead of an API description, see `zen-rag-docs`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# The schema index
|
|
@@ -31,7 +31,7 @@ zen rag schema <index|search|list|grep|trace|show|stats> [spec...]
|
|
|
31
31
|
| `show` | _print exactly these things_ | no | instant |
|
|
32
32
|
| `stats` | _what is in this index?_ | no | instant |
|
|
33
33
|
|
|
34
|
-
Only `search` ranks, and only `search` costs a network round trip
|
|
34
|
+
Only `search` ranks, and only `search` costs a network round trip - it embeds
|
|
35
35
|
the query before it can compare anything. The other five read `graph.json` off
|
|
36
36
|
the disk and answer in milliseconds, so reach for `search` when the question is
|
|
37
37
|
vague and for `list`/`grep`/`trace` when it is precise. If a search feels slow,
|
|
@@ -39,7 +39,7 @@ it is that one embedding call, not the index: near-zero CPU for several seconds
|
|
|
39
39
|
is the tell.
|
|
40
40
|
|
|
41
41
|
> **`search` takes bare words as the query, not as a subcommand.**
|
|
42
|
-
> `zen rag schema search list methods` does not list anything
|
|
42
|
+
> `zen rag schema search list methods` does not list anything - it runs a
|
|
43
43
|
> semantic search for the phrase _"list methods"_ and returns ten ranked
|
|
44
44
|
> guesses. The listing command is `zen rag schema list methods`.
|
|
45
45
|
|
|
@@ -67,8 +67,8 @@ Two structures, kept together, because neither answers alone:
|
|
|
67
67
|
Finding the field is retrieval. Getting from the field to `POST
|
|
68
68
|
/auth/reset-password` and the exact shape of its body is traversal. So a search
|
|
69
69
|
does both: it seeds on the vector hits, walks the graph outward from them, and
|
|
70
|
-
answers with **the connected piece of the API that matched**
|
|
71
|
-
the schemas they carry and the fields inside them
|
|
70
|
+
answers with **the connected piece of the API that matched** - the operations,
|
|
71
|
+
the schemas they carry and the fields inside them - rather than a ranked list of
|
|
72
72
|
fragments naming types nobody printed.
|
|
73
73
|
|
|
74
74
|
## What is in one
|
|
@@ -85,10 +85,10 @@ Three kinds of node, joined by the `$ref`s between them. Documents are
|
|
|
85
85
|
| `property` | `Method:listUsers#page_size` | a query/path/header **parameter** |
|
|
86
86
|
|
|
87
87
|
A parameter is a property like any other, deliberately. Nobody should have to
|
|
88
|
-
know in advance whether `page_size` lives in a query string or a body
|
|
88
|
+
know in advance whether `page_size` lives in a query string or a body - that is
|
|
89
89
|
the thing they came here to find out.
|
|
90
90
|
|
|
91
|
-
Every node carries a **direction**
|
|
91
|
+
Every node carries a **direction** - `input`, `output` or `both` - propagated
|
|
92
92
|
from the operations down through composition, so a DTO used on both sides is
|
|
93
93
|
honestly both rather than whichever side was read last. That is what makes
|
|
94
94
|
"a field in a **response**" a filter and not a hope.
|
|
@@ -98,7 +98,7 @@ TypeScript compiler can narrow.
|
|
|
98
98
|
|
|
99
99
|
```
|
|
100
100
|
schema-db/
|
|
101
|
-
├── manifest.json written LAST
|
|
101
|
+
├── manifest.json written LAST - its absence means "not indexed"
|
|
102
102
|
├── graph.json topology, read whole
|
|
103
103
|
├── schemas.json the raw schemas, read on first hydrate
|
|
104
104
|
├── operations.json likewise
|
|
@@ -111,7 +111,7 @@ different model is refused rather than answered with noise.
|
|
|
111
111
|
## Installing
|
|
112
112
|
|
|
113
113
|
`zen rag` ships in `@zenera/rag`, a sibling of the CLI. It has no binary of its
|
|
114
|
-
own
|
|
114
|
+
own - installing it adds the `rag` subcommand to `zen`, which is also where the
|
|
115
115
|
credentials already live.
|
|
116
116
|
|
|
117
117
|
```sh
|
|
@@ -136,11 +136,11 @@ zen rag schema index <spec...> [--embedding <ref>] [-o <dir>] [--batch <n>]
|
|
|
136
136
|
|
|
137
137
|
| Flag | Default | Meaning |
|
|
138
138
|
| ------------------- | ------------- | ------------------------------------------------------------ |
|
|
139
|
-
| `--embedding <ref>` |
|
|
139
|
+
| `--embedding <ref>` | - | Which embedder makes the vectors. Omit it to see the choices |
|
|
140
140
|
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes; `$ZEN_SCHEMA_DB` if that is set |
|
|
141
141
|
| `--batch <n>` | `96` | Texts per embedding request, and how often progress prints |
|
|
142
|
-
| `--no-sources` |
|
|
143
|
-
| `--quiet` |
|
|
142
|
+
| `--no-sources` | - | Keep no copy of the documents; `show --source` rebuilds them |
|
|
143
|
+
| `--quiet` | - | No narration |
|
|
144
144
|
|
|
145
145
|
```sh
|
|
146
146
|
zen rag schema index openapi.yaml --embedding openai:text-embedding-3-small
|
|
@@ -154,7 +154,7 @@ what you want when an API is split across files. Swagger 2.0 and OpenAPI
|
|
|
154
154
|
This is the one command here that spends money and time: it embeds every
|
|
155
155
|
operation, schema and field. It prints a per-document table (paths, operations,
|
|
156
156
|
schemas, fields) and a progress line per batch, and **stdout is the output
|
|
157
|
-
directory and nothing else**
|
|
157
|
+
directory and nothing else** - so `DIR=$(zen rag schema index …)` works.
|
|
158
158
|
|
|
159
159
|
The embedding reference names a provider first: `openai:text-embedding-3-small`,
|
|
160
160
|
not a bare model id. Credentials come from the `zen` keyring (`zen key ls`), and
|
|
@@ -168,7 +168,7 @@ stale index is a confident wrong answer.
|
|
|
168
168
|
Every reading command takes `-d`, `--dir`. Without one:
|
|
169
169
|
|
|
170
170
|
1. `$ZEN_SCHEMA_DB`, if it is set. **Set this once** instead of typing `-d` on
|
|
171
|
-
every command
|
|
171
|
+
every command - `export ZEN_SCHEMA_DB=/assets/schema-db`.
|
|
172
172
|
2. Otherwise the **nearest index** to the working directory: here, then a short
|
|
173
173
|
way down into it, then up a level and again, stopping at your home
|
|
174
174
|
directory. The one chosen is named on stderr as it is used, so an answer is
|
|
@@ -176,7 +176,7 @@ Every reading command takes `-d`, `--dir`. Without one:
|
|
|
176
176
|
3. Otherwise `./schema-db`, which is only so the error names the directory you
|
|
177
177
|
were expecting.
|
|
178
178
|
|
|
179
|
-
What is looked for is a `manifest.json`
|
|
179
|
+
What is looked for is a `manifest.json` - an index is self-describing, so
|
|
180
180
|
nothing searches for a directory _called_ `schema-db` and one called anything
|
|
181
181
|
else is found the same way. `schema-db` is just the name a new one is given.
|
|
182
182
|
|
|
@@ -193,13 +193,13 @@ zen rag schema search [terms…] [filters…]
|
|
|
193
193
|
### The field is the point
|
|
194
194
|
|
|
195
195
|
A query is not one string. It is a handful of **fields**, and the field a phrase
|
|
196
|
-
arrives in decides the filter it runs under
|
|
196
|
+
arrives in decides the filter it runs under - `--output-property "invoice total"`
|
|
197
197
|
means _kind=property, on the response side_, and none of that has to be said
|
|
198
198
|
twice.
|
|
199
199
|
|
|
200
200
|
| Term | Searches |
|
|
201
201
|
| ----------------------- | ------------------------------------------------- |
|
|
202
|
-
| `<text>` | Everything
|
|
202
|
+
| `<text>` | Everything - the same as `--all` |
|
|
203
203
|
| `--all <q>` | Everything, unfiltered |
|
|
204
204
|
| `--method <q>` | Operations |
|
|
205
205
|
| `--type <q>` | Schemas, on the side `--direction` names |
|
|
@@ -210,7 +210,7 @@ twice.
|
|
|
210
210
|
| `--output-property <q>` | Fields a call returns |
|
|
211
211
|
| `--query <json\|->` | A whole query object; `-` reads stdin |
|
|
212
212
|
|
|
213
|
-
Every term is repeatable. **`--all` is the weakest of them**
|
|
213
|
+
Every term is repeatable. **`--all` is the weakest of them** - it cannot filter,
|
|
214
214
|
so put the intent where it belongs: a request field in `--input-property`, a
|
|
215
215
|
response field in `--output-property`, an action in `--method`.
|
|
216
216
|
|
|
@@ -218,23 +218,23 @@ response field in `--output-property`, an action in `--method`.
|
|
|
218
218
|
|
|
219
219
|
| Flag | Default | Meaning |
|
|
220
220
|
| --------------------------- | ----------- | ---------------------------------------------------------- |
|
|
221
|
-
| `-d`, `--dir <dir>` | found | Which index
|
|
221
|
+
| `-d`, `--dir <dir>` | found | Which index - see "Which index gets read" |
|
|
222
222
|
| `--embedding <ref>` | the index's | Must be the one the index was built with |
|
|
223
223
|
| `--direction <d>` | `any` | `input`, `output` or `any` |
|
|
224
224
|
| `--method-type <t>` | `any` | `read_only` (GET/HEAD/OPTIONS) or `read_write` |
|
|
225
|
-
| `--exclude-id <id>` |
|
|
226
|
-
| `--exclude-method <name>` |
|
|
227
|
-
| `--exclude-type <name>` |
|
|
228
|
-
| `--exclude-property <name>` |
|
|
225
|
+
| `--exclude-id <id>` | - | Drop a node. Repeatable |
|
|
226
|
+
| `--exclude-method <name>` | - | Drop an operation by name. Repeatable |
|
|
227
|
+
| `--exclude-type <name>` | - | Drop a schema by name. Repeatable |
|
|
228
|
+
| `--exclude-property <name>` | - | Drop a field by name. Repeatable |
|
|
229
229
|
| `--source <name>` | every one | Search only this document, as `stats` names it. Repeatable |
|
|
230
230
|
| `--limit <n>` | `5` | Seeds kept per term |
|
|
231
231
|
| `--max-hops <n>` | `3` | How far apart two hits may be and still join |
|
|
232
232
|
| `--max-nodes <n>` | `200` | Nodes per result |
|
|
233
233
|
| `--format <f>` | `text` | `text`, `mermaid`, `mermaid-flowchart`, `ts`, `openapi` |
|
|
234
|
-
| `--show-source` |
|
|
235
|
-
| `--no-docs` |
|
|
236
|
-
| `--interactive` |
|
|
237
|
-
| `--quiet` |
|
|
234
|
+
| `--show-source` | - | Tag each operation and schema with its document |
|
|
235
|
+
| `--no-docs` | - | Leave the descriptions out |
|
|
236
|
+
| `--interactive` | - | Prompt, search, refine. Needs a terminal |
|
|
237
|
+
| `--quiet` | - | No narration |
|
|
238
238
|
|
|
239
239
|
```sh
|
|
240
240
|
zen rag schema search --method "reset a user password" --format ts
|
|
@@ -244,14 +244,14 @@ zen rag schema search --method "apply a tag" --source policy_api --show-source
|
|
|
244
244
|
```
|
|
245
245
|
|
|
246
246
|
When an index holds two revisions of one API, `--source` is what keeps the
|
|
247
|
-
answer inside the one you mean
|
|
247
|
+
answer inside the one you mean - the same words rank in both, so without it the
|
|
248
248
|
two have to be told apart by eye after the fact. It is repeatable, and the names
|
|
249
249
|
it takes are the ones `stats` prints; anything else is refused, and the refusal
|
|
250
250
|
lists what the index does hold.
|
|
251
251
|
|
|
252
252
|
`--format ts` emits TypeScript closed over its own `$ref`s: everything named is
|
|
253
253
|
also declared, so the output compiles on its own. `--format openapi` emits a
|
|
254
|
-
standalone document holding just the matched slice
|
|
254
|
+
standalone document holding just the matched slice - the one to hand to a code
|
|
255
255
|
generator or a mock server. The Mermaid formats are for looking at.
|
|
256
256
|
|
|
257
257
|
### Turning one search into a session
|
|
@@ -267,7 +267,7 @@ zen rag schema search --all "subscription" --exclude-type Subscription --exclude
|
|
|
267
267
|
|
|
268
268
|
Non-interactive search is a tool, not an afterthought. Every field is a flag,
|
|
269
269
|
the whole query can arrive as one JSON object, `--json` is a stable shape, no
|
|
270
|
-
terminal is needed, and **an empty result exits 0**
|
|
270
|
+
terminal is needed, and **an empty result exits 0** - a caller must never have
|
|
271
271
|
to tell "nothing matched" from "the index is missing" by parsing stderr.
|
|
272
272
|
|
|
273
273
|
```sh
|
|
@@ -307,7 +307,7 @@ quit
|
|
|
307
307
|
|
|
308
308
|
## Reading it without searching
|
|
309
309
|
|
|
310
|
-
None of these need an embedder or a credential
|
|
310
|
+
None of these need an embedder or a credential - they are plain reads of the
|
|
311
311
|
graph on disk.
|
|
312
312
|
|
|
313
313
|
```sh
|
|
@@ -316,7 +316,7 @@ zen rag schema stats
|
|
|
316
316
|
```
|
|
317
317
|
|
|
318
318
|
`show` prints named nodes with no retrieval in between; `stats` says what is in
|
|
319
|
-
an index and what built it
|
|
319
|
+
an index and what built it - counts by kind, the embedding model, the documents
|
|
320
320
|
it came from. `stats` is the fastest way to answer "is this index the one I
|
|
321
321
|
think it is?".
|
|
322
322
|
|
|
@@ -325,7 +325,7 @@ think it is?".
|
|
|
325
325
|
| The question | The command |
|
|
326
326
|
| ------------------------------------------------ | ---------------------------------------- |
|
|
327
327
|
| "how do I reset a password with this API?" | `search --method "reset a password"` |
|
|
328
|
-
| _anything you would have run `grep` for_ | `grep` / `list`
|
|
328
|
+
| _anything you would have run `grep` for_ | `grep` / `list` - never the shell |
|
|
329
329
|
| "which call can reach this field?" | `trace <field>` |
|
|
330
330
|
| "what does the create-user request look like?" | `search --input-type "create user"` |
|
|
331
331
|
| "what operations exist under /users?" | `list methods --path "*/users*"` |
|
|
@@ -343,7 +343,7 @@ its best guesses whether or not any of them are right.
|
|
|
343
343
|
### Exact matching, when the question is whether something exists
|
|
344
344
|
|
|
345
345
|
Search **ranks**. A ranking returns the top of a list, which means it can never
|
|
346
|
-
tell you that something is absent
|
|
346
|
+
tell you that something is absent - "no results" and "not there" look the same.
|
|
347
347
|
When that is the actual question, do not search:
|
|
348
348
|
|
|
349
349
|
```
|
|
@@ -381,12 +381,12 @@ zen rag schema grep status --path "/invoices/*" # the word, in one corner
|
|
|
381
381
|
```
|
|
382
382
|
|
|
383
383
|
`list` walks one kind of node and matches its structured fields; `grep` matches
|
|
384
|
-
the text of every node in the index
|
|
384
|
+
the text of every node in the index - the same text the search was built from,
|
|
385
385
|
so the two agree on what the API says. A pattern with `*` or `?` is a glob
|
|
386
386
|
matched against the whole string; a plain word is a substring, so `--name
|
|
387
387
|
password` finds `ResetPasswordPayload` and `--name "Password*"` finds nothing.
|
|
388
388
|
|
|
389
|
-
**`--regex` is the only way to say "one of these"**
|
|
389
|
+
**`--regex` is the only way to say "one of these"** - a glob has no alternation.
|
|
390
390
|
On `list` it turns every pattern into a regular expression. On `grep` it turns
|
|
391
391
|
the **pattern** into one; `--name` and `--path` stay globs-or-substrings there,
|
|
392
392
|
because they are always names:
|
|
@@ -409,7 +409,7 @@ have to be recovered from `--json`.
|
|
|
409
409
|
|
|
410
410
|
Both report `found` as the true total even when `--limit` shortens what is
|
|
411
411
|
printed, so a cut answer never misreports how much there is. Nothing matching
|
|
412
|
-
exits 0 with empty stdout
|
|
412
|
+
exits 0 with empty stdout - and that emptiness is trustworthy, which is the
|
|
413
413
|
whole point of them.
|
|
414
414
|
|
|
415
415
|
`grep --ids-only` composes:
|
|
@@ -420,13 +420,13 @@ zen rag schema grep token --ids-only | xargs zen rag schema show --format ts
|
|
|
420
420
|
|
|
421
421
|
### Upwards, from a field to the calls that carry it
|
|
422
422
|
|
|
423
|
-
Finding the field is half the job. The other half
|
|
424
|
-
actually reach it
|
|
423
|
+
Finding the field is half the job. The other half - which operation can
|
|
424
|
+
actually reach it - is a walk up the `$ref`s.
|
|
425
425
|
|
|
426
426
|
`search` does part of it: it stitches its seeds into one connected piece and
|
|
427
427
|
prints what each operation accepts and returns, so a lucky search does show the
|
|
428
428
|
call. But it joins only what **ranked**, only within `--max-hops` (3 by
|
|
429
|
-
default), and it never names the chain
|
|
429
|
+
default), and it never names the chain - and the call almost never repeats the
|
|
430
430
|
word, so `GET /users/{userId}` and `city` have nothing in common except the
|
|
431
431
|
edges between them. `trace` follows those edges instead of guessing at them:
|
|
432
432
|
exhaustive, and certain.
|
|
@@ -454,14 +454,14 @@ the answer.
|
|
|
454
454
|
| `--kind <k>` | types + properties | `method`, `type` or `property`. Repeatable |
|
|
455
455
|
| `--direction <d>` | `any` | Only the calls that accept it, or that return it |
|
|
456
456
|
| `--max-hops <n>` | `8` | How far up to walk |
|
|
457
|
-
| `--limit <n>` |
|
|
458
|
-
| `--routes <n>` |
|
|
459
|
-
| `--ids-only` |
|
|
460
|
-
| `--regex` |
|
|
461
|
-
| `--source <name>` |
|
|
462
|
-
| `--show-source` |
|
|
463
|
-
|
|
464
|
-
A bare word matches the way `list --name` does
|
|
457
|
+
| `--limit <n>` | - | Trace at most n matching nodes |
|
|
458
|
+
| `--routes <n>` | - | Operations printed per node; `found` counts them all |
|
|
459
|
+
| `--ids-only` | - | Bare operation ids, one per line, for piping |
|
|
460
|
+
| `--regex` | - | Read the pattern as a regex; `--case-sensitive` too |
|
|
461
|
+
| `--source <name>` | - | Only nodes from one document |
|
|
462
|
+
| `--show-source` | - | Print which document each operation came from |
|
|
463
|
+
|
|
464
|
+
A bare word matches the way `list --name` does - a substring, or a glob when it
|
|
465
465
|
has `*` or `?`. A node id (`Type:User`) is taken as that node rather than as a
|
|
466
466
|
pattern. Operations are left out of a name match on purpose: they are where a
|
|
467
467
|
trace ends, not where one starts.
|
|
@@ -487,7 +487,7 @@ name it once with `ZEN_SCHEMA_DB`.
|
|
|
487
487
|
| `grep -r password` \| _only in schemas_ | `zen rag schema grep password --kind type` |
|
|
488
488
|
| `grep -E "pass(word\|phrase)"` | `zen rag schema grep "pass(word\|phrase)" --regex` |
|
|
489
489
|
| `grep password` (case matters) | `zen rag schema grep password --case-sensitive` |
|
|
490
|
-
| `grep -c` / `wc -l` | `--json`, and read `found`
|
|
490
|
+
| `grep -c` / `wc -l` | `--json`, and read `found` - it counts past `--limit` |
|
|
491
491
|
| `grep -l` / `grep -o` for piping | `zen rag schema grep password --ids-only` |
|
|
492
492
|
| `grep "/users" spec.yaml` | `zen rag schema list methods --path "*/users*"` |
|
|
493
493
|
| `grep -i "updateuser"` | `zen rag schema list methods --name "*Update*"` |
|
|
@@ -506,7 +506,7 @@ zen rag schema list properties --name "*password*" --show-source
|
|
|
506
506
|
```
|
|
507
507
|
|
|
508
508
|
If none of these fits the question, the question is about meaning, and the
|
|
509
|
-
answer is `search`
|
|
509
|
+
answer is `search` - still not the shell.
|
|
510
510
|
|
|
511
511
|
### Naming what you want in `show`
|
|
512
512
|
|
|
@@ -522,7 +522,7 @@ have. A bare name means exactly that name; add `*` to take more than one.
|
|
|
522
522
|
`--show-source` names the document each node came from, which is the quick way
|
|
523
523
|
to tell two versions of the same API apart. `--exact` prints only what was
|
|
524
524
|
named instead of the neighbourhood around it, which with `--format openapi`
|
|
525
|
-
gives a valid self-contained slice of the specification
|
|
525
|
+
gives a valid self-contained slice of the specification - enough to generate a
|
|
526
526
|
client or a mock payload from.
|
|
527
527
|
|
|
528
528
|
## Giving it to an agent
|
|
@@ -545,25 +545,25 @@ const project = await loadProject('./my-project', { tools: schemaTools(index) })
|
|
|
545
545
|
| -------------------------- | ------------------------------------------------------------------- |
|
|
546
546
|
| `search_api` | the search above, with the same fields |
|
|
547
547
|
| `describe_types` | named schemas as TypeScript, closed over what they refer to |
|
|
548
|
-
| `find_types_with_property` | every schema with a field of this name
|
|
549
|
-
| `list_api` | methods, types or fields by name
|
|
550
|
-
| `grep_api` | every literal occurrence of a string
|
|
548
|
+
| `find_types_with_property` | every schema with a field of this name - exact lookup, no searching |
|
|
549
|
+
| `list_api` | methods, types or fields by name - complete, and counted in full |
|
|
550
|
+
| `grep_api` | every literal occurrence of a string - the way to prove absence |
|
|
551
551
|
| `trace_api` | up from a field or schema to the operations that carry it |
|
|
552
552
|
|
|
553
553
|
Only `search_api` ranks; the other five are exact. `find_types_with_property`
|
|
554
554
|
is the one for the repair loop. When `tsc` says `'password' does not exist in
|
|
555
|
-
type 'PublicUserProfile'`, the model does not need the word explained again
|
|
555
|
+
type 'PublicUserProfile'`, the model does not need the word explained again -
|
|
556
556
|
it needs the list of types that _do_ have one, and embedding the word will only
|
|
557
557
|
rank the guess it already made near the top. `grep_api` is the same instinct
|
|
558
558
|
widened: it is how a model checks that a search returning nothing really means
|
|
559
559
|
there is nothing. `trace_api` is the step after either of them: a field is of
|
|
560
560
|
no use until the call that carries it is known, and no ranking will find that
|
|
561
|
-
call
|
|
561
|
+
call - the operation and the field share no words, only edges.
|
|
562
562
|
|
|
563
563
|
`list_api` and `grep_api` take `name`, `path`, `regex` and `source`, so a
|
|
564
564
|
common word can be narrowed to one route or one document rather than read out
|
|
565
565
|
in full. When an index holds more than one document, both tools name the source
|
|
566
|
-
of every row without being asked
|
|
566
|
+
of every row without being asked - with two versions of the same API indexed
|
|
567
567
|
together, which one answered is part of the answer.
|
|
568
568
|
|
|
569
569
|
Tell the agent in its prompt to search before it writes a call, and to put the
|
|
@@ -571,8 +571,8 @@ intent in the narrow field. A model left to itself puts everything in `all`.
|
|
|
571
571
|
|
|
572
572
|
## Wiring it into a project means writing the project a skill
|
|
573
573
|
|
|
574
|
-
**Whenever an index is used by a Zenera project
|
|
575
|
-
`zen rag` reachable from the agent's sandbox
|
|
574
|
+
**Whenever an index is used by a Zenera project - as `schema:*` tools, or as
|
|
575
|
+
`zen rag` reachable from the agent's sandbox - write a skill for it in that
|
|
576
576
|
project.** Not optional, and not the same thing as passing the tools in.
|
|
577
577
|
|
|
578
578
|
Wiring alone leaves the model to infer everything that matters. A tool
|
|
@@ -580,7 +580,7 @@ description says what `grep_api` does; it cannot say that this index holds the
|
|
|
580
580
|
ACME policy API, that names are `snake_case`, that every route is under
|
|
581
581
|
`/api/v1/policy`, or that `list_api` is the right first move here because the
|
|
582
582
|
API has three hundred operations and search will hand back five. That is
|
|
583
|
-
project knowledge, and project knowledge belongs in a skill
|
|
583
|
+
project knowledge, and project knowledge belongs in a skill - where it is
|
|
584
584
|
loaded only when the model is actually working on this API, instead of sitting
|
|
585
585
|
in the system prompt of every run.
|
|
586
586
|
|
|
@@ -598,10 +598,10 @@ find_types_with_property]` if the skill should be what unlocks them.
|
|
|
598
598
|
| Section | Because |
|
|
599
599
|
| --------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
600
600
|
| Which API | The name, the version, and the document it was built from |
|
|
601
|
-
| Where the index | `ZEN_SCHEMA_DB`, or the `-d` to pass
|
|
601
|
+
| Where the index | `ZEN_SCHEMA_DB`, or the `-d` to pass - an agent cannot guess a path |
|
|
602
602
|
| Which command | Meaning → `search`; presence, spelling or a count → `list`/`grep`; which endpoint carries a field → `trace` |
|
|
603
603
|
| Never the shell | State it outright. `grep`/`rg`/`jq` on the spec is the default reflex |
|
|
604
|
-
| The conventions | Auth, base path, pagination, casing, error envelope
|
|
604
|
+
| The conventions | Auth, base path, pagination, casing, error envelope - none of it is in the graph |
|
|
605
605
|
| Worked examples | Two or three, with **real operation and schema names from this index** |
|
|
606
606
|
| The repair loop | Compiler said the field is not on the type → `find_types_with_property`, then `trace` for the call that carries it |
|
|
607
607
|
|
|
@@ -614,7 +614,7 @@ Best practice, in order of how often it is got wrong:
|
|
|
614
614
|
prove absence. Left alone a model searches for everything, gets five ranked
|
|
615
615
|
guesses, and writes a call against the best of them.
|
|
616
616
|
3. **Keep it short.** A skill is prompt. One screen of routing rules and
|
|
617
|
-
conventions beats a transcription of this document
|
|
617
|
+
conventions beats a transcription of this document - link to `zen rag
|
|
618
618
|
schema --help` for the flags.
|
|
619
619
|
4. **Re-index, then re-read the skill.** Both go stale against the same
|
|
620
620
|
change, and a skill quoting operations that no longer exist is worse than
|
|
@@ -625,7 +625,7 @@ schema --help` for the flags.
|
|
|
625
625
|
```md
|
|
626
626
|
---
|
|
627
627
|
name: billing-api
|
|
628
|
-
description: How to find the right call in the Acme Billing API (v2)
|
|
628
|
+
description: How to find the right call in the Acme Billing API (v2) - which schema
|
|
629
629
|
carries which field, and which endpoint accepts it. Use before writing any request.
|
|
630
630
|
---
|
|
631
631
|
|
|
@@ -639,7 +639,7 @@ all under `/v2`. Bearer token in `Authorization`; cursors, never page numbers.
|
|
|
639
639
|
- Does X exist, how is it spelled, how many are there → `list_api` / `grep_api`.
|
|
640
640
|
These are complete; a search is not, and cannot prove absence.
|
|
641
641
|
- Which endpoint carries this field → `trace_api`. Never guess the owner.
|
|
642
|
-
- Never `grep`/`rg`/`jq` the spec
|
|
642
|
+
- Never `grep`/`rg`/`jq` the spec - the tools above are local and exact.
|
|
643
643
|
|
|
644
644
|
Worked: the invoice total is `Invoice.amount_due` (minor units), returned by
|
|
645
645
|
`GetInvoice` and `ListInvoices`; `trace_api of: amount_due` shows both.
|
|
@@ -649,10 +649,10 @@ Worked: the invoice total is `Invoice.amount_due` (minor units), returned by
|
|
|
649
649
|
|
|
650
650
|
| Symptom | Cause |
|
|
651
651
|
| ------------------------------------------------ | ----------------------------------------------------------------------------------- |
|
|
652
|
-
| "not installed" | `@zenera/rag` is not resolvable
|
|
652
|
+
| "not installed" | `@zenera/rag` is not resolvable - install it, or use the two-`--package` npx form |
|
|
653
653
|
| Refused for a different embedding | The index records the model that built it; re-index or pass the right `--embedding` |
|
|
654
654
|
| No manifest / not an index | A build that did not finish. `manifest.json` is written last on purpose |
|
|
655
|
-
| `provider "openai": no api key` | `zen key ls`
|
|
655
|
+
| `provider "openai": no api key` | `zen key ls` - the keyring, or a real environment variable |
|
|
656
656
|
| A usage error before any credential is asked for | Deliberate: everything about the invocation is checked first, so a typo is a typo |
|
|
657
657
|
| Nothing matched | Exit 0 with an empty answer. Try fewer words, or `--all` instead of a narrow field |
|
|
658
658
|
| Answers about the wrong version of the API | Nothing watches the document. Re-index after it changes |
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zen-review
|
|
3
|
+
description: Checking a project before committing - the four mechanical checks `/review-project` makes before any judgement (`zen check`, the §2.5 path sweep, the memory house-rules copy, the spec-sync record), what each one owns, what their exit codes mean, and what deliberately has no check because no tool can make it. Load before running `/review-project`, before saying a project is ready, and whenever a review finding needs verifying rather than restating.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reviewing a project
|
|
7
|
+
|
|
8
|
+
A review of an agent project is two jobs wearing one name. One half is
|
|
9
|
+
decidable - a schema is valid or it is not, a path resolves or it does not, a
|
|
10
|
+
copy matches its reference or it does not - and a human doing it by hand gets it
|
|
11
|
+
wrong in the same three places every time. The other half is judgement: whether
|
|
12
|
+
an agent has one job, whether a description routes, whether a number is in the
|
|
13
|
+
wrong file.
|
|
14
|
+
|
|
15
|
+
This skill owns the first half, so the prompt can be all of the second.
|
|
16
|
+
|
|
17
|
+
## The one command
|
|
18
|
+
|
|
19
|
+
From the project root, or anywhere at all:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
.github/skills/zen-review/scripts/review.sh
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
It runs four checks in the order a reviewer needs them and prints a summary:
|
|
26
|
+
|
|
27
|
+
| Step | Runs | Owns |
|
|
28
|
+
| ----------- | ------------------------------------------ | -------------------------------------------- |
|
|
29
|
+
| `zen check` | the CLI | everything decidable about the configuration |
|
|
30
|
+
| `paths` | `zen-review/scripts/check-paths.sh` | paths a running agent cannot open - §2.5 |
|
|
31
|
+
| `memory` | `zen-memory/scripts/check-instructions.sh` | the house-rules copy, byte for byte - §5.3 |
|
|
32
|
+
| `spec-sync` | `zen-spec-sync/scripts/snapshot.sh status` | whether the record of the last pass is sound |
|
|
33
|
+
|
|
34
|
+
Every step runs even when an earlier one fails, because a review that stops at
|
|
35
|
+
the first problem is one somebody has to run four times. The exit code is `1` if
|
|
36
|
+
any step wants attention and `0` if none does. `review.sh fast` passes
|
|
37
|
+
`--no-models --no-sandbox` to `zen check`, which is the right call while
|
|
38
|
+
iterating and the wrong one before committing - a key that authenticates says
|
|
39
|
+
nothing about the model id it is spent on.
|
|
40
|
+
|
|
41
|
+
Nothing below matters while `zen check` fails. Report what it said and fix that
|
|
42
|
+
first.
|
|
43
|
+
|
|
44
|
+
## The two scripts this skill ships
|
|
45
|
+
|
|
46
|
+
### `check-paths.sh` - the §2.5 sweep
|
|
47
|
+
|
|
48
|
+
A running agent's whole world is four paths: `/workspace`, `/assets`, `/skills`
|
|
49
|
+
and `/memory`. Every path-shaped token in `agents/*instructions.md`,
|
|
50
|
+
`agents/prompts/*.md` and a skill's markdown is read by a model as an
|
|
51
|
+
instruction to open something, so anything outside those four is an instruction
|
|
52
|
+
to open a file that is not there.
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
.github/skills/zen-review/scripts/check-paths.sh # each candidate, with file and line
|
|
56
|
+
.github/skills/zen-review/scripts/check-paths.sh raw # the tokens alone, unfiltered
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
It exits `1` whenever it prints a candidate, because the list is meant to be
|
|
60
|
+
emptied or explained rather than skimmed. It strips urls before tokenising, skips
|
|
61
|
+
a handful of English constructions that contain a slash, and leaves
|
|
62
|
+
`agents/memory-instructions.md` out entirely - that file is worked examples by
|
|
63
|
+
design, and `check-instructions.sh` is the check it actually needs.
|
|
64
|
+
|
|
65
|
+
Everything it does print is either noise the script has not learned yet or a
|
|
66
|
+
real finding. There is no third case. A candidate that is genuinely noise is a
|
|
67
|
+
one-line addition to `NOISE` in the script - **upstream**, see below, not in the
|
|
68
|
+
copy sitting in this project.
|
|
69
|
+
|
|
70
|
+
`raw` is the sweep with nothing filtered, for when you suspect the filter.
|
|
71
|
+
|
|
72
|
+
### `check-instructions.sh` - the memory house rules
|
|
73
|
+
|
|
74
|
+
Lives in the `zen-memory` skill, because it is about memory and it is read at
|
|
75
|
+
the moment that skill is:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
.github/skills/zen-memory/scripts/check-instructions.sh # the verdict
|
|
79
|
+
.github/skills/zen-memory/scripts/check-instructions.sh diff # and every differing line
|
|
80
|
+
.github/skills/zen-memory/scripts/check-instructions.sh fix # copy the reference over
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`agents/memory-instructions.md` must be a byte-identical copy of the `zen-memory`
|
|
84
|
+
skill's `references/memory-instructions.md`, and the reference is rewritten by
|
|
85
|
+
every `zen init` and `zen open`, so the copy goes stale without anyone touching
|
|
86
|
+
it. It drifts by **trailing whitespace inside tables**, which is invisible on
|
|
87
|
+
screen - this is the check no one should be asked to make by eye. When the
|
|
88
|
+
difference is whitespace alone the script says so, because that is the usual
|
|
89
|
+
cause and the least believable finding.
|
|
90
|
+
|
|
91
|
+
`fix` is the one-line `cp` and nothing else. Project policy belongs in
|
|
92
|
+
`agents/memory-policy-instructions.md`, which filename order puts directly after
|
|
93
|
+
the copy - see the `zen-memory` skill.
|
|
94
|
+
|
|
95
|
+
## What has no check, on purpose
|
|
96
|
+
|
|
97
|
+
Not because it would be hard, but because the answer would be wrong:
|
|
98
|
+
|
|
99
|
+
- **Whether an agent has one job.** Read the prompt.
|
|
100
|
+
- **Whether a description routes.** Two overlapping descriptions both parse.
|
|
101
|
+
- **Whether a fact belongs in a skill.** A threshold in a prompt is valid YAML.
|
|
102
|
+
- **Whether a tool grant is justified.** `zen check` confirms the selector
|
|
103
|
+
resolves, never that the agent needs it.
|
|
104
|
+
- **Whether the newest spec-sync history entry is honest.** A pass can claim
|
|
105
|
+
anything; only reading the diff says whether it did it.
|
|
106
|
+
|
|
107
|
+
That list is `/review-project`, and §9 of the copilot instructions is the long
|
|
108
|
+
form. Run the script first so the prompt is spent on this.
|
|
109
|
+
|
|
110
|
+
## Where these scripts live, and why edits to them vanish
|
|
111
|
+
|
|
112
|
+
`zen init` and `zen open` rewrite the whole `.github/` tree from the version of
|
|
113
|
+
`zen` in hand. These scripts arrive with it, so a change made to the copy in a
|
|
114
|
+
project is gone at the next `open`. A filter that should hold for every project
|
|
115
|
+
belongs in the distribution - `packages/cli/templates/editor/.github/skills/` in
|
|
116
|
+
the @zenera/neo repository - and reaches this project the next time the tree is
|
|
117
|
+
written.
|
|
118
|
+
|
|
119
|
+
Do not confuse these with a project's own scripts. `agents/skills/<name>/scripts/`
|
|
120
|
+
is run by **the project's agents**, inside the sandbox, at
|
|
121
|
+
`/skills/<name>/scripts/…`. `.github/skills/<name>/scripts/` is run by **the
|
|
122
|
+
editor's assistant**, on the host, at a workspace path. The two have different
|
|
123
|
+
readers and neither can see the other.
|