Home

mweinbach / agent-coworker

publicmweinbach/agent-coworker
Overview Code History Branches Pull requestsIssuesInsights
main
HomeOverview Code PRsIssues

feat(workflows): add the sandboxed script runtime

2 months ago

9d74a75
Authored
mweinbach7/26/2026, 4:19:21 PM
A workflow script is model-authored, so it is untrusted input and runs behind
two boundaries that do different jobs:

- a `node:vm` context for AUTHORITY. A fresh realm has no ambient capabilities
  and confines the function-constructor chain, so
  `[].constructor.constructor("return typeof Bun")()` yields "undefined". This
  matters because bash is sandboxed by default (`mode: "workspace-write"`), so an
  in-process runner would grant more authority than the tool the model already
  has.
- a `Worker` for AVAILABILITY. `vm` cannot interrupt `while(true){}`; without a
  separate thread one such script would freeze the whole server. Startup measures
  13-16ms against agent calls that take seconds.

The realm is sealed with an allowlist rather than a denylist. A fresh Bun vm
realm ships ShadowRealm, WebAssembly, Atomics, SharedArrayBuffer, WeakRef,
FinalizationRegistry, Intl and eval, and that set grows with each engine release.
Two are not cosmetic: `new ShadowRealm()` inside a vm context panics the Bun
process (exit code 3, which terminate() cannot save you from), and Intl is an
independent clock that would silently poison journal replay.

The worker bootstrap is a string constant on purpose. `Bun.build` with splitting
drops modules referenced only as `new Worker(new URL(...))`, which would ship
broken in the packaged binary alone and never reproduce in development.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kk98XjGKJrKp5ynbiNFMFu

Parent0f2848e

7 files changed
  • src/shared/workflows.ts+48−0
  • src/workflows/compile.ts+98−0
  • src/workflows/flags.ts+15−0
  • src/workflows/scheduler.ts+59−0
  • src/workflows/schema.ts+74−0
  • src/workflows/types.ts+82−0
  • src/workflows/workerBootstrap.ts+388−0