{"slug": "run-any-coding-agent-in-a-sandbox-with-one-chat-call", "title": "Run Any Coding Agent in a Sandbox, With One chat() Call", "summary": "TanStack AI released a new sandbox layer that lets developers run any coding agent in an isolated environment with a single chat() call, decoupling agent selection from runtime. The system supports multiple agents including Claude Code, Codex, and Grok Build, and multiple sandbox providers such as Docker, local processes, and cloud VMs, all swappable with one-line changes.", "body_md": "Wiring a coding agent into your own app sounds simple until you actually do it. Then you hit two walls at once: every agent CLI speaks its own protocol, and every one of them wants to run somewhere it can touch a real filesystem and a shell.\n\nSo you write a bespoke adapter for Claude Code. A different one for Codex. A third for whatever ships next quarter. And then you still have to answer the scary question: where does this thing run, and what can it reach while it runs?\n\nTanStack AI's new sandbox layer collapses both walls into one pattern. A coding agent runs **inside an isolated sandbox**, and its work streams straight back through the same chat() you already use. This post walks through how it fits together, and the part that has no equivalent anywhere else: plugging in *any* agent that speaks the Agent Client Protocol, with no dedicated package.\n\nA \"coding agent in your app\" is really two independent decisions:\n\n**Which agent runs** - Claude Code, Codex, OpenCode, Grok Build, or something newer.\n\n**Where it runs** - your laptop for dev, a container for isolation, a cloud VM or the edge for production.\n\nMost setups hard-couple those two decisions. The agent's SDK assumes a runtime, the runtime assumes an agent, and swapping either one means rewriting the integration. You end up maintaining a matrix of glue you never wanted to own.\n\nThe fix is to make both decisions **independent and swappable**, behind one interface. That is exactly what the sandbox layer does.\n\nHere is a complete, runnable shape. An agent clones a repo into a Docker sandbox, fixes a bug, and streams its work back:\n\n``` js\nimport { chat } from '@tanstack/ai'\nimport { grokBuildText } from '@tanstack/ai-grok-build'\nimport {\n  createSecrets,\n  defineSandbox,\n  defineWorkspace,\n  githubRepo,\n  withSandbox,\n} from '@tanstack/ai-sandbox'\nimport { dockerSandbox } from '@tanstack/ai-sandbox-docker'\n\nconst sandbox = defineSandbox({\n  id: 'fix-the-bug',\n  provider: dockerSandbox({ image: 'node:22' }),\n  workspace: defineWorkspace({\n    source: githubRepo({ repo: 'owner/app' }),\n    setup: ['corepack enable', 'pnpm install'],\n    secrets: createSecrets({ XAI_API_KEY: process.env.XAI_API_KEY ?? '' }),\n  }),\n})\n\nconst stream = chat({\n  adapter: grokBuildText('grok-build'),\n  messages,\n  middleware: [withSandbox(sandbox)],\n})\n```\n\nThe harness adapter (grokBuildText) declares it needs a sandbox, withSandbox() provides one, and the agent's tool calls, file edits, and reasoning come back as the same AG-UI stream chunks any other adapter produces. Your UI does not need to know a coding agent is on the other end.\n\nEverything below is a variation on this one snippet.\n\nThe provider owns isolation - *where* the agent actually runs. Every provider implements the same SandboxHandle contract, so swapping one is a one-line change to your sandbox definition:\n\n``` js\nimport { localProcessSandbox } from '@tanstack/ai-sandbox-local-process'\nimport { dockerSandbox } from '@tanstack/ai-sandbox-docker'\nimport { daytonaSandbox } from '@tanstack/ai-sandbox-daytona'\nimport { vercelSandbox } from '@tanstack/ai-sandbox-vercel'\n\nconst dev = localProcessSandbox() // your machine, fast dev loop\nconst isolated = dockerSandbox({ image: 'node:22' }) // a real container boundary\nconst cloud = daytonaSandbox() // managed cloud sandbox\nconst microvm = vercelSandbox({ runtime: 'node24' }) // managed microVM\n```\n\nThere is also a Cloudflare provider for running the agent and a live preview at the edge. The workspace, secrets, and policy you attach do not change when you swap providers - only the isolation, auth, and snapshot behavior do.\n\nThe harness decides *what* runs. The first-class adapters cover the agents most people reach for:\n\n@tanstack/ai-grok-build - grokBuildText\n\n@tanstack/ai-claude-code - claudeCodeText\n\n@tanstack/ai-codex - codexText\n\n@tanstack/ai-opencode - opencodeText\n\nSwitching agents is the other one-line change:\n\n``` js\nimport { claudeCodeText } from '@tanstack/ai-claude-code'\n\nconst stream = chat({\n  adapter: claudeCodeText('sonnet'),\n  messages,\n  middleware: [withSandbox(sandbox)],\n})\n```\n\nSame sandbox, same wiring, different agent. The two axes really are independent.\n\nFirst-class adapters are great until the agent you want does not have one. This is where most stacks stop and you go back to writing glue.\n\nTanStack AI does not. The [Agent Client Protocol](https://agentclientprotocol.com) (ACP) is a shared JSON-RPC protocol that a growing list of coding agents already speak. acpCompatible turns *any* of them into a chat() adapter, with no dedicated package. Think of it as the openaiCompatible of coding agents.\n\n``` js\nimport { acpCompatible } from '@tanstack/ai-acp'\n\nconst pi = acpCompatible({\n  name: 'pi',\n  command: ({ model, harnessCwd }) =>\n    `pi --acp -m ${model} --cwd ${harnessCwd}`,\n})\n\nconst stream = chat({\n  adapter: pi('pi-fast'),\n  messages,\n  middleware: [withSandbox(sandbox)],\n})\n```\n\nThat is the whole integration. You describe how to launch the agent's ACP server, and acpCompatible handles the session, permissions, tool bridging, and translation into the same AG-UI stream as every other adapter.\n\nThe payoff is breadth. The [ACP agents list](https://agentclientprotocol.com/get-started/agents) already includes gemini --acp, Cursor, Goose, Cline, OpenHands, Qwen Code, Kimi CLI, Pi, and dozens more. Any of them drops into a sandbox with the snippet above. Like openaiCompatible, you can declare typed models and per-call modelOptions so the whole thing stays type-checked.\n\nBecause every harness runs through the same sandbox layer, capabilities are shared rather than re-implemented per agent:\n\n**Secrets** - createSecrets() injects values into the agent's environment at create time. They are never written to snapshots or the event log.\n\n**Provisioning** - clone a repo, run setup commands, and project workspace skills (files, instructions, MCP servers) into the harness's native conventions.\n\n**Streaming** - text, reasoning, and tool activity come back as standard AG-UI chunks, so existing chat UIs render an in-sandbox agent with no changes.\n\n**Session resume** - thread a session id back through modelOptions.sessionId to continue where the agent left off.\n\n**Guardrails** - permission modes (and defineSandboxPolicy) decide what the agent may do without prompting.\n\n``` php\nflowchart LR\n  UI[\"chat() in your app\"] --> MW[\"withSandbox() middleware\"]\n  MW --> SBX[\"Sandbox: real fs + shell\"]\n  SBX --> CLI[\"Harness CLI: grok / claude / codex / any ACP agent\"]\n  CLI -->|\"ACP or stream\"| TR[\"Translate to AG-UI chunks\"]\n  TR --> UI\n```\n\nThe middleware ensures the sandbox exists, the adapter spawns the agent inside it, and the agent's protocol (ACP for the compatible path, native streams for the first-class ones) is translated back into the chunks your UI already speaks.\n\nIf you have ever wanted an agent to actually act on a real codebase - clone it, run the tests, edit files, hand back a diff - this is the shortest path there. Pick a provider, pick an agent (or bring your own ACP agent), and drive it with the chat() you already know.\n\nRead the [sandbox docs](https://tanstack.com/ai/latest/docs/sandbox/overview) to get an agent fixing a bug in a sandbox on your laptop in a few minutes, then swap the provider when you are ready to ship.\n\nOne import. Any agent. Any sandbox.", "url": "https://wpnews.pro/news/run-any-coding-agent-in-a-sandbox-with-one-chat-call", "canonical_source": "https://tanstack.com/blog/run-coding-agents-in-a-sandbox", "published_at": "2026-06-30 12:00:00+00:00", "updated_at": "2026-06-30 14:21:06.887197+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-agents", "ai-infrastructure"], "entities": ["TanStack AI", "Claude Code", "Codex", "Grok Build", "OpenCode", "Docker", "Daytona", "Vercel"], "alternates": {"html": "https://wpnews.pro/news/run-any-coding-agent-in-a-sandbox-with-one-chat-call", "markdown": "https://wpnews.pro/news/run-any-coding-agent-in-a-sandbox-with-one-chat-call.md", "text": "https://wpnews.pro/news/run-any-coding-agent-in-a-sandbox-with-one-chat-call.txt", "jsonld": "https://wpnews.pro/news/run-any-coding-agent-in-a-sandbox-with-one-chat-call.jsonld"}}