@zenera/cli 1.1.0 → 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 (61) 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 +79 -19
  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/commands/sandbox.js +226 -22
  11. package/dist/engine.d.ts +3 -1
  12. package/dist/engine.js +10 -2
  13. package/dist/image.d.ts +16 -0
  14. package/dist/image.js +85 -0
  15. package/dist/keys.d.ts +95 -12
  16. package/dist/keys.js +175 -34
  17. package/dist/lib.d.ts +2 -2
  18. package/dist/lib.js +2 -2
  19. package/dist/liveness.d.ts +16 -6
  20. package/dist/liveness.js +74 -23
  21. package/dist/main.js +0 -0
  22. package/dist/podman.d.ts +57 -1
  23. package/dist/podman.js +177 -12
  24. package/dist/projects.d.ts +18 -0
  25. package/dist/projects.js +60 -1
  26. package/dist/sandbox.d.ts +14 -1
  27. package/dist/sandbox.js +88 -8
  28. package/dist/scaffold.d.ts +21 -15
  29. package/dist/scaffold.js +133 -167
  30. package/dist/term.d.ts +2 -0
  31. package/dist/term.js +14 -0
  32. package/dist/validate.d.ts +20 -3
  33. package/dist/validate.js +309 -14
  34. package/package.json +2 -18
  35. package/templates/{.github → editor/.github}/copilot-instructions.md +161 -48
  36. package/templates/{.github → editor/.github}/prompts/new-skill.prompt.md +13 -6
  37. package/templates/editor/.github/skills/api-schema-index/SKILL.md +292 -0
  38. package/templates/editor/.github/skills/zen-cli/SKILL.md +74 -0
  39. package/templates/editor/.github/skills/zen-cli/references/check.md +92 -0
  40. package/templates/editor/.github/skills/zen-cli/references/faker.md +111 -0
  41. package/templates/editor/.github/skills/zen-cli/references/frame.md +119 -0
  42. package/templates/editor/.github/skills/zen-cli/references/inspect.md +61 -0
  43. package/templates/editor/.github/skills/zen-cli/references/keys.md +114 -0
  44. package/templates/editor/.github/skills/zen-cli/references/projects.md +99 -0
  45. package/templates/editor/.github/skills/zen-cli/references/rag.md +159 -0
  46. package/templates/editor/.github/skills/zen-cli/references/run.md +104 -0
  47. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +91 -0
  48. package/templates/editor/.vscode/settings.json +6 -0
  49. package/templates/parts/exa.yaml.tmpl +5 -0
  50. package/templates/parts/model.yaml.tmpl +4 -0
  51. package/templates/parts/models.yaml.tmpl +10 -0
  52. package/templates/project/INSTRUCTIONS.md +7 -0
  53. package/templates/project/SPECIFICATION.md +6 -0
  54. package/templates/project/agents/prompts/default.md +15 -0
  55. package/templates/project/agents.yaml.tmpl +44 -0
  56. package/templates/project/assets/README.md +12 -0
  57. package/templates/project/gitignore +9 -0
  58. package/templates/project/sandbox/Dockerfile +21 -0
  59. package/templates/.github/skills/zen-cli/SKILL.md +0 -110
  60. /package/templates/{.github → editor/.github}/prompts/new-agent.prompt.md +0 -0
  61. /package/templates/{.github → editor/.github}/prompts/review-project.prompt.md +0 -0
@@ -0,0 +1,91 @@
1
+ # The sandbox — `zen sandbox`
2
+
3
+ ```
4
+ zen sandbox [status|up|pull|clean|disk] [options]
5
+ ```
6
+
7
+ Shell commands run in a container over the session workspace, never on the
8
+ host. None of this is required: a run does all of it on its own, the first time
9
+ an agent that can reach a shell is about to start one. These subcommands are for
10
+ doing it deliberately — before a demo, in CI, or when diagnosing.
11
+
12
+ | Subcommand | What it does |
13
+ | ---------- | -------------------------------------------------------------- |
14
+ | `status` | What is installed, running and pulled. Changes nothing |
15
+ | `up` | Install if asked, start the machine, pull or build the image |
16
+ | `pull` | Just the image: pulled, or built from the project's Dockerfile |
17
+ | `clean` | Remove every container this CLI created |
18
+ | `disk` | What the engine and every known project occupy |
19
+
20
+ | Flag | Meaning |
21
+ | ----------------------- | --------------------------------------- |
22
+ | `--project <name\|dir>` | Which project the image comes from |
23
+ | `--image <ref>` | Use this image instead of the project's |
24
+
25
+ The engine is Podman. On macOS a machine has to exist and be running; `up`
26
+ offers to install and start one, and its size follows the project's `cpus` and
27
+ `memory`.
28
+
29
+ ## Configuring it — `sandbox:` in `agents.yaml`
30
+
31
+ Top level, and again per agent, where an agent's block is merged over the base.
32
+
33
+ | Key | Meaning |
34
+ | --------- | ---------------------------------------------------------------- |
35
+ | `image` | The image to run. Mutually exclusive with `build` |
36
+ | `build` | `{ dockerfile, context? }` — build one instead. Excludes `image` |
37
+ | `cpus` | CPU limit |
38
+ | `memory` | Memory limit, in MiB |
39
+ | `network` | Whether the container has one |
40
+ | `workdir` | Where the workspace is mounted. `/workspace` by default |
41
+ | `timeout` | Seconds one command may take |
42
+ | `user` | Who commands run as |
43
+ | `persist` | Keep the container between runs |
44
+ | `env` | A name-only allow-list of variables to pass in |
45
+
46
+ `env` refuses names matching `KEY`, `TOKEN`, `SECRET`, `PASSWORD`, `PASSWD` or
47
+ `CREDENTIAL`: the keyring has already materialised real credentials into the
48
+ process environment, and a sandbox is the last place they should be forwarded to.
49
+
50
+ ## `persist: true` is usually what you want
51
+
52
+ Only `/workspace` and `/home/agent` survive an ephemeral container. A
53
+ `pip install` as root, or an `apt-get install`, lands in the image's system
54
+ paths and is gone by the next run — so the agent silently reinstalls its
55
+ toolchain every single time. `zen init` scaffolds `persist: true` for that
56
+ reason.
57
+
58
+ The caveat: the container's name is a function of its configuration, so any
59
+ change to the sandbox block names a _new_ container and abandons the installed
60
+ rootfs. If runs keep beginning with an install, either persist, or bake the
61
+ toolchain into the image.
62
+
63
+ ## Building an image instead of naming one
64
+
65
+ ```yaml
66
+ sandbox:
67
+ build:
68
+ dockerfile: sandbox/Dockerfile
69
+ persist: true
70
+ ```
71
+
72
+ The tag is content-addressed — a hash of the Dockerfile and every file in its
73
+ context — so a changed Dockerfile is a different image and a `persist: true`
74
+ container can never be left sitting on a stale rootfs. It is built only when
75
+ that tag is absent, which is safe precisely because the tag follows the content.
76
+ `zen sandbox pull` forces a rebuild.
77
+
78
+ ## Hardening
79
+
80
+ `no-new-privileges`, an init process, a pid limit, no restart policy. Not
81
+ `--cap-drop=ALL` (it breaks `apt` and `pip`) and never `--privileged`.
82
+
83
+ ## When it goes wrong
84
+
85
+ Exit code `5` means the container engine is missing or the image could not be
86
+ prepared, and the message names the command to run for this platform. `zen check`
87
+ distinguishes the two cases: a broken Dockerfile is an error, a laptop with no
88
+ Podman is a warning.
89
+
90
+ `zen sandbox clean` removes every container this CLI created — the way out of a
91
+ container left on a bad rootfs.
@@ -0,0 +1,6 @@
1
+ {
2
+ "chat.useNestedAgentsMdFiles": false,
3
+ "chat.tools.terminal.autoApprove": {
4
+ "zen": true
5
+ }
6
+ }
@@ -0,0 +1,5 @@
1
+ # exa:* is web search and page reading, here because this
2
+ # machine has an Exa key. The key is read from the environment
3
+ # when a tool is called, so a clone of this project without one
4
+ # still loads and only the call fails.
5
+ - exa:*
@@ -0,0 +1,4 @@
1
+ # The model an agent uses when it does not pin its own. Change it here and the
2
+ # whole project moves. The prefix is the *provider* name, not the vendor — drop
3
+ # it and the id goes to the default provider, whatever the id looks like.
4
+ model: {{ref}}
@@ -0,0 +1,10 @@
1
+ # The model an agent uses when it does not pin its own. Change it here and the
2
+ # whole project moves. A named configuration is what gives the knobs below
3
+ # somewhere to live; a bare `model: <provider>:<id>` works when there are none.
4
+ models:
5
+ main:
6
+ provider: {{provider}}
7
+ model: {{id}}
8
+ {{options}}
9
+
10
+ model: main
@@ -0,0 +1,7 @@
1
+ # House rules
2
+
3
+ Everything in this file is prepended to every agent's prompt, so it is the
4
+ place for the things that are true regardless of who is answering: tone,
5
+ constraints, what to do when the answer is not knowable.
6
+
7
+ Replace this with yours.
@@ -0,0 +1,6 @@
1
+ # Specification
2
+
3
+ What the project is meant to produce, the constraints it has to hold to, and
4
+ how to tell a finished job from an unfinished one.
5
+
6
+ Anything written here is the specification; while it is empty there is none.
@@ -0,0 +1,15 @@
1
+ You are a helpful assistant working inside a project workspace.
2
+
3
+ You have tools to read, search and edit files. The workspace is the only
4
+ place you can see; paths are relative to its root.
5
+
6
+ You can also run shell commands. They run in a container over the same
7
+ workspace, not on the user's machine, so a command that fails there has cost
8
+ them nothing — but it is still their work in the directory, so read before you
9
+ overwrite and say what you ran.
10
+
11
+ Read a file before you change it: `apply_patch` matches the surrounding text
12
+ exactly, so a patch written from memory will not apply. Use `apply_patch` to
13
+ change part of a file and `write_file` only for a new one.
14
+
15
+ Say what you changed.
@@ -0,0 +1,44 @@
1
+ # Who exists, and what they may reach for.
2
+ #
3
+ version: 1
4
+
5
+ {{model}}
6
+
7
+ # Anything in assets/ is mounted read-only at /assets for every agent: they can
8
+ # read, list and search it, and no tool can change it. It is a convention, so
9
+ # the folder is enough — set `assets: <path>` only to keep the material
10
+ # somewhere else in this project.
11
+
12
+ # The container `sandbox:*` commands run in. `build:` names a Dockerfile to
13
+ # build instead of an image to pull, so anything this project always needs is
14
+ # in the image rather than installed by an agent on every run — put it in
15
+ # sandbox/Dockerfile. Swap the whole block for `image: <ref>` to pull a
16
+ # published one instead; the two cannot both be set.
17
+ #
18
+ # `persist: true` keeps the container between runs rather than throwing it
19
+ # away, so what an agent installs for itself is still there next time —
20
+ # otherwise only /workspace and its home directory survive. `zen sandbox
21
+ # clean` removes the ones left behind. Everything else has a default; see the
22
+ # sandbox: block in docs/agents-yaml.md to size it.
23
+ sandbox:
24
+ persist: true
25
+ build:
26
+ dockerfile: sandbox/Dockerfile
27
+
28
+ agents:
29
+ - name: default
30
+ description: The entry point.
31
+ # Instructions live in agents/prompts/<name>.md and are picked up by
32
+ # convention — no need to name the file here.
33
+ #
34
+ # workspace:* is every file tool at once, sandbox:* is the shell. Name
35
+ # them one by one to be narrower, or subtract: [workspace:*, -delete_file]
36
+ #
37
+ # sandbox:* runs commands in a container, not on this machine, so it
38
+ # needs podman — `zen run` installs and starts what it can on its own,
39
+ # and `zen sandbox status` says where that got to. Drop the line if you
40
+ # would rather this agent never reached a shell.
41
+ tools:
42
+ - workspace:*
43
+ - sandbox:*
44
+ {{exa}}
@@ -0,0 +1,12 @@
1
+ # assets
2
+
3
+ Everything in this folder is mounted at /assets when an agent runs. Every agent
4
+ in this project can read, list and search it, and no tool of theirs can change
5
+ it — so this is where reference material goes: handbooks, specifications,
6
+ schemas, worked examples, the style guide the output is supposed to follow.
7
+
8
+ It is the project's own files that agents get without being asked. The
9
+ workspace they are pointed at is the work; this is what they consult while
10
+ doing it.
11
+
12
+ Delete this file once there is something here to read.
@@ -0,0 +1,9 @@
1
+ # Sessions hold run state, memory, blobs and whatever the agent wrote.
2
+ # None of it is source.
3
+ sessions/
4
+
5
+ # Scratch, inside the workspace so the sandbox can reach it.
6
+ .tmp/
7
+
8
+ # Credentials.
9
+ .env
@@ -0,0 +1,21 @@
1
+ # The container `run_command` runs in. Built by `zen run` and `zen check`, and
2
+ # named by the `sandbox: build:` block in agents.yaml.
3
+ #
4
+ # Python and Node both, because an agent asked to look at a repository does not
5
+ # get to choose which one it finds. Add what this project always needs here
6
+ # rather than letting an agent install it at run time: a root `pip install` or
7
+ # `apt-get` lands in the container's own filesystem, which is thrown away.
8
+
9
+ FROM node:24-bookworm-slim AS node
10
+ FROM python:3.14-slim-bookworm
11
+
12
+ # Copy Node.js runtime and global modules from official Node image
13
+ COPY --from=node /usr/local/bin/node /usr/local/bin/node
14
+ COPY --from=node /usr/local/include/node /usr/local/include/node
15
+ COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
16
+
17
+ # Symlink npm and npx executables
18
+ RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
19
+ && ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
20
+
21
+ RUN npm install -g @zenera/cli @zenera/rag @google/genai
@@ -1,110 +0,0 @@
1
- ---
2
- name: zen-cli
3
- description: How to drive this project from the terminal with `zen` — running it, validating it, credentials, the sandbox and run reports.
4
- ---
5
-
6
- # The `zen` command line
7
-
8
- Everything here operates on a project directory. The project is resolved from
9
- the working directory, or by name from the registry `zen init` wrote to, or
10
- explicitly with `--project <name|dir>`. Every command takes `--json` and prints
11
- a machine-readable answer instead of a rendered one.
12
-
13
- ## Running
14
-
15
- ```
16
- zen run [project] [prompt] [options]
17
- ```
18
-
19
- On a terminal with no prompt it opens the TUI; with a prompt, or without a tty,
20
- it answers once on stdout. The first word is the project when it names one, and
21
- the first word of the prompt when it does not — `--project` settles it.
22
-
23
- | Flag | What it does |
24
- | ----------------------- | -------------------------------------------- |
25
- | `--project <name\|dir>` | Which project. Inferred from the directory |
26
- | `--session <id>` | Continue a particular session |
27
- | `--new` | Start a fresh one |
28
- | `--workspace <dir>` | What the agent may read and write |
29
- | `--model <ref>` | Override the default model for this run |
30
- | `--image <ref>` | Override the container commands run in |
31
- | `--read-only` | Withhold every tool that can write |
32
- | `--quiet` | The answer only; no narration |
33
- | `--plain` | One shot, even on a terminal |
34
- | `--out <file>` | Write the answer to a file as well as stdout |
35
- | `--yes` | Accept the questions it would otherwise ask |
36
-
37
- Flags always win over the file: the repository states intent, the invocation
38
- overrides it. There is no `resume` — a session continues itself, because its
39
- state is what it is.
40
-
41
- With a prompt on the command line nothing is asked: a fresh session, the current
42
- directory as the workspace, writable.
43
-
44
- ## Validating
45
-
46
- ```
47
- zen check [dir] [--strict] [--quiet] everything agents.yaml names
48
- zen models [--project <name|dir>] providers, models and embeddings resolved
49
- ```
50
-
51
- `zen check` reads the project the way `zen run` does and reports in full without
52
- calling a model — a missing prompt file, an unknown tool, a handoff to nobody, a
53
- model alias on an undeclared provider. `zen models` answers the narrower
54
- question of what each agent would actually talk to, and which credential it
55
- needs. Run `zen check` after any edit to `agents.yaml`, a prompt or a skill; it
56
- is the cheapest possible test.
57
-
58
- ## Credentials
59
-
60
- ```
61
- zen key ls [--check] what is on the keyring, and whether it works
62
- zen key add <provider>[/name] add one — never on the command line
63
- zen key use <provider>/<name> choose the active key for a provider
64
- zen key check [provider[/name]] a round trip per key
65
- zen key show <provider>[/name] masked, or --reveal for the secret itself
66
- zen key rm <provider>/<name> forget it
67
- zen key env [provider …] `eval "$(zen key env)"` for other tools
68
- ```
69
-
70
- The secret never comes from argv — a command line lands in `ps`, in shell
71
- history and in CI logs. `zen key add` takes it from piped stdin or an echo-off
72
- prompt, and nowhere else. Real environment variables win over the keyring, so
73
- `.env` still decides inside a run.
74
-
75
- ## The sandbox
76
-
77
- ```
78
- zen sandbox status is a container runtime there, is the image pulled
79
- zen sandbox up start it
80
- zen sandbox pull fetch the image ahead of the first run
81
- zen sandbox clean throw away persisted containers
82
- ```
83
-
84
- Shell commands run in a container over the session workspace, not on the host.
85
- If runs begin by installing a toolchain, set `sandbox.image` to one that already
86
- has it, or `sandbox.persist: true`, rather than paying for it every run.
87
-
88
- ## Reports and sessions
89
-
90
- ```
91
- zen list [--sessions] [--prune] every known project
92
- zen inspect [run] [--session <id>] [--open] [--serve] a run's report.html
93
- zen open [project] [--editor <cmd>] [--wait] open it in an editor
94
- zen version CLI, library and Node
95
- ```
96
-
97
- `zen inspect` renders the trajectory of a run — every message, tool call, skill
98
- activation and handoff, in order, with what each one cost. It is the first place
99
- to look when behaviour is wrong and the prompt looks right: it shows what the
100
- model was actually given, which is rarely what you assumed.
101
-
102
- Sessions live under `sessions/` and hold run state, memory, blobs and whatever
103
- the agent wrote. None of it is source and none of it is committed.
104
-
105
- ## Exit codes
106
-
107
- Non-zero on failure, with the offending key or file named in the message. A load
108
- error names the exact path — `agents.yaml: agents[1].skills.discovery — …` — so
109
- read it rather than guessing; the loader is strict on purpose and an unknown key
110
- is an error, not a value quietly ignored.