diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 210740f..b59f9eb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -27,6 +27,7 @@ This guide is for both humans and coding agents. Agent-specific operating instru
Choose the smallest verification set that covers your change, and include the commands you ran in your PR or handoff notes when the context would help reviewers.
- Public API changes to any entrypoint listed in `scripts/workspace-entrypoints.ts`, including `@execbox/core/runtime` and `@execbox/quickjs/remote-endpoint`: run `npm run api:check`
+- Put security-focused specs under `packages/*/__tests__/security/`; `npm run test:security` runs those grouped suites.
## Changesets
diff --git a/README.md b/README.md
index be862c9..6d2fd08 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Portable code execution for [Model Context Protocol](https://modelcontextprotoco
-Execbox turns host tool catalogs into callable guest namespaces, supports MCP wrapping on both sides of the boundary, and lets you place guest JavaScript where it fits your deployment: inline, behind a worker host, or across your own remote transport.
+Execbox turns host tool catalogs into callable guest namespaces, supports MCP wrapping on both sides of the boundary, and lets you place guest JavaScript where it fits your deployment: inline QuickJS, worker-hosted QuickJS, or a remote runner behind your own transport.
## Package Map
@@ -24,6 +24,12 @@ Execbox turns host tool catalogs into callable guest namespaces, supports MCP wr
Runnable examples live in [`examples/`](./examples/) and are indexed in [`examples/README.md`](./examples/README.md).
+## Choosing a Runtime
+
+- Start with `@execbox/quickjs` for trusted code and the smallest setup.
+- Use `new QuickJsExecutor({ host: "worker" })` when you want QuickJS off the main thread with pooled worker shells.
+- Use `@execbox/remote` when your application owns a process, container, VM, or network boundary for the runtime.
+
## Docs
- [Public Docs](https://execbox.aallam.com)
diff --git a/docs/architecture/README.md b/docs/architecture/README.md
index 5f36941..cec0aa0 100644
--- a/docs/architecture/README.md
+++ b/docs/architecture/README.md
@@ -2,16 +2,16 @@
Execbox is the code-execution part of the `execbox` workspace. It turns host tool catalogs into callable guest namespaces, lets those namespaces wrap MCP tools, and uses executor backends that decide where and how guest JavaScript runs.
-This Concepts section is for two audiences:
+This Concepts section is for library users choosing how to integrate execbox:
-- Integrators choosing packages and deployment shapes
-- Contributors reasoning about package boundaries, control flow, and trade-offs
+- Start here when you need the package map, trust model, and overall flow
+- Use the deeper pages when you are choosing a runtime, wrapping MCP tools, or implementing a remote runner
## Reading Guide
- Start here for the package map, trust model, and overall flow.
- Read [execbox-core.md](./execbox-core.md) for provider resolution, execution contracts, and error handling.
-- Read [execbox-executors.md](./execbox-executors.md) for QuickJS host modes and remote execution trade-offs.
+- Read [execbox-executors.md](./execbox-executors.md) for inline QuickJS, worker-hosted QuickJS, and remote execution trade-offs.
- Read [execbox-mcp-and-protocol.md](./execbox-mcp-and-protocol.md) for MCP wrapping and where `@execbox/core/protocol` fits.
- Read [execbox-remote-workflow.md](./execbox-remote-workflow.md) for the end-to-end remote execution control flow.
- Read [execbox-protocol-reference.md](./execbox-protocol-reference.md) for the protocol message catalog and session rules.
@@ -99,4 +99,4 @@ Key implications:
## Architecture In One Paragraph
-`@execbox/core` owns the app-facing execution contract, provider resolution, MCP adapters, and the `@execbox/core/protocol` transport surface. Runtime implementers use `@execbox/core/runtime` for shared dispatch, manifest, timeout, log, and normalization helpers. `@execbox/quickjs` exposes the default runtime-specific reusable runner. Hosted `@execbox/quickjs` modes and `@execbox/remote` sit on top of `@execbox/core/protocol`, which owns the transport boundary: message shapes, shared host sessions, and reusable resource pools for transport-backed execution.
+`@execbox/core` owns the app-facing execution contract, provider resolution, MCP adapters, and the `@execbox/core/protocol` transport surface. Runtime implementers use `@execbox/core/runtime` for shared dispatch, manifest, timeout, log, and normalization helpers. `@execbox/quickjs` exposes the default runtime-specific reusable runner. Worker-hosted QuickJS and `@execbox/remote` sit on top of `@execbox/core/protocol`, which owns transport messages, shared host sessions, and reusable resource pools for transport-backed execution.
diff --git a/docs/architecture/execbox-executors.md b/docs/architecture/execbox-executors.md
index 9a8ae0f..038d3b0 100644
--- a/docs/architecture/execbox-executors.md
+++ b/docs/architecture/execbox-executors.md
@@ -1,6 +1,6 @@
# Execbox Executors
-This page explains how the available executors and QuickJS host modes differ and what trade-offs they make.
+This page explains how the available executors differ and what trade-offs they make.
## Executor Comparison
@@ -40,7 +40,7 @@ flowchart LR
That design gives QuickJS two useful properties:
- the runtime semantics are centralized in one runner implementation
-- the same guest/tool-call model can be reused behind hosted worker and remote transport boundaries
+- the same guest/tool-call model can be reused behind worker-hosted and remote transport boundaries
## Worker-Hosted QuickJS
@@ -94,7 +94,7 @@ Every `execute()` call still creates a fresh QuickJS runtime/context, reinjects
Pooling is implemented at the host-shell layer, not at the QuickJS runtime layer.
- `@execbox/core/protocol` exposes a small bounded async `createResourcePool()` helper that owns reusable shells, idle eviction, and `prewarm()` / `dispose()` support.
-- Hosted `QuickJsExecutor` pools `Worker` shells. Each shell owns one long-lived transport wrapper plus one attached QuickJS protocol endpoint.
+- Worker-hosted `QuickJsExecutor` pools `Worker` shells. Each shell owns one long-lived transport wrapper plus one attached QuickJS protocol endpoint.
- The worker entrypoint only attaches `attachQuickJsProtocolEndpoint(...)` once. That endpoint accepts one active `execute` message at a time and starts a fresh `runQuickJsSession()` for each message.
- Concurrency therefore comes from pool size, not from multiplexing several executions through one shell.
@@ -130,5 +130,5 @@ In pooled mode, a worker can exit before the host session subscribes to close ev
## Choosing an Executor
- Choose `QuickJsExecutor` when you want the default backend with the least operational friction.
-- Choose `RemoteExecutor` when you want the same execution API but need the runtime to live behind an application-defined transport boundary.
+- Choose `RemoteExecutor` when you want the same execution API but need the runtime to live behind an application-defined process, container, VM, or network boundary.
- Choose `QuickJsExecutor` with `host: "worker"` when you want the QuickJS semantics off the main thread with a hard-stop termination path and low-latency pooled reuse by default.
diff --git a/docs/architecture/execbox-mcp-and-protocol.md b/docs/architecture/execbox-mcp-and-protocol.md
index 6cf1a35..a5dbe3b 100644
--- a/docs/architecture/execbox-mcp-and-protocol.md
+++ b/docs/architecture/execbox-mcp-and-protocol.md
@@ -44,7 +44,7 @@ flowchart LR
It owns:
- the `execute`, `cancel`, `started`, `tool_call`, `tool_result`, and `done` message types
-- the shared host transport session used by hosted `@execbox/quickjs` modes and `@execbox/remote`
+- the shared host transport session used by worker-hosted `@execbox/quickjs` and `@execbox/remote`
- Node transport bootstrap helpers for worker execution
- the reusable async resource pool used by pooled worker shells
@@ -74,7 +74,7 @@ flowchart TB
subgraph TransportBacked["Transport-backed executors"]
PROTO["@execbox/core/protocol
messages + host session + resource pool"]
- HOSTED["QuickJsExecutor host modes"]
+ HOSTED["QuickJsExecutor host: worker"]
REM["RemoteExecutor"]
QJS_ENDPOINT["QuickJS protocol endpoint
worker side"]
REMOTE_ENDPOINT["Runtime-owned remote endpoint
QuickJS adapter is shipped"]
@@ -91,7 +91,7 @@ flowchart TB
## Transport-Backed Execution Flow
-The same host-session model is used for hosted QuickJS and remote execution:
+The same host-session model is used for worker-hosted QuickJS and remote execution:
```mermaid
sequenceDiagram
diff --git a/docs/architecture/execbox-protocol-reference.md b/docs/architecture/execbox-protocol-reference.md
index 08627fb..feb4e2a 100644
--- a/docs/architecture/execbox-protocol-reference.md
+++ b/docs/architecture/execbox-protocol-reference.md
@@ -2,7 +2,7 @@
This page is the message-level reference for `@execbox/core/protocol`.
-It describes the wire shapes and session semantics used by transport-backed execbox runtimes such as hosted QuickJS and remote execution. It is grounded in the shipped implementation and should be read as a practical reference, not as a formal RFC.
+It describes the wire shapes and session semantics used by transport-backed execbox runtimes such as worker-hosted QuickJS and remote execution. This is an advanced reference for runtime and remote-runner implementers; most application users should start with [Getting Started](../getting-started.md), [Executors](./execbox-executors.md), and [Security & Boundaries](../security.md).
For the higher-level control-flow explanation, read [execbox-remote-workflow.md](./execbox-remote-workflow.md). For the normative runner specification, read [execbox-runner-specification.md](./execbox-runner-specification.md).
diff --git a/docs/architecture/execbox-runner-specification.md b/docs/architecture/execbox-runner-specification.md
index 961cfef..68775c5 100644
--- a/docs/architecture/execbox-runner-specification.md
+++ b/docs/architecture/execbox-runner-specification.md
@@ -1,6 +1,6 @@
# Execbox Runner Specification
-This page defines the runner specification for transport-backed execbox runners.
+This page defines the runner specification for transport-backed execbox runners. It is an advanced reference for users implementing their own runner boundary.
Use it when you want to implement a non-TypeScript runner, such as a Go remote runner, without reverse-engineering the shipped TypeScript implementation. For the control-flow walkthrough, read [execbox-remote-workflow.md](./execbox-remote-workflow.md). For the message catalog, read [execbox-protocol-reference.md](./execbox-protocol-reference.md).
diff --git a/docs/architecture/index.md b/docs/architecture/index.md
index 1960dff..0d3ebc2 100644
--- a/docs/architecture/index.md
+++ b/docs/architecture/index.md
@@ -2,16 +2,16 @@
Execbox is the code-execution part of the `execbox` workspace. It turns host tool catalogs into callable guest namespaces, lets those namespaces wrap MCP tools, and uses executor backends that decide where and how guest JavaScript runs.
-This Concepts section is for two audiences:
+This Concepts section is for library users choosing how to integrate execbox:
-- integrators choosing packages and deployment shapes
-- contributors reasoning about package boundaries, control flow, and trade-offs
+- start here when you need the package map, trust model, and overall flow
+- use the deeper pages when you are choosing a runtime, wrapping MCP tools, or implementing a remote runner
## Reading guide
- Start here for the package map, trust model, and overall flow.
- Read [Core](/architecture/execbox-core) for provider resolution, execution contracts, and error handling.
-- Read [Executors](/architecture/execbox-executors) for QuickJS host modes and remote execution trade-offs.
+- Read [Executors](/architecture/execbox-executors) for inline QuickJS, worker-hosted QuickJS, and remote execution trade-offs.
- Read [MCP And Protocol](/architecture/execbox-mcp-and-protocol) for MCP wrapping and where `@execbox/core/protocol` fits.
- Read [Remote Workflow](/architecture/execbox-remote-workflow) for the end-to-end remote execution control flow.
- Read [Protocol Reference](/architecture/execbox-protocol-reference) for the protocol message catalog and session rules.
diff --git a/docs/getting-started.md b/docs/getting-started.md
index dd6df12..35f0989 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -1,6 +1,6 @@
# Getting Started
-Execbox works best when you start with QuickJS, get one provider flow working, and then choose a stronger boundary only when your deployment needs it.
+Execbox works best when you start with inline QuickJS, get one provider flow working, and then choose a different runtime placement only when your deployment needs it.
## Requirements
@@ -45,9 +45,11 @@ console.log(result);
## Which package should I use?
-- Use `@execbox/quickjs` first unless you already know you need a separate runtime boundary.
-- Use `new QuickJsExecutor({ host: "worker" })` when you want QuickJS off the main thread with pooled workers.
-- Use `@execbox/remote` only when your runtime already lives behind an application-owned transport.
+- Use `@execbox/quickjs` first for trusted code and the smallest setup.
+- Use `new QuickJsExecutor({ host: "worker" })` when you want QuickJS off the main thread with pooled worker shells.
+- Use `@execbox/remote` when your application owns the process, container, VM, or network boundary for the runtime.
+
+Worker-hosted QuickJS improves local lifecycle control, but it still shares the host process. Read [Security](/security) before treating any runtime placement as a production trust boundary.
## Run the examples
diff --git a/docs/index.md b/docs/index.md
index 809a59f..dec8b64 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -19,7 +19,7 @@ features:
- title: Code-first tool use
details: Let agents write code against typed tool namespaces instead of serializing every intermediate step back through tool calls.
- title: Execution boundary choice
- details: Start with inline QuickJS, move to worker hosts, or push execution behind your own remote transport.
+ details: Start with inline QuickJS, move QuickJS off the main thread, or run behind your own remote transport.
- title: MCP on both sides
details: Wrap upstream MCP tools into guest namespaces and expose execbox execution back out as MCP tools for downstream clients.
---
@@ -36,11 +36,11 @@ That split gives you one execution contract across inline QuickJS, worker-hosted
## Choose a backend
-| Backend | Package | Start here when |
-| --------------------- | ------------------ | -------------------------------------------------------------------------------- |
-| In-process QuickJS | `@execbox/quickjs` | You want the easiest install and the default development path. |
-| Worker-backed QuickJS | `@execbox/quickjs` | You want the runtime off the main thread with pooled worker reuse. |
-| Remote transport | `@execbox/remote` | You already own the transport/runtime boundary and want execbox to plug into it. |
+| Backend | Package | Start here when |
+| --------------------- | ------------------ | ------------------------------------------------------------------------------------ |
+| In-process QuickJS | `@execbox/quickjs` | You want the easiest install and the default development path. |
+| Worker-backed QuickJS | `@execbox/quickjs` | You want the runtime off the main thread with pooled worker reuse. |
+| Remote transport | `@execbox/remote` | Your application owns the process, container, VM, or network boundary for a runtime. |
## Security posture
diff --git a/docs/performance/index.md b/docs/performance/index.md
index c5d1647..97548ee 100644
--- a/docs/performance/index.md
+++ b/docs/performance/index.md
@@ -4,20 +4,20 @@ This page summarizes practical performance guidance for choosing and configuring
## Executor Comparison
-Each executor makes a different trade-off between isolation strength, startup cost, and steady-state latency.
+Each executor makes a different trade-off between runtime placement, startup cost, and steady-state latency.
-| Executor | Isolation | Relative Latency | Best For |
-| ----------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------- | --------------------------------------------------------------------- |
-| `QuickJsExecutor` | In-process QuickJS runtime | Fastest steady-state path | Trusted code and the lowest possible latency |
-| `QuickJsExecutor` (`host: "worker"`, pooled) | Worker thread shell with a fresh guest runtime per execution | Low latency after startup | General use when you want strong local isolation with good throughput |
-| `QuickJsExecutor` (`host: "worker"`, ephemeral) | Fresh worker per execution | High startup cost | Per-execution host isolation when you accept much higher latency |
-| `RemoteExecutor` | Network transport | Depends on the transport and remote host | Remote isolation, remote capacity, or remote scheduling |
+| Executor | Runtime placement | Relative Latency | Best For |
+| ----------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------- | ------------------------------------------------------------------- |
+| `QuickJsExecutor` | In-process QuickJS runtime | Fastest steady-state path | Trusted code and the lowest possible latency |
+| `QuickJsExecutor` (`host: "worker"`, pooled) | Worker thread shell with a fresh guest runtime per execution | Low latency after startup | Off-main-thread execution with good local throughput |
+| `QuickJsExecutor` (`host: "worker"`, ephemeral) | Fresh worker per execution | High startup cost | Fresh worker lifecycle per execution when higher latency is allowed |
+| `RemoteExecutor` | Caller-owned transport to a remote runner | Depends on the transport and remote host | App-owned runtime boundaries, remote capacity, or remote scheduling |
## Practical Characteristics
### Pooled executors are the default hot-path choice
-Worker-hosted `QuickJsExecutor` defaults to pooled mode. Pooling reuses the worker shell while still creating a fresh guest runtime for each execution. That keeps the host boundary in place without paying worker startup cost on every call.
+Worker-hosted `QuickJsExecutor` defaults to pooled mode. Pooling reuses the worker shell while still creating a fresh guest runtime for each execution. That keeps the off-main-thread shell warm without paying worker startup cost on every call.
If you care about request latency or throughput, start with pooled mode. Ephemeral mode is primarily an isolation choice, not a speed choice.
@@ -27,11 +27,11 @@ Tool calls still pay for host dispatch, serialization, and the round-trip back i
### First execution is different from steady state
-Fresh hosted executors are slower than steady-state pooled executors because they still need to stand up the host shell and the guest runtime. Use `prewarm()` on pooled worker hosts when you want those costs paid before traffic arrives; it warms both the outer shell and a real no-op guest execution path.
+Fresh worker shells are slower than steady-state pooled executors because they still need to stand up the shell and the guest runtime. Use `prewarm()` on pooled worker hosts when you want those costs paid before traffic arrives; it warms both the outer shell and a real no-op guest execution path.
## Pool Sizing
-Pool `maxSize` is the main throughput control for hosted worker executors.
+Pool `maxSize` is the main throughput control for worker-hosted QuickJS executors.
- `QuickJsExecutor` with `host: "worker"` starts with a CPU-aware default pool size based on available parallelism, capped at `4`.
- Size the pool to the concurrency you actually expect, not just to the default.
@@ -52,13 +52,13 @@ const executor = new QuickJsExecutor({
## Choosing An Executor
-| Priority | Recommended |
-| ---------------------------------------------- | ------------------------------------------------------ |
-| Lowest latency for trusted code | `QuickJsExecutor` |
-| Best local balance of isolation and throughput | `QuickJsExecutor` with `host: "worker"` in pooled mode |
-| Fresh host boundary every execution | `QuickJsExecutor` with a hosted `ephemeral` mode |
-| Remote isolation or remote capacity | `RemoteExecutor` |
+| Priority | Recommended |
+| --------------------------------------------- | ------------------------------------------------------ |
+| Lowest latency for trusted code | `QuickJsExecutor` |
+| Best local off-main-thread throughput | `QuickJsExecutor` with `host: "worker"` in pooled mode |
+| Fresh worker lifecycle every execution | `QuickJsExecutor` with worker `mode: "ephemeral"` |
+| App-owned runtime boundary or remote capacity | `RemoteExecutor` |
-For most applications, start with `QuickJsExecutor` and move to `host: "worker"` when you want stronger local isolation without leaving the package.
+For most applications, start with `QuickJsExecutor` and move to `host: "worker"` when you want local execution off the main thread without leaving the package.
Use `QuickJsExecutor` only for trusted code paths. See [Security & Boundaries](/security) before treating an in-process runtime as if it were a hard tenant boundary.
diff --git a/packages/core/README.md b/packages/core/README.md
index 0ef5182..525e477 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -33,6 +33,8 @@ Swap in `@execbox/remote` only when you already own the runtime transport bounda
## Runtime Implementer Surface
+Most application code can skip this section.
+
Application code should usually import from `@execbox/core`, `@execbox/core/mcp`, or `@execbox/core/protocol`.
Executor and runner packages should import shared runtime helpers from `@execbox/core/runtime` instead. That subpath contains the manifest dispatcher, runtime option defaults, timeout helpers, log formatting, code normalization, and error normalization used to keep runtime implementations aligned.
diff --git a/packages/quickjs/README.md b/packages/quickjs/README.md
index 33a5987..e275b74 100644
--- a/packages/quickjs/README.md
+++ b/packages/quickjs/README.md
@@ -65,14 +65,14 @@ await executor.prewarm();
## Advanced Imports
- `@execbox/quickjs/runner` exports the reusable QuickJS runner
-- `@execbox/quickjs/runner/protocol-endpoint` exports the low-level QuickJS protocol loop used by hosted worker integrations
+- `@execbox/quickjs/runner/protocol-endpoint` exports the low-level QuickJS protocol loop used by worker-hosted integrations
- `@execbox/quickjs/remote-endpoint` adapts the QuickJS protocol loop to `@execbox/remote` runner ports
## Operational Notes
- Each execution gets a fresh QuickJS runtime with JSON-only tool and result boundaries.
- This package is the default deployment path, not a hard security boundary for hostile or multi-tenant code.
-- If you need a stronger deployment boundary, move execution behind `@execbox/remote`.
+- If you need a stronger deployment boundary, move execution behind `@execbox/remote` and a process, container, VM, or network boundary your application owns.
## Read Next
diff --git a/packages/quickjs/src/hosted/shared.ts b/packages/quickjs/src/hosted/shared.ts
index 61304b4..5efffa0 100644
--- a/packages/quickjs/src/hosted/shared.ts
+++ b/packages/quickjs/src/hosted/shared.ts
@@ -14,12 +14,12 @@ import type {
} from "@execbox/core";
/**
- * Default grace period before a hosted shell is forcefully terminated.
+ * Default grace period before a worker-hosted shell is forcefully terminated.
*/
const DEFAULT_CANCEL_GRACE_MS = 25;
/**
- * Default pooling limits shared by the hosted QuickJS executors.
+ * Default pooling limits shared by worker-hosted QuickJS executors.
*/
const DEFAULT_POOL_OPTIONS: Required = {
idleTimeoutMs: 30_000,
@@ -29,7 +29,7 @@ const DEFAULT_POOL_OPTIONS: Required = {
};
/**
- * Minimal code used to warm a hosted shell without touching user providers.
+ * Minimal code used to warm a worker shell without touching user providers.
*/
const DEFAULT_PREWARM_CODE = "undefined";
diff --git a/packages/quickjs/src/hosted/workerHostedExecutor.ts b/packages/quickjs/src/hosted/workerHostedExecutor.ts
index 6410375..2c6b2ff 100644
--- a/packages/quickjs/src/hosted/workerHostedExecutor.ts
+++ b/packages/quickjs/src/hosted/workerHostedExecutor.ts
@@ -173,7 +173,7 @@ export class WorkerHostedQuickJsExecutor implements Executor {
private readonly warmup: Promise | undefined;
/**
- * Creates a hosted QuickJS executor that launches worker-thread shells on demand.
+ * Creates a QuickJS executor that launches worker-thread shells on demand.
*/
constructor(options: QuickJsWorkerExecutorOptions) {
this.cancelGraceMs = options.cancelGraceMs ?? DEFAULT_CANCEL_GRACE_MS;
diff --git a/packages/quickjs/src/types.ts b/packages/quickjs/src/types.ts
index fe52215..c9719ce 100644
--- a/packages/quickjs/src/types.ts
+++ b/packages/quickjs/src/types.ts
@@ -9,7 +9,7 @@ import type {
export type QuickJsExecutorHost = "inline" | "worker";
/**
- * Lifecycle modes for hosted QuickJS shells.
+ * Lifecycle modes for worker-hosted QuickJS shells.
*/
export type QuickJsHostedMode = "pooled" | "ephemeral";
@@ -43,13 +43,13 @@ export interface QuickJsWorkerExecutorOptions extends ExecutorRuntimeOptions {
/** Uses a worker thread to host each QuickJS runtime. */
host: "worker";
- /** Time to wait before forcefully tearing down a hung hosted shell. */
+ /** Time to wait before forcefully tearing down a hung worker shell. */
cancelGraceMs?: number;
- /** Whether to reuse hosted shells or spawn a fresh one per execution. */
+ /** Whether to reuse worker shells or spawn a fresh one per execution. */
mode?: QuickJsHostedMode;
- /** Pool sizing and idle-eviction settings for pooled hosted shells. */
+ /** Pool sizing and idle-eviction settings for pooled worker shells. */
pool?: ExecutorPoolOptions;
/** Optional worker thread V8 limits used as a coarse safety backstop. */
diff --git a/packages/remote/README.md b/packages/remote/README.md
index 4fcb6c8..848d9d8 100644
--- a/packages/remote/README.md
+++ b/packages/remote/README.md
@@ -10,7 +10,7 @@ Transport-backed executor for execbox. Use it when you want the execbox API on t
- you want execbox execution to live outside the application process
- you already own the network stack, process topology, or runtime placement
-- you want to keep the same provider/executor model while moving the runtime behind your own boundary
+- you want to keep the same provider/executor model while moving the runtime behind your own process, container, VM, or network boundary
## Install