@zenera/cli 1.1.2 → 1.1.4
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 +228 -31
- package/dist/audit.d.ts +13 -8
- package/dist/audit.js +21 -24
- package/dist/catalog.d.ts +111 -0
- package/dist/catalog.js +439 -0
- package/dist/commands/check.js +72 -17
- package/dist/commands/index.d.ts +2 -2
- package/dist/commands/index.js +3 -2
- package/dist/commands/init.js +71 -11
- package/dist/commands/key.js +144 -36
- package/dist/commands/models.d.ts +0 -6
- package/dist/commands/models.js +546 -101
- package/dist/commands/open.js +2 -2
- package/dist/commands/run.js +3 -0
- package/dist/engine.d.ts +2 -0
- package/dist/engine.js +1 -0
- package/dist/home.d.ts +2 -0
- package/dist/home.js +2 -0
- package/dist/keys.d.ts +104 -13
- package/dist/keys.js +175 -34
- package/dist/lib.d.ts +2 -1
- package/dist/lib.js +2 -1
- package/dist/liveness.d.ts +48 -6
- package/dist/liveness.js +268 -28
- package/dist/sandbox.d.ts +2 -0
- package/dist/sandbox.js +58 -7
- package/dist/scaffold.d.ts +21 -21
- package/dist/scaffold.js +132 -204
- package/dist/validate.d.ts +17 -1
- package/dist/validate.js +100 -10
- package/package.json +2 -18
- package/templates/{.github → editor/.github}/copilot-instructions.md +37 -9
- package/templates/editor/.github/skills/api-schema-index/SKILL.md +292 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +77 -0
- package/templates/editor/.github/skills/zen-cli/references/check.md +88 -0
- package/templates/editor/.github/skills/zen-cli/references/faker.md +111 -0
- package/templates/editor/.github/skills/zen-cli/references/frame.md +119 -0
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +61 -0
- package/templates/editor/.github/skills/zen-cli/references/keys.md +119 -0
- package/templates/editor/.github/skills/zen-cli/references/models.md +108 -0
- package/templates/editor/.github/skills/zen-cli/references/projects.md +99 -0
- package/templates/editor/.github/skills/zen-cli/references/rag.md +159 -0
- package/templates/editor/.github/skills/zen-cli/references/run.md +104 -0
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +91 -0
- package/templates/editor/.vscode/settings.json +6 -0
- package/templates/parts/exa.yaml.tmpl +5 -0
- package/templates/parts/model.yaml.tmpl +4 -0
- package/templates/parts/models.yaml.tmpl +10 -0
- package/templates/project/INSTRUCTIONS.md +7 -0
- package/templates/project/SPECIFICATION.md +6 -0
- package/templates/project/agents/prompts/default.md +15 -0
- package/templates/project/agents.yaml.tmpl +44 -0
- package/templates/project/assets/README.md +12 -0
- package/templates/project/gitignore +9 -0
- package/templates/{sandbox → project/sandbox}/Dockerfile +2 -0
- package/templates/.github/skills/zen-cli/SKILL.md +0 -110
- /package/templates/{.github → editor/.github}/prompts/new-agent.prompt.md +0 -0
- /package/templates/{.github → editor/.github}/prompts/new-skill.prompt.md +0 -0
- /package/templates/{.github → editor/.github}/prompts/review-project.prompt.md +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# The frame
|
|
2
|
+
|
|
3
|
+
What is true of every command, whichever one is being run.
|
|
4
|
+
|
|
5
|
+
## Invocation
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
zen <command> [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Three names run the same program: `zen`, `zn` and `zenera`. Help and error
|
|
12
|
+
hints name the binary that was actually invoked, so `zn run` is spelled `zn`
|
|
13
|
+
back at you.
|
|
14
|
+
|
|
15
|
+
## Global options
|
|
16
|
+
|
|
17
|
+
| Flag | Meaning |
|
|
18
|
+
| ----------------------- | -------------------------------------------------------- |
|
|
19
|
+
| `-h`, `--help` | The command list, or a command's own help |
|
|
20
|
+
| `-v`, `--version` | The version, and nothing else |
|
|
21
|
+
| `--json` | Machine-readable output on stdout instead of a rendering |
|
|
22
|
+
| `-C`, `--directory <d>` | Act as if run in `<d>` |
|
|
23
|
+
|
|
24
|
+
These are lifted out of the argument list before a command parses its own
|
|
25
|
+
flags, so they work in any position and a command never declares them itself.
|
|
26
|
+
Everything after the command name belongs to that command.
|
|
27
|
+
|
|
28
|
+
## Aliases
|
|
29
|
+
|
|
30
|
+
Not listed in help, but they work.
|
|
31
|
+
|
|
32
|
+
| Alias | Command |
|
|
33
|
+
| -------------------- | --------- |
|
|
34
|
+
| `ls` | `list` |
|
|
35
|
+
| `new` | `init` |
|
|
36
|
+
| `keys` | `key` |
|
|
37
|
+
| `validate`, `doctor` | `check` |
|
|
38
|
+
| `report` | `inspect` |
|
|
39
|
+
| `edit`, `code` | `open` |
|
|
40
|
+
| `mock` | `faker` |
|
|
41
|
+
|
|
42
|
+
## stdout is the answer, stderr is the narration
|
|
43
|
+
|
|
44
|
+
The answer to what was asked goes to stdout: a model's reply, a report, a list.
|
|
45
|
+
Progress, banners, warnings and the spinner go to stderr. So
|
|
46
|
+
`zen run acme "…" > answer.md` captures the answer and nothing else, and
|
|
47
|
+
`2>/dev/null` silences everything but it.
|
|
48
|
+
|
|
49
|
+
`--json` applies to every command and prints one machine-readable document on
|
|
50
|
+
stdout in place of the rendered form. Under `--json` nothing is asked
|
|
51
|
+
interactively — the questions a run would ask are taken as answered.
|
|
52
|
+
|
|
53
|
+
The banner is drawn only when stderr is a terminal, so a piped invocation never
|
|
54
|
+
sees it.
|
|
55
|
+
|
|
56
|
+
## Exit codes
|
|
57
|
+
|
|
58
|
+
| Code | Name | Means |
|
|
59
|
+
| ---- | ----------- | ---------------------------------------------------------- |
|
|
60
|
+
| 0 | ok | It worked |
|
|
61
|
+
| 1 | failed | It ran and did not succeed |
|
|
62
|
+
| 2 | usage | The command line was wrong |
|
|
63
|
+
| 3 | invalid | The project is not valid — bad `agents.yaml`, missing file |
|
|
64
|
+
| 4 | credentials | No usable credential for what was asked |
|
|
65
|
+
| 5 | sandbox | No container engine, or the image could not be prepared |
|
|
66
|
+
|
|
67
|
+
A wrong invocation and a wrong answer are deliberately not the same code, which
|
|
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 — …`.
|
|
70
|
+
Read it rather than guessing: the loader is strict on purpose and an unknown key
|
|
71
|
+
is an error, not a value quietly ignored.
|
|
72
|
+
|
|
73
|
+
## Which project
|
|
74
|
+
|
|
75
|
+
Most commands operate on a project directory, resolved in this order:
|
|
76
|
+
|
|
77
|
+
1. `--project <name|dir>` — a registry name or a path.
|
|
78
|
+
2. The working directory, if it is a project (or is inside one).
|
|
79
|
+
3. For `zen run`, a bare first word that names a registered project.
|
|
80
|
+
|
|
81
|
+
`zen check` is the exception: its bare argument is a directory if one is there
|
|
82
|
+
and a registered name otherwise, and it needs no `zenera.json`, so an
|
|
83
|
+
unregistered directory can still be validated.
|
|
84
|
+
|
|
85
|
+
## Environment
|
|
86
|
+
|
|
87
|
+
| Variable | Effect |
|
|
88
|
+
| ------------------ | ----------------------------------------------------- |
|
|
89
|
+
| `ZENERA_HOME` | Moves the whole home tree. Default `~/.zenera/neo` |
|
|
90
|
+
| `ZENERA_THEME` | `dark`, `light` or `auto` for the TUI palette |
|
|
91
|
+
| `ZENERA_EDITOR` | The editor `zen open` launches |
|
|
92
|
+
| `ZENERA_DEBUG` | Print a stack trace when something unexpected escapes |
|
|
93
|
+
| `VISUAL`, `EDITOR` | Consulted by `zen open` after `ZENERA_EDITOR` |
|
|
94
|
+
| `COLORFGBG` | Read as a hint when the palette is being detected |
|
|
95
|
+
| Provider keys | `OPENAI_API_KEY` and friends — see [keys.md](keys.md) |
|
|
96
|
+
|
|
97
|
+
A real environment variable always beats the keyring.
|
|
98
|
+
|
|
99
|
+
## Where things live
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
~/.zenera/neo/ the home tree (0700)
|
|
103
|
+
projects.json the registry: name -> directory
|
|
104
|
+
keys.json credentials (0600)
|
|
105
|
+
keys/ key files, for providers that hold a file
|
|
106
|
+
faker/ generator cache for `zen faker`
|
|
107
|
+
|
|
108
|
+
<project>/
|
|
109
|
+
zenera.json { version, name }
|
|
110
|
+
INSTRUCTIONS.md house rules, prepended to every agent's prompt
|
|
111
|
+
agents.yaml the configuration
|
|
112
|
+
agents/prompts/ one .md per agent
|
|
113
|
+
agents/skills/ one directory per skill, each with SKILL.md
|
|
114
|
+
sandbox/Dockerfile the image commands run in, when the project builds one
|
|
115
|
+
sessions/ run state, memory, blobs, reports — never committed
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Credential files are refused if anyone but the owner can read them, the way
|
|
119
|
+
`ssh` refuses a loose private key: `chmod 600` and try again.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Reports — `zen inspect`
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
zen inspect [run] [--session <id>] [--open] [--rebuild] [--serve [port]]
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Alias: `report`.
|
|
8
|
+
|
|
9
|
+
Renders the trajectory of a run: every message, tool call, skill activation and
|
|
10
|
+
hand-off, in order, with what each one cost. With no arguments it takes the
|
|
11
|
+
newest run of the newest session.
|
|
12
|
+
|
|
13
|
+
| Flag | Meaning |
|
|
14
|
+
| ---------------- | ------------------------------------------------------- |
|
|
15
|
+
| `[run]` | A run id. The newest otherwise |
|
|
16
|
+
| `--session <id>` | Which session the run belongs to |
|
|
17
|
+
| `--open` | Open the report in a browser |
|
|
18
|
+
| `--rebuild` | Rebuild `report.html` from the recorded state |
|
|
19
|
+
| `--serve [port]` | Serve it locally, which the report needs for its assets |
|
|
20
|
+
|
|
21
|
+
Use `--serve` rather than opening the file directly when the report has media in
|
|
22
|
+
it; the page fetches its assets and `file://` will not give them to it.
|
|
23
|
+
|
|
24
|
+
## Why it is the first thing to look at
|
|
25
|
+
|
|
26
|
+
It shows what the model was actually given, which is rarely what you assumed. A
|
|
27
|
+
prompt that reads correctly and behaves wrongly is nearly always a prompt that
|
|
28
|
+
was assembled differently from how it looks in the repository: a skill that did
|
|
29
|
+
not activate, a hand-off that fired early, a tool that was withheld, an asset
|
|
30
|
+
that was not attached.
|
|
31
|
+
|
|
32
|
+
The report also draws the architecture — agents, their tools, their hand-offs —
|
|
33
|
+
and falls back to reconstructing the wiring from the trajectory when the run
|
|
34
|
+
did not record it.
|
|
35
|
+
|
|
36
|
+
## Where it comes from
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
<project>/sessions/<session-id>/runs/<run-id>/
|
|
40
|
+
input.md what was asked
|
|
41
|
+
output.md what came back
|
|
42
|
+
state.json the whole trajectory
|
|
43
|
+
report.html the rendering, rebuilt from state.json on demand
|
|
44
|
+
meta.json when it ran, how long it took
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Ids are timestamps: `20260825-143012-a7f3`. Listing them is `zen list --sessions`.
|
|
48
|
+
|
|
49
|
+
Large images are lifted out of the recorded state and stored alongside it, so a
|
|
50
|
+
photograph re-sent on every turn does not bloat every message. The report
|
|
51
|
+
resolves them back.
|
|
52
|
+
|
|
53
|
+
## What it prints
|
|
54
|
+
|
|
55
|
+
The path to `report.html` on stdout — it is the answer, so it pipes. `--json`
|
|
56
|
+
gives `{ session, run, report }` instead. A report that is missing is built
|
|
57
|
+
before either; `--rebuild` builds one that already exists again, which is always
|
|
58
|
+
safe because the report is derived and `state.json` is the truth. That is also
|
|
59
|
+
what makes an old run readable by a newer renderer.
|
|
60
|
+
|
|
61
|
+
To assert on a run in a script, read `state.json` rather than the report.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Credentials — `zen key`
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
zen key <ls|add|use|check|rm|show|env> [ref] [options]
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Alias: `keys`.
|
|
8
|
+
|
|
9
|
+
Keys live in `~/.zenera/neo/keys.json`, mode `0600`, and are materialised into
|
|
10
|
+
the environment just before a run. **A real environment variable always wins**,
|
|
11
|
+
so a `.env` or an exported key still decides.
|
|
12
|
+
|
|
13
|
+
A reference is `provider` or `provider/name`. A provider may hold several named
|
|
14
|
+
keys; one of them is active.
|
|
15
|
+
|
|
16
|
+
## Subcommands
|
|
17
|
+
|
|
18
|
+
| Command | What it does |
|
|
19
|
+
| --------------------------------- | --------------------------------------- |
|
|
20
|
+
| `zen key ls [--check]` | Everything stored, and its state |
|
|
21
|
+
| `zen key add <provider>[/name]` | Read a key from stdin, or ask for it |
|
|
22
|
+
| `zen key use <provider>/<name>` | Choose which one a run uses |
|
|
23
|
+
| `zen key check [provider[/name]]` | Ask the provider whether it still works |
|
|
24
|
+
| `zen key rm <provider>/<name>` | Forget one |
|
|
25
|
+
| `zen key show <ref> [--reveal]` | Masked by default |
|
|
26
|
+
| `zen key env [provider …]` | Shell exports, for other tools |
|
|
27
|
+
|
|
28
|
+
`zen key add` also takes `--project` and `--location`, for a Vertex service
|
|
29
|
+
account.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
zen key add openai # prompts, echo off
|
|
33
|
+
pbpaste | zen key add openai/work # or from stdin
|
|
34
|
+
eval "$(zen key env)" # hand them to something else
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**The secret never comes from argv.** A command line lands in `ps`, in shell
|
|
38
|
+
history and in CI logs, so `zen key add` takes the value from piped stdin or an
|
|
39
|
+
echo-off prompt and from nowhere else.
|
|
40
|
+
|
|
41
|
+
## Providers
|
|
42
|
+
|
|
43
|
+
| Name | Environment variable | Holds | Where a key comes from |
|
|
44
|
+
| ------------ | -------------------------------- | ------ | ----------------------------------- |
|
|
45
|
+
| `openai` | `OPENAI_API_KEY` | secret | platform.openai.com/api-keys |
|
|
46
|
+
| `anthropic` | `ANTHROPIC_API_KEY` | secret | console.anthropic.com/settings/keys |
|
|
47
|
+
| `google` | `GEMINI_API_KEY` | secret | aistudio.google.com/apikey |
|
|
48
|
+
| `vertex` | `GOOGLE_APPLICATION_CREDENTIALS` | file | a service-account JSON key from GCP |
|
|
49
|
+
| `vertex` | `VERTEX_API_KEY` | secret | an express-mode key from GCP |
|
|
50
|
+
| `openrouter` | `OPENROUTER_API_KEY` | secret | openrouter.ai/settings/keys |
|
|
51
|
+
| `exa` | `EXA_API_KEY` | secret | dashboard.exa.ai/api-keys |
|
|
52
|
+
|
|
53
|
+
`exa` is a service the tools call, not a model provider.
|
|
54
|
+
|
|
55
|
+
### Vertex takes either shape
|
|
56
|
+
|
|
57
|
+
A **service-account file** is absorbed into `~/.zenera/neo/keys/` and
|
|
58
|
+
`GOOGLE_APPLICATION_CREDENTIALS` points at it. It wants a project too, from
|
|
59
|
+
`--project`, or `GOOGLE_CLOUD_PROJECT`, or the `project_id` inside the file, and
|
|
60
|
+
a region from `--location` (`global` otherwise). Application Default
|
|
61
|
+
Credentials from `gcloud auth application-default login` work with no entry at
|
|
62
|
+
all.
|
|
63
|
+
|
|
64
|
+
An **express-mode key** is an ordinary secret under `VERTEX_API_KEY`, and
|
|
65
|
+
addresses no project: a key and a project are alternatives, and sending both
|
|
66
|
+
gets a `403` that mentions neither. `--project` and `--location` are therefore
|
|
67
|
+
refused alongside a key.
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
zen key add vertex --project acme-prod --location europe-west4
|
|
71
|
+
# paste a path → the file shape
|
|
72
|
+
# paste a key → the express shape
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Which one you gave is read off the value: a path that exists is the file, and
|
|
76
|
+
anything else is the key.
|
|
77
|
+
|
|
78
|
+
## Credentials the keyring does not hold
|
|
79
|
+
|
|
80
|
+
`zen key ls` also lists what the environment brought and what `gcloud` left
|
|
81
|
+
behind, marked `~` and named for the variable rather than for a key:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
~ vertex/$VERTEX_API_KEY vx-1…9f0z live from the environment
|
|
85
|
+
~ vertex/adc …/application_default_credentials.json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
These can be listed and checked, not chosen or forgotten — there is nothing to
|
|
89
|
+
choose between, and nothing of ours to remove. Unset the variable, or
|
|
90
|
+
`gcloud auth application-default revoke`.
|
|
91
|
+
|
|
92
|
+
## Liveness
|
|
93
|
+
|
|
94
|
+
`zen key check` and `zen key ls --check` do one round trip per key and record
|
|
95
|
+
the verdict:
|
|
96
|
+
|
|
97
|
+
- **live** — authenticated. A rate-limited answer counts as live, because it
|
|
98
|
+
proves the credential.
|
|
99
|
+
- **dead** — the provider rejected it. A verdict.
|
|
100
|
+
- **blocked** — the credential was accepted and the **account** refused: an API
|
|
101
|
+
switched off in the project, an empty balance, a model this key was never
|
|
102
|
+
granted. Do not rotate the key; a new one is refused identically. The check
|
|
103
|
+
carries a `fix` — for a disabled Google API, the exact
|
|
104
|
+
`gcloud services enable <api> --project <id>`.
|
|
105
|
+
- **unknown** — the provider could not be asked. Says nothing about the key;
|
|
106
|
+
usually the network.
|
|
107
|
+
|
|
108
|
+
`zen init` uses the same probe to pick which provider to scaffold with, so a
|
|
109
|
+
project is not built around a revoked key.
|
|
110
|
+
|
|
111
|
+
## When a run says there is no credential
|
|
112
|
+
|
|
113
|
+
The frame does **not** materialise the keyring for you — each command that needs
|
|
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 — set OPENAI_API_KEY`, the
|
|
116
|
+
credential is fine and the command is at fault. Everything that runs a model
|
|
117
|
+
(`run`, `check`, `models`, `faker`, `rag`) already does this.
|
|
118
|
+
|
|
119
|
+
Exit code `4` means no usable credential for what was asked.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Models — `zen models`
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
zen models <providers|ls|search|show|test|pick> [ref] [options]
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Alias: `model`.
|
|
8
|
+
|
|
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
|
+
but a credential.
|
|
12
|
+
|
|
13
|
+
## Subcommands
|
|
14
|
+
|
|
15
|
+
| Command | What it does |
|
|
16
|
+
| --------------------------- | ------------------------------------------------------ |
|
|
17
|
+
| `zen models` | Providers, credential source, how many models, how old |
|
|
18
|
+
| `zen models <provider>` | Short for `ls <provider>` |
|
|
19
|
+
| `zen models ls [provider]` | Everything it serves |
|
|
20
|
+
| `zen models search <query>` | Narrow it |
|
|
21
|
+
| `zen models show <ref>` | One model, every field the vendor gave |
|
|
22
|
+
| `zen models test <ref> …` | One real minimal call per ref, and a verdict |
|
|
23
|
+
| `zen models pick` | The first ref that answers, printed on stdout |
|
|
24
|
+
|
|
25
|
+
Filters, on `ls` and `search`: `--chat`, `--embeddings`, `--images`, `--audio`,
|
|
26
|
+
`--tools`, `--vision`, `--free`, `--min-context <n>`, `--provider <name>`,
|
|
27
|
+
`--limit <n>`, `--all`, `--refresh`.
|
|
28
|
+
|
|
29
|
+
`pick` requires `--chat` or `--embedding`, and takes `--provider` and `--limit`.
|
|
30
|
+
|
|
31
|
+
## Where the lists come from
|
|
32
|
+
|
|
33
|
+
The providers themselves, cached for a day in `~/.zenera/neo/catalog`. When a
|
|
34
|
+
provider cannot be asked, the last listing is used and reported as stale; only
|
|
35
|
+
if there was never one does a short built-in list stand in. Every row says which
|
|
36
|
+
it was — `--json` carries `source` per model and `origin` per provider.
|
|
37
|
+
|
|
38
|
+
`--refresh` bypasses the cache. It is the only thing that does.
|
|
39
|
+
|
|
40
|
+
`zen models` on its own does **not** go to the network. `ls` and `search` do.
|
|
41
|
+
|
|
42
|
+
## Testing a model
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
zen models test openai:gpt-4o-mini
|
|
46
|
+
zen models test vertex:gemini-embedding-001 --embedding
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The role is taken from the flag, else from what the provider says the model is
|
|
50
|
+
for, else from the id. One minimal call: `ok` for a chat model, one short vector
|
|
51
|
+
for an embedder — the embedding's width is reported, which matters because a
|
|
52
|
+
model serving a different number of dimensions is not interchangeable with the
|
|
53
|
+
one an index was built on.
|
|
54
|
+
|
|
55
|
+
Four verdicts, and they want four different actions:
|
|
56
|
+
|
|
57
|
+
| Verdict | Means | Do |
|
|
58
|
+
| ----------- | -------------------------------------------- | -------------------------- |
|
|
59
|
+
| `answers` | it works | nothing |
|
|
60
|
+
| `refused` | the credential was rejected | `zen key check <provider>` |
|
|
61
|
+
| `blocked` | the credential was fine, the account said no | the `fix` printed under it |
|
|
62
|
+
| `no answer` | it could not be reached | try again |
|
|
63
|
+
|
|
64
|
+
Exit `0` when every ref answered, `4` when any did not, `2` for a ref that does
|
|
65
|
+
not parse.
|
|
66
|
+
|
|
67
|
+
## Recovering from a blocked model
|
|
68
|
+
|
|
69
|
+
This is what the command is for.
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
$ zen models test vertex:gemini-embedding-001
|
|
73
|
+
vertex:gemini-embedding-001 blocked Vertex AI API has not been used in project my-proj …
|
|
74
|
+
vertex:gemini-embedding-001: gcloud services enable aiplatform.googleapis.com --project my-proj
|
|
75
|
+
error 1 of 1 did not answer
|
|
76
|
+
find one that does: zen models pick --embedding
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Two ways out. Run the `gcloud` line, or take a different model:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
$ zen models pick --embedding
|
|
83
|
+
openai:text-embedding-3-small
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`pick` tries a short ordered list one at a time and stops at the first that
|
|
87
|
+
works. Sequential on purpose — the goal is one working ref, not a survey. The
|
|
88
|
+
ref goes to **stdout alone and unstyled**, so it substitutes directly:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
zen rag schema index --embedding "$(zen models pick --embedding)" ./specs/*.yaml
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`zen models pick --embedding --json` gives `{ref, provider, model, role,
|
|
95
|
+
dimensions, ms, tried}` — `tried` lists every candidate and why it was passed
|
|
96
|
+
over, so a caller can see _why_ a provider was skipped rather than only that it
|
|
97
|
+
was.
|
|
98
|
+
|
|
99
|
+
When nothing answers, exit `4` and the table of everything tried.
|
|
100
|
+
|
|
101
|
+
## What it will not do
|
|
102
|
+
|
|
103
|
+
There is no `test --all`. A sweep across every model on the machine is a bill,
|
|
104
|
+
not a diagnostic — name the refs you care about, or use `pick`.
|
|
105
|
+
|
|
106
|
+
There is no ranking. The candidate order in `pick` is cheapest-and-fastest
|
|
107
|
+
first, which is about how quickly an answer arrives, not about which model is
|
|
108
|
+
better.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Projects — `init`, `list`, `open`, `version`
|
|
2
|
+
|
|
3
|
+
## `zen init`
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
zen init [dir] [--name <name>] [--model <ref>] [--force]
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Creates a project here, or in `<dir>`, and records it in the registry so `zen
|
|
10
|
+
list` and `zen open` can find it by name.
|
|
11
|
+
|
|
12
|
+
| Flag | Meaning |
|
|
13
|
+
| --------------- | ------------------------------------------------------- |
|
|
14
|
+
| `--name <name>` | The registry name. Defaults to the directory's basename |
|
|
15
|
+
| `--model <ref>` | The model to scaffold with, taken as written |
|
|
16
|
+
| `--force` | Write into a directory that already holds a project |
|
|
17
|
+
|
|
18
|
+
What it writes:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
zenera.json { version, name }
|
|
22
|
+
INSTRUCTIONS.md house rules
|
|
23
|
+
agents.yaml the configuration
|
|
24
|
+
agents/prompts/default.md the default agent's prompt
|
|
25
|
+
agents/skills/ empty, for skills
|
|
26
|
+
assets/README.md
|
|
27
|
+
sandbox/Dockerfile the image the sandbox builds
|
|
28
|
+
sessions/ empty
|
|
29
|
+
.gitignore
|
|
30
|
+
.vscode/settings.json editor files
|
|
31
|
+
.github/ copilot instructions, prompts, this skill
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The project's own files are never overwritten — `--force` is what allows
|
|
35
|
+
writing into an occupied directory, and the files already there stay. The
|
|
36
|
+
editor files are the exception: `.vscode/settings.json` and the `.github/` tree
|
|
37
|
+
are ours and are replaced on every `init` and every `zen open`, so edits to them
|
|
38
|
+
do not survive.
|
|
39
|
+
|
|
40
|
+
The default agent gets the file tools and a sandboxed shell, plus `exa:*` when
|
|
41
|
+
the keyring holds an Exa key.
|
|
42
|
+
|
|
43
|
+
**Choosing the model.** Without `--model`, the keyring is asked — not counted.
|
|
44
|
+
Stored credentials are probed, because holding a key is not the same as holding
|
|
45
|
+
a working one, and the model is picked from a provider that answers. A key from
|
|
46
|
+
the environment is taken at its word. Each provider has its own scaffolded
|
|
47
|
+
default, and every scaffolded ref names its provider: the model shorthand reads
|
|
48
|
+
the first segment as a **provider name**, not a vendor, so a bare
|
|
49
|
+
`gemini-3.5-flash` would be asked of OpenAI.
|
|
50
|
+
|
|
51
|
+
## `zen list`
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
zen list [--sessions] [--prune]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Every known project: its sessions, the last run, and whether one is live right
|
|
58
|
+
now.
|
|
59
|
+
|
|
60
|
+
| Flag | Meaning |
|
|
61
|
+
| ------------ | -------------------------------------------- |
|
|
62
|
+
| `--sessions` | Expand each project into its sessions |
|
|
63
|
+
| `--prune` | Forget entries whose directory has gone away |
|
|
64
|
+
|
|
65
|
+
The registry is an index, not the truth. An entry pointing at a directory that
|
|
66
|
+
no longer exists is shown dimmed rather than hidden, because a moved project is
|
|
67
|
+
a thing to fix, not a thing to silently lose.
|
|
68
|
+
|
|
69
|
+
## `zen open`
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
zen open [project] [--editor <cmd>] [--wait]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Opens the project directory in an editor. This is the only command that locates
|
|
76
|
+
a project for a human rather than for itself.
|
|
77
|
+
|
|
78
|
+
| Flag | Meaning |
|
|
79
|
+
| ---------------- | ------------------------------------- |
|
|
80
|
+
| `--editor <cmd>` | The command to launch |
|
|
81
|
+
| `--wait` | Do not return until the editor closes |
|
|
82
|
+
|
|
83
|
+
The editor is chosen in this order: `--editor`, `$ZENERA_EDITOR`, the editor
|
|
84
|
+
this terminal belongs to, `$VISUAL` or `$EDITOR`, a known editor on `PATH` or
|
|
85
|
+
installed, then the platform opener.
|
|
86
|
+
|
|
87
|
+
Opening refreshes the editor files (`.vscode/settings.json` and the `.github/`
|
|
88
|
+
tree) in the directory being opened. VS Code and its forks are launched with
|
|
89
|
+
`--disable-workspace-trust`, so the settings written there apply to the new
|
|
90
|
+
window immediately rather than after a prompt.
|
|
91
|
+
|
|
92
|
+
## `zen version`
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
zen version
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The CLI version, the library version and the Node version. `zen --version`
|
|
99
|
+
prints the CLI version alone and returns before anything else loads.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# API search — `zen rag`
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
zen rag schema <index|search|show|stats> [spec...]
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Provided by `@zenera/rag` — `npm i -g @zenera/rag` if `zen rag` says it is not
|
|
8
|
+
installed.
|
|
9
|
+
|
|
10
|
+
Reads an OpenAPI/Swagger document as a **graph** — operations, schemas and the
|
|
11
|
+
fields inside them, joined by the `$ref`s between them — and makes it
|
|
12
|
+
searchable. The answer to a search is not a list of matches but the connected
|
|
13
|
+
piece of the API that matched: the operations, the schemas they carry and the
|
|
14
|
+
fields inside them, printed as text, a diagram, or TypeScript that compiles.
|
|
15
|
+
|
|
16
|
+
It exists because a large specification does not fit in a context window and
|
|
17
|
+
grepping it returns fragments that name types nobody printed.
|
|
18
|
+
|
|
19
|
+
## `index`
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
zen rag schema index <spec...> [--embedding <ref>] [-o <dir>] [--batch <n>]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Flag | Default | Meaning |
|
|
26
|
+
| ------------------- | ------------- | ------------------------------------------------------------ |
|
|
27
|
+
| `--embedding <ref>` | — | Which embedder makes the vectors. Omit it to see the choices |
|
|
28
|
+
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes |
|
|
29
|
+
| `--batch <n>` | `96` | Texts per embedding request, and how often progress prints |
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
zen rag schema index openapi.yaml --embedding openai:text-embedding-3-small
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Unlike the faker, `$ref`s are **bundled, not dereferenced**: component names are
|
|
36
|
+
the node ids and the cycles between them are the edges. `discriminator` is kept —
|
|
37
|
+
it is what turns a `oneOf` into a tagged union a compiler can narrow.
|
|
38
|
+
|
|
39
|
+
What lands in `<out>`:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
manifest.json written last; its presence means the index is complete
|
|
43
|
+
graph.json the nodes and edges
|
|
44
|
+
schemas.json the schemas, read lazily
|
|
45
|
+
operations.json the operations, read lazily
|
|
46
|
+
lance/ the vector and full-text indexes
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The manifest records the embedding ref **and** the embedder's own id, so a
|
|
50
|
+
search with a different model is refused rather than quietly returning nonsense.
|
|
51
|
+
|
|
52
|
+
## `search`
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
zen rag schema search [terms…] [filters…]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Every argument is validated before an embedder is constructed, so a typo is a
|
|
59
|
+
usage error rather than a credential error.
|
|
60
|
+
|
|
61
|
+
### Terms — repeatable, and the field is the point
|
|
62
|
+
|
|
63
|
+
| Term | Searches |
|
|
64
|
+
| ----------------------- | ---------------------------------------- |
|
|
65
|
+
| `<text>` | Everything, the same as `--all` |
|
|
66
|
+
| `--all <q>` | Everything, unfiltered |
|
|
67
|
+
| `--method <q>` | Operations |
|
|
68
|
+
| `--type <q>` | Schemas, on the side `--direction` names |
|
|
69
|
+
| `--input-type <q>` | Schemas a call accepts |
|
|
70
|
+
| `--output-type <q>` | Schemas a call returns |
|
|
71
|
+
| `--property <q>` | Fields and parameters, per `--direction` |
|
|
72
|
+
| `--input-property <q>` | Fields and parameters a call accepts |
|
|
73
|
+
| `--output-property <q>` | Fields a call returns |
|
|
74
|
+
| `--query <json\|->` | A whole query object; `-` reads stdin |
|
|
75
|
+
|
|
76
|
+
Putting the intent in the field that matches what is wanted is what makes the
|
|
77
|
+
search good. A request field belongs in `--input-property`, a response field in
|
|
78
|
+
`--output-property`; `--all` cannot filter and is the weakest of them.
|
|
79
|
+
|
|
80
|
+
### Filters and shape
|
|
81
|
+
|
|
82
|
+
| Flag | Default | Meaning |
|
|
83
|
+
| --------------------------- | ------------- | ------------------------------------------------------- |
|
|
84
|
+
| `-d`, `--dir <dir>` | `./schema-db` | Which index |
|
|
85
|
+
| `--embedding <ref>` | the index's | Must be the one the index was built with |
|
|
86
|
+
| `--direction <d>` | `any` | `input`, `output` or `any` |
|
|
87
|
+
| `--method-type <t>` | `any` | `read_only`, `read_write` or `any` |
|
|
88
|
+
| `--exclude-id <id>` | — | Drop a node. Repeatable |
|
|
89
|
+
| `--exclude-method <name>` | — | Drop an operation by name. Repeatable |
|
|
90
|
+
| `--exclude-type <name>` | — | Drop a schema by name. Repeatable |
|
|
91
|
+
| `--exclude-property <name>` | — | Drop a field by name. Repeatable |
|
|
92
|
+
| `--limit <n>` | `5` | Seeds kept per term |
|
|
93
|
+
| `--max-hops <n>` | `3` | How far apart two hits may be |
|
|
94
|
+
| `--max-nodes <n>` | `200` | Nodes per result |
|
|
95
|
+
| `--format <f>` | `text` | `text`, `mermaid`, `mermaid-flowchart`, `ts`, `openapi` |
|
|
96
|
+
| `--no-docs` | — | Leave the descriptions out |
|
|
97
|
+
| `--interactive` | — | Prompt, search, refine. Needs a terminal |
|
|
98
|
+
| `--quiet` | — | No narration |
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
zen rag schema search --method "reset a user password" --format ts
|
|
102
|
+
zen rag schema search --output-property "invoice total" --direction output
|
|
103
|
+
echo '{"methods":["cancel a subscription"]}' | zen rag schema search --query -
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The exclusions are what turn one search into a session: pass back the ids of
|
|
107
|
+
what you have already been shown to be shown something else instead of the same
|
|
108
|
+
thing again.
|
|
109
|
+
|
|
110
|
+
`--format ts` emits TypeScript closed over its own `$ref`s — everything named is
|
|
111
|
+
also declared, so the output compiles on its own.
|
|
112
|
+
|
|
113
|
+
### `--interactive`
|
|
114
|
+
|
|
115
|
+
A prompt that keeps the query between searches:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
<text> search everything
|
|
119
|
+
all|method|type <text> search one field
|
|
120
|
+
input-property <text> also: output-property, property, input-type, output-type
|
|
121
|
+
direction <d> input | output | any
|
|
122
|
+
method-type <t> read_only | read_write | any
|
|
123
|
+
format <f> text | mermaid | mermaid-flowchart | ts | openapi
|
|
124
|
+
show the query as it stands
|
|
125
|
+
reset forget it, exclusions included
|
|
126
|
+
quit
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## `show`
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
zen rag schema show <id...> [-d <dir>] [--format <f>]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Prints named nodes with no search in between. Needs no embedder and no
|
|
136
|
+
credential — it is a read of the graph.
|
|
137
|
+
|
|
138
|
+
## `stats`
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
zen rag schema stats [-d <dir>]
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
What is in an index and what built it: counts by kind, the embedding model, the
|
|
145
|
+
documents it came from. Also needs no embedder.
|
|
146
|
+
|
|
147
|
+
## Giving it to an agent
|
|
148
|
+
|
|
149
|
+
`@zenera/rag/tools` exports the same search as tools an agent can call:
|
|
150
|
+
|
|
151
|
+
| Tool | For |
|
|
152
|
+
| -------------------------- | ------------------------------------------------------------------- |
|
|
153
|
+
| `search_api` | The search above, with the same fields |
|
|
154
|
+
| `describe_types` | Named schemas as TypeScript, closed over what they refer to |
|
|
155
|
+
| `find_types_with_property` | Every schema with a field of this name — exact lookup, no searching |
|
|
156
|
+
| `list_methods` | Operations by path, to see the shape of the API before asking |
|
|
157
|
+
|
|
158
|
+
They share the group `schema`, so an agent takes them with `schema:*` in its
|
|
159
|
+
`tools:`.
|