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.
npm install spawn-agent aiimport { 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). |
| 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(...).
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.
MIT