Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ PLAN.md
# Generated bundle for the worker backend's ShellWorker. Built
# by packages/computer/src/backends/worker/script/build-bundle.mjs
# on prepare / pretest / pretypecheck.
packages/computer/src/backends/worker/generated-bundle.ts
packages/computer/src/backends/worker-shell/generated-bundle.ts

# SEA binary destinations populated at publish time from
# artifacts/computerd/ via the build-bin step. The @cloudflare/computer
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,6 @@ file and add it to the list above.
backed tests only run on Linux and are skipped elsewhere
automatically.
- **Examples are real consumers.** `examples/think`,
`examples/container`, and `examples/worker` exercise the public
`examples/container`, and `examples/worker-shell` exercise the public
surface. If you change a public API, update them in the same
change.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ To see the pieces working together, start with the examples:
- [`examples/container`](examples/container) — runs `computerd` inside a
container, mounts a workspace, and talks to a Durable Object over
capnweb.
- [`examples/worker`](examples/worker) — same HTTP surface as the
- [`examples/worker-shell`](examples/worker-shell) — same HTTP surface as the
container example, but the shell runs in a Dynamic Worker loaded
through `env.LOADER`. No container.
- [`examples/think`](examples/think) — an agent that uses the
Expand Down
12 changes: 6 additions & 6 deletions docs/05_runtime_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ interface WorkspaceRuntimeResult {
}
```

Command backends leave `value` unset. `isolate-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 a configured `SyncRetryScheduler` can durably retry the pull without rerunning the command.
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 a configured `SyncRetryScheduler` can durably retry the pull without rerunning the command.

## Backend routing

```ts
await workspace.runtime.exec("grep -R TODO .", {
backend: "isolate-shell",
backend: "worker-shell",
});

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

Expand All @@ -94,16 +94,16 @@ Command backends continue to use the existing synchronization bracket:
push → spawn → events/result → pull
```

A backend with `sync: "none"`, such as `isolate-shell`, shares the host store and reports zero push/pull counts. A Container has its own VFS and synchronizes changes before and after command execution. Fully draining either `result()` or the event stream completes the post-command pull before the stream closes.
A backend with `sync: "none"`, such as `worker-shell`, shares the host store and reports zero push/pull counts. A Container has its own VFS and synchronizes changes before and after command execution. Fully draining either `result()` or the event stream completes the post-command pull before the stream closes.

Module backends use host capability calls against the authoritative Workspace and therefore require no push/pull round trip.

## Lifecycle differences

`container-shell` provides computerd's retained process log, replay, signals, and disposal.

`isolate-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.
`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.

`isolate-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.
`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.

See [16. Execution runtime architecture](./16_code_execution.md) and [17. Isolate JavaScript](./17_isolate_javascript.md).
2 changes: 1 addition & 1 deletion docs/09_tool_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ When assigning the same instance to `Think.workspace`, construct it with `useThi
const workspace = new Workspace({
storage: ctx.storage,
backends: [
new WorkerBackend({ id: "shell", /* ... */ }),
new WorkerShellBackend({ id: "shell", /* ... */ }),
new CloudflareContainerBackend({ id: "container", /* ... */ }),
],
});
Expand Down
8 changes: 4 additions & 4 deletions docs/10_project_layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ packages/computer/
│ ├── backend.ts # Command backend interface
│ ├── backends/
│ │ ├── container/ # Cloudflare Container + computerd backend
│ │ ├── worker/ # Dynamic Worker + just-bash backend
│ │ ├── javascript/ # Dynamic Worker ECMAScript backend
│ │ ├── worker-shell/ # Dynamic Worker + just-bash shell backend
│ │ ├── worker-javascript/ # Dynamic Worker ECMAScript module backend
│ │ └── test.ts # In-process test backend
│ ├── proxy.ts # WorkspaceProxy
│ ├── proxy-stub.ts # Client-side stub plumbing
Expand Down Expand Up @@ -199,7 +199,7 @@ Runnable examples live at the repo root, not inside any package:
```
examples/
├── container/ # Reference container image for computerd
├── worker/ # WorkerBackend example
├── worker-shell/ # WorkerShellBackend example
├── code/ # workspace.runtime with Worker and Container shells
└── think/ # @cloudflare/think integration
```
Expand All @@ -210,7 +210,7 @@ so each example can declare its own dependencies and scripts.
## Testing

- **Unit tests live next to source.** Packages follow the `foo.ts` + `foo.test.ts` convention.
- **Workerd integration tests** for WorkerBackend, Workspace RPC, and `workspace.runtime` live in `packages/computer/tests/` with dedicated Vitest and Wrangler configuration.
- **Workerd integration tests** for WorkerShellBackend, Workspace RPC, and `workspace.runtime` live in `packages/computer/tests/` with dedicated Vitest and Wrangler configuration.
- **Container and load harness tests** live in `packages/computer/test-harness/`:
- `end-to-end.test.ts` — DO ↔ container round-trip
- `shell.test.ts` — shell surface against a real backend
Expand Down
20 changes: 10 additions & 10 deletions docs/12_worker_backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

> [!NOTE]
> This doc reflects shipped code in
> `packages/computer/src/backends/worker/`. The example deployment
> lives at `examples/worker/`.
> `packages/computer/src/backends/worker-shell/`. The example deployment
> lives at `examples/worker-shell/`.

The worker backend is the second `WorkspaceBackend` shape the
package ships. It pairs a Workspace with a
Expand All @@ -17,7 +17,7 @@ Import via the sub-path so the bundled just-bash payload tree-shakes
out of consumers that don't use it:

```ts
import { WorkerBackend } from "@cloudflare/computer/backends/worker";
import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";
```

## When to reach for it
Expand All @@ -32,7 +32,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
[`isolate-javascript` backend](./17_isolate_javascript.md), not through just-bash's
[`worker-javascript` 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 All @@ -55,7 +55,7 @@ Reach for the container backend when the agent runs `npm`, a real language runti
agent code
│ Workers RPC
host DO ─── Workspace ─── WorkerBackend
host DO ─── Workspace ─── WorkerShellBackend
│ env.LOADER.get(loaderId, codeCallback)
│ .getEntrypoint("ShellWorker")
Expand Down Expand Up @@ -158,7 +158,7 @@ they already handle.

## Fetcher factory escape hatch

`WorkerBackend` is source-agnostic. The common case takes
`WorkerShellBackend` is source-agnostic. The common case takes
`{ loader, workspace, ctx }` and builds the loader callback
itself. For deployments that need a different Fetcher source — a
Workers service binding, a Workers-for-Platforms dispatch
Expand Down Expand Up @@ -219,7 +219,7 @@ export class MyAgent extends DurableObject<Env> {
storage: ctx.storage,
sessionId: ctx.id.toString(),
artifacts: { binding: env.ARTIFACTS },
backends: [new WorkerBackend(/* ... */)],
backends: [new WorkerShellBackend(/* ... */)],
});
}
}
Expand All @@ -241,7 +241,7 @@ network-bound `git` subcommands do. See

## Example

`examples/worker/` is a single wrangler project that mirrors
`examples/worker-shell/` is a single wrangler project that mirrors
`examples/container/` beat for beat:

- One `wrangler.jsonc` with the Durable Object, an R2 mount at
Expand All @@ -250,15 +250,15 @@ network-bound `git` subcommands do. See
`/c/<name>/file/...` and `/c/<name>/exec` routes the container
example also exposes).
- No Dockerfile, no build script. The shell bundle ships with
`@cloudflare/computer/backends/worker` as `SHELL_MODULES`
`@cloudflare/computer/backends/worker-shell` as `SHELL_MODULES`
(a record of module name → source covering the entry plus
every code-split chunk); the backend hands the whole record
to the Loader callback itself.

The DO's backend wiring fits in three lines:

```ts
new WorkerBackend({
new WorkerShellBackend({
loader: env.LOADER,
workspace: { binding: "ContainerExample", id: ctx.id.toString() },
ctx,
Expand Down
4 changes: 2 additions & 2 deletions docs/13_git_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> [!NOTE]
> This doc describes shipped code in `packages/computer/src/git/`
> and the `git` custom command in
> `packages/computer/src/backends/worker/`. Everything below
> `packages/computer/src/backends/worker-shell/`. Everything below
> works today.

`workspace.git` is a major typed surface on `Workspace`, alongside `fs`, `runtime`, Assets, and Artifacts. It is opt-in: pass `createGitClient()` from `@cloudflare/computer/git` as `WorkspaceOptions.git` to enable it. Git runs every operation against the local SQLite-backed VFS through `isomorphic-git`, so a
Expand Down Expand Up @@ -1068,7 +1068,7 @@ commands receive the live host stub the shell already reached,
so they share its lifetime without refetching.

```ts
import { ShellWorker, defineGitCommand } from "@cloudflare/computer/backends/worker";
import { ShellWorker, defineGitCommand } from "@cloudflare/computer/backends/worker-shell";
import { type CustomCommand } from "just-bash";

class MyShell extends ShellWorker {
Expand Down
2 changes: 1 addition & 1 deletion docs/14_assets_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ client when constructing the `Workspace`:
```ts
const ws = new Workspace({
storage: ctx.storage,
backends: [new WorkerBackend(/* ... */)],
backends: [new WorkerShellBackend(/* ... */)],
assets: (ws) => createAssets({ ws, bucket: env.ASSETS, s3: { bucket: "agent-assets" }, env }),
});
```
Expand Down
4 changes: 2 additions & 2 deletions docs/15_artifacts_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> [!NOTE]
> This doc describes shipped code in
> `packages/computer/src/artifacts/` and the `artifacts` custom
> command in `packages/computer/src/backends/worker/`.
> command in `packages/computer/src/backends/worker-shell/`.

[Cloudflare Artifacts](https://developers.cloudflare.com/artifacts/)
is versioned, Git-speaking repository storage. A Worker reaches it
Expand Down Expand Up @@ -250,7 +250,7 @@ export class MyAgent extends DurableObject<Env> {
storage: ctx.storage,
sessionId: ctx.id.toString(),
artifacts: { binding: env.ARTIFACTS },
backends: [new WorkerBackend(/* ... */)],
backends: [new WorkerShellBackend(/* ... */)],
});
}
}
Expand Down
22 changes: 11 additions & 11 deletions docs/16_code_execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ The selected backend defines how it interprets `source`.
| Backend | Source language | Intended use |
| --- | --- | --- |
| `container-shell` | shell command | Full Linux, native binaries, installed packages, processes |
| `isolate-shell` | just-bash command | Fast text tools and Workspace Git without a Container |
| `isolate-javascript` | ECMAScript module | Isolated structured JavaScript with trusted Workspace modules |
| `worker-shell` | just-bash command | Fast text tools and Workspace Git without a Container |
| `worker-javascript` | ECMAScript module | Isolated structured JavaScript with trusted Workspace 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: "isolate-javascript",
backend: "worker-javascript",
});

handle.id;
await handle.kill();

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

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

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. `isolate-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. `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.

`isolate-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 `isolate-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 `worker-javascript`.

## 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 IsolateJavaScriptBackend({
id: "isolate-javascript-readonly",
new WorkerJavaScriptBackend({
id: "worker-javascript-readonly",
loader: env.LOADER,
access: "read",
});

new IsolateJavaScriptBackend({
id: "isolate-javascript",
new WorkerJavaScriptBackend({
id: "worker-javascript",
loader: env.LOADER,
access: "read-write",
});
Expand Down
14 changes: 7 additions & 7 deletions docs/17_isolate_javascript.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Isolate JavaScript runtime

`IsolateJavaScriptBackend` runs an ECMAScript module in a fresh Cloudflare Dynamic Worker:
`WorkerJavaScriptBackend` runs an ECMAScript module in a fresh Cloudflare Dynamic Worker:

```ts
import { Workspace } from "@cloudflare/computer";
import { IsolateJavaScriptBackend } from "@cloudflare/computer/backends/javascript";
import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";

const workspace = new Workspace({
storage: ctx.storage,
waitUntil: ctx.waitUntil.bind(ctx),
backends: [
new IsolateJavaScriptBackend({
new WorkerJavaScriptBackend({
loader: env.LOADER,
root: "/workspace",
access: "read-write",
Expand Down Expand Up @@ -40,7 +40,7 @@ const handle = await workspace.runtime.exec(
}
`,
{
backend: "isolate-javascript",
backend: "worker-javascript",
input: { value: 21 },
encoding: "utf8",
},
Expand Down Expand Up @@ -70,7 +70,7 @@ await workspace.fs.writeFile(
await workspace.runtime.exec(
`import task from "./task.js"; export default task;`,
{
backend: "isolate-javascript",
backend: "worker-javascript",
cwd: "/workspace",
input: { value: 42 },
},
Expand All @@ -96,7 +96,7 @@ Host calls have a caller-visible deadline, controlled by `maxHostCallMs` and def
Bare imports are installed at backend construction, not passed on individual executions:

```ts
new IsolateJavaScriptBackend({
new WorkerJavaScriptBackend({
loader: env.LOADER,
modules: {
"tar-stream": TAR_STREAM_BUNDLE,
Expand Down Expand Up @@ -165,4 +165,4 @@ Console output is bounded but currently buffered in the Dynamic Worker and publi

## Trusted integrations

A host can configure additional reserved capability modules through `IsolateJavaScriptBackend.trustedModules`; these modules are fixed when the backend is constructed and cannot be supplied or replaced by caller source.
A host can configure additional reserved capability modules through `WorkerJavaScriptBackend.trustedModules`; these modules are fixed when the backend is constructed and cannot be supplied or replaced by caller source.
Loading
Loading