Spawn available local agents on an user's computer
A Vercel AI SDK provider for Claude Code, Codex, Cursor, GitHub Copilot, Gemini, OpenCode, Factory Droid, and Pi — streamed over the Agent Client Protocol.
Install
npm install spawn-agent ai
Usage
import { streamText } from "ai"; import { spawnAgent } from "spawn-agent"; const { textStream } = streamText({ model: spawnAgent("claude"), prompt: "Refactor src/auth.ts to use the new session API", }); for await (const chunk of textStream) { process.stdout.write(chunk); }
Pass settings inline at the call site, or build a pre-configured provider with createSpawnAgent:
import { generateText } from "ai"; import { spawnAgent } from "spawn-agent"; const { text } = await generateText({ model: spawnAgent("codex", { cwd: "/Users/me/project", permission: "auto-allow", mcpServers: [ { type: "stdio", name: "filesystem", command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], }, ], }), prompt: "Summarize README.md in three bullets", });
| Setting | Effect |
|---|---|
cwd |
Working directory the agent operates in. |
permission |
"auto-allow" (default) / "auto-allow-once" / "auto-reject" / "stream". |
mcpServers |
MCP server configs the agent connects to for extra tools. |
additionalDirectories |
Extra absolute paths the agent can read/write. |
systemPrompt |
Prepended to user prompts. |
inactivityTimeoutMs |
Kill the turn if the agent goes silent (default 3 min). |
Supported agents
| ID | Display name | Notes |
|---|---|---|
claude |
Claude Code | requires @agentclientprotocol/claude-agent-acp |
codex |
Codex | requires @zed-industries/codex-acp |
cursor |
Cursor Agent | native ACP |
copilot |
GitHub Copilot CLI | native ACP |
gemini |
Gemini CLI | native ACP |
opencode |
OpenCode | native ACP |
droid |
Factory Droid | native ACP |
pi |
Pi | native ACP |
For a custom ACP-speaking subprocess, use spawnAgent.fromAdapter(...).
Stateful sessions
For multi-turn conversations on a single subprocess, use createSpawnAgentSession. Each streamText call against session.model sends one session/prompt turn, so the agent's conversation memory is preserved across turns:
import { streamText } from "ai"; import { createSpawnAgentSession } from "spawn-agent"; await using session = await createSpawnAgentSession("codex"); await streamText({ model: session.model, prompt: "list TODOs" }); await streamText({ model: session.model, prompt: "now fix the highest one" }); // slash commands via providerOptions await streamText({ model: session.model, prompt: "agent client protocol", providerOptions: { spawnAgent: { command: "web" } }, });
For human-in-the-loop permission prompts, terminal handlers, and session resume, the session.agent field exposes the underlying SpawnAgent. See packages/spawn-agent/src/index.ts for the full API.
Contributing
License
MIT