@zenera/cli 1.1.36 → 1.1.39

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 (72) hide show
  1. package/README.md +158 -900
  2. package/dist/archive.js +1 -1
  3. package/dist/batch.js +2 -3
  4. package/dist/cache.js +1 -1
  5. package/dist/candidates.js +1 -1
  6. package/dist/catalog.d.ts +1 -1
  7. package/dist/catalog.js +1 -1
  8. package/dist/commands/cache.js +1 -1
  9. package/dist/commands/check.js +1 -3
  10. package/dist/commands/export.js +1 -3
  11. package/dist/commands/import.js +1 -2
  12. package/dist/commands/index.js +6 -7
  13. package/dist/commands/init.js +1 -4
  14. package/dist/commands/inspect.d.ts +1 -1
  15. package/dist/commands/inspect.js +1 -4
  16. package/dist/commands/key.js +1 -2
  17. package/dist/commands/list.js +4 -5
  18. package/dist/commands/memory.js +1 -2
  19. package/dist/commands/meta.js +2 -4
  20. package/dist/commands/models.d.ts +1 -1
  21. package/dist/commands/models.js +1 -2
  22. package/dist/commands/run.js +2 -2
  23. package/dist/commands/sandbox.js +6 -7
  24. package/dist/engine.d.ts +3 -90
  25. package/dist/engine.js +16 -302
  26. package/dist/external.js +1 -1
  27. package/dist/history.js +1 -1
  28. package/dist/lib.d.ts +1 -2
  29. package/dist/lib.js +1 -2
  30. package/dist/liveness.d.ts +1 -1
  31. package/dist/liveness.js +1 -1
  32. package/dist/meta/host.d.ts +1 -2
  33. package/dist/meta/host.js +1 -2
  34. package/dist/modelref.d.ts +1 -1
  35. package/dist/podman.d.ts +1 -1
  36. package/dist/podman.js +4 -4
  37. package/dist/resolve.d.ts +2 -2
  38. package/dist/resolve.js +2 -3
  39. package/dist/resources.d.ts +2 -2
  40. package/dist/resources.js +6 -6
  41. package/dist/sandbox.d.ts +2 -60
  42. package/dist/sandbox.js +1 -200
  43. package/dist/term.d.ts +1 -22
  44. package/dist/term.js +3 -26
  45. package/dist/tui/app.js +1 -1
  46. package/dist/tui/models.d.ts +1 -1
  47. package/dist/validate.d.ts +1 -2
  48. package/dist/validate.js +1 -3
  49. package/package.json +7 -6
  50. package/templates/editor/.github/skills/zen-cli/SKILL.md +3 -3
  51. package/templates/editor/.github/skills/zen-cli/references/frame.md +2 -2
  52. package/templates/editor/.github/skills/zen-cli/references/{faker.md → gym.md} +45 -40
  53. package/templates/editor/.github/skills/zen-cli/references/keys.md +2 -2
  54. package/templates/editor/.github/skills/zen-cli/references/models.md +1 -1
  55. package/templates/editor/.github/skills/zen-cli/references/rag.md +1 -1
  56. package/templates/editor/.vscode/agents.schema.json +1 -1
  57. package/dist/audit.d.ts +0 -58
  58. package/dist/audit.js +0 -148
  59. package/dist/env.d.ts +0 -20
  60. package/dist/env.js +0 -65
  61. package/dist/home.d.ts +0 -35
  62. package/dist/home.js +0 -112
  63. package/dist/ids.d.ts +0 -12
  64. package/dist/ids.js +0 -44
  65. package/dist/image.d.ts +0 -16
  66. package/dist/image.js +0 -85
  67. package/dist/keys.d.ts +0 -269
  68. package/dist/keys.js +0 -624
  69. package/dist/projects.d.ts +0 -91
  70. package/dist/projects.js +0 -303
  71. package/dist/session.d.ts +0 -112
  72. package/dist/session.js +0 -188
package/dist/sandbox.js CHANGED
@@ -1,202 +1,12 @@
1
- import { DEFAULT_SANDBOX_IMAGE, GATEWAY_URL_ENV, SANDBOX_GROUP, SandboxPool, } from '@zenera/neo';
2
- import { mkdirSync } from 'node:fs';
3
- import { basename, join } from 'node:path';
4
- import { resolveBuild } from "./image.js";
5
- import { credentials } from "./keys.js";
6
1
  import { assertLocks, ensurePodmanReady } from "./podman.js";
7
- import { warn } from "./term.js";
8
- // ---------------------------------------------------------------------------
9
- // The sandbox, as this CLI wires it
10
- //
11
- // The library takes resolved values; the config states names and numbers. This
12
- // is the layer between the two, and it owns the two decisions the library has
13
- // no business making: which host variables are worth forwarding, and where the
14
- // container's home directory lives.
15
- //
16
- // It lives in the session directory, which is the whole point. A session is
17
- // already a self-contained thing — copy the directory and its conversation,
18
- // memory and blobs travel with it — and a `pip install --user` that vanished
19
- // on close would be the only part of a session that did not. So `$HOME` is a
20
- // bind mount into `.data/sandbox/home`, and what the agent installs for itself
21
- // is still there when the session is opened again. Everything *outside* the
22
- // mounts is throwaway, which is what keeps a stale container from becoming a
23
- // second, invisible configuration.
24
- // ---------------------------------------------------------------------------
25
- /** Where the persistent home lives, inside the container. */
26
- const HOME = '/home/agent';
27
- /** Where a credential *file* is mounted, inside the container. */
28
- const KEY_MOUNT = '/run/zenera/keys';
29
- /**
30
- * The credentials the run is using, in the form a container takes.
31
- *
32
- * Two shapes, two mechanisms. A secret is forwarded by *name* — podman reads
33
- * the value from its own environment, so nothing is written into an argv that
34
- * `ps` will show. A service-account file has to be present as a file, so the
35
- * one file is bind-mounted read-only and the variable is rewritten to where it
36
- * landed; mounting the directory it came from would drag in whatever else the
37
- * user keeps beside it.
38
- *
39
- * This is the part of the design that gives something away, and it should be
40
- * said plainly: the sandbox runs code the model wrote, and a key it can read
41
- * is a key it can send. `keys: false`, or `network: none`, is the answer for a
42
- * project where that is not an acceptable trade.
43
- */
44
- function forwarded() {
45
- const secrets = [];
46
- const env = {};
47
- const mounts = [];
48
- for (const cred of credentials()) {
49
- if (cred.holds === 'file') {
50
- const at = `${KEY_MOUNT}/${basename(cred.value)}`;
51
- mounts.push({ host: cred.value, at, readOnly: true });
52
- env[cred.env] = at;
53
- continue;
54
- }
55
- secrets.push(cred.env);
56
- }
57
- // Not secrets, and useless without one: a service account says which
58
- // project it belongs to but never which region to call, and a gateway key
59
- // says nothing of where the gateway is.
60
- for (const name of ['GOOGLE_CLOUD_PROJECT', 'GOOGLE_CLOUD_LOCATION', GATEWAY_URL_ENV]) {
61
- const value = process.env[name];
62
- if (value) {
63
- env[name] = value;
64
- }
65
- }
66
- return { secrets, env, mounts };
67
- }
68
- export function buildSandbox(opts) {
69
- // An explicit --image is an answer, so there is nothing left to build.
70
- const build = opts.image ? undefined : resolveBuild(opts.root, opts.config.sandbox);
71
- const base = {
72
- ...(opts.config.sandbox ?? {}),
73
- ...((opts.image ?? build?.tag) ? { image: opts.image ?? build?.tag } : {}),
74
- ...(opts.keys === false ? { keys: false } : {}),
75
- ...(opts.persist === false ? { persist: false } : {}),
76
- };
77
- const home = join(opts.session.data, 'sandbox', 'home');
78
- const mounts = [{ host: home, at: HOME }, ...(opts.mounts ?? [])];
79
- const keys = base.keys === false ? undefined : forwarded();
80
- if (keys) {
81
- mounts.push(...keys.mounts);
82
- }
83
- // Skills and assets are mounted read-only, and a python script run from a
84
- // read-only directory fails on writing its own `__pycache__` — a confusing
85
- // error about a file nobody asked for.
86
- // `ZENERA_AGENT` tells a `zen` run by `run_command` that no person is there.
87
- const extra = { HOME, PYTHONDONTWRITEBYTECODE: '1', ZENERA_AGENT: '1', ...(keys?.env ?? {}) };
88
- const spec = toSpec(base, extra, secretsOf(keys?.secrets, opts.env));
89
- const agents = {};
90
- for (const agent of opts.config.agents) {
91
- if (agent.sandbox) {
92
- const merged = merge(base, agent.sandbox);
93
- if (opts.persist === false) {
94
- merged.persist = false;
95
- }
96
- // An agent that opts out gets neither the variables nor the mount,
97
- // but the mount is on the pool and cannot be taken back per agent —
98
- // so the variable is what actually decides, and without it the file
99
- // sitting there is not a credential anything will look for.
100
- const own = merged.keys === false ? undefined : keys;
101
- agents[agent.name] = toSpec(merged, { HOME, PYTHONDONTWRITEBYTECODE: '1', ZENERA_AGENT: '1', ...(own?.env ?? {}) }, own && secretsOf(own.secrets, opts.env));
102
- }
103
- }
104
- const pool = new SandboxPool({
105
- ...spec,
106
- agents,
107
- root: opts.workspace,
108
- key: opts.session.id,
109
- readOnly: opts.readOnly,
110
- mounts,
111
- });
112
- return { pool, spec, image: spec.image ?? DEFAULT_SANDBOX_IMAGE, build, home, mounts };
113
- }
114
- /**
115
- * An agent's overrides on the project's block. `image` and `build` answer the
116
- * same question, so naming either one drops the other: a plain spread would
117
- * leave an agent's `image` sitting next to the project's `build`, and the
118
- * schema forbids exactly that combination when it is written down.
119
- */
120
- function merge(base, agent) {
121
- const merged = { ...base, ...agent };
122
- if (agent.image !== undefined) {
123
- delete merged.build;
124
- }
125
- if (agent.build !== undefined) {
126
- delete merged.image;
127
- }
128
- return merged;
129
- }
130
- /**
131
- * The two sources of forwarded names, as one list: the credentials the keyring
132
- * selected, and whatever the project's `.env` declares. Deduped, because the
133
- * same variable named twice is the same `--env` twice.
134
- *
135
- * `undefined` in means keys are withheld, and the file goes with them.
136
- */
137
- function secretsOf(secrets, env) {
138
- if (!secrets) {
139
- return undefined;
140
- }
141
- return [...new Set([...secrets, ...(env ?? [])])];
142
- }
143
- /**
144
- * Config names a variable; this reads it. A name that is not set on this host
145
- * is simply not forwarded — an empty string in the container is a different
146
- * thing from an absent one, and tools test for absence.
147
- *
148
- * A name that has already been answered with a value drops off the forwarded
149
- * list: `--env NAME=value` and `--env NAME` are the same variable twice, and
150
- * the one that carries a value is the one that was resolved on purpose. That
151
- * matters for `GOOGLE_APPLICATION_CREDENTIALS`, which is rewritten here to
152
- * where the key file was mounted — a `.env` naming it must not put the host's
153
- * path back, since that path does not exist inside the container.
154
- */
155
- function toSpec(config, extra, secrets) {
156
- const env = { ...extra };
157
- for (const name of config.env ?? []) {
158
- const value = process.env[name];
159
- if (value !== undefined && value !== '') {
160
- env[name] = value;
161
- }
162
- }
163
- return {
164
- image: config.image,
165
- cpus: config.cpus,
166
- memory: config.memory,
167
- network: config.network,
168
- workdir: config.workdir,
169
- timeout: config.timeout,
170
- hardening: config.hardening,
171
- user: config.user,
172
- persist: config.persist,
173
- env,
174
- secrets: secrets?.filter((name) => !(name in env)),
175
- };
176
- }
177
- /**
178
- * Whether anything in this project can reach a shell.
179
- *
180
- * Read off the *resolved* tool lists rather than off the config's selectors,
181
- * because `sandbox:*`, `*` and a bare name all mean the same thing by the time
182
- * the loader is done, and only one of those three is greppable.
183
- */
184
- export function usesSandbox(project) {
185
- return project.agents.some((a) => a.tools.some((t) => t.group === SANDBOX_GROUP));
186
- }
187
2
  /**
188
3
  * Images this process has already settled. A batch opens the same project
189
4
  * dozens of times at once, and without this each one shells out to podman and
190
5
  * the concurrent copies race each other to pull the very same image.
191
6
  */
192
7
  const READY = new Set();
193
- /**
194
- * Asked before the first turn rather than at the first tool call, so a missing
195
- * container engine costs nothing instead of costing a round trip and half a
196
- * plan. A project that never shells out never gets here at all.
197
- */
8
+ /** The engine's preflight on a terminal: podman is offered for install and started if needed. */
198
9
  export async function preflight(setup, yes) {
199
- mkdirSync(setup.home, { recursive: true });
200
10
  if (READY.has(setup.image)) {
201
11
  return;
202
12
  }
@@ -211,13 +21,4 @@ export async function preflight(setup, yes) {
211
21
  await assertLocks(1, { reuses: setup.pool.for().name });
212
22
  READY.add(setup.image);
213
23
  }
214
- /** Best-effort teardown: losing a container must never lose a run. */
215
- export async function teardown(pool) {
216
- try {
217
- await pool.dispose();
218
- }
219
- catch (err) {
220
- warn(`could not clean up the sandbox: ${err instanceof Error ? err.message : String(err)}`);
221
- }
222
- }
223
24
  //# sourceMappingURL=sandbox.js.map
package/dist/term.d.ts CHANGED
@@ -1,25 +1,4 @@
1
- export declare const EXIT: {
2
- readonly ok: 0;
3
- readonly failed: 1;
4
- readonly usage: 2;
5
- readonly invalid: 3;
6
- readonly credentials: 4;
7
- readonly sandbox: 5;
8
- };
9
- export type ExitCode = (typeof EXIT)[keyof typeof EXIT];
10
- /**
11
- * An error that already knows what it means. Anything else reaching the top is
12
- * a bug and exits `failed`, which is the distinction a script needs: a wrong
13
- * invocation and a wrong answer are not the same failure.
14
- */
15
- export declare class CliError extends Error {
16
- readonly code: ExitCode;
17
- readonly hint?: string;
18
- constructor(message: string, code?: ExitCode, hint?: string);
19
- }
20
- export declare const usageError: (m: string, hint?: string) => CliError;
21
- export declare const invalidError: (m: string, hint?: string) => CliError;
22
- export declare const credentialError: (m: string, hint?: string) => CliError;
1
+ export { EngineError as CliError, credentialError, EXIT, invalidError, usageError, type ExitCode, } from '@zenera/engine';
23
2
  export type Appearance = 'dark' | 'light';
24
3
  /** One grey per background. The only 256-colour indices in the CLI. */
25
4
  export declare const CHROME: Record<Appearance, number>;
package/dist/term.js CHANGED
@@ -11,32 +11,9 @@ import { styleText } from 'node:util';
11
11
  // `styleText` no-ops when the stream is not a tty and honours NO_COLOR itself,
12
12
  // so there is no flag to thread through and no piped output to garble.
13
13
  // ---------------------------------------------------------------------------
14
- export const EXIT = {
15
- ok: 0,
16
- failed: 1,
17
- usage: 2,
18
- invalid: 3,
19
- credentials: 4,
20
- sandbox: 5,
21
- };
22
- /**
23
- * An error that already knows what it means. Anything else reaching the top is
24
- * a bug and exits `failed`, which is the distinction a script needs: a wrong
25
- * invocation and a wrong answer are not the same failure.
26
- */
27
- export class CliError extends Error {
28
- code;
29
- hint;
30
- constructor(message, code = EXIT.failed, hint) {
31
- super(message);
32
- this.name = 'CliError';
33
- this.code = code;
34
- this.hint = hint;
35
- }
36
- }
37
- export const usageError = (m, hint) => new CliError(m, EXIT.usage, hint);
38
- export const invalidError = (m, hint) => new CliError(m, EXIT.invalid, hint);
39
- export const credentialError = (m, hint) => new CliError(m, EXIT.credentials, hint);
14
+ // The engine raises these too, so `instanceof CliError` holds for its errors.
15
+ import { usageError } from '@zenera/engine';
16
+ export { EngineError as CliError, credentialError, EXIT, invalidError, usageError, } from '@zenera/engine';
40
17
  /** One grey per background. The only 256-colour indices in the CLI. */
41
18
  export const CHROME = { dark: 245, light: 242 };
42
19
  let sniffed;
package/dist/tui/app.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { TextInput } from '@inkjs/ui';
3
+ import { display } from '@zenera/engine';
3
4
  import { addUsage, isCheckpoint, turns, zeroUsage, } from '@zenera/neo';
4
5
  import { Box, Static, Text, useApp, useInput, useStdout } from 'ink';
5
6
  import { pathToFileURL } from 'node:url';
@@ -7,7 +8,6 @@ import React, { useCallback, useContext, useEffect, useRef, useState } from 'rea
7
8
  import * as Engine from "../engine.js";
8
9
  import { History } from "../history.js";
9
10
  import { format } from "../narrate.js";
10
- import { display } from "../session.js";
11
11
  import { CliError } from "../term.js";
12
12
  import { hostUrls, hyperlink, hyperlinks, linkBlock, mountsOf } from "./links.js";
13
13
  import { resolveTheme, THEMES } from "./theme.js";
@@ -1,5 +1,5 @@
1
+ import type { Provider } from '@zenera/engine';
1
2
  import { type Balance, type Catalog, type CatalogEntry, type Role } from '../catalog.ts';
2
- import type { Provider } from '../keys.ts';
3
3
  export interface ProviderRow {
4
4
  provider: Provider;
5
5
  /** where its credential came from — `environment`, `keyring` — or '' for none */
@@ -1,6 +1,5 @@
1
+ import { type DeclaredRole, type KeyStore, type Liveness } from '@zenera/engine';
1
2
  import { type AnyTool, type ProjectConfig, type Runner } from '@zenera/neo';
2
- import { type DeclaredRole } from './audit.ts';
3
- import { type KeyStore, type Liveness } from './keys.ts';
4
3
  /**
5
4
  * `error` — the project will not load, or will not run.
6
5
  * `warning` — it loads, and something about it is probably not what was meant.
package/dist/validate.js CHANGED
@@ -1,10 +1,8 @@
1
+ import { SHAPES, auditModels, credentialFor, envNames, form, resolveBuild, } from '@zenera/engine';
1
2
  import { EXA_GROUP, FileSkillProvider, SANDBOX_MOUNT, Sandbox, exaTools, fileTools, frontmatter, projectRegistry, readProjectConfig, sandboxTools, selectTools, toList, } from '@zenera/neo';
2
3
  import { existsSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, } from 'node:fs';
3
4
  import { tmpdir } from 'node:os';
4
5
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
5
- import { auditModels, credentialFor } from "./audit.js";
6
- import { resolveBuild } from "./image.js";
7
- import { SHAPES, envNames, form } from "./keys.js";
8
6
  import { probeModels } from "./liveness.js";
9
7
  import { BuildError, ensurePodmanReady } from "./podman.js";
10
8
  import { ownVersion, staleShared } from "./scaffold.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenera/cli",
3
- "version": "1.1.36",
3
+ "version": "1.1.39",
4
4
  "description": "Command-line front end for @zenera/neo: agentic projects you can run, share and commit.",
5
5
  "keywords": [
6
6
  "agents",
@@ -15,13 +15,13 @@
15
15
  "access": "public"
16
16
  },
17
17
  "author": "Andrey Ryabov",
18
- "homepage": "https://github.com/andreyryabov/ZeneraNeo#readme",
18
+ "homepage": "https://github.com/zenera-ai/ZeneraNeo#readme",
19
19
  "repository": {
20
20
  "type": "git",
21
- "url": "git+https://github.com/andreyryabov/ZeneraNeo.git",
21
+ "url": "git+https://github.com/zenera-ai/ZeneraNeo.git",
22
22
  "directory": "packages/cli"
23
23
  },
24
- "bugs": "https://github.com/andreyryabov/ZeneraNeo/issues",
24
+ "bugs": "https://github.com/zenera-ai/ZeneraNeo/issues",
25
25
  "type": "module",
26
26
  "bin": {
27
27
  "zen": "./dist/main.js",
@@ -54,8 +54,9 @@
54
54
  "@google/genai": "^2.30.0",
55
55
  "@inkjs/ui": "^2.0.0",
56
56
  "@openrouter/sdk": "^1.4.25",
57
- "@zenera/neo": "^1.1.36",
58
- "@zenera/view": "^1.1.36",
57
+ "@zenera/engine": "^1.1.39",
58
+ "@zenera/neo": "^1.1.39",
59
+ "@zenera/view": "^1.1.39",
59
60
  "google-auth-library": "^10.0.0",
60
61
  "ink": "^7.1.1",
61
62
  "openai": "^6.0.0",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: zen-cli
3
- description: How to drive this project from the terminal with `zen` - running it, validating it, credentials, the sandbox, run reports, and the `faker` and `rag` modules.
3
+ description: How to drive this project from the terminal with `zen` - running it, validating it, credentials, the sandbox, run reports, and the `gym` and `rag` modules.
4
4
  ---
5
5
 
6
6
  # The `zen` command line
@@ -33,7 +33,7 @@ zen version
33
33
 
34
34
  zen meta <run|prompts|resume|model|dataset> [project] [args]
35
35
 
36
- zen faker <serve|build|cache> [spec...]
36
+ zen gym <serve|build|cache|model> [spec...]
37
37
  zen rag schema <index|restore|ready|search|list|grep|trace|show|stats> [spec...]
38
38
  zen rag docs <index|restore|ready|search|list|grep|show|stats> [path...]
39
39
  ```
@@ -61,7 +61,7 @@ guess a flag, and do not read them all.
61
61
  | The evaluation dataset: cases, drift, notes, drawing a sample | [dataset.md](./references/dataset.md) (and `zen-dataset` skill) |
62
62
  | Tuning the prose on the dataset: workers, applies, STATUS.md | [finetune.md](./references/finetune.md) |
63
63
  | Sharing a project: archives, what travels, importing one safely | [export.md](./references/export.md) |
64
- | `zen faker` - a mock API from an OpenAPI/Swagger document | [faker.md](./references/faker.md) |
64
+ | `zen gym` - a mock API from an OpenAPI/Swagger document | [gym.md](./references/gym.md) |
65
65
  | `zen rag` - searching an API description, or a pile of markdown | [rag.md](./references/rag.md) |
66
66
 
67
67
  ## The short version
@@ -37,7 +37,7 @@ Not listed in help, but they work.
37
37
  | `validate`, `doctor` | `check` |
38
38
  | `report` | `inspect` |
39
39
  | `edit`, `code` | `open` |
40
- | `mock` | `faker` |
40
+ | `mock` | `gym` |
41
41
 
42
42
  ## stdout is the answer, stderr is the narration
43
43
 
@@ -103,7 +103,7 @@ A real environment variable always beats the keyring.
103
103
  projects.json the registry: name -> directory
104
104
  keys.json credentials (0600)
105
105
  keys/ key files, for providers that hold a file
106
- faker/ generator cache for `zen faker`
106
+ gym/ generator cache for `zen gym`
107
107
 
108
108
  <project>/
109
109
  zenera.json { version, name }
@@ -1,11 +1,11 @@
1
- # Mock APIs - `zen faker`
1
+ # Agent API environments - `zen gym`
2
2
 
3
3
  ```
4
- zen faker <serve|build|cache> [spec...]
4
+ zen gym <serve|build|cache|model> [spec...]
5
5
  ```
6
6
 
7
- Alias: `zen mock`. Provided by `@zenera/faker` - `npm i -g @zenera/faker` if
8
- `zen faker` says it is not installed.
7
+ Provided by `@zenera/gym` - `npm i -g @zenera/gym` if
8
+ `zen gym` says it is not installed.
9
9
 
10
10
  Serves a mock API from one or more OpenAPI/Swagger documents. For each
11
11
  operation a **model writes a Python generator**, which is self-tested inside a
@@ -14,17 +14,18 @@ plausible, not `"string"` repeated.
14
14
 
15
15
  ## Subcommands
16
16
 
17
- | Command | What it does |
18
- | ----------------- | ----------------------------------------------------- |
19
- | `serve <spec...>` | Serve the documents. Generators are written on demand |
20
- | `build <spec...>` | Write every generator now and exit |
21
- | `cache ls\|clear` | What has been generated, or throw it away |
17
+ | Command | What it does |
18
+ | ----------------- | ---------------------------------------------------------- |
19
+ | `serve <spec...>` | Serve the documents. Generators are written on demand |
20
+ | `build <spec...>` | Write every generator now and exit |
21
+ | `cache ls\|clear` | What has been generated, or throw it away |
22
+ | `model [ref]` | Show or set the model; `--clear` forgets the stored choice |
22
23
 
23
24
  ```
24
- zen faker serve openapi.yaml
25
- zen faker serve api/*.yaml --port 9000 --seed 7
26
- zen faker build openapi.yaml --concurrency 8
27
- zen faker cache clear
25
+ zen gym serve openapi.yaml
26
+ zen gym serve api/*.yaml --port 9000 --seed 7
27
+ zen gym build openapi.yaml --concurrency 8
28
+ zen gym cache clear
28
29
  ```
29
30
 
30
31
  `build` is the one to run in CI or before a demo: it pays for every generator up
@@ -32,23 +33,25 @@ front and exits non-zero, with a table, if any could not be written.
32
33
 
33
34
  ## Options
34
35
 
35
- | Flag | Default | Meaning |
36
- | ------------------- | --------------------- | ----------------------------------------------- |
37
- | `--port <n>` | `8787` | Port to listen on |
38
- | `--host <h>` | `127.0.0.1` | Anything else is reachable off-machine |
39
- | `--model <ref>` | project default | Which model writes the generators |
40
- | `--image <ref>` | a baked image | Skip the baked image and use this one |
41
- | `--cache <dir>` | `~/.zenera/neo/faker` | Where generators live |
42
- | `--seed <n>` | - | Answer the same request the same way every time |
43
- | `--attempts <n>` | `3` | Tries per generator before giving up |
44
- | `--concurrency <n>` | `4` | Generators written at once |
45
- | `--timeout <s>` | `30` | Seconds one generator may take |
46
- | `--max-body <n>` | 1 MB | Largest request body accepted, in bytes |
47
- | `--rebuild` | - | Ignore what is cached and write it again |
48
- | `--no-cache` | - | Do not record what is written |
49
- | `--quiet` | - | No narration |
36
+ | Flag | Default | Meaning |
37
+ | ------------------- | ------------------- | ----------------------------------------------- |
38
+ | `--port <n>` | `8787` | Port to listen on |
39
+ | `--host <h>` | `127.0.0.1` | Anything else is reachable off-machine |
40
+ | `--model <ref>` | project default | Which model writes the generators |
41
+ | `--image <ref>` | a baked image | Skip the baked image and use this one |
42
+ | `--cache <dir>` | `~/.zenera/neo/gym` | Where generators live |
43
+ | `--seed <n>` | - | Answer the same request the same way every time |
44
+ | `--attempts <n>` | `3` | Tries per generator before giving up |
45
+ | `--concurrency <n>` | `4` | Generators written at once |
46
+ | `--timeout <s>` | `30` | Seconds one generator may take |
47
+ | `--max-body <n>` | 1 MB | Largest request body accepted, in bytes |
48
+ | `--rebuild` | - | Ignore what is cached and write it again |
49
+ | `--no-cache` | - | Do not record what is written |
50
+ | `--quiet` | - | No narration |
50
51
 
51
52
  Credentials come from the `zen` keyring - see [keys.md](keys.md).
53
+ Model selection: `--model`, `ZENERA_GYM_MODEL`, `~/.zenera/neo/gym.json`,
54
+ then the best model the available keys support.
52
55
 
53
56
  ## Serving
54
57
 
@@ -56,17 +59,19 @@ Binds the loopback address by default. On start it prints a table per document:
56
59
  paths, methods, and how many operations have a response schema and therefore get
57
60
  a generator.
58
61
 
59
- | Endpoint | Answers |
60
- | ----------------- | ------------------------- |
61
- | `/__faker/routes` | Every route it will serve |
62
- | `/__faker/health` | Whether it is up |
62
+ | Endpoint | Answers |
63
+ | --------------- | ------------------------- |
64
+ | `/__gym/routes` | Every route it will serve |
65
+ | `/__gym/health` | Whether it is up |
63
66
 
64
67
  Response headers:
65
68
 
66
- | Header | Meaning |
67
- | ------------------- | ----------------------------------------------------- |
68
- | `x-faker-operation` | The `operationId` that answered |
69
- | `x-faker-cache` | `hit` or `miss` - whether this call cost a model turn |
69
+ | Header | Meaning |
70
+ | ----------------- | ----------------------------------------------------- |
71
+ | `x-gym-operation` | The `operationId` that answered |
72
+ | `x-gym-cache` | `hit` or `miss` - whether this call cost a model turn |
73
+
74
+ Gym provides simulation, not task scoring, rewards, or a training loop.
70
75
 
71
76
  Incoming headers are filtered: `authorization`, `cookie` and anything matching
72
77
  `key|token|secret|password|credential` never reach a generator.
@@ -91,7 +96,7 @@ Probes are synthetic on purpose - real request bodies never reach a prompt.
91
96
 
92
97
  ## The cache
93
98
 
94
- Generators live in the machine's shared cache, `~/.zenera/neo/cache/faker-generator/`,
99
+ Generators live in the machine's shared cache, `~/.zenera/neo/cache/gym-generator/`,
95
100
  keyed by the operation's shape - so the same spec served from two directories is
96
101
  written once, and a spec edit produces a new key rather than a stale answer. A
97
102
  generator that a model gave up on is remembered for the life of the process, so
@@ -99,17 +104,17 @@ a hopeless operation is not re-asked on every request; a _transient_ failure - a
99
104
  429, a dropped socket - is not, because it is about this minute rather than this
100
105
  operation.
101
106
 
102
- `~/.zenera/neo/faker/` is the container's workspace, and scratch: a cache hit is
107
+ `~/.zenera/neo/gym/` is the container's workspace, and scratch: a cache hit is
103
108
  copied into it, because the container can only run what is under its mount.
104
109
 
105
- `zen faker cache ls` lists what has been generated. `zen faker cache clear`
110
+ `zen gym cache ls` lists what has been generated. `zen gym cache clear`
106
111
  removes the generators, the workspace and the container together. They have to
107
112
  go together: the container's name is a hash of its configuration, so deleting
108
113
  the workspace alone would leave a stopped container bind-mounted onto a
109
114
  directory that no longer exists, and every generator would fail with
110
115
  `python3: can't open file '/workspace/generators/…/gen.py'`.
111
116
 
112
- `zen cache ls --kind faker-generator` reaches the same entries from the other
117
+ `zen cache ls --kind gym-generator` reaches the same entries from the other
113
118
  side, along with everything else this machine has cached.
114
119
 
115
120
  ## Documents it accepts
@@ -77,7 +77,7 @@ turns gateway mode on without the keyring - and `zen key mode`/`ls`/`check`
77
77
  report and probe it (`bifrost/$BIFROST_API_KEY`), with nothing stored. In this
78
78
  mode `zen models` lists only
79
79
  what the gateway serves - see `models.md`. The full guide is
80
- [docs/gateway.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/gateway.md).
80
+ [docs/gateway.md](https://github.com/zenera-ai/ZeneraNeo/blob/main/docs/gateway.md).
81
81
 
82
82
  ### Vertex takes either shape
83
83
 
@@ -141,6 +141,6 @@ The frame does **not** materialise the keyring for you - each command that needs
141
141
  a credential opens the store itself. If `zen key ls` shows a key as live and a
142
142
  command still says `provider "openai": no api key - set OPENAI_API_KEY`, the
143
143
  credential is fine and the command is at fault. Everything that runs a model
144
- (`run`, `check`, `models`, `faker`, `rag`) already does this.
144
+ (`run`, `check`, `models`, `gym`, `rag`) already does this.
145
145
 
146
146
  Exit code `4` means no usable credential for what was asked.
@@ -58,7 +58,7 @@ stderr with a `⇄ bifrost mode` line, `browse` carries the same badge on every
58
58
  screen, and `--json` adds a `gateway` field. `zen models` then does go to the
59
59
  network, since one request covers every provider; `test` asks through the
60
60
  gateway too. The full guide is
61
- [docs/gateway.md](https://github.com/andreyryabov/ZeneraNeo/blob/main/docs/gateway.md).
61
+ [docs/gateway.md](https://github.com/zenera-ai/ZeneraNeo/blob/main/docs/gateway.md).
62
62
 
63
63
  ## Testing a model
64
64
 
@@ -34,7 +34,7 @@ zen rag schema index <spec...> [--embedding <ref>] [-o <dir>] [--batch <n>]
34
34
  zen rag schema index openapi.yaml --embedding openai:text-embedding-3-small
35
35
  ```
36
36
 
37
- Unlike the faker, `$ref`s are **bundled, not dereferenced**: component names are
37
+ Unlike the gym, `$ref`s are **bundled, not dereferenced**: component names are
38
38
  the node ids and the cycles between them are the edges. `discriminator` is kept -
39
39
  it is what turns a `oneOf` into a tagged union a compiler can narrow.
40
40
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://raw.githubusercontent.com/andreyryabov/ZeneraNeo/main/packages/cli/templates/editor/.vscode/agents.schema.json",
3
+ "$id": "https://raw.githubusercontent.com/zenera-ai/ZeneraNeo/main/packages/cli/templates/editor/.vscode/agents.schema.json",
4
4
  "title": "Zenera Neo agents.yaml",
5
5
  "description": "Who exists in this project, what they may reach for, and which model answers for them. Written by `zen init` and replaced by every `zen init` and `zen open`, so it describes the version of `zen` in hand. The runtime is the authority: `zen check` reads the project the way a run does.",
6
6
  "type": "object",