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:
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-dockerSave 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)
}
}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.
To learn more about each piece:
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)
}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.
sbxSandbox() runs the agent in a hypervisor microVM, not in a container.
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.
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: