Package Exports
- @acp-kit/core
- @acp-kit/core/node
Readme
ACP Kit
ACP Kit is a runtime for building applications on top of the Agent Client Protocol.
It launches an ACP agent process, manages the protocol connection, handles authentication, exposes host adapters for permissions / files / terminals, and turns raw session/update traffic into normalized turn, message, reasoning, and tool events. Your application chooses an agent profile, attaches a host, opens a session, and consumes stable events.
Why ACP Kit:
- Stable events over messy
session/update. Per-message, per-tool, per-turn events with correlation ids (messageId,toolCallId,turnId) — drive UI state and transcripts without parsing raw protocol traffic. - Lifecycle is handled for you. Cross-platform process spawn, startup diagnostics,
auth_requiredretry,session.errorsurfacing, vendor_metapass-through, multiple sessions over one agent process. - Six common agents, one import.
import { ClaudeCode, GitHubCopilot, CodexCli, GeminiCli, QwenCode, OpenCode } from '@acp-kit/core'— or drive any other ACP-capable agent via a customAgentProfile.
Install
npm install @acp-kit/coreRequires Node.js >= 20.11 and a reachable ACP agent CLI on PATH.
Quick Start
import { createAcpRuntime, ClaudeCode } from '@acp-kit/core';
await using acp = createAcpRuntime({
agent: ClaudeCode,
host: {
requestPermission: async () => 'allow_once',
chooseAuthMethod: async ({ methods }) => methods[0]?.id ?? null,
},
});
await using session = await acp.newSession({ cwd: process.cwd() });
session.on({
messageDelta: (e) => process.stdout.write(e.delta),
toolStart: (e) => console.log(`\n[tool ${e.toolCallId}] ${e.title ?? e.name}`),
toolEnd: (e) => console.log(`[tool ${e.toolCallId}] ${e.status}`),
turnCompleted: (e) => console.log(`\n(turn ${e.turnId} done: ${e.stopReason})`),
});
await session.prompt('Summarize this repository.');session.on(...) accepts a camelCase handler map (shown above), a single 'tool.start'-style event type for one listener, or 'event' for the full union. Each callback is type-narrowed. See Getting Started for the full event vocabulary, multi-session use, and how to debug startup / auth failures.
Examples
The repository ships with five runnable examples under examples/. Each one is a standalone npm package that installs the published @acp-kit/core from npm:
| Example | Runs without an agent installed | What it shows |
|---|---|---|
quick-start/ |
No | Minimal single-prompt script. |
pair-programming/ |
No | Two sessions in one runtime as AUTHOR + REVIEWER, looping until the reviewer says APPROVED. |
mock-runtime/ |
Yes | Self-contained mock ACP server. Use this to see the full event flow without installing an agent. |
real-agent-cli/ |
No | Interactive CLI driver for real agents (copilot, claude, codex, gemini, qwen, opencode) with prompts for auth and permission decisions. |
web-daemon/ |
No | Tiny node:http + Server-Sent Events demo: POST a prompt, stream normalized events back to a browser. |
cd examples/mock-runtime
npm install
npm startSee examples/README.md for details.
What ACP Kit Does
flowchart TB
P["Your Product<br/>(editor extension · desktop shell · web daemon · CLI)"]
K["<b>ACP Kit</b><br/>process spawn · auth · session lifecycle<br/>event normalization · host adapters"]
S["@agentclientprotocol/sdk<br/>JSON-RPC framing · typed payloads"]
A["ACP Agent CLI<br/>(Claude · Copilot · Codex · Gemini · Qwen · OpenCode)"]
P -- normalized events --> K
K -- uses --> S
S -- stdio --> AWithout ACP Kit, every product that wants to host an ACP agent has to write the same plumbing: pick the right CLI for the platform, spawn it without breaking on Windows shells or login envs, surface stderr when it fails to start, run initialize, retry session/new after auth_required, expose host capabilities only when the application actually backs them, parse session/update notifications into something a UI can render, and decide when a turn is really done.
ACP Kit packages all of that behind createAcpRuntime({...}).newSession({ cwd }) (or the runOneShotPrompt one-shot helper). The agent stays a regular ACP server; your application stays a regular consumer of typed events. See Architecture for the layer breakdown.
API Overview
RuntimeSession emits normalized RuntimeSessionEvents: stable per-message, per-tool, and per-turn events with correlation ids (messageId, toolCallId, turnId). They drive transcripts, UI state, and multi-agent orchestration. If you need raw protocol traffic (debuggers, protocol bridges), composeWireMiddleware / normalizeWireMiddleware let you observe the exact JSON-RPC frames.
Create the runtime with an agent profile and a host that implements only the capabilities your application backs:
import {
createAcpRuntime,
ClaudeCode,
type RuntimeHost,
type AgentProfile,
} from '@acp-kit/core';
await using acp = createAcpRuntime({
agent: ClaudeCode, // built-in constant, or a custom AgentProfile literal
host: {
requestPermission: async (req) => 'allow_once',
chooseAuthMethod: async ({ methods }) => methods[0]?.id ?? null,
// readTextFile / writeTextFile / createTerminal+friends are advertised to
// the agent only when you provide them. See docs/api-overview.md.
} satisfies RuntimeHost,
});Then open a session, subscribe to events, send prompts:
await using session = await acp.newSession({ cwd: '/path/to/workspace' });
session.on({
messageDelta: (e) => process.stdout.write(e.delta),
toolStart: (e) => console.log(`[tool ${e.toolCallId}] ${e.title ?? e.name}`),
toolEnd: (e) => console.log(`[tool ${e.toolCallId}] ${e.status}`),
turnCompleted: (e) => console.log(`done: ${e.stopReason}`),
});
const result = await session.prompt('Refactor utils.ts'); // Promise<PromptResult>
await session.cancel(); // optional: cancel the in-flight turn
// session and runtime are disposed automatically by `await using`Lifecycle helpers: acp.shutdown() (explicit teardown), acp.reconnect() (drop the agent process and reconnect), session.setMode(modeId) / session.setModel(modelId) (switch mid-session when the agent advertises options). One-shot helper: runOneShotPrompt({ agent, cwd, prompt }) yields RuntimeSessionEvents and disposes everything when iteration completes.
The full surface is exported from a single entry point: @acp-kit/core. See API Overview for the complete RuntimeHost, AcpRuntime, RuntimeSession, and RuntimeSessionEvent reference.
Supported ACP Agents
ACP Kit can drive any agent that speaks the Agent Client Protocol over stdio. Six agents ship as named constants you import and pass as agent: <Constant>:
| Agent | Constant |
|---|---|
| Claude Code | ClaudeCode |
| GitHub Copilot | GitHubCopilot |
| Codex CLI | CodexCli |
| Gemini CLI | GeminiCli |
| Qwen Code | QwenCode |
| OpenCode | OpenCode |
The runtime treats every agent uniformly: features like
session/load,setMode,setModel,session/list, file system, and terminal capabilities are forwarded to whichever agent advertises them in itsinitializeresponse. Inspectacp.agentCapabilitiesafter the runtime is ready to see exactly what a given agent CLI version supports.
To override one field on a built-in profile (e.g. agent: { ...ClaudeCode, env: { ANTHROPIC_API_KEY } }) or to drive a brand-new agent via a custom AgentProfile literal, see Supported Agents for per-agent details (command/args, login flow, known quirks).
How It Compares to @agentclientprotocol/sdk
ACP Kit is built on top of @agentclientprotocol/sdk, not as a replacement.
@agentclientprotocol/sdkis the protocol toolkit. It gives youClientSideConnection,ndJsonStream, typed request/response/notification payloads, and JSON-RPC framing — once you already have a connection to an ACP server.- ACP Kit is the client runtime. It launches the agent, manages the connection lifecycle, runs auth, exposes host adapters, normalizes raw protocol updates into stable events, and tracks turn state.
The protocol layer underneath stays exactly @agentclientprotocol/sdk. ACP Kit does not fork it, replace it, or hide it — it depends on it as a regular npm dependency. For the full layered diagram and side-by-side code comparison, see SDK vs Runtime.
Compatibility
| Dependency | Version |
|---|---|
@agentclientprotocol/sdk |
^0.18 |
| Node.js | >= 20.11 (matches the package's engines field; CI tests Node 20 and 22) |
| TypeScript (consumers) | >= 5.2 (for using / await using syntax) |
| OS | Windows, macOS, Linux |
ACP Kit aims to track the latest stable @agentclientprotocol/sdk minor release. Breaking changes in the SDK will be matched by a minor or major bump in @acp-kit/core while v0.x is in effect.
Status
ACP Kit is experimental (v0.x). The public API may change between minor versions until v1.0; every breaking change is called out in CHANGELOG.md. See docs/migration-plan.md for incremental adoption.
Documentation
- Getting Started — install, first session, common failures
- API Overview — complete
RuntimeHost,AcpRuntime,RuntimeSession, and event reference - Supported Agents — per-agent command, login, known quirks
- SDK vs Runtime — the boundary between the official SDK and ACP Kit
- Architecture — runtime layers and design principles
- Package Plan — why ACP Kit ships as a single package today
- Migration Plan — incremental adoption path for existing ACP products
Development
npm install # install workspace deps (packages/core only)
npm run build # tsc -b packages/core
npm test # vitest runTo try an example: cd examples/mock-runtime && npm install && npm start.
Contributions are welcome. Please open an issue to discuss non-trivial changes before sending a PR.