Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/codemode-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@cloudflare/computer": minor
---

Rename `WorkerJavaScriptBackend` to `CodemodeBackend`, and change its default id from `"worker-javascript"` to `"codemode"`. There is no alias for the old names. To upgrade:

1. Rename the import path and exports:
- `@cloudflare/computer/backends/worker-javascript` → `@cloudflare/computer/backends/codemode`
- `WorkerJavaScriptBackend` → `CodemodeBackend`
- `WorkerJavaScriptBackendOptions` → `CodemodeBackendOptions`
2. Decide what id the backend uses. A backend without `id` now registers as `"codemode"`, and the exec tool, which shows the model each backend's id, offers it as `"codemode"`. Its `type`, which traces record, is now `"codemode"` whatever the id. Runs are saved under the id of the backend that started them, and a backend only sees runs saved under its own id. A `"codemode"` backend doesn't fail on runs saved under `"worker-javascript"`; it ignores them. It doesn't resume or fail interrupted ones, `runtime.pending()` doesn't list their waiting calls, `runtime.getExec(id)` on it throws `ENOENT`, and the rows stay in storage.
- To keep runs waiting for a person, saved results and journals, and existing `backend: "worker-javascript"` and `exec: { backends: { "worker-javascript": ... } }` references working, pass `id: "worker-javascript"` to `new CodemodeBackend(...)`. The exec tool then keeps offering it to the model as `"worker-javascript"`.
- Otherwise, change `backend: "worker-javascript"` to `backend: "codemode"` and `exec.backends` keys from `"worker-javascript"` to `"codemode"`. Left unchanged, `backend: "worker-javascript"` throws `no backend with id "worker-javascript"` and `exec.backends` throws `unknown backend "worker-javascript"`. Runs saved before the upgrade, including any still running or waiting for a person when you deploy, are then out of reach: nothing resumes, lists or cleans them up unless a backend with `id: "worker-javascript"` comes back.
2 changes: 1 addition & 1 deletion .changeset/exec-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"@cloudflare/computer": minor
---

`runtime.exec()` takes `metadata`, a record of strings for host modules that the run's code never sees. Host module calls read it as `context.execution.metadata`, `runtime.pending()` lists it with each waiting call, and a replayable run keeps it when it resumes. `WorkerJavaScriptBackend` caps it at 16 KiB of keys and values.
`runtime.exec()` takes `metadata`, a record of strings for host modules that the run's code never sees. Host module calls read it as `context.execution.metadata`, `runtime.pending()` lists it with each waiting call, and a replayable run keeps it when it resumes. `CodemodeBackend` caps it at 16 KiB of keys and values.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ jobs:
- name: assets
workspace: "@example/computer-assets"
path: examples/assets
- name: codemode
workspace: "@example/computer-codemode"
path: examples/codemode
- name: container
workspace: "@example/computer-container"
path: examples/container
Expand All @@ -164,9 +167,6 @@ jobs:
- name: tutorial
workspace: "@example/computer-tutorial"
path: examples/tutorial
- name: worker-javascript
workspace: "@example/computer-worker-javascript"
path: examples/worker-javascript
- name: worker-shell
workspace: "@example/computer-worker-shell"
path: examples/worker-shell
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SQLite and exposes one pluggable execution surface through
- **Isolate shell** runs [just-bash](https://github.com/vercel-labs/just-bash)
in a Dynamic Worker. It reaches the authoritative Workspace over
Workers RPC, so there is no second store or sync round trip.
- **Isolate JavaScript** runs an ECMAScript module in a fresh Dynamic
- **Codemode** runs an ECMAScript module in a fresh Dynamic
Worker with structured input/results, durable relative imports,
configured libraries, Workspace-backed `node:fs/promises`, and host modules such as
`codemode:git`, `codemode:artifacts`, and `codemode:container`.
Expand Down Expand Up @@ -62,14 +62,14 @@ public surface. Each is a Worker workspace with its own README.
- [`examples/worker-shell`](examples/worker-shell) — same HTTP surface as the
container example, but the shell runs [just-bash](https://github.com/vercel-labs/just-bash)
in a Dynamic Worker loaded through `env.LOADER`. No container.
- [`examples/worker-javascript`](examples/worker-javascript) — mirrors
- [`examples/codemode`](examples/codemode) — mirrors
`worker-shell`, but `exec` evaluates an ECMAScript module in a Dynamic
Worker instead of running a shell command.
- [`examples/vite-bundle`](examples/vite-bundle) — a Vite-built Worker
that ships `src/skills` into every workspace with `computerBundle()`
and `WorkerBundle`, including under `vite dev`.
- [`examples/egress`](examples/egress) — sends one URL through the container,
Worker shell, and Worker JavaScript backends with matching `none`, `all`, or
Worker shell, and codemode backends with matching `none`, `all`, or
custom egress policies.
- [`examples/mcp`](examples/mcp) — a Computer MCP example:
one Code Mode `code` tool backed by a durable workspace, a Worker shell,
Expand Down
10 changes: 5 additions & 5 deletions docs/05_runtime_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ flowchart LR
- The files are ordinary Workspace files. A container backend receives them on its next push like any other change.
- If saving fails, for example under a read-only mount, the entry has `status: "not-saved"` and a `reason`; the result still holds the last lines.

Command backends leave `value` unset. `worker-javascript` uses `value` for the module's structured return value and reports a zero-entry completed sync. A command can complete while its post-command pull fails; in that case `sync.status` is `"pending"`, and the next `pull()` resumes the operation from its durable watermark without rerunning the command.
Command backends leave `value` unset. `codemode` uses `value` for the module's structured return value and reports a zero-entry completed sync. A command can complete while its post-command pull fails; in that case `sync.status` is `"pending"`, and the next `pull()` resumes the operation from its durable watermark without rerunning the command.

## Backend routing

Expand All @@ -121,7 +121,7 @@ await workspace.runtime.exec(
import fs from "node:fs/promises";
export default async () => fs.readFile("/workspace/package.json", "utf8");
`,
{ backend: "worker-javascript" },
{ backend: "codemode" },
);
```

Expand All @@ -132,14 +132,14 @@ Omitting `backend` selects the first configured backend. Backend selection is ro
```ts
workspace.runtime.backends();
// [
// { id: "worker-javascript", protocol: "module", callable: true, description: "..." },
// { id: "codemode", protocol: "module", callable: true, description: "..." },
// { id: "container-shell", protocol: "command", callable: false, description: "..." },
// ]
```

- `protocol` says what `exec` source means there: a shell command (`"command"`) or module source (`"module"`).
- `callable` says whether the backend takes structured `input` and returns a `value`.
- `description`, when present, is what the backend tells a model about itself. `WorkerJavaScriptBackend` lists its source language and every module code can import, and `WorkerShellBackend` and `ContainerBackend` describe what they can run. The `exec` tool builds its description from these.
- `description`, when present, is what the backend tells a model about itself. `CodemodeBackend` lists its source language and every module code can import, and `WorkerShellBackend` and `ContainerBackend` describe what they can run. The `exec` tool builds its description from these.

The list is fixed when the Workspace is constructed. A client from `getWorkspace()` takes a copy of it when the client loads, so once awaited the answer is the same locally and over RPC. Before then, the client reports no backends.

Expand All @@ -163,7 +163,7 @@ Module backends use host capability calls against the authoritative Workspace an

`container-shell` provides computerd's retained process log, replay, signals, and disposal. Execution handles are scoped to the UUID of the container process that accepted them, so they cannot target a reused execution id after process replacement. The latest UUID owner for each execution ID is stored in Workspace SQLite, with a bounded in-memory LRU cache, so direct by-ID operations preserve the fence across Durable Object incarnation and cache eviction.

`worker-javascript` provides a Workspace-owned execution journal, retained result/events, host cancellation, and explicit disposal. Active Workers cannot be serialized across host restart; orphaned running records are reconciled to failed.
`codemode` provides a Workspace-owned execution journal, retained result/events, host cancellation, and explicit disposal. Active Workers cannot be serialized across host restart; orphaned running records are reconciled to failed.

`worker-shell` intentionally preserves one-call, buffered-result behavior in this release. It does not retain executions for later reattachment or disposal. `timeoutMs` and a concurrent `killExec()` for a caller-supplied execution ID cooperatively abort just-bash at statement boundaries; by the time an ordinary `exec()` promise returns, the command has already settled. Use the Container or JavaScript isolate when detached execution and retained lifecycle are required.

Expand Down
8 changes: 4 additions & 4 deletions docs/09_tool_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ Pass the returned AI SDK `ToolSet` to `generateText`, `streamText`, or an agent
`exec: { backends }` lists the backends the model can use, keyed by backend id. Leave it out to use every backend.

```ts
createAITools({ workspace }); // every backend
createAITools({ workspace, exec: { backends: { "worker-javascript": {} } } }); // just this one
createAITools({ workspace }); // every backend
createAITools({ workspace, exec: { backends: { codemode: {} } } }); // just this one
createAITools({
workspace,
exec: { backends: { "worker-javascript": { description: "Use for data work." } } }, // with your own text
exec: { backends: { codemode: { description: "Use for data work." } } }, // with your own text
});
```

Expand Down Expand Up @@ -361,7 +361,7 @@ The tool uses forced removal, so deleting a missing path succeeds. Set `recursiv

`exec` calls `workspace.runtime.exec` on the chosen backend and streams bounded output. `createExecTool({ workspace, backends?, maxBytes?, maxLines?, metadata? })` takes the same `backends` as the `exec` option, plus output limits and [metadata](#run-metadata).

Each backend's entry in the tool description joins two parts: your text, if any, and what the backend says about itself (`backend.description`, read through `workspace.runtime.backends()`). `WorkerJavaScriptBackend` describes its source language and every module code can import, so the list stays in step with `modules`. `WorkerShellBackend` and `ContainerBackend` describe their command sets, network access, and startup cost. A backend that says nothing gets a one-line default, so add text for a custom backend.
Each backend's entry in the tool description joins two parts: your text, if any, and what the backend says about itself (`backend.description`, read through `workspace.runtime.backends()`). `CodemodeBackend` describes its source language and every module code can import, so the list stays in step with `modules`. `WorkerShellBackend` and `ContainerBackend` describe their command sets, network access, and startup cost. A backend that says nothing gets a one-line default, so add text for a custom backend.

The tool offers only the arguments that can work:

Expand Down
6 changes: 3 additions & 3 deletions docs/10_project_layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ packages/computer/
│ ├── backends/
│ │ ├── container/ # Cloudflare Container + computerd backend
│ │ ├── worker-shell/ # Dynamic Worker + just-bash shell backend
│ │ ├── worker-javascript/ # Dynamic Worker ECMAScript module backend
│ │ ├── codemode/ # Dynamic Worker ECMAScript module backend
│ │ └── test.ts # In-process test backend
│ ├── mounts/ # Mount registry, indexer, R2Bucket and WorkerBundle
│ ├── vite/ # computerBundle Vite plugin (@cloudflare/computer/vite)
Expand All @@ -74,7 +74,7 @@ packages/computer/
└── package.json
```

The package builds ESM and declarations with tsdown. Public entrypoints include the root export, tools, Git, assets, artifacts, the Container, Worker shell, and Worker JavaScript backends, and Cloudflare observability. The injected service is the separate `computerd` package, and shared wire types live in `@cloudflare/computer-rpc`.
The package builds ESM and declarations with tsdown. Public entrypoints include the root export, tools, Git, assets, artifacts, the Container, Worker shell, and codemode backends, and Cloudflare observability. The injected service is the separate `computerd` package, and shared wire types live in `@cloudflare/computer-rpc`.

## `packages/dofs/` — `@cloudflare/dofs`

Expand Down Expand Up @@ -213,7 +213,7 @@ Runnable examples live at the repo root, not inside any package:
examples/
├── container/ # computerd inside a Cloudflare Container
├── worker-shell/ # WorkerShellBackend (just-bash) example
├── worker-javascript/ # WorkerJavaScriptBackend example
├── codemode/ # CodemodeBackend example
├── think/ # @cloudflare/think chat integration
├── think-compare-runtimes/ # container vs worker runtime comparison UI
├── tutorial/ # step-by-step pandoc PDF agent
Expand Down
2 changes: 1 addition & 1 deletion docs/12_worker_backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ isolate that boots instantly, scales out cheaply, and has no
container lifecycle. The shell is the just-bash interpreter; the
supported command set is broad (`cat`, `grep`, `awk`, `sed`, `jq`,
`sort`) but not the full Linux userland. JavaScript modules run through the
[`worker-javascript` backend](./17_isolate_javascript.md), not through just-bash's
[codemode backend](./17_isolate_javascript.md), not through just-bash's
Node-only language commands. Filesystem operations forward into the same
SQLite store as the container backend, so the storage shape, mount
rules, and read-only enforcement are unchanged.
Expand Down
20 changes: 10 additions & 10 deletions docs/16_code_execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The selected backend defines how it interprets `source`.
| --- | --- | --- |
| `container-shell` | shell command | Full Linux, native binaries, installed packages, processes |
| `worker-shell` | just-bash command | Fast text tools and Workspace Git without a Container |
| `worker-javascript` | ECMAScript module | Isolated structured JavaScript with Workspace host modules |
| `codemode` | ECMAScript module | Isolated structured JavaScript with Workspace host modules |

Applications may register additional command or module backends under their own IDs. Backend IDs are part of the execution contract: changing the backend may change the source language.

Expand All @@ -26,19 +26,19 @@ Applications may register additional command or module backends under their own
```ts
const handle = await workspace.runtime.exec(source, {
id: "build-1",
backend: "worker-javascript",
backend: "codemode",
});

handle.id;
await handle.kill();

const resumed = await workspace.runtime.getExec("build-1", {
backend: "worker-javascript",
backend: "codemode",
resume: "full",
});

await workspace.runtime.disposeExec("build-1", {
backend: "worker-javascript",
backend: "codemode",
});
```

Expand All @@ -59,9 +59,9 @@ interface WorkspaceRuntimeResult {

Command backends leave `value` unset. Module backends use it for their structured return value.

`container-shell` retains the existing computerd process lifecycle. `worker-javascript` keeps an execution journal in the Workspace database and retains events/results until `disposeExec`. Active isolate cancellation is host-driven by disposing the child Worker. An execution left running across a Workspace host restart is reconciled to failed because a live Worker capability cannot be serialized into SQLite.
`container-shell` retains the existing computerd process lifecycle. `codemode` keeps an execution journal in the Workspace database and retains events/results until `disposeExec`. Active isolate cancellation is host-driven by disposing the child Worker. An execution left running across a Workspace host restart is reconciled to failed because a live Worker capability cannot be serialized into SQLite.

`worker-shell` intentionally retains its existing behavior in this release: it buffers a just-bash call to completion, does not retain cross-request events, and cannot reattach by ID. Callers that require supervised process behavior should use `container-shell`; callers that require a managed isolate should use `worker-javascript`.
`worker-shell` intentionally retains its existing behavior in this release: it buffers a just-bash call to completion, does not retain cross-request events, and cannot reattach by ID. Callers that require supervised process behavior should use `container-shell`; callers that require a managed isolate should use `codemode`.

## Backend authority

Expand All @@ -70,14 +70,14 @@ There is no general `workspace.scope()` abstraction. Backend construction fixes
For different authority levels, configure distinct backend instances:

```ts
new WorkerJavaScriptBackend({
id: "worker-javascript-readonly",
new CodemodeBackend({
id: "codemode-readonly",
loader: env.LOADER,
access: "read",
});

new WorkerJavaScriptBackend({
id: "worker-javascript",
new CodemodeBackend({
id: "codemode",
loader: env.LOADER,
access: "read-write",
});
Expand Down
Loading
Loading