withruntime 0.11.1 → 0.11.2

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 (53) hide show
  1. package/BLAXEL.md +1 -1
  2. package/DAYTONA.md +1 -1
  3. package/E2B.md +57 -29
  4. package/README.md +4 -3
  5. package/README.src.md +4 -3
  6. package/compatibility-lock.json +14 -14
  7. package/dist/blaxel/errors.js +4 -4
  8. package/dist/blaxel/sandbox.d.ts +1 -2
  9. package/dist/blaxel/sandbox.js +1 -2
  10. package/dist/cli.d.ts +1 -1
  11. package/dist/cli.js +63 -15
  12. package/dist/client.d.ts +11 -59
  13. package/dist/client.js +8 -113
  14. package/dist/daytona/daytona.d.ts +1 -2
  15. package/dist/daytona/daytona.js +1 -2
  16. package/dist/daytona/sandbox.d.ts +1 -1
  17. package/dist/daytona/sandbox.js +1 -1
  18. package/dist/e2b/client.d.ts +15 -2
  19. package/dist/e2b/client.js +61 -7
  20. package/dist/e2b/commands.d.ts +3 -0
  21. package/dist/e2b/commands.js +16 -5
  22. package/dist/e2b/errors.d.ts +26 -2
  23. package/dist/e2b/errors.js +38 -5
  24. package/dist/e2b/filesystem.d.ts +1 -1
  25. package/dist/e2b/filesystem.js +82 -16
  26. package/dist/e2b/index.d.ts +2 -2
  27. package/dist/e2b/index.js +2 -2
  28. package/dist/e2b/sandbox.d.ts +23 -14
  29. package/dist/e2b/sandbox.js +195 -178
  30. package/dist/e2b/unsupported.d.ts +19 -0
  31. package/dist/e2b/unsupported.js +21 -0
  32. package/dist/e2b/users.d.ts +9 -0
  33. package/dist/e2b/users.js +22 -0
  34. package/dist/errors.d.ts +4 -4
  35. package/dist/errors.js +12 -10
  36. package/dist/machine.d.ts +180 -0
  37. package/dist/machine.js +504 -0
  38. package/dist/openai-agents/index.d.ts +1 -1
  39. package/dist/openai-agents/index.js +1 -1
  40. package/dist/products/jobs.d.ts +2 -3
  41. package/dist/products/jobs.js +1 -2
  42. package/dist/products/limits.d.ts +4 -10
  43. package/dist/products/network.d.ts +1 -1
  44. package/dist/products/secrets.d.ts +1 -1
  45. package/dist/products/switching.d.ts +2 -3
  46. package/dist/sandbox.d.ts +7 -92
  47. package/dist/sandbox.js +8 -362
  48. package/dist/transport.d.ts +4 -2
  49. package/dist/transport.js +6 -4
  50. package/dist/types.d.ts +53 -8
  51. package/dist/vercel/sandbox.d.ts +1 -2
  52. package/dist/vercel/sandbox.js +1 -2
  53. package/package.json +1 -1
package/BLAXEL.md CHANGED
@@ -34,7 +34,7 @@ name, or through `getByExternalId`, use the same Runtime key.
34
34
  - **Machine:** Blaxel's default of 4096 MB. vCPUs follow Blaxel's rule of one
35
35
  per 2048 MB (at least one, at most 16): 2 for the default, 4 for 8192 MB. A
36
36
  trial sandbox has at most 4096 MB (2 vCPUs); `memory: 8192` or more needs
37
- prepaid credit, and on the trial is refused with a 400 (`invalid_trial`)
37
+ prepaid credit, and on the trial is refused with a 400 (`no_credit_size_limit`)
38
38
  saying so.
39
39
  - **Image:** Blaxel's `base-image`, `py-app`, `ts-app`, `node`,
40
40
  `docker-in-sandbox` and `jupyter-server` are Runtime's stock image (Ubuntu
package/DAYTONA.md CHANGED
@@ -17,7 +17,7 @@ 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, checked 29 September 2026. The exact releases and artifact hashes
20
+ on PyPI, and checked against `@daytona/sdk` 0.222.0 on 5 October 2026. The exact releases and artifact hashes
21
21
  are kept in `compatibility-lock.json`.
22
22
 
23
23
  ## Keys
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.52.0
24
- and `@e2b/code-interpreter` 2.8.0 (Python: `e2b` 2.52.0, `e2b-code-interpreter`
25
- 2.10.1) on 2 October 2026. The exact package releases and artifact hashes are kept in
23
+ The mapping was written against `e2b` 2.51.0 and checked against `e2b` 2.52.1
24
+ and `@e2b/code-interpreter` 2.8.0 (Python: `e2b` 2.52.1, `e2b-code-interpreter`
25
+ 2.10.1) on 5 October 2026. The exact package releases and artifact hashes are kept in
26
26
  `compatibility-lock.json`.
27
27
 
28
28
  ## Keys
@@ -30,30 +30,54 @@ and `@e2b/code-interpreter` 2.8.0 (Python: `e2b` 2.52.0, `e2b-code-interpreter`
30
30
  The package uses, in order: an `apiKey` you pass, `RUNTIME_API_KEY`, a Runtime
31
31
  key left in `E2B_API_KEY`, and the key `npx withruntime login` saved on this
32
32
  machine. An E2B key (`e2b_...`) is never sent anywhere. If one is passed as
33
- `apiKey` and `RUNTIME_API_KEY` is not set, the call fails with
34
- `AuthenticationError`.
33
+ `apiKey`, or left in `E2B_API_KEY`, and `RUNTIME_API_KEY` is not set, the call
34
+ fails with `AuthenticationError` (Python: `AuthenticationException`) saying
35
+ so, rather than fall back to a saved login that may be another account's.
36
+ When `RUNTIME_API_KEY` and `E2B_API_KEY` hold two different Runtime keys, which
37
+ may be two accounts, a warning says so once (`RUNTIME_E2B_TWO_KEYS`; Python: a
38
+ `RuntimeWarning`). A template with no image of its name fails naming the
39
+ account the key belongs to and where the key came from.
35
40
 
36
41
  ## What a sandbox gets
37
42
 
38
43
  - **Machine:** E2B's default, 2 vCPU and 512 MiB. For another, pass
39
44
  `runtime: { create: { memoryMiB: 4096 } }` (Python:
40
45
  `runtime_create={"memory_mib": 4096}`).
41
- - **Timeout:** E2B's default of 300 seconds. When it ends, the sandbox is
42
- stopped, as E2B kills it. `lifecycle: { onTimeout: "pause" }` pauses it
43
- instead.
46
+ - **Timeout:** kept by Runtime's server, never by a timer in your process,
47
+ so it holds after the process that made the sandbox exits. A `timeoutMs`
48
+ you give (Python `timeout`, seconds), up to 24 hours, deletes the sandbox
49
+ when it runs out, as E2B kills it; so does `lifecycle: { onTimeout: "kill" }`.
50
+ With no timeout, E2B's default of 300 seconds applies, and when it runs out
51
+ the sandbox **pauses** instead: nobody asked for it to end, so nothing is
52
+ lost, and the next call wakes it. E2B deletes it at that point.
53
+ `lifecycle: { onTimeout: "pause" }` pauses at any timeout.
54
+ - **What a pause keeps, and costs:** memory, files and running processes, for
55
+ as long as the account has credit, billed as paused storage by the GB a
56
+ month for what the sandbox alone holds (`pricing.md`, "Paused storage").
57
+ Sandboxes created with no timeout and never killed pile up as paused
58
+ storage: call `kill()` when the work is done, or give a `timeoutMs`.
59
+ - **On a pilot account:** the server keeps every sandbox running until you
60
+ end it, with no idle pause, whatever `timeoutMs` says, and machine size is
61
+ the pilot's. `kill()` deletes it.
62
+ - **Kill:** `kill()` deletes the sandbox for good, as E2B's does: its disk,
63
+ memory and shared ports go, and it no longer counts against the account's
64
+ sandboxes.
44
65
  - **Idle pause:** Runtime's default, which E2B does not have. After 60
45
66
  seconds with nothing happening in it (no request, running command, open
46
67
  connection, traffic or CPU use) the sandbox pauses with its memory kept, and
47
- the next command or file call wakes it. While it is paused, `isRunning()`
48
- is `false` and `getInfo()` says `paused`, so code that reads either as
49
- "the sandbox is gone" should not. Pass
68
+ the next command or file call wakes it. To code written for E2B it is still
69
+ running: `isRunning()` is `true`, `getInfo()` says `running` and
70
+ `list({ query: { state: ["running"] } })` includes it. Pass
50
71
  `runtime: { create: { idlePauseSeconds: 0 } }` (Python:
51
72
  `runtime_create={"idle_pause_seconds": 0}`) to keep it running, as on E2B.
52
- - **Connections:** one client per key, holding at most 48 connections to the
53
- API at once, since one address may hold 64. Each command being run holds
54
- one while its output is read, and 8 are kept for other calls, so past 40
55
- commands at once from one process the rest wait their turn. Pass your own
56
- client with `runtime: { client: new Runtime({ maxConnections }) }` (Python:
73
+ - **Connections:** one client per key, holding up to 4,096 connections to
74
+ the API at once, the most Runtime's edge gives an address that has used a
75
+ valid key. E2B's SDK holds no call back, and neither does this one: a
76
+ thousand commands at once from one process all run at once. Past an
77
+ account's room the API answers with a retry, which the client waits out. If
78
+ calls ever wait for a connection, a warning says so once
79
+ (`RUNTIME_E2B_QUEUED`). Runtime's own SDK keeps 48; pass your own client
80
+ with `runtime: { client: new Runtime({ maxConnections }) }` (Python:
57
81
  `client=Runtime(max_connections=...)`).
58
82
  - **Funding:** left to Runtime, as `withruntime`'s own `create()` does. The
59
83
  free trial is used while the account has trial time, then prepaid credit.
@@ -67,30 +91,30 @@ machine. An E2B key (`e2b_...`) is never sent anywhere. If one is passed as
67
91
 
68
92
  | E2B | On Runtime |
69
93
  | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
70
- | `Sandbox.create()`, `Sandbox.create(template, opts)` | `sandboxes.create`. `base` and `code-interpreter-v1` are Runtime's stock image. Any other name must be a ready Runtime image with that name. A UUID is an image or a snapshot. |
71
- | `timeoutMs` (Python `timeout`, seconds) | Left out, the sandbox has no time limit: it runs while it works and pauses itself when idle. Given, it is `timeoutSeconds`, rounded up. Under 60 s becomes 60 s, with a warning. Up to 24 hours, as on E2B: a Runtime time limit reaches at most an hour ahead, so while this process runs the adapter extends it every five minutes, never past the end asked for. If the process ends first, the sandbox ends at its last limit, at most an hour later. Over 24 hours throws `InvalidArgumentError`. |
94
+ | `Sandbox.create()`, `Sandbox.create(template, opts)` | `sandboxes.create`. `base` and `code-interpreter-v1` are Runtime's stock image. Any other name, with its `:tag`, is a Runtime image of that name, resolved by the create itself; E2B's `team/` prefix is dropped, since an account's images are its own. A UUID is an image or a snapshot. A name no image has throws `TemplateError` saying how to build it. |
95
+ | `timeoutMs` (Python `timeout`, seconds) | `timeoutSeconds`, rounded up, kept by the server, with `onTimeout: "delete"`. Left out, 300 s with `onTimeout: "pause"`. Under 60 s becomes 60 s, with a warning. Up to 24 hours, as on E2B; over throws `InvalidArgumentError`. |
72
96
  | `metadata` | labels (at most 32). |
73
97
  | `envs` | Given to every command and code run through this object. |
74
98
  | `allowInternetAccess: false` | `network: { internet: false }`. |
75
- | `lifecycle.onTimeout` | `onLeaseEnd`: `kill` is `stop`, `pause` is `pause`. |
99
+ | `lifecycle.onTimeout` | `onTimeout`: `kill` is `delete`, `pause` is `pause`. |
76
100
  | `commands.run(cmd, { cwd, envs, timeoutMs, onStdout, onStderr })` | A native process started by a streamed exec that reads it from the first byte, so Runtime holds a fast writer back rather than drop output: the result is whole, however long. The default command connection deadline is 60 s; `0` disables it. The process lives up to 24 hours, within the sandbox lease. |
77
101
  | Non-zero exit | Throws `CommandExitError` with `exitCode`, `stdout`, `stderr` and `error` (`exit status N`). A command killed by a signal has `exitCode` -1. |
78
- | Command past its timeout | Disconnects with `TimeoutError` (Python: `TimeoutException`) without killing the command; reconnect by pid to keep reading. |
102
+ | Command past its timeout | Disconnects with `TimeoutError` (Python: `TimeoutException`) without killing the command; reconnect by pid to keep reading. A command whose sandbox is killed under it ends with `TimeoutError` too, saying the sandbox was killed or reached its end of life. |
79
103
  | `commands.run(cmd, { background: true })` | `spawn`. Returns a `CommandHandle` with `pid`, `wait()`, `kill()` (SIGKILL), `sendStdin`, `closeStdin`, `disconnect`, `stdout`, `stderr`, `exitCode`. Runtime keeps the last 1 MiB a process printed; anything older that was not read in time is lost, which sets `truncated` and warns. A command with `stdin: true` starts the same way. |
80
104
  | `user` (commands, PTY and files) | Runs as that Linux user through `sudo -u`; `root` needs nothing more. A user the sandbox lacks throws `InvalidArgumentError` saying how to add one; none is ever created. `user: "user"` is the sandbox's own user. Watching a directory as another user is refused. |
81
- | `commands.list`, `kill(pid)`, `sendStdin(pid)`, `closeStdin(pid)`, `connect(pid)` | Runtime's processes. A pid is a number derived from Runtime's process id, not the Linux pid. |
105
+ | `commands.list`, `kill(pid)`, `sendStdin(pid)`, `closeStdin(pid)`, `connect(pid)` | Runtime's processes. A pid is a number derived from Runtime's process id, not the Linux pid. `commands.list` shows each command as E2B starts it: `cmd` `/bin/bash`, `args` `["-l", "-c", "<your command>"]` (a PTY: `["-i", "-l"]`), the command cut at 256 characters, `envs` empty. |
82
106
  | `pty.create`, `connect`, `sendInput`, `resize`, `kill` (Python snake_case) | Native PTY processes with lossless byte callbacks. A reader timeout or disconnect detaches without killing the process; reconnect resumes reading. |
83
107
  | `files.read(path, { format })` | `files.read`. `text`, `bytes`, `blob` and `stream` (Python: `text`, `bytes`, `stream`). |
84
108
  | `files.write(path, data)`, `write([...])`, `writeFiles` | `files.write`. Parent directories are made, and a file that exists is replaced. |
85
- | `files.list(path, { depth })` | `files.list`, hidden files included. `owner` and `group` come from native metadata, with `""` for older guests that omit them. |
86
- | `files.makeDir`, `exists`, `getInfo`, `rename`, `remove` | `files.stat`, `mkdir`, `rename` (replacing a file that exists) and `remove` (recursive). A missing file throws `FileNotFoundError`. |
87
- | Relative paths | Resolved against the home directory, `/workspace` on Runtime. |
109
+ | `files.list(path, { depth })` | `files.list`, hidden files included. `owner` and `group` come from native metadata, with `""` for older guests that omit them. `depth` below one throws `InvalidArgumentError` "depth should be at least one". |
110
+ | `files.makeDir`, `exists`, `getInfo`, `rename`, `remove` | `files.stat`, `mkdir`, `rename` (replacing a file that exists) and `remove` (recursive). A missing file throws `FileNotFoundError`. Entries read as envd gives them: `permissions` begins with the kind's letter (`-rw-r--r--`, `drwxr-xr-x`, `L` for a link), the sandbox user is `user`, and a link's `symlinkTarget` is absolute. |
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`. |
88
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. |
89
- | `sandbox.kill()`, `Sandbox.kill(id)` | `stop`, without waiting. `false` when the sandbox was not found or had already ended. |
90
- | `sandbox.setTimeout(ms)`, `Sandbox.setTimeout(id, ms)` | `extend`: the end moves to now + ms, up to 24 hours (past an hour it is carried on as for `timeoutMs`). An earlier end is refused: Runtime cannot end a lease early. A sandbox with no time limit has no end to move, and nothing changes. |
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. |
91
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`. |
92
116
  | `sandbox.pause()`, `betaPause`, `Sandbox.pause(id)` | `pause`, keeping memory and files. `false` when it was already paused. |
93
- | `getInfo`, `isRunning` | `get`. `templateId` is `base` or the image or snapshot id. `envdVersion` is `runtime`. |
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. |
94
118
  | `Sandbox.list({ query: { metadata, state }, limit })` | `sandboxes.list` by labels and state, oldest first, with E2B's paginator (`hasNext`, `nextItems()`, `nextToken`). A `template` or `startedAfter` filter, `order: "desc"` and a saved `nextToken` are applied by the adapter, which reads every match once and pages through them. |
95
119
  | `fork`, `createSnapshot`, `deleteSnapshot` | Runtime's memory-preserving forks and snapshots; deleting a snapshot removes that saved capture. A fork's `count` is 1 to 20, as E2B checks it. |
96
120
  | `getHost(port)` | `<port>-<id>.runtimehost.com` at once, as E2B answers it, and the port is shared as a public Runtime preview beside the caller (the sync Python sandbox shares it before returning). `await sandbox.getPublicHost(port)` returns once the share has landed. On the free trial a shared port is private and a host alone cannot reach it, so both throw `PublicPreviewNotAllowedError` (Python: `PublicPreviewNotAllowedException`, a kind of `NotSupportedError`) at once. Use `(await sandbox.runtime.previews.create(port)).urlWithToken`, or send its token as the `x-runtime-preview-token` header. |
@@ -98,7 +122,7 @@ machine. An E2B key (`e2b_...`) is never sent anywhere. If one is passed as
98
122
  | `Execution`, `Result`, `Logs`, `ExecutionError`, `OutputMessage` | The same shapes. Results that are too large to send inline are fetched and inlined. `logs.stdout` has one entry per line. |
99
123
  | `createCodeContext`, `listCodeContexts`, `restartCodeContext`, `removeCodeContext` | Runtime's interpreter contexts. |
100
124
  | `getMetrics({ start, end })`, `Sandbox.getMetrics(id)` | Runtime's measured CPU and memory, one entry per host reading. `diskUsed` is null: Runtime does not read disk use inside the sandbox. |
101
- | Error classes | E2B's names and parents. Each also carries Runtime's `code`, `hint` and `requestId`, with the original error as `cause`. |
125
+ | Error classes and other exports | Every name `e2b` and the code interpreter export imports, errors with E2B's names and parents. Python also imports each from the module E2B defines it in, so `from e2b.exceptions import TimeoutException` becomes `from withruntime.e2b.exceptions import TimeoutException`, and `WriteEntry` comes from `withruntime.e2b.sandbox.filesystem.filesystem`. Each error also carries Runtime's `code`, `hint` and `requestId`, with the original error as `cause`. |
102
126
 
103
127
  ## Gaps
104
128
 
@@ -131,6 +155,10 @@ returns a handle with `get_new_events()` and `stop()`; asynchronous
131
155
  a callback. Stream failures and lost events are reported, never treated as a
132
156
  successful empty watch. A positive watch timeout bounds the client subscription and stops its owned watch;
133
157
  zero leaves the subscription unlimited. The sandbox lease still applies. Both languages refuse watching network mounts.
158
+ As on envd, a path that is a file is refused with `InvalidArgumentError`
159
+ (Python: `InvalidArgumentException`). Runtime writes a file whole, by a rename
160
+ into place, which its watch sees as a create; a file's create is therefore
161
+ followed by a write event, which E2B code waiting for the write receives.
134
162
 
135
163
  PTY `timeoutMs` (Python `timeout`, seconds) defaults to sixty seconds, including
136
164
  the opening handshake; zero leaves the reader unlimited. Callbacks receive raw
@@ -161,7 +189,7 @@ every refusal: `tests/e2b` here and `sdks/python/tests/test_e2b_*.py`.
161
189
 
162
190
  The end-to-end tests run an unmodified E2B program against the real API with
163
191
  its one import changed. They create six sandboxes on the key's account. Each
164
- has 2 vCPU and 512 MiB, lasts at most five minutes and is stopped when its
192
+ has 2 vCPU and 512 MiB, lasts at most five minutes and is deleted when its
165
193
  case ends. They are not part of `bun run test`.
166
194
 
167
195
  ```bash no-run
package/README.md CHANGED
@@ -27,11 +27,12 @@ console.log(result.exitCode, result.stdout);
27
27
 
28
28
  `Sandbox.create()` needs no arguments and returns once the sandbox is running;
29
29
  `await using` stops it when the block ends (Node 24, Bun or TypeScript; on
30
- Node 22 call `await sbx.stop()`). With no arguments you get the free
31
- trial while it lasts (100 free hours, up to eight sandboxes running at once), 2 vCPU, 4 GiB of
30
+ Node 22 call `await sbx.stop()`). With no arguments you get the
31
+ included usage, a 1 GB machine running all month every month with no card (up to
32
+ eight sandboxes running at once without credit), 2 vCPU, 4 GiB of
32
33
  memory and a 4 GiB disk. The current default image includes NumPy, pandas and
33
34
  matplotlib; see the [sandbox environment](https://withruntime.com/docs/sandbox-environment).
34
- The trial's hours are spent first, then prepaid credit, with nothing to
35
+ The included usage is spent first, then prepaid credit, with nothing to
35
36
  choose; `funding` is accepted and ignored.
36
37
 
37
38
  The sandbox object does the rest:
package/README.src.md CHANGED
@@ -29,11 +29,12 @@ console.log(result.exitCode, result.stdout);
29
29
 
30
30
  `Sandbox.create()` needs no arguments and returns once the sandbox is running;
31
31
  `await using` stops it when the block ends (Node 24, Bun or TypeScript; on
32
- Node 22 call `await sbx.stop()`). With no arguments you get the free
33
- trial while it lasts ({{trial-hours}} free hours, up to {{trial-sandboxes}} sandboxes running at once), 2 vCPU, 4 GiB of
32
+ Node 22 call `await sbx.stop()`). With no arguments you get the
33
+ included usage, {{included-machine}} every month with no card (up to
34
+ {{trial-sandboxes}} sandboxes running at once without credit), 2 vCPU, 4 GiB of
34
35
  memory and a 4 GiB disk. The current default image includes NumPy, pandas and
35
36
  matplotlib; see the [sandbox environment](https://withruntime.com/docs/sandbox-environment).
36
- The trial's hours are spent first, then prepaid credit, with nothing to
37
+ The included usage is spent first, then prepaid credit, with nothing to
37
38
  choose; `funding` is accepted and ignored.
38
39
 
39
40
  The sandbox object does the rest:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "checkedAt": "2026-09-29",
3
+ "checkedAt": "2026-10-05",
4
4
  "providers": [
5
5
  {
6
6
  "id": "e2b",
@@ -9,9 +9,9 @@
9
9
  {
10
10
  "registry": "npm",
11
11
  "name": "e2b",
12
- "version": "2.52.0",
12
+ "version": "2.52.1",
13
13
  "artifacts": {
14
- "2.52.0": "sha512-TmUZlAvQq8BbguodpA+BBdawR/x5uILMQtHcLkdaLUqevsDjDdh46IYYU8ZRYKsQ4OhWr4xhsFIPSg1kgf+O0w=="
14
+ "2.52.1": "sha512-qbX0s6qV2gfN4/+NBTIli1hkztfH/1kL4AEAYTaP4wjx7dp2m2wnXcN35iz+8Gug0q4TPN9w4xbdw/TGJr/Bpw=="
15
15
  }
16
16
  },
17
17
  {
@@ -25,10 +25,10 @@
25
25
  {
26
26
  "registry": "pypi",
27
27
  "name": "e2b",
28
- "version": "2.52.0",
28
+ "version": "2.52.1",
29
29
  "artifacts": {
30
- "e2b-2.52.0-py3-none-any.whl": "sha256-6f4b5084b09986db43e99c7405bae6b14dc56984a69bbb1dc0687f1c71515cfb",
31
- "e2b-2.52.0.tar.gz": "sha256-58c0042609513799341d4c1837e2581a4a5e73d3d62c9f1c57495c5e23eedee2"
30
+ "e2b-2.52.1-py3-none-any.whl": "sha256-708583a37c9b797b0044bd92fa407c21aec65f101f2fd4c4a0ccd842dbe33de1",
31
+ "e2b-2.52.1.tar.gz": "sha256-3af5c037b971ebc89a1ef0e5ced0e1c9ecbf3d65f2c23df5db7ad9faef8f68fa"
32
32
  }
33
33
  },
34
34
  {
@@ -49,9 +49,9 @@
49
49
  {
50
50
  "registry": "npm",
51
51
  "name": "@daytona/sdk",
52
- "version": "0.220.0",
52
+ "version": "0.222.0",
53
53
  "artifacts": {
54
- "0.220.0": "sha512-PJio3vbDwRApzlsK6AGO7r4CHJcF9PI5DWuUW2yUnA2MVJSh/jotS0onKBv6boC5F+oboljTibUMxrwVPIrOlQ=="
54
+ "0.222.0": "sha512-N0hjbprttUcAQE3eBegzRNIhQTzbPOGAuS2LJvl4a6bLp3rjCY1R7G9HbE9STepiBQDAs5B08Vv1rpRTXw9PaA=="
55
55
  }
56
56
  },
57
57
  {
@@ -66,25 +66,25 @@
66
66
  {
67
67
  "registry": "npm",
68
68
  "name": "@daytona/api-client",
69
- "version": "0.220.0",
69
+ "version": "0.222.0",
70
70
  "artifacts": {
71
- "0.220.0": "sha512-XaMEtiQCaIHc3T7y3HUqx1A5eWSnd+FJvhpSHDwP3Snu9Nnhy4t+K2LHBWgJQn9dGtWXsdOsbB9K0BqpmFJtyA=="
71
+ "0.222.0": "sha512-KvD+k6LMaqauQBedbMPTZG3UK3oITwmI5onfqbQJOdEG3xD6Occ3dJRphPlXqfF7tdtmDiXv3yrbyyOusqjvdA=="
72
72
  }
73
73
  },
74
74
  {
75
75
  "registry": "npm",
76
76
  "name": "@daytona/toolbox-api-client",
77
- "version": "0.220.0",
77
+ "version": "0.222.0",
78
78
  "artifacts": {
79
- "0.220.0": "sha512-Kn94AOxhGQil0XygOOR26SaCkndE4dOtxYS0hLbqrTxcP3H1uq1HGFGSRkHFQNkaR8eL9QwFUPSMqd0Vr3A64A=="
79
+ "0.222.0": "sha512-crdx4Zoxjtd7sGoURS3Dwd0xEQ+6lW6e+tu45TgUx85BpDAoTEr0z7i13HgXcEfAYMIcj8o70FOlI5JlkEJ5dw=="
80
80
  }
81
81
  },
82
82
  {
83
83
  "registry": "npm",
84
84
  "name": "@daytona/analytics-api-client",
85
- "version": "0.220.0",
85
+ "version": "0.222.0",
86
86
  "artifacts": {
87
- "0.220.0": "sha512-3BGYILzjo2aFTJhLd6XBXlNEQBSo9Zr2Nj31OdX9o50fMRVUwVydF6ekIGkPGSLwskz6b6xxg5BSS+f9dbrxCQ=="
87
+ "0.222.0": "sha512-KNIk2b21pLzKMdKPnz+7cOXE9Qjvlfe9hwfiIdAatxa9jYbwJQTmbxs7BpdDB7I9GtdUionpdskxJWL+rVcWvA=="
88
88
  }
89
89
  }
90
90
  ]
@@ -94,15 +94,15 @@ const BLAXEL_HINTS = {
94
94
  cwd_not_found: "Make the directory with sandbox.fs.mkdir(path), or pass an existing workingDir to sandbox.process.exec.",
95
95
  sandbox_paused: "Call sandbox.unarchive(), then try again.",
96
96
  not_running: "The sandbox is not running: call sandbox.unarchive() if it was archived, or make a new one with SandboxInstance.create if it was deleted.",
97
- trial_busy: "The trial's sandboxes are all in use: delete one you no longer need (sandbox.delete()) or archive it (sandbox.archive()), then try again. Moving to paid credit is the account owner's decision.",
98
- public_preview_not_allowed: "On the trial, share the port privately: sandbox.previews.create({ metadata: { name }, spec: { port, public: false } }) and a token from preview.tokens.create(expiresAt) on a server supporting absolute preview deadlines. A public preview needs a paid sandbox, which is the account owner's decision.",
97
+ no_credit_running_limit: "The sandboxes an account without credit runs at once are all in use: delete one you no longer need (sandbox.delete()) or archive it (sandbox.archive()), then try again. Moving to paid credit is the account owner's decision.",
98
+ public_preview_not_allowed: "Without credit, share the port privately: sandbox.previews.create({ metadata: { name }, spec: { port, public: false } }) and a token from preview.tokens.create(expiresAt) on a server supporting absolute preview deadlines. A public preview needs a paid sandbox, which is the account owner's decision.",
99
99
  busy: AGAIN,
100
100
  guest_busy: AGAIN,
101
101
  rate_limited: AGAIN,
102
102
  unauthorized: "Set RUNTIME_API_KEY to a Runtime key (https://withruntime.com/account/keys), or run `npx withruntime login` once. A Blaxel key (BL_API_KEY) is never sent.",
103
103
  };
104
104
  /** A trial create over the trial's size, in Blaxel's field. */
105
- const TRIAL_CAP = "A trial sandbox has at most 4096 MB of memory (2 vCPUs); pass memory 4096 or add credit.";
105
+ const TRIAL_CAP = "Without credit, a sandbox has at most 4096 MB of memory (2 vCPUs); pass memory 4096 or add credit.";
106
106
  /** A Runtime SDK error as Blaxel's: ResponseError (SandboxGatewayError for a
107
107
  * 502, 503 or 504), NotSupportedError for a product Runtime has switched off,
108
108
  * CredentialsError when there is no Runtime key. Anything else passes through
@@ -118,7 +118,7 @@ export function translate(error) {
118
118
  return new NotSupportedError(error.code.replace(/_unavailable$/, ""), error.hint ?? "", error.message);
119
119
  if (error.status < 200 || error.status > 599)
120
120
  return error;
121
- const trialCap = error.code === "invalid_trial";
121
+ const trialCap = error.code === "no_credit_size_limit";
122
122
  const hint = trialCap ? undefined : (BLAXEL_HINTS[error.code] ?? error.hint);
123
123
  const message = [
124
124
  trialCap ? TRIAL_CAP : error.message,
@@ -127,8 +127,7 @@ export declare class SandboxInstance {
127
127
  get expiresIn(): number | undefined;
128
128
  /** Creates a sandbox and answers once it runs. Blaxel's defaults: the base
129
129
  * image (Runtime's stock image) and 4096 MB, with vCPUs at one per 2048 MB.
130
- * Funding is left to Runtime: the free trial while the account has trial
131
- * time, then prepaid credit. A name another live sandbox holds is refused
130
+ * Funding is left to Runtime: the included usage first, then prepaid credit. A name another live sandbox holds is refused
132
131
  * with a 409, as in Blaxel. */
133
132
  static create<T extends typeof SandboxInstance>(this: T, sandbox?: SandboxCreateConfiguration | SandboxModel, { createIfNotExist }?: {
134
133
  safe?: boolean;
@@ -523,8 +523,7 @@ export class SandboxInstance {
523
523
  // ---- create, get, list ---------------------------------------------------
524
524
  /** Creates a sandbox and answers once it runs. Blaxel's defaults: the base
525
525
  * image (Runtime's stock image) and 4096 MB, with vCPUs at one per 2048 MB.
526
- * Funding is left to Runtime: the free trial while the account has trial
527
- * time, then prepaid credit. A name another live sandbox holds is refused
526
+ * Funding is left to Runtime: the included usage first, then prepaid credit. A name another live sandbox holds is refused
528
527
  * with a 409, as in Blaxel. */
529
528
  static async create(sandbox, { createIfNotExist = false } = {}) {
530
529
  const config = configOf(sandbox);
package/dist/cli.d.ts CHANGED
@@ -30,7 +30,7 @@ declare const kit: {
30
30
  };
31
31
  export type CliKit = typeof kit;
32
32
  export declare function run(argv: string[], env?: NodeJS.ProcessEnv, out?: Out): Promise<number>;
33
- /** `runtime usage` for a person: the balance, the trial and what each kind
33
+ /** `runtime usage` for a person: the balance, the included usage and what each kind
34
34
  * of resource was charged, in dollars. --json keeps every figure, and each
35
35
  * resource with its rates and CPU time. */
36
36
  /** One row per resource, for a spreadsheet: when it ran, how big it was, how
package/dist/cli.js CHANGED
@@ -36,7 +36,7 @@ Account
36
36
  The account's audit log (owner or admin keys)
37
37
  sso Single sign-on and SCIM directory sync (owner or
38
38
  admin keys); an owner changes it on the website
39
- usage [--csv] Balance, trial time and charges; --csv, each resource
39
+ usage [--csv] Balance, included usage and charges; --csv, each resource
40
40
  usage export --since <UTC time> --until <UTC time>
41
41
  Every settlement in the range as CSV; --json, each page
42
42
  limits Whether this key is read-only, and its daily spending limit
@@ -695,16 +695,18 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
695
695
  const [who, spend] = await Promise.all([rt.me(), rt.usage().catch(() => undefined)]);
696
696
  const trialLeft = spend?.trial ? spend.trial.availableMs / 3_600_000 : 0;
697
697
  const credit = spend ? BigInt(spend.available) : 0n;
698
+ // A pilot's sandboxes run on the pilot, before anything else and free.
698
699
  const funding = !spend
699
700
  ? undefined
700
701
  : [
702
+ ...(spend.pilot ? [pilotFunding(spend.pilot)] : []),
701
703
  ...(trialLeft > 0
702
704
  ? [
703
- `free trial, ${trialLeft.toLocaleString("en-US", { maximumFractionDigits: 1 })} hours left`,
705
+ `included usage, ${trialLeft.toLocaleString("en-US", { maximumFractionDigits: 1 })} hours left without credit`,
704
706
  ]
705
707
  : []),
706
708
  ...(credit > 0n ? [`${dollars(credit)} of credit`] : []),
707
- ].join("; ") || "no trial time or credit left: runtime billing";
709
+ ].join("; ") || "no included usage or credit left: runtime billing";
708
710
  print(table([
709
711
  ["organization", who.orgName ? `${who.orgName} (${who.orgId})` : who.orgId],
710
712
  ...(who.role ? [["role", who.role]] : []),
@@ -765,7 +767,10 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
765
767
  return 0;
766
768
  }
767
769
  if (command === "limits") {
768
- const l = await (await client(env)).limits.get();
770
+ const rt = await client(env);
771
+ // The usage call only adds the pilot's line: a key that cannot read it
772
+ // still gets its limits.
773
+ const [l, spend] = await Promise.all([rt.limits.get(), rt.usage().catch(() => undefined)]);
769
774
  // As `usage` shows money: $0.0014 of spend read $0.00 until 30 September 2026.
770
775
  const usd = (micros) => dollars(micros);
771
776
  const access = l.access === "read"
@@ -783,7 +788,13 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
783
788
  ],
784
789
  ["used, last 24 hours", usd(l.daily.usedMicros)],
785
790
  ...(l.daily.remainingMicros === null ? [] : [["left", usd(l.daily.remainingMicros)]]),
786
- ...(l.trial ? [["free trial", trialLeft(l.trial)]] : []),
791
+ ...(l.trial ? [["free time", trialLeft(l.trial)]] : []),
792
+ ...(spend?.pilot
793
+ ? [
794
+ ["pilot", pilotFunding(spend.pilot)],
795
+ ["pilot sandbox hours", pilotLeft(spend.pilot)],
796
+ ]
797
+ : []),
787
798
  ]), l);
788
799
  return 0;
789
800
  }
@@ -1029,7 +1040,7 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
1029
1040
  }
1030
1041
  throw unknown("command", command, COMMANDS);
1031
1042
  }
1032
- /** `runtime usage` for a person: the balance, the trial and what each kind
1043
+ /** `runtime usage` for a person: the balance, the included usage and what each kind
1033
1044
  * of resource was charged, in dollars. --json keeps every figure, and each
1034
1045
  * resource with its rates and CPU time. */
1035
1046
  /** One row per resource, for a spreadsheet: when it ran, how big it was, how
@@ -1083,15 +1094,42 @@ export function usageCsv(u) {
1083
1094
  }
1084
1095
  /** Milliseconds as hours, to a tenth: "8,731.2". */
1085
1096
  const hours = (ms) => (ms / 3_600_000).toLocaleString("en-US", { maximumFractionDigits: 1 });
1086
- /** The free trial's time left, as `runtime usage` and `runtime limits` say it. */
1097
+ /** The machine time left without credit, as `runtime usage` and `runtime
1098
+ * limits` say it: this month's included usage, as hours at 2 vCPU and 4 GiB,
1099
+ * or for an account given free hours before 5 October 2026, those hours too. */
1087
1100
  function trialLeft(trial) {
1088
- return `${hours(trial.availableMs)} of ${hours(trial.totalMs)} hours left`;
1101
+ const renews = trial.renewsAt ? `, renews ${trial.renewsAt.slice(0, 10)}` : "";
1102
+ return trial.totalMs > 0
1103
+ ? `${hours(trial.availableMs)} hours left (${hours(trial.totalMs)} free hours given before 5 October 2026, and the included usage${renews})`
1104
+ : `${hours(trial.availableMs)} hours at 2 vCPU and 4 GiB left this month${renews}`;
1105
+ }
1106
+ /** This month's included usage, one row per product, as `runtime usage`
1107
+ * says it. */
1108
+ function allowanceRows(allowances) {
1109
+ const amount = (n) => n.toLocaleString("en-US", { maximumFractionDigits: 1 });
1110
+ return allowances.map((a) => [
1111
+ `included ${a.pool.replace(/-/g, " ")}`,
1112
+ `${amount(a.left)} of ${amount(a.quantity)} ${a.unit}s left`,
1113
+ ]);
1114
+ }
1115
+ /** What a pilot gives, as `runtime whoami` and `runtime limits` say it: the
1116
+ * sandboxes it runs free and until when, past which credit does not run
1117
+ * them. */
1118
+ function pilotFunding(pilot) {
1119
+ const at = (iso) => `${iso.slice(0, 16).replace("T", " ")} UTC`;
1120
+ return `a pilot: up to ${pilot.sandboxes.toLocaleString("en-US")} sandboxes free, running until ${at(pilot.graceEndsAt)}; credit does not run it; to extend it, write to support`;
1089
1121
  }
1090
1122
  /** A pilot's sandbox hours left, as `runtime usage` says them. */
1091
1123
  function pilotLeft(pilot) {
1092
1124
  const left = `${hours(pilot.leftMs)} of ${pilot.hours.toLocaleString("en-US")} left`;
1125
+ // How long they last at the rate its sandboxes run now (an API before
1126
+ // 0414 does not say how many run).
1127
+ const running = pilot.running ?? 0;
1128
+ const pace = running > 0
1129
+ ? `; at ${running.toLocaleString("en-US")} running, about ${hours(pilot.leftMs / running)} hours`
1130
+ : "";
1093
1131
  return pilot.leftMs > 0
1094
- ? `${left}; new pilot sandboxes until ${pilot.endsAt.slice(0, 16).replace("T", " ")} UTC`
1132
+ ? `${left}${pace}; new pilot sandboxes until ${pilot.endsAt.slice(0, 16).replace("T", " ")} UTC`
1095
1133
  : "This pilot's sandbox hours are used.";
1096
1134
  }
1097
1135
  function usageSummary(u) {
@@ -1114,7 +1152,9 @@ function usageSummary(u) {
1114
1152
  if (micros(u.expired) > 0n)
1115
1153
  rows.push(["expired or taken back", dollars(micros(u.expired))]);
1116
1154
  if (u.trial)
1117
- rows.push(["free trial", trialLeft(u.trial)]);
1155
+ rows.push(["free time", trialLeft(u.trial)]);
1156
+ if (u.allowances)
1157
+ rows.push(...allowanceRows(u.allowances));
1118
1158
  if (u.pilot)
1119
1159
  rows.push(["pilot sandbox hours", pilotLeft(u.pilot)]);
1120
1160
  if (u.outbound) {
@@ -1126,7 +1166,15 @@ function usageSummary(u) {
1126
1166
  ]);
1127
1167
  }
1128
1168
  const kinds = new Map();
1129
- for (const resource of u.resources ?? []) {
1169
+ // Every resource, by kind, from an API that totals them (6 October 2026);
1170
+ // an older one sends only its hundred newest, counted here.
1171
+ for (const k of u.kinds ?? [])
1172
+ kinds.set(k.kind, {
1173
+ count: k.resources,
1174
+ charged: micros(k.chargedMicros),
1175
+ held: micros(k.heldMicros),
1176
+ });
1177
+ for (const resource of u.kinds ? [] : (u.resources ?? [])) {
1130
1178
  const kind = typeof resource.kind === "string" ? resource.kind : "other";
1131
1179
  const entry = kinds.get(kind) ?? { count: 0, charged: 0n, held: 0n };
1132
1180
  entry.count++;
@@ -1305,7 +1353,7 @@ function runningTime(seconds) {
1305
1353
  });
1306
1354
  return `${shown} ${unit}${shown === "1" ? "" : "s"}`;
1307
1355
  }
1308
- /** The sandboxes the free trial paid for, said beside what was priced. */
1356
+ /** The sandboxes free usage paid for, said beside what was priced. */
1309
1357
  function trialNote(trial, all, trialSeconds) {
1310
1358
  if (!trial)
1311
1359
  return "";
@@ -1314,7 +1362,7 @@ function trialNote(trial, all, trialSeconds) {
1314
1362
  ? "It"
1315
1363
  : "All of them"
1316
1364
  : `${trial} of them, ${runningTime(trialSeconds)} of that time,`;
1317
- return ` ${which} ran on the free trial, which charged nothing; Runtime's side prices ${trial === 1 ? "it" : "them"} at the standard rates, what the same work costs on paid credit.`;
1365
+ return ` ${which} ran on free usage, which charged nothing; Runtime's side prices ${trial === 1 ? "it" : "them"} at the standard rates, what the same work costs on paid credit.`;
1318
1366
  }
1319
1367
  async function switching(command, argv, env, out) {
1320
1368
  const args = parse(argv, [], command === "compare" ? ["from", "days"] : ["from"]);
@@ -2808,7 +2856,7 @@ read = readSecret) {
2808
2856
  const JOB_HELP = `runtime job <command>
2809
2857
 
2810
2858
  A job runs a command in a fresh sandbox, once or on a schedule. Each run spends
2811
- the free trial's hours first, then credit at the sandbox rates.
2859
+ the included usage first, then credit at the sandbox rates.
2812
2860
 
2813
2861
  create <name> (--cron "<min hour day month weekday>" [--timezone Europe/Berlin] | --at <time|now>)
2814
2862
  [--vcpu 2] [--memory 4096] [--disk 4096] [--cpu shared|reserved] [--cpu-floor <thousandths>]
@@ -3254,7 +3302,7 @@ const CREATE_FLAGS = [
3254
3302
  "get-or-create",
3255
3303
  ];
3256
3304
  /** Says on standard error, once for each reason, why a create has not
3257
- * answered yet: it is waiting for a trial slot or room, which can take up to
3305
+ * answered yet: it is waiting for a slot without credit or room, which can take up to
3258
3306
  * two minutes, and silence reads as a hang. */
3259
3307
  function waiting(out) {
3260
3308
  const said = new Set();