@zenera/cli 1.1.2 → 1.1.3

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.
Files changed (50) hide show
  1. package/README.md +88 -11
  2. package/dist/audit.d.ts +8 -6
  3. package/dist/audit.js +14 -22
  4. package/dist/commands/check.js +34 -7
  5. package/dist/commands/init.js +71 -11
  6. package/dist/commands/key.js +126 -36
  7. package/dist/commands/models.js +3 -3
  8. package/dist/commands/open.js +2 -2
  9. package/dist/commands/run.js +3 -0
  10. package/dist/engine.d.ts +2 -0
  11. package/dist/engine.js +1 -0
  12. package/dist/keys.d.ts +95 -12
  13. package/dist/keys.js +175 -34
  14. package/dist/lib.d.ts +1 -1
  15. package/dist/lib.js +1 -1
  16. package/dist/liveness.d.ts +16 -6
  17. package/dist/liveness.js +74 -23
  18. package/dist/sandbox.d.ts +2 -0
  19. package/dist/sandbox.js +58 -7
  20. package/dist/scaffold.d.ts +21 -21
  21. package/dist/scaffold.js +132 -204
  22. package/dist/validate.js +3 -3
  23. package/package.json +2 -18
  24. package/templates/{.github → editor/.github}/copilot-instructions.md +7 -6
  25. package/templates/editor/.github/skills/api-schema-index/SKILL.md +292 -0
  26. package/templates/editor/.github/skills/zen-cli/SKILL.md +74 -0
  27. package/templates/editor/.github/skills/zen-cli/references/check.md +92 -0
  28. package/templates/editor/.github/skills/zen-cli/references/faker.md +111 -0
  29. package/templates/editor/.github/skills/zen-cli/references/frame.md +119 -0
  30. package/templates/editor/.github/skills/zen-cli/references/inspect.md +61 -0
  31. package/templates/editor/.github/skills/zen-cli/references/keys.md +114 -0
  32. package/templates/editor/.github/skills/zen-cli/references/projects.md +99 -0
  33. package/templates/editor/.github/skills/zen-cli/references/rag.md +159 -0
  34. package/templates/editor/.github/skills/zen-cli/references/run.md +104 -0
  35. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +91 -0
  36. package/templates/editor/.vscode/settings.json +6 -0
  37. package/templates/parts/exa.yaml.tmpl +5 -0
  38. package/templates/parts/model.yaml.tmpl +4 -0
  39. package/templates/parts/models.yaml.tmpl +10 -0
  40. package/templates/project/INSTRUCTIONS.md +7 -0
  41. package/templates/project/SPECIFICATION.md +6 -0
  42. package/templates/project/agents/prompts/default.md +15 -0
  43. package/templates/project/agents.yaml.tmpl +44 -0
  44. package/templates/project/assets/README.md +12 -0
  45. package/templates/project/gitignore +9 -0
  46. package/templates/{sandbox → project/sandbox}/Dockerfile +2 -0
  47. package/templates/.github/skills/zen-cli/SKILL.md +0 -110
  48. /package/templates/{.github → editor/.github}/prompts/new-agent.prompt.md +0 -0
  49. /package/templates/{.github → editor/.github}/prompts/new-skill.prompt.md +0 -0
  50. /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,114 @@
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
+ - **unknown** — the provider could not be asked. Says nothing about the key;
101
+ usually the network.
102
+
103
+ `zen init` uses the same probe to pick which provider to scaffold with, so a
104
+ project is not built around a revoked key.
105
+
106
+ ## When a run says there is no credential
107
+
108
+ The frame does **not** materialise the keyring for you — each command that needs
109
+ a credential opens the store itself. If `zen key ls` shows a key as live and a
110
+ command still says `provider "openai": no api key — set OPENAI_API_KEY`, the
111
+ credential is fine and the command is at fault. Everything that runs a model
112
+ (`run`, `check`, `models`, `faker`, `rag`) already does this.
113
+
114
+ Exit code `4` means no usable credential for what was asked.
@@ -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:`.
@@ -0,0 +1,104 @@
1
+ # Running — `zen run`
2
+
3
+ ```
4
+ zen run [project] [prompt] [options]
5
+ ```
6
+
7
+ On a terminal with no prompt it opens the TUI. With a prompt, or with no tty, it
8
+ answers once on stdout and exits.
9
+
10
+ ## Options
11
+
12
+ | Flag | What it does |
13
+ | ----------------------- | ------------------------------------------------------ |
14
+ | `--project <name\|dir>` | Which project. Inferred from the directory otherwise |
15
+ | `--session <id>` | Continue a particular session |
16
+ | `--new` | Start a fresh one |
17
+ | `--workspace <dir>` | What the agent may read and write |
18
+ | `--model <ref>` | Override the default model for this run |
19
+ | `--image <ref>` | Override the container image commands run in |
20
+ | `--read-only` | Withhold every tool that can write |
21
+ | `--quiet` | The answer only; no narration |
22
+ | `--plain` | One shot, even on a terminal |
23
+ | `--theme <dark\|light>` | Force the palette. Detected otherwise; `$ZENERA_THEME` |
24
+ | `--out <file>` | Write the answer to a file as well as to stdout |
25
+ | `--yes` | Accept the questions it would otherwise ask |
26
+
27
+ Flags always beat the file: the repository states intent, the invocation
28
+ overrides it.
29
+
30
+ ## Which word is the project
31
+
32
+ The first positional is read as a project when it names one, and as the first
33
+ word of the prompt when it does not:
34
+
35
+ ```
36
+ zen run acme the acme project, TUI
37
+ zen run acme "what changed?" the acme project, one answer
38
+ zen run "what changed?" this directory's project, one answer
39
+ zen run --project why "why?" when the project is called "why"
40
+ ```
41
+
42
+ The prompt comes from the argument, or from stdin, or from the TUI:
43
+
44
+ ```
45
+ git diff | zen run --quiet "summarise this diff"
46
+ ```
47
+
48
+ ## What a prompt on the command line implies
49
+
50
+ A prompt is a request for an answer, not a conversation to pick up, so it
51
+ answers the three questions itself: **a fresh session**, **the directory you are
52
+ in** as the workspace, and **no confirmation**. Every flag still wins —
53
+ `--session`, `--workspace` and `--read-only` override it — and the TUI, where
54
+ there is someone to ask, still asks.
55
+
56
+ There is no `resume`. A session continues itself, because its state is what it
57
+ is; `--session <id>` picks which one.
58
+
59
+ ## The TUI
60
+
61
+ Drawn only when there is a terminal on both stdin and stdout, no prompt,
62
+ no `--plain`, no `--quiet` and no `--json`. It streams the answer, shows
63
+ reasoning as it arrives, and reports per-turn and per-session token usage in the
64
+ footer.
65
+
66
+ Reasoning only _arrives_ if the model was asked for it: OpenAI needs
67
+ `reasoningSummary` on the responses API, Anthropic needs `thinkingBudgetTokens`,
68
+ Gemini has `includeThoughts` on by default. An OpenAI project shows nothing
69
+ until `agents.yaml` asks.
70
+
71
+ Palette selection: `--theme` > `$ZENERA_THEME` > a query to the terminal >
72
+ `COLORFGBG` > dark.
73
+
74
+ ## Sessions
75
+
76
+ One session is one continuing conversation, with its own workspace, memory and
77
+ run history. Ids look like `20260825-143012-a7f3`.
78
+
79
+ ```
80
+ <project>/sessions/<id>/
81
+ workspace/ what the agent sees, unless --workspace said otherwise
82
+ runs/<run-id>/ input.md, output.md, state.json, report.html, meta.json
83
+ .data/
84
+ state.json the live, resumable state, rewritten after every run
85
+ session.json when it was made, and the workspace it is rooted at
86
+ memory/
87
+ blobs/
88
+ sandbox/home/ /home/agent inside the container
89
+ .lock held while a run is in flight
90
+ ```
91
+
92
+ The recorded workspace is what makes resuming safe: a session that quietly
93
+ changed what "the workspace" meant between turns would be unexplainable, so it
94
+ is written once and reused.
95
+
96
+ None of `sessions/` is source and none of it is committed.
97
+
98
+ A session is locked while it runs, and a lock whose process is gone is stale by
99
+ definition and is taken over.
100
+
101
+ ## Afterwards
102
+
103
+ Each run writes a `report.html` next to its state; the run prints a
104
+ `file://` link to it. See [inspect.md](inspect.md).