Docs · Overview

@faustine-ai/browser-sandbox

Run model-written JavaScript in the browser, in a dedicated Worker inside an opaque-origin <iframe sandbox>: no network, no DOM, no storage, only the functions you hand it, called over a private MessageChannel. Functions you mark can be held for a human before they run. A busy loop is stopped with terminate(), not hoped away.

your page                                    sandbox frame (origin "null")
┌─────────────────────────────────────┐      ┌───────────────────────────────────────┐
│ functions = defineFunctions({ … })  │      │ CSP: default-src 'none';              │
│   run here, with your session,      │      │      connect-src 'none';              │
│   your router, your storage         │◀─MC──┼─▶   worker-src blob:                  │
│                                     │      │  ┌ Worker ─────────────────────────┐  │
│ sandbox.run({ code, functions })    │      │  │ sdk.orders.list(input) → "call" │  │
│   → { status, value | error | … }   │      │  │ ES builtins, timers, console    │  │
└─────────────────────────────────────┘      │  │ no fetch / XHR / WS / DOM       │  │
                                             │  └─────────────────────────────────┘  │
                                             └───────────────────────────────────────┘
  • One door. The code sees a tree of the names you defined and nothing else. A name outside the map runs nothing.
  • Structured clone only. File and Blob cross; functions, DOM nodes and class instances do not.
  • Approval at the bridge. Mark a function approval: true and decide per call (pause) or per batch after the run was cut (collect), with a deterministic replay. The model cannot skip it.
  • Real limits. Wall clock, a busy-loop watchdog, calls per run, input and output bytes, log lines. Expiry terminates the worker.
  • Fits the AI SDK, Cloudflare codemode and TanStack AI through small adapters; no runtime dependency on any of them.
  • 8.5 KB min+gz for the core, 2.4 KB for the worker runtime, 0.5 KB for the frame relay. No dependencies.

Tested in Chromium, Firefox and WebKit on every change, including a suite of escape attempts that must all fail (see Security model).

Contents

  1. 01Why a frame and a worker
  2. 02Getting started
  3. 03Frame modessrcdoc: no server · url: a static document you serve
  4. 04Functions
  5. 05Running code
  6. 06Approvaldeny (default) · pause: one decision per call, the run waits · collect: one decision per batch, after the run was cut
  7. 07Limits and cancellation
  8. 08IntegrationsAI SDK (useChat, Chat) · Cloudflare @cloudflare/codemode · TanStack AI
  9. 09What crosses the boundary
  10. 10Security model
  11. 11Browser support, size, versioning
  12. 12API referencecreateSandbox(options): Sandbox · sandbox.run(options): Promise<RunResult> · Functions · Output · Frame (@faustine-ai/browser-sandbox/frame, also on the main entry) · Adapters · Types
  13. 13FAQ