Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

agent-runner

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, ... }

API

runAgent(task): Promise<AgentResult>

  • AgentTask{ prompt, workdir, model?, systemPrompt?, maxTurns?, sandbox?, signal?, onEvent? }. workdir is the host directory the agent works in (mounted into the sandbox when jailed). sandbox present → jailed; absent → local.
  • AgentEvent{ type: 'tool', name, input } | { type: 'text', text } streamed via onEvent.
  • AgentResult{ text, sessionId, metrics }. AgentMetrics exposes what the provider reports: totalTokens/inputTokens/outputTokens, costUsd, durationMs, toolCalls, permissionDenials, terminalReason. (The provider does not expose the CLI's num_turns, so it is not reported.)

Auth

  • Local: uses your Claude Code login (claude on PATH).
  • Jailed: the sbx claude-code template provides claude + auth inside the sandbox; the agent's process runs there via sbx exec. Requires the sbx CLI on the host. (This jailed path runs on a host with sbx — it can't run inside another sandbox.)

Lifecycle

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.

Composition (planned)

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.

See examples/agent-runner.