Run a Claude Code agent task through the Vercel AI SDK (ai + ai-sdk-provider-claude-code), optionally jailed in an sbx sandbox, with guaranteed lifecycle cleanup.
One generation path (streamText + claudeCode); jailing only changes where the claude process runs (via the SDK's spawnClaudeCodeProcess hook). Sandboxes are always removed — on normal exit, on error, and on SIGINT/SIGTERM.
import { runAgent } from 'agent-runner'
const result = await runAgent({
prompt: 'Build a fib.js that prints fib(30), run it, add a README.',
workdir: '/tmp/build',
model: 'sonnet',
sandbox: { image: 'docker.io/docker/sandbox-templates:claude-code' }, // omit → run locally
onEvent: (e) => e.type === 'tool' && console.log('⚙', e.name),
})
console.log(result.metrics) // { totalTokens, costUsd, toolCalls, durationMs, terminalReason, ... }runAgent(task): Promise<AgentResult>
AgentTask—{ prompt, workdir, model?, systemPrompt?, maxTurns?, sandbox?, signal?, onEvent? }.workdiris the host directory the agent works in (mounted into the sandbox when jailed).sandboxpresent → jailed; absent → local.AgentEvent—{ type: 'tool', name, input } | { type: 'text', text }streamed viaonEvent.AgentResult—{ text, sessionId, metrics }.AgentMetricsexposes what the provider reports:totalTokens/inputTokens/outputTokens,costUsd,durationMs,toolCalls,permissionDenials,terminalReason. (The provider does not expose the CLI'snum_turns, so it is not reported.)
- Local: uses your Claude Code login (
claudeonPATH). - Jailed: the sbx
claude-codetemplate providesclaude+ auth inside the sandbox; the agent's process runs there viasbx exec. Requires thesbxCLI on the host. (This jailed path runs on a host withsbx— it can't run inside another sandbox.)
Sandboxes created for a run are tracked in a scope and removed when runAgent returns or throws (await using), and synchronously on process exit / SIGINT / SIGTERM — so a killed run never leaves a sandbox behind.
runAgent takes a fully-composed task. Declaring user profiles and stacks/prompts (e.g. Next.js vs Vike vs Vike-no-scaffolder) from config files is a separate layer that will compose those into AgentTasks and call runAgent — keeping this package a single-responsibility primitive.