nylorun 0.12.2-beta → 0.14.0-beta

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/CHANGELOG.md CHANGED
@@ -1,5 +1,79 @@
1
1
  # nylorun
2
2
 
3
+ ## 0.14.0-beta
4
+
5
+ ### Minor Changes
6
+
7
+ - 35e29b7: **Environments replace sandboxes and vaults (protocol 11). This is a fresh start: upgrading deletes your sandboxes, their disks and every vault except the model's, and closes every open session (its history stays readable).** List what you have before upgrading; see "Environments replace sandboxes and vaults" in MIGRATION.md.
8
+
9
+ An Environment is where sessions run: one sandbox (kind `virtual`, `pod` or `none`) with a recipe that can change, and one vault of secrets for its shell, MCP servers and HTTP tools. The app decides who uses which Environment; the Runtime keeps it by id and holds its lifecycle.
10
+
11
+ - `@nylorun/core`: protocol 11 (the Host accepts 11 only; older clients get `426`), required feature `environments`. `PutEnvironmentRequestSchema`, `EnvironmentViewSchema` (`recipe`, `version`, `appliedVersion`, `ownerUserId`, `lastUsedAt`), `PutEnvironmentSecretRequestSchema`, `EnvironmentSecretViewSchema`, `ENVIRONMENT_EVENT_TYPES`, `TenantEnvironmentsConfigSchema`, `environmentGranted`. `PutSessionRequest.environment` replaces `sandbox`, `vaultIds` and `credentialSelections`; `SessionView.environment` replaces the session's sandbox and vault fields. Error codes `environment_busy`, `environment_unavailable`, `environment_lost`, `environment_not_granted`, `environment_owner_mismatch` and `session_closed` (the `sandbox_*` codes and `sandbox_expired` are gone); session events `environment.state`, `environment.exec` and `environment.attached`; scope `environments:write`. Credential coverage takes `environmentId` and answers `covered` or `missing`; the MCP preview takes `environmentId`. The vault Management schemas are removed.
12
+ - `@nylorun/runtime`: `/v1/environments/{id}` replaces `/v1/sandboxes/{id}`: `PUT` creates, finds or changes one (`kind` and `storage` fixed; a recipe change bumps `version`; a pod gets a new image or resources at its next start from stopped, a new allowlist within seconds), with list by label, events (`nylorun.environment-event/1`), stop, reset and delete. Each Environment owns one vault: `PUT|GET|DELETE /v1/environments/{id}/secrets/{name}` on the Runtime API, write-only, with a second credential for a host or URL refused at the write (`409 credential_conflict`). An optional owner guard (`ownerUserId`) is checked when a session opens and at every turn start. `lifecycle.deleteAfter` deletes an Environment unused that long; TTL and `onExpiry` are gone. Kind `none` holds secrets for MCP-only agents. `/v1/tenant/vaults`, user and installation vaults, the Tenant's default sandbox, inline sandboxes and `{ session }` sharing are removed. The Tenant setting is `environments.config` (`limits.environments`). Identity files grant `environments:` (an old `sandboxes:` key, or `sandboxes:write`, stops the Runtime with a message naming the new key). Migration `0020_environments`.
13
+ - `@nylorun/harness`: the Harness API claims `environment.state` and `environment.exec`, and its workspace fields name `environmentId`.
14
+ - `@nylorun/agents`: `client.environments` (`put`, `get`, `list`, `page`, `stop`, `reset`, `delete`, `events`, `secrets.put|list|get|delete`, `forSession`) replaces `client.sandboxes`; `createSession({ environment })`; `sessions.page({ environmentId })` filters by Environment. The AG-UI handler's session options take `environment`.
15
+ - `@nylorun/admin`: `admin.coverage({ agentId, environmentId })` replaces `admin.vaults`; `admin.mcp.preview({ url, environmentId })`.
16
+ - `@nylorun/studio`: Environments replace Sandboxes, with a create form, stop, reset, delete and their secrets; the Credentials forms write an Environment's secrets; New session picks an Environment and shows its coverage.
17
+ - `nylorun`: `nylorun sandbox ls|rm` list and delete Environments; `nylorun mcp inspect --environment <id>` replaces `--vault`; `nylo reset --environments` replaces `--sandboxes`; `nylo doctor sandbox` reports the Environment limits.
18
+
19
+ - 7800358: **Each turn is one OpenTelemetry trace, projected from the session log (R7).** An operator could not see what a turn did or where its time went without grepping container logs. Now every turn is a trace with a span for each model call, tool call and egress tunnel, exported over OTLP to any collector, readable per turn from the Runtime, and joined to the trace of the app that started it. No protocol change.
20
+
21
+ - **Traces from the log.** A turn's end is its root span, `invoke_agent <agent>`; each model call is a `chat <model>` span, each tool call and flow HTTP stage an `execute_tool <tool>` span, each egress-gate tunnel a `CONNECT <host>` span, and each pause and answer a marker. A model or gate tool span is the gate's own start and end; usage and cost are the gate's (`nylorun.usage.mismatch` when the harness reported other numbers). Attribute names follow the OTel GenAI conventions at one pinned commit, recorded as `nylorun.semconv.genai` on the resource. Ids are derived from the log under a key the Tenant keeps (setting `trace.key`), so every export and read of a turn gives the same ids.
22
+ - **OTLP export, off until you set an endpoint.** With `OTEL_EXPORTER_OTLP_ENDPOINT` (or `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`) the Runtime posts OTLP/HTTP JSON from a replication slot of its own, `nylorun_trace_export`, in batches of up to 512 spans or every 2 s; `OTEL_EXPORTER_OTLP_HEADERS`, `OTEL_SERVICE_NAME` and `OTEL_RESOURCE_ATTRIBUTES` work as usual. No turn waits for it. A collector that is down costs only its spans: after three retries a batch is dropped and logged as `trace_export_dropped`, and the slot moves on, so Postgres keeps no WAL for it. `nylorun start` passes these variables to the runtime container.
23
+ - **References by default.** Spans point at log events (`nylorun.event.cursor`) and carry no content unless you opt in per kind with `NYLORUN_TRACE_CONTENT` (`user`, `outputs`, `tool-results`, `errors`), or all of them with `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true`, each cut at 8 KiB. A span never carries a credential value, a prompt, a person's id, an identity header or an idempotency key.
24
+ - **`GET /v1/sessions/{id}/turns/{turnId}/trace`** answers a turn's spans as OTLP JSON, the same spans the exporter posts: look at a turn without a collector, or post it to one to backfill. Application keys, as the `/calls` reads. Host feature `traces`; `@nylorun/agents` adds `session.trace(turnId)`, and `@nylorun/core/contracts` `TurnTraceSchema`.
25
+ - **Trace context in and out.** A `traceparent` (and `tracestate`) on `POST /v1/sessions/{id}/commands`, an AG-UI run or an A2A message puts the turn in the caller's trace; `command.message` records it as `trace`. The turn hands its context on: to the harness in `TurnStart.trace`, to HTTP tools as `traceparent` beside `Idempotency-Key`, to MCP servers as `traceparent` on the call's requests, and to sandbox commands as `TRACEPARENT`.
26
+ - **Harness API** (additive): the `effect.intent` answer `execute` may carry the tool call's `traceparent`. `@nylorun/harness`: `HarnessExecutors.tool` takes it as a fourth argument (`ToolCallContext`).
27
+
28
+ ### Patch Changes
29
+
30
+ - a0cbca1: **Clearer wording when a definition runs your code.** The refusal for a code tool or a flow's tool stage, the `hooks were removed` error and `nylo endpoints` now say that the Runtime runs agents from their manifests alone, instead of that it runs no code of yours during a session. Only the message text changed; anything matching the old wording (for example `runs no code of yours during a session`) needs the new text.
31
+ - Pin core to the tested release.
32
+ - Pin admin to the tested release.
33
+ - Pin runtime to the tested release.
34
+ - Pin studio to the tested release.
35
+ - Updated dependencies [17a97e9]
36
+ - Updated dependencies [b6214d9]
37
+ - Updated dependencies [e917bd6]
38
+ - Updated dependencies [5165451]
39
+ - Updated dependencies [35e29b7]
40
+ - Updated dependencies [e917bd6]
41
+ - Updated dependencies [a0cbca1]
42
+ - Updated dependencies [3013501]
43
+ - Updated dependencies [6061a3a]
44
+ - Updated dependencies [7d496e4]
45
+ - Updated dependencies [81c783e]
46
+ - Updated dependencies [7800358]
47
+ - Updated dependencies
48
+ - @nylorun/core@0.20.0-beta
49
+ - @nylorun/admin@0.16.0-beta
50
+
51
+ ## 0.13.0-beta
52
+
53
+ ### Minor Changes
54
+
55
+ - 1345f61: **`nylo` ships in `nylorun`; `@nylorun/cli` is deprecated.** One package runs a project's local Tenant (`nylorun`) and is the Runtime client of the linked installation (`nylo`). MIGRATION.md ("`nylo` ships in `nylorun`") has the details.
56
+
57
+ - `nylorun`: a second bin, `nylo` (`npx -p nylorun nylo <command>`), with the same commands, flags, output and exit codes as `@nylorun/cli`'s. The `nylorun` command never loads it. nylorun now depends on `@nylorun/admin`, which `nylo` uses. `nylo configure`'s provider sign-in comes from `@earendil-works/pi-ai` (about 100 MB with its provider SDKs), which is not a dependency: the first `nylo configure` installs the tested version into `~/.nylorun/lib/pi-ai-<version>/` with npm, without install scripts, unless it resolves beside nylorun, so `npx nylorun` stays about 11 MB. `nylorun configure`, `nylorun status --env` and `nylorun doctor sandbox` still exit 2, now naming `npx -p nylorun nylo …`. `nylorun status|reset` (the local Tenant's containers and volumes) and `nylo status|reset` (the Management API) keep their meanings; both usages and the README say which is which.
58
+ - **Deprecated (`@nylorun/cli`):** its `nylo` prints one line on stderr and runs nylorun's `nylo` with the same arguments and exit code; stdout is unchanged, so `eval "$(npx @nylorun/cli env)"` still works. It depends on `nylorun` only. A later release removes it.
59
+ - **Breaking (`@nylorun/admin`): the `./project` subpath is removed.** It re-exported `@nylorun/core/project` for `nylo`, which now imports Core directly. Import `@nylorun/core/project` instead.
60
+ - `@nylorun/create-agent`: `compatibility.json` no longer pins `@nylorun/cli`; the examples run `nylo` from their `nylorun` devDependency.
61
+
62
+ ### Patch Changes
63
+
64
+ - 554df94: **Fixes for the one client layer.**
65
+
66
+ - `@nylorun/admin`: `createAdmin` reads the Project link only in its local-Host step. Explicit `url` and `key`, or `NYLORUN_RUNTIME_URL` with `NYLORUN_MANAGEMENT_KEY`, no longer fail on a `.nylorun/link.json` that cannot be read (EACCES for a root-owned file after `sudo npx nylorun start`, EISDIR); the local-Host step refuses such a link, naming it, as it refuses a broken one (when nothing else names the Host root).
67
+ - `@nylorun/admin`: a refusal without the Runtime's rejection body takes its code from the status: `invalid_request` (400), `credential_invalid` (401), `not_found` (404), `unsupported_media_type` (415), `internal_error` (5xx), else `request_rejected`; it was always `not_found`. Studio's own answers (`{ message }`, from its server and proxy, such as "This Studio session is invalid or has expired.") keep their message instead of one naming only the request and the status.
68
+ - `nylorun`: `start` refuses Project or Host root credentials in a newer format than it reads ("Upgrade nylorun"), as it refuses a newer link, instead of replacing them with new keys in its own format.
69
+
70
+ - Pin admin to the tested release.
71
+ - Pin runtime to the tested release.
72
+ - Pin studio to the tested release.
73
+ - Updated dependencies [554df94]
74
+ - Updated dependencies [1345f61]
75
+ - @nylorun/admin@0.15.0-beta
76
+
3
77
  ## 0.12.2-beta
4
78
 
5
79
  ### Patch Changes
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # nylorun
2
2
 
3
3
  Sets up and runs local Nylorun Tenants: the Runtime and Studio, in Docker
4
- Compose, one Tenant per project. It needs nothing in your project; run it with
4
+ Compose, one Tenant per project. Its second command, `nylo`, is the Runtime
5
+ client of the linked installation. It needs nothing in your project; run it with
5
6
  `npx` in the project's directory:
6
7
 
7
8
  ```sh
@@ -14,10 +15,13 @@ and S2, serving exactly that Tenant, and its name is the Tenant's name.
14
15
  `nylorun start` in a project creates the project's Tenant (the Runtime creates
15
16
  it on its first start) and links the project to it; anywhere else, it starts
16
17
  the Tenant `default`. Projects that must not share agents, credentials or
17
- history run separate Tenants. Agents, sessions and model providers belong to
18
- the Runtime client, [`@nylorun/cli`](../cli/README.md) (command `nylo`).
19
- Depends on `@nylorun/core` only among Nylorun packages and never imports
20
- `@nylorun/runtime`. Vocabulary: [runtime/src/CONTEXT.md](../runtime/src/CONTEXT.md).
18
+ history run separate Tenants. The Tenant's status, data, signing keys and model
19
+ provider over its APIs belong to the Runtime client, `nylo`
20
+ ([below](#the-runtime-client-nylo)), which works on a remote installation too.
21
+ Depends on `@nylorun/core` and `@nylorun/admin` (for `nylo`) among Nylorun
22
+ packages and never imports `@nylorun/runtime`; the `nylorun` command loads
23
+ neither `nylo` nor `@nylorun/admin`. Vocabulary:
24
+ [runtime/server/src/CONTEXT.md](../../runtime/server/src/CONTEXT.md).
21
25
 
22
26
  Prerequisites, installed by the developer (nylorun never downloads them): Node
23
27
  24 or newer, and Docker with Compose v2 ([Docker
@@ -44,12 +48,12 @@ nylorun studio [--tenant <name>] [--no-open] # sign a browser in to Studio on
44
48
  nylorun reset [--tenant <name>] [--yes] # delete the Tenant's volumes, Tenant directory and vault key; the next start creates it anew
45
49
  nylorun ls [--json] # the Tenants on this machine, with their state, memory and URLs
46
50
  nylorun delete <tenant> --yes # remove a Tenant: containers, volumes, Host root and vault key
47
- nylorun sandbox ls [--tenant <name>] [--label <key=value>]... [--json] # the running Tenant's sandboxes
48
- nylorun sandbox rm <id> [--tenant <name>] # delete a sandbox and its files
51
+ nylorun sandbox ls [--tenant <name>] [--label <key=value>]... [--json] # the running Tenant's Environments
52
+ nylorun sandbox rm <id> [--tenant <name>] # delete an Environment: its sandbox, files and vault
49
53
  nylorun key put <id> [--management] [--tenant <name>] # create or rotate the Tenant's application key <id> (--management: a management key); prints it once
50
54
  nylorun key list [--tenant <name>] [--json] # the Tenant's keys: id, role, when issued
51
55
  nylorun key rm <id> [--tenant <name>] # delete a key: it stops working at once
52
- nylorun mcp inspect <url> [--server <name>] [--vault <id>] [--sse] [--tenant <name>] [--json] # a remote MCP server's tools, with the installation vault's credential
56
+ nylorun mcp inspect <url> [--server <name>] [--environment <id>] [--sse] [--tenant <name>] [--json] # a remote MCP server's tools, with an Environment's credential
53
57
  nylorun doctor [--json] # prerequisites and the Tenant's health
54
58
  nylorun telemetry [status|enable|disable] # Studio's anonymous usage analytics
55
59
  nylorun sandbox enable --context <name> [--tenant <name>] [--host-address <ip>] [--bind-address <ip>] [--no-pull]
@@ -59,10 +63,15 @@ nylorun sandbox status [--tenant <name>] [--json] # pods on a Kubernetes conte
59
63
 
60
64
  `up` and `down` are the Docker Compose spellings of `start` and `stop`: `down`
61
65
  stops the containers and keeps the volumes, so no Tenant data is lost. Removed
62
- commands exit 2 naming the replacement: `nylorun dev`, `nylorun configure`,
63
- `nylorun status --env`, `nylorun doctor sandbox` and the MCP OAuth `connect`
64
- subcommand of `nylorun mcp` (protocol 10: add a key or a gateway credential to a
65
- vault instead, and preview the server with `nylorun mcp inspect`).
66
+ commands exit 2 naming the replacement: `nylorun dev` and the MCP OAuth `connect`
67
+ subcommand of `nylorun mcp` (protocol 10: write a key or a gateway credential as
68
+ an Environment's secret instead, and preview the server with
69
+ `nylorun mcp inspect --environment <id>`), and `--vault` of `nylorun mcp inspect`
70
+ (protocol 11: `--environment <id>`).
71
+ `nylorun configure`, `nylorun status --env` and `nylorun doctor sandbox` exit 2
72
+ naming `nylo configure`, `nylo env` and `nylo doctor sandbox`.
73
+ `nylorun status` and `nylorun reset` are not `nylo status` and `nylo reset`: see
74
+ [`status` and `reset`](#status-and-reset-nylorun-or-nylo).
66
75
 
67
76
  ## Tenants
68
77
 
@@ -177,7 +186,7 @@ replaced by the application key otherwise.
177
186
 
178
187
  Every Tenant serves the Runtime API, which takes **application keys**, and the
179
188
  Management API (`/v1/tenant/*`), which takes **management keys**
180
- ([SELF_HOSTING.md](../SELF_HOSTING.md#keys)). `nylorun key` manages both on the
189
+ ([SELF_HOSTING.md](../../guides/SELF_HOSTING.md#keys)). `nylorun key` manages both on the
181
190
  running Tenant through `nylorun-operate` in its runtime container, so only this
182
191
  machine can issue a management key.
183
192
 
@@ -194,26 +203,28 @@ application key. `nylorun sandbox` and `nylorun mcp` use the linked project's ke
194
203
 
195
204
  ## MCP servers
196
205
 
197
- An agent names its MCP servers by URL; the operator gives each URL a vault
198
- credential, a `bearer` token or a `headers` map, with `via` and an identity
199
- header when an MCP gateway holds each person's sign-in. Add it on Studio's
200
- Credentials page or with `@nylorun/admin` (no `nylorun` command adds one); the
201
- whole flow, with gateway recipes, is in
202
- [DEPLOYMENT.md](../DEPLOYMENT.md#mcp-servers-and-http-tools).
206
+ An agent names its MCP servers by URL; a session gets a credential for a URL from
207
+ the Environment it is opened on (`createSession({ environment })`): a secret of that
208
+ Environment, a `bearer` token or a `headers` map, with `via` and an identity
209
+ header when an MCP gateway holds each person's sign-in. Write it with
210
+ `client.environments.secrets.put(id, name, secret)` of `@nylorun/agents` (the
211
+ Runtime API, an application key) or in Studio; no `nylorun` command writes one.
212
+ The whole flow, with gateway recipes, is in
213
+ [DEPLOYMENT.md](../../guides/DEPLOYMENT.md#mcp-servers-and-http-tools).
203
214
 
204
215
  `nylorun mcp inspect <url>` shows what a remote MCP server offers before an
205
216
  agent names it, through the running Tenant's Management API
206
217
  (`POST /v1/tenant/mcp/preview`, with the management key). The Runtime connects
207
- with the installation vault's credential for `<url>` (`--vault <id>` picks the
208
- vault when several hold one), lists the tools within 15 s and calls none. It
218
+ with Environment `<id>`'s credential for `<url>` when `--environment <id>` names one
219
+ (without it, no credential is sent), lists the tools within 15 s and calls none. It
209
220
  prints a table of each tool's model name, input schema size, hints
210
221
  (`read-only`, `destructive`, `idempotent`) and description, then the tools
211
222
  renamed for the model. `--server` is the server name your manifest uses (default:
212
223
  the host's name, `linear` for `mcp.linear.app`); `--sse` speaks the older SSE
213
224
  transport; `--json` prints the Runtime's answer. A server that answers `401`
214
225
  needs a credential: it says so, and names the server's sign-in from its
215
- protected-resource metadata, since such a server needs a key in a vault or an
216
- MCP gateway that holds each person's sign-in. A server it cannot list exits 1 with
226
+ protected-resource metadata, since such a server needs a key in an Environment's
227
+ secrets or an MCP gateway that holds each person's sign-in. A server it cannot list exits 1 with
217
228
  the reason (`mcp.unreachable` for an address the Runtime refuses).
218
229
 
219
230
  ## The containers
@@ -306,17 +317,20 @@ on every start and writes the result to `NYLORUN_STUDIO_ANALYTICS_ID` in
306
317
 
307
318
  ## Sandboxes
308
319
 
309
- A session gets a sandbox when it is opened with one, or when the Tenant's
310
- default names one (`PUT /v1/tenant/sandbox`). A local Tenant runs them on the
311
- Runtime's **virtual** backend: an emulated shell in the Runtime process, with no
312
- extra containers. It is not a VM or container boundary.
313
-
314
- A sandbox can also be a resource with its own id (`PUT /v1/sandboxes/{id}`,
315
- `client.sandboxes` in `@nylorun/agents`) that sessions attach to and that
316
- outlives them. `nylorun sandbox ls` lists the running Tenant's sandboxes with
317
- their state, attached sessions and labels; `nylorun sandbox rm <id>` deletes one
318
- and its files (refused while a turn runs in it). Neither starts a stopped Tenant
319
- (exit 3).
320
+ A session gets a sandbox from the Environment it is opened on
321
+ (`createSession({ environment: id })`; protocol 11): an Environment has its own id
322
+ (`PUT /v1/environments/{id}`, `client.environments` in `@nylorun/agents`), one
323
+ sandbox and one vault of secrets, and outlives the sessions that name it. A session
324
+ opened on none has no sandbox. Kind `virtual` (the default) runs on the Runtime's
325
+ **virtual** backend: an emulated shell in the Runtime process, with no extra
326
+ containers. It is not a VM or container boundary. Kind `pod` runs in a pod on a
327
+ cluster (below).
328
+
329
+ `nylorun sandbox ls` lists the running Tenant's Environments with their kind,
330
+ state, sessions and labels; `nylorun sandbox rm <id>` deletes one, with its files
331
+ and vault (refused while a turn runs in it). Neither starts a stopped Tenant
332
+ (exit 3). The Tenant's limits for Environments (`limits.environments`, `idle`,
333
+ resources, network) are `PUT /v1/tenant/sandbox` on the Management API.
320
334
 
321
335
  ### Pods on a cluster (preview)
322
336
 
@@ -331,8 +345,8 @@ lets pods reach only three ports on the Docker host, and adds the `sandboxes`
331
345
  service to the Tenant: the one container holding the cluster credentials
332
346
  (`<Host root>/sandboxes/`). On kind under Linux, pass `--host-address 172.17.0.1`.
333
347
  `nylorun sandbox disable` removes the service (`--delete-namespace` also deletes
334
- the namespace and every sandbox in it). Sessions keep using the virtual backend
335
- in this release.
348
+ the namespace and every sandbox in it). Sessions run in a pod when their
349
+ Environment has kind `pod` (`client.environments.put(id, { kind: "pod" })`).
336
350
 
337
351
  ## Host root
338
352
 
@@ -350,8 +364,95 @@ its files and ports; the next start creates the Tenant anew (with a new id) and
350
364
  relinks the project. `nylorun delete <tenant> --yes` removes the Tenant's
351
365
  containers, volumes and Host root: the vault key (KEK) and all its data go with it.
352
366
 
367
+ ## The Runtime client: `nylo`
368
+
369
+ `nylo` acts on the one Tenant of the linked installation: a local Tenant or any
370
+ Runtime reachable by URL and key. Run it without installing, or in a project
371
+ that has `nylorun` as a devDependency:
372
+
373
+ ```sh
374
+ npx -p nylorun nylo status # anywhere
375
+ npx nylo status # in a project with nylorun installed
376
+ ```
377
+
378
+ Outside such a project, `npx nylo` looks for an npm package named `nylo`, which
379
+ is not this one: use `npx -p nylorun nylo`. The deprecated
380
+ [`@nylorun/cli`](../legacy/README.md) runs this `nylo` for one more release.
381
+
382
+ ```sh
383
+ nylo status [--json] # the Tenant, its checks and counts
384
+ nylo reset [--sessions|--environments|--all] [--yes]
385
+ nylo access signing-keys … # the Tenant's signing keys: list, rotate, revoke
386
+ nylo configure # set or replace the Tenant's model provider
387
+ nylo env # export lines for the linked Project
388
+ nylo doctor sandbox [--json] # sandbox backend via the Management API
389
+ ```
390
+
391
+ Every command acts on the linked installation: the [Project link and
392
+ credentials](#the-project-link), or `NYLORUN_RUNTIME_URL` and
393
+ `NYLORUN_SERVER_KEY` when the Project has no link. An installation serves one
394
+ Tenant, so nothing selects it. `status`, `reset`, `access`, `configure` and
395
+ `doctor` use the Management API with the Project's management key, or
396
+ `NYLORUN_MANAGEMENT_KEY` (with `NYLORUN_RUNTIME_URL` when there is no link);
397
+ `env` prints the Runtime URL and the application key, for the Runtime API:
398
+
399
+ ```sh
400
+ eval "$(npx -p nylorun nylo env)"
401
+ # → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY
402
+ ```
403
+
404
+ `nylo` only reads the link, with `@nylorun/core/project`'s reader. It refuses a
405
+ link from an older nylorun (format 0 to 2) and says to run `npx nylorun start`,
406
+ which links the project again. `createClient` in `@nylorun/agents` reads the
407
+ link (or the two variables) too, so the project's `npm run dev` and `npm start`
408
+ need no Nylorun tool.
409
+
410
+ Local Tenant commands (`up`, `down`, `start`, `stop`, `logs`, `studio`) exit 2
411
+ naming `npx nylorun <command>`. `nylo tenant …` exits 2: `npx nylorun start`
412
+ creates the project's Tenant and the link, and `nylo status|reset` replace
413
+ `nylo tenant status|reset`. `nylo endpoints` was removed with Action endpoints
414
+ (protocol 8: the Runtime runs agents from their manifests alone) and exits 2.
415
+
416
+ ### `status` and `reset`: `nylorun` or `nylo`
417
+
418
+ Both commands have a `status` and a `reset`, which act on different things:
419
+
420
+ | | `nylorun` | `nylo` |
421
+ | --- | --- | --- |
422
+ | Acts on | the local Tenant on this machine (`--tenant`, `NYLORUN_TENANT` or the link), through Docker and `nylorun-operate` in its runtime container | the linked installation, local or remote, through the Management API with a management key |
423
+ | `status` | the containers, endpoints and Runtime health, and the Tenant's state: it answers when the Tenant is stopped or not open, and says why | the open Tenant's checks, counts and sandbox backend (`GET /v1/tenant`); when the Tenant does not answer it fails and points at `nylorun status` |
424
+ | `reset` | deletes all the Tenant's data: volumes, `tenant/` and the vault key; the next `start` creates it anew, with a new id, and relinks the project | clears the sessions (the default), the Environments (`--environments`) or all the data (`--all`) after draining work in flight; the Tenant, its keys and the Project link are kept |
425
+
426
+ `nylo reset --all` asks first; pass `--yes` when not in a terminal.
427
+ `nylorun reset` asks too, or takes `--yes`.
428
+
429
+ ### `nylo configure`
430
+
431
+ Lists the Tenant's model catalog (`GET /v1/tenant/models`), asks for a provider,
432
+ a model and its sign-in (an API key, or the provider's OAuth), and sets the
433
+ Tenant's model provider (`PUT /v1/tenant/model`). The sign-in flows come from
434
+ `@earendil-works/pi-ai`, about 100 MB with its provider SDKs, which no other
435
+ command needs, so it is not a dependency of nylorun and `npx nylorun` stays
436
+ small. When it does not resolve beside nylorun, the first `nylo configure`
437
+ installs the version nylorun was tested with, with npm and without install
438
+ scripts, into `~/.nylorun/lib/pi-ai-<version>/` (under `NYLORUN_HOME` when that
439
+ is set), and later runs reuse it. Studio's model settings, and `.env` at
440
+ `nylorun start`, set the provider without it.
441
+
442
+ ### `nylo` exit codes
443
+
444
+ | Code | Meaning |
445
+ | --- | --- |
446
+ | 0 | Success |
447
+ | 1 | Generic failure |
448
+ | 2 | Usage error, or a moved or removed command |
449
+ | 6 | No Runtime at the linked or local URL |
450
+ | 130 / 143 | SIGINT / SIGTERM |
451
+
353
452
  ## Exit codes
354
453
 
454
+ These are `nylorun`'s; [`nylo`'s](#nylo-exit-codes) are above.
455
+
355
456
  | Code | Meaning |
356
457
  | --- | --- |
357
458
  | 0 | Success |
@@ -376,5 +477,9 @@ containers, volumes and Host root: the vault key (KEK) and all its data go with
376
477
  | Studio login expired | `nylorun studio` |
377
478
  | Which Studio is which | `nylorun ls` lists each Tenant's Studio URL; `nylorun studio --tenant <name>` opens one signed in |
378
479
  | `Tenant … was created by nylorun 0.5` (exit 3) | `nylorun reset --tenant <name>` (its data starts fresh) |
480
+ | `nylo`: no Runtime answers, or the Tenant is not open | `npx nylorun start`, then `npx nylorun status`, which shows the cause and its `repair` |
481
+ | `nylo`: no management key | `npx nylorun start` in the project writes one; elsewhere set `NYLORUN_MANAGEMENT_KEY` |
482
+ | `nylo`: `403 key_role_mismatch` | The key belongs to the other API: a management key for the Management API, an application key for the Runtime API |
483
+ | `nylo`: old Project link refused | `npx nylorun start` in the project |
379
484
 
380
- See [MIGRATION.md](../MIGRATION.md).
485
+ See [MIGRATION.md](../../guides/MIGRATION.md).
package/dist/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import "./baseline.js";
3
3
  import { baselineEnv } from "./baseline.js";
4
+ import { refuseNativeWindows, runCommand } from "./command.js";
4
5
  import { CliError } from "./errors.js";
5
6
  import { isStackCommand, keyCommand, keyUsage, mcpCommand, mcpUsage, sandboxCommand, sandboxUsage, stackCommand, stackUsage, studioCommand, } from "./stack/index.js";
6
7
  const usage = `nylorun <up|down|start|stop|status|logs|studio|reset|ls|delete|sandbox|key|mcp|doctor|telemetry>
@@ -20,12 +21,16 @@ else (outside a project) the default Tenant; NYLORUN_HOME sets its Host root
20
21
 
21
22
  nylorun sets up and runs local Tenants. "nylorun start" in a project creates the
22
23
  project's Tenant and the Project link; anywhere else, it starts the default Tenant.
23
- Agents, sessions and model providers belong to the Runtime client: npx @nylorun/cli --help`;
24
- const CLIENT = "npx @nylorun/cli";
25
- /** Commands that were removed, or moved to the Runtime client (`@nylorun/cli`, command `nylo`). */
24
+ nylorun status and reset act on the local Tenant's containers and volumes on this machine.
25
+ The package's other command, nylo, is the Runtime client of the linked installation: its
26
+ status and reset go through the Management API, and it sets the model provider (nylo --help,
27
+ or npx -p nylorun nylo --help).`;
28
+ /** `nylo`, the Runtime client (this package's second command), run without installing. */
29
+ const CLIENT = "npx -p nylorun nylo";
30
+ /** Commands that were removed, or that are the Runtime client's (`nylo`). */
26
31
  const MOVED_TO_CLIENT = {
27
32
  dev: "nylorun dev was removed: run `npx nylorun start` in your project (it creates the project's Tenant and the Project link), then your project's `npm run dev`.",
28
- configure: `nylorun configure moved to the Runtime client: ${CLIENT} configure`,
33
+ configure: `nylorun configure is the Runtime client's: ${CLIENT} configure`,
29
34
  serve: "nylorun serve was removed. Use node dist/src/main.js with NYLORUN_RUNTIME_URL and NYLORUN_SERVER_KEY.",
30
35
  runtime: "nylorun runtime was removed: the local Runtime runs in Docker Compose. Use nylorun up|down|status|logs.",
31
36
  };
@@ -35,13 +40,12 @@ async function main() {
35
40
  const [command, ...args] = process.argv.slice(2);
36
41
  if (!command || command === "--help" || command === "-h")
37
42
  return void console.log(usage);
38
- if (process.platform === "win32")
39
- throw new CliError("Nylorun does not run on native Windows. Use WSL2: install Node 24 and Docker (Docker Desktop's WSL integration) inside your WSL distribution and run nylorun there (https://learn.microsoft.com/windows/wsl/install).", 1);
43
+ refuseNativeWindows();
40
44
  const moved = MOVED_TO_CLIENT[command];
41
45
  if (moved)
42
46
  throw usageError(moved);
43
47
  if (command === "status" && args.includes("--env"))
44
- throw usageError(`nylorun status --env moved to the Runtime client: ${CLIENT} env`);
48
+ throw usageError(`nylorun status --env is the Runtime client's: ${CLIENT} env`);
45
49
  if (command === "studio") {
46
50
  if (args.includes("--local-ui"))
47
51
  throw usageError(LOCAL_UI_REMOVED);
@@ -76,7 +80,7 @@ async function main() {
76
80
  }
77
81
  if (command === "doctor") {
78
82
  if (args[0] === "sandbox")
79
- throw usageError(`nylorun doctor sandbox moved to the Runtime client: ${CLIENT} doctor sandbox`);
83
+ throw usageError(`nylorun doctor sandbox is the Runtime client's: ${CLIENT} doctor sandbox`);
80
84
  if (args.some((option) => option !== "--json"))
81
85
  throw usageError("Usage: nylorun doctor [--json]");
82
86
  const { doctorStack } = await import("./doctor.js");
@@ -85,13 +89,4 @@ async function main() {
85
89
  }
86
90
  throw usageError(usage);
87
91
  }
88
- async function finish(code) {
89
- process.exitCode = code;
90
- for (const stream of [process.stdout, process.stderr])
91
- await new Promise((resolve) => stream.write("", () => resolve()));
92
- process.exit(code);
93
- }
94
- void main().then(() => finish(process.exitCode === undefined ? 0 : Number(process.exitCode)), (error) => {
95
- console.error(error instanceof Error ? error.message : String(error));
96
- return finish(error instanceof CliError ? error.exitCode : 1);
97
- });
92
+ runCommand(main);
@@ -0,0 +1,8 @@
1
+ /**
2
+ * `nylo access`: the linked Tenant's signing keys, which sign capability links and run tokens,
3
+ * through the Management API with the Project's management key. (Subject tokens, the
4
+ * access policy, browser keys and revocations left the Runtime in protocol 7.)
5
+ */
6
+ import type { ManagementClient } from "@nylorun/admin";
7
+ export declare const accessUsage = "nylo access signing-keys <list|rotate|revoke>\n\n signing-keys list list the signing keys\n signing-keys rotate [--force] rotate; --force ends outstanding links and run tokens\n signing-keys revoke <kid> revoke a previous or standby key";
8
+ export declare function accessCommand(input: readonly string[], client?: () => Promise<ManagementClient>): Promise<void>;
@@ -0,0 +1,33 @@
1
+ import { findProjectRoot } from "@nylorun/core/project";
2
+ import { CliError } from "../../errors.js";
3
+ import { linkedConnection, managementClient } from "../project/connection.js";
4
+ export const accessUsage = `nylo access signing-keys <list|rotate|revoke>
5
+
6
+ signing-keys list list the signing keys
7
+ signing-keys rotate [--force] rotate; --force ends outstanding links and run tokens
8
+ signing-keys revoke <kid> revoke a previous or standby key`;
9
+ const usageError = (message = accessUsage) => new CliError(message, 2);
10
+ async function linkedClient() {
11
+ return managementClient(await linkedConnection(findProjectRoot() ?? process.cwd()));
12
+ }
13
+ const print = (value) => console.log(JSON.stringify(value, null, 2));
14
+ export async function accessCommand(input, client = linkedClient) {
15
+ const [topic, action, ...args] = input;
16
+ if (topic === "signing-keys") {
17
+ const keys = async () => (await client()).signingKeys;
18
+ if (action === "list" && args.length === 0)
19
+ return print(await (await keys()).list());
20
+ if (action === "rotate") {
21
+ const force = args[0] === "--force";
22
+ if (args.length > (force ? 1 : 0))
23
+ throw usageError();
24
+ return print(await (await keys()).rotate({ force }));
25
+ }
26
+ if (action === "revoke" && args.length === 1)
27
+ return print(await (await keys()).revoke(args[0]));
28
+ throw usageError();
29
+ }
30
+ if (topic === "policy" || topic === "keys" || topic === "revoke" || topic === "token")
31
+ throw usageError(`nylo access ${topic} was removed: the Runtime no longer mints subject tokens or keeps an access policy, browser keys or revocations (protocol 7). Trust your identity provider's tokens with an identity file, and give servers an application key (nylorun key put <id>).`);
32
+ throw usageError();
33
+ }
@@ -0,0 +1,2 @@
1
+ /** `nylo <command> [...args]`. */
2
+ export declare function main(argv: readonly string[]): Promise<void>;
@@ -0,0 +1,106 @@
1
+ import { findProjectRoot } from "@nylorun/core/project";
2
+ import { CliError } from "../errors.js";
3
+ import { refuseNativeWindows } from "../command.js";
4
+ import { printLinkedEnvExports } from "./project/env.js";
5
+ import { linkedConnection, managementClient } from "./project/connection.js";
6
+ import { accessCommand } from "./access/commands.js";
7
+ import { resetCommand, statusCommand } from "./installation/commands.js";
8
+ const usage = `nylo <status|reset|access|configure|env|doctor>
9
+
10
+ Runtime client for the linked installation and its one Tenant (the Project link that
11
+ npx nylorun start writes, or NYLORUN_RUNTIME_URL with NYLORUN_SERVER_KEY, and
12
+ NYLORUN_MANAGEMENT_KEY for status, reset, access, configure and doctor):
13
+ status [--json] the Tenant, its checks and counts
14
+ reset [--sessions|--environments|--all] [--yes]
15
+ clear the Tenant's sessions, Environments or all its data
16
+ access signing-keys list|rotate|revoke the Tenant's token signing keys (nylo access --help)
17
+ configure set the linked Tenant's model provider
18
+ env print the linked Project's NYLORUN_* variables as exports
19
+ doctor sandbox [--json] show which sandbox backend this Tenant's Host offers
20
+
21
+ nylo status and reset go through the Management API, to a local or a remote installation.
22
+ Local Tenants are nylorun's, the other command of this package: npx nylorun start in a
23
+ project creates its Tenant and the Project link, and nylorun status and reset act on the
24
+ local Tenant's containers and volumes.`;
25
+ /** Local Tenant commands, which `nylorun` runs. */
26
+ const LOCAL_COMMANDS = new Set([
27
+ "up", "down", "start", "stop", "logs", "studio", "runtime", "restart", "run",
28
+ ]);
29
+ const TENANT_REMOVED = `nylo tenant was removed: an installation serves one Tenant.
30
+ Run "npx nylorun start" in your project to create its Tenant and the Project link.
31
+ Then use nylo status and nylo reset on the linked installation.`;
32
+ const ENDPOINTS_REMOVED = `nylo endpoints was removed: the Runtime runs agents from their manifests alone,
33
+ so there are no Action endpoints. An agent's tools are http() tools and remote MCP servers
34
+ (see MIGRATION.md).`;
35
+ const usageError = (message) => new CliError(message, 2);
36
+ /** `nylo <command> [...args]`. */
37
+ export async function main(argv) {
38
+ const [command, ...args] = argv;
39
+ if (!command || command === "--help" || command === "-h")
40
+ return void console.log(usage);
41
+ refuseNativeWindows();
42
+ if (command === "tenant")
43
+ throw usageError(TENANT_REMOVED);
44
+ if (command === "status")
45
+ return await statusCommand(args);
46
+ if (command === "reset")
47
+ return await resetCommand(args);
48
+ if (command === "endpoints")
49
+ throw usageError(ENDPOINTS_REMOVED);
50
+ if (command === "access") {
51
+ if (args[0] === "--help" || args[0] === "-h" || args.length === 0) {
52
+ const { accessUsage } = await import("./access/commands.js");
53
+ return void console.log(accessUsage);
54
+ }
55
+ return await accessCommand(args);
56
+ }
57
+ if (command === "env") {
58
+ if (args.length)
59
+ throw usageError("Usage: nylo env");
60
+ await printLinkedEnvExports(findProjectRoot() ?? process.cwd());
61
+ return;
62
+ }
63
+ if (command === "doctor") {
64
+ const [topic, ...options] = args;
65
+ if (topic !== "sandbox" || options.some((option) => option !== "--json"))
66
+ throw usageError("Usage: nylo doctor sandbox [--json]. Check the local Tenant with npx nylorun doctor.");
67
+ const { doctorSandbox } = await import("./doctor.js");
68
+ await doctorSandbox({ json: options.includes("--json") });
69
+ return;
70
+ }
71
+ if (command === "dev")
72
+ throw usageError('nylorun dev was removed: run "npx nylorun start" once in your project, then your project\'s npm run dev.');
73
+ if (LOCAL_COMMANDS.has(command))
74
+ throw usageError(`Local Tenants are nylorun's: npx nylorun ${command}`);
75
+ if (command === "configure") {
76
+ for (const arg of args) {
77
+ if (arg === "--global" || arg === "--db")
78
+ throw usageError(`${arg} was removed. Use the Runtime Host root (NYLORUN_HOME) and a Project link instead.`);
79
+ if (arg.startsWith("-"))
80
+ throw usageError(usage);
81
+ }
82
+ if (args.length)
83
+ throw usageError(usage);
84
+ const projectRoot = findProjectRoot() ?? process.cwd();
85
+ const auth = await linkedConnection(projectRoot);
86
+ const admin = managementClient(auth);
87
+ // The provider login flows (pi-ai) load only here.
88
+ const { ConfigurationCancelled, configureProvider, fetchModelCatalog } = await import("./model/configure.js");
89
+ const { putHostModel } = await import("./model/host-model.js");
90
+ const controller = new AbortController();
91
+ const cancel = (signal) => controller.abort(new ConfigurationCancelled(signal));
92
+ process.once("SIGINT", () => cancel("SIGINT"));
93
+ process.once("SIGTERM", () => cancel("SIGTERM"));
94
+ const health = await fetch(`${auth.url}/health`).catch(() => undefined);
95
+ if (!health?.ok)
96
+ throw new CliError(`No Runtime is listening at ${auth.url}. Start the local Tenant with "npx nylorun start".`, 6);
97
+ const catalog = await fetchModelCatalog(admin);
98
+ const prompted = await configureProvider({
99
+ signal: controller.signal,
100
+ catalog,
101
+ });
102
+ await putHostModel(admin, prompted);
103
+ return;
104
+ }
105
+ throw usageError(usage);
106
+ }
@@ -0,0 +1,26 @@
1
+ export type SandboxReport = {
2
+ preference: string;
3
+ backend: string | null;
4
+ isolation?: string;
5
+ reason?: string;
6
+ probes: {
7
+ name: string;
8
+ isolation: string;
9
+ available: boolean;
10
+ reason?: string;
11
+ version?: string;
12
+ }[];
13
+ defaultImage?: string;
14
+ /** The Tenant's Environment settings in force (`environments.config`, protocol 11). */
15
+ config?: {
16
+ limits?: {
17
+ network?: readonly string[];
18
+ idle?: string;
19
+ environments?: number;
20
+ };
21
+ };
22
+ };
23
+ /** `nylo doctor sandbox`: Tenant sandbox report via the Management API (F2-4). */
24
+ export declare function doctorSandbox(options: {
25
+ json: boolean;
26
+ }): Promise<void>;