Skip to content

Commit d6ac72d

Browse files
authored
refactor!: remove remote runtime package (#43)
1 parent 1fa0edc commit d6ac72d

50 files changed

Lines changed: 97 additions & 1641 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/tidy-v1-api-surface.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
"@execbox/core": minor
33
"@execbox/quickjs": minor
4-
"@execbox/remote": minor
54
---
65

7-
Tighten the pre-1.0 public API surface by keeping low-level core helpers out of the main `@execbox/core` entrypoint, removing unsupported QuickJS runner subpath exports, and keeping runner-side remote endpoint types with `@execbox/quickjs/remote-endpoint`.
6+
Tighten the pre-1.0 public API surface by keeping low-level core helpers out of the main `@execbox/core` entrypoint and removing unsupported QuickJS runner subpath exports. The v1 runtime surface is now inline QuickJS plus worker-hosted QuickJS.

AGENTS.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
- `execbox` is a Node.js 22+ npm workspace that publishes the `@execbox/*` package family.
66
- Core source lives under `packages/*/src`, tests live under `packages/*/__tests__`, runnable examples live under `examples/`, and the public docs site lives under `docs/`.
7-
- The workspace currently contains `@execbox/core`, `@execbox/quickjs`, and `@execbox/remote`.
7+
- The workspace currently contains `@execbox/core` and `@execbox/quickjs`.
88
- Keep changes aligned with existing package boundaries. Prefer changing the owning package instead of introducing cross-package shortcuts.
99

1010
## Setup Commands
@@ -30,8 +30,9 @@
3030

3131
- For most code changes, run `npm run format:check`, `npm run lint`, `npm run typecheck`, `npm test`, and `npm run build`.
3232
- If you change package exports, manifest fields, or published type-resolution behavior, also run `npm run package:check`.
33-
- If you change the public API of any entrypoint listed in `scripts/workspace-entrypoints.ts`, including `@execbox/core/runtime` and `@execbox/quickjs/remote-endpoint`, also run `npm run api:check`.
34-
- If you change docs site content, navigation, or VitePress config, also run `npm run docs:build`.
33+
- If you change the public API of any entrypoint listed in `scripts/workspace-entrypoints.ts`, including `@execbox/core/runtime`, also run `npm run api:check`.
34+
- If you change examples or runtime guidance, also run `npm run examples`.
35+
- If you change docs site content, navigation, or Starlight/Astro config, also run `npm run docs:build`.
3536
- If you touch execution boundaries, timeout handling, abort propagation, schema validation, or log/memory controls, also run `npm run test:security`.
3637

3738
## Security Notes
@@ -51,6 +52,6 @@
5152
## Useful References
5253

5354
- Start with `README.md` for the package map.
54-
- Use `docs/getting-started.md` for install and example expectations.
55-
- Use `docs/security.md` and `docs/architecture/README.md` before changing execution boundaries or runtime claims.
55+
- Use `docs/src/content/docs/getting-started.md` for install and example expectations.
56+
- Use `docs/src/content/docs/security.md` and `docs/src/content/docs/architecture/index.md` before changing execution boundaries or runtime claims.
5657
- For the human-oriented contribution workflow, see `CONTRIBUTING.md`.

CONTRIBUTING.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ This guide is for both humans and coding agents. Agent-specific operating instru
2121

2222
- General code changes: `npm run format:check`, `npm run lint`, `npm run typecheck`, `npm test`, and `npm run build`
2323
- Package export, manifest, or published type-resolution changes: `npm run package:check`
24+
- Example or runtime guidance changes: `npm run examples`
2425
- Docs site changes: `npm run docs:build`
2526
- Security or execution-boundary changes: `npm run test:security`
2627

2728
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.
2829

29-
- 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`
30+
- Public API changes to any entrypoint listed in `scripts/workspace-entrypoints.ts`, including `@execbox/core/runtime`: run `npm run api:check`
3031
- Put security-focused specs under `packages/*/__tests__/security/`; `npm run test:security` runs those grouped suites.
3132

3233
## Changesets

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@ Portable code execution for [Model Context Protocol](https://modelcontextprotoco
66

77
[![License](https://img.shields.io/github/license/aallam/execbox?style=flat-square)](https://github.com/aallam/execbox/blob/main/LICENSE)
88
[![Docs](https://img.shields.io/badge/docs-site-0ea5e9?style=flat-square)](https://execbox.aallam.com)
9-
[![Packages](https://img.shields.io/badge/packages-3-111827?style=flat-square)](#package-map)
9+
[![Packages](https://img.shields.io/badge/packages-2-111827?style=flat-square)](#package-map)
1010

1111
</div>
1212

13-
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.
13+
Execbox turns host tool catalogs into callable guest namespaces, supports MCP wrapping on both sides of the boundary, and lets you run guest JavaScript through inline QuickJS or worker-hosted QuickJS.
1414

1515
## Package Map
1616

1717
| Package | npm | What it is for |
1818
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
1919
| [`@execbox/core`](./packages/core/) | [![npm](https://img.shields.io/npm/v/%40execbox%2Fcore?style=flat-square)](https://www.npmjs.com/package/@execbox/core) | Core execution contract, provider resolution, MCP adapters, and runtime/protocol subpaths |
2020
| [`@execbox/quickjs`](./packages/quickjs/) | [![npm](https://img.shields.io/npm/v/%40execbox%2Fquickjs?style=flat-square)](https://www.npmjs.com/package/@execbox/quickjs) | QuickJS executor for inline and worker hosts |
21-
| [`@execbox/remote`](./packages/remote/) | [![npm](https://img.shields.io/npm/v/%40execbox%2Fremote?style=flat-square)](https://www.npmjs.com/package/@execbox/remote) | Advanced transport-backed executor for app-owned runtime boundaries |
2221

2322
## Examples
2423

benchmarks/results.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,3 @@ This suite only measures the parent Node process.
139139
### What this snapshot does not prove
140140

141141
- It does not prove exact throughput rankings for every workload or host. The concurrency and tool-call suites are still sensitive to local scheduler noise.
142-
- It does not measure `RemoteExecutor`, because remote performance depends on the caller-owned transport and remote runtime deployment.

docs/astro.config.mjs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ export default defineConfig({
4343
label: "MCP Provider",
4444
slug: "architecture/execbox-mcp-and-protocol",
4545
},
46-
{
47-
label: "Remote Runner",
48-
slug: "architecture/execbox-remote-workflow",
49-
},
5046
],
5147
},
5248
{
@@ -64,10 +60,6 @@ export default defineConfig({
6460
label: "Protocol",
6561
slug: "architecture/execbox-protocol-reference",
6662
},
67-
{
68-
label: "Runner Specification",
69-
slug: "architecture/execbox-runner-specification",
70-
},
7163
],
7264
},
7365
],

docs/src/content/docs/architecture/execbox-core.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ The resolved provider also carries two maps:
7171

7272
## Guest Code Normalization
7373

74-
Executors do not evaluate arbitrary snippets directly. Runtime implementers import `normalizeCode()` from `@execbox/core/runtime` to turn model- or user-produced text into a consistent async function body.
74+
Executors normalize snippets before evaluation. Runtime implementers import `normalizeCode()` from `@execbox/core/runtime` to turn model- or user-produced text into a consistent async function body.
7575

7676
That normalization handles:
7777

@@ -129,7 +129,7 @@ interface Executor {
129129
}
130130
```
131131

132-
The core package intentionally does not decide where the code runs. It only defines what the runtime must honor.
132+
The core package defines what every runtime must honor while executor packages decide where code runs.
133133

134134
```mermaid
135135
sequenceDiagram
@@ -194,12 +194,11 @@ Executors are responsible for their own runtime-specific classification rules, b
194194

195195
## Why the Core Stays Small
196196

197-
The core package does not own QuickJS, worker threads, process boundaries, or transport mechanics. That separation keeps the core useful for:
197+
The core package stays focused on provider, execution, MCP, runtime-helper, and protocol contracts. That separation keeps the core useful for:
198198

199199
- direct in-process runtimes
200200
- worker-backed runtimes
201201
- MCP wrapper servers
202-
- remote execution models
203202

204203
The consequence is deliberate separation between:
205204

docs/src/content/docs/architecture/execbox-executors.md

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,31 @@
11
---
22
title: Execbox Executors
3-
description: Compare inline QuickJS, worker-hosted QuickJS, and remote executor trade-offs.
3+
description: Compare inline QuickJS and worker-hosted QuickJS trade-offs.
44
---
55

66
This page explains how the available executors differ and what trade-offs they make.
77

88
## Executor Comparison
99

10-
| Executor or mode | Runtime boundary | Tool bridge style | Main strengths | Main constraints |
11-
| --------------------------------------- | ------------------------------------- | ------------------------------- | ------------------------------------------------ | ----------------------------------------------- |
12-
| `QuickJsExecutor` | Fresh in-process QuickJS runtime | Shared runner callback | No native addon, simple install, default backend | Still in-process |
13-
| `QuickJsExecutor` with `host: "worker"` | Worker thread + fresh QuickJS runtime | Shared host session + messages | Hard-stop worker termination, pooled by default | Still same OS process; ephemeral mode is slower |
14-
| `RemoteExecutor` | App-defined remote transport boundary | Shared host session + transport | Same API across a remote boundary | You own transport/runtime deployment |
10+
| Executor or mode | Runtime boundary | Tool bridge style | Main strengths | Main constraints |
11+
| --------------------------------------- | ------------------------------------- | ------------------------------ | ------------------------------------------------ | ----------------------------------------------- |
12+
| `QuickJsExecutor` | Fresh in-process QuickJS runtime | Shared runner callback | No native addon, simple install, default backend | Still in-process |
13+
| `QuickJsExecutor` with `host: "worker"` | Worker thread + fresh QuickJS runtime | Shared host session + messages | Hard-stop worker termination, pooled by default | Still same OS process; ephemeral mode is slower |
1514

1615
```mermaid
1716
flowchart LR
1817
HOST["Host application"]
1918
QJS["QuickJsExecutor"]
2019
QJSRT["QuickJS runtime"]
21-
REM["RemoteExecutor"]
22-
REMRT["Remote runner"]
2320
WQJS["QuickJsExecutor\nhost: worker"]
2421
THREAD["Worker thread"]
2522
RUNNER["core runner semantics"]
26-
PROTO["@execbox/core/protocol<br/>messages + host session"]
23+
PROTO["@execbox/core/protocol<br/>worker messages + host session"]
2724
WQJSRT["QuickJS runtime in worker"]
2825
2926
HOST --> QJS --> QJSRT
30-
HOST --> REM --> REMRT
3127
HOST --> WQJS --> THREAD --> WQJSRT
3228
QJS --> RUNNER
33-
REM --> PROTO
34-
REMRT --> RUNNER
3529
WQJS --> PROTO
3630
THREAD --> RUNNER
3731
```
@@ -43,11 +37,11 @@ flowchart LR
4337
That design gives QuickJS two useful properties:
4438

4539
- the runtime semantics are centralized in one runner implementation
46-
- the same guest/tool-call model can be reused behind worker-hosted and remote transport boundaries
40+
- the same guest/tool-call model can be reused behind worker-hosted execution
4741

4842
## Worker-Hosted QuickJS
4943

50-
`QuickJsExecutor` with `host: "worker"` uses a worker thread for lifecycle isolation, but it does not invent a second scripting model. It loads the same QuickJS session runner used by the inline QuickJS executor, reuses the shared QuickJS protocol endpoint inside the worker, and uses the shared `@execbox/core/protocol` host session on the parent side. By default it keeps a worker shell warm between executions; `mode: "ephemeral"` switches to a fresh worker per execution.
44+
`QuickJsExecutor` with `host: "worker"` uses a worker thread for lifecycle isolation while keeping the same scripting model as inline QuickJS. It loads the same QuickJS session runner used by the inline QuickJS executor, reuses the shared QuickJS protocol endpoint inside the worker, and uses the shared `@execbox/core/protocol` host session on the parent side. By default it keeps a worker shell warm between executions; `mode: "ephemeral"` switches to a fresh worker per execution.
5145

5246
```mermaid
5347
sequenceDiagram
@@ -70,19 +64,18 @@ sequenceDiagram
7064

7165
The available executors expose the same public result shape, but they enforce limits differently.
7266

73-
| Concern | QuickJS inline | Remote | QuickJS host: worker |
74-
| ------------------- | ----------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
75-
| Timeout | QuickJS interrupt/deadline handling | Shared host-session timeout + remote cancel + transport teardown | Shared host-session timeout + worker cancellation + worker termination backstop |
76-
| Memory | QuickJS runtime memory limit | Remote runtime decides the hard boundary; execbox still forwards limits | QuickJS memory limit inside worker, optional worker resource limits as backstop |
77-
| Abort to host tools | Abort signal passed through core callback | Abort signal passed through shared host session | Abort signal passed through shared host session |
78-
| Log capture | Captured inside runner | Captured inside the remote runner and returned over the transport boundary | Captured inside worker-side QuickJS runner |
67+
| Concern | QuickJS inline | QuickJS host: worker |
68+
| ------------------- | ----------------------------------------- | ------------------------------------------------------------------------------- |
69+
| Timeout | QuickJS interrupt/deadline handling | Shared host-session timeout + worker cancellation + worker termination backstop |
70+
| Memory | QuickJS runtime memory limit | QuickJS memory limit inside worker, optional worker resource limits as backstop |
71+
| Abort to host tools | Abort signal passed through core callback | Abort signal passed through shared host session |
72+
| Log capture | Captured inside runner | Captured inside worker-side QuickJS runner |
7973

8074
## Security and Operational Trade-offs
8175

82-
- All executor modes provide defense-in-depth measures, not standalone hard hostile-code boundaries.
76+
- All executor modes provide defense-in-depth measures around guest execution.
8377
- QuickJS is the easiest operational default and has the cleanest shared runtime story.
84-
- Remote execution keeps the same executor API while moving the runtime behind an app-defined boundary, but execbox deliberately does not ship the network stack for you.
85-
- Worker-hosted QuickJS improves lifecycle isolation and hard-stop behavior, but not process-level trust isolation.
78+
- Worker-hosted QuickJS improves lifecycle isolation and hard-stop behavior inside the host process.
8679

8780
## Pooled QuickJS Shells
8881

@@ -99,7 +92,7 @@ Pooling is implemented at the host-shell layer, not at the QuickJS runtime layer
9992
- `@execbox/core/protocol` exposes a small bounded async `createResourcePool()` helper that owns reusable shells, idle eviction, and `prewarm()` / `dispose()` support.
10093
- Worker-hosted `QuickJsExecutor` pools `Worker` shells. Each shell owns one long-lived transport wrapper plus one attached QuickJS protocol endpoint.
10194
- 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.
102-
- Concurrency therefore comes from pool size, not from multiplexing several executions through one shell.
95+
- Concurrency comes from pool size: each shell handles one active execution at a time.
10396

10497
At execution time the flow is:
10598

@@ -116,7 +109,7 @@ If all shells are busy and the pool is already at `maxSize`, the next `acquire()
116109
### Reuse And Eviction Rules
117110

118111
- Successful executions return the shell to the pool.
119-
- Normal guest/runtime/tool failures also return the shell, because they do not imply a poisoned host shell.
112+
- Normal guest/runtime/tool failures also return the shell, because the host shell remains reusable after those outcomes.
120113
- `timeout` and `internal_error` results evict the shell, because those outcomes mean the worker or transport state may no longer be trustworthy.
121114
- Idle pooled shells are evicted after `idleTimeoutMs`, down to `minSize`.
122115
- `dispose()` tears down the executor-owned pool and any idle shells it still owns.
@@ -125,13 +118,7 @@ If all shells are busy and the pool is already at `maxSize`, the next `acquire()
125118

126119
In pooled mode, a worker can exit before the host session subscribes to close events. The pooled transport wrappers retain the first close reason and replay it to later `onClose(...)` subscribers, so an early shell death still resolves as `internal_error` instead of hanging the execution.
127120

128-
### What Is Not Pooled
129-
130-
- `QuickJsExecutor` stays in-process and ephemeral because there is no expensive transport shell to reuse.
131-
- `RemoteExecutor` stays transport-factory based and ephemeral because transport ownership belongs to the caller.
132-
133121
## Choosing an Executor
134122

135123
- Choose `QuickJsExecutor` when you want the default backend with the least operational friction.
136-
- 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.
137124
- 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.

0 commit comments

Comments
 (0)