nylorun 0.16.0-beta → 0.17.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,46 @@
1
1
  # nylorun
2
2
 
3
+ ## 0.17.0-beta
4
+
5
+ ### Minor Changes
6
+
7
+ - cc8d034: Track T3 in the clients. The SDK has `client.agents.plan(id, input)` (what a move would do), `client.agents.restart(id, { retry? })` and `list({ outdated: true })`. The CLI has `nylorun agents pin <id> <n>`, `track <id>`, `restart <id> [--retry]`, `put --dry-run`, and `list --outdated` (`--behind` kept as its alias), and prints the version an Agent moves to. Studio's Agent page moves an Agent (Move to vN, Pin, Track), restarts it on a pending version or retries a failed one, and shows "vN at next start", a version waiting for secrets, or one that failed to start. The starter's dev loop no longer deletes and remakes its Agent: the tracking Agent moves on each save.
8
+ - 22c61ce: Protocol 16, Agents from one manifest (track T2), a fresh start. An agent manifest (v8) is one versioned document at `/v1/agent-manifests/{name}` with a `harness` section (what runs inside the loop, including the harness's id) and a `runtime` section (what an environment manifest said). The Runtime checks the two against each other when it is saved (`422 manifest_inconsistent` with `details.gaps`), in place of `requires` at session open. Agent definitions and environment manifests are gone.
9
+
10
+ Environments are Agents: `/v1/agents/{id}` and its sub-routes, made from a saved manifest only (`manifest: "name"` tracks it, `"name@n"` pins a version; either resolves once, into `resolvedVersion`), with a derived `state` (`working`, `sleeping`, `input_required`, `failing`, `paused`) and `attention`. Every session runs on one Agent (`PUT /v1/sessions/{id} { agent, ownerUserId }`) and pins its manifest version. No session is special (D71). Error codes, events (`agent.*`), scopes (`agents:write`, `agent-manifests:write`) and identity-file grants (`agents`) say Agent; model budget scope `agent` is `manifest`. Harness API 5: `turn.start.agent` replaces `turn.start.environment`, with `definition` and `loop`. Migration 0032 closes older sessions (`protocol_16`) and drops Environments with their disks and vaults.
11
+
12
+ The SDK has `client.agentManifests`, `client.agents` and `composeManifest(dir)` for three-file authoring; the CLI has `nylorun apply`, `nylorun agent-manifests`, `nylorun agents` and `nylorun migrate v8`; Studio has an Agents screen, an Agent page and an Agent manifests screen. See MIGRATION.md.
13
+
14
+ - 4fa160d: Agent memory, storage and API (track T5, D72). An agent manifest's `harness.memory` (`access`: `read_write` or `read_only`; `instructions`, at most 4,096 characters) turns on the Agent's memory: Markdown files under `/memories` it keeps across sessions, wakes and upgrades. The Runtime keeps them in Postgres (`memories`, `memory_versions`, migration 0036) with a version per change and who made it. `GET /v1/agents/{id}/memories` lists them (`pathPrefix`), `GET`, `PUT` (whole content, with an optional `contentSha256` precondition: `409 memory_conflict`) and `DELETE /v1/agents/{id}/memories/{path}` read, write and delete one (or a folder), and `GET /v1/agents/{id}/memory_versions` and `.../memory_versions/{versionId}` page the versions. A fork copies the memories (the fork plan adds `memories`); a delete removes them. `@nylorun/core` adds `memoryPathOf`, `memoryDescriptionOf` and the memory contracts; new Runtime limits `memoryBytes` (100 KB) and `memoriesPerAgent` (10,000); new error code `memory_conflict`. The SDK adds `client.agents.memories`; the CLI adds `nylorun agents memories ls|cat|put|rm|versions`. The model's `memory` tool arrives in the next steps of T5.
15
+ - 9e60e40: Protocol 17, a queue per session (track T4, D76). A message sent while the session's turn runs or waits is queued (`{status: "queued", queuedMessageId, position}`, `message.queued`) and starts the next turn when this one ends, with every queued message, each its own user message (`queue.taken`); a cancel ends the turn, not the queue. `delivery: "reject"` keeps the refusal, now `409 session_busy`, and a protocol 16 client's messages default to it, so the Host serves protocol 16 and 17. The queue holds at most the Runtime limit `sessionQueuedMessages` (`429 queue_full`), and session reads count `queuedMessages`. Our engine takes `{kind: "messages", messages}` as a turn's input. The SDK's `input` and `inputParts` take `delivery`, and the CLI's `sessions send` takes `--reject-if-busy`. See MIGRATION.md.
16
+ - f85483d: Triggers (track T4, D74). An agent manifest's `runtime.triggers` declares `schedule` (cron with an IANA `timezone`) and `at` triggers, each with the session its runs go to (a session id, opened on the first run, or `new` for a session per run) and its prompt. They start active with a new Agent, fire on a durable timer per trigger with Postgres as the truth (one late fire after downtime, never a backfill, a fixed jitter per trigger), and each fire is a run (`started`, `queued`, `skipped` or `failed`, with a reason) at `GET /v1/agents/{id}/runs`. A schedule adds at most one queued message to a busy session. `GET /v1/agents/{id}/triggers` and `POST .../triggers/{triggerId}/pause`, `/resume` and `/run` (with an `Idempotency-Key`); Agent reads add `nextWakeAt`, and the Agent's stream adds `agent.run`, `agent.trigger_paused` and `agent.trigger_resumed`. New Runtime limits: `triggersPerAgent`, `triggerMinIntervalMs` and `triggerRunRetentionMs` (with floors), `triggerRunsPerHour`, `triggerJitterPercent`, `triggerJitterMaxMs`, `triggerPromptChars`; Host tuning `triggers.lateGraceMs` and `triggers.intervalCheckFires`. The SDK's `client.agents` adds `triggers`, `pauseTrigger`, `resumeTrigger`, `runTrigger` and `runs`; the CLI adds `nylorun agents triggers` and `nylorun agents runs`.
17
+ - ae54de7: Webhook triggers (track T4, D75). A `webhook: "standard-webhooks"` trigger has an endpoint, `POST /v1/webhooks/{endpointId}`, an anonymous, unversioned route that takes any body up to the new Runtime limit `webhookBodyBytes` and verifies Standard Webhooks (`webhook-id`, `webhook-timestamp` within the Host's `triggers.webhookToleranceMs`, `webhook-signature`) in the keys service, which alone opens the trigger's sealed secret; anything else is `401` and writes nothing. A delivery runs the trigger once per `webhook-id` (`202 {runId, status}`); a paused trigger answers a signed one `409 trigger_paused`. `POST /v1/agents/{id}/triggers/{triggerId}/secret` makes or replaces the `whsec_` secret, shown once (`agent.trigger_secret_rotated`); trigger reads show `webhookUrl` and `secretSet`. The payload reaches the model under the trigger's prompt in a labelled `<trigger-payload>` block. The SDK adds `agents.rotateWebhookSecret`, and the CLI `nylorun agents triggers new-secret`.
18
+
19
+ ### Patch Changes
20
+
21
+ - Pin core to the tested release.
22
+ - Pin agents to the tested release.
23
+ - Pin admin to the tested release.
24
+ - Pin runtime to the tested release.
25
+ - Pin studio to the tested release.
26
+ - Updated dependencies [218b078]
27
+ - Updated dependencies [cc8d034]
28
+ - Updated dependencies [22c61ce]
29
+ - Updated dependencies [1ded443]
30
+ - Updated dependencies [76dcd11]
31
+ - Updated dependencies [bf942ed]
32
+ - Updated dependencies [4fa160d]
33
+ - Updated dependencies [9fed948]
34
+ - Updated dependencies [ffeb3bb]
35
+ - Updated dependencies [9e60e40]
36
+ - Updated dependencies [f85483d]
37
+ - Updated dependencies [ae54de7]
38
+ - Updated dependencies
39
+ - Updated dependencies
40
+ - @nylorun/core@0.24.0-beta
41
+ - @nylorun/agents@0.24.0-beta
42
+ - @nylorun/admin@0.19.0-beta
43
+
3
44
  ## 0.16.0-beta
4
45
 
5
46
  ### Minor Changes
package/README.md CHANGED
@@ -15,7 +15,7 @@ and S2, serving exactly that Tenant, and its name is the Tenant's name.
15
15
  `nylorun start` in a project creates the project's Tenant (the Runtime creates
16
16
  it on its first start) and links the project to it; anywhere else, it starts
17
17
  the Tenant `default`. Projects that must not share agents, credentials or
18
- history run separate Tenants. The `tenant` and `environments` groups act on a
18
+ history run separate Tenants. The `tenant`, `agents` and `apply` commands act on a
19
19
  Tenant over its APIs, so they work on a remote installation too
20
20
  ([below](#remote-installations)). Depends on `@nylorun/core`,
21
21
  `@nylorun/admin` and `@nylorun/agents` among Nylorun packages and never imports
@@ -50,32 +50,33 @@ nylorun studio [--tenant <name>] [--no-open] # sign a browser in to Studio on
50
50
  nylorun doctor [--json] # prerequisites and the Tenant's health
51
51
  nylorun doctor sandbox [--tenant <name>] [--json] # the sandbox backend the Tenant's Host offers
52
52
 
53
- # agents, sessions, environments, artifacts: the Runtime API (an application key, or NYLORUN_TOKEN)
53
+ # apply, agent-manifests, agents, sessions, artifacts: the Runtime API (an application key, or NYLORUN_TOKEN)
54
54
  # every one takes --tenant <name>, and --as <subject> [--scope <scope>]... to act for a person
55
- nylorun agents list [--json]
56
- nylorun agents get <id> # its manifest
57
- nylorun agents save <manifest.json|-> [--files <dir>]... [--implementation-version <v>] [--dry-run]
58
- nylorun sessions list [--agent <id>] [--status <s>] [--environment <id>] [--owner <user>] [--limit <n>] [--cursor <c>] [--json]
59
- nylorun sessions create --agent <id> --owner <user> [--environment <id>] [--id <id>] [--info <json>]
55
+ nylorun apply [<dir>...] [--dry-run] [--if-match <n>] # plan, then save each folder's agent.manifest.json, its files uploaded
56
+ nylorun migrate v8 <agent.json> [--runtime <environment-manifest.json>] [--name <name>] [--out <dir>] # the three files from a v7 manifest; reads no Runtime
57
+ nylorun agent-manifests list [--json] # name, latest version, runtime kind, harness, Agents
58
+ nylorun agent-manifests get <name>[@<n>] | versions <name> | rm <name>
59
+ nylorun agents list [--state <s>] [--manifest <name>] [--label <key=value>]... [--behind] [--limit <n>] [--cursor <c>] [--json] # --behind: on an older manifest version
60
+ nylorun agents get|stop|reset|rm|snapshot|versions <id>
61
+ nylorun agents put <id> --manifest <name[@n]> [--owner <user>] [--label <key=value>]... # name tracks its latest version, name@n pins one
62
+ nylorun agents fork <id> <new-id> [--manifest <name[@n]>] [--disk <latest|n|empty>] [--secrets <copy|none>] [--dry-run] # onto a new manifest version
63
+ nylorun agents restore <id> <version|latest>
64
+ nylorun agents delete-version <id> <version>
65
+ nylorun agents events <id> [--from <n>] [--types <type,…>] [--since <time>] [--until <time>]
66
+ nylorun agents triggers list <id> | pause|resume <id> <trigger> | run <id> <trigger> [--idempotency-key <k>] | new-secret <id> <trigger>
67
+ nylorun agents runs <id> [--trigger <id>] [--limit <n>] [--cursor <c>] # what each trigger fire came to
68
+ nylorun agents memories ls|cat|put|rm|versions <id> [<path>] [<file|->] # its memories (track T5); put seeds one
69
+ nylorun agents secrets list|get|put|rm <id> [<name>] [<secret.json|->] # put without a file: a slot's value on stdin
70
+ nylorun sessions list [--agent <id>] [--manifest <name>] [--status <s>] [--owner <user>] [--limit <n>] [--cursor <c>] [--json]
71
+ nylorun sessions create --agent <id> --owner <user> [--id <id>] [--info <json>] # a session on Agent <id>
60
72
  nylorun sessions get <id>
61
- nylorun sessions send <id> [<text>] [--data <json>] [--file <artifact>[@<version>]]... [--idempotency-key <k>]
73
+ nylorun sessions send <id> [<text>] [--data <json>] [--file <artifact>[@<version>]]... [--idempotency-key <k>] [--reject-if-busy] # queued while a turn runs
62
74
  nylorun sessions approve <id> <interaction> [--deny]
63
75
  nylorun sessions respond <id> <interaction> <json>
64
76
  nylorun sessions cancel <id> [--reason <text>]
65
77
  nylorun sessions watch <id> [--follow] [--cursor <c>] # events as JSON lines until interrupted
66
78
  nylorun sessions history|usage|calls [--tool]|trace <id> …
67
79
  nylorun sessions exec <id> [--timeout <s>] -- <command>... # bash in the session's sandbox
68
- nylorun environments list [--label <key=value>]... [--behind] [--limit <n>] [--cursor <c>] [--json] # --behind: made from an older manifest version
69
- nylorun environments get|stop|reset|delete|snapshot|versions <id>
70
- nylorun environments put <id> --manifest <name[@n]> [--label <key=value>]... # made from a manifest version; what it runs never changes
71
- nylorun environments put <id> [<inline.json|->] [--kind <virtual|pod|none>] [--label <key=value>]...
72
- nylorun environments fork <id> <new-id> [--manifest <name[@n]>] [--disk <latest|n|empty>] [--secrets <copy|none>] [--dry-run] # onto a new manifest version
73
- nylorun environments restore <id> <version|latest>
74
- nylorun environments delete-version <id> <version>
75
- nylorun environments events <id> [--from <n>] [--types <type,…>] [--since <time>] [--until <time>]
76
- nylorun environments secrets list|get|put|rm <id> [<name>] [<secret.json|->] # put without a file: a slot's value on stdin
77
- nylorun environments manifests list [--json] | get <name> [--version <n>] | versions <name> | rm <name>
78
- nylorun environments manifests save <manifest.json>... [--if-match <n>] [--dry-run] # files with "from": a folder, uploaded by hash
79
80
  nylorun artifacts list [--session <id>] [--label <key=value>]... [--limit <n>] [--cursor <c>] [--json]
80
81
  nylorun artifacts get|tree|diff|link|rm <id> …
81
82
  nylorun artifacts upload <file|-> [--name <name>] [--content-type <type>] [--session <id>] [--label <key=value>]... [--to <id>]
@@ -83,7 +84,7 @@ nylorun artifacts download <id> [--version <n>] [--output <file>]
83
84
  nylorun artifacts zip <id> [--version <n>] --output <file>
84
85
 
85
86
  # tenant: the Tenant's settings (Management API, a management key)
86
- nylorun tenant reset [--sessions|--environments|--all] [--yes] [--tenant <name>]
87
+ nylorun tenant reset [--sessions|--agents|--all] [--yes] [--tenant <name>]
87
88
  nylorun tenant keys put <id> [--management] [--tenant <name>] # create or rotate key <id>; prints it once
88
89
  nylorun tenant keys list [--tenant <name>] [--json] # id, role, when issued
89
90
  nylorun tenant keys rm <id> [--tenant <name>] # it stops working at once
@@ -92,13 +93,13 @@ nylorun tenant models catalog|providers|get [--tenant <name>] [--json] # the m
92
93
  nylorun tenant models set [--tenant <name>] # sign in to a model provider and set the Tenant's model
93
94
  nylorun tenant models set --provider <id> --model <id> [--base-url <url>] [--tenant <name>] # the same, with an API key piped in on stdin (CI)
94
95
  nylorun tenant models select <provider> [--model <id>] [--tenant <name>] # use another provider that has a credential
95
- nylorun tenant usage [--scope tenant|agent|turn] [--id <id>] [--period day|month|total] [--tenant <name>] # calls, tokens and cost (JSON)
96
+ nylorun tenant usage [--scope tenant|manifest|turn] [--id <id>] [--period day|month|total] [--tenant <name>] # calls, tokens and cost (JSON); manifest: the Agents made from agent manifest <id>
96
97
  nylorun tenant calls [--after <cursor>] [--limit <n>] [--tenant <name>] # every recorded model call as NDJSON, until caught up
97
- nylorun tenant budgets [get | put <file|->] [--tenant <name>] # the model spend caps
98
+ nylorun tenant budgets [get | put <file|->] [--tenant <name>] # the model spend caps: tenant, manifest (id: its name) or turn
98
99
  nylorun tenant tool-policy [get | put <file|->] [--tenant <name>] # the Tool Gate's rules
99
- nylorun tenant settings sandbox|artifacts|skills|limits [get | put <file|->] [--tenant <name>] # Environment, artifact store and skill settings, Runtime limits
100
- nylorun tenant coverage --agent <id> [--environment <id>] [--tenant <name>] [--json] # which secret each MCP server and HTTP tool would get
101
- nylorun tenant mcp inspect <url> [--server <name>] [--environment <id>] [--sse] [--tenant <name>] [--json]
100
+ nylorun tenant settings sandbox|artifacts|skills|limits [get | put <file|->] [--tenant <name>] # Agents' environments, artifact store and skill settings, Runtime limits
101
+ nylorun tenant coverage --agent <id> [--tenant <name>] [--json] # which secret of Agent <id>'s vault each MCP server and HTTP tool would get
102
+ nylorun tenant mcp inspect <url> [--server <name>] [--agent <id>] [--sse] [--tenant <name>] [--json]
102
103
 
103
104
  # local: the Tenants on this machine (Docker and kubectl)
104
105
  nylorun local ls [--json] # the Tenants on this machine, with their state, memory and URLs
@@ -116,10 +117,13 @@ stops the containers and keeps the volumes, so no Tenant data is lost. A command
116
117
  that moved into a group, or was removed, exits 2 naming its replacement:
117
118
  `nylorun logs`, `ls`, `delete`, `reset` and `telemetry` are under `local` (and
118
119
  `sandbox enable|disable|status`); `nylorun key` and `mcp` are under `tenant`;
119
- `nylorun sandbox ls|rm` is `nylorun environments list|delete`; `nylorun
120
- configure` is `nylorun tenant models set`. `nylorun dev`, `nylorun env` and the
121
- MCP OAuth `connect` subcommand of `nylorun tenant mcp` (protocol 10: write a key
122
- or a gateway credential as an Environment's secret instead) are gone.
120
+ `nylorun sandbox ls|rm` is `nylorun agents list|rm`; `nylorun environments` is
121
+ `nylorun agents` (protocol 16: Environments are Agents, and environment manifests
122
+ are the runtime section of an agent manifest); `nylorun agents save` is `nylorun
123
+ apply`; `nylorun configure` is `nylorun tenant models set`. `nylorun dev`,
124
+ `nylorun env` and the MCP OAuth `connect` subcommand of `nylorun tenant mcp`
125
+ (protocol 10: write a key or a gateway credential as an Agent's secret instead)
126
+ are gone.
123
127
 
124
128
  The package's second command, `nylo`, was the Runtime client until nylorun took
125
129
  its commands. For one release it names the `nylorun` command that replaced each
@@ -260,19 +264,21 @@ shows each key's id, role and when it was issued, never the keys; `nylorun
260
264
  tenant keys rm <id>` deletes one. Ids match `^[a-z][a-z0-9-]{0,31}$`; `studio`
261
265
  belongs to Studio and `bootstrap` to `NYLORUN_MANAGEMENT_KEY_FILE`, and both are
262
266
  refused. Putting an id that holds the other role is refused. Give each app server
263
- its own application key. On a local Tenant, the `tenant` and `environments`
267
+ its own application key. On a local Tenant, the `tenant` and Runtime API
264
268
  commands use the linked project's keys, or the keys `cli` and `cli-management`
265
269
  they put once and keep in `<Host root>/cli-credentials.json` (mode 0600).
266
270
 
267
271
  ## MCP servers
268
272
 
269
- An agent names its MCP servers by URL; a session gets a credential for a URL from
270
- the Environment it is opened on (`createSession({ environment })`): a secret of that
271
- Environment, a `bearer` token or a `headers` map, with `via` and an identity
272
- header when an MCP gateway holds each person's sign-in. Write it with
273
- `nylorun environments secrets put <id> <name> <secret.json|->` (the secret's JSON
273
+ An agent manifest names its MCP servers by URL, and may name the runtime
274
+ section's secret slot each one authenticates with (`credential`); a session gets
275
+ a credential for a URL from the Agent it runs on (`createSession({ agent })`): a
276
+ secret of that Agent's vault, a `bearer` token or a `headers` map, with `via` and
277
+ an identity header when an MCP gateway holds each person's sign-in. Write it with
278
+ `nylorun agents secrets put <id> <name>` (a slot's value on standard input) or
279
+ `nylorun agents secrets put <id> <name> <secret.json|->` (the secret's JSON
274
280
  comes from a file or standard input, never the command line),
275
- `client.environments.secrets.put(id, name, secret)` of `@nylorun/agents` (the
281
+ `client.agents.secrets.put(id, name, secret)` of `@nylorun/agents` (the
276
282
  Runtime API, an application key) or in Studio.
277
283
  The whole flow, with gateway recipes, is in
278
284
  [DEPLOYMENT.md](../../guides/DEPLOYMENT.md#mcp-servers-and-http-tools).
@@ -280,7 +286,7 @@ The whole flow, with gateway recipes, is in
280
286
  `nylorun tenant mcp inspect <url>` shows what a remote MCP server offers before an
281
287
  agent names it, through the Tenant's Management API
282
288
  (`POST /v1/tenant/mcp/preview`, with the management key). The Runtime connects
283
- with Environment `<id>`'s credential for `<url>` when `--environment <id>` names one
289
+ with Agent `<id>`'s credential for `<url>` when `--agent <id>` names one
284
290
  (without it, no credential is sent), lists the tools within 15 s and calls none. It
285
291
  prints a table of each tool's model name, input schema size, hints
286
292
  (`read-only`, `destructive`, `idempotent`) and description, then the tools
@@ -288,7 +294,7 @@ renamed for the model. `--server` is the server name your manifest uses (default
288
294
  the host's name, `linear` for `mcp.linear.app`); `--sse` speaks the older SSE
289
295
  transport; `--json` prints the Runtime's answer. A server that answers `401`
290
296
  needs a credential: it says so, and names the server's sign-in from its
291
- protected-resource metadata, since such a server needs a key in an Environment's
297
+ protected-resource metadata, since such a server needs a key in an Agent's
292
298
  secrets or an MCP gateway that holds each person's sign-in. A server it cannot list exits 1 with
293
299
  the reason (`mcp.unreachable` for an address the Runtime refuses).
294
300
 
@@ -382,20 +388,22 @@ on every start and writes the result to `NYLORUN_STUDIO_ANALYTICS_ID` in
382
388
 
383
389
  ## Sandboxes
384
390
 
385
- A session gets a sandbox from the Environment it is opened on
386
- (`createSession({ environment: id })`; protocol 11): an Environment has its own id
387
- (`PUT /v1/environments/{id}`, `client.environments` in `@nylorun/agents`), one
388
- sandbox and one vault of secrets, and outlives the sessions that name it. A session
389
- opened on none has no sandbox. Kind `virtual` (the default) runs on the Runtime's
390
- **virtual** backend: an emulated shell in the Runtime process, with no extra
391
- containers. It is not a VM or container boundary. Kind `pod` runs in a pod on a
392
- cluster (below).
393
-
394
- `nylorun environments list` lists the Tenant's Environments with their kind,
395
- state, sessions and labels; `nylorun environments delete <id>` deletes one, with its files
396
- and vault (refused while a turn runs in it). Neither starts a stopped Tenant
397
- (exit 3). The Tenant's limits for Environments (`limits.environments`, `idle`,
398
- resources, network) are `PUT /v1/tenant/sandbox` on the Management API.
391
+ A session gets a sandbox from the Agent it runs on (`createSession({ agent: id })`;
392
+ protocol 16): an Agent has its own id (`PUT /v1/agents/{id}`, `client.agents` in
393
+ `@nylorun/agents`), is made from a saved agent manifest, has the sandbox its
394
+ manifest's `runtime.kind` gives and one vault of secrets, and outlives its
395
+ sessions. Kind `virtual` runs on the Runtime's **virtual** backend: an emulated
396
+ shell in the Runtime process, with no extra containers. It is not a VM or
397
+ container boundary. Kind `pod` runs in a pod on a cluster (below); kind `none`
398
+ has no sandbox, and a manifest with no runtime section makes Agents of kind
399
+ `none`.
400
+
401
+ `nylorun agents list` lists the Tenant's Agents with the manifest version each
402
+ runs, its kind, state, sessions, owner and labels; `nylorun agents rm <id>`
403
+ deletes one, with its files and vault (refused while a turn runs on it). Neither
404
+ starts a stopped Tenant (exit 3). The Tenant's limits for Agents
405
+ (`limits.environments`, `idle`, resources, network) are `PUT /v1/tenant/sandbox`
406
+ on the Management API.
399
407
 
400
408
  ### Pods on a cluster (preview)
401
409
 
@@ -411,7 +419,7 @@ service to the Tenant: the one container holding the cluster credentials
411
419
  (`<Host root>/sandboxes/`). On kind under Linux, pass `--host-address 172.17.0.1`.
412
420
  `nylorun local sandbox disable` removes the service (`--delete-namespace` also deletes
413
421
  the namespace and every sandbox in it). Sessions run in a pod when their
414
- Environment has kind `pod` (`client.environments.put(id, { kind: "pod" })`).
422
+ Agent's manifest has `runtime.kind` `pod`.
415
423
 
416
424
  ## Host root
417
425
 
@@ -431,14 +439,14 @@ containers, volumes and Host root: the vault key (KEK) and all its data go with
431
439
 
432
440
  ## Remote installations
433
441
 
434
- The `agents`, `sessions`, `environments`, `artifacts` and `tenant` groups,
442
+ The `apply`, `agent-manifests`, `agents`, `sessions`, `artifacts` and `tenant` commands,
435
443
  `status` and `doctor sandbox` act on a Tenant over its APIs. Without `--tenant`, they act on the installation the
436
444
  environment names, when it names one for their API:
437
445
 
438
446
  | Variables | Acts on |
439
447
  | --- | --- |
440
448
  | `NYLORUN_RUNTIME_URL` and `NYLORUN_MANAGEMENT_KEY` | `status`, `doctor sandbox` and `tenant` (the Management API) |
441
- | `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY` | `agents`, `sessions`, `environments` and `artifacts` (the Runtime API) |
449
+ | `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY` | `apply`, `agent-manifests`, `agents`, `sessions` and `artifacts` (the Runtime API) |
442
450
  | `NYLORUN_RUNTIME_URL` and `NYLORUN_TOKEN` | the same, with an identity provider's token in place of the key: the person it names, with the scopes it grants |
443
451
 
444
452
  `NYLORUN_RUNTIME_URL` alone is an app's and names nothing, as for
@@ -459,16 +467,52 @@ sessions and to the scopes given (`--scope`, repeatable; default
459
467
  `sessions:own`). Use it to see what one person sees, or to act on their sessions
460
468
  from a terminal.
461
469
 
462
- ### Saving an agent from its manifest
470
+ ### Agent manifests: `apply`
463
471
 
464
- `nylorun agents save agent.json --files skills/` saves the agent a manifest
465
- describes, as `saveAgent` does from code. A manifest names each definition file
466
- (a skill folder's files) by the SHA-256 of its bytes, so the files under the
467
- `--files` folders are matched by content, whatever their paths; the ones the
468
- Runtime does not hold are uploaded first (`PUT /v1/files/sha256:…`). A file the
469
- manifest names but no folder holds stops the save before any request, naming
470
- where the manifest names it. `nylorun agents get <id>` prints a saved agent's
471
- manifest; the Runtime does not hand files back, so keep them with the manifest.
472
+ An agent runs from a saved **agent manifest** (protocol 16): one named, versioned
473
+ document with a harness section (instructions, tools, skills, MCP servers,
474
+ plugins) and a runtime section (kind, image, network, setup, files, secret
475
+ slots). Author it as files, one folder per agent:
476
+
477
+ ```
478
+ agents/triage/agent.manifest.json # { "manifestSchemaVersion": 8, "name": "triage",
479
+ # "harness": "./harness.manifest.json",
480
+ # "runtime": "../../shared/runtime.manifest.json" }
481
+ agents/triage/harness.manifest.json # instructions, tools, "skills": "./skills",
482
+ # "mcpServers": "./mcp.json", "plugins": ["../../plugins/github"],
483
+ # "credentials": { "linear": "linear" }, "requires": { "sandbox": "any" }
484
+ agents/triage/skills/<skill>/SKILL.md
485
+ shared/runtime.manifest.json # kind, image, "files": [{ "path": "/workspace/kit", "from": "./kit" }], secrets
486
+ ```
487
+
488
+ `nylorun apply agents/triage` composes the folder as `composeManifest` of
489
+ `@nylorun/agents` does (each path relative to the file that names it; skills,
490
+ plugins and `from` folders hashed; `credentials` set on the servers and HTTP
491
+ tools it names; `requires` checked against the runtime and left out), prints the
492
+ plan (`triage: version 2 → 3`, then each change as `section path op`, warnings
493
+ and errors) and saves it under `If-Match` set to the version it planned
494
+ against, uploading the files the Runtime does not hold (`PUT /v1/files/sha256:…`).
495
+ A manifest whose sections do not fit, or whose runtime misses what its harness
496
+ `requires`, is an error: nothing is saved and the command exits 1. `--dry-run`
497
+ prints the plans only; `--if-match <n>` saves only over version `n`.
498
+ `nylorun apply agents/` applies every subfolder with an `agent.manifest.json`;
499
+ every folder composes before anything is sent.
500
+
501
+ `nylorun agent-manifests list` shows each manifest's latest version, runtime
502
+ kind, harness and the Agents made from it; `get <name>[@<n>]` prints a version,
503
+ `versions <name>` its history and `rm <name>` deletes it (refused while an Agent
504
+ was made from it). Make an Agent from it with `nylorun agents put <id> --manifest
505
+ <name>` (tracking its latest version) or `--manifest <name>@<n>` (pinned), and
506
+ open sessions on it with `nylorun sessions create --agent <id> --owner <user>`.
507
+
508
+ `nylorun migrate v8 agent.json [--runtime box.json] [--out agents/triage]`
509
+ writes the three files from an agent manifest v7 (as `nylorun agents save` took
510
+ it) and the environment manifest v1 its sessions ran in: the environment
511
+ manifest's fields become the runtime file, its `harness` the harness file's `id`,
512
+ and v7's `requires` stays in the harness file for `apply` to check. With no
513
+ environment manifest the kind is `pod` when the agent requires one, `virtual`
514
+ when it has skills or requires a sandbox, else `none`. It overwrites no file and
515
+ prints the gaps to fix before `apply`.
472
516
 
473
517
  ### `local reset` or `tenant reset`
474
518
 
@@ -477,7 +521,7 @@ Both reset a Tenant, in different ways:
477
521
  | | `nylorun local reset` | `nylorun tenant reset` |
478
522
  | --- | --- | --- |
479
523
  | Acts on | the local Tenant on this machine, through Docker | the Tenant, local or remote, through the Management API with a management key |
480
- | 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 | 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 |
524
+ | 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 | the sessions (the default), the Agents with their vaults, disks and sessions (`--agents`) or all the data (`--all`) after draining work in flight; the Tenant, its keys and the Project link are kept |
481
525
 
482
526
  `nylorun tenant reset --all` asks first; pass `--yes` when not in a terminal.
483
527
  `nylorun local reset` asks too, or takes `--yes`.
@@ -558,7 +602,7 @@ them. The Runtime's own are `NYLORUN_TUNING`, which `nylorun start` passes on.
558
602
  | 0 | Success |
559
603
  | 1 | Generic failure, including a missing Docker or Compose v2 |
560
604
  | 2 | Usage error (including no Tenant selected, or `local delete` without `--yes`), or a removed or moved command |
561
- | 3 | `status`: the Runtime is not answering; `tenant`, `environments`, `local sandbox`: the local Tenant is not running; `stop`/`local logs`: no Tenant yet; `local delete`: no such Tenant; `start`: a Tenant created by nylorun 0.5 (reset it) |
605
+ | 3 | `status`: the Runtime is not answering; `tenant`, `agents`, `apply`, `local sandbox`: the local Tenant is not running; `stop`/`local logs`: no Tenant yet; `local delete`: no such Tenant; `start`: a Tenant created by nylorun 0.5 (reset it) |
562
606
  | 4 | The Runtime port is held by another Host |
563
607
  | 5 | `up`/`start`/`studio`: this nylorun pins a Runtime older than the one that last ran the Tenant; update nylorun, or `start --allow-downgrade` |
564
608
  | 7 | The containers, the Tenant or Studio did not become ready (an unavailable Tenant's cause is printed) |
@@ -577,7 +621,7 @@ them. The Runtime's own are `NYLORUN_TUNING`, which `nylorun start` passes on.
577
621
  | Studio login expired | `nylorun studio` |
578
622
  | Which Studio is which | `nylorun local ls` lists each Tenant's Studio URL; `nylorun studio --tenant <name>` opens one signed in |
579
623
  | `Tenant … was created by nylorun 0.5` (exit 3) | `nylorun local reset --tenant <name>` (its data starts fresh) |
580
- | `tenant` or `environments`: the Tenant is not running or not open | `npx nylorun start`, then `npx nylorun status`, which shows the cause and its `repair` |
624
+ | `tenant`, `agents` or `apply`: the Tenant is not running or not open | `npx nylorun start`, then `npx nylorun status`, which shows the cause and its `repair` |
581
625
  | No management key for a remote installation | Set `NYLORUN_MANAGEMENT_KEY`; on the Runtime's machine `nylorun tenant keys put <id> --management` issues one |
582
626
  | `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 |
583
627
  | Old Project link refused | `npx nylorun start` in the project |
package/dist/cli.js CHANGED
@@ -12,14 +12,24 @@ ${stackUsage}
12
12
  doctor sandbox [--tenant <name>] [--json]
13
13
  the sandbox backend the Tenant's Host offers
14
14
 
15
+ Agent manifests:
16
+ apply [<dir>...] [--dry-run] [--if-match <n>]
17
+ save the agent manifest each folder's agent.manifest.json
18
+ describes, with the files it names (Runtime API)
19
+ migrate v8 <agent.json> [--runtime <environment-manifest.json>] [--out <dir>]
20
+ write the three manifest files from an agent manifest v7
21
+ and an environment manifest v1 (reads no Runtime)
22
+
15
23
  Groups, each with its own --help:
16
- agents list | get | save the Tenant's agents (Runtime API, an application key)
24
+ agent-manifests list | get | versions | rm
25
+ the Tenant's agent manifests (Runtime API)
26
+ agents list | get | put | fork | stop | reset | rm | snapshot | restore
27
+ versions | delete-version | events | secrets
28
+ the Tenant's Agents, made from saved manifests; sessions
29
+ run on them (Runtime API)
17
30
  sessions list | create | get | send | approve | respond | cancel | watch | history
18
31
  usage | calls | trace | exec
19
32
  the Tenant's sessions (Runtime API)
20
- environments list | get | put | fork | stop | reset | delete | snapshot | restore
21
- versions | delete-version | events | secrets | manifests
22
- the Tenant's Environments (Runtime API)
23
33
  artifacts list | get | upload | download | tree | diff | zip | link | rm
24
34
  the Tenant's file artifacts (Runtime API)
25
35
  tenant reset | keys | signing-keys | models | usage | calls | budgets | tool-policy |
@@ -32,7 +42,8 @@ A command acts on the local Tenant --tenant names, else the linked project's, el
32
42
  project) the default Tenant; NYLORUN_HOME sets its Host root (default
33
43
  ~/.nylorun/tenants/<name>). Without --tenant, NYLORUN_RUNTIME_URL names a remote installation:
34
44
  with NYLORUN_MANAGEMENT_KEY for status, doctor sandbox and tenant; with NYLORUN_SERVER_KEY, or an
35
- identity provider's token in NYLORUN_TOKEN, for agents, sessions, environments and artifacts.
45
+ identity provider's token in NYLORUN_TOKEN, for apply, agent-manifests, agents, sessions and
46
+ artifacts.
36
47
  The Runtime API groups act for a person with --as <subject> [--scope <scope>]...`;
37
48
  const localUsage = `nylorun local <command>
38
49
 
@@ -54,7 +65,8 @@ const MOVED = {
54
65
  ls: "nylorun ls moved: nylorun local ls",
55
66
  delete: "nylorun delete moved: nylorun local delete",
56
67
  telemetry: "nylorun telemetry moved: nylorun local telemetry",
57
- reset: "nylorun reset moved: nylorun local reset deletes a local Tenant's volumes; nylorun tenant reset clears its sessions or Environments through the Management API",
68
+ reset: "nylorun reset moved: nylorun local reset deletes a local Tenant's volumes; nylorun tenant reset clears its sessions or Agents through the Management API",
69
+ environments: "nylorun environments is nylorun agents in protocol 16: Environments are Agents, made from saved agent manifests (nylorun apply). Environment manifests are the runtime section of an agent manifest (nylorun migrate v8).",
58
70
  key: "nylorun key moved: nylorun tenant keys put|list|rm",
59
71
  keys: "nylorun keys is nylorun tenant keys put|list|rm",
60
72
  mcp: "nylorun mcp moved: nylorun tenant mcp inspect <url>",
@@ -66,10 +78,10 @@ const MOVED = {
66
78
  runtime: "nylorun runtime was removed: the local Runtime runs in Docker Compose. Use nylorun up|down|status and nylorun local logs.",
67
79
  };
68
80
  const SANDBOX_MOVED = {
69
- ls: "nylorun sandbox ls moved: nylorun environments list",
70
- list: "nylorun sandbox ls moved: nylorun environments list",
71
- rm: "nylorun sandbox rm moved: nylorun environments delete <id>",
72
- delete: "nylorun sandbox rm moved: nylorun environments delete <id>",
81
+ ls: "nylorun sandbox ls moved: nylorun agents list",
82
+ list: "nylorun sandbox ls moved: nylorun agents list",
83
+ rm: "nylorun sandbox rm moved: nylorun agents rm <id>",
84
+ delete: "nylorun sandbox rm moved: nylorun agents rm <id>",
73
85
  };
74
86
  const LOCAL_UI_REMOVED = "--local-ui was removed: Studio runs in its own container. Run nylorun studio.";
75
87
  const usageError = (message) => new CliError(message, 2);
@@ -150,11 +162,18 @@ async function main() {
150
162
  process.exitCode = await tenantCommand(defaultStackDeps(env), args);
151
163
  return;
152
164
  }
153
- if (command === "agents" || command === "sessions" || command === "environments" || command === "artifacts") {
165
+ if (command === "apply" ||
166
+ command === "migrate" ||
167
+ command === "agent-manifests" ||
168
+ command === "agents" ||
169
+ command === "sessions" ||
170
+ command === "artifacts") {
154
171
  const group = {
172
+ apply: async () => (await import("./client/apply.js")).applyCommand,
173
+ migrate: async () => (await import("./client/migrate.js")).migrateCommand,
174
+ "agent-manifests": async () => (await import("./client/agent-manifests.js")).agentManifestsCommand,
155
175
  agents: async () => (await import("./client/agents.js")).agentsCommand,
156
176
  sessions: async () => (await import("./client/sessions.js")).sessionsCommand,
157
- environments: async () => (await import("./client/environments.js")).environmentsCommand,
158
177
  artifacts: async () => (await import("./client/artifacts.js")).artifactsCommand,
159
178
  }[command];
160
179
  process.exitCode = await (await group())(defaultStackDeps(env), args);
@@ -0,0 +1,4 @@
1
+ import type { StackDeps } from "../stack/commands.js";
2
+ export declare const agentManifestsUsage: string;
3
+ /** `nylorun agent-manifests <command> ...` */
4
+ export declare function agentManifestsCommand(deps: StackDeps, args: readonly string[]): Promise<number>;
@@ -0,0 +1,100 @@
1
+ import { parseAgentManifestRef } from "@nylorun/core/contracts";
2
+ import { parseFlags, positional, printJson, printTable, runtimeCall, runtimeClient, runtimeFlagsUsage, usageError, } from "./runtime.js";
3
+ export const agentManifestsUsage = `nylorun agent-manifests <command>
4
+
5
+ The Tenant's agent manifests, through the Runtime API with an application key (or
6
+ NYLORUN_TOKEN). Save one with nylorun apply <dir>.
7
+
8
+ list [--json] each manifest's latest version: its runtime kind, harness
9
+ and the Agents made from it
10
+ get <name>[@<n>] a manifest's latest version (or version n), as JSON
11
+ versions <name> its versions, with the Agents made from each
12
+ rm <name> delete every version (refused while an Agent was made
13
+ from one)
14
+
15
+ ${runtimeFlagsUsage}`;
16
+ /** The harness that runs a manifest's loop, as the list prints it. */
17
+ function harnessOf(view) {
18
+ const { harness } = view.manifest;
19
+ const id = harness.id ?? "nylorun";
20
+ return "kind" in harness && harness.kind === "workflow" ? `${id} (flow)` : id;
21
+ }
22
+ async function list(deps, args) {
23
+ const usage = "nylorun agent-manifests list [--json]";
24
+ const flags = parseFlags(args, { booleans: ["--json"] }, usage);
25
+ positional(flags, 0, usage);
26
+ const { client, connection } = await runtimeClient(deps, flags);
27
+ const manifests = await runtimeCall(() => client.agentManifests.list());
28
+ if (flags.booleans.has("--json")) {
29
+ printJson(deps, manifests);
30
+ return 0;
31
+ }
32
+ if (manifests.length === 0)
33
+ deps.out(`No agent manifests on ${connection.label}. Save one with nylorun apply <dir>.`);
34
+ else
35
+ printTable(deps, [
36
+ ["NAME", "VERSION", "KIND", "HARNESS", "AGENTS"],
37
+ ...manifests.map((view) => [
38
+ view.name,
39
+ String(view.version),
40
+ view.manifest.runtime?.kind ?? "none",
41
+ harnessOf(view),
42
+ String(view.agents),
43
+ ]),
44
+ ]);
45
+ return 0;
46
+ }
47
+ async function get(deps, args) {
48
+ const usage = "nylorun agent-manifests get <name>[@<n>]";
49
+ const flags = parseFlags(args, {}, usage);
50
+ const [ref] = positional(flags, 1, usage);
51
+ const parsed = parseAgentManifestRef(ref);
52
+ if (!parsed)
53
+ throw usageError(`${ref} is not an agent manifest's name, or name@version such as triage@3.`);
54
+ const { client } = await runtimeClient(deps, flags);
55
+ printJson(deps, await runtimeCall(() => client.agentManifests.get(parsed.name, parsed.version)));
56
+ return 0;
57
+ }
58
+ async function versions(deps, args) {
59
+ const usage = "nylorun agent-manifests versions <name>";
60
+ const flags = parseFlags(args, {}, usage);
61
+ const [name] = positional(flags, 1, usage);
62
+ const { client } = await runtimeClient(deps, flags);
63
+ printJson(deps, await runtimeCall(() => client.agentManifests.versions(name)));
64
+ return 0;
65
+ }
66
+ async function remove(deps, args) {
67
+ const usage = "nylorun agent-manifests rm <name>";
68
+ const flags = parseFlags(args, {}, usage);
69
+ const [name] = positional(flags, 1, usage);
70
+ const { client, connection } = await runtimeClient(deps, flags);
71
+ const deleted = await runtimeCall(() => client.agentManifests.delete(name));
72
+ if (!deleted.deleted) {
73
+ deps.err(`No agent manifest ${name} on ${connection.label}.`);
74
+ return 1;
75
+ }
76
+ deps.out(`Deleted agent manifest ${name}: every version.`);
77
+ return 0;
78
+ }
79
+ const COMMANDS = {
80
+ list,
81
+ ls: list,
82
+ get,
83
+ versions,
84
+ rm: remove,
85
+ delete: remove,
86
+ };
87
+ /** `nylorun agent-manifests <command> ...` */
88
+ export async function agentManifestsCommand(deps, args) {
89
+ const [sub, ...rest] = args;
90
+ if (sub === "--help" || sub === "-h") {
91
+ deps.out(agentManifestsUsage);
92
+ return 0;
93
+ }
94
+ if (sub === "save")
95
+ throw usageError("Save an agent manifest with nylorun apply <dir>: it composes agent.manifest.json and the files it names.");
96
+ const command = sub !== undefined && Object.hasOwn(COMMANDS, sub) ? COMMANDS[sub] : undefined;
97
+ if (!command)
98
+ throw usageError(sub ? `Unknown agent-manifests command ${sub}.\n${agentManifestsUsage}` : agentManifestsUsage);
99
+ return command(deps, rest);
100
+ }
@@ -1,6 +1,4 @@
1
1
  import type { StackDeps } from "../stack/commands.js";
2
2
  export declare const agentsUsage: string;
3
- /** Every `sha256:<hex>` a manifest names under a `files` map, with where it names it. */
4
- export declare function namedFiles(manifest: unknown): Map<string, string>;
5
- /** `nylorun agents <list|get|save> ...` */
3
+ /** `nylorun agents <command> ...` */
6
4
  export declare function agentsCommand(deps: StackDeps, args: readonly string[]): Promise<number>;