@nylorun/runtime 0.9.0-beta → 0.11.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.
Files changed (192) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +110 -37
  3. package/dist/adapters/execution/restate.d.ts +130 -0
  4. package/dist/adapters/execution/restate.js +442 -0
  5. package/dist/adapters/media.d.ts +2 -2
  6. package/dist/adapters/media.js +2 -2
  7. package/dist/adapters/observe.d.ts +2 -1
  8. package/dist/adapters/observe.js +2 -3
  9. package/dist/adapters/sandbox/virtual.js +1 -1
  10. package/dist/adapters/streams/s2.d.ts +18 -0
  11. package/dist/adapters/streams/s2.js +361 -0
  12. package/dist/assets.d.ts +2 -2
  13. package/dist/assets.js +5 -3
  14. package/dist/core/executors.d.ts +15 -3
  15. package/dist/core/executors.js +40 -5
  16. package/dist/core/flow-host.d.ts +225 -0
  17. package/dist/core/flow-host.js +518 -0
  18. package/dist/core/limits.d.ts +40 -0
  19. package/dist/core/limits.js +76 -0
  20. package/dist/core/runtime.d.ts +5 -90
  21. package/dist/core/runtime.js +3 -1447
  22. package/dist/core/sandbox-routes.d.ts +40 -0
  23. package/dist/core/sandbox-routes.js +106 -0
  24. package/dist/core/turn-manifest.d.ts +50 -0
  25. package/dist/core/turn-manifest.js +66 -0
  26. package/dist/execution/memory.d.ts +54 -0
  27. package/dist/execution/memory.js +217 -0
  28. package/dist/execution/types.d.ts +125 -0
  29. package/dist/execution/types.js +52 -0
  30. package/dist/host/config-for.d.ts +17 -0
  31. package/dist/host/config-for.js +27 -0
  32. package/dist/host/config.d.ts +16 -0
  33. package/dist/host/create-host.d.ts +56 -0
  34. package/dist/host/create-host.js +420 -0
  35. package/dist/host/environment.d.ts +13 -0
  36. package/dist/host/environment.js +53 -0
  37. package/dist/host/execution.d.ts +61 -0
  38. package/dist/host/execution.js +69 -0
  39. package/dist/host/http.d.ts +39 -0
  40. package/dist/host/http.js +142 -0
  41. package/dist/host/index.d.ts +8 -0
  42. package/dist/host/index.js +7 -0
  43. package/dist/host/logger.d.ts +3 -0
  44. package/dist/host/logger.js +18 -0
  45. package/dist/host/main.d.ts +3 -0
  46. package/dist/host/main.js +201 -0
  47. package/dist/host/stack-config.d.ts +72 -0
  48. package/dist/host/stack-config.js +193 -0
  49. package/dist/index.d.ts +7 -2
  50. package/dist/index.js +4 -2
  51. package/dist/infra/database.d.ts +16 -0
  52. package/dist/infra/database.js +31 -0
  53. package/dist/infra/execution.d.ts +39 -0
  54. package/dist/infra/execution.js +68 -0
  55. package/dist/infra/index.d.ts +42 -0
  56. package/dist/infra/index.js +56 -0
  57. package/dist/infra/readiness.d.ts +33 -0
  58. package/dist/infra/readiness.js +53 -0
  59. package/dist/infra/streams.d.ts +17 -0
  60. package/dist/infra/streams.js +33 -0
  61. package/dist/infra/workers.d.ts +39 -0
  62. package/dist/infra/workers.js +31 -0
  63. package/dist/mcp/connect.d.ts +1 -0
  64. package/dist/mcp/connect.js +2 -0
  65. package/dist/mcp/pool.d.ts +3 -1
  66. package/dist/mcp/pool.js +2 -1
  67. package/dist/mcp/stdio.d.ts +2 -0
  68. package/dist/mcp/stdio.js +3 -1
  69. package/dist/model/auth-store.d.ts +1 -1
  70. package/dist/model/auth-store.js +2 -2
  71. package/dist/model/models.d.ts +4 -0
  72. package/dist/model/models.js +22 -26
  73. package/dist/model/pi-model.d.ts +2 -2
  74. package/dist/model/pi-model.js +6 -6
  75. package/dist/model/settings.d.ts +5 -1
  76. package/dist/model/settings.js +6 -2
  77. package/dist/sandbox/manager.d.ts +26 -8
  78. package/dist/sandbox/manager.js +95 -47
  79. package/dist/sandbox/select.d.ts +5 -4
  80. package/dist/sandbox/select.js +18 -13
  81. package/dist/sandbox/share.d.ts +23 -0
  82. package/dist/sandbox/share.js +58 -0
  83. package/dist/sandbox/types.d.ts +2 -2
  84. package/dist/store/canonical.d.ts +5 -0
  85. package/dist/store/canonical.js +17 -0
  86. package/dist/store/cursor.d.ts +9 -0
  87. package/dist/store/cursor.js +18 -0
  88. package/dist/store/memory.d.ts +57 -0
  89. package/dist/store/memory.js +643 -0
  90. package/dist/store/ownership.d.ts +19 -0
  91. package/dist/store/ownership.js +33 -0
  92. package/dist/store/postgres/connect.d.ts +25 -0
  93. package/dist/store/postgres/connect.js +25 -0
  94. package/dist/store/postgres/locking.d.ts +16 -0
  95. package/dist/store/postgres/locking.js +22 -0
  96. package/dist/store/postgres/migrations/001_initial.d.ts +27 -0
  97. package/dist/store/postgres/migrations/001_initial.js +196 -0
  98. package/dist/store/postgres/migrations/index.d.ts +49 -0
  99. package/dist/store/postgres/migrations/index.js +75 -0
  100. package/dist/store/postgres/names.d.ts +11 -0
  101. package/dist/store/postgres/names.js +42 -0
  102. package/dist/store/postgres/store.d.ts +11 -0
  103. package/dist/store/postgres/store.js +790 -0
  104. package/dist/store/postgres/tenants.d.ts +90 -0
  105. package/dist/store/postgres/tenants.js +207 -0
  106. package/dist/store/types.d.ts +440 -0
  107. package/dist/store/types.js +10 -0
  108. package/dist/streams/basin.d.ts +23 -0
  109. package/dist/streams/basin.js +51 -0
  110. package/dist/streams/memory.d.ts +25 -0
  111. package/dist/streams/memory.js +124 -0
  112. package/dist/streams/relay.d.ts +37 -0
  113. package/dist/streams/relay.js +254 -0
  114. package/dist/streams/types.d.ts +115 -0
  115. package/dist/streams/types.js +86 -0
  116. package/dist/tenant/actions.d.ts +153 -0
  117. package/dist/tenant/actions.js +191 -0
  118. package/dist/tenant/advance.d.ts +15 -0
  119. package/dist/tenant/advance.js +439 -0
  120. package/dist/tenant/auth.d.ts +11 -0
  121. package/dist/tenant/auth.js +34 -0
  122. package/dist/tenant/commands.d.ts +3 -0
  123. package/dist/tenant/commands.js +384 -0
  124. package/dist/tenant/context.d.ts +140 -0
  125. package/dist/tenant/context.js +40 -0
  126. package/dist/tenant/effects.d.ts +20 -0
  127. package/dist/tenant/effects.js +539 -0
  128. package/dist/tenant/envelope.d.ts +7 -0
  129. package/dist/tenant/envelope.js +22 -0
  130. package/dist/tenant/ephemeral.d.ts +42 -0
  131. package/dist/tenant/ephemeral.js +224 -0
  132. package/dist/tenant/http.d.ts +32 -0
  133. package/dist/tenant/http.js +51 -0
  134. package/dist/tenant/live.d.ts +92 -0
  135. package/dist/tenant/live.js +290 -0
  136. package/dist/tenant/logger.d.ts +9 -0
  137. package/dist/tenant/logger.js +25 -0
  138. package/dist/tenant/model-setting.d.ts +16 -0
  139. package/dist/tenant/model-setting.js +12 -0
  140. package/dist/tenant/module.d.ts +38 -0
  141. package/dist/tenant/module.js +319 -0
  142. package/dist/tenant/paths.d.ts +28 -0
  143. package/dist/tenant/paths.js +91 -0
  144. package/dist/tenant/pool.d.ts +10 -0
  145. package/dist/tenant/pool.js +54 -0
  146. package/dist/tenant/principals.d.ts +13 -0
  147. package/dist/tenant/principals.js +37 -0
  148. package/dist/tenant/quarantine-error.d.ts +6 -0
  149. package/dist/tenant/quarantine-error.js +9 -0
  150. package/dist/tenant/quarantine.d.ts +27 -0
  151. package/dist/tenant/quarantine.js +72 -0
  152. package/dist/tenant/reset.d.ts +22 -0
  153. package/dist/tenant/reset.js +81 -0
  154. package/dist/tenant/routes-tenant.d.ts +12 -0
  155. package/dist/tenant/routes-tenant.js +126 -0
  156. package/dist/tenant/routes.d.ts +9 -0
  157. package/dist/tenant/routes.js +142 -0
  158. package/dist/tenant/runtime.d.ts +81 -0
  159. package/dist/tenant/runtime.js +298 -0
  160. package/dist/tenant/scheduler.d.ts +25 -0
  161. package/dist/tenant/scheduler.js +84 -0
  162. package/dist/tenant/session.d.ts +60 -0
  163. package/dist/tenant/session.js +94 -0
  164. package/dist/tenant/sessions.d.ts +34 -0
  165. package/dist/tenant/sessions.js +149 -0
  166. package/dist/tenant/status.d.ts +37 -0
  167. package/dist/tenant/status.js +130 -0
  168. package/dist/tenant/store-memory.d.ts +16 -0
  169. package/dist/tenant/store-memory.js +111 -0
  170. package/dist/tenant/store-pg.d.ts +15 -0
  171. package/dist/tenant/store-pg.js +140 -0
  172. package/dist/tenant/streams.d.ts +126 -0
  173. package/dist/tenant/streams.js +419 -0
  174. package/dist/tenant/sweep.d.ts +15 -0
  175. package/dist/tenant/sweep.js +122 -0
  176. package/dist/tenant/types.d.ts +205 -0
  177. package/dist/tenant/types.js +23 -0
  178. package/dist/tenant/worker.d.ts +84 -0
  179. package/dist/tenant/worker.js +189 -0
  180. package/dist/vault/kek.d.ts +5 -2
  181. package/dist/vault/kek.js +7 -10
  182. package/dist/vault/service.d.ts +37 -31
  183. package/dist/vault/service.js +439 -359
  184. package/dist/version.d.ts +1 -1
  185. package/dist/version.js +1 -1
  186. package/package.json +14 -11
  187. package/dist/adapters/sandbox/microsandbox.d.ts +0 -2
  188. package/dist/adapters/sandbox/microsandbox.js +0 -238
  189. package/dist/core/main.js +0 -35
  190. package/dist/core/store.d.ts +0 -30
  191. package/dist/core/store.js +0 -202
  192. /package/dist/{core/main.d.ts → host/config.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,86 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.0-beta
4
+
5
+ ### Minor Changes
6
+
7
+ - bf1c2da: **`nylorun dev --ephemeral` runs on the Docker stack, with a Tenant-level fixture model (breaking beta).**
8
+
9
+ - `nylorun dev --ephemeral` creates a temporary Tenant through `@nylorun/admin` (no Project link written), seeds it from `.env` with the fixture model, opens Studio on it and runs the watcher; the Tenant is deleted with its active work cancelled when the watcher ends, Ctrl-C included. It needs a Runtime that advertises `tenant-fixture-model`.
10
+ - `PUT /v1/tenant/config/seed` accepts `fixtureModel: true`, stored as Tenant setting `model.fixture`: that Tenant's model calls use the Runtime's fixture model while other Tenants on the Host keep theirs. `HOST_PROTOCOL` advertises the new optional feature `tenant-fixture-model` (`OPTIONAL_HOST_FEATURES` in `@nylorun/core/compatibility`); clients do not require it.
11
+ - `startEphemeralRuntime()` keeps its signature but its Tenants live in memory instead of SQLite under the Host root; nothing survives `close()`.
12
+ - Closing a Tenant waits for running advances at most the advance grace period (30 s by default) and then abandons them; their lease lapses and the next advance takes over.
13
+ - A Worker stop, Tenant close or ended Restate attempt no longer fails or cancels the turn it interrupts: outcomes already returned are recorded, nothing is settled, and the next advance resumes the turn from its checkpoint. Only a user cancel settles `cancelled`; an advance deadline fails the turn with the deadline's message.
14
+
15
+ - bf1c2da: **The microsandbox backend is removed; the Runtime runs sandbox tools on the virtual backend only.** The optional `microsandbox` dependency is gone. `sandbox.backend` and `NYLORUN_SANDBOX` accept `auto` or `virtual`, and `auto` selects `virtual`. A Tenant that stored `microsandbox` reads it as `auto`. `nylorun doctor sandbox` and the `nylorun dev` banner report only the virtual shell.
16
+ - bf1c2da: **Tenants are Postgres schemas only; SQLite and the `nylorun-runtime` launcher are removed (breaking beta).**
17
+
18
+ - The Runtime runs on Postgres (the Session Store, one schema per Tenant), Restate (Durable Session Execution: one advance per session, fenced by an ownership epoch, and a per-Tenant sweep) and S2 (Durable Streams: every event is written to a Postgres outbox and relayed to the session's stream, which history and SSE read). `--role api|worker|all` selects the process role; `/ready` covers Postgres, Restate and S2.
19
+ - SQLite Tenants are not migrated. On first start the Runtime moves every `tenants/<id>/` directory that holds a `tenant.sqlite` to `trash/<id>-sqlite-<time>/` and logs `sqlite_tenant_moved_to_trash`; recreate those Tenants.
20
+ - `@nylorun/runtime` has no bin: the `nylorun-runtime` launcher and `host-state.json` are gone. The Runtime runs as the `ghcr.io/nylorun/runtime` image (`nylorun start`); its Host entry requires `NYLORUN_DATABASE_URL`.
21
+ - `openTenantRuntime(config, hooks)` requires the Tenant's opened `store` and `envelope`; `OpenTenantRuntime` receives them from the Tenant store. `HostStateFile` is no longer exported.
22
+ - `@nylorun/core`: `LAUNCHER_PROTOCOL` and the launcher error codes are removed; `QuarantineSchema` drops `locked`, `lockPath` and `lockPid`; `TenantStatusSchema.checks.sqlite` is now `checks.store`. `TenantStatusSchema` gains optional `execution` (stuck invocations) and `streams` (basin, outbox depth, relay lag); `HostAggregateSchema` gains optional `outboxDepth` and `relayLagMs`.
23
+
24
+ - bf1c2da: **Tenants can register a Studio principal.** `CreateTenantRequest` gains optional `studioCredentialHash` behind the new protocol feature `studio-principal`; the Runtime stores it as application principal `studio`, and idempotent create compares it too. `@nylorun/admin` exports `deriveStudioToken(adminKey, tenantId)` (HMAC-SHA256 over `nylorun/studio/v1`, NUL, Tenant id) and `createTenant` sends the hash of that key, so Studio can reach any Tenant's API with a key derived from the admin key. Clients require the new feature, so upgrade the Runtime with them.
25
+ - 1d84b3e: **Native Windows is no longer supported; Windows developers use WSL2.** Nylorun runs on macOS and Linux. On native Windows, `nylorun` and `npm create @nylorun/agent` stop with WSL2 guidance. Install Node 24 and Docker (Docker Desktop's WSL integration) inside your WSL distribution and keep projects in its Linux filesystem. The Windows-only process handling (`taskkill`, `.cmd` shims, `npm.cmd`) is removed. `nylorun doctor` reports WSL as `Linux (WSL: <distribution>)`.
26
+
27
+ ### Patch Changes
28
+
29
+ - ba1b239: **`nylorun` sets up the local stack; `@nylorun/cli` becomes the Runtime client `nylo` (breaking beta).**
30
+
31
+ - New unscoped package **`nylorun`**: `npx nylorun up` sets up the Docker stack on the first run and starts it after that, from any directory; `npx nylorun down` stops it (volumes are kept). `up` and `down` are aliases of `start` and `stop`. It also owns `status`, `logs`, `studio`, `reset` and `doctor`, pins the Runtime and Studio images (`package.json` `nylorun.runtime` / `nylorun.studio`), depends on `@nylorun/core` only, and never creates Tenants.
32
+ - **`@nylorun/cli`** is the Runtime client with the command **`nylo`**: `nylo tenant create [name]` (creates the Tenant; in a project, writes the Project link and seeds the model provider and sandbox from `.env`), `nylo tenant current|list|use|status|reset|delete`, `nylo configure`, `nylo env` (was `nylorun status --env`) and `nylo doctor sandbox`. It no longer provides the `nylorun` command or the stack commands.
33
+ - **Removed:** `nylorun dev` and `nylorun dev --ephemeral`. Link once with `nylo tenant create`, then run the project's own `npm run dev`. Moved commands exit 2 and name their replacement.
34
+ - **Starter:** the generated project depends on `@nylorun/agents` only (no Nylorun devDependency); `dev` is `tsx watch --env-file-if-exists=.env src/main.ts`. `npm create @nylorun/agent` installs the project and prints the next steps (`npx nylorun up`, `npx @nylorun/cli tenant create`, `npm run dev`) instead of starting development; `--no-open` is accepted and ignored.
35
+ - `connectAgents` names those steps when it finds no Runtime connection. Runtime repair hints, model errors and core's sandbox message name `nylo` and `nylorun up`.
36
+
37
+ - 262bded: A Tenant's stream wiring no longer logs after it stops. A basin repair that failed after the Tenant closed could write to a Tenant log directory that was already removed and end the process with an unhandled rejection.
38
+ - Pin core to the tested release.
39
+ - Pin harness to the tested release.
40
+ - Updated dependencies [bf1c2da]
41
+ - Updated dependencies [ba1b239]
42
+ - Updated dependencies [bf1c2da]
43
+ - Updated dependencies [bf1c2da]
44
+ - Updated dependencies [bf1c2da]
45
+ - Updated dependencies
46
+ - @nylorun/core@0.6.0-beta
47
+ - @nylorun/harness@0.19.1-beta
48
+
49
+ ## 0.10.0-beta
50
+
51
+ ### Minor Changes
52
+
53
+ - c49efed: **Runtime Clients and Admin API (supporting packages).**
54
+
55
+ - **core:** `AdminStatusSchema`, Project-link schemas, `ERROR_CODES` (launcher codes include `platform_unsupported`, `launcher_failed`, `downgrade_refused`), `admin-status` feature, `newPrincipalId`, `compareVersions`.
56
+ - **runtime:** `/v1/admin/status` (alias `/v1/admin/host`), loopback/`Origin`/content-type checks; the launcher ships as this package's `nylorun-runtime` bin (source under `src/launcher/`, not in `exports`) and runs the Host on the Node it runs on.
57
+ - **studio:** `nylorun-studio` binary; connects via `resolveConnection`; waits for `dev`; never calls Admin API or writes `.nylorun/`.
58
+
59
+ **Prerequisites:** developers install Node 24+ and `@nylorun/runtime` (`npm install --global @nylorun/runtime`) themselves; no package downloads Node or the Runtime, and there are no per-platform Runtime packages. Launcher commands: `version`, `up`, `down`, `restart`, `run`, `status`, `logs` (launcher protocol 1).
60
+
61
+ - c49efed: **Breaking (pre-1.0 minor):** Replace a single SQLite Runtime per Project or home directory with a **Runtime Host** that serves isolated **Tenants**, selected by `Nylorun-Tenant` and negotiated with `Nylorun-Protocol` (protocol `2`, feature `runtime-tenants`). Vocabulary: Host root + Tenant + Project link.
62
+
63
+ - **core:** `PROTOCOL_VERSION = 2`, `HOST_PROTOCOL`, `TENANT_HEADER`, `PROTOCOL_HEADER`, `newTenantId` / `isTenantId`, `checkCompatibility`; health schema gains `hostId` + `protocol` (`service: "nylorun-runtime"`); Tenant/admin wire schemas; Tenant model routes under `/v1/tenant/*`.
64
+ - **runtime:** Host process + Tenant module; Tenant model routes under `/v1/tenant/*`; `startEphemeralRuntime` for tests/embeds; executors via `PUT /v1/executors`; sandbox prefix `nylorun-<tenant-id>-`.
65
+ - **agents:** `createClient({ url, key, tenant })`; Transport sends Tenant + protocol headers; `/health` compatibility cache; `IncompatibleRuntimeError` with upgrade remedies.
66
+ - **cli:** Host root lifecycle (`runtime up|down|status|logs|restart|run`); Project link (`.nylorun/link.json` + `credentials.json`); `tenant` commands; `runtime status --env` exports `NYLORUN_RUNTIME_URL`, `NYLORUN_SERVER_KEY`, `NYLORUN_TENANT`; removed Project/home SQLite selectors.
67
+ - **studio:** `startStudio({ …, tenant: { id, name } })`; proxy forwards Tenant + protocol headers; UI shows Tenant name/short id.
68
+
69
+ - fd9fd87: Add workflows: compose agents and `tool()` with `Chain`, `Switch`, `Parallel`, `Map`, and `Loop`. A workflow is a registered runnable (`kind: "workflow"`) with the same session API as an agent — `export const agents`, `saveAgent` (saves referenced agents first), `createSession`, `input` (`content` or `data`), `observe({ follow })`, `pending`, `approve`, `cancel`. Slots (`{ run, id?, input? }`) reshape data between nodes. The flow engine (`runFlowDurable`) returns effects only; `harness/src/loop/` and `runDurable` are unchanged.
70
+
71
+ HostEffect gains flow kinds `agent`, `tool` (node), `fn`, and `verify`, each with `path`, `key`, and `iterations`. The Runtime drives agent nodes through the public session contract (linked sessions, shared sandbox via `PutSession.sandbox`), offers `fn` / `verify` again on lease expiry, and routes executor Actions by `(workflowId, key)` with claim-scoped `ctx.sandbox`. Optional `message.manifest` is a turn-only variant of the session pin (turn manifests). Studio shows the manifest tree, live node status, and session links. Examples under `examples/agents/{chain,switch,parallel,map,loop,ship-feature}/`.
72
+
73
+ ### Patch Changes
74
+
75
+ - Pin core to the tested release.
76
+ - Pin harness to the tested release.
77
+ - Updated dependencies [c49efed]
78
+ - Updated dependencies [c49efed]
79
+ - Updated dependencies [fd9fd87]
80
+ - Updated dependencies
81
+ - @nylorun/core@0.5.0-beta
82
+ - @nylorun/harness@0.19.0-beta
83
+
3
84
  ## 0.9.0-beta
4
85
 
5
86
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # @nylorun/runtime
2
2
 
3
- The independent OSS HTTP execution host consumes `@nylorun/harness/run` and `@nylorun/core/contracts`. Cloud installs published `@nylorun/harness` from npm and does not import this Runtime package. Client authoring, sessions and connected executors belong to `@nylorun/agents`.
3
+ The independent OSS **Runtime Host** consumes `@nylorun/harness/run` and
4
+ `@nylorun/core/contracts`. Cloud installs published `@nylorun/harness` from npm
5
+ and does not import this package. Client authoring and sessions belong to
6
+ `@nylorun/agents`; Tenant lifecycle management belongs to `@nylorun/admin`.
7
+ Vocabulary: [src/CONTEXT.md](./src/CONTEXT.md).
4
8
 
5
9
  Requires Node 24+. Build from the repository root:
6
10
 
@@ -9,43 +13,112 @@ npm install
9
13
  npm run build --workspace @nylorun/core
10
14
  npm run build --workspace @nylorun/harness
11
15
  npm run build --workspace @nylorun/runtime
12
- NYLORUN_SERVER_KEY='<separate-secret-at-least-16-characters>' npm start --workspace @nylorun/runtime
13
16
  ```
14
17
 
15
- Default address: `http://127.0.0.1:8787`. `HOST`, `PORT`, and `NYLORUN_SQLITE_PATH` configure binding and storage. Missing server credentials fail startup. The default model is a credential-free scripted development response. It does not simulate conversations, tools or provider compatibility.
16
-
17
- `NYLORUN_EXECUTORS_JSON` is an array of `{token, agentId, implementationVersion}`. Each secret must differ from the application server key and every other executor token. An optional `manifestHash` on an existing record is ignored and does not hide or reject work. SDK clients use `NYLORUN_RUNTIME_URL`, `NYLORUN_SERVER_KEY`, and `NYLORUN_EXECUTOR_KEY`; runtime executor scope is the agent id, never broadened by client input.
18
-
19
- For a model gateway, set `NYLORUN_MODEL_GATEWAY_URL`, `NYLORUN_MODEL_GATEWAY_KEY`, and `NYLORUN_MODEL`. The gateway receives `{model, call, context}` and returns a harness ModelCandidate or string. Provider credentials remain host configuration. The generic gateway requires an implementation of this envelope; it does not claim arbitrary provider wire compatibility. Alternatively supply a `ModelProvider` to `startRuntime`.
20
-
21
- ```ts
22
- import { startRuntime } from '@nylorun/runtime/core';
23
- const runtime = await startRuntime({
24
- sqlitePath: './nylorun.sqlite',
25
- serverToken: process.env.NYLORUN_SERVER_KEY!,
26
- executors: [], // Configure exact scoped executor credentials before customer actions.
27
- port: 8787,
28
- });
29
- // Application owns lifecycle.
30
- await runtime.close();
18
+ ## Running the Runtime
19
+
20
+ The Runtime runs as the `ghcr.io/nylorun/runtime` image, next to Postgres,
21
+ Restate and S2: `nylorun start` runs that stack on a developer machine. The
22
+ package is a library with no bin; its Host entry is `@nylorun/runtime/server`
23
+ (`dist/host/main.js`), which requires `NYLORUN_DATABASE_URL`. For tests and
24
+ ephemeral embeds, use `startEphemeralRuntime()` from `@nylorun/runtime/core`.
25
+ See [MIGRATION.md](../MIGRATION.md).
26
+
27
+ No Tenant state lives only in the Runtime process. Each Tenant's data is the
28
+ Postgres schema `tenant_<id>` (the Session Store); Restate runs one advance of a session at a
29
+ time and holds the Tenant's sweep timer (Durable Session Execution); every
30
+ session's events are relayed from the schema's outbox to its own S2 stream,
31
+ which history and SSE read (Durable Streams). An API node serves the Tenant API,
32
+ Admin API and SSE, and a Worker runs advances; `--role api|worker|all` picks
33
+ them, and the local stack runs one process with `all`.
34
+
35
+ The container is configured by its environment, which the stack's Compose file
36
+ sets: `NYLORUN_DATABASE_URL` (required), `NYLORUN_RESTATE_INGRESS_URL`,
37
+ `NYLORUN_RESTATE_ADMIN_URL`, `NYLORUN_WORKER_URL` and
38
+ `NYLORUN_RESTATE_IDENTITY_KEY` (Restate), `NYLORUN_S2_ENDPOINT` and
39
+ `NYLORUN_S2_TOKEN`, and in container mode `NYLORUN_LISTEN_HOST`,
40
+ `NYLORUN_LISTEN_PORT`, `NYLORUN_ALLOWED_HOSTS` and `NYLORUN_PUBLIC_URL`.
41
+
42
+ The Host root is `NYLORUN_HOME` or `~/.nylorun` (bind-mounted at `/nylorun` in
43
+ the stack). What stays on the Host is under `tenants/<tenantId>/`.
44
+
45
+ ## Layout
46
+
47
+ ```text
48
+ <host root>/
49
+ host.json # format 1: hostId, host, port, runtimeVersion, …
50
+ host-credentials.json # adminKey (0600)
51
+ stack/ # compose.yaml, .env (0600), Restate identity key
52
+ tenants/<tenantId>/ # vault-kek, plugin-data, logs, home, tmp, sandboxes
53
+ trash/ # SQLite Tenants from before the Postgres switch
31
54
  ```
32
55
 
33
- The session-first `/v1` API is specified in [HOST_CONTRACT.md](../harness/HOST_CONTRACT.md). `/health` confirms HTTP liveness; `/ready` checks SQLite and scheduler availability. Readiness is not a provider connectivity probe or functional correctness claim. Application tokens authorize definition/session APIs, while exact scoped executor credentials authorize authenticated SSE `/v1/executors/connect`, action discovery, claims, renewal and results. Session observers cannot claim actions.
34
-
35
- SQLite transactions persist session checkpoints, command receipts, individual effects/actions, waits and canonical history. Actions are committed before notifications. Accepted execution is detached from HTTP request lifetime. Restart schedules persisted runnable sessions; model intents lacking recorded outcomes become uncertain. Expired customer claims become uncertain and are not automatically repeated. `GET /v1/sessions/:id` exposes waits, outstanding actions and uncertain effect summaries. Cancellation ends the current turn; a later message can start another turn from the state preceding the cancelled turn. Canonical events and uncertain external work remain inspectable. Reconciliation operations are not implemented in this pass.
36
-
37
- One process owns each SQLite database. A local PID lock rejects concurrent owners and recovers only when the recorded process no longer exists. Shared/network filesystems and multiple replicas are unsupported. Keep the database and its WAL/journal together; do not delete persisted effects separately from checkpoints. Invalid lock contents or PID reuse fail closed and require operator inspection. TLS and external ingress belong to deployment infrastructure.
38
-
39
- The vault holds two scopes. End-user vaults each belong to one `ownerUserId` and store URL-bound credentials for outbound calls such as MCP. The host scope stores model provider credentials the Runtime uses when it calls a provider; Studio and `nylorun configure` can keep multiple providers and select the active provider/model. Secret values are encrypted with AES-256-GCM under a key-encryption key. Set `NYLORUN_VAULT_KEK` to 32 bytes encoded as base64, or allow the host to create `.nylorun/vault-kek` (mode 0600) on the first write. A database that already holds vault ciphertext will not open without that key. Reads return metadata only.
40
-
41
- Agents that declare `.use(sandbox())` get Runtime-executed `bash`, `read`, `write`, `edit`, `grep` and `glob` tools. The Runtime owns each sandbox: one per session, created on the first sandbox tool call, stopped after its idle timeout, and reattached with its files on the next call, including after a restart. On first use the Runtime probes its backends in order and keeps the choice for its lifetime: a microsandbox microVM (macOS on Apple Silicon, or Linux with `/dev/kvm`), then the in-process virtual shell (`just-bash`). Set `NYLORUN_SANDBOX=microsandbox` or `virtual` to force one; a forced backend never falls back. `GET /v1/host/sandbox` reports the selection, and `nylorun doctor sandbox` shows the same probe. Virtual workspaces live in `sandboxes/` beside the SQLite file. Tool calls emit `sandbox.state` and `sandbox.exec` session events. A sandbox call interrupted by a crash becomes uncertain and is never re-run. `microsandbox` is an optional dependency pinned to an exact version. See [the sandbox design](../docs/design/sandboxes.md) for guarantees and limitations.
42
-
43
- ## Local project workflow
44
-
45
- Install `@nylorun/cli` (generated projects already include it). Use `nylorun up` and `nylorun dev` in a generated project. It loads the exported `agents` registry from `agents/index.ts`, starts this Runtime in a separate process, and, when no host model credential is stored, prompts in an interactive terminal and writes it to the vault. It then registers manifests, connects scoped SDK executors, and opens Studio. Use `--no-studio` or `--no-open` as needed. Runtime binds loopback on port 8787 (`PORT` override). The CLI creates separate server and executor credentials with mode 0600 in `.nylorun/local-credentials.json`; SQLite defaults to `.nylorun/runtime.sqlite`.
46
-
47
- `nylorun serve [entry]` loads `dist/agents/index.js` by default and runs without Studio/watch, attaching to the Runtime that `nylorun up` started. It uses the same first-start prompt. `nylorun configure` replaces the host credential against a Runtime that is already listening. `nylorun studio` attaches using the project's local server credential (or `NYLORUN_SERVER_KEY`). Studio can replace an API-key credential. If `MODEL_PROVIDER`, `MODEL`, and `MODEL_PROVIDER_API_KEY` are already set, the first start seeds the vault from them and does not prompt. Existing `.env` model settings and `.nylorun/auth.json` are imported once the same way. No provider request occurs during that setup. `NYLORUN_DEV_MODEL=fixture` and `NYLORUN_MODEL_GATEWAY_URL` remain separate from the vault.
48
-
49
- Definitions have no `agent.run()`; applications use `@nylorun/agents`. The previous in-process host (`Runtime`, `serveAgents`, `openSession`, `httpModel`, `localSessions`, and the AG-UI route) has been removed; remove any remaining usage from applications.
50
-
51
- Source changes restart the local stack. Start a new session after definition or implementation edits; live upgrades are deferred. `GET /v1/agents` and `GET /v1/sessions?agentId=...` are server-authenticated local discovery conveniences.
56
+ ## HTTP surface
57
+
58
+ | Route | Auth | Notes |
59
+ | --- | --- | --- |
60
+ | `GET /health` | none | `service: "nylorun-runtime"`, `hostId`, protocol `{min,max,features}`, pid |
61
+ | `GET /ready` | none | Listener up, Tenants discovered, and Postgres, Restate and S2 answer (`checks`) |
62
+ | `GET /v1/admin/status` | admin key | `AdminStatusSchema`; alias `GET /v1/admin/host` |
63
+ | `/v1/admin/tenants*` | admin key | Create / list / get / delete Tenants |
64
+ | `POST /v1/admin/host/shutdown` | admin key | Host-private; not in `@nylorun/admin` |
65
+ | `/v1/*` Tenant routes | application or executor | Require `Nylorun-Tenant` + `Nylorun-Protocol` |
66
+
67
+ Every route checks `Host` first (`421 host_rejected`), rejects any `Origin`
68
+ (`403 origin_rejected`, no CORS headers), and rejects non-JSON bodies with
69
+ `415 unsupported_media_type`. Missing or unsupported protocol → `426` before
70
+ authentication. Unknown, quarantined or rejected Tenant credentials → opaque
71
+ `404` with identical body.
72
+
73
+ ## Embedding and tests
74
+
75
+ Tests and ephemeral embeds use `startEphemeralRuntime()` from
76
+ `@nylorun/runtime/core`: private Host on port 0, temporary Host root, one Tenant,
77
+ returns `{ url, tenantId, applicationKey, adminKey, close() }`. It is not durable:
78
+ its Tenants live in memory and are gone after `close()`. The smoke checks'
79
+ temporary Tenants (`scripts/lib/temporary-tenant.mjs`) do not use it; they are
80
+ created on the Docker stack.
81
+
82
+ Register executors with `PUT /v1/executors` using the application principal
83
+ (application-mode `connectAgents` does this with derived tokens). Model gateway
84
+ and sandbox backend are Tenant configuration (vault / seed), not Host process
85
+ env.
86
+
87
+ ## Session behaviour
88
+
89
+ The session-first `/v1` API is specified in
90
+ [HOST_CONTRACT.md](../harness/HOST_CONTRACT.md). Application tokens authorize
91
+ definition/session APIs; executor credentials authorize authenticated SSE
92
+ connect, action discovery, claims, renewal and results. Session observers cannot
93
+ claim actions.
94
+
95
+ Postgres transactions persist session checkpoints, command receipts, individual
96
+ effects/actions, waits and the event outbox — **per Tenant schema**; history is
97
+ read from Durable Streams (S2). An advance owns its session through a lease with
98
+ an epoch; a Worker that takes over after a crash marks in-flight effects
99
+ `uncertain`. Vault ciphertext needs that Tenant's own KEK.
100
+
101
+ Agents that declare `.use(sandbox())` get Runtime-executed sandbox tools. The
102
+ Tenant owns each sandbox; backend names are prefixed `nylorun-<tenant-id>-`.
103
+
104
+ ## Local Project workflow
105
+
106
+ A project depends on `@nylorun/agents` only. `npx nylorun up` runs the local
107
+ stack (Docker); `npx @nylorun/cli tenant create` (`nylo`) creates the
108
+ project's Tenant and writes its Project link; the project's `npm run dev` runs
109
+ `src/main.ts` under `tsx watch`; `npx nylorun studio` opens Studio.
110
+
111
+ ## Troubleshooting
112
+
113
+ | Symptom | What to do |
114
+ | --- | --- |
115
+ | `kek-missing` | Restore `vault-kek` in the Tenant directory |
116
+ | `corrupt` / `migration-failed` / `envelope-invalid` / `open-failed` / `open-timeout` | Follow the `nylo tenant status` repair string |
117
+ | `schema-too-new` | Run a Runtime at least as new as the one that migrated the schema |
118
+ | `426 protocol_unsupported` | Upgrade clients or Host to a compatible set |
119
+ | `421 host_rejected` / `403 origin_rejected` | Call from a server process, not a browser; in a container, list the `Host` in `NYLORUN_ALLOWED_HOSTS` |
120
+ | `503` for a Tenant | Postgres or Restate is unreachable; `GET /ready` names which |
121
+ | Port in use | Change `NYLORUN_PORT` in `<Host root>/stack/.env` and run `nylorun up` |
122
+ | Logs | `nylorun logs runtime` |
123
+
124
+ Definitions have no `agent.run()`; applications use `@nylorun/agents`.
@@ -0,0 +1,130 @@
1
+ import { type DurableExecution, type StuckInvocation, type Wake, type WorkerHandlers } from "../../execution/types.js";
2
+ export interface RestateTimeouts {
3
+ /**
4
+ * How long an invocation may run without journal progress before Restate
5
+ * asks it to suspend. An advance makes no journal entries while it runs, so
6
+ * this must exceed the longest segment. Default one hour.
7
+ */
8
+ inactivityMs?: number;
9
+ /** How long after the inactivity timeout Restate aborts the attempt. Default one hour. */
10
+ abortMs?: number;
11
+ }
12
+ /**
13
+ * Retries of a handler that throws (an infrastructure error). After
14
+ * `maxAttempts` the invocation is paused, never killed, and shows up in
15
+ * `listStuckInvocations` until an operator resumes it.
16
+ */
17
+ export interface RestateRetry {
18
+ /** Default 100. */
19
+ initialIntervalMs?: number;
20
+ /** Default 30000. */
21
+ maxIntervalMs?: number;
22
+ /** Default 2. */
23
+ exponentiationFactor?: number;
24
+ /** Attempts, including the first, before pausing. Default 70. */
25
+ maxAttempts?: number;
26
+ }
27
+ export interface RestateExecutionOptions {
28
+ /** Restate ingress, e.g. `http://restate:8080`. */
29
+ ingressUrl: string;
30
+ /** Restate admin API, e.g. `http://restate:9070`. Needed by `start`. */
31
+ adminUrl: string;
32
+ /** Where `start` serves the Worker endpoint (HTTP/2 cleartext). */
33
+ workerListen?: {
34
+ host: string;
35
+ port: number;
36
+ };
37
+ /** The endpoint URL Restate calls, registered by `start`. */
38
+ workerAdvertisedUrl?: string;
39
+ /**
40
+ * Prepended to every service name, so several Runtimes (or test runs) can
41
+ * share one Restate server without taking each other's invocations.
42
+ * Letters, digits and `_` only. Default "".
43
+ */
44
+ servicePrefix?: string;
45
+ /**
46
+ * Request identity public keys (`publickeyv1_...`). When given, the Worker
47
+ * endpoint accepts only requests signed by a Restate server holding the
48
+ * matching private key.
49
+ */
50
+ identityKeys?: string[];
51
+ timeouts?: RestateTimeouts;
52
+ retry?: RestateRetry;
53
+ /** Delay between sweep passes of one Tenant. Default 5000. */
54
+ sweepIntervalMs?: number;
55
+ /**
56
+ * How long wakes with a `dedupeKey` are remembered. Default and minimum
57
+ * 24 hours (§12.3).
58
+ */
59
+ dedupeRetentionMs?: number;
60
+ /**
61
+ * Overwrite a deployment already registered at `workerAdvertisedUrl`, so a
62
+ * restarted Worker with changed code takes effect. Default true, which suits
63
+ * a stable URL on a developer machine. Rolling upgrades should advertise a
64
+ * versioned URL instead (§14.6).
65
+ */
66
+ forceRegistration?: boolean;
67
+ /** How long `start` keeps retrying registration while Restate comes up. Default 60000. */
68
+ registrationTimeoutMs?: number;
69
+ /** Replaces the SDK's console logging. */
70
+ logger?: (level: string, message: string) => void;
71
+ }
72
+ /** A Restate invocation that needs an operator: paused, or retrying after failures. */
73
+ export type { StuckInvocation };
74
+ export declare function createRestateExecution(options: RestateExecutionOptions): RestateExecution;
75
+ export declare class RestateExecution implements DurableExecution {
76
+ private readonly options;
77
+ private handlers?;
78
+ private stopping;
79
+ private server?;
80
+ private readonly sessions;
81
+ private readonly controllers;
82
+ private readonly inflight;
83
+ private readonly names;
84
+ private readonly ingressUrl;
85
+ private readonly adminUrl;
86
+ private readonly sweepIntervalMs;
87
+ constructor(options: RestateExecutionOptions);
88
+ /** Service names this execution registers, for diagnostics and tests. */
89
+ get serviceNames(): {
90
+ session: string;
91
+ tenant: string;
92
+ timer: string;
93
+ };
94
+ wake(tenantId: string, sessionId: string, wake: Wake): Promise<void>;
95
+ timer(tenantId: string, key: string, at: Date): Promise<void>;
96
+ armSweep(tenantId: string): Promise<void>;
97
+ disarmSweep(tenantId: string): Promise<void>;
98
+ /**
99
+ * Readiness: the admin API (`/health`), which `start` registers with, and the
100
+ * ingress (`/restate/health`), which every wake, timer and sweep goes
101
+ * through, both answer.
102
+ */
103
+ probe(signal: AbortSignal): Promise<void>;
104
+ /** This Runtime's paused or backing-off invocations for `tenantId` (Tenant status). */
105
+ stuckInvocations(tenantId: string): Promise<StuckInvocation[]>;
106
+ start(handlers: WorkerHandlers): Promise<void>;
107
+ stop(): Promise<void>;
108
+ private definitions;
109
+ /** Runs `advance` with a signal aborted by `stop` or by the end of the Restate attempt. */
110
+ private runAdvance;
111
+ /** Runs a Worker handler so that `stop` waits for it. Refuses once stopping; Restate retries. */
112
+ private runTracked;
113
+ private staleSweepMs;
114
+ private serviceOptions;
115
+ /** One-way send through the ingress. Retries while the ingress is unreachable or overloaded. */
116
+ private send;
117
+ /** Registers the Worker endpoint with the admin API, retrying until Restate is up. */
118
+ private register;
119
+ }
120
+ /**
121
+ * Lists invocations of this Runtime's services that need an operator: paused
122
+ * after exhausting retries, or backing off after a failure. Reads Restate's
123
+ * SQL introspection (`POST /query` on the admin API).
124
+ */
125
+ export declare function listStuckInvocations(options: {
126
+ adminUrl: string;
127
+ servicePrefix?: string;
128
+ tenantId?: string;
129
+ limit?: number;
130
+ }): Promise<StuckInvocation[]>;