@zenera/cli 1.1.5 → 1.1.8
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/dist/commands/index.js +2 -2
- package/dist/podman.d.ts +0 -9
- package/dist/podman.js +3 -10
- package/package.json +2 -2
- package/templates/editor/.github/skills/api-schema-index/SKILL.md +278 -39
- package/templates/editor/.github/skills/zen-cli/SKILL.md +1 -1
- package/templates/editor/.github/skills/zen-cli/references/rag.md +139 -31
package/dist/commands/index.js
CHANGED
|
@@ -48,8 +48,8 @@ export const EXTERNAL = {
|
|
|
48
48
|
},
|
|
49
49
|
rag: {
|
|
50
50
|
package: '@zenera/rag',
|
|
51
|
-
summary: '
|
|
52
|
-
usage: 'zen rag
|
|
51
|
+
summary: 'Retrieval over a corpus: index it, then ask it something.',
|
|
52
|
+
usage: 'zen rag <subject> <command> [args...]',
|
|
53
53
|
install: 'npm i -g @zenera/rag',
|
|
54
54
|
banner: { head: 'Zenera', accent: 'Rag', subtitle: 'Api Retrieval' },
|
|
55
55
|
},
|
package/dist/podman.d.ts
CHANGED
|
@@ -34,15 +34,6 @@ export interface PodmanStatus {
|
|
|
34
34
|
imagePresent?: boolean;
|
|
35
35
|
}
|
|
36
36
|
export declare function ensurePodmanReady(opts?: PodmanOptions): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* Builds the project's Dockerfile under its tag.
|
|
39
|
-
*
|
|
40
|
-
* Run every time rather than skipped when the tag already exists, because the
|
|
41
|
-
* tag is a hash of the Dockerfile and its context and the engine's layer cache
|
|
42
|
-
* is a hash of the same thing plus the base image. Asking it is cheap, and it
|
|
43
|
-
* is the only thing that notices when `FROM node:24` starts meaning a different
|
|
44
|
-
* node:24.
|
|
45
|
-
*/
|
|
46
37
|
/**
|
|
47
38
|
* A build that ran and failed, rather than a host that could not be asked.
|
|
48
39
|
*
|
package/dist/podman.js
CHANGED
|
@@ -167,15 +167,6 @@ function parseMachines(stdout) {
|
|
|
167
167
|
// ---------------------------------------------------------------------------
|
|
168
168
|
// The image
|
|
169
169
|
// ---------------------------------------------------------------------------
|
|
170
|
-
/**
|
|
171
|
-
* Builds the project's Dockerfile under its tag.
|
|
172
|
-
*
|
|
173
|
-
* Run every time rather than skipped when the tag already exists, because the
|
|
174
|
-
* tag is a hash of the Dockerfile and its context and the engine's layer cache
|
|
175
|
-
* is a hash of the same thing plus the base image. Asking it is cheap, and it
|
|
176
|
-
* is the only thing that notices when `FROM node:24` starts meaning a different
|
|
177
|
-
* node:24.
|
|
178
|
-
*/
|
|
179
170
|
/**
|
|
180
171
|
* A build that ran and failed, rather than a host that could not be asked.
|
|
181
172
|
*
|
|
@@ -204,7 +195,9 @@ async function build(engine, spec, run, force = false) {
|
|
|
204
195
|
return;
|
|
205
196
|
}
|
|
206
197
|
}
|
|
207
|
-
note(dim(
|
|
198
|
+
note(dim(`${force ? 'rebuilding' : 'building'} the sandbox image from ${spec.dockerfile}`));
|
|
199
|
+
note(dim(' the agent runs its commands inside a container, so the image is needed first'));
|
|
200
|
+
note(dim(' this takes a few minutes; later runs reuse it until the Dockerfile changes'));
|
|
208
201
|
const built = await stream(engine, ['build', '--tag', spec.tag, '--file', spec.dockerfile, spec.context], run, BUILD_MS);
|
|
209
202
|
if (built.code !== 0) {
|
|
210
203
|
throw new BuildError(`could not build ${spec.dockerfile}`, EXIT.sandbox, last(built) || 'run the build by hand to see what the engine says');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenera/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "Command-line front end for @zenera/neo: agentic projects you can run, share and commit.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@inkjs/ui": "^2.0.0",
|
|
52
52
|
"ink": "^7.1.1",
|
|
53
53
|
"react": "^19.2.8",
|
|
54
|
-
"@zenera/neo": "^1.1.
|
|
54
|
+
"@zenera/neo": "^1.1.8",
|
|
55
55
|
"@anthropic-ai/sdk": "^0.120.0",
|
|
56
56
|
"@google/genai": "^2.18.0",
|
|
57
57
|
"@openrouter/sdk": "^1.2.80",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-schema-index
|
|
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,
|
|
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.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# The schema index
|
|
7
7
|
|
|
8
8
|
A schema index is an OpenAPI/Swagger description turned into something that can
|
|
9
9
|
be **asked a question**. It is built once, on disk, and answered from without a
|
|
10
|
-
model: `zen rag schema index` writes it, and
|
|
10
|
+
model: `zen rag schema index` writes it, and six commands read it.
|
|
11
11
|
|
|
12
12
|
It exists because a real specification does not fit in a context window, and
|
|
13
13
|
grepping it does not help. The parts that answer "how do I reset a password?"
|
|
@@ -18,7 +18,7 @@ word "password" appears in forty places that are not the one you want.
|
|
|
18
18
|
## The commands
|
|
19
19
|
|
|
20
20
|
```
|
|
21
|
-
zen rag schema <index|search|list|grep|show|stats> [spec...]
|
|
21
|
+
zen rag schema <index|search|list|grep|trace|show|stats> [spec...]
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
| Command | Answers | Embedder? | Typical |
|
|
@@ -27,21 +27,34 @@ zen rag schema <index|search|list|grep|show|stats> [spec...]
|
|
|
27
27
|
| `search` | _what is this API's way to do X?_ | **yes** | seconds |
|
|
28
28
|
| `list` | _what methods/types/fields are there?_ | no | instant |
|
|
29
29
|
| `grep` | _does the string X appear anywhere?_ | no | instant |
|
|
30
|
+
| `trace` | _which call can reach this field?_ | no | instant |
|
|
30
31
|
| `show` | _print exactly these things_ | no | instant |
|
|
31
32
|
| `stats` | _what is in this index?_ | no | instant |
|
|
32
33
|
|
|
33
34
|
Only `search` ranks, and only `search` costs a network round trip — it embeds
|
|
34
|
-
the query before it can compare anything. The other
|
|
35
|
+
the query before it can compare anything. The other five read `graph.json` off
|
|
35
36
|
the disk and answer in milliseconds, so reach for `search` when the question is
|
|
36
|
-
vague and for `list`/`grep` when it is precise. If a search feels slow,
|
|
37
|
-
that one embedding call, not the index: near-zero CPU for several seconds
|
|
38
|
-
the tell.
|
|
37
|
+
vague and for `list`/`grep`/`trace` when it is precise. If a search feels slow,
|
|
38
|
+
it is that one embedding call, not the index: near-zero CPU for several seconds
|
|
39
|
+
is the tell.
|
|
39
40
|
|
|
40
41
|
> **`search` takes bare words as the query, not as a subcommand.**
|
|
41
42
|
> `zen rag schema search list methods` does not list anything — it runs a
|
|
42
43
|
> semantic search for the phrase _"list methods"_ and returns ten ranked
|
|
43
44
|
> guesses. The listing command is `zen rag schema list methods`.
|
|
44
45
|
|
|
46
|
+
> **Never reach for shell `grep`, `rg`, `find`, `cat` or `jq` here.**
|
|
47
|
+
> Not on the specification, not on `graph.json`, not on anything under the
|
|
48
|
+
> index directory. `zen rag schema grep` and `zen rag schema list` are the
|
|
49
|
+
> exact-matching commands, they are local, they need no credential, and they
|
|
50
|
+
> answer in milliseconds. Shell tools on the same files are strictly worse:
|
|
51
|
+
> they match raw YAML/JSON lines rather than nodes, so they cannot tell a
|
|
52
|
+
> field from a `$ref` from a description, cannot say which operation a hit
|
|
53
|
+
> belongs to, cannot filter by kind or direction, and they miss every name
|
|
54
|
+
> the index normalised. A `grep -r password openapi.yaml` returns forty lines
|
|
55
|
+
> of text; `zen rag schema grep password` returns the nodes, with their ids,
|
|
56
|
+
> ready to hand back to `show`.
|
|
57
|
+
|
|
45
58
|
## Why it is a graph and not a search box
|
|
46
59
|
|
|
47
60
|
Two structures, kept together, because neither answers alone:
|
|
@@ -124,8 +137,9 @@ zen rag schema index <spec...> [--embedding <ref>] [-o <dir>] [--batch <n>]
|
|
|
124
137
|
| Flag | Default | Meaning |
|
|
125
138
|
| ------------------- | ------------- | ------------------------------------------------------------ |
|
|
126
139
|
| `--embedding <ref>` | — | Which embedder makes the vectors. Omit it to see the choices |
|
|
127
|
-
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes
|
|
140
|
+
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes; `$ZEN_SCHEMA_DB` if that is set |
|
|
128
141
|
| `--batch <n>` | `96` | Texts per embedding request, and how often progress prints |
|
|
142
|
+
| `--no-sources` | — | Keep no copy of the documents; `show --source` rebuilds them |
|
|
129
143
|
| `--quiet` | — | No narration |
|
|
130
144
|
|
|
131
145
|
```sh
|
|
@@ -149,6 +163,27 @@ a real environment variable always wins.
|
|
|
149
163
|
Rebuild the index when the specification changes. Nothing watches it, and a
|
|
150
164
|
stale index is a confident wrong answer.
|
|
151
165
|
|
|
166
|
+
## Which index gets read
|
|
167
|
+
|
|
168
|
+
Every reading command takes `-d`, `--dir`. Without one:
|
|
169
|
+
|
|
170
|
+
1. `$ZEN_SCHEMA_DB`, if it is set. **Set this once** instead of typing `-d` on
|
|
171
|
+
every command — `export ZEN_SCHEMA_DB=/assets/schema-db`.
|
|
172
|
+
2. Otherwise the **nearest index** to the working directory: here, then a short
|
|
173
|
+
way down into it, then up a level and again, stopping at your home
|
|
174
|
+
directory. The one chosen is named on stderr as it is used, so an answer is
|
|
175
|
+
never anonymous.
|
|
176
|
+
3. Otherwise `./schema-db`, which is only so the error names the directory you
|
|
177
|
+
were expecting.
|
|
178
|
+
|
|
179
|
+
What is looked for is a `manifest.json` — an index is self-describing, so
|
|
180
|
+
nothing searches for a directory _called_ `schema-db` and one called anything
|
|
181
|
+
else is found the same way. `schema-db` is just the name a new one is given.
|
|
182
|
+
|
|
183
|
+
Two indexes the same distance away is refused rather than guessed at: the wrong
|
|
184
|
+
index does not fail, it answers confidently about a different API. Name one
|
|
185
|
+
with `-d`, or set `ZEN_SCHEMA_DB`.
|
|
186
|
+
|
|
152
187
|
## Searching it
|
|
153
188
|
|
|
154
189
|
```
|
|
@@ -181,23 +216,24 @@ response field in `--output-property`, an action in `--method`.
|
|
|
181
216
|
|
|
182
217
|
### Shaping the answer
|
|
183
218
|
|
|
184
|
-
| Flag | Default
|
|
185
|
-
| --------------------------- |
|
|
186
|
-
| `-d`, `--dir <dir>` |
|
|
187
|
-
| `--embedding <ref>` | the index's
|
|
188
|
-
| `--direction <d>` | `any`
|
|
189
|
-
| `--method-type <t>` | `any`
|
|
190
|
-
| `--exclude-id <id>` | —
|
|
191
|
-
| `--exclude-method <name>` | —
|
|
192
|
-
| `--exclude-type <name>` | —
|
|
193
|
-
| `--exclude-property <name>` | —
|
|
194
|
-
| `--limit <n>` | `5`
|
|
195
|
-
| `--max-hops <n>` | `3`
|
|
196
|
-
| `--max-nodes <n>` | `200`
|
|
197
|
-
| `--format <f>` | `text`
|
|
198
|
-
| `--
|
|
199
|
-
| `--
|
|
200
|
-
| `--
|
|
219
|
+
| Flag | Default | Meaning |
|
|
220
|
+
| --------------------------- | ----------- | ------------------------------------------------------- |
|
|
221
|
+
| `-d`, `--dir <dir>` | found | Which index — see "Which index gets read" |
|
|
222
|
+
| `--embedding <ref>` | the index's | Must be the one the index was built with |
|
|
223
|
+
| `--direction <d>` | `any` | `input`, `output` or `any` |
|
|
224
|
+
| `--method-type <t>` | `any` | `read_only` (GET/HEAD/OPTIONS) or `read_write` |
|
|
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
|
+
| `--limit <n>` | `5` | Seeds kept per term |
|
|
230
|
+
| `--max-hops <n>` | `3` | How far apart two hits may be and still join |
|
|
231
|
+
| `--max-nodes <n>` | `200` | Nodes per result |
|
|
232
|
+
| `--format <f>` | `text` | `text`, `mermaid`, `mermaid-flowchart`, `ts`, `openapi` |
|
|
233
|
+
| `--show-source` | — | Tag each operation and schema with its document |
|
|
234
|
+
| `--no-docs` | — | Leave the descriptions out |
|
|
235
|
+
| `--interactive` | — | Prompt, search, refine. Needs a terminal |
|
|
236
|
+
| `--quiet` | — | No narration |
|
|
201
237
|
|
|
202
238
|
```sh
|
|
203
239
|
zen rag schema search --method "reset a user password" --format ts
|
|
@@ -281,6 +317,8 @@ think it is?".
|
|
|
281
317
|
| The question | The command |
|
|
282
318
|
| ------------------------------------------------ | ---------------------------------------- |
|
|
283
319
|
| "how do I reset a password with this API?" | `search --method "reset a password"` |
|
|
320
|
+
| _anything you would have run `grep` for_ | `grep` / `list` — never the shell |
|
|
321
|
+
| "which call can reach this field?" | `trace <field>` |
|
|
284
322
|
| "what does the create-user request look like?" | `search --input-type "create user"` |
|
|
285
323
|
| "what operations exist under /users?" | `list methods --path "*/users*"` |
|
|
286
324
|
| "how many operations are there at all?" | `list methods` (or `--json` for `found`) |
|
|
@@ -290,9 +328,9 @@ think it is?".
|
|
|
290
328
|
| "is this index the right one?" | `stats` |
|
|
291
329
|
|
|
292
330
|
The rule: **a question about meaning is a `search`; a question about presence,
|
|
293
|
-
count or spelling is a `list` or a `grep
|
|
294
|
-
|
|
295
|
-
them are right.
|
|
331
|
+
count or spelling is a `list` or a `grep`; a question about reachability is a
|
|
332
|
+
`trace`.** Search cannot answer the last two, because a ranking always returns
|
|
333
|
+
its best guesses whether or not any of them are right.
|
|
296
334
|
|
|
297
335
|
### Exact matching, when the question is whether something exists
|
|
298
336
|
|
|
@@ -307,15 +345,16 @@ zen rag schema grep <pattern> [-d <dir>] [filters…]
|
|
|
307
345
|
|
|
308
346
|
| Flag | For | Meaning |
|
|
309
347
|
| ------------------- | ------ | ---------------------------------------------- |
|
|
310
|
-
| `--name <p>` |
|
|
311
|
-
| `--path <p>` |
|
|
348
|
+
| `--name <p>` | both | Match the name. Repeatable |
|
|
349
|
+
| `--path <p>` | both | Match the route it sits on. Repeatable |
|
|
350
|
+
| `--regex` | both | Read the patterns as regular expressions |
|
|
351
|
+
| `--case-sensitive` | both | Stop ignoring case |
|
|
352
|
+
| `--source <name>` | both | Only one document, as `stats` names it |
|
|
353
|
+
| `--show-source` | both | Print which document each row came from |
|
|
312
354
|
| `--method-type <t>` | `list` | `read_only`, `read_write` or `any` |
|
|
313
355
|
| `--direction <d>` | `list` | `input`, `output` or `any` |
|
|
314
|
-
| `--regex` | `grep` | Read the pattern as a regular expression |
|
|
315
|
-
| `--case-sensitive` | `grep` | Stop ignoring case |
|
|
316
356
|
| `--kind <k>` | `grep` | `method`, `type` or `property`. Repeatable |
|
|
317
357
|
| `--ids-only` | `grep` | Bare ids, one per line, for piping |
|
|
318
|
-
| `--source <name>` | both | Only one document, as `stats` names it |
|
|
319
358
|
| `--limit <n>` | both | Print at most n; `found` still counts them all |
|
|
320
359
|
| `--json` | both | `{found, truncated, rows}` / `…, matches}` |
|
|
321
360
|
| `--quiet` | both | No narration |
|
|
@@ -330,6 +369,7 @@ zen rag schema list properties --name password # every field so named
|
|
|
330
369
|
zen rag schema grep password # every literal occurrence
|
|
331
370
|
zen rag schema grep "pass(word|phrase)" --regex
|
|
332
371
|
zen rag schema grep password --kind type --ids-only
|
|
372
|
+
zen rag schema grep status --path "/invoices/*" # the word, in one corner
|
|
333
373
|
```
|
|
334
374
|
|
|
335
375
|
`list` walks one kind of node and matches its structured fields; `grep` matches
|
|
@@ -338,6 +378,27 @@ so the two agree on what the API says. A pattern with `*` or `?` is a glob
|
|
|
338
378
|
matched against the whole string; a plain word is a substring, so `--name
|
|
339
379
|
password` finds `ResetPasswordPayload` and `--name "Password*"` finds nothing.
|
|
340
380
|
|
|
381
|
+
**`--regex` is the only way to say "one of these"** — a glob has no alternation.
|
|
382
|
+
On `list` it turns every pattern into a regular expression. On `grep` it turns
|
|
383
|
+
the **pattern** into one; `--name` and `--path` stay globs-or-substrings there,
|
|
384
|
+
because they are always names:
|
|
385
|
+
|
|
386
|
+
```sh
|
|
387
|
+
zen rag schema list methods --regex --path "^/(users|teams)/"
|
|
388
|
+
zen rag schema list types --regex --name "(Request|Response)$"
|
|
389
|
+
zen rag schema grep "pass(word|phrase)" --regex --path "*/users*"
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
`--name` and `--path` are constraints on `grep` as well, which is what makes a
|
|
393
|
+
common word usable: `grep status` across a whole API is unreadable,
|
|
394
|
+
`grep status --path "/invoices/*" --kind property` is an answer. On `list
|
|
395
|
+
properties` and on `grep`, `--path` matches the route a parameter's operation
|
|
396
|
+
sits on; a schema belongs to no one route, so `--path` never selects one.
|
|
397
|
+
|
|
398
|
+
When an index holds several documents, `--show-source` puts
|
|
399
|
+
`[source: billing_api_v2]` on every row, so which document answered does not
|
|
400
|
+
have to be recovered from `--json`.
|
|
401
|
+
|
|
341
402
|
Both report `found` as the true total even when `--limit` shortens what is
|
|
342
403
|
printed, so a cut answer never misreports how much there is. Nothing matching
|
|
343
404
|
exits 0 with empty stdout — and that emptiness is trustworthy, which is the
|
|
@@ -349,23 +410,116 @@ whole point of them.
|
|
|
349
410
|
zen rag schema grep token --ids-only | xargs zen rag schema show --format ts
|
|
350
411
|
```
|
|
351
412
|
|
|
413
|
+
### Upwards, from a field to the calls that carry it
|
|
414
|
+
|
|
415
|
+
Finding the field is half the job. The other half — which operation can
|
|
416
|
+
actually reach it — is a walk up the `$ref`s.
|
|
417
|
+
|
|
418
|
+
`search` does part of it: it stitches its seeds into one connected piece and
|
|
419
|
+
prints what each operation accepts and returns, so a lucky search does show the
|
|
420
|
+
call. But it joins only what **ranked**, only within `--max-hops` (3 by
|
|
421
|
+
default), and it never names the chain — and the call almost never repeats the
|
|
422
|
+
word, so `GET /users/{userId}` and `city` have nothing in common except the
|
|
423
|
+
edges between them. `trace` follows those edges instead of guessing at them:
|
|
424
|
+
exhaustive, and certain.
|
|
425
|
+
|
|
426
|
+
```
|
|
427
|
+
zen rag schema trace <pattern|id...> [-d <dir>] [filters…]
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
```sh
|
|
431
|
+
zen rag schema trace city
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
Property:Address.city
|
|
436
|
+
GET /users/{userId} getUser output PublicUserProfile.address → Address.city
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
One command instead of three lookups and a guess: find the field, find what
|
|
440
|
+
holds `Address`, find what accepts _that_, and hope you followed every branch.
|
|
441
|
+
The last column is the whole route, so the shape of the call can be read off
|
|
442
|
+
the answer.
|
|
443
|
+
|
|
444
|
+
| Flag | Default | Meaning |
|
|
445
|
+
| ----------------- | ------------------ | ---------------------------------------------------- |
|
|
446
|
+
| `--kind <k>` | types + properties | `method`, `type` or `property`. Repeatable |
|
|
447
|
+
| `--direction <d>` | `any` | Only the calls that accept it, or that return it |
|
|
448
|
+
| `--max-hops <n>` | `8` | How far up to walk |
|
|
449
|
+
| `--limit <n>` | — | Trace at most n matching nodes |
|
|
450
|
+
| `--routes <n>` | — | Operations printed per node; `found` counts them all |
|
|
451
|
+
| `--ids-only` | — | Bare operation ids, one per line, for piping |
|
|
452
|
+
| `--regex` | — | Read the pattern as a regex; `--case-sensitive` too |
|
|
453
|
+
| `--source <name>` | — | Only nodes from one document |
|
|
454
|
+
| `--show-source` | — | Print which document each operation came from |
|
|
455
|
+
|
|
456
|
+
A bare word matches the way `list --name` does — a substring, or a glob when it
|
|
457
|
+
has `*` or `?`. A node id (`Type:User`) is taken as that node rather than as a
|
|
458
|
+
pattern. Operations are left out of a name match on purpose: they are where a
|
|
459
|
+
trace ends, not where one starts.
|
|
460
|
+
|
|
461
|
+
```sh
|
|
462
|
+
zen rag schema trace password --direction input
|
|
463
|
+
zen rag schema trace "*Settings" --kind type
|
|
464
|
+
zen rag schema trace mfa_secret --ids-only | xargs zen rag schema show --format openapi
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
`no operation reaches it` is a real answer, and one worth having: the schema is
|
|
468
|
+
unreachable in this document, so no request will ever carry it.
|
|
469
|
+
|
|
470
|
+
### Instead of the shell
|
|
471
|
+
|
|
472
|
+
Every reflex that reaches for a shell tool has a command here that answers the
|
|
473
|
+
same question better. Add `-d <dir>` when the index is not the nearest one, or
|
|
474
|
+
name it once with `ZEN_SCHEMA_DB`.
|
|
475
|
+
|
|
476
|
+
| The reflex | The command |
|
|
477
|
+
| --------------------------------------- | ----------------------------------------------------- |
|
|
478
|
+
| `grep -ri password spec.yaml` | `zen rag schema grep password` |
|
|
479
|
+
| `grep -r password` \| _only in schemas_ | `zen rag schema grep password --kind type` |
|
|
480
|
+
| `grep -E "pass(word\|phrase)"` | `zen rag schema grep "pass(word\|phrase)" --regex` |
|
|
481
|
+
| `grep password` (case matters) | `zen rag schema grep password --case-sensitive` |
|
|
482
|
+
| `grep -c` / `wc -l` | `--json`, and read `found` — it counts past `--limit` |
|
|
483
|
+
| `grep -l` / `grep -o` for piping | `zen rag schema grep password --ids-only` |
|
|
484
|
+
| `grep "/users" spec.yaml` | `zen rag schema list methods --path "*/users*"` |
|
|
485
|
+
| `grep -i "updateuser"` | `zen rag schema list methods --name "*Update*"` |
|
|
486
|
+
| `grep "UserSettings"` | `zen rag schema list types --name "*UserSettings*"` |
|
|
487
|
+
| `grep -A5 password` for the field | `zen rag schema list properties --name "*password*"` |
|
|
488
|
+
| `grep -rl password specs/` (which one?) | `zen rag schema grep password --show-source` |
|
|
489
|
+
| `cat`/`yq` a schema out of the document | `zen rag schema show --type UserSettings --format ts` |
|
|
490
|
+
| `ls` the index directory | `zen rag schema stats` |
|
|
491
|
+
|
|
492
|
+
```sh
|
|
493
|
+
export ZEN_SCHEMA_DB=/assets/schema-db # once, then never again
|
|
494
|
+
zen rag schema grep "password" --limit 10
|
|
495
|
+
zen rag schema list methods --path "*user*"
|
|
496
|
+
zen rag schema list types --name "*UserSettings*"
|
|
497
|
+
zen rag schema list properties --name "*password*" --show-source
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
If none of these fits the question, the question is about meaning, and the
|
|
501
|
+
answer is `search` — still not the shell.
|
|
502
|
+
|
|
352
503
|
### Naming what you want in `show`
|
|
353
504
|
|
|
354
505
|
```sh
|
|
355
506
|
zen rag schema show --method GetCurrentUserInfo --format openapi --exact
|
|
356
507
|
zen rag schema show --type "*Invoice*" --format ts
|
|
357
508
|
zen rag schema show --source billing-api --format openapi
|
|
509
|
+
zen rag schema show --type "*Invoice*" --show-source
|
|
358
510
|
```
|
|
359
511
|
|
|
360
512
|
Ids are one way in, but `--method` and `--type` take the names you already
|
|
361
513
|
have. A bare name means exactly that name; add `*` to take more than one.
|
|
362
|
-
`--
|
|
363
|
-
|
|
364
|
-
|
|
514
|
+
`--show-source` names the document each node came from, which is the quick way
|
|
515
|
+
to tell two versions of the same API apart. `--exact` prints only what was
|
|
516
|
+
named instead of the neighbourhood around it, which with `--format openapi`
|
|
517
|
+
gives a valid self-contained slice of the specification — enough to generate a
|
|
518
|
+
client or a mock payload from.
|
|
365
519
|
|
|
366
520
|
## Giving it to an agent
|
|
367
521
|
|
|
368
|
-
The same engine, as
|
|
522
|
+
The same engine, as six tools in the group `schema`. An agent takes them all
|
|
369
523
|
with `schema:*` in its `tools:`.
|
|
370
524
|
|
|
371
525
|
```ts
|
|
@@ -386,18 +540,103 @@ const project = await loadProject('./my-project', { tools: schemaTools(index) })
|
|
|
386
540
|
| `find_types_with_property` | every schema with a field of this name — exact lookup, no searching |
|
|
387
541
|
| `list_api` | methods, types or fields by name — complete, and counted in full |
|
|
388
542
|
| `grep_api` | every literal occurrence of a string — the way to prove absence |
|
|
543
|
+
| `trace_api` | up from a field or schema to the operations that carry it |
|
|
389
544
|
|
|
390
|
-
Only `search_api` ranks; the other
|
|
545
|
+
Only `search_api` ranks; the other five are exact. `find_types_with_property`
|
|
391
546
|
is the one for the repair loop. When `tsc` says `'password' does not exist in
|
|
392
547
|
type 'PublicUserProfile'`, the model does not need the word explained again —
|
|
393
548
|
it needs the list of types that _do_ have one, and embedding the word will only
|
|
394
549
|
rank the guess it already made near the top. `grep_api` is the same instinct
|
|
395
550
|
widened: it is how a model checks that a search returning nothing really means
|
|
396
|
-
there is nothing.
|
|
551
|
+
there is nothing. `trace_api` is the step after either of them: a field is of
|
|
552
|
+
no use until the call that carries it is known, and no ranking will find that
|
|
553
|
+
call — the operation and the field share no words, only edges.
|
|
554
|
+
|
|
555
|
+
`list_api` and `grep_api` take `name`, `path`, `regex` and `source`, so a
|
|
556
|
+
common word can be narrowed to one route or one document rather than read out
|
|
557
|
+
in full. When an index holds more than one document, both tools name the source
|
|
558
|
+
of every row without being asked — with two versions of the same API indexed
|
|
559
|
+
together, which one answered is part of the answer.
|
|
397
560
|
|
|
398
561
|
Tell the agent in its prompt to search before it writes a call, and to put the
|
|
399
562
|
intent in the narrow field. A model left to itself puts everything in `all`.
|
|
400
563
|
|
|
564
|
+
## Wiring it into a project means writing the project a skill
|
|
565
|
+
|
|
566
|
+
**Whenever an index is used by a Zenera project — as `schema:*` tools, or as
|
|
567
|
+
`zen rag` reachable from the agent's sandbox — write a skill for it in that
|
|
568
|
+
project.** Not optional, and not the same thing as passing the tools in.
|
|
569
|
+
|
|
570
|
+
Wiring alone leaves the model to infer everything that matters. A tool
|
|
571
|
+
description says what `grep_api` does; it cannot say that this index holds the
|
|
572
|
+
NSX policy API, that names are `snake_case`, that every route is under
|
|
573
|
+
`/policy/api/v1`, or that `list_api` is the right first move here because the
|
|
574
|
+
API has three hundred operations and search will hand back five. That is
|
|
575
|
+
project knowledge, and project knowledge belongs in a skill — where it is
|
|
576
|
+
loaded only when the model is actually working on this API, instead of sitting
|
|
577
|
+
in the system prompt of every run.
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
<project>/agents/skills/<api>-api/SKILL.md
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
Frontmatter is `name` and `description`; the description is what the model
|
|
584
|
+
reads when choosing, so it must name the API and the questions it answers.
|
|
585
|
+
Add `tools: [search_api, list_api, grep_api, trace_api, describe_types,
|
|
586
|
+
find_types_with_property]` if the skill should be what unlocks them.
|
|
587
|
+
|
|
588
|
+
### What the skill has to say
|
|
589
|
+
|
|
590
|
+
| Section | Because |
|
|
591
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
592
|
+
| Which API | The name, the version, and the document it was built from |
|
|
593
|
+
| Where the index | `ZEN_SCHEMA_DB`, or the `-d` to pass — an agent cannot guess a path |
|
|
594
|
+
| Which command | Meaning → `search`; presence, spelling or a count → `list`/`grep`; which endpoint carries a field → `trace` |
|
|
595
|
+
| Never the shell | State it outright. `grep`/`rg`/`jq` on the spec is the default reflex |
|
|
596
|
+
| The conventions | Auth, base path, pagination, casing, error envelope — none of it is in the graph |
|
|
597
|
+
| Worked examples | Two or three, with **real operation and schema names from this index** |
|
|
598
|
+
| The repair loop | Compiler said the field is not on the type → `find_types_with_property`, then `trace` for the call that carries it |
|
|
599
|
+
|
|
600
|
+
Best practice, in order of how often it is got wrong:
|
|
601
|
+
|
|
602
|
+
1. **Use real names.** `list_api types --name "*Policy*"` with output the model
|
|
603
|
+
will actually see beats a generic `<TypeName>` placeholder, because the
|
|
604
|
+
names are the anchors it steers by.
|
|
605
|
+
2. **Say which command answers which question**, and say that a ranking cannot
|
|
606
|
+
prove absence. Left alone a model searches for everything, gets five ranked
|
|
607
|
+
guesses, and writes a call against the best of them.
|
|
608
|
+
3. **Keep it short.** A skill is prompt. One screen of routing rules and
|
|
609
|
+
conventions beats a transcription of this document — link to `zen rag
|
|
610
|
+
schema --help` for the flags.
|
|
611
|
+
4. **Re-index, then re-read the skill.** Both go stale against the same
|
|
612
|
+
change, and a skill quoting operations that no longer exist is worse than
|
|
613
|
+
none.
|
|
614
|
+
5. **One skill per API**, named after it. Two APIs in one skill and the model
|
|
615
|
+
mixes their conventions.
|
|
616
|
+
|
|
617
|
+
```md
|
|
618
|
+
---
|
|
619
|
+
name: billing-api
|
|
620
|
+
description: How to find the right call in the Acme Billing API (v2) — which schema
|
|
621
|
+
carries which field, and which endpoint accepts it. Use before writing any request.
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
# The Billing API
|
|
625
|
+
|
|
626
|
+
Indexed at `/assets/schema-db` (already in `$ZEN_SCHEMA_DB`). 214 operations,
|
|
627
|
+
all under `/v2`. Bearer token in `Authorization`; cursors, never page numbers.
|
|
628
|
+
|
|
629
|
+
- Vague question ("how do I cancel a subscription?") → `search_api`, intent in
|
|
630
|
+
the narrowest field: `methods`, not `all`.
|
|
631
|
+
- Does X exist, how is it spelled, how many are there → `list_api` / `grep_api`.
|
|
632
|
+
These are complete; a search is not, and cannot prove absence.
|
|
633
|
+
- Which endpoint carries this field → `trace_api`. Never guess the owner.
|
|
634
|
+
- Never `grep`/`rg`/`jq` the spec — the tools above are local and exact.
|
|
635
|
+
|
|
636
|
+
Worked: the invoice total is `Invoice.amount_due` (minor units), returned by
|
|
637
|
+
`GetInvoice` and `ListInvoices`; `trace_api of: amount_due` shows both.
|
|
638
|
+
```
|
|
639
|
+
|
|
401
640
|
## When it goes wrong
|
|
402
641
|
|
|
403
642
|
| Symptom | Cause |
|
|
@@ -28,7 +28,7 @@ zen sandbox [status|up|pull|clean|disk] [options]
|
|
|
28
28
|
zen version
|
|
29
29
|
|
|
30
30
|
zen faker <serve|build|cache> [spec...]
|
|
31
|
-
zen rag schema <index|search|list|grep|show|stats> [spec...]
|
|
31
|
+
zen rag schema <index|search|list|grep|trace|show|stats> [spec...]
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Read the reference before answering
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# API search — `zen rag`
|
|
2
2
|
|
|
3
3
|
```
|
|
4
|
-
zen rag schema <index|search|list|grep|show|stats> [spec...]
|
|
4
|
+
zen rag schema <index|search|list|grep|trace|show|stats> [spec...]
|
|
5
5
|
```
|
|
6
6
|
|
|
7
7
|
Provided by `@zenera/rag` — `npm i -g @zenera/rag` if `zen rag` says it is not
|
|
@@ -25,8 +25,10 @@ zen rag schema index <spec...> [--embedding <ref>] [-o <dir>] [--batch <n>]
|
|
|
25
25
|
| Flag | Default | Meaning |
|
|
26
26
|
| ------------------- | ------------- | ------------------------------------------------------------ |
|
|
27
27
|
| `--embedding <ref>` | — | Which embedder makes the vectors. Omit it to see the choices |
|
|
28
|
-
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes
|
|
28
|
+
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes; `$ZEN_SCHEMA_DB` if set |
|
|
29
29
|
| `--batch <n>` | `96` | Texts per embedding request, and how often progress prints |
|
|
30
|
+
| `--no-sources` | — | Keep no copy of the documents in the index |
|
|
31
|
+
| `--quiet` | — | No narration |
|
|
30
32
|
|
|
31
33
|
```
|
|
32
34
|
zen rag schema index openapi.yaml --embedding openai:text-embedding-3-small
|
|
@@ -49,6 +51,21 @@ lance/ the vector and full-text indexes
|
|
|
49
51
|
The manifest records the embedding ref **and** the embedder's own id, so a
|
|
50
52
|
search with a different model is refused rather than quietly returning nonsense.
|
|
51
53
|
|
|
54
|
+
## Which index gets read
|
|
55
|
+
|
|
56
|
+
Every reading command takes `-d`, `--dir`. Without one:
|
|
57
|
+
|
|
58
|
+
1. `$ZEN_SCHEMA_DB`, if it is set.
|
|
59
|
+
2. Otherwise the **nearest index** to the working directory — here, then a
|
|
60
|
+
short way down, then up a level and again, stopping at your home directory.
|
|
61
|
+
The one used is named on stderr.
|
|
62
|
+
3. Otherwise `./schema-db`, so the error names the directory you expected.
|
|
63
|
+
|
|
64
|
+
What is looked for is a `manifest.json`, not a directory called `schema-db`, so
|
|
65
|
+
an index called anything else is found the same way. Two the same distance away
|
|
66
|
+
is refused rather than guessed at — name one with `-d`, or set `ZEN_SCHEMA_DB`
|
|
67
|
+
once and stop typing it.
|
|
68
|
+
|
|
52
69
|
## `search`
|
|
53
70
|
|
|
54
71
|
```
|
|
@@ -84,23 +101,24 @@ search good. A request field belongs in `--input-property`, a response field in
|
|
|
84
101
|
|
|
85
102
|
### Filters and shape
|
|
86
103
|
|
|
87
|
-
| Flag | Default
|
|
88
|
-
| --------------------------- |
|
|
89
|
-
| `-d`, `--dir <dir>` |
|
|
90
|
-
| `--embedding <ref>` | the index's
|
|
91
|
-
| `--direction <d>` | `any`
|
|
92
|
-
| `--method-type <t>` | `any`
|
|
93
|
-
| `--exclude-id <id>` | —
|
|
94
|
-
| `--exclude-method <name>` | —
|
|
95
|
-
| `--exclude-type <name>` | —
|
|
96
|
-
| `--exclude-property <name>` | —
|
|
97
|
-
| `--limit <n>` | `5`
|
|
98
|
-
| `--max-hops <n>` | `3`
|
|
99
|
-
| `--max-nodes <n>` | `200`
|
|
100
|
-
| `--format <f>` | `text`
|
|
101
|
-
| `--
|
|
102
|
-
| `--
|
|
103
|
-
| `--
|
|
104
|
+
| Flag | Default | Meaning |
|
|
105
|
+
| --------------------------- | ----------- | ------------------------------------------------------- |
|
|
106
|
+
| `-d`, `--dir <dir>` | found | Which index — see "Which index gets read" |
|
|
107
|
+
| `--embedding <ref>` | the index's | Must be the one the index was built with |
|
|
108
|
+
| `--direction <d>` | `any` | `input`, `output` or `any` |
|
|
109
|
+
| `--method-type <t>` | `any` | `read_only`, `read_write` or `any` |
|
|
110
|
+
| `--exclude-id <id>` | — | Drop a node. Repeatable |
|
|
111
|
+
| `--exclude-method <name>` | — | Drop an operation by name. Repeatable |
|
|
112
|
+
| `--exclude-type <name>` | — | Drop a schema by name. Repeatable |
|
|
113
|
+
| `--exclude-property <name>` | — | Drop a field by name. Repeatable |
|
|
114
|
+
| `--limit <n>` | `5` | Seeds kept per term |
|
|
115
|
+
| `--max-hops <n>` | `3` | How far apart two hits may be |
|
|
116
|
+
| `--max-nodes <n>` | `200` | Nodes per result |
|
|
117
|
+
| `--format <f>` | `text` | `text`, `mermaid`, `mermaid-flowchart`, `ts`, `openapi` |
|
|
118
|
+
| `--show-source` | — | Tag each operation and schema with its document |
|
|
119
|
+
| `--no-docs` | — | Leave the descriptions out |
|
|
120
|
+
| `--interactive` | — | Prompt, search, refine. Needs a terminal |
|
|
121
|
+
| `--quiet` | — | No narration |
|
|
104
122
|
|
|
105
123
|
```
|
|
106
124
|
zen rag schema search --method "reset a user password" --format ts
|
|
@@ -135,7 +153,7 @@ quit
|
|
|
135
153
|
|
|
136
154
|
```
|
|
137
155
|
zen rag schema list <methods|types|properties> [-d <dir>] [--name <p>] [--path <p>]
|
|
138
|
-
zen rag schema grep <pattern> [-d <dir>] [--
|
|
156
|
+
zen rag schema grep <pattern> [-d <dir>] [--name <p>] [--path <p>] [--kind <k>]
|
|
139
157
|
```
|
|
140
158
|
|
|
141
159
|
Exact, and therefore complete. `search` ranks, so it can only hand back the top
|
|
@@ -144,26 +162,44 @@ read `graph.json` directly, with no embedder, no credential and no network.
|
|
|
144
162
|
|
|
145
163
|
| Flag | For | Meaning |
|
|
146
164
|
| ------------------- | ------ | -------------------------------------------- |
|
|
147
|
-
| `--name <p>` |
|
|
148
|
-
| `--path <p>` |
|
|
165
|
+
| `--name <p>` | both | Match the name. Repeatable |
|
|
166
|
+
| `--path <p>` | both | Match the route it sits on. Repeatable |
|
|
167
|
+
| `--regex` | both | Read the patterns as regular expressions |
|
|
168
|
+
| `--case-sensitive` | both | Stop ignoring case |
|
|
149
169
|
| `--source <name>` | both | Only nodes from one document |
|
|
170
|
+
| `--show-source` | both | Print which document each row came from |
|
|
150
171
|
| `--method-type <t>` | `list` | `read_only`, `read_write` or `any` |
|
|
151
172
|
| `--direction <d>` | `list` | `input`, `output` or `any` |
|
|
152
|
-
| `--regex` | `grep` | Read the pattern as a regular expression |
|
|
153
|
-
| `--case-sensitive` | `grep` | Stop ignoring case |
|
|
154
173
|
| `--kind <k>` | `grep` | `method`, `type` or `property`. Repeatable |
|
|
155
174
|
| `--ids-only` | `grep` | Just the ids, one per line, for piping |
|
|
156
175
|
| `--limit <n>` | both | Rows to print. `found` still counts them all |
|
|
176
|
+
| `--quiet` | both | No narration |
|
|
177
|
+
|
|
178
|
+
Under `--json`: `{found, truncated, rows}` from `list`, `{found, truncated,
|
|
179
|
+
matches}` from `grep`. `grep` takes **one** pattern — quote it if it has
|
|
180
|
+
spaces — and `list` **one** subject.
|
|
157
181
|
|
|
158
182
|
A pattern with `*` or `?` is a glob matched against the whole string; a plain
|
|
159
183
|
word is a substring. So `--name password` finds `ResetPasswordPayload`, and
|
|
160
|
-
`--name "Password*"` finds nothing, because nothing starts with it.
|
|
184
|
+
`--name "Password*"` finds nothing, because nothing starts with it. `--regex`
|
|
185
|
+
makes it a regular expression instead — the only way to say "one of these". On
|
|
186
|
+
`list` it applies to every pattern; on `grep` it applies to the pattern, while
|
|
187
|
+
`--name` and `--path` stay globs-or-substrings:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
zen rag schema list methods --regex --path "^/(users|teams)/"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`--path` selects on the route an operation sits on, and on the route a
|
|
194
|
+
parameter's operation sits on. A schema belongs to no one route, so `--path`
|
|
195
|
+
never selects one.
|
|
161
196
|
|
|
162
197
|
```
|
|
163
198
|
zen rag schema list methods --path "*/users*"
|
|
164
199
|
zen rag schema list types --name "*Password*"
|
|
165
200
|
zen rag schema grep password
|
|
166
201
|
zen rag schema grep "pass(word|phrase)" --regex
|
|
202
|
+
zen rag schema grep status --path "/invoices/*" --kind property
|
|
167
203
|
zen rag schema grep token --ids-only | xargs zen rag schema show --format ts
|
|
168
204
|
```
|
|
169
205
|
|
|
@@ -171,11 +207,71 @@ No match exits 0 with nothing on stdout — that is the answer, and unlike an
|
|
|
171
207
|
empty search it is a reliable one. Under `--limit`, `found` is still the true
|
|
172
208
|
total, so a shortened answer never misreports how much there is.
|
|
173
209
|
|
|
210
|
+
## `trace`
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
zen rag schema trace <pattern|id...> [-d <dir>] [--kind <k>] [--direction <d>]
|
|
214
|
+
[--max-hops <n>] [--limit <n>] [--routes <n>]
|
|
215
|
+
[--ids-only] [--regex] [--case-sensitive] [--source <name>]
|
|
216
|
+
[--show-source]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The question `list` and `grep` leave you holding: you have found the field, so
|
|
220
|
+
**which call can reach it?** `trace` walks up the `$ref`s from every node of
|
|
221
|
+
that name to the operations that accept or return it, and prints the chain in
|
|
222
|
+
between. Also a plain graph read — no embedder, no credential.
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
zen rag schema trace city
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
Property:Address.city
|
|
230
|
+
GET /users/{userId} getUser output PublicUserProfile.address → Address.city
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
By hand that is three lookups and a guess: find the field, find what holds
|
|
234
|
+
`Address`, find what accepts _that_, and hope you followed every branch.
|
|
235
|
+
|
|
236
|
+
`search` does some of this already — it stitches its seeds into one connected
|
|
237
|
+
piece and prints what each operation accepts and returns. But it links only
|
|
238
|
+
what **ranked**, only within `--max-hops`, and it never names the chain; and
|
|
239
|
+
`getUser` and `city` share no word, so the field has to rank on its own and the
|
|
240
|
+
call has to land near it. `trace` follows the edges instead, which are already
|
|
241
|
+
there and are certain.
|
|
242
|
+
|
|
243
|
+
| Flag | Default | Meaning |
|
|
244
|
+
| ----------------- | ------------------ | ---------------------------------------------------- |
|
|
245
|
+
| `--kind <k>` | types + properties | `method`, `type` or `property`. Repeatable |
|
|
246
|
+
| `--direction <d>` | `any` | Keep only the calls that accept it, or return it |
|
|
247
|
+
| `--max-hops <n>` | `8` | How far up to walk |
|
|
248
|
+
| `--limit <n>` | — | Trace at most n matching nodes |
|
|
249
|
+
| `--routes <n>` | — | Operations printed per node; `found` counts them all |
|
|
250
|
+
| `--ids-only` | — | Bare operation ids, one per line, for piping |
|
|
251
|
+
| `--regex` | — | Read the pattern as a regex; `--case-sensitive` too |
|
|
252
|
+
| `--source <name>` | — | Only nodes from one document |
|
|
253
|
+
| `--show-source` | — | Print which document each operation came from |
|
|
254
|
+
|
|
255
|
+
A bare word is matched the way `list --name` matches it — substring, or a glob
|
|
256
|
+
when it has `*` or `?`. A node id (`Type:User`) is taken as that node and not
|
|
257
|
+
as a pattern. Operations are left out of a name match on purpose: they are
|
|
258
|
+
where a trace ends.
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
zen rag schema trace password --direction input
|
|
262
|
+
zen rag schema trace "*Settings" --kind type
|
|
263
|
+
zen rag schema trace mfa_secret --ids-only | xargs zen rag schema show --format openapi
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
A node nothing carries prints `no operation reaches it` — a real answer, and
|
|
267
|
+
one worth having: it means the schema is unreachable in this document.
|
|
268
|
+
|
|
174
269
|
## `show`
|
|
175
270
|
|
|
176
271
|
```
|
|
177
|
-
zen rag schema show [id...] [-d <dir>] [--format <f>]
|
|
178
|
-
[--method <name>] [--type <name>] [--source <name>]
|
|
272
|
+
zen rag schema show [id...] [-d <dir>] [--format <f>] [--exact]
|
|
273
|
+
[--method <name>] [--type <name>] [--source <name>]
|
|
274
|
+
[--show-source] [--max-nodes <n>] [--no-docs] [--quiet]
|
|
179
275
|
```
|
|
180
276
|
|
|
181
277
|
Prints named nodes with no search in between. Needs no embedder and no
|
|
@@ -183,9 +279,19 @@ credential — it is a read of the graph.
|
|
|
183
279
|
|
|
184
280
|
Ids are one way in; `--method` and `--type` name things directly, which is
|
|
185
281
|
usually what you have. A bare name means exactly that name; add `*` to select
|
|
186
|
-
more than one. `--source <name>` takes a whole document
|
|
187
|
-
|
|
188
|
-
|
|
282
|
+
more than one. `--source <name>` takes a whole document, and `--show-source`
|
|
283
|
+
tags each node with the document it came from. `--exact` prints only what was
|
|
284
|
+
named instead of the neighbourhood around it — with `--format openapi` that is
|
|
285
|
+
a valid, self-contained slice of the specification. Without it the neighbours
|
|
286
|
+
are stitched in, up to `--max-nodes`.
|
|
287
|
+
|
|
288
|
+
`--source <name> --format openapi` with nothing else named prints the
|
|
289
|
+
**verbatim** document as it was indexed, unless the index was built
|
|
290
|
+
`--no-sources`, in which case it is rebuilt from the graph and says so.
|
|
291
|
+
|
|
292
|
+
A name that matches nothing is an **error**, not an empty answer: naming
|
|
293
|
+
something is a claim that it is there, and `list --name` is the command for
|
|
294
|
+
asking whether it is.
|
|
189
295
|
|
|
190
296
|
```
|
|
191
297
|
zen rag schema show --method GetCurrentUserInfo --format openapi --exact
|
|
@@ -212,10 +318,12 @@ documents it came from. Also needs no embedder.
|
|
|
212
318
|
| `find_types_with_property` | Every schema with a field of this name — exact lookup, no searching |
|
|
213
319
|
| `list_api` | Methods, types or fields by name — complete, and counted in full |
|
|
214
320
|
| `grep_api` | Every literal occurrence of a string — the way to prove absence |
|
|
321
|
+
| `trace_api` | Up from a field or schema to the operations that carry it |
|
|
215
322
|
|
|
216
323
|
Only `search_api` ranks. Reach for the others whenever the question is whether
|
|
217
324
|
something exists, because a search that returns nothing and a thing that is not
|
|
218
|
-
there look exactly the same.
|
|
325
|
+
there look exactly the same. `trace_api` is the one for after a field has been
|
|
326
|
+
found and the endpoint to call is what is actually wanted.
|
|
219
327
|
|
|
220
328
|
They share the group `schema`, so an agent takes them with `schema:*` in its
|
|
221
329
|
`tools:`.
|