withruntime 0.14.0 → 0.16.1

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 (62) hide show
  1. package/BLAXEL.md +97 -32
  2. package/COMPATIBILITY.md +120 -5
  3. package/DAYTONA.md +34 -3
  4. package/E2B.md +34 -5
  5. package/README.md +33 -0
  6. package/README.src.md +33 -0
  7. package/VERCEL.md +52 -5
  8. package/compatibility-lock.json +71 -111
  9. package/dist/blaxel/client.d.ts +11 -0
  10. package/dist/blaxel/client.js +28 -0
  11. package/dist/blaxel/errors.d.ts +65 -0
  12. package/dist/blaxel/errors.js +114 -0
  13. package/dist/blaxel/index.d.ts +10 -3
  14. package/dist/blaxel/index.js +23 -4
  15. package/dist/blaxel/preview.d.ts +29 -4
  16. package/dist/blaxel/preview.js +79 -5
  17. package/dist/blaxel/sandbox.js +1 -0
  18. package/dist/blaxel/session.js +4 -2
  19. package/dist/cli-extras.js +2 -1
  20. package/dist/cli-words.js +1 -0
  21. package/dist/cli.d.ts +1 -1
  22. package/dist/cli.js +61 -26
  23. package/dist/client.d.ts +1 -1
  24. package/dist/daytona/client.d.ts +4 -0
  25. package/dist/daytona/client.js +8 -3
  26. package/dist/daytona/daytona.d.ts +3 -0
  27. package/dist/daytona/daytona.js +2 -1
  28. package/dist/e2b/sandbox.d.ts +6 -5
  29. package/dist/e2b/sandbox.js +9 -12
  30. package/dist/freestyle/index.d.ts +77 -5
  31. package/dist/freestyle/index.js +380 -48
  32. package/dist/identity.js +63 -22
  33. package/dist/index.d.ts +2 -2
  34. package/dist/machine.d.ts +28 -13
  35. package/dist/machine.js +49 -15
  36. package/dist/mcp.js +16 -3
  37. package/dist/modal/index.d.ts +15 -0
  38. package/dist/modal/index.js +35 -7
  39. package/dist/morph/index.d.ts +255 -0
  40. package/dist/morph/index.js +641 -0
  41. package/dist/network-cli.js +2 -2
  42. package/dist/product-names.d.ts +2 -2
  43. package/dist/product-names.js +2 -2
  44. package/dist/products/limits.d.ts +16 -2
  45. package/dist/products/limits.js +2 -2
  46. package/dist/products/mcp.d.ts +5 -0
  47. package/dist/products/network-products.d.ts +21 -3
  48. package/dist/products/network-products.js +3 -1
  49. package/dist/products/previews.d.ts +6 -3
  50. package/dist/products/previews.js +1 -1
  51. package/dist/snapshots.d.ts +4 -0
  52. package/dist/ssh.d.ts +35 -0
  53. package/dist/ssh.js +93 -1
  54. package/dist/transport.d.ts +11 -8
  55. package/dist/transport.js +46 -12
  56. package/dist/types.d.ts +24 -0
  57. package/dist/vercel/command.d.ts +48 -1
  58. package/dist/vercel/command.js +237 -6
  59. package/dist/vercel/sandbox-user.js +2 -1
  60. package/dist/vercel/sandbox.d.ts +16 -2
  61. package/dist/vercel/sandbox.js +45 -2
  62. package/package.json +6 -1
package/BLAXEL.md CHANGED
@@ -11,8 +11,11 @@ import { SandboxInstance } from "withruntime/blaxel"; // was: from "@blaxel/core
11
11
  ```
12
12
 
13
13
  The mapping was written against `@blaxel/core` 0.3.24 and Blaxel's sandbox API
14
- source, checked 30 September 2026. Every name `@blaxel/core` exports can be
15
- imported: code that only mentions an agent, model or MCP helper still loads.
14
+ source, checked 30 September 2026, and checked against `@blaxel/core` 0.3.30
15
+ and `blaxel` 0.4.18 on PyPI on 16 October 2026 (below, "0.3.30 and 0.4.18").
16
+ The exact releases and artifact hashes are kept in `compatibility-lock.json`.
17
+ Every name `@blaxel/core` exports can be imported: code that only mentions an
18
+ agent, model or MCP helper still loads.
16
19
 
17
20
  ## Keys
18
21
 
@@ -84,35 +87,38 @@ name, or through `getByExternalId`, use the same Runtime key.
84
87
 
85
88
  ## Mapping
86
89
 
87
- | Blaxel | On Runtime |
88
- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
89
- | `SandboxInstance.create({ name, image, memory, labels, ports, envs, ... })` | `sandboxes.create`. A name another live sandbox holds is a 409, as in Blaxel; one held by a sandbox still being deleted is waited for. |
90
- | `createIfNotExists` | `create` with `getOrCreate`: Runtime settles two callers racing for one name, and both get the one sandbox. An existing sandbox is answered as it is. |
91
- | `get(name)`, `getByExternalId`, `list({ limit, externalId, showTerminated })` | The live sandbox with that name, or with the `externalId` label; Blaxel's paginated list (`data`, `nextPage`, `for await`, `autoPagingToArray`). |
92
- | `delete` (static and on the sandbox) | `stop`: the sandbox ends at once. Using that object afterwards is a 404. |
93
- | `metadata`, `spec`, `status`, `state`, `lastUsedAt`, `expiresIn` | From the Runtime sandbox and its `blaxel/` labels (image, memory, ports, region, TTL, expiry, lifecycle, archived), which any client reads; `state` is `STANDBY` while paused. |
94
- | `updateMetadata`, `updateTtl`, `updateLifecycle`, `updateNetwork` | Labels (the display name and `externalId` are labels); the paused retention, as at create; network rules. |
95
- | `archive`, `unarchive` | `pause`, `wake`. Runtime keeps memory and processes too, and the next call wakes it. |
96
- | `network: { allowedDomains, forbiddenDomains, proxy }` | Runtime network rules: `allow` and `deny`. |
97
- | `volumes: [{ name, mountPath }]` | The Runtime volume with that name, mounted read-write. |
98
- | `fetch(port, path, init)` | The request goes to a private Runtime preview of the port (made on first use, then reused) with its token. |
99
- | `process.exec` without `waitForCompletion` | One Runtime process, answered running. Its Blaxel name is kept in its command line, so `get("name")` finds it from any client. |
100
- | `process.exec({ waitForCompletion: true })` | One streamed call, answered with `status`, `exitCode`, `stdout`, `stderr` and `logs`. Past `timeout` the wait ends with a 422 and the process runs on. |
101
- | `onLog`, `onStdout`, `onStderr`, `streamLogs` | The process's output as it comes; `streamLogs` gives whole lines, as Blaxel's does. |
102
- | `process.get`, `wait`, `list`, `logs`, `stop`, `kill`, `writeStdin`, `closeStdin` | Runtime processes by id or name. `wait` follows output with one deadline covering lookup and output. Cancellation leaves the process running. `stop` is SIGTERM, `kill` SIGKILL. |
103
- | `keepAlive`, `timeout` | The sandbox does not pause for idleness while the process may run (its `timeout`, 600 s by default, 0 for as long as a lease allows); once no `keepAlive` process runs, it gets its idle pause back. |
104
- | `restartOnFailure`, `maxRestarts`, `waitForPorts`, `workingDir`, `env`, `stdin` | A restart loop in the same process, with Blaxel's note in the output (`restartCount` counts the notes); a wait in the sandbox for the ports; as in Blaxel. |
105
- | `fs.read`, `write`, `readBinary`, `writeBinary`, `writeTree`, `mkdir`, `rm`, `cp` | Runtime's files API, or one command. A path only root may read or write (outside `/workspace`, or made by a root process) goes through sudo, as Blaxel's root-owned API could. |
106
- | `fs.ls`, `find`, `grep`, `search` | One command each, with Blaxel's defaults, limits and excluded directories. `ls` reports owners. |
107
- | `fs.watch(path, callback, { withContent, ignore })`, `fs.download` | A Runtime watch (`path/**` for subdirectories); a download to the local disk. |
108
- | `previews.create`, `createIfNotExists`, `get`, `list`, `delete` | Runtime previews of `spec.port`, public or private. The Blaxel name is kept in a label, so any client finds it by name. |
109
- | `preview.tokens.create(expiresAt)` | A token for that long: at least a minute, at most a week. It is read from Blaxel's `X-Blaxel-Preview-Token` header or `?bl_preview_token=` as from Runtime's `x-runtime-preview-token` and `?runtime_preview_token=`, and never passed on to your server. |
110
- | `snapshots.create`, `list`, `get`, `delete`; `Snapshot.create`, `get`, `list`, `fork` | Runtime snapshots, kept 365 days: files, memory and running processes. |
111
- | `fork(name)`, `fork(name, { snapshotId, envs })` | A Runtime fork of the running sandbox, or a new sandbox from the snapshot (by id, or by name among this sandbox's); `envs` are added over the source's. |
112
- | `CodeInterpreter.create`, `runCode`, `createCodeContext` | Runtime's interpreter, with the same result classes. The sandbox's envs reach every context. |
113
- | `sandbox.sessions.create`, `createIfExpired`, `list`, `get`, `delete` | A Runtime sandbox session: a token for commands, files and previews of this one sandbox, for a day unless `expiresAt` says sooner (a day at most). `responseHeaders["Access-Control-Allow-Origin"]` names the pages that may use it; `*`, other response headers and `requestHeaders` are refused. `createIfExpired` reuses the session this process made last; a token is shown only when made. |
114
- | `SandboxInstance.fromSession(session)` | The sandbox, driven with the session's token alone; anything that manages the sandbox is refused. |
115
- | `ResponseError`, `SandboxGatewayError`, `isGatewayError`, `isGatewayTimeout` | Runtime's errors by Blaxel's names: `status` and `code` are the HTTP status; `runtimeCode`, `hint` and `requestId` are Runtime's. |
90
+ | Blaxel | On Runtime |
91
+ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
92
+ | `SandboxInstance.create({ name, image, memory, labels, ports, envs, ... })` | `sandboxes.create`. A name another live sandbox holds is a 409, as in Blaxel; one held by a sandbox still being deleted is waited for. |
93
+ | `createIfNotExists` | `create` with `getOrCreate`: Runtime settles two callers racing for one name, and both get the one sandbox. An existing sandbox is answered as it is. |
94
+ | `get(name)`, `getByExternalId`, `list({ limit, externalId, showTerminated })` | The live sandbox with that name, or with the `externalId` label; Blaxel's paginated list (`data`, `nextPage`, `for await`, `autoPagingToArray`). |
95
+ | `delete` (static and on the sandbox) | `stop`: the sandbox ends at once. Using that object afterwards is a 404. |
96
+ | `metadata`, `spec`, `status`, `state`, `lastUsedAt`, `expiresIn` | From the Runtime sandbox and its `blaxel/` labels (image, memory, ports, region, TTL, expiry, lifecycle, archived), which any client reads; `state` is `STANDBY` while paused. |
97
+ | `updateMetadata`, `updateTtl`, `updateLifecycle`, `updateNetwork` | Labels (the display name and `externalId` are labels); the paused retention, as at create; network rules. |
98
+ | `archive`, `unarchive` | `pause`, `wake`. Runtime keeps memory and processes too, and the next call wakes it. |
99
+ | `network: { allowedDomains, forbiddenDomains, proxy }` | Runtime network rules: `allow` and `deny`. |
100
+ | `volumes: [{ name, mountPath }]` | The Runtime volume with that name, mounted read-write. |
101
+ | `fetch(port, path, init)` | The request goes to a private Runtime preview of the port (made on first use, then reused) with its token. |
102
+ | `process.exec` without `waitForCompletion` | One Runtime process, answered running. Its Blaxel name is kept in its command line, so `get("name")` finds it from any client. |
103
+ | `process.exec({ waitForCompletion: true })` | One streamed call, answered with `status`, `exitCode`, `stdout`, `stderr` and `logs`. Past `timeout` the wait ends with a 422 and the process runs on. |
104
+ | `onLog`, `onStdout`, `onStderr`, `streamLogs` | The process's output as it comes; `streamLogs` gives whole lines, as Blaxel's does. |
105
+ | `process.get`, `wait`, `list`, `logs`, `stop`, `kill`, `writeStdin`, `closeStdin` | Runtime processes by id or name. `wait` follows output with one deadline covering lookup and output. Cancellation leaves the process running. `stop` is SIGTERM, `kill` SIGKILL. |
106
+ | `keepAlive`, `timeout` | The sandbox does not pause for idleness while the process may run (its `timeout`, 600 s by default, 0 for as long as a lease allows); once no `keepAlive` process runs, it gets its idle pause back. |
107
+ | `restartOnFailure`, `maxRestarts`, `waitForPorts`, `workingDir`, `env`, `stdin` | A restart loop in the same process, with Blaxel's note in the output (`restartCount` counts the notes); a wait in the sandbox for the ports; as in Blaxel. |
108
+ | `fs.read`, `write`, `readBinary`, `writeBinary`, `writeTree`, `mkdir`, `rm`, `cp` | Runtime's files API, or one command. A path only root may read or write (outside `/workspace`, or made by a root process) goes through sudo, as Blaxel's root-owned API could. |
109
+ | `fs.ls`, `find`, `grep`, `search` | One command each, with Blaxel's defaults, limits and excluded directories. `ls` reports owners. |
110
+ | `fs.watch(path, callback, { withContent, ignore })`, `fs.download` | A Runtime watch (`path/**` for subdirectories); a download to the local disk. |
111
+ | `previews.create`, `createIfNotExists`, `get`, `list`, `delete` | Runtime previews of `spec.port`, public or private. The Blaxel name is kept in a label, so any client finds it by name. The shorthand `{ port, name?, public? }` is a private `preview-<port>` unless it says otherwise; `createIfNotExists` answers an existing one as it is. |
112
+ | `preview.tokens.createIfExpired(expiresAt?, minValidity?)` | The token this call made last in this process for the sandbox's port, while it lasts `minValidity` more and ends by `expiresAt`; else a new one. Runtime keeps no list of tokens, so a new process makes a new one. |
113
+ | `isBlaxelError`, `getBlaxelErrorCode`, `getBlaxelErrorStatus`, `getBlaxelErrorMessage`, `getBlaxelErrorRequestId` | Blaxel's readers over the errors here. A `ResponseError`'s code is its HTTP status, as its `code` is; its request id is Runtime's. |
114
+ | `settings.integration`, `initialize({ integration })`, `BL_INTEGRATION` | Kept and checked as Blaxel does (`<name>/<semver>`, warned once and `""` otherwise); never sent, as Runtime does not attribute traffic by it. |
115
+ | `preview.tokens.create(expiresAt)` | A token for that long: at least a minute, at most a week. It is read from Blaxel's `X-Blaxel-Preview-Token` header or `?bl_preview_token=` as from Runtime's `x-runtime-preview-token` and `?runtime_preview_token=`, and never passed on to your server. |
116
+ | `snapshots.create`, `list`, `get`, `delete`; `Snapshot.create`, `get`, `list`, `fork` | Runtime snapshots, kept 365 days: files, memory and running processes. |
117
+ | `fork(name)`, `fork(name, { snapshotId, envs })` | A Runtime fork of the running sandbox, or a new sandbox from the snapshot (by id, or by name among this sandbox's); `envs` are added over the source's. |
118
+ | `CodeInterpreter.create`, `runCode`, `createCodeContext` | Runtime's interpreter, with the same result classes. The sandbox's envs reach every context. |
119
+ | `sandbox.sessions.create`, `createIfExpired`, `list`, `get`, `delete` | A Runtime sandbox session: a token for commands, files and previews of this one sandbox, for a day unless `expiresAt` says sooner (a day at most). `responseHeaders["Access-Control-Allow-Origin"]` names the pages that may use it; `*`, other response headers and `requestHeaders` are refused. `createIfExpired` reuses the session this process made last; a token is shown only when made. |
120
+ | `SandboxInstance.fromSession(session)` | The sandbox, driven with the session's token alone; anything that manages the sandbox is refused. |
121
+ | `ResponseError`, `SandboxGatewayError`, `isGatewayError`, `isGatewayTimeout` | Runtime's errors by Blaxel's names: `status` and `code` are the HTTP status; `runtimeCode`, `hint` and `requestId` are Runtime's. |
116
122
 
117
123
  ## Gaps
118
124
 
@@ -184,6 +190,65 @@ Some differences are not refusals:
184
190
  - A preview token shorter than a minute lasts a minute. Deleting one token
185
191
  revokes every token of that preview.
186
192
 
193
+ ## 0.3.30 and 0.4.18, 16 October 2026
194
+
195
+ Reviewed the published npm tarball of `@blaxel/core` 0.3.29 → 0.3.30 and the
196
+ PyPI wheel and sdist of `blaxel` 0.4.17 → 0.4.18, each its registry's latest
197
+ when checked. The pinned files matched `compatibility-lock.json`, the new ones
198
+ their registry's SHA-512 integrity or SHA-256 digest, and the wheel's source is
199
+ byte for byte its sdist's. They were compared file by file; nothing was
200
+ installed or run outside the oracle. The npm package's dependencies did not
201
+ change.
202
+
203
+ | Upstream change | Drop-in disposition |
204
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
205
+ | Workspace secrets, which Blaxel's proxy puts into a sandbox's routing as `{{SECRET:name}}`: the generated API calls `listSecrets`, `upsertSecret`, `deleteSecret`, `deleteSecretByQuery`; Python `SecretInstance`, `SyncSecretInstance` (`set`, `list`, `delete`), `SecretAPIError` and `blaxel.core.secret`. | Importable and refused with `NotSupportedError` naming Runtime secrets, `runtime.secrets.set(name, { value, hosts })`: a Runtime secret names the hosts it may reach, which Blaxel's calls do not, and the drop-in already refuses Blaxel's proxy routing. `SecretAPIError` is a `BlaxelError`, never raised. Before, the imports failed. |
206
+ | `deleteDriveFolder` in the generated API. | Importable and refused, as every drive call is. |
207
+ | The SDK sends an "Installed SDK" event to PostHog once per version (internal `common/posthog`, not exported). | Nothing to follow: the drop-in sends nothing to Blaxel or its analytics. |
208
+ | Custom domains' `validationMethod`, the `kernelExtensions` extra argument, and doc text (the 60 s floor of `ttl-idle`). | Nothing new to do: custom domains are refused, an extra argument other than `iptables` is refused, and the drop-in has no `ttl-idle` floor (a paused sandbox is kept whole days). |
209
+
210
+ `tests/blaxel/blaxel-0-3-30.test.ts` (2) and
211
+ `sdks/python/tests/test_blaxel_0_4_18.py` (2) fail without this change; the
212
+ export list moves to 0.3.30's 275 names. `compat-inventory.json`: blaxel 611
213
+ present, 123 refused, 31 missing of 765 before; 616, 123, 31 of 770 now.
214
+ blaxel-python 375, 11, 652 of 1038 before; 388, 11, 672 of 1071 now (the
215
+ inventory counts the Python stand-ins, as `ImageInstance` before them, as
216
+ missing).
217
+
218
+ ## 0.3.29 and 0.4.17, 15 October 2026
219
+
220
+ Reviewed the published npm tarball of `@blaxel/core` 0.3.25 → 0.3.29 and the
221
+ PyPI wheel and sdist of `blaxel` 0.4.13 → 0.4.17 (0.3.26 to 0.3.28 and 0.4.14
222
+ to 0.4.16 came out between, all on 13 October). Each was its registry's latest
223
+ when checked. The pinned files matched the hashes already in
224
+ `compatibility-lock.json`, the new ones their registry's SHA-512 integrity or
225
+ SHA-256 digest, and each wheel's Python source is byte for byte its sdist's.
226
+ They were compared file by file; nothing was installed or run outside the
227
+ oracle, which runs 0.3.29 and passes. The npm package's dependencies did not
228
+ change. Python's `withruntime.blaxel` follows the same changes under Python's
229
+ names: `BlaxelError`, `is_blaxel_error(err, code=None)`,
230
+ `SandboxPreviewCreateConfiguration`, `create_if_expired(expires_at=None,
231
+ min_validity=timedelta(hours=1))`, `settings.integration`.
232
+
233
+ | Upstream change | Drop-in disposition |
234
+ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
235
+ | Error helpers `isBlaxelError`, `getBlaxelErrorCode`, `getBlaxelErrorStatus`, `getBlaxelErrorMessage`, `getBlaxelErrorRequestId` and the error code and body types. Python: `BlaxelError` becomes the base of `ResponseError` and every `*APIError`, with `status`, `code`, `request_id`, `retryable` and the rest, and `is_blaxel_error`. | Followed. The helpers read the drop-in's errors with Blaxel's rules; a request id with no Blaxel header is Runtime's. In Python every API error the drop-in raises is a `BlaxelError`: `status` is the HTTP status, `code` Runtime's code, `request_id` Runtime's, `retryable` Runtime's own judgement; Blaxel's gateway fields are None. `VolumeAPIError` and `blaxel.core.errors` import. |
236
+ | `previews.create` and `createIfNotExists` take `{ port, name?, public? }` (Python: a dict or `SandboxPreviewCreateConfiguration`): a private `preview-<port>` by default, checked with `RangeError` (Python `ValueError`); an existing preview is answered as it is. | Followed, with Blaxel's checks and messages, before anything is shared. Before, the shorthand failed (`spec.port is required`, or a TypeError in `createIfNotExists`). |
237
+ | `preview.tokens.createIfExpired(expiresAt?, minValidity?)` reuses the latest listed token that lasts `minValidity` (an hour) more and ends by `expiresAt` (a day), else makes one; a public preview is refused. | Followed. Runtime keeps no list of the tokens it signs, so the token reused is the one this call made last in this process for the sandbox's port; arguments and the public refusal are Blaxel's, checked before any request. Revoking the preview's tokens (`tokens.delete`) forgets it. |
238
+ | `SandboxPreview.url`, `SandboxPreviewToken.name`. | Followed. |
239
+ | `settings.integration`, `Config.integration` and `BL_INTEGRATION`: a `<name>/<semver>` token appended to Blaxel's User-Agent. | Kept and checked as Blaxel does, warned once when invalid, never sent: it only attributes traffic to Blaxel. Before, `settings.integration` threw `NotSupportedError`. Python's `settings.user_agent` and other settings still raise `NotSupportedError`. |
240
+ | `fs.search` now sends its query (it was dropped). | Nothing to do: the drop-in's search always used it. |
241
+ | `ImageInstance` takes `buildMemory`, `buildVolume`, `buildRegion`; generated API clients gain `headFilesystemByPath`, service-account `role`, and doc text; Python's resource errors keep the response. | Nothing to follow: `ImageInstance` and the generated API calls stay refused with Runtime's alternative (`runtime.images`, `SandboxInstance`). Python's `ResponseError.from_api_response`, which wraps a generated-client response, now raises `NotSupportedError` saying so. |
242
+
243
+ `tests/blaxel/blaxel-0-3-29.test.ts` (9) and
244
+ `sdks/python/tests/test_blaxel_0_4_17.py` (9) fail without this change. The
245
+ export list moves to 0.3.29's 270 names. `compat-inventory.json`, regenerated
246
+ from the verified packages: blaxel 596 present, 123 refused, 31 missing before
247
+ (of 750); 611, 123, 31 now (of 765). blaxel-python 252, 9, 642 before (of
248
+ 903, 0.4.13 exported fewer names from `blaxel.core`); 375, 11, 652 now (of
249
+ 1038). The pinned-official Python tests (`RUNTIME_COMPAT_OFFICIAL=1`) were not
250
+ run against 0.4.17.
251
+
187
252
  ## The process line
188
253
 
189
254
  A process's command line, which both this package and the Python one write
@@ -207,7 +272,7 @@ leaves those names alone.
207
272
 
208
273
  `bun run test` in `packages/cloud-sdk` runs the unit tests against a fake of
209
274
  Runtime's SDK: `tests/blaxel`, including a check that every name
210
- `@blaxel/core` 0.3.24 exports is exported here.
275
+ `@blaxel/core` 0.3.30 exports is exported here.
211
276
 
212
277
  The end-to-end test runs Blaxel's guides, unmodified but for the import,
213
278
  against the real API: `tests/fixtures/blaxel-quickstart.mjs` (create, processes,
package/COMPATIBILITY.md CHANGED
@@ -14,19 +14,134 @@ interface for it. Python coverage is in the Python SDK's compatibility documents
14
14
  The Cloudflare module implements the 0.x `@cloudflare/sandbox` API. Version 1.0.0,
15
15
  published 30 September 2026, is a different package: it removes `getSandbox`, the
16
16
  `Sandbox` class, `exec`, processes, sessions and preview proxying, and keeps only
17
- `Files`, `S3Mount` and `DirectoryBackup` for the caller's own Durable Object. The
18
- pin stays 0.12.10; `compatibility-lock.json` records 1.0.0 as reviewed and
19
- unsupported, and `bun run compat:upstream` flags any other release.
17
+ `Files`, `S3Mount` and `DirectoryBackup` for the caller's own Durable Object.
18
+ Version 1.0.1 (13 October 2026) is the same API: its `dist/index.mjs` is byte for
19
+ byte 1.0.0's, its declarations export the same names inline instead of in one
20
+ list, its `zod` dependency moves from 4.5.4 to 4.6.5, and README example links
21
+ change. The pin stays 0.12.10; `compatibility-lock.json` records 1.0.0 and 1.0.1
22
+ as reviewed and unsupported, and `bun run compat:upstream` flags any other release.
20
23
 
21
24
  | Provider | Published package inspected | Runtime import | Implemented sandbox surface |
22
25
  | ----------- | --------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
23
26
  | Runloop | `@runloop/api-client` 2.0.0 | `withruntime/runloop` | `Runloop`, basic `RunloopSDK` command handles, devbox create/get/list/suspend/resume/shutdown, disk snapshots; synchronous and asynchronous commands, resident named shells with variables, functions, aliases, options and working directory, execution completion/output/stdin/signals, text files |
24
27
  | CodeSandbox | `@codesandbox/sdk` 2.4.2 | `withruntime/codesandbox` | `CodeSandbox`, `VMTier`, create/fork/resume/shutdown/restart/hibernate/delete/list/get; connected command and file clients; output/status subscriptions and same-client command restart; configured tasks and setup steps; public preview ports and readiness checks |
25
28
  | Fly Sprites | `@fly/sprites` 0.2.3 | `withruntime/sprites` | `SpritesClient`, create/lookup/list/delete/restart; `exec`, `execFile`, Node streams and event-based `spawn`; attachable native processes; binary/text/JSON files, directory traversal, append, chmod, chown and `asRoot` through sudo, file watches; preview access settings; checkpoints as disk snapshots; domain network policy; session kill; port watcher and port proxy; `APIError` with the vendor's limit codes |
26
- | Freestyle | `freestyle` 0.2.17 | `withruntime/freestyle` | `Freestyle`, VM create/ref/get/list/start/pause/delete/update; command execution, binary/text files and streams, filesystem metadata; native snapshots; explicit deny-all or outbound-public firewall intent |
27
- | Modal | `modal` 0.11.0 | `withruntime/modal` | `ModalClient`, app-name grouping, registry images and Dockerfile layers, CPU sandbox create/get/list/name lookup, text/binary process streams and stdin, command completion, filesystem transfer and metadata, tags, encrypted public previews, outbound allowlists, memory snapshot capture |
29
+ | Freestyle | `freestyle` 0.2.20 | `withruntime/freestyle` | `Freestyle`, VM create/ref/get/list/start/pause/delete/update; command execution, binary/text files and streams, filesystem metadata; native snapshots; explicit deny-all or outbound-public firewall intent |
30
+ | Morph | `morphcloud` 0.0.20 | `withruntime/morph` | `MorphCloudClient`, images list, snapshot create/get/list/delete/metadata and cached `setup` chains, instance start/boot/get/list/stop/pause/resume/branch/snapshot, metadata, wake-on, TTL at start, streamed exec, HTTP services as previews, file `sync` |
31
+ | Modal | `modal` 0.11.1 | `withruntime/modal` | `ModalClient`, app-name grouping, registry images and Dockerfile layers, CPU sandbox create/get/list/name lookup, text/binary process streams and stdin, command completion, filesystem transfer and metadata, tags, encrypted public previews, outbound allowlists, memory snapshot capture |
28
32
  | Cloudflare | `@cloudflare/sandbox` 0.12.10 (0.x API) | `withruntime/cloudflare` | `getSandbox`, named Runtime sandboxes, explicit execution sessions, text exec and SSE output, background processes, logs/signals/waits, binary/text files, recursive listings, environment updates, signed Runtime previews, conditional Worker Durable Object entry, Worker preview proxy, destruction |
29
33
 
34
+ ### Modal 0.11.1 review (16 October 2026)
35
+
36
+ The pin advances from 0.11.0 to 0.11.1; support remains partial. Both npm
37
+ tarballs were fetched into an empty directory, matched the lock (0.11.0) and
38
+ the registry (0.11.1), and were compared file by file without installing or
39
+ executing them. Only `package.json`, `README.md` and the four `dist` files
40
+ change; most of the declaration diff is generated protobuf types. The public
41
+ changes, and what `withruntime/modal` does with each:
42
+
43
+ - `sandboxes.fromName` and `experimentalFromName` take `includeTerminated`:
44
+ when no sandbox of that name runs, the most recent terminated one is
45
+ returned. Followed: a running sandbox of the name still wins, otherwise the
46
+ stopped one with the latest end time. Before, the option was refused as
47
+ unknown.
48
+ - `client.environments` (`EnvironmentService`, `EnvironmentObjectsService`,
49
+ `Environment`, `EnvironmentAppsService`) looks up, creates, lists and
50
+ deletes Modal Environments. Refused before any request, as the
51
+ `environment` options already are: a Runtime account's sandboxes share one
52
+ namespace, grouped by app name and tags.
53
+ - `App.info()` returns an App's lifecycle and its Functions and Servers.
54
+ Refused, naming `client.sandboxes.list({ appId })`: a Runtime app is a label
55
+ on its sandboxes, with no lifecycle, Functions or Servers.
56
+ - `volumes.fromName` takes a VolumeFS `version` (1 or 2). Refused when given:
57
+ a Runtime volume has one format.
58
+ - Sidecars take `includeOidcIdentityToken` and `proxy`; sidecars were already
59
+ refused as a whole. `functions.fromId`, `Function_.stats()`,
60
+ `Function_.metrics` (`FunctionMetricsManager`) and the deprecation of
61
+ `FunctionTimeoutError` for `FunctionCall.get` timeouts are Functions, outside
62
+ the CPU sandbox scope (`FunctionMetricsManager` joins the inventory's
63
+ outside list). Not followed, with nothing to follow: an internal `keys`
64
+ argument leaves `Secret`'s constructor, `execWait` and `Sandbox._wait` take
65
+ an internal abort signal, `smol-toml` moves from ^1.3.3 to ^1.9.0, and the
66
+ README links a sidecar identity-token example.
67
+
68
+ `tests/compat/modal-0-11-1.test.ts` fails on the old adapter;
69
+ `compat-inventory.json` records 221 present, 168 refused and 0 missing of 389.
70
+ `tests/compat/reference.bun.lock` records the new `smol-toml` range; it
71
+ already resolved 1.9.0, so the opt-in reference install is unchanged (not
72
+ rerun here).
73
+
74
+ ### Morph 0.0.20 (15 October 2026)
75
+
76
+ `morphcloud` 0.0.20 (npm, 6 October 2025, the latest) is the TypeScript SDK;
77
+ all 73 inventory items are present or refused, none missing. How it maps:
78
+
79
+ - An instance is a sandbox; a snapshot is a Runtime snapshot; metadata are
80
+ labels (`compat.provider` and `morph.*` stay the adapter's). `stop` deletes
81
+ the sandbox, as Morph's stop deletes the instance; snapshots stay.
82
+ - `snapshots.create` boots the image at its size, keeps its disk and deletes
83
+ the sandbox. `morphvm-minimal` is Runtime's default image; another id must
84
+ be a Runtime image. A digest becomes the snapshot's name (`morph-` and its
85
+ SHA-256), so `setup` caches by Morph's chain hash.
86
+ - `branch(n)` is one fork with the snapshot kept: copies keep memory and
87
+ running processes.
88
+ - `ttlSeconds` is the time limit (60 to 86400); `ttlAction` stop deletes,
89
+ pause pauses. Runtime also pauses an idle sandbox after a minute and wakes
90
+ it on the next request, which Morph does not.
91
+ - `exposeHttpService` is a preview: public with no `auth_mode` (needs a kept
92
+ top-up), private with `api_key` (send its token as `x-runtime-preview-token`).
93
+ - `exec` of a string or one-item array runs in a shell, a longer array as
94
+ arguments; 24 hours by default; a timeout throws as Morph's does.
95
+ - Refused, naming the alternative: `ssh`, `sshKey`, `sshKeyRotate` (use
96
+ `runtime sandboxes ssh`), `reboot`, `setTTL` after start, `sync` with
97
+ delete/dry run/.gitignore, and the raw `GET`/`POST`/`DELETE` verbs.
98
+ - `bun scripts/compatibility-morph-live.ts --run` runs the quickstart, setup
99
+ cache, HTTP service, pause and resume, branch and snapshot calls against the
100
+ real API.
101
+ - Morph's richer Python SDK (`morphcloud` 0.1.115, PyPI) has its own adapter,
102
+ `withruntime.morph`, inventoried as `morph-python`; see
103
+ [the Python document](../../sdks/python/COMPATIBILITY.md).
104
+
105
+ ### Freestyle 0.2.18, 0.2.19 and 0.2.20 review (15 October 2026)
106
+
107
+ The pin advances from 0.2.17 to 0.2.20; support remains partial. The four npm
108
+ tarballs were fetched into an empty directory, matched the lock (0.2.17) and
109
+ the registry (the rest), and were compared file by file without installing or
110
+ executing them.
111
+
112
+ - 0.2.18, PTY connections. `open` and `attach` take `reconnect` (`true` or
113
+ `timeoutMs`, `initialDelayMs`, `maxDelayMs`), `connectTimeoutMs`,
114
+ `onStateChange`, `onReplayStart` and `onReplayEnd`, and check the timers
115
+ with a `RangeError`; `PtySession` gains `ready`, `state` and `reconnect()`;
116
+ `write` and `signal` throw `PTY is not connected` while disconnected and
117
+ `resize` is remembered and applied again after a reattachment; `detach`
118
+ cancels recovery and reports `Detached` once. Before, the adapter refused
119
+ each new option with `CompatibilityError`. Now a dropped connection is
120
+ reattached to the same Runtime process with Freestyle's backoff, after
121
+ checking the process still exists (a 4xx other than 409 or 429 ends the
122
+ session), and nothing typed is replayed. A Runtime terminal replays the
123
+ session's output from its start on each connection without marking where
124
+ the replay ends, as Freestyle's older guest agents do, so the replay
125
+ callbacks never fire and a replay begins at the `connected` state. Runtime
126
+ terminals send no keepalive, so a silent connection is not timed out; the
127
+ browser's online and visibility events retry a closed session. A first
128
+ connection waits `connectTimeoutMs` only when given (no wait limit before).
129
+ - 0.2.18, new `connectXterm({ pty, terminal, slug, ... })` and the
130
+ `XtermTerminal` and `ConnectXtermOptions` types: implemented on the same
131
+ sessions, with reconnect on by default, the screen reset at each
132
+ connection, and the replay's terminal queries muted until it is written.
133
+ - 0.2.18, browser PTYs now need an identity access token (a WebSocket
134
+ subprotocol). Identity tokens are refused here; Runtime terminals
135
+ authenticate with the Runtime key. `@xterm/xterm` is a new dev dependency
136
+ only, so the reference install is unchanged.
137
+ - 0.2.18, `PtySessionInfo.slug` is now documented as kept after the shell
138
+ exits, until the session is closed (`open`'s get-or-create doc already
139
+ said so). Not followed: Runtime keeps exited processes and cannot remove
140
+ one, so a slug kept after exit could never be opened afresh. A slug is
141
+ still released when its shell exits.
142
+ - 0.2.19 changes only its version. 0.2.20 adds `expiresAt` to identity access
143
+ tokens, in the identities product this adapter does not provide.
144
+
30
145
  ### Freestyle 0.2.17 review (11 October 2026)
31
146
 
32
147
  The pin advances from 0.2.16; support remains partial. The exact npm tarballs
package/DAYTONA.md CHANGED
@@ -17,8 +17,8 @@ from withruntime.daytona import AsyncDaytona # was: from daytona import AsyncDa
17
17
  ```
18
18
 
19
19
  The mapping was written against `@daytona/sdk` 0.220.0 and `daytona` 0.220.0
20
- on PyPI, and checked against `@daytona/sdk` and `daytona` 0.223.1 on
21
- 9 October 2026 (below, "0.223.1"). The exact releases and artifact hashes
20
+ on PyPI, and checked against `@daytona/sdk` and `daytona` 0.224.1 on
21
+ 15 October 2026 (below, "0.224.1"). The exact releases and artifact hashes
22
22
  are kept in `compatibility-lock.json`.
23
23
 
24
24
  ## Keys
@@ -97,7 +97,7 @@ Each of these throws `NotSupportedError` before anything happens. Its
97
97
  | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
98
98
  | A snapshot name with no Runtime image or snapshot | `daytona.snapshot.create({ name, image })` here, or `npx withruntime images build`. This throws `DaytonaNotFoundError`. |
99
99
  | GPUs, `spot`, `linkedSandbox`, `secrets`, `otelEndpointOverride` | Runtime runs Linux on CPUs. For `secrets`, a Runtime secret (`npx withruntime secrets set NAME --host <host>`): the sandbox sees a placeholder. For telemetry, `runtime.otel.create()`. |
100
- | A `target` other than `us`, `jwtToken` | Runtime runs in one US region and signs in with keys. |
100
+ | A `target` other than `us` (the client's or a create's), `jwtToken` | Runtime runs in one US region and signs in with keys. |
101
101
  | The entrypoint session, language servers | Sessions with `runAsync`. |
102
102
  | Screenshots of a region, with the cursor, scaled, or as WebP | The whole screen as PNG or JPEG; crop and scale it yourself. |
103
103
  | `computerUse.accessibility`, the desktop's processes one by one | Screenshots with the mouse and keyboard; `computerUse.getStatus()`, `stop()` and `start()`. |
@@ -126,6 +126,37 @@ Some differences are not refusals:
126
126
  - `autoArchiveInterval` is recorded only: Runtime has no archive tier.
127
127
  - Runtime's stock image is Ubuntu 24.04 with Python 3.12, Node.js 24 and Bun.
128
128
 
129
+ ## 0.224.1, 15 October 2026
130
+
131
+ Reviewed the published npm tarballs for `@daytona/sdk`, `@daytona/api-client`,
132
+ `@daytona/toolbox-api-client` and `@daytona/analytics-api-client` 0.223.1 →
133
+ 0.224.1, and the PyPI wheel and sdist for `daytona` 0.223.1 → 0.224.1 (0.224.0,
134
+ published between them, was also fetched: on npm, 0.224.1 adds only the stream
135
+ decoder change and the dependency floors below; on PyPI it is the same source
136
+ with a new version). Each was its registry's latest when checked. Every pinned
137
+ file matched the hash already in `compatibility-lock.json`, and every new file
138
+ matched its registry's SHA-512 integrity or SHA-256 digest; the wheel's Python
139
+ source is byte for byte its sdist's. Nothing was installed, imported or run.
140
+ The three API clients changed only their version. `@daytona/sdk` changed
141
+ `Daytona` (create params and the client's `target` docs), `Snapshot` (docs),
142
+ and its output stream decoder, ESM and CommonJS alike; `daytona` changed the
143
+ same, sync and async, plus the async PTY handle.
144
+
145
+ | Upstream change | Drop-in disposition |
146
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147
+ | `daytona.create({ target })` (Python `target` on `CreateSandboxFromSnapshotParams` and `CreateSandboxFromImageParams`) picks the region for that create, over the client's `target`. | Followed, in both languages. `"us"` or none creates the sandbox in Runtime's one region; any other is refused with the same `NotSupportedError` as a client `target`, before anything is built or made. Before, TypeScript dropped it without a word and Python raised `TypeError`. |
148
+ | The client's `target` (and `DAYTONA_TARGET`) and a snapshot's `regionId` (Python `region_id`) are documented as the default region, overridden per call. | Documentation only; the client's `target` is checked as before. TypeScript already refused a snapshot `regionId`; Python accepted `region_id` and dropped it, and now refuses it the same way (`""` still means the default). |
149
+ | The output stream decoder finds an stdout or stderr marker that ends exactly at the end of a message, which it held back before, and buffers in linear time. | Not applicable: the drop-in takes output from Runtime's exec, which keeps stdout and stderr apart, and never parses Daytona's markers. |
150
+ | Python `AsyncPtyHandle.wait()` shields its reader, so cancelling a caller's wait (for example `asyncio.wait_for`) leaves the PTY connected. | Already so: the drop-in's `wait()` awaits `asyncio.shield` of its reader task. |
151
+ | `@daytona/sdk` requires `ws` exactly 8.22.0 (was ^8.22.0), `@aws-sdk/client-s3` and `lib-storage` ^3.1146.0 and `shell-quote` ^1.12.0. | The oracle's `bun.lock` moves with them (ws stays 8.22.0). |
152
+
153
+ `tests/daytona/daytona-0-224-1.test.ts` and
154
+ `sdks/python/tests/test_daytona_0_224_1.py` check a create's `target` both
155
+ ways, that it overrides the client's, and (Python) that a snapshot's
156
+ `region_id` is refused; they fail without this change. The oracle was not run
157
+ against the new release, since it executes Daytona's code; the provider
158
+ remains marked `partial`.
159
+
129
160
  ## 0.223.1, 9 October 2026
130
161
 
131
162
  Reviewed the published npm tarballs for `@daytona/sdk`, `@daytona/api-client`,
package/E2B.md CHANGED
@@ -20,9 +20,9 @@ from withruntime.e2b import Sandbox # was: from e2b import Sandbox
20
20
  from withruntime.e2b.code_interpreter import Sandbox # was: from e2b_code_interpreter import Sandbox
21
21
  ```
22
22
 
23
- The mapping was written against `e2b` 2.51.0 and checked against `e2b` 2.55.0
24
- and `@e2b/code-interpreter` 2.8.3 on 9 October 2026. Python was checked
25
- against `e2b` 2.55.1 and `e2b-code-interpreter` 2.10.5 the same day. The exact
23
+ The mapping was written against `e2b` 2.51.0 and checked against `e2b` 2.56.0
24
+ and `@e2b/code-interpreter` 2.9.0 on 15 October 2026. Python was checked
25
+ against `e2b` 2.56.0 and `e2b-code-interpreter` 2.11.0 the same day. The exact
26
26
  package releases and artifact hashes are kept in `compatibility-lock.json`.
27
27
 
28
28
  ## Keys
@@ -111,7 +111,7 @@ account the key belongs to and where the key came from.
111
111
  | Relative paths | Resolved against the home directory, `/workspace` on Runtime, and given back under `/home/user`, as E2B gives them: `write("a.txt")` returns `/home/user/a.txt`. A path given in full comes back as given. `pwd` in a command prints `/workspace`. |
112
112
  | `/home/user` (E2B's home) | The first time a path, `cwd` or command names it, it becomes a link to `/workspace`, unless something is already there. |
113
113
  | `sandbox.kill()`, `Sandbox.kill(id)` | `delete`: gone for good. `false` when the sandbox was not found or was already deleted. |
114
- | `sandbox.setTimeout(ms)`, `Sandbox.setTimeout(id, ms)` | `extend`: the end moves to now + ms, up to 24 hours. An earlier end is refused: Runtime cannot bring a time limit forward. A sandbox with no time limit (a pilot's) has no end to move, and nothing changes. |
114
+ | `sandbox.setTimeout(ms)`, `Sandbox.setTimeout(id, ms)` | The sandbox's time limit becomes now + ms, sooner or later than before, up to 24 hours (an update's `timeoutSeconds`; under a minute is a minute), and its end still does what it was created to. A sandbox with no time limit gets one; a persistent one (a pilot's) has none to set, and nothing changes. |
115
115
  | `Sandbox.connect(id, { timeoutMs })`, `sandbox.connect()` | `get`. A paused sandbox is woken. A running one's end moves later, never earlier, up to 24 hours. An ended one throws `SandboxNotFoundError`. |
116
116
  | `sandbox.pause()`, `betaPause`, `Sandbox.pause(id)` | `pause`, keeping memory and files. `false` when it was already paused. |
117
117
  | `getInfo`, `isRunning` | `get`. `templateId` is the template the sandbox was created from, as you named it (kept in the label `e2b-template`, which `metadata` leaves out), or `base`. `envdVersion` is `runtime`. A sandbox Runtime paused for being idle is `running`. `endAt` is when it ends by itself; one that never will (no time limit, as a pilot's) reads 24 hours ahead, the furthest E2B allows. |
@@ -134,7 +134,6 @@ before anything happens. The error's `feature` names the gap and its
134
134
  | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
135
135
  | An E2B template name with no Runtime image of that name | Build it: `npx withruntime images build --dockerfile e2b.Dockerfile --name <template>`. This throws `TemplateError`. |
136
136
  | `Template`, `waitForPort` and the other ready checks | `runtime.images.build(...)` |
137
- | `setTimeout` to an earlier time | `kill()` when the work is done. |
138
137
  | A pause with `mode: "filesystem"` or `keepMemory: false` | Runtime's pause keeps memory. For the files alone, `createSnapshot({ mode: "filesystem" })`. |
139
138
  | `onResume: "reboot"` | Stop the sandbox and create a new one. |
140
139
  | `fork({ timeoutMs })` | Fork without it, then call `setTimeout` on each fork. |
@@ -260,3 +259,33 @@ source files changed, one was removed, and one interpreter file changed.
260
259
  modes, the refusals, their messages and the new exports; they fail without
261
260
  this change. The official differential contracts were not run against the new
262
261
  releases, since they execute E2B's code; the provider remains marked `partial`.
262
+
263
+ ## e2b 2.56.0, 15 October 2026
264
+
265
+ Reviewed the published npm tarballs for `e2b` 2.55.0 → 2.56.0 and
266
+ `@e2b/code-interpreter` 2.8.3 → 2.9.0, and the PyPI wheels and sdists for
267
+ `e2b` 2.55.1 → 2.56.0 and `e2b-code-interpreter` 2.10.5 → 2.11.0. Each was
268
+ npm's or PyPI's latest when checked. Every pinned file matched the hash already
269
+ in `compatibility-lock.json`, and every new file matched its registry's SHA-512
270
+ integrity or SHA-256 digest; each wheel's Python source is byte for byte its
271
+ sdist's. Nothing was installed, imported or run for the review. JavaScript
272
+ sources were read from the source maps. The declarations (`index.d.ts`) of
273
+ both npm packages and the `__init__.py` of both Python packages are byte for
274
+ byte unchanged, so the public surface is the same: the recomputed
275
+ `compat-inventory.json` has the same items, only the upstream paths move.
276
+
277
+ | Upstream change | Drop-in disposition |
278
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
279
+ | JavaScript: the process-wide in-flight request caps are removed (`src/api/inflight.ts` and the `E2B_API_INFLIGHT_REQUESTS`, `E2B_ENVD_INFLIGHT_REQUESTS`, `E2B_ENVD_RPC_INFLIGHT_REQUESTS` variables, which threw on a negative value). Requests are bounded by undici's connections only. | No change: the drop-in never read these variables. Its own connection cap (`E2B_MAX_CONNECTIONS` in `src/e2b/client.ts`, 4096) is Runtime's and unchanged. |
280
+ | JavaScript: `undici` 8.11.2 becomes the only undici (the `undici8` alias and the undici 7 fallback are gone); below Node 22.19 the global `fetch` is used. `engines.node` is now `>=22.19.0`, `@e2b/dockerfile-utils` `^0.1.1` (0.1.1 changes only its own version and engines). | Not mirrored: the drop-in uses Runtime's transport and keeps `node >=22.12`. The oracle lock moves to `e2b` 2.56.0 with `undici` 8.11.2 and `@e2b/dockerfile-utils` 0.1.1. |
281
+ | Python: the per-origin `ConnectionBalancer` over several pyqwest pools is replaced by one pool with `max_connections_per_address` (pyqwest `>=0.12,<0.13`); `E2B_STREAMS_PER_CONNECTION` is no longer read, and `E2B_MAX_CONNECTIONS` caps connections per resolved address. | No change: `e2b.api` and its clients are E2B's HTTP internals, which the drop-in leaves out; its connection limit is Runtime's own. |
282
+ | Python: `e2b` and `e2b-code-interpreter` require Python 3.11 (`sandbox/mcp.py` imports `NotRequired` from `typing`). | Not followed: `withruntime` keeps Python 3.10, so code moved off E2B on 3.10 keeps working. The official contracts install the new wheels, so that step runs on Python 3.11 (`prepare_compatibility.py` moves to a Python 3.11 or newer on the PATH when run under 3.10, as in CI). |
283
+ | `@e2b/code-interpreter` 2.9.0 and `e2b-code-interpreter` 2.11.0 change only their versions, dependency floors (`e2b ^2.56.0`) and engines. | Note only. |
284
+
285
+ No behaviour changed that the drop-ins mirror, so there is no new behaviour
286
+ test; `tests/e2b/exports.test.ts` and `sdks/python/tests/test_e2b_exports.py`
287
+ now name the new releases, whose export lists are the same. The oracle
288
+ (`oracle/check.mjs`, 37 passed) ran against `e2b` 2.56.0 and
289
+ `@e2b/code-interpreter` 2.9.0, and the Python official contracts (18 passed)
290
+ against the new wheels in an isolated virtualenv on Python 3.11 and 3.12. The
291
+ provider remains marked `partial`.
package/README.md CHANGED
@@ -147,6 +147,21 @@ with its token. A Blaxel key is never sent anywhere. Drives, codegen, schedules
147
147
  `NotSupportedError` before anything happens, naming what to use instead.
148
148
  `BLAXEL.md` in this package lists every mapping and gap.
149
149
 
150
+ ## Code written for Morph Cloud
151
+
152
+ `withruntime/morph` translates Morph's TypeScript client (`morphcloud`).
153
+ Change the import:
154
+
155
+ ```ts no-run
156
+ import { MorphCloudClient } from "withruntime/morph"; // was: from "morphcloud"
157
+ ```
158
+
159
+ Instances become sandboxes, snapshots Runtime snapshots, metadata labels and
160
+ HTTP services previews; `setup` caches by Morph's chain hash and `branch`
161
+ copies memory and processes. `stop` deletes the sandbox, as Morph's does.
162
+ SSH, reboot and a time limit set after start throw `CompatibilityError`
163
+ naming the alternative. `COMPATIBILITY.md` lists every mapping.
164
+
150
165
  ## Agent frameworks
151
166
 
152
167
  `withruntime/openai-agents` is a sandbox client for the OpenAI Agents SDK's
@@ -183,6 +198,24 @@ connected yet, it offers `runtime_connect`, which walks you through the browser
183
198
  approval. Remote clients add `https://api.withruntime.com/mcp` and sign in through
184
199
  the browser, or send a bearer key.
185
200
 
201
+ ## How Runtime compares
202
+
203
+ For typical agent work, Runtime costs 42% to 88% less than fourteen other
204
+ sandbox providers at their published rates. These pages show the arithmetic,
205
+ each with the rates it used and the date they were read:
206
+
207
+ - [Best sandbox for AI agents](https://withruntime.com/compare/best-sandbox-for-ai-agents)
208
+ - Alternatives to [E2B](https://withruntime.com/compare/e2b-alternatives),
209
+ [Daytona](https://withruntime.com/compare/daytona-alternatives),
210
+ [Modal](https://withruntime.com/compare/modal-alternatives) and
211
+ [Vercel Sandbox](https://withruntime.com/compare/vercel-sandbox-alternatives)
212
+ - [E2B vs Daytona](https://withruntime.com/compare/e2b-vs-daytona), and
213
+ [every comparison](https://withruntime.com/compare)
214
+ - [The agent sandbox price index](https://withruntime.com/pricing/agent-sandbox-price-index):
215
+ every provider's rates, also as CSV and JSON
216
+ - [Sandbox cost calculator](https://withruntime.com/calculators/sandbox-cost-calculator)
217
+ and [Runtime's pricing](https://withruntime.com/pricing)
218
+
186
219
  ## Reliability and support
187
220
 
188
221
  - **Status:** https://withruntime.com/status checks the API from outside every