Skip to main content
You have code you didn’t write, from an LLM, from a user-submitted form, from a third-party plugin, and you want to actually run it, capture stdout and stderr, and not let it touch anything important. Sandboxes are built for this.

When to use this recipe

  • Running snippets an LLM produced as part of a tool-use loop.
  • Evaluating user-submitted answers in a coding interview or learning product.
  • Sandboxing third-party plugins or untrusted webhook payloads that happen to contain code.
  • A “scratch interpreter” backend for an internal tool.

Prerequisites

  • A Brimble account with API access enabled (paid plan, API key from the profile drawer).
  • The TypeScript, Python, or Go SDK installed (see SDKs).
  • BRIMBLE_SANDBOX_KEY set in your environment.

Recipe

The key options here are egress: { mode: "deny_all" } (no outbound network), oneShot: true (auto-destroy when the main process exits), and a tight timeout_seconds on the exec call. Together they give you a single-use, networkless, time-bounded executor.

What’s happening

  1. create. Blocks until the sandbox is ready, so the next call can run immediately.
  2. egress: { mode: "deny_all" }. Outbound network is denied. The sandbox can’t curl external services, exfiltrate data, or pivot. Inbound calls from the Brimble API (your exec, your file ops) still work. (blockOutbound: true is the legacy equivalent.)
  3. oneShot: true. When the main process exits, the sandbox auto-destroys. You don’t have to remember to clean up.
  4. destroyTimeout: "30m". A backstop: even if oneShot misfires (the process never returns, hangs in a loop), the sandbox is gone after 30 minutes.
  5. Small specs. 0.5 vCPU equivalent, 512 MB memory, 2 GB ephemeral disk. Pick a size that matches the work; the sandbox is hard-capped at these limits.
  6. timeout_seconds: 30. Wall-clock cap on the exec itself. The process is killed at the limit and you get a non-zero exit code.
  7. try / finally plus destroy. Belt and suspenders. The oneShot flag should already handle cleanup, but if the SDK call itself fails before the process can exit, the explicit destroy ensures we don’t leave an idle sandbox running.

Variations

  • Use runCode with language: "node" for JavaScript snippets. Pick a Node-friendly template like node-22.
  • Capture larger output by lifting timeout_seconds and increasing specs.memory and specs.disk. The exec result is fully buffered; very large stdout streams should be written to a file inside the sandbox and downloaded with getFile instead.
  • Reuse a sandbox for many calls by dropping oneShot: true and calling runCode repeatedly. Cheaper per-call (no provisioning latency) but you’re responsible for cleanup.
  • Provide read-only inputs by pre-uploading files with putFile before the runCode call. The snippet can read them at known paths.
  • Surface failures cleanly by mapping non-zero exit_code to your own error type. Non-zero doesn’t throw, the SDK returns a normal result with the exit code and stderr.

Next steps

Last modified on July 1, 2026