Standalone TypeScript helpers for connecting host applications to Agent Client Protocol agents.
Use this package when you want to launch an ACP agent from a registry id or inline distribution manifest, connect over stdio, and work with a small typed client instead of wiring JSON-RPC streams by hand.
acp-client is a good fit for:
- Node-based hosts that need to launch registry-backed ACP agents such as
codex-acp. - Hosts that want to preinstall, update, and inspect ACP agent distributions before launch.
- Hosts that already manage an ACP transport and want runtime-neutral session helpers.
- SDKs that accept either common ACP registry ids or caller-provided agent distributions.
- Integrations that want Node filesystem or terminal callbacks matching advertised ACP client capabilities.
It is not a good fit when you need:
- A full chat transcript, timeline reducer, permission UI, or persistence layer.
- Browser-native ACP transport helpers.
- A registry validator that rejects unknown ids at compile time or runtime.
- A framework-specific React, Vue, Electron, or CLI application shell.
- Runtime: Node.js 18 or newer.
- Module format: ESM.
- Peer dependency:
zodv3.25 or v4. - Transport: the high-level Node client launches stdio agents; lower-level helpers accept already-open streams.
- Registry ids remain open strings.
AcpAdapterIdimproves autocomplete for bundled ids while still accepting custom or newly published ids.
The package deliberately stays close to ACP protocol shapes. You get a typed connection/session layer, registry launch support, and optional Node host callbacks, but application policy and user experience remain host-owned.
npm install acp-client zodThis example proves the primary value path: resolve a known registry adapter, launch it over stdio, create a session, send a prompt, and close the managed process.
import { createNodeAcpClient } from "acp-client/node"
const client = await createNodeAcpClient({
agent: "codex-acp",
cwd: process.cwd(),
clientInfo: {
name: "example-client",
version: "1.0.0",
},
handler: {
async requestPermission() {
return { outcome: { outcome: "cancelled" } }
},
async sessionUpdate(params) {
console.log(params)
},
},
})
try {
const session = await client.newSession({
cwd: process.cwd(),
mcpServers: [],
})
await session.prompt("Hello from ACP")
} finally {
await client.close()
}Use acp-client for runtime-neutral client/session helpers, transport
primitives, adapter metadata, and Zod schemas:
import {
createAcpClient,
knownAcpAdapterIds,
type AcpAdapterId,
type AgentDistribution,
} from "acp-client"Use acp-client/node from Node runtimes that need to launch agents, synchronize
the ACP registry cache, manage local installs, or provide filesystem/terminal
callbacks:
import {
createAcpRegistryService,
createNodeAcpClient,
ensureAgentInstalled,
} from "acp-client/node"Use acp-client/protocol for curated ACP SDK protocol constants, request
errors, NDJSON framing, and protocol types without higher-level client helpers:
import {
PROTOCOL_VERSION,
RequestError,
type SessionNotification,
} from "acp-client/protocol"Use AcpAdapterId when downstream SDKs should autocomplete bundled registry ids
while still accepting custom registry entries:
import {
knownAcpAdapterIds,
type AcpAdapterId,
type AgentDistribution,
} from "acp-client"
export const defaultAgent = knownAcpAdapterIds[0]
export type AgentInput = AcpAdapterId | AgentDistributionknownAcpAdapterIds is generated from the bundled ACP registry fallback. Full
catalog reads go through createAcpRegistryService() from acp-client/node;
registry-backed catalog entries include display metadata such as website, icon,
source, unofficial status, and GitHub star count when available.
Managed install APIs are available from acp-client/node for hosts that want to
preinstall agents before launch, run deterministic updates, and read persisted
install status without maintaining parallel metadata:
import {
ensureAgentInstalled,
getInstalledAgent,
resolveInstalledAgentProcessSpec,
updateAgent,
} from "acp-client/node"
await updateAgent(agentDistribution, { cacheDir })
const status = await getInstalledAgent(agentDistribution.id, { cacheDir })
const processSpec = await resolveInstalledAgentProcessSpec(agentDistribution, {
cacheDir,
installIfMissing: true,
maxInstalledAgeMs: 24 * 60 * 60 * 1000,
})- docs/api.md: compact public API identifier map.
- docs/context.md: package concepts, lifecycle guidance, registry behavior, and managed install semantics.
- examples: runnable Node and inline registry examples.
- docs/windows.md: durable Windows platform notes for process, path, shell, and CI behavior.
This project is licensed under the MIT License.