# ACP SDK for Go A Go implementation of the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/) — a JSON-RPC 2.0 protocol over stdio for communication between AI agents and their clients (editors, IDEs). > Build ACP-compliant agents and clients in Go with strongly-typed schema models, stdio transport, helper builders, and runnable examples. ## Features - **Schema parity:** Type-safe Go structs for every ACP schema type, including discriminated unions for `ContentBlock`, `SessionUpdate`, `ToolCall`, and more. - **Bidirectional JSON-RPC 2.0:** Full request/response over newline-delimited stdio, with notification support for streaming updates. - **Typed connections:** `AgentSideConnection` and `ClientSideConnection` wrappers with methods matching the ACP interface. - **Subprocess transport:** `transport.Spawn` launches agent/client subprocesses with clean environment, configurable timeouts, and graceful shutdown. - **Helper builders:** `helpers.AgentMessageUpdate`, `helpers.ToolCallStartUpdate`, `helpers.ToolCallProgressUpdate`, and more for ergonomic content construction. - **Contrib utilities:** `ToolCallTracker`, `PermissionBroker`, and `SessionAccumulator` for common real-world patterns. - **Examples:** Runnable echo agent, interactive client, and agent+client duet. ## Interactive CLI The `examples/cli` directory ships a ready-to-use interactive ACP client powered by the SDK: ```bash # Build go build -o acp-cli ./examples/cli # Run a session with a local agent ./acp-cli run -- ./examples/agent # Run with any ACP-compatible agent binary ./acp-cli run -- claude-agent-acp # Pass environment variables and set working directory ./acp-cli run -- claude-agent-acp --work-dir /project --env API_KEY=xxx ``` Inside the session: - Type any message and press Enter to prompt the agent - `:cancel` — cancel the current prompt - `:exit` or `:quit` — end the session ## Install ```bash go get github.com/keepmind9/acp-sdk-go ``` ## Quick Start ### Run an Agent ```go package main import ( "context" "log" "github.com/keepmind9/acp-sdk-go/agent" "github.com/keepmind9/acp-sdk-go/core" "github.com/keepmind9/acp-sdk-go/schema" ) type MyAgent struct { *agent.Base } func (a *MyAgent) Initialize(_ context.Context, req *schema.InitializeRequest) (*schema.InitializeResponse, error) { pv := schema.ProtocolVersion(1) return &schema.InitializeResponse{ ProtocolVersion: &pv, AgentCapabilities: &schema.AgentCapabilities{}, AgentInfo: &schema.Implementation{Name: "my-agent", Version: "0.1.0"}, }, nil } func (a *MyAgent) NewSession(_ context.Context, req *schema.NewSessionRequest) (*schema.NewSessionResponse, error) { return &schema.NewSessionResponse{}, nil } func (a *MyAgent) Prompt(_ context.Context, req *schema.PromptRequest) (*schema.PromptResponse, error) { return &schema.PromptResponse{}, nil } func main() { core.RunAgent(&MyAgent{Base: &agent.Base{}}) } ``` ### Connect a Client ```go package main import ( "context" "log" "github.com/keepmind9/acp-sdk-go/client" "github.com/keepmind9/acp-sdk-go/core" "github.com/keepmind9/acp-sdk-go/schema" "github.com/keepmind9/acp-sdk-go/transport" ) type MyClient struct { *client.Base } func (c *MyClient) SessionUpdate(_ context.Context, notif *schema.SessionNotification) error { if notif.Update.AgentMessageChunk != nil { log.Printf("session update: %s", notif.Update.AgentMessageChunk.Content.Text.Text) } return nil } func main() { subprocess, err := transport.Spawn("my-agent-binary") if err != nil { log.Fatal(err) } defer subprocess.Close() conn := core.ConnectToAgent(&MyClient{Base: &client.Base{}}, subprocess) pv := schema.ProtocolVersion(1) resp, err := conn.Initialize(&schema.InitializeRequest{ ProtocolVersion: &pv, ClientCapabilities: &schema.ClientCapabilities{}, }) if err != nil { log.Fatal(err) } log.Printf("connected: agent %s", resp.AgentInfo.Name) } ``` ## Project Layout ``` acp-sdk-go/ ├── agent/ # Agent-side SDK: Agent interface, AgentSideConnection, router ├── client/ # Client-side SDK: Client interface, ClientSideConnection, router ├── contrib/ # High-level utilities: ToolCallTracker, PermissionBroker, SessionAccumulator ├── core/ # Convenience helpers: RunAgent, ConnectToAgent ├── helpers/ # Factory functions for ContentBlock, SessionUpdate, ToolCall ├── rpc/ # JSON-RPC 2.0 engine: Connection, Handler, Router, DecodeResponse ├── schema/ # All ACP data types, constants, discriminated unions ├── transport/ # Stdio transport and subprocess management └── examples/ # Runnable examples: agent, client, duet, echo_agent ``` ## Schema Code Generation The `schema/` package is auto-generated from the ACP specification. Do not edit generated files directly. ```bash make gen # download latest schema + regenerate all schema/*.go make gen-schema # regenerate from local schema.json (no download) make gen-download # download schema.json and meta.json from GitHub ``` After `make gen`, run `make fmt` to ensure the generated code is formatted. `make all` runs both. ## Testing ```bash make test # all tests with race detector make test-short # fast tests without race detector make e2e # end-to-end smoke test ``` ## Contributing Contributions are welcome. Please ensure: - `make all` passes before opening a PR (build, fmt, vet, test) - New code includes table-driven tests with `testify` - Public APIs have doc comments - Commits follow [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, `refactor:`, `opt:`, `chore:` ## License MIT License. See [LICENSE](LICENSE).