# Agent Client Protocol Python Sdk > The helpers under`acp.contrib`package recurring patterns we saw in integrations such as Toad, kimi-cli, and Gemini. Keep in mind they are experimental—APIs can still shift as we learn. Use this page --- # Source: https://github.com/agentclientprotocol/python-sdk/blob/main/docs/contrib.md # Experimental Contrib Modules The helpers under `acp.contrib` package recurring patterns we saw in integrations such as Toad, kimi-cli, and Gemini. Keep in mind they are experimental—APIs can still shift as we learn. Use this page as a menu: - **`session_state.SessionAccumulator`** — build a canonical, immutable snapshot of every session update so UIs can render tool calls and plans without re-implementing state machines. - **`tool_calls.ToolCallTracker` + `permissions.PermissionBroker`** — coordinate streamed tool call updates and permission prompts from one place. ## SessionAccumulator (`acp.contrib.session_state`) **Use it when:** you need a live, merged view of `SessionNotification` events (e.g. tool calls, plan entries, user/agent messages) to drive UI widgets. **Key capabilities** - `SessionAccumulator.apply(notification)` reconciles `tool_call` and `tool_call_update` payloads, even if the start event arrives late. - `snapshot()` returns an immutable `SessionSnapshot` Pydantic model containing the plan, current mode, commands, and ordered message history. - `subscribe(callback)` lets you push snapshots into stores or UI components whenever state changes. - Automatic reset on session-change (toggle with `auto_reset_on_session_change`). > Tip: Create one accumulator per UI controller. Feed every raw `SessionNotification` into it and render from `snapshot.tool_calls` / `snapshot.user_messages` instead of mutating state manually. ## ToolCallTracker & PermissionBroker (`acp.contrib.tool_calls`, `acp.contrib.permissions`) **Use them when:** your agent runtime synthesises tool call IDs, streams arguments, and prompts the user for approval. The helpers centralise the bookkeeping so you don’t juggle raw Pydantic models. - `ToolCallTracker.start()/progress()/append_stream_text()` emits canonical `ToolCallStart` / `ToolCallProgress` updates and keeps an in-memory view via `view()` or `tool_call_model()`. - `PermissionBroker.request_for()` wraps `requestPermission` RPCs. It reuses tracker state (or a provided `ToolCall`), lets you append extra content, and defaults to Approve / Approve for session / Reject options. - `default_permission_options()` exposes that canonical option triple if you need to customise it. > Tip: Keep one tracker near the agent event loop. Emit notifications through it and share the tracker with `PermissionBroker` so permission prompts always match the latest tool call state. ## Design Guardrails To stay aligned with the ACP schema, the contrib layer follows a few rules: - Schema data classes continue to live in `acp.schema`. Contrib helpers clone them with `.model_copy(deep=True)` before mutation. - The core runtime never imports contrib modules implicitly—you opt in when they help. - Helpers focus on painful bookkeeping (tool call aggregation, permission UX) and leave product-specific policy to your application. Try the contrib modules, then open an issue or PR with feedback so we know which APIs should graduate into the stable surface. --- # Source: https://github.com/agentclientprotocol/python-sdk/blob/main/docs/index.md Agent Client Protocol # Agent Client Protocol SDK (Python) Ship ACP-compatible agents and clients in Python without rebuilding JSON-RPC transports or schema models. This SDK mirrors each ACP release so your integrations stay interoperable with editors, CLIs, and hosted clients. ## Install & verify ```bash pip install agent-client-protocol # or uv add agent-client-protocol ``` Next steps live in the [Quickstart](quickstart.md): launch the echo agent, wire it to Zed (or another ACP client), and exercise the programmatic spawn helpers. ## ACP at a glance - ACP is the stdio protocol that lets “clients” (editors, shells, CLIs) orchestrate AI “agents.” - Sessions exchange structured payloads (`session/update`, permission prompts, tool calls) defined in the upstream schema. - Matching the schema version keeps your Python integrations compatible with tools such as Zed, Gemini CLI, or kimi-cli. ## SDK building blocks - `acp.schema`: generated Pydantic models that validate every payload against the canonical specification. - `acp.agent` / `acp.client`: async base classes, JSON-RPC supervision, and lifecycle orchestration. - `acp.helpers`: builders for content blocks, tool calls, permissions, and notifications. - `acp.contrib`: experimental utilities (session accumulators, permission brokers, tool call trackers) harvested from production deployments. - `examples/`: runnable agents, clients, duet demos, and the Gemini CLI bridge. ## Quick links | Need | Link | | --- | --- | | Quickstart walkthrough | [quickstart.md](quickstart.md) | | Real-world adopters | [use-cases.md](use-cases.md) | | Contrib helpers | [contrib.md](contrib.md) | | Releasing workflow | [releasing.md](releasing.md) | | Example scripts | [github.com/agentclientprotocol/python-sdk/tree/main/examples](https://github.com/agentclientprotocol/python-sdk/tree/main/examples) | ## Choose a path - **Just exploring?** Skim [use-cases.md](use-cases.md) to see how kimi-cli, agent-client-kernel, and others use the SDK. - **Building agents?** Copy `examples/echo_agent.py` or `examples/agent.py`, then layer in `acp.helpers` for tool calls and permissions. - **Embedding clients?** Start with `examples/client.py` or the `spawn_agent_process` / `spawn_client_process` helpers in the [Quickstart](quickstart.md#programmatic-launch). ## Reference material - [Quickstart](quickstart.md) — installation, editor wiring, and programmatic launch walkthroughs. - [Use Cases](use-cases.md) — real adopters with succinct descriptions of what they build. - [Experimental Contrib](contrib.md) — deep dives on the `acp.contrib` utilities. - [Releasing](releasing.md) — schema upgrade process, versioning policy, and publishing checklist. Need API-level details? Browse the source in `src/acp/` or generate docs with `mkdocstrings`. ## Feedback & support - Open issues or discussions on GitHub for bugs, feature requests, or integration help. - Join [GitHub Discussions](https://github.com/agentclientprotocol/python-sdk/discussions) to swap ideas. - Chat with the community on [agentclientprotocol.zulipchat.com](https://agentclientprotocol.zulipchat.com/). - Follow ACP roadmap updates at [agentclientprotocol.com](https://agentclientprotocol.com/). --- # Source: https://github.com/agentclientprotocol/python-sdk/blob/main/docs/migration-guide-0.7.md # Migrating to ACP Python SDK 0.7 ACP 0.7 reshapes the public surface so that Python-facing names, runtime helpers, and schema models line up with the evolving Agent Client Protocol schema. This guide covers the major changes in 0.7.0 and calls out the mechanical steps you need to apply in downstream agents, clients, and transports. ## 1. `acp.schema` models now expose `snake_case` fields - Every generated model in `acp.schema` (see `src/acp/schema.py`) now uses Pythonic attribute names such as `session_id`, `stop_reason`, and `field_meta`. The JSON aliases (e.g., `alias="sessionId"`) stay intact so over-the-wire payloads remain camelCase. - Instantiating a model or accessing response values must now use the `snake_case` form: ```python # Before (0.6 and earlier) PromptResponse(stopReason="end_turn") params.sessionId # After (0.7 and later) PromptResponse(stop_reason="end_turn") params.session_id ``` - If you relied on `model_dump()` to emit camelCase keys automatically, switch to `model_dump(by_alias=True)` (or use helpers such as `text_block`, `start_tool_call`, etc.) so responses continue to match the protocol. - `field_meta` stays available for extension data. Any extra keys that were nested under `_meta` should now be provided via keyword arguments when constructing the schema models (see section 3). ## 2. `acp.run_agent` and `acp.connect_to_agent` replace manual connection wiring `AgentSideConnection` and `ClientSideConnection` still exist internally, but the top-level entry points now prefer the helper functions implemented in `src/acp/core.py`. ### Updating agents - Old pattern: ```python conn = AgentSideConnection(lambda conn: Agent(), writer, reader) await asyncio.Event().wait() # keep running ``` - New pattern: ```python await run_agent(MyAgent(), input_stream=writer, output_stream=reader) ``` - When your agent just runs over stdio, call `await run_agent(MyAgent())` and the helper will acquire asyncio streams via `stdio_streams()` for you. ### Updating clients and tests - Old pattern: ```python conn = ClientSideConnection(lambda conn: MyClient(), proc.stdin, proc.stdout) ``` - New pattern: ```python conn = connect_to_agent(MyClient(), proc.stdin, proc.stdout) ``` - `spawn_agent_process` / `spawn_client_process` now accept concrete `Agent`/`Client` instances instead of factories that received the connection. Instantiate your implementation first and pass it in. - Importing the legacy connection classes via `acp.AgentSideConnection` / `acp.ClientSideConnection` issues a `DeprecationWarning` (see `src/acp/__init__.py:82-96`). Update your imports to `run_agent` and `connect_to_agent` to silence the warning. ## 3. `Agent` and `Client` interface methods take explicit parameters Both interfaces in `src/acp/interfaces.py` now look like idiomatic Python protocols: methods use `snake_case` names and receive the individual schema fields rather than a single request model. ### What changed - Method names follow `snake_case` (`request_permission`, `session_update`, `new_session`, `set_session_model`, etc.). - Parameters represent the schema fields, so there is no need to unpack `params` manually. - Each method is decorated with `@param_model(...)`. Combined with the `compatible_class` helper (see `src/acp/utils.py`), this keeps the camelCase wrappers alive for callers that still pass a full Pydantic request object—but those wrappers now emit `DeprecationWarning`s to encourage migration. ### How to update your implementations 1. Rename your method overrides to their `snake_case` equivalents. 2. Replace `params: Model` arguments with the concrete fields plus `**kwargs` to collect future `_meta` keys. 3. Access schema data directly via those parameters. Example migration for an agent: ```python # Before class EchoAgent: async def prompt(self, params: PromptRequest) -> PromptResponse: text = params.prompt[0].text return PromptResponse(stopReason="end_turn") # After class EchoAgent: async def prompt(self, prompt, session_id, **kwargs) -> PromptResponse: text = prompt[0].text return PromptResponse(stop_reason="end_turn") ``` Similarly, a client method such as `requestPermission` becomes: ```python class RecordingClient(Client): async def request_permission(self, options, session_id, tool_call, **kwargs): ... ``` ### Additional notes - The connection layers automatically assemble the right request/response models using the `param_model` metadata, so callers do not need to build Pydantic objects manually anymore. - For extension points (`field_meta`), pass keyword arguments from the connection into your handler signature: they arrive inside `**kwargs`. ### Backward compatibility - The change should be 100% backward compatible as long as you update your method names and signatures. The `compatible_class` wrapper ensures that existing callers passing full request models continue to work. The old style API will remain functional before the next major release(1.0). - Because camelCase wrappers remain for now, you can migrate file-by-file while still running against ACP 0.7. Just watch for the new deprecation warnings in your logs/tests. --- # Source: https://github.com/agentclientprotocol/python-sdk/blob/main/docs/quickstart.md # Quickstart Spin up a working ACP agent/client loop in minutes. Keep this page beside the terminal and check off each section as you go. Want inspiration? Hop to the [Use Cases](use-cases.md) list to see how teams like kimi-cli or Zed apply the SDK in production. ## Quick checklist | Goal | Command / Link | | ----------------------------------- | --------------------------------------------------------------------- | | Install the SDK | `pip install agent-client-protocol` or `uv add agent-client-protocol` | | Run the echo agent | `python examples/echo_agent.py` | | Point Zed (or another client) at it | Update `settings.json` as shown below | | Programmatically drive an agent | Copy the `spawn_agent_process` example | | Run tests before hacking further | `make check && make test` | ## Before you begin - Python 3.10–3.14 with `pip` or `uv` - An ACP-capable client such as Zed (recommended for validation) - Optional: the Gemini CLI (`gemini --experimental-acp`) for the bridge example ## Step 1 — Install the SDK _Install the library from PyPI or add it to your uv workspace._ ```bash pip install agent-client-protocol # or uv add agent-client-protocol ``` ## Step 2 — Launch the Echo agent _Run the provided streaming agent so clients have something to talk to._ Start the ready-made echo example; it streams text blocks back to any ACP client. Leave it running in a terminal: ```bash python examples/echo_agent.py ``` ## Step 3 — Connect from an ACP-aware client _Point a client at the script and confirm you can exchange streamed updates._ ### Zed Add an Agent Server entry in `settings.json` (Zed → Settings → Agents panel): ```json { "agent_servers": { "Echo Agent (Python)": { "command": "/abs/path/to/python", "args": [ "/abs/path/to/agentclientprotocol/python-sdk/examples/echo_agent.py" ] } } } ``` Open the Agents panel and start the session. Each message you send should be echoed back via streamed `session/update` notifications. ### Other clients Any ACP client that communicates over stdio can spawn the same script; no additional transport configuration is required. ### Programmatic launch Prefer to drive agents directly from Python? The `spawn_agent_process` helper wires stdio and lifecycle management for you: ```python import asyncio import sys from pathlib import Path from typing import Any from acp import spawn_agent_process, text_block from acp.interfaces import Client class SimpleClient(Client): async def request_permission( self, options, session_id, tool_call, **kwargs: Any ): return {"outcome": {"outcome": "cancelled"}} async def session_update(self, session_id, update, **kwargs): print("update:", session_id, update) async def main() -> None: script = Path("examples/echo_agent.py") async with spawn_agent_process(SimpleClient(), sys.executable, str(script)) as (conn, _proc): await conn.initialize(protocol_version=1) session = await conn.new_session(cwd=str(script.parent), mcp_servers=[]) await conn.prompt( session_id=session.session_id, prompt=[text_block("Hello from spawn!")], ) asyncio.run(main()) ``` `spawn_agent_process` manages the child process, wires its stdio into ACP framing, and closes everything when the block exits. The mirror helper `spawn_client_process` lets you drive an ACP client from Python as well. ## Step 4 — Extend the agent _Swap the echo demo for your own `Agent` subclass._ Create your own agent by subclassing `acp.Agent`. The pattern mirrors the echo example: ```python from acp import Agent, PromptResponse class MyAgent(Agent): async def prompt(self, prompt, session_id, **kwargs) -> PromptResponse: # inspect prompt, stream updates, then finish the turn return PromptResponse(stop_reason="end_turn") ``` Run it with `run_agent()` inside an async entrypoint and wire it to your client. Refer to: - [`examples/echo_agent.py`](https://github.com/agentclientprotocol/python-sdk/blob/main/examples/echo_agent.py) for the smallest streaming agent - [`examples/agent.py`](https://github.com/agentclientprotocol/python-sdk/blob/main/examples/agent.py) for an implementation that negotiates capabilities and streams richer updates - [`examples/duet.py`](https://github.com/agentclientprotocol/python-sdk/blob/main/examples/duet.py) to see `spawn_agent_process` in action alongside the interactive client - [`examples/gemini.py`](https://github.com/agentclientprotocol/python-sdk/blob/main/examples/gemini.py) to drive the Gemini CLI (`--experimental-acp`) directly from Python Need builders for common payloads? `acp.helpers` mirrors the Go/TS helper APIs: ```python from acp import start_tool_call, update_tool_call, text_block, tool_content start_update = start_tool_call("call-42", "Open file", kind="read", status="pending") finish_update = update_tool_call( "call-42", status="completed", content=[tool_content(text_block("File opened."))], ) ``` Each helper wraps the generated Pydantic models in `acp.schema`, so the right discriminator fields (`type`, `sessionUpdate`, and friends) are always populated. That keeps examples readable while maintaining the same validation guarantees as constructing the models directly. Golden fixtures in `tests/test_golden.py` ensure the helpers stay in sync with future schema revisions. ## Optional — Talk to the Gemini CLI _Have the Gemini CLI installed? Run the bridge to exercise permission flows._ If you have the Gemini CLI installed and authenticated: ```bash python examples/gemini.py --yolo # auto-approve permission prompts python examples/gemini.py --sandbox --model gemini-1.5-pro ``` Environment helpers: - `ACP_GEMINI_BIN` — override the CLI path (defaults to `PATH` lookup) - `ACP_GEMINI_TEST_ARGS` — extra flags forwarded during the smoke test - `ACP_ENABLE_GEMINI_TESTS=1` — opt-in toggle for `tests/test_gemini_example.py` Authentication hiccups (e.g. missing `GOOGLE_CLOUD_PROJECT`) are surfaced but treated as skips during testing so the suite stays green on machines without credentials. ## Next steps - Compare what you built with the real integrations listed on the [Use Cases](use-cases.md) page. - Explore `docs/contrib.md` for higher-level utilities like session accumulators and permission brokers. - Run `make check` / `make test` before committing changes, and regenerate schema artifacts with `make gen-all` when ACP versions advance. - Need help? Start a thread in [GitHub Discussions](https://github.com/agentclientprotocol/python-sdk/discussions) or chat with other ACP developers at [agentclientprotocol.zulipchat.com](https://agentclientprotocol.zulipchat.com/). --- # Source: https://github.com/agentclientprotocol/python-sdk/blob/main/docs/releasing.md # Releasing Every package release tracks an upstream ACP schema tag from [`agentclientprotocol/agent-client-protocol`](https://github.com/agentclientprotocol/agent-client-protocol). Follow this checklist to stay in lockstep. ## Prep checklist 1. **Choose the schema tag** (e.g. `v0.4.5`) and regenerate artifacts: ```bash ACP_SCHEMA_VERSION=v0.4.5 make gen-all ``` This refreshes `schema/` and the generated `src/acp/schema.py`. 2. **Bump the SDK version** in `pyproject.toml` (and regenerate `uv.lock` if deps moved). 3. **Run the standard gates:** ```bash make check # Ruff format/lint, type analysis, dep hygiene make test # pytest + doctests ``` 4. **Refresh docs + examples** so user-facing flows (e.g. Gemini bridge) reflect behaviour in the new schema. ## Commit & review - Keep the diff tight: regenerated schema files, version bumps, doc updates, and any required fixture refresh (goldens, RPC tests, etc.). - Use a Conventional Commit such as `release: v0.4.5`. - In the PR description, capture: - The ACP schema tag you targeted. - Output from `make check` / `make test` (and optional Gemini tests if you ran them). - Behavioural or API highlights that reviewers should focus on. ## Publish via GitHub Release Releases are automated by `on-release-main.yml` once the PR lands on `main`. 1. Draft a GitHub Release for the new tag (the UI creates the tag if missing). 2. Publishing the release triggers the workflow, which: - Syncs the tag back into `pyproject.toml`. - Builds and uploads to PyPI via `uv publish` using `PYPI_TOKEN`. - Deploys updated docs with `mkdocs gh-deploy`. No local build/publish steps are needed—just provide a clear release summary (highlights, compatibility notes, migration tips). ## Extra tips - Breaking schema bumps often mean updating `tests/test_golden.py`, `tests/test_rpc.py`, and any examples touched by new fields. - Use `make clean` if you need a fresh slate before re-running `make gen-all`. - When available, run the Gemini smoke test (`ACP_ENABLE_GEMINI_TESTS=1`, set `ACP_GEMINI_BIN`) to catch regressions early. --- # Source: https://github.com/agentclientprotocol/python-sdk/blob/main/docs/use-cases.md # Use Cases This page mirrors the quick-read style of the README/index: skim the tables, copy links, and see how others apply the SDK. For the protocol overview itself, visit the official [agent](https://agentclientprotocol.com/overview/agents) and [client](https://agentclientprotocol.com/overview/clients) guides. ## Agents | Project | What it showcases | | --- | --- | | [MoonshotAI/kimi-cli](https://github.com/MoonshotAI/kimi-cli) | A CLI-first ACP+MCP agent that helps with software dev and terminal workflows. Highlights streaming updates, permission prompts, and tool call UX. | | [MiniMax-AI/Mini-Agent](https://github.com/MiniMax-AI/Mini-Agent) | A minimal yet professional single agent demo project that showcases the core execution pipeline and production-grade features of agents. | | [OpenHands/OpenHands-CLI](https://github.com/OpenHands/OpenHands-CLI) | A lightweight, modern CLI to interact with the OpenHands agent. | | [evalstate/fast-agent](https://github.com/evalstate/fast-agent) | Define, Prompt and Test MCP enabled Agents and Workflows | ## Clients | Project | What it showcases | | --- | --- | | [wiki3-ai/agent-client-kernel](https://github.com/wiki3-ai/agent-client-kernel) | A Jupyter kernel that speaks ACP so notebooks can chat with external agents. Great reference if you’re embedding ACP in notebook tooling. | | [OhadRubin/simple-acp-client](https://github.com/OhadRubin/simple-acp-client) | A Claude Agent SDK–style Python client that wraps ACP executables with a friendly API. Use it as a starting point for bespoke clients. | ## Add your integration Shipping something with this SDK? Tell us! - Open an issue or PR with a short blurb and link. - Start a thread in [GitHub Discussions](https://github.com/agentclientprotocol/python-sdk/discussions). - Drop a note in [agentclientprotocol.zulipchat.com](https://agentclientprotocol.zulipchat.com/). We’ll keep this list current so newcomers can see what’s possible.