- MCP Server ToolsUpdated
- Managed MCP with chat()Updated
- Manual MCPUpdated
- MCP Type GenerationUpdated
- MCP Client InputUpdated
- MCP Server Tools: AdvancedNew
- MCP EventsNew
- MCP AppsUpdated
- Serve Tools over HTTPUpdated
- Serve Resources and PromptsUpdated
- Ask for InputUpdated
- Draft Text from a ToolUpdated
- MCP Server TasksUpdated
- MCP Server AuthUpdated
- MCP Server SessionsUpdated
- MCP Server on stdioUpdated
Persistence (Advanced)
- GenerationsUpdated
- Realtime Voice ChatUpdated
- Text-to-SpeechUpdated
- TranscriptionUpdated
- Transcription: AdvancedNew
- Voice CreationUpdated
- Audio RecordingUpdated
- Audio GenerationUpdated
- Image GenerationUpdated
- Image Generation: AdvancedNew
- Video GenerationUpdated
- Video Generation: AdvancedNew
- Live GenerationUpdated
- World GenerationUpdated
- Generation HooksUpdated
- Build your first harnessUpdated
- Host optionsNew
- Send and show mediaUpdated
- Connect clientsUpdated
- Write a client in any languageNew
- Access and tenantsNew
- Run in the terminalUpdated
- Deploy a harnessUpdated
- Send inputs safelyUpdated
- Run a tool without a model
- Durable sessionsUpdated
- Run background work on workersNew
- List, rename, and fork sessionsUpdated
- Lifecycle and retentionNew
- Run side effects onceUpdated
- Wait for a personNew
- Build on the session logUpdated
- Control how a turn endsUpdated
- Store settings per threadUpdated
- Compact a long sessionUpdated
- Fork and reset a threadUpdated
- One log for a session treeUpdated
- Write a pluginUpdated
- Track usage and costUpdated
- Ask before risky tool callsUpdated
- Give your agent coding toolsUpdated
- Sandbox and extend the coding toolsUpdated
- Run the coding tools for many threadsNew
- Undo a turnUpdated
- Build a coding agentUpdated
- Delegate to coding agentsUpdated
- Switch between agent profilesUpdated
- Auth and connectorsUpdated
- Share a thread between peopleUpdated
- Connect model providersUpdated
- Build your own UIUpdated
- Code mode in a harnessUpdated
- Work until a goal is metUpdated
- Run agents from a harnessUpdated
- Hand off a conversationNew
- Add skillsUpdated
- Use MCP serversUpdated
- Give your agent a computerNew
- Use from any MCP clientUpdated
- Use a harness from an editor (ACP)Updated
- OverviewUpdated
- Quick StartUpdated
- ProvidersUpdated
- HarnessesUpdated
- Harness AuthUpdated
- WorkspaceUpdated
- ToolsUpdated
- PolicyUpdated
- Lifecycle & SnapshotsUpdated
- Portable SnapshotsUpdated
- Keep Files After ReloadUpdated
- Save a Named VersionUpdated
- Branch From a VersionUpdated
- Send a Frozen FileUpdated
- Let the Agent Save and ForkUpdated
- Pick Which Files to KeepUpdated
- What a Snapshot StoresUpdated
- Instance DurabilityUpdated
- Durable RunsUpdated
- EventsUpdated
Sandboxes (Advanced)
- Runtime ContextUpdated
- Bring Your Own KeyUpdated
- Keep Keys on the ServerNew
- Debug LoggingUpdated
- Multimodal ContentUpdated
- Files APIUpdated
- Per-Model Type SafetyUpdated
- Runtime Adapter SwitchingUpdated
- Tree-ShakingUpdated
- Extend AdapterUpdated
- Extend Adapter: AdvancedNew
- Typed Pre-Configured OptionsUpdated
- Test with a Fake ModelUpdated
- Prompt CachingUpdated
- Mid-Conversation ChangesUpdated
- Approval Flow ProcessingUpdated
Quick Start
This guide runs a Grok Build agent in Docker. The agent clones a repo, fixes a bug, and the script prints the git diff.
You need:
- Docker, running.
- An XAI_API_KEY.
- A public GitHub repo with a bug. The samples use owner/buggy-app. Replace it with your repo.
1. Install the packages#
npm i @tanstack/ai @tanstack/ai-grok-build @tanstack/ai-sandbox @tanstack/ai-sandbox-dockerpnpm add @tanstack/ai @tanstack/ai-grok-build @tanstack/ai-sandbox @tanstack/ai-sandbox-dockeryarn add @tanstack/ai @tanstack/ai-grok-build @tanstack/ai-sandbox @tanstack/ai-sandbox-dockerbun add @tanstack/ai @tanstack/ai-grok-build @tanstack/ai-sandbox @tanstack/ai-sandbox-docker- @tanstack/ai: the chat() pipeline.
- @tanstack/ai-grok-build: the Grok Build harness adapter.
- @tanstack/ai-sandbox: defineSandbox, defineWorkspace, and withSandbox.
- @tanstack/ai-sandbox-docker: the Docker provider. It runs the agent in a container.
2. Write the agent script#
Save this as fix-bug.mts:
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: 'bug-fixer',
provider: dockerSandbox({ image: 'node:22' }),
workspace: defineWorkspace({
// Where the code comes from. A shallow clone by default.
source: githubRepo({ repo: 'owner/buggy-app' }),
packageManager: 'pnpm',
// These commands run once, when the sandbox is new.
setup: [GROK_CLI_INSTALL_COMMAND, 'corepack enable', 'pnpm install'],
// Put into the sandbox env. Never saved to snapshots, stores, or logs.
secrets: createSecrets({
XAI_API_KEY: process.env.XAI_API_KEY ?? '',
}),
}),
lifecycle: { reuse: 'thread', snapshot: 'after-setup', keepAlive: '30m' },
})
const stream = chat({
threadId: 'bug-fix-1',
adapter: grokBuildText('grok-build'),
messages: [
{ role: 'user', content: 'The tests fail. Find the bug and fix it.' },
],
middleware: [withSandbox(repoSandbox)],
})
for await (const chunk of stream) {
if (chunk.type === 'TEXT_MESSAGE_CONTENT') {
process.stdout.write(chunk.delta)
}
if (chunk.type === 'CUSTOM' && chunk.name === 'file.changed') {
console.log('\n--- diff ---\n')
console.log(chunk.value.diff)
}
}- provider is where the agent runs. Here it is a Docker container.
- workspace is what the agent sees: the cloned repo, the Grok CLI, and the installed dependencies.
- lifecycle keeps one sandbox per thread. It also takes a snapshot after setup, so only the first run pays for the clone and the install.
- threadId names the sandbox. The next run with the same threadId uses the same container.
3. Run it#
XAI_API_KEY=your-key npx tsx fix-bug.mtsYou see the agent's text as it works. When the run ends, you see the diff of every file it changed. The agent cloned the repo, found the bug, and edited the files, all inside the container.
How it works#
- grokBuildText declares that it needs a sandbox. withSandbox(repoSandbox) gives it one.
- withSandbox resumes the sandbox for threadId, or creates it and runs setup.
- The adapter starts grok inside the sandbox. Its events come back as normal chat() chunks.
- When the run ends, the Grok Build adapter sends a file.changed event with the git diff of the working tree.
To learn more about each piece:
- Workspace: package manager detection, parallel setup steps, and clone depth.
- Events: every event a harness run sends.
- Lifecycle & Snapshots: reuse and snapshots.
No Docker? Run on your host#
The local-process provider runs the agent directly on your host. It gives no isolation, but it is the fastest loop for development.
npm i @tanstack/ai-sandbox-local-processpnpm add @tanstack/ai-sandbox-local-processyarn add @tanstack/ai-sandbox-local-processbun add @tanstack/ai-sandbox-local-processThis sample uses the grok login on your machine, so the grok CLI must be installed on your host.
import { chat } from '@tanstack/ai'
import { grokBuildText } from '@tanstack/ai-grok-build'
import {
defineSandbox,
defineWorkspace,
githubRepo,
withSandbox,
} from '@tanstack/ai-sandbox'
import { localProcessSandbox } from '@tanstack/ai-sandbox-local-process'
const repoSandbox = defineSandbox({
id: 'bug-fixer',
provider: localProcessSandbox({
scrubEnv: ['XAI_API_KEY', 'GROK_API_KEY'],
}),
workspace: defineWorkspace({
source: githubRepo({ repo: 'owner/buggy-app' }),
setup: ['corepack enable', 'pnpm install'],
}),
lifecycle: { reuse: 'thread' },
})
const stream = chat({
adapter: grokBuildText('composer-2.5', { authMode: 'host' }),
messages: [
{ role: 'user', content: 'The tests fail. Find the bug and fix it.' },
],
threadId: 'thread-1',
middleware: [withSandbox(repoSandbox)],
})
for await (const chunk of stream) {
if (chunk.type === 'TEXT_MESSAGE_CONTENT') process.stdout.write(chunk.delta)
}- authMode: 'host' tells the adapter to use your grok login.
- scrubEnv removes API keys that the host process inherited. If those keys stay, they override the login.
On a CI runner there is no browser login. There, set authMode: 'api-key' and pass XAI_API_KEY as a workspace secret. See Harness Auth.
Want a microVM? Use Docker Sandboxes#
sbxSandbox() runs the agent in a hypervisor microVM, not in a container.
- Install Docker Sandboxes so that sbx is on your PATH:
- macOS: brew trust docker/tap, then brew install docker/tap/sbx.
- Windows: turn on HypervisorPlatform, then winget install -h Docker.sbx.
- Debian or Ubuntu: curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh, then apt-get install docker-sbx. Add your user to the kvm group.
- Run sbx login.
- Change repoSandbox in fix-bug.mts:
import {
createSecrets,
defineSandbox,
defineWorkspace,
githubRepo,
} from '@tanstack/ai-sandbox'
import { sbxSandbox } from '@tanstack/ai-sandbox-docker'
const repoSandbox = defineSandbox({
id: 'bug-fixer',
provider: sbxSandbox({
allowNetwork: ['*.npmjs.org', 'registry.npmjs.org'],
}),
workspace: defineWorkspace({
source: githubRepo({ repo: 'owner/buggy-app' }),
setup: ['pnpm install'],
secrets: createSecrets({
XAI_API_KEY: process.env.XAI_API_KEY ?? '',
}),
}),
lifecycle: { reuse: 'thread' },
})allowNetwork lets pnpm install reach the npm registry. A known adapter such as grok-build also adds its model API host.
sbxSandbox() always clones a Git repo into the VM. It does not take snapshots. It resumes a sandbox by its name.
Run a full example app#
examples/sandbox-web is a complete app. It is a "build me an app" agent (Claude Code on Docker) with runs that continue after a refresh. It scaffolds an app in the sandbox, starts the dev server, and streams back a live preview URL.
examples/sandbox-cloudflare runs a coding agent at the edge. You pick Claude Code, Codex, or Grok Build for each run in the UI.
Next, pick one: