Skip to content
Sandboxes

Sandboxes Overview

A sandbox gives the agent a filesystem and a shell. chat() alone can only talk about code.

A sandbox gives the agent a real computer to work in: a cloned repo, a shell, and processes. The agent runs inside it, and its edits, commands, and tool calls stream back to you like any other chat() run.

Try it

This runs a Grok Build agent in a Docker container. You need Docker running and an XAI_API_KEY.

  1. Install the packages:
shell
npm i @tanstack/ai @tanstack/ai-grok-build @tanstack/ai-sandbox @tanstack/ai-sandbox-docker
  1. Save this as agent.mts:
ts
import { chat } from '@tanstack/ai'
import { GROK_CLI_INSTALL_COMMAND, grokBuildText } from '@tanstack/ai-grok-build'
import {
  createSecrets,
  defineSandbox,
  defineWorkspace,
  githubRepo,
  withSandbox,
} from '@tanstack/ai-sandbox'
import { dockerSandbox } from '@tanstack/ai-sandbox-docker'

const repoSandbox = defineSandbox({
  id: 'repo-agent',
  provider: dockerSandbox({ image: 'node:22' }),
  workspace: defineWorkspace({
    source: githubRepo({ repo: 'TanStack/ai' }),
    setup: [GROK_CLI_INSTALL_COMMAND],
    secrets: createSecrets({
      XAI_API_KEY: process.env.XAI_API_KEY ?? '',
    }),
  }),
})

const stream = chat({
  threadId: 'overview-demo',
  adapter: grokBuildText('grok-build'),
  messages: [{ role: 'user', content: 'List the packages in this repo.' }],
  middleware: [withSandbox(repoSandbox)],
})

for await (const chunk of stream) {
  if (chunk.type === 'TEXT_MESSAGE_CONTENT') process.stdout.write(chunk.delta)
}
  1. Run it with npx tsx agent.mts.

The agent clones the repo into a container, reads it, and streams its answer to your terminal. Your host filesystem stays untouched.

For a full walkthrough that fixes a bug and prints the diff, go to Quick Start.

How it works

A sandboxed run has three parts. You can change one without changing the others.

PartWhat it decidesYou pick it with
ProviderWhere the agent runs: your host, a container, a microVM, or a cloud VM.A provider such as dockerSandbox, sbxSandbox, or localProcessSandbox. See Providers.
WorkspaceWhat the agent sees: the repo, the package manager, the setup commands, and the secrets.defineWorkspace({ ... }). See Workspace.
Harness adapterWhich agent runs, and how its output turns into chat chunks.grokBuildText, claudeCodeText, codexText, opencodeText, or acpCompatible. See Harnesses.

defineSandbox() binds a provider and a workspace into one reusable definition. You can also add a policy, a lifecycle, and hooks. withSandbox(definition) is the chat() middleware that turns the sandbox on for a run.

A run goes through three steps:

plaintext
chat({ adapter: grokBuildText(), middleware: [withSandbox(repoSandbox)] })
  |
  |- withSandbox.setup     get a sandbox: resume it, or restore a snapshot, or create and bootstrap
  |- adapter.chatStream    start `grok` INSIDE the sandbox, stream its events back as AG-UI chunks
  '- withSandbox.onFinish  snapshot or destroy, as the lifecycle says

Every harness adapter declares requires: [SandboxCapability]. If no middleware gives it a sandbox, chat() fails at the call site. A coding agent never runs without a place to run.

The provider decides where the agent runs, not how it signs in. The default authMode is 'api-key'. Set 'host' when the machine already has a CLI login. See Harness Auth.

When to use a sandbox

Use a sandbox when the agent must act on a real codebase:

  • Issue triage and bug-fix bots. Clone the repo, reproduce the bug, find the cause, and post the findings or a draft fix.
  • PR review. Check out a branch, run the test and lint scripts, and comment on the results.
  • Build and preview. Let the agent scaffold or change an app, start the dev server, and give the user a live preview URL. See Cloudflare and the examples/sandbox-* apps.
  • Evals and benchmarks. Run an agent against a fixture repo with a known bug, then make sure the diff is correct.
  • Coding copilots that must run code, edit files, and run commands.

If the model only needs to read code that you already have in memory, you do not need a sandbox. A normal chat() with tools is enough.

Pick the next piece

Start here:

Add these when you need them:

  • Tools: give the agent your own app tools.
  • Policy: allow, ask, or deny what the agent runs.
  • Lifecycle & Snapshots: reuse a sandbox and skip setup on the next run.
  • Events: stream file edits and tool calls to a UI.

For production:

The Sandboxes (Advanced) group in the sidebar has the rest: the run journal, takeover, reaping, provisioning, observability, Cloudflare, and the provider details.

Example apps

  • examples/sandbox-web: a "build me an app" agent on Docker with durable runs. It scaffolds an app, starts the dev server, and gives back a live preview URL. The run continues after a refresh or a closed tab, and Stop cancels the agent.
  • examples/sandbox-cloudflare: the same idea at the edge. You pick the harness for each run in the UI.
  • examples/ts-react-chat at /repo-report: clone TanStack/ai, pick the harness and the auth mode (host or api-key), and read a typed report from useChat().final. See Harness Agents.