# chuk-acp
[](https://github.com/chuk-ai/chuk-acp/actions/workflows/ci.yml)
[](https://badge.fury.io/py/chuk-acp)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/Apache-2.0)
[](https://github.com/psf/black)
[](https://github.com/astral-sh/ruff)
[](https://codecov.io/gh/chuk-ai/chuk-acp)
A Python implementation of the [Agent Client Protocol (ACP)](https://agentclientprotocol.com) - the standard protocol for communication between code editors and AI coding agents.
---
## π Table of Contents
- [Overview](#overview)
- [Why ACP?](#why-acp)
- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [CLI Tool](#cli-tool)
- [Building an Agent](#building-an-agent)
- [Building a Client](#building-a-client)
- [Core Concepts](#core-concepts)
- [Complete Examples](#complete-examples)
- [API Reference](#api-reference)
- [Protocol Support](#protocol-support)
- [Architecture](#architecture)
- [Testing](#testing)
- [Relationship to MCP](#relationship-to-mcp)
- [Contributing](#contributing)
- [License](#license)
- [Links](#links)
---
## Overview
The **Agent Client Protocol (ACP)** is to AI coding agents what the Language Server Protocol (LSP) is to programming languages. It standardizes communication between code editors/IDEs and coding agentsβprograms that use generative AI to autonomously modify code.
**chuk-acp** provides a complete, production-ready Python implementation of ACP, enabling you to:
- π¬ **Interact with agents instantly** using the CLI (`uvx chuk-acp claude-code-acp` or `echo "hello" | uvx chuk-acp client -- kimi --acp`)
- π€ **Build ACP-compliant coding agents** easily with the high-level `ACPAgent` API
- π₯οΈ **Build editors/IDEs** that can connect to any ACP-compliant agent with `ACPClient`
- π **Integrate AI capabilities** into existing development tools
- π§ͺ **Test and develop** against the ACP specification
---
## Why ACP?
### The Problem
Without a standard protocol, every AI coding tool creates its own proprietary interface, leading to:
- Fragmentation across different tools and editors
- Inability to switch agents or editors without rewriting integration code
- Duplicated effort implementing similar functionality
- Limited interoperability
### The Solution
ACP provides a **standard, open protocol** that:
- β
Enables **any agent to work with any editor**
- β
Provides **consistent user experience** across tools
- β
Allows **innovation at both the editor and agent level**
- β
Built on proven standards (JSON-RPC 2.0)
- β
Supports **async/streaming** for real-time AI interactions
Think LSP for language tooling, but for AI coding agents.
---
## Features
### π― Complete ACP Implementation
- Full support for ACP v1 specification
- All baseline methods and content types
- Optional capabilities (modes, session loading, file system, terminal)
- Protocol compliance test suite
- **MCP Servers Support**: Automatically sends empty `mcpServers: []` for compatibility with agents that require it
- **Flexible AgentInfo**: Handles agents that return incomplete initialization data
### π§ Developer-Friendly
- **CLI Tool**: Interactive command-line client for testing agents (`uvx chuk-acp`)
- **Zero Installation**: Run with `uvx` - no setup required
- **Type-Safe**: Comprehensive type hints throughout
- **Async-First**: Built on `anyio` for efficient async/await patterns
- **Optional Pydantic**: Use Pydantic for validation, or go dependency-free with fallback
- **Well-Documented**: Extensive examples and API documentation
- **Production-Ready**: Tested across Python 3.11, 3.12 on Linux, macOS, Windows
### π Flexible & Extensible
- **Multiple transports**: Stdio (with more coming)
- **Custom methods**: Extend protocol with `_meta` fields and custom methods
- **Pluggable**: Easy to integrate into existing tools
- **MCP Integration**: Seamless compatibility with Model Context Protocol
### π‘οΈ Quality & Security
- Comprehensive test coverage
- Security scanning with Bandit and CodeQL
- Type checking with mypy
- Automated dependency updates
- CI/CD with GitHub Actions
---
## Quick Start (60 Seconds!)
### π Try Without Installation
The absolute fastest way to get started - no cloning, no installation:
```bash
# 1. Download a standalone agent example
curl -O https://raw.githubusercontent.com/chuk-ai/chuk-acp/main/examples/standalone_agent.py
# 2. Run it with uvx (automatically installs chuk-acp temporarily)
uvx chuk-acp client python standalone_agent.py
# That's it! Start chatting with your agent.
```
See [QUICKSTART.md](QUICKSTART.md) for full details.
### Or Connect to External Agents
```bash
# Claude Code (requires ANTHROPIC_API_KEY)
ANTHROPIC_API_KEY=sk-... uvx chuk-acp claude-code-acp
# Kimi (Chinese AI assistant)
uvx chuk-acp client -- kimi --acp
```
**That's it!** `uvx` automatically handles installation. Perfect for quick testing.
---
## Installation
### Using uvx (Recommended for One-Off Usage)
No installation needed! `uvx` runs the CLI directly:
```bash
# Single prompt mode (interactive with stdin)
echo "Create a Python function to calculate fibonacci" | uvx chuk-acp client -- kimi --acp
# With faster validation (optional)
uvx --from 'chuk-acp[pydantic]' chuk-acp claude-code-acp
```
### Using uv (Recommended for Development)
[uv](https://github.com/astral-sh/uv) is a fast Python package installer:
```bash
# Basic installation (includes CLI)
uv pip install chuk-acp
# With Pydantic validation support (recommended for better performance)
uv pip install chuk-acp[pydantic]
# Or add to your project
uv add chuk-acp
```
### Using pip
```bash
# Basic installation (includes CLI)
pip install chuk-acp
# With Pydantic support (recommended)
pip install chuk-acp[pydantic]
```
### Development Installation
```bash
git clone https://github.com/chuk-ai/chuk-acp.git
cd chuk-acp
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install -e ".[dev,pydantic]"
```
### Requirements
- Python 3.11 or higher
- Dependencies: `anyio`, `typing-extensions`
- Optional: `pydantic` (for faster validation - works without it using fallback mechanism)
---
## Quick Start
### CLI Tool - Interactive Chat with Any Agent
The easiest way to interact with ACP agents is using the built-in CLI. Works instantly with `uvx` or after installation.
The CLI supports three modes:
1. **Agent passthrough** - For editors/tools (explicitly use `agent` subcommand)
2. **Interactive client** - For humans (explicitly use `client` subcommand)
3. **Auto-detect** - Smart mode selection (TTY = interactive, piped = passthrough)
#### Try It Now (No Installation!)
```bash
# Connect to Claude Code (requires ANTHROPIC_API_KEY)
ANTHROPIC_API_KEY=sk-... uvx chuk-acp client claude-code-acp
# Connect to Kimi agent (use -- to separate flags)
echo "hello" | uvx chuk-acp client -- kimi --acp
# Interactive mode with verbose output
echo "your question" | uvx chuk-acp --verbose client -- kimi --acp
# Interactive chat opens automatically
# Just start typing your questions!
```
#### After Installation
```bash
# Interactive client mode (explicit)
chuk-acp client python examples/echo_agent.py
# Agent passthrough mode (for editors like Zed)
chuk-acp agent python my_agent.py
# Auto-detect mode (interactive if TTY, passthrough if piped)
chuk-acp python examples/echo_agent.py
# Single prompt (requires stdin for kimi)
echo "Create a Python function to calculate factorial" | chuk-acp client -- kimi --acp
# Using a config file
chuk-acp --config examples/kimi_config.json
# With environment variables
chuk-acp client python agent.py --env DEBUG=true --env API_KEY=xyz
# Force interactive mode even when piped
chuk-acp --interactive python agent.py
# Verbose output for debugging
chuk-acp client python agent.py --verbose
```
#### Interactive Mode Commands
When in interactive chat mode, you can use these special commands:
| Command | Description |
|---------|-------------|
| `/quit` or `/exit` | Exit the client |
| `/new` | Start a new session (clears context) |
| `/info` | Show agent information and session ID |
#### Example Interactive Session
**With Claude Code:**
```bash
$ ANTHROPIC_API_KEY=sk-... uvx chuk-acp claude-code-acp
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ACP Interactive Client β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
You: Create a Python function to check if a string is a palindrome
Agent: Here's a Python function to check if a string is a palindrome:
def is_palindrome(s):
# Remove spaces and convert to lowercase
s = s.replace(" ", "").lower()
# Check if string equals its reverse
return s == s[::-1]
You: /quit
Goodbye!
```
**With Kimi:**
```bash
$ echo "What's the best way to handle async errors in Python?" | uvx chuk-acp client -- kimi --acp
Agent: [Kimi's response with thinking and detailed explanation...]
```
#### Configuration Files
Use standard ACP configuration format (compatible with Zed, VSCode, etc.):
**claude_code_config.json:**
```json
{
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "sk-..."
}
}
```
**kimi_config.json:**
```json
{
"command": "kimi",
"args": ["--acp"],
"env": {}
}
```
Then use with:
```bash
chuk-acp --config claude_code_config.json
chuk-acp --config kimi_config.json
```
#### Important: Using `--` for Agent Flags
When an agent requires flags (like `kimi --acp`), use `--` to separate chuk-acp flags from agent arguments:
```bash
# Correct - use -- separator
chuk-acp client -- kimi --acp
# Also works via config file
chuk-acp --config kimi_config.json
```
Without `--`, argparse treats `--acp` as a chuk-acp flag and fails. Using a config file avoids this issue entirely.
**π See [CLI.md](CLI.md) for complete CLI documentation and advanced usage.**
### Using with Editors (Zed, VSCode, etc.)
chuk-acp can run your custom agents in editors that support ACP, like Zed. The `agent` mode provides a passthrough that lets editors communicate directly with your agent via the ACP protocol.
#### Zed Configuration
Add this to your Zed `settings.json` (usually `~/.config/zed/settings.json`):
```json
{
"agent_servers": {
"My Custom Agent": {
"command": "uvx",
"args": [
"chuk-acp",
"agent",
"python",
"/absolute/path/to/my_agent.py"
],
"env": {}
}
}
}
```
Or using auto-detect mode (will automatically use passthrough when piped from Zed):
```json
{
"agent_servers": {
"My Custom Agent": {
"command": "uvx",
"args": [
"chuk-acp",
"python",
"/absolute/path/to/my_agent.py"
],
"env": {}
}
}
}
```
**What this does:**
- `uvx` automatically installs `chuk-acp` in a temporary environment
- `chuk-acp agent` runs in passthrough mode (just executes your agent with the ACP protocol layer)
- Your agent gets access to the `chuk-acp` package (so `from chuk_acp.agent import ACPAgent` works)
- No `--from` or `--with` flags needed!
**Example agent file** (`my_agent.py`):
```python
from typing import List
from chuk_acp.agent import ACPAgent, AgentSession
from chuk_acp.protocol.types import AgentInfo, Content
class MyAgent(ACPAgent):
def get_agent_info(self) -> AgentInfo:
return AgentInfo(name="my-agent", version="1.0.0")
async def handle_prompt(self, session: AgentSession, prompt: List[Content]) -> str:
text = prompt[0].get("text", "") if prompt else ""
return f"You said: {text}"
if __name__ == "__main__":
MyAgent().run()
```
See [`examples/zed_config.json`](examples/zed_config.json) for more configuration examples.
### The Easiest Way: ACPClient
The fastest way to get started programmatically is with the high-level `ACPClient`, which handles all protocol details automatically:
**Option A: Direct Usage**
```python
"""quickstart.py"""
import anyio
from chuk_acp import ACPClient
async def main():
# Connect to an agent - handles initialization, sessions, everything!
async with ACPClient("python", ["echo_agent.py"]) as client:
# Send a prompt and get the response
result = await client.send_prompt("Hello!")
print(f"Agent: {result.full_message}")
anyio.run(main)
```
**Option B: Using Standard ACP Configuration**
This matches the configuration format used by editors like Zed, VSCode, etc.:
```python
"""quickstart_config.py"""
import anyio
from chuk_acp import ACPClient, AgentConfig
async def main():
# Standard ACP configuration format
config = AgentConfig(
command="kimi", # Any ACP-compatible agent
args=["--acp"], # Agent-specific arguments
env={"DEBUG": "true"} # Optional environment variables
)
async with ACPClient.from_config(config) as client:
result = await client.send_prompt("Hello!")
print(f"Agent: {result.full_message}")
anyio.run(main)
```
Or load from a JSON file (like `~/.config/zed/settings.json`):
```python
from chuk_acp import load_agent_config
config = load_agent_config("~/.config/my-app/agent.json")
async with ACPClient.from_config(config) as client:
result = await client.send_prompt("Hello!")
```
**What `ACPClient` does automatically:**
- β
Starts the agent process
- β
Handles protocol initialization
- β
Creates and manages sessions
- β
Captures all notifications
- β
Cleans up resources
- β
Supports standard ACP configuration format
**Want more control?** The low-level API gives you fine-grained control over the protocol. See the examples below.
---
### Building an Agent
The fastest way to build an ACP agent is with the high-level `ACPAgent` class:
```python
"""my_agent.py"""
from typing import List
from chuk_acp.agent import ACPAgent, AgentSession
from chuk_acp.protocol.types import AgentInfo, Content
class MyAgent(ACPAgent):
"""Your custom agent implementation."""
def get_agent_info(self) -> AgentInfo:
"""Return agent information."""
return AgentInfo(
name="my-agent",
version="1.0.0",
title="My Custom Agent"
)
async def handle_prompt(
self, session: AgentSession, prompt: List[Content]
) -> str:
"""Handle a prompt - this is where your agent logic goes."""
# Extract text from prompt
text = prompt[0].get("text", "") if prompt else ""
# Your agent logic here
response = f"I received: {text}"
# Return the response
return response
if __name__ == "__main__":
agent = MyAgent()
agent.run()
```
**Run your agent:**
```bash
# Test with CLI (using uv for environment management)
uvx chuk-acp client uv run my_agent.py
# Or if chuk-acp is installed globally
chuk-acp client python my_agent.py
```
**What `ACPAgent` does automatically:**
- β
Handles all protocol messages (initialize, session/new, session/prompt)
- β
Manages sessions and routing
- β
Sends responses in correct format
- β
Error handling and logging
- β
Stdin/stdout transport
**Real example:** See [`examples/echo_agent.py`](examples/echo_agent.py) - a complete working agent in just 35 lines!
#### π Even Easier: chuk-acp-agent
For an even simpler agent-building experience, check out **[chuk-acp-agent](https://github.com/chrishayuk/chuk-acp-agent)** - an opinionated agent kit built on top of chuk-acp:
```python
from chuk_acp_agent import Agent, Context
class MyAgent(Agent):
async def on_prompt(self, ctx: Context, prompt: str):
# Session memory
count = ctx.memory.get("count", 0) + 1
ctx.memory.set("count", count)
# Stream response
yield f"Message #{count}: {prompt}\n"
if __name__ == "__main__":
MyAgent().run()
```
**Features:**
- π¦ Batteries-included: session memory, streaming helpers, MCP integration
- π― Minimal boilerplate: just implement `on_prompt()`
- π§ Context API: `ctx.memory`, `ctx.emit()`, `ctx.fs`, `ctx.terminal`
- π οΈ Built-in MCP tool support via `chuk-tool-processor`
Install: `pip install chuk-acp-agent` or see the [chuk-acp-agent docs](https://github.com/chrishayuk/chuk-acp-agent).
---
### More Examples
For more complete examples showing different use cases:
```bash
# Clone the repository
git clone https://github.com/chuk-ai/chuk-acp.git
cd chuk-acp
# Install
uv pip install -e ".[pydantic]"
# Run examples (all use the high-level ACPClient)
uv run python examples/simple_client.py # Basic single prompt
uv run python examples/quick_start.py # Multi-turn conversation
uv run python examples/config_example.py # Configuration support (Zed/VSCode format)
# Advanced: Low-level protocol examples
uv run python examples/low_level/simple_client.py # Manual protocol handling
uv run python examples/low_level/quick_start.py # Self-contained with embedded agent
uv run python examples/low_level/comprehensive_demo.py # All ACP features
```
See the [examples directory](https://github.com/chuk-ai/chuk-acp/tree/main/examples) for detailed documentation.
> **Note**: Examples are in the GitHub repository. If you installed via pip, clone the repo to access them.
### Option B: Build Your Own (10 Minutes)
Create a complete ACP client and agent from scratch.
#### Step 1: Install
```bash
uv pip install chuk-acp[pydantic]
```
#### Step 2: Create an Agent
Save this as `echo_agent.py`:
```python
"""echo_agent.py - A simple ACP agent"""
import json
import sys
import uuid
from chuk_acp.protocol import (
create_response,
create_notification,
METHOD_INITIALIZE,
METHOD_SESSION_NEW,
METHOD_SESSION_PROMPT,
METHOD_SESSION_UPDATE,
)
from chuk_acp.protocol.types import AgentInfo, AgentCapabilities, TextContent
# Read messages from stdin, write to stdout
for line in sys.stdin:
msg = json.loads(line.strip())
method = msg.get("method")
params = msg.get("params", {})
msg_id = msg.get("id")
# Route to handlers
if method == METHOD_INITIALIZE:
result = {
"protocolVersion": 1,
"agentInfo": AgentInfo(name="echo-agent", version="1.0.0").model_dump(),
"agentCapabilities": AgentCapabilities().model_dump(),
}
response = create_response(id=msg_id, result=result)
elif method == METHOD_SESSION_NEW:
session_id = f"session-{uuid.uuid4().hex[:8]}"
response = create_response(id=msg_id, result={"sessionId": session_id})
elif method == METHOD_SESSION_PROMPT:
session_id = params["sessionId"]
user_text = params["prompt"][0].get("text", "")
# Send a notification with the echo
from chuk_acp.protocol.types import SessionUpdate
session_update = SessionUpdate(
sessionUpdate="agent_message_chunk",
content=TextContent(text=f"Echo: {user_text}")
)
notification = create_notification(
method=METHOD_SESSION_UPDATE,
params={
"sessionId": session_id,
"update": session_update.model_dump(exclude_none=True),
},
)
sys.stdout.write(json.dumps(notification.model_dump()) + "\n")
sys.stdout.flush()
# Send the response
response = create_response(id=msg_id, result={"stopReason": "end_turn"})
else:
continue
sys.stdout.write(json.dumps(response.model_dump()) + "\n")
sys.stdout.flush()
```
#### Step 3: Create a Client
Save this as `my_client.py`:
```python
"""my_client.py - Connect to the echo agent using ACPClient"""
import anyio
from chuk_acp import ACPClient
async def main():
# Connect to the agent - handles everything automatically!
async with ACPClient("python", ["echo_agent.py"]) as client:
# Send a prompt and get the response
result = await client.send_prompt("Hello!")
print(f"Agent says: {result.full_message}")
if __name__ == "__main__":
anyio.run(main())
```
#### Step 4: Run It!
```bash
uv run python my_client.py
```
**Output:**
```
β Connected to echo-agent
β Session: session-a1b2c3d4
Sending: Hello!
Agent says: Echo: Hello!
β Done!
```
π **That's it!** You've built a working ACP agent and client.
### What You Learned
**Option A** showed you the fastest path - running pre-built examples.
**Option B** taught you:
- **Agents**: Read JSON-RPC from stdin, write to stdout using `create_response()` and `create_notification()`
- **Clients**: Connect via `stdio_transport`, use `send_initialize()` and `send_session_new()`, manually handle messages to capture notifications
- **Protocol flow**: Initialize β Create Session β Send Prompts (with notifications) β Get Response
- **Best practices**: Use library types (`TextContent`, `AgentInfo`) and method constants (`METHOD_INITIALIZE`)
### Next Steps
**Explore More Features:**
Check out the complete examples in the [GitHub repository](https://github.com/chuk-ai/chuk-acp/tree/main/examples):
- [simple_client.py](https://github.com/chuk-ai/chuk-acp/blob/main/examples/simple_client.py) - Clean client with notification handling
- [echo_agent.py](https://github.com/chuk-ai/chuk-acp/blob/main/examples/echo_agent.py) - Production-ready agent with error handling
- [comprehensive_demo.py](https://github.com/chuk-ai/chuk-acp/blob/main/examples/comprehensive_demo.py) - Filesystem, terminal, all ACP features
**Build Something:**
- Add file system access to your agent (see Example 3 below)
- Implement tool calls and permission requests
- Support multiple concurrent sessions
- Add streaming for long responses
**Learn More:**
- [API Reference](#api-reference) - Complete API documentation
- [Protocol Support](#protocol-support) - What's supported in ACP v1
- [ACP Specification](https://agentclientprotocol.com) - Official protocol docs
---
## Core Concepts
### The Agent-Client Model
```
βββββββββββββββ ββββββββββββββββ
β Client β βββ JSON-RPC βββ β Agent β
β (Editor) β over stdio β (AI Tool) β
βββββββββββββββ ββββββββββββββββ
β β
β β
User Interface AI Model
File System Code Analysis
Permissions Code Generation
```
### Key Components
#### 1. **Protocol Layer** (`chuk_acp.protocol`)
The core protocol implementation:
- **JSON-RPC 2.0**: Request/response and notification messages
- **Message Types**: Initialize, session management, prompts
- **Content Types**: Text, images, audio, resources, annotations
- **Capabilities**: Negotiate features between client and agent
#### 2. **Transport Layer** (`chuk_acp.transport`)
Communication mechanism:
- **Stdio Transport**: Process-based communication (current)
- **Extensible**: WebSocket, HTTP, etc. (future)
#### 3. **Type System** (`chuk_acp.protocol.types`)
Strongly-typed protocol structures:
- Content types (text, image, audio)
- Capabilities and features
- Session modes and states
- Tool calls and permissions
### The ACP Flow
```
1. INITIALIZE
Client βββ Agent: Protocol version, capabilities
Agent βββ Client: Agent info, supported features
2. SESSION CREATION
Client βββ Agent: Working directory, MCP servers
Agent βββ Client: Session ID
3. PROMPT TURN
Client βββ Agent: User prompt (text, images, etc.)
Agent βββ Client: [Streaming updates]
Agent βββ Client: Stop reason (end_turn, max_tokens, etc.)
4. ONGOING INTERACTION
- Session updates (thoughts, tool calls, messages)
- Permission requests (file access, terminal, etc.)
- Mode changes (ask β code β architect)
- Cancellation support
```
---
## Complete Examples
### Example 1: Echo Agent (Using Library)
A minimal agent that echoes user input using chuk-acp library helpers:
```python
"""echo_agent.py - Agent using chuk-acp library"""
import json
import sys
import uuid
from typing import Dict, Any
from chuk_acp.protocol import (
create_response,
create_error_response,
create_notification,
METHOD_INITIALIZE,
METHOD_SESSION_NEW,
METHOD_SESSION_PROMPT,
METHOD_SESSION_UPDATE,
)
from chuk_acp.protocol.types import (
AgentInfo,
AgentCapabilities,
SessionUpdate,
TextContent,
)
class EchoAgent:
def __init__(self):
self.sessions = {}
def handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""Use library types instead of manual dict construction."""
agent_info = AgentInfo(name="echo-agent", version="0.1.0")
agent_capabilities = AgentCapabilities()
return {
"protocolVersion": 1,
"agentInfo": agent_info.model_dump(exclude_none=True),
"agentCapabilities": agent_capabilities.model_dump(exclude_none=True),
}
def handle_session_new(self, params: Dict[str, Any]) -> Dict[str, Any]:
session_id = f"session_{uuid.uuid4().hex[:8]}"
self.sessions[session_id] = {"cwd": params.get("cwd")}
return {"sessionId": session_id}
def handle_session_prompt(self, params: Dict[str, Any]) -> Dict[str, Any]:
session_id = params["sessionId"]
prompt = params["prompt"]
# Use library helpers to create notification
text_content = TextContent(
text=f"Echo: You said '{prompt[0].get('text', '')}'"
)
session_update = SessionUpdate(
sessionUpdate="agent_message_chunk",
content=text_content
)
notification = create_notification(
method=METHOD_SESSION_UPDATE,
params={
"sessionId": session_id,
"update": session_update.model_dump(exclude_none=True),
},
)
sys.stdout.write(json.dumps(notification.model_dump(exclude_none=True)) + "\n")
sys.stdout.flush()
return {"stopReason": "end_turn"}
def run(self):
for line in sys.stdin:
message = json.loads(line.strip())
method = message.get("method")
msg_id = message.get("id")
try:
# Route to handler using method constants
if method == METHOD_INITIALIZE:
result = self.handle_initialize(message.get("params", {}))
elif method == METHOD_SESSION_NEW:
result = self.handle_session_new(message.get("params", {}))
elif method == METHOD_SESSION_PROMPT:
result = self.handle_session_prompt(message.get("params", {}))
else:
raise Exception(f"Unknown method: {method}")
# Use library helper to create response
response = create_response(id=msg_id, result=result)
except Exception as e:
# Use library helper for error responses
response = create_error_response(id=msg_id, code=-32603, message=str(e))
sys.stdout.write(json.dumps(response.model_dump(exclude_none=True)) + "\n")
sys.stdout.flush()
if __name__ == "__main__":
EchoAgent().run()
```
> **Note**: This demonstrates using the library's protocol helpers (`create_response`, `create_notification`, `TextContent`, etc.) instead of manual JSON construction. See `examples/echo_agent.py` for the complete implementation.
### Example 2: Client with Session Updates
Capture and handle streaming updates from agent:
```python
"""client_with_updates.py - Capture session/update notifications"""
import asyncio
import uuid
import anyio
from chuk_acp import (
stdio_transport,
send_initialize,
send_session_new,
ClientInfo,
ClientCapabilities,
TextContent,
)
from chuk_acp.protocol import (
create_request,
JSONRPCNotification,
JSONRPCResponse,
METHOD_SESSION_PROMPT,
METHOD_SESSION_UPDATE,
)
async def main():
async with stdio_transport("python", ["examples/echo_agent.py"]) as (read, write):
# Initialize
init_result = await send_initialize(
read, write,
protocol_version=1,
client_info=ClientInfo(name="client", version="1.0.0"),
capabilities=ClientCapabilities()
)
print(f"Connected to {init_result.agentInfo.name}")
# Create session
session = await send_session_new(read, write, cwd="/tmp")
# Send prompt and capture notifications
prompt_text = "Write a hello world function"
print(f"User: {prompt_text}")
request_id = str(uuid.uuid4())
request = create_request(
method=METHOD_SESSION_PROMPT,
params={
"sessionId": session.sessionId,
"prompt": [TextContent(text=prompt_text).model_dump(exclude_none=True)],
},
id=request_id,
)
await write.send(request)
# Collect notifications and response
agent_messages = []
stop_reason = None
with anyio.fail_after(60.0):
while stop_reason is None:
message = await read.receive()
# Handle session/update notifications
if isinstance(message, JSONRPCNotification):
if message.method == METHOD_SESSION_UPDATE:
params = message.params or {}
# Agent message chunks
update = params.get("update", {})
if update.get("sessionUpdate") == "agent_message_chunk":
content = update.get("content", {})
if isinstance(content, dict) and "text" in content:
agent_messages.append(content["text"])
# Thoughts (optional)
if "thought" in params:
print(f"[Thinking: {params['thought']}]")
# Tool calls (optional)
if "toolCall" in params:
tool = params["toolCall"]
print(f"[Calling: {tool.get('name')}]")
# Handle response
elif isinstance(message, JSONRPCResponse):
if message.id == request_id:
result = message.result
if isinstance(result, dict):
stop_reason = result.get("stopReason")
# Display captured agent messages
if agent_messages:
print(f"Agent: {''.join(agent_messages)}")
print(f"Completed: {stop_reason}")
asyncio.run(main())
```
> **Key Point**: To capture `session/update` notifications, you need to manually handle the request/response loop instead of using `send_session_prompt()`, which discards notifications. See `examples/simple_client.py` for a complete working example.
### Example 3: Agent with File System Access
Agent that can read/write files:
```python
"""file_agent.py - Agent with filesystem capabilities"""
from chuk_acp.protocol.types import AgentCapabilities
# Declare filesystem capabilities
capabilities = AgentCapabilities(
filesystem=True # Enables fs/read_text_file and fs/write_text_file
)
async def handle_file_operation(session_id: str, operation: str, path: str):
"""Request file access from client."""
# Request permission
permission = await send_session_request_permission(
read, write,
session_id=session_id,
request=PermissionRequest(
id="perm-123",
description=f"Read file: {path}",
tools=[{"name": "fs/read_text_file", "arguments": {"path": path}}]
)
)
if permission.granted:
# Read the file via client
# (Client implements fs/read_text_file method)
pass
```
### Example 4: Multi-Session Client
Manage multiple concurrent sessions:
```python
"""multi_session_client.py"""
import asyncio
from chuk_acp import stdio_transport, send_session_new, send_session_prompt
async def create_and_run_session(read, write, cwd: str, prompt: str):
"""Create a session and send a prompt."""
session = await send_session_new(read, write, cwd=cwd)
result = await send_session_prompt(
read, write,
session_id=session.sessionId,
prompt=[TextContent(text=prompt)]
)
return result
async def main():
async with stdio_transport("python", ["my_agent.py"]) as (read, write):
# Initialize once
await send_initialize(...)
# Run multiple sessions concurrently
tasks = [
create_and_run_session(read, write, "/project1", "Refactor auth"),
create_and_run_session(read, write, "/project2", "Add tests"),
create_and_run_session(read, write, "/project3", "Fix bug #123"),
]
results = await asyncio.gather(*tasks)
print(f"Completed {len(results)} sessions")
asyncio.run(main())
```
---
## API Reference
### High-Level Client
The `ACPClient` provides the simplest way to interact with ACP agents:
#### Direct Usage
```python
from chuk_acp import ACPClient
async with ACPClient("python", ["agent.py"]) as client:
# Access agent information
print(f"Agent: {client.agent_info.name}")
print(f"Session: {client.current_session.sessionId}")
# Send prompts
result = await client.send_prompt("Hello!")
print(result.full_message) # Complete agent response
print(result.stop_reason) # Why agent stopped
# Create new sessions
new_session = await client.new_session(cwd="/other/path")
```
#### Configuration-Based Usage
Use standard ACP configuration format (compatible with Zed, VSCode, etc.):
```python
from chuk_acp import ACPClient, AgentConfig, load_agent_config
# Method 1: Create config directly
config = AgentConfig(
command="kimi",
args=["--acp"],
env={"DEBUG": "true"},
cwd="/optional/path"
)
async with ACPClient.from_config(config) as client:
result = await client.send_prompt("Hello!")
# Method 2: Load from JSON file
config = load_agent_config("~/.config/my-app/agent.json")
async with ACPClient.from_config(config) as client:
result = await client.send_prompt("Hello!")
# Method 3: From dictionary (like editor configs)
config = AgentConfig(**{
"command": "kimi",
"args": ["--acp"],
"env": {}
})
async with ACPClient.from_config(config) as client:
result = await client.send_prompt("Hello!")
```
**Example JSON config file:**
```json
{
"command": "kimi",
"args": ["--acp"],
"env": {
"DEBUG": "true",
"LOG_LEVEL": "info"
},
"cwd": "/optional/path"
}
```
**Key Classes:**
- `ACPClient` - Main client class
- `AgentConfig` - Standard ACP configuration format
- `load_agent_config()` - Load config from JSON file
- `PromptResult` - Contains response and all notifications
- `SessionInfo` - Session information
- `SessionUpdate` - Individual notification from agent
### Low-Level Protocol API
For fine-grained control over the protocol:
### Protocol Helpers
#### JSON-RPC Message Helpers
Build protocol messages using library helpers:
```python
from chuk_acp.protocol import (
create_request,
create_response,
create_error_response,
create_notification,
)
# Create a request
request = create_request(
method="session/prompt",
params={"sessionId": "session-1", "prompt": [...]},
id="req-123"
)
# Create a response
response = create_response(id="req-123", result={"stopReason": "end_turn"})
# Create an error response
error = create_error_response(id="req-123", code=-32603, message="Internal error")
# Create a notification
from chuk_acp.protocol.types import SessionUpdate, TextContent
session_update = SessionUpdate(
sessionUpdate="agent_message_chunk",
content=TextContent(text="Hello!")
)
notification = create_notification(
method="session/update",
params={
"sessionId": "session-1",
"update": session_update.model_dump(exclude_none=True)
}
)
```
#### Method Constants
Use constants instead of string literals for protocol methods:
```python
from chuk_acp.protocol import (
METHOD_INITIALIZE,
METHOD_SESSION_NEW,
METHOD_SESSION_PROMPT,
METHOD_SESSION_UPDATE,
METHOD_SESSION_CANCEL,
METHOD_FS_READ_TEXT_FILE,
METHOD_FS_WRITE_TEXT_FILE,
METHOD_TERMINAL_CREATE,
# ... and more
)
# Use in message routing
if method == METHOD_INITIALIZE:
# Handle initialize
pass
elif method == METHOD_SESSION_PROMPT:
# Handle prompt
pass
```
### Transport
#### `stdio_transport(command, args)`
Create a stdio transport connection to an agent.
```python
async with stdio_transport("python", ["agent.py"]) as (read_stream, write_stream):
# Use streams for communication
pass
```
### Initialization
#### `send_initialize(read, write, protocol_version, client_info, capabilities)`
Initialize the connection and negotiate capabilities.
```python
result = await send_initialize(
read_stream,
write_stream,
protocol_version=1,
client_info=ClientInfo(name="my-client", version="1.0.0"),
capabilities=ClientCapabilities(filesystem=True)
)
# result.agentInfo, result.capabilities, result.protocolVersion
```
### Session Management
#### `send_session_new(read, write, cwd, mcp_servers=None, mode=None)`
Create a new session.
```python
session = await send_session_new(
read_stream,
write_stream,
cwd="/absolute/path",
mode="code" # Optional: ask, architect, code
)
# session.sessionId
```
#### `send_session_prompt(read, write, session_id, prompt)`
Send a prompt to the agent.
```python
result = await send_session_prompt(
read_stream,
write_stream,
session_id="session-123",
prompt=[
TextContent(text="Write a function"),
ImageContent(data="base64...", mimeType="image/png")
]
)
# result.stopReason: end_turn, max_tokens, cancelled, refusal
```
> **Note**: `send_session_prompt` discards `session/update` notifications from the agent. To capture agent responses (message chunks, thoughts, tool calls), manually handle the request/response loop. See Example 2 or `examples/simple_client.py` for details.
#### `send_session_cancel(write, session_id)`
Cancel an ongoing prompt turn.
```python
await send_session_cancel(write_stream, session_id="session-123")
```
### Content Types
#### `TextContent(text)`
Plain text content.
```python
content = TextContent(text="Hello, world!")
```
#### `ImageContent(data, mimeType)`
Base64-encoded image.
```python
content = ImageContent(
data="iVBORw0KGgoAAAANSUhEUgA...",
mimeType="image/png"
)
```
#### `AudioContent(data, mimeType)`
Base64-encoded audio.
```python
content = AudioContent(
data="SUQzBAA...",
mimeType="audio/mpeg"
)
```
---
## Protocol Support
chuk-acp implements the **complete ACP v1 specification**.
### β
Baseline Agent Methods (Required)
| Method | Description | Status |
|--------|-------------|--------|
| `initialize` | Protocol handshake and capability negotiation | β
|
| `authenticate` | Optional authentication | β
|
| `session/new` | Create new conversation sessions | β
|
| `session/prompt` | Process user prompts | β
|
| `session/cancel` | Cancel ongoing operations | β
|
### β
Optional Agent Methods
| Method | Capability | Status |
|--------|------------|--------|
| `session/load` | Resume previous sessions | β
|
| `session/set_mode` | Change session modes | β
|
### β
Client Methods (Callbacks)
| Method | Description | Status |
|--------|-------------|--------|
| `session/request_permission` | Request user approval for actions | β
|
| `fs/read_text_file` | Read file contents | β
|
| `fs/write_text_file` | Write file contents | β
|
| `terminal/create` | Create terminal sessions | β
|
| `terminal/output` | Stream terminal output | β
|
| `terminal/release` | Release terminal control | β
|
| `terminal/wait_for_exit` | Wait for command completion | β
|
| `terminal/kill` | Terminate running commands | β
|
### β
Content Types
- Text content (baseline - always supported)
- Image content (base64-encoded)
- Audio content (base64-encoded)
- Embedded resources
- Resource links
- Annotations
### β
Session Features
- Session management (create, load, cancel)
- Multiple parallel sessions
- Session modes: `ask`, `architect`, `code`
- Session history replay
- MCP server integration
### β
Tool Integration
- Tool calls with status tracking (`pending`, `in_progress`, `completed`, `failed`)
- Permission requests
- File location tracking
- Structured output (diffs, terminals, content)
- Slash commands (optional)
### β
Protocol Requirements
- **File paths**: All paths must be absolute β
- **Line numbers**: 1-based indexing β
- **JSON-RPC 2.0**: Strict compliance β
- **Extensibility**: `_meta` fields and custom methods β
---
## Architecture
### Project Structure
```
chuk-acp/
βββ src/chuk_acp/
β βββ protocol/ # Core protocol implementation
β β βββ jsonrpc.py # JSON-RPC 2.0 (requests, responses, errors)
β β βββ acp_pydantic_base.py # Optional Pydantic support
β β βββ types/ # Protocol type definitions
β β β βββ content.py # Content types (text, image, audio)
β β β βββ capabilities.py # Client/agent capabilities
β β β βββ session.py # Session types and modes
β β β βββ tools.py # Tool calls and permissions
β β β βββ plan.py # Task planning types
β β β βββ terminal.py # Terminal integration
β β β βββ ...
β β βββ messages/ # Message handling
β β βββ initialize.py # Initialize/authenticate
β β βββ session.py # Session management
β β βββ filesystem.py # File operations
β β βββ terminal.py # Terminal operations
β β βββ send_message.py # Core messaging utilities
β β
β βββ transport/ # Transport layer
β β βββ base.py # Abstract transport interface
β β βββ stdio.py # Stdio transport (subprocess)
β β
β βββ __init__.py # Public API exports
β
βββ examples/ # Working examples
β βββ echo_agent.py # Simple echo agent
β βββ simple_client.py # Basic client
β βββ quick_start.py # Getting started
β βββ comprehensive_demo.py # Full-featured demo
β
βββ tests/ # Test suite
β βββ test_protocol_compliance.py # Spec compliance
β βββ test_jsonrpc.py # JSON-RPC tests
β βββ test_types.py # Type system tests
β βββ test_messages.py # Message handling
β βββ test_stdio_transport.py # Transport tests
β
βββ .github/ # CI/CD workflows
βββ workflows/
β βββ ci.yml # Testing and linting
β βββ publish.yml # PyPI publishing
β βββ codeql.yml # Security scanning
βββ ...
```
### Design Principles
1. **Protocol First**: Strict adherence to ACP specification
2. **Type Safety**: Comprehensive type hints throughout
3. **Optional Dependencies**: Pydantic is optional, not required
4. **Async by Default**: Built on `anyio` for async/await
5. **Extensibility**: Custom methods and `_meta` fields supported
6. **Testability**: Loosely coupled, dependency injection
7. **Zero-Config**: Works out of the box with sensible defaults
### Layer Separation
```
βββββββββββββββββββββββββββββββββββββββ
β User Code (Agents/Clients) β
βββββββββββββββββββββββββββββββββββββββ€
β High-Level API (messages/) β β send_initialize, send_prompt, etc.
βββββββββββββββββββββββββββββββββββββββ€
β Protocol Layer (types/, jsonrpc) β β Content types, capabilities
βββββββββββββββββββββββββββββββββββββββ€
β Transport Layer (transport/) β β Stdio, future: WebSocket, HTTP
βββββββββββββββββββββββββββββββββββββββ
```
---
## Testing
### Running Tests
```bash
# Run all tests
make test
# Run with coverage
make test-cov
# Run specific test file
uv run pytest tests/test_protocol_compliance.py -v
# Test without Pydantic (fallback mode)
uv pip uninstall pydantic
uv run pytest
```
### Test Categories
- **Protocol Compliance** (`test_protocol_compliance.py`): Validates ACP spec adherence
- **JSON-RPC** (`test_jsonrpc.py`): JSON-RPC 2.0 implementation
- **Types** (`test_types.py`): Type system and content types
- **Messages** (`test_messages.py`): Message handling and serialization
- **Transport** (`test_stdio_transport.py`): Transport layer
### Code Quality Checks
```bash
# Format code
make format
# Lint
make lint
# Type check
make mypy
# Security scan
make security
# All checks
make check
```
---
## Relationship to MCP
**ACP** and **MCP** (Model Context Protocol) are complementary protocols:
| Protocol | Purpose | Focus |
|----------|---------|-------|
| **MCP** | What data/tools agents can access | Context & tools |
| **ACP** | Where the agent lives in your workflow | Agent lifecycle |
### Integration
ACP reuses MCP data structures for content types and resources:
```python
from chuk_acp.protocol.types import (
TextContent, # From MCP
ImageContent, # From MCP
ResourceContent, # From MCP
)
# ACP sessions can specify MCP servers
session = await send_session_new(
read, write,
cwd="/project",
mcp_servers=[
MCPServer(
name="filesystem",
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "/path"]
)
]
)
```
### When to Use What
- **Use ACP** to build AI coding agents that integrate with editors
- **Use MCP** to provide context and tools to language models
- **Use both** for a complete AI-powered development environment
---
## Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for:
- Development setup
- Code style and standards
- Testing requirements
- Pull request process
- Release workflow
### Quick Start for Contributors
```bash
# Clone and setup
git clone https://github.com/chuk-ai/chuk-acp.git
cd chuk-acp
uv venv
source .venv/bin/activate
uv pip install -e ".[dev,pydantic]"
# Run checks
make check
# Run examples
cd examples && python simple_client.py
```
### Areas for Contribution
- π Bug fixes and issue resolution
- β¨ New features (check ACP spec for ideas)
- π Documentation improvements
- π§ͺ Additional test coverage
- π Additional transports (WebSocket, HTTP, etc.)
- π¨ Example agents and clients
- π§ Tooling and developer experience
---
## License
This project is licensed under the **Apache License 2.0**.
See [LICENSE](LICENSE) for full details.
---
## Links
### Official Resources
- **ACP Specification**: https://agentclientprotocol.com
- **GitHub Repository**: https://github.com/chuk-ai/chuk-acp
- **PyPI Package**: https://pypi.org/project/chuk-acp/
- **Issue Tracker**: https://github.com/chuk-ai/chuk-acp/issues
- **Discussions**: https://github.com/chuk-ai/chuk-acp/discussions
- **CLI Documentation**: [CLI.md](CLI.md)
### Related Projects
**ACP Agents:**
- **Claude Code**: https://github.com/zed-industries/claude-code-acp - Anthropic's official Claude adapter
- **Kimi**: https://github.com/MoonshotAI/kimi-cli - AI coding agent from Moonshot AI
**Protocols:**
- **Model Context Protocol (MCP)**: https://modelcontextprotocol.io - Data & tool access for agents
- **Language Server Protocol (LSP)**: https://microsoft.github.io/language-server-protocol/ - Inspiration for ACP
### Community
- Report bugs: [GitHub Issues](https://github.com/chuk-ai/chuk-acp/issues)
- Ask questions: [GitHub Discussions](https://github.com/chuk-ai/chuk-acp/discussions)
- Contribute: See [CONTRIBUTING.md](CONTRIBUTING.md)
---
<div align="center">
**Built with β€οΈ for the AI coding community**
[β Star us on GitHub](https://github.com/chuk-ai/chuk-acp) | [π¦ Install from PyPI](https://pypi.org/project/chuk-acp/) | [π Read the Spec](https://agentclientprotocol.com)
</div>
Raw data
{
"_id": null,
"home_page": null,
"name": "chuk-acp",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "acp, agent-client-protocol, ai, coding-agent, editor",
"author": null,
"author_email": "Christopher Hay <chrishayuk@somejunkmailbox.com>",
"download_url": "https://files.pythonhosted.org/packages/29/dc/6698b6d148f768d7e238491aa46daf07139c01fae3a785d6a0c7f3b3b660/chuk_acp-0.3.0.tar.gz",
"platform": null,
"description": "# chuk-acp\n\n[](https://github.com/chuk-ai/chuk-acp/actions/workflows/ci.yml)\n[](https://badge.fury.io/py/chuk-acp)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/Apache-2.0)\n[](https://github.com/psf/black)\n[](https://github.com/astral-sh/ruff)\n[](https://codecov.io/gh/chuk-ai/chuk-acp)\n\nA Python implementation of the [Agent Client Protocol (ACP)](https://agentclientprotocol.com) - the standard protocol for communication between code editors and AI coding agents.\n\n---\n\n## \ud83d\udcd6 Table of Contents\n\n- [Overview](#overview)\n- [Why ACP?](#why-acp)\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n - [CLI Tool](#cli-tool)\n - [Building an Agent](#building-an-agent)\n - [Building a Client](#building-a-client)\n- [Core Concepts](#core-concepts)\n- [Complete Examples](#complete-examples)\n- [API Reference](#api-reference)\n- [Protocol Support](#protocol-support)\n- [Architecture](#architecture)\n- [Testing](#testing)\n- [Relationship to MCP](#relationship-to-mcp)\n- [Contributing](#contributing)\n- [License](#license)\n- [Links](#links)\n\n---\n\n## Overview\n\nThe **Agent Client Protocol (ACP)** is to AI coding agents what the Language Server Protocol (LSP) is to programming languages. It standardizes communication between code editors/IDEs and coding agents\u2014programs that use generative AI to autonomously modify code.\n\n**chuk-acp** provides a complete, production-ready Python implementation of ACP, enabling you to:\n\n- \ud83d\udcac **Interact with agents instantly** using the CLI (`uvx chuk-acp claude-code-acp` or `echo \"hello\" | uvx chuk-acp client -- kimi --acp`)\n- \ud83e\udd16 **Build ACP-compliant coding agents** easily with the high-level `ACPAgent` API\n- \ud83d\udda5\ufe0f **Build editors/IDEs** that can connect to any ACP-compliant agent with `ACPClient`\n- \ud83d\udd0c **Integrate AI capabilities** into existing development tools\n- \ud83e\uddea **Test and develop** against the ACP specification\n\n---\n\n## Why ACP?\n\n### The Problem\n\nWithout a standard protocol, every AI coding tool creates its own proprietary interface, leading to:\n\n- Fragmentation across different tools and editors\n- Inability to switch agents or editors without rewriting integration code\n- Duplicated effort implementing similar functionality\n- Limited interoperability\n\n### The Solution\n\nACP provides a **standard, open protocol** that:\n\n- \u2705 Enables **any agent to work with any editor**\n- \u2705 Provides **consistent user experience** across tools\n- \u2705 Allows **innovation at both the editor and agent level**\n- \u2705 Built on proven standards (JSON-RPC 2.0)\n- \u2705 Supports **async/streaming** for real-time AI interactions\n\nThink LSP for language tooling, but for AI coding agents.\n\n---\n\n## Features\n\n### \ud83c\udfaf Complete ACP Implementation\n\n- Full support for ACP v1 specification\n- All baseline methods and content types\n- Optional capabilities (modes, session loading, file system, terminal)\n- Protocol compliance test suite\n- **MCP Servers Support**: Automatically sends empty `mcpServers: []` for compatibility with agents that require it\n- **Flexible AgentInfo**: Handles agents that return incomplete initialization data\n\n### \ud83d\udd27 Developer-Friendly\n\n- **CLI Tool**: Interactive command-line client for testing agents (`uvx chuk-acp`)\n- **Zero Installation**: Run with `uvx` - no setup required\n- **Type-Safe**: Comprehensive type hints throughout\n- **Async-First**: Built on `anyio` for efficient async/await patterns\n- **Optional Pydantic**: Use Pydantic for validation, or go dependency-free with fallback\n- **Well-Documented**: Extensive examples and API documentation\n- **Production-Ready**: Tested across Python 3.11, 3.12 on Linux, macOS, Windows\n\n### \ud83d\ude80 Flexible & Extensible\n\n- **Multiple transports**: Stdio (with more coming)\n- **Custom methods**: Extend protocol with `_meta` fields and custom methods\n- **Pluggable**: Easy to integrate into existing tools\n- **MCP Integration**: Seamless compatibility with Model Context Protocol\n\n### \ud83d\udee1\ufe0f Quality & Security\n\n- Comprehensive test coverage\n- Security scanning with Bandit and CodeQL\n- Type checking with mypy\n- Automated dependency updates\n- CI/CD with GitHub Actions\n\n---\n\n## Quick Start (60 Seconds!)\n\n### \ud83d\ude80 Try Without Installation\n\nThe absolute fastest way to get started - no cloning, no installation:\n\n```bash\n# 1. Download a standalone agent example\ncurl -O https://raw.githubusercontent.com/chuk-ai/chuk-acp/main/examples/standalone_agent.py\n\n# 2. Run it with uvx (automatically installs chuk-acp temporarily)\nuvx chuk-acp client python standalone_agent.py\n\n# That's it! Start chatting with your agent.\n```\n\nSee [QUICKSTART.md](QUICKSTART.md) for full details.\n\n### Or Connect to External Agents\n\n```bash\n# Claude Code (requires ANTHROPIC_API_KEY)\nANTHROPIC_API_KEY=sk-... uvx chuk-acp claude-code-acp\n\n# Kimi (Chinese AI assistant)\nuvx chuk-acp client -- kimi --acp\n```\n\n**That's it!** `uvx` automatically handles installation. Perfect for quick testing.\n\n---\n\n## Installation\n\n### Using uvx (Recommended for One-Off Usage)\n\nNo installation needed! `uvx` runs the CLI directly:\n\n```bash\n# Single prompt mode (interactive with stdin)\necho \"Create a Python function to calculate fibonacci\" | uvx chuk-acp client -- kimi --acp\n\n# With faster validation (optional)\nuvx --from 'chuk-acp[pydantic]' chuk-acp claude-code-acp\n```\n\n### Using uv (Recommended for Development)\n\n[uv](https://github.com/astral-sh/uv) is a fast Python package installer:\n\n```bash\n# Basic installation (includes CLI)\nuv pip install chuk-acp\n\n# With Pydantic validation support (recommended for better performance)\nuv pip install chuk-acp[pydantic]\n\n# Or add to your project\nuv add chuk-acp\n```\n\n### Using pip\n\n```bash\n# Basic installation (includes CLI)\npip install chuk-acp\n\n# With Pydantic support (recommended)\npip install chuk-acp[pydantic]\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/chuk-ai/chuk-acp.git\ncd chuk-acp\nuv venv\nsource .venv/bin/activate # On Windows: .venv\\Scripts\\activate\nuv pip install -e \".[dev,pydantic]\"\n```\n\n### Requirements\n\n- Python 3.11 or higher\n- Dependencies: `anyio`, `typing-extensions`\n- Optional: `pydantic` (for faster validation - works without it using fallback mechanism)\n\n---\n\n## Quick Start\n\n### CLI Tool - Interactive Chat with Any Agent\n\nThe easiest way to interact with ACP agents is using the built-in CLI. Works instantly with `uvx` or after installation.\n\nThe CLI supports three modes:\n\n1. **Agent passthrough** - For editors/tools (explicitly use `agent` subcommand)\n2. **Interactive client** - For humans (explicitly use `client` subcommand)\n3. **Auto-detect** - Smart mode selection (TTY = interactive, piped = passthrough)\n\n#### Try It Now (No Installation!)\n\n```bash\n# Connect to Claude Code (requires ANTHROPIC_API_KEY)\nANTHROPIC_API_KEY=sk-... uvx chuk-acp client claude-code-acp\n\n# Connect to Kimi agent (use -- to separate flags)\necho \"hello\" | uvx chuk-acp client -- kimi --acp\n\n# Interactive mode with verbose output\necho \"your question\" | uvx chuk-acp --verbose client -- kimi --acp\n\n# Interactive chat opens automatically\n# Just start typing your questions!\n```\n\n#### After Installation\n\n```bash\n# Interactive client mode (explicit)\nchuk-acp client python examples/echo_agent.py\n\n# Agent passthrough mode (for editors like Zed)\nchuk-acp agent python my_agent.py\n\n# Auto-detect mode (interactive if TTY, passthrough if piped)\nchuk-acp python examples/echo_agent.py\n\n# Single prompt (requires stdin for kimi)\necho \"Create a Python function to calculate factorial\" | chuk-acp client -- kimi --acp\n\n# Using a config file\nchuk-acp --config examples/kimi_config.json\n\n# With environment variables\nchuk-acp client python agent.py --env DEBUG=true --env API_KEY=xyz\n\n# Force interactive mode even when piped\nchuk-acp --interactive python agent.py\n\n# Verbose output for debugging\nchuk-acp client python agent.py --verbose\n```\n\n#### Interactive Mode Commands\n\nWhen in interactive chat mode, you can use these special commands:\n\n| Command | Description |\n|---------|-------------|\n| `/quit` or `/exit` | Exit the client |\n| `/new` | Start a new session (clears context) |\n| `/info` | Show agent information and session ID |\n\n#### Example Interactive Session\n\n**With Claude Code:**\n```bash\n$ ANTHROPIC_API_KEY=sk-... uvx chuk-acp claude-code-acp\n\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n\u2551 ACP Interactive Client \u2551\n\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\nYou: Create a Python function to check if a string is a palindrome\n\nAgent: Here's a Python function to check if a string is a palindrome:\n\ndef is_palindrome(s):\n # Remove spaces and convert to lowercase\n s = s.replace(\" \", \"\").lower()\n # Check if string equals its reverse\n return s == s[::-1]\n\nYou: /quit\nGoodbye!\n```\n\n**With Kimi:**\n```bash\n$ echo \"What's the best way to handle async errors in Python?\" | uvx chuk-acp client -- kimi --acp\n\nAgent: [Kimi's response with thinking and detailed explanation...]\n```\n\n#### Configuration Files\n\nUse standard ACP configuration format (compatible with Zed, VSCode, etc.):\n\n**claude_code_config.json:**\n```json\n{\n \"command\": \"claude-code-acp\",\n \"args\": [],\n \"env\": {\n \"ANTHROPIC_API_KEY\": \"sk-...\"\n }\n}\n```\n\n**kimi_config.json:**\n```json\n{\n \"command\": \"kimi\",\n \"args\": [\"--acp\"],\n \"env\": {}\n}\n```\n\nThen use with:\n```bash\nchuk-acp --config claude_code_config.json\nchuk-acp --config kimi_config.json\n```\n\n#### Important: Using `--` for Agent Flags\n\nWhen an agent requires flags (like `kimi --acp`), use `--` to separate chuk-acp flags from agent arguments:\n\n```bash\n# Correct - use -- separator\nchuk-acp client -- kimi --acp\n\n# Also works via config file\nchuk-acp --config kimi_config.json\n```\n\nWithout `--`, argparse treats `--acp` as a chuk-acp flag and fails. Using a config file avoids this issue entirely.\n\n**\ud83d\udcd6 See [CLI.md](CLI.md) for complete CLI documentation and advanced usage.**\n\n### Using with Editors (Zed, VSCode, etc.)\n\nchuk-acp can run your custom agents in editors that support ACP, like Zed. The `agent` mode provides a passthrough that lets editors communicate directly with your agent via the ACP protocol.\n\n#### Zed Configuration\n\nAdd this to your Zed `settings.json` (usually `~/.config/zed/settings.json`):\n\n```json\n{\n \"agent_servers\": {\n \"My Custom Agent\": {\n \"command\": \"uvx\",\n \"args\": [\n \"chuk-acp\",\n \"agent\",\n \"python\",\n \"/absolute/path/to/my_agent.py\"\n ],\n \"env\": {}\n }\n }\n}\n```\n\nOr using auto-detect mode (will automatically use passthrough when piped from Zed):\n\n```json\n{\n \"agent_servers\": {\n \"My Custom Agent\": {\n \"command\": \"uvx\",\n \"args\": [\n \"chuk-acp\",\n \"python\",\n \"/absolute/path/to/my_agent.py\"\n ],\n \"env\": {}\n }\n }\n}\n```\n\n**What this does:**\n- `uvx` automatically installs `chuk-acp` in a temporary environment\n- `chuk-acp agent` runs in passthrough mode (just executes your agent with the ACP protocol layer)\n- Your agent gets access to the `chuk-acp` package (so `from chuk_acp.agent import ACPAgent` works)\n- No `--from` or `--with` flags needed!\n\n**Example agent file** (`my_agent.py`):\n\n```python\nfrom typing import List\nfrom chuk_acp.agent import ACPAgent, AgentSession\nfrom chuk_acp.protocol.types import AgentInfo, Content\n\nclass MyAgent(ACPAgent):\n def get_agent_info(self) -> AgentInfo:\n return AgentInfo(name=\"my-agent\", version=\"1.0.0\")\n\n async def handle_prompt(self, session: AgentSession, prompt: List[Content]) -> str:\n text = prompt[0].get(\"text\", \"\") if prompt else \"\"\n return f\"You said: {text}\"\n\nif __name__ == \"__main__\":\n MyAgent().run()\n```\n\nSee [`examples/zed_config.json`](examples/zed_config.json) for more configuration examples.\n\n### The Easiest Way: ACPClient\n\nThe fastest way to get started programmatically is with the high-level `ACPClient`, which handles all protocol details automatically:\n\n**Option A: Direct Usage**\n```python\n\"\"\"quickstart.py\"\"\"\nimport anyio\nfrom chuk_acp import ACPClient\n\nasync def main():\n # Connect to an agent - handles initialization, sessions, everything!\n async with ACPClient(\"python\", [\"echo_agent.py\"]) as client:\n # Send a prompt and get the response\n result = await client.send_prompt(\"Hello!\")\n print(f\"Agent: {result.full_message}\")\n\nanyio.run(main)\n```\n\n**Option B: Using Standard ACP Configuration**\n\nThis matches the configuration format used by editors like Zed, VSCode, etc.:\n\n```python\n\"\"\"quickstart_config.py\"\"\"\nimport anyio\nfrom chuk_acp import ACPClient, AgentConfig\n\nasync def main():\n # Standard ACP configuration format\n config = AgentConfig(\n command=\"kimi\", # Any ACP-compatible agent\n args=[\"--acp\"], # Agent-specific arguments\n env={\"DEBUG\": \"true\"} # Optional environment variables\n )\n\n async with ACPClient.from_config(config) as client:\n result = await client.send_prompt(\"Hello!\")\n print(f\"Agent: {result.full_message}\")\n\nanyio.run(main)\n```\n\nOr load from a JSON file (like `~/.config/zed/settings.json`):\n\n```python\nfrom chuk_acp import load_agent_config\n\nconfig = load_agent_config(\"~/.config/my-app/agent.json\")\nasync with ACPClient.from_config(config) as client:\n result = await client.send_prompt(\"Hello!\")\n```\n\n**What `ACPClient` does automatically:**\n- \u2705 Starts the agent process\n- \u2705 Handles protocol initialization\n- \u2705 Creates and manages sessions\n- \u2705 Captures all notifications\n- \u2705 Cleans up resources\n- \u2705 Supports standard ACP configuration format\n\n**Want more control?** The low-level API gives you fine-grained control over the protocol. See the examples below.\n\n---\n\n### Building an Agent\n\nThe fastest way to build an ACP agent is with the high-level `ACPAgent` class:\n\n```python\n\"\"\"my_agent.py\"\"\"\nfrom typing import List\nfrom chuk_acp.agent import ACPAgent, AgentSession\nfrom chuk_acp.protocol.types import AgentInfo, Content\n\nclass MyAgent(ACPAgent):\n \"\"\"Your custom agent implementation.\"\"\"\n\n def get_agent_info(self) -> AgentInfo:\n \"\"\"Return agent information.\"\"\"\n return AgentInfo(\n name=\"my-agent\",\n version=\"1.0.0\",\n title=\"My Custom Agent\"\n )\n\n async def handle_prompt(\n self, session: AgentSession, prompt: List[Content]\n ) -> str:\n \"\"\"Handle a prompt - this is where your agent logic goes.\"\"\"\n # Extract text from prompt\n text = prompt[0].get(\"text\", \"\") if prompt else \"\"\n\n # Your agent logic here\n response = f\"I received: {text}\"\n\n # Return the response\n return response\n\nif __name__ == \"__main__\":\n agent = MyAgent()\n agent.run()\n```\n\n**Run your agent:**\n```bash\n# Test with CLI (using uv for environment management)\nuvx chuk-acp client uv run my_agent.py\n\n# Or if chuk-acp is installed globally\nchuk-acp client python my_agent.py\n```\n\n**What `ACPAgent` does automatically:**\n- \u2705 Handles all protocol messages (initialize, session/new, session/prompt)\n- \u2705 Manages sessions and routing\n- \u2705 Sends responses in correct format\n- \u2705 Error handling and logging\n- \u2705 Stdin/stdout transport\n\n**Real example:** See [`examples/echo_agent.py`](examples/echo_agent.py) - a complete working agent in just 35 lines!\n\n#### \ud83d\ude80 Even Easier: chuk-acp-agent\n\nFor an even simpler agent-building experience, check out **[chuk-acp-agent](https://github.com/chrishayuk/chuk-acp-agent)** - an opinionated agent kit built on top of chuk-acp:\n\n```python\nfrom chuk_acp_agent import Agent, Context\n\nclass MyAgent(Agent):\n async def on_prompt(self, ctx: Context, prompt: str):\n # Session memory\n count = ctx.memory.get(\"count\", 0) + 1\n ctx.memory.set(\"count\", count)\n\n # Stream response\n yield f\"Message #{count}: {prompt}\\n\"\n\nif __name__ == \"__main__\":\n MyAgent().run()\n```\n\n**Features:**\n- \ud83d\udce6 Batteries-included: session memory, streaming helpers, MCP integration\n- \ud83c\udfaf Minimal boilerplate: just implement `on_prompt()`\n- \ud83d\udd27 Context API: `ctx.memory`, `ctx.emit()`, `ctx.fs`, `ctx.terminal`\n- \ud83d\udee0\ufe0f Built-in MCP tool support via `chuk-tool-processor`\n\nInstall: `pip install chuk-acp-agent` or see the [chuk-acp-agent docs](https://github.com/chrishayuk/chuk-acp-agent).\n\n---\n\n### More Examples\n\nFor more complete examples showing different use cases:\n\n```bash\n# Clone the repository\ngit clone https://github.com/chuk-ai/chuk-acp.git\ncd chuk-acp\n\n# Install\nuv pip install -e \".[pydantic]\"\n\n# Run examples (all use the high-level ACPClient)\nuv run python examples/simple_client.py # Basic single prompt\nuv run python examples/quick_start.py # Multi-turn conversation\nuv run python examples/config_example.py # Configuration support (Zed/VSCode format)\n\n# Advanced: Low-level protocol examples\nuv run python examples/low_level/simple_client.py # Manual protocol handling\nuv run python examples/low_level/quick_start.py # Self-contained with embedded agent\nuv run python examples/low_level/comprehensive_demo.py # All ACP features\n```\n\nSee the [examples directory](https://github.com/chuk-ai/chuk-acp/tree/main/examples) for detailed documentation.\n\n> **Note**: Examples are in the GitHub repository. If you installed via pip, clone the repo to access them.\n\n### Option B: Build Your Own (10 Minutes)\n\nCreate a complete ACP client and agent from scratch.\n\n#### Step 1: Install\n\n```bash\nuv pip install chuk-acp[pydantic]\n```\n\n#### Step 2: Create an Agent\n\nSave this as `echo_agent.py`:\n\n```python\n\"\"\"echo_agent.py - A simple ACP agent\"\"\"\nimport json\nimport sys\nimport uuid\n\nfrom chuk_acp.protocol import (\n create_response,\n create_notification,\n METHOD_INITIALIZE,\n METHOD_SESSION_NEW,\n METHOD_SESSION_PROMPT,\n METHOD_SESSION_UPDATE,\n)\nfrom chuk_acp.protocol.types import AgentInfo, AgentCapabilities, TextContent\n\n# Read messages from stdin, write to stdout\nfor line in sys.stdin:\n msg = json.loads(line.strip())\n method = msg.get(\"method\")\n params = msg.get(\"params\", {})\n msg_id = msg.get(\"id\")\n\n # Route to handlers\n if method == METHOD_INITIALIZE:\n result = {\n \"protocolVersion\": 1,\n \"agentInfo\": AgentInfo(name=\"echo-agent\", version=\"1.0.0\").model_dump(),\n \"agentCapabilities\": AgentCapabilities().model_dump(),\n }\n response = create_response(id=msg_id, result=result)\n\n elif method == METHOD_SESSION_NEW:\n session_id = f\"session-{uuid.uuid4().hex[:8]}\"\n response = create_response(id=msg_id, result={\"sessionId\": session_id})\n\n elif method == METHOD_SESSION_PROMPT:\n session_id = params[\"sessionId\"]\n user_text = params[\"prompt\"][0].get(\"text\", \"\")\n\n # Send a notification with the echo\n from chuk_acp.protocol.types import SessionUpdate\n\n session_update = SessionUpdate(\n sessionUpdate=\"agent_message_chunk\",\n content=TextContent(text=f\"Echo: {user_text}\")\n )\n notification = create_notification(\n method=METHOD_SESSION_UPDATE,\n params={\n \"sessionId\": session_id,\n \"update\": session_update.model_dump(exclude_none=True),\n },\n )\n sys.stdout.write(json.dumps(notification.model_dump()) + \"\\n\")\n sys.stdout.flush()\n\n # Send the response\n response = create_response(id=msg_id, result={\"stopReason\": \"end_turn\"})\n\n else:\n continue\n\n sys.stdout.write(json.dumps(response.model_dump()) + \"\\n\")\n sys.stdout.flush()\n```\n\n#### Step 3: Create a Client\n\nSave this as `my_client.py`:\n\n```python\n\"\"\"my_client.py - Connect to the echo agent using ACPClient\"\"\"\nimport anyio\nfrom chuk_acp import ACPClient\n\n\nasync def main():\n # Connect to the agent - handles everything automatically!\n async with ACPClient(\"python\", [\"echo_agent.py\"]) as client:\n # Send a prompt and get the response\n result = await client.send_prompt(\"Hello!\")\n print(f\"Agent says: {result.full_message}\")\n\n\nif __name__ == \"__main__\":\n anyio.run(main())\n```\n\n#### Step 4: Run It!\n\n```bash\nuv run python my_client.py\n```\n\n**Output:**\n```\n\u2713 Connected to echo-agent\n\u2713 Session: session-a1b2c3d4\n\nSending: Hello!\nAgent says: Echo: Hello!\n\u2713 Done!\n```\n\n\ud83c\udf89 **That's it!** You've built a working ACP agent and client.\n\n### What You Learned\n\n**Option A** showed you the fastest path - running pre-built examples.\n\n**Option B** taught you:\n- **Agents**: Read JSON-RPC from stdin, write to stdout using `create_response()` and `create_notification()`\n- **Clients**: Connect via `stdio_transport`, use `send_initialize()` and `send_session_new()`, manually handle messages to capture notifications\n- **Protocol flow**: Initialize \u2192 Create Session \u2192 Send Prompts (with notifications) \u2192 Get Response\n- **Best practices**: Use library types (`TextContent`, `AgentInfo`) and method constants (`METHOD_INITIALIZE`)\n\n### Next Steps\n\n**Explore More Features:**\n\nCheck out the complete examples in the [GitHub repository](https://github.com/chuk-ai/chuk-acp/tree/main/examples):\n- [simple_client.py](https://github.com/chuk-ai/chuk-acp/blob/main/examples/simple_client.py) - Clean client with notification handling\n- [echo_agent.py](https://github.com/chuk-ai/chuk-acp/blob/main/examples/echo_agent.py) - Production-ready agent with error handling\n- [comprehensive_demo.py](https://github.com/chuk-ai/chuk-acp/blob/main/examples/comprehensive_demo.py) - Filesystem, terminal, all ACP features\n\n**Build Something:**\n- Add file system access to your agent (see Example 3 below)\n- Implement tool calls and permission requests\n- Support multiple concurrent sessions\n- Add streaming for long responses\n\n**Learn More:**\n- [API Reference](#api-reference) - Complete API documentation\n- [Protocol Support](#protocol-support) - What's supported in ACP v1\n- [ACP Specification](https://agentclientprotocol.com) - Official protocol docs\n\n---\n\n## Core Concepts\n\n### The Agent-Client Model\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Client \u2502 \u2190\u2500\u2500 JSON-RPC \u2500\u2500\u2192 \u2502 Agent \u2502\n\u2502 (Editor) \u2502 over stdio \u2502 (AI Tool) \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2191 \u2191\n \u2502 \u2502\n User Interface AI Model\n File System Code Analysis\n Permissions Code Generation\n```\n\n### Key Components\n\n#### 1. **Protocol Layer** (`chuk_acp.protocol`)\n\nThe core protocol implementation:\n\n- **JSON-RPC 2.0**: Request/response and notification messages\n- **Message Types**: Initialize, session management, prompts\n- **Content Types**: Text, images, audio, resources, annotations\n- **Capabilities**: Negotiate features between client and agent\n\n#### 2. **Transport Layer** (`chuk_acp.transport`)\n\nCommunication mechanism:\n\n- **Stdio Transport**: Process-based communication (current)\n- **Extensible**: WebSocket, HTTP, etc. (future)\n\n#### 3. **Type System** (`chuk_acp.protocol.types`)\n\nStrongly-typed protocol structures:\n\n- Content types (text, image, audio)\n- Capabilities and features\n- Session modes and states\n- Tool calls and permissions\n\n### The ACP Flow\n\n```\n1. INITIALIZE\n Client \u2500\u2500\u2192 Agent: Protocol version, capabilities\n Agent \u2500\u2500\u2192 Client: Agent info, supported features\n\n2. SESSION CREATION\n Client \u2500\u2500\u2192 Agent: Working directory, MCP servers\n Agent \u2500\u2500\u2192 Client: Session ID\n\n3. PROMPT TURN\n Client \u2500\u2500\u2192 Agent: User prompt (text, images, etc.)\n Agent \u2500\u2500\u2192 Client: [Streaming updates]\n Agent \u2500\u2500\u2192 Client: Stop reason (end_turn, max_tokens, etc.)\n\n4. ONGOING INTERACTION\n - Session updates (thoughts, tool calls, messages)\n - Permission requests (file access, terminal, etc.)\n - Mode changes (ask \u2192 code \u2192 architect)\n - Cancellation support\n```\n\n---\n\n## Complete Examples\n\n### Example 1: Echo Agent (Using Library)\n\nA minimal agent that echoes user input using chuk-acp library helpers:\n\n```python\n\"\"\"echo_agent.py - Agent using chuk-acp library\"\"\"\nimport json\nimport sys\nimport uuid\nfrom typing import Dict, Any\n\nfrom chuk_acp.protocol import (\n create_response,\n create_error_response,\n create_notification,\n METHOD_INITIALIZE,\n METHOD_SESSION_NEW,\n METHOD_SESSION_PROMPT,\n METHOD_SESSION_UPDATE,\n)\nfrom chuk_acp.protocol.types import (\n AgentInfo,\n AgentCapabilities,\n SessionUpdate,\n TextContent,\n)\n\nclass EchoAgent:\n def __init__(self):\n self.sessions = {}\n\n def handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:\n \"\"\"Use library types instead of manual dict construction.\"\"\"\n agent_info = AgentInfo(name=\"echo-agent\", version=\"0.1.0\")\n agent_capabilities = AgentCapabilities()\n\n return {\n \"protocolVersion\": 1,\n \"agentInfo\": agent_info.model_dump(exclude_none=True),\n \"agentCapabilities\": agent_capabilities.model_dump(exclude_none=True),\n }\n\n def handle_session_new(self, params: Dict[str, Any]) -> Dict[str, Any]:\n session_id = f\"session_{uuid.uuid4().hex[:8]}\"\n self.sessions[session_id] = {\"cwd\": params.get(\"cwd\")}\n return {\"sessionId\": session_id}\n\n def handle_session_prompt(self, params: Dict[str, Any]) -> Dict[str, Any]:\n session_id = params[\"sessionId\"]\n prompt = params[\"prompt\"]\n\n # Use library helpers to create notification\n text_content = TextContent(\n text=f\"Echo: You said '{prompt[0].get('text', '')}'\"\n )\n\n session_update = SessionUpdate(\n sessionUpdate=\"agent_message_chunk\",\n content=text_content\n )\n\n notification = create_notification(\n method=METHOD_SESSION_UPDATE,\n params={\n \"sessionId\": session_id,\n \"update\": session_update.model_dump(exclude_none=True),\n },\n )\n\n sys.stdout.write(json.dumps(notification.model_dump(exclude_none=True)) + \"\\n\")\n sys.stdout.flush()\n\n return {\"stopReason\": \"end_turn\"}\n\n def run(self):\n for line in sys.stdin:\n message = json.loads(line.strip())\n method = message.get(\"method\")\n msg_id = message.get(\"id\")\n\n try:\n # Route to handler using method constants\n if method == METHOD_INITIALIZE:\n result = self.handle_initialize(message.get(\"params\", {}))\n elif method == METHOD_SESSION_NEW:\n result = self.handle_session_new(message.get(\"params\", {}))\n elif method == METHOD_SESSION_PROMPT:\n result = self.handle_session_prompt(message.get(\"params\", {}))\n else:\n raise Exception(f\"Unknown method: {method}\")\n\n # Use library helper to create response\n response = create_response(id=msg_id, result=result)\n except Exception as e:\n # Use library helper for error responses\n response = create_error_response(id=msg_id, code=-32603, message=str(e))\n\n sys.stdout.write(json.dumps(response.model_dump(exclude_none=True)) + \"\\n\")\n sys.stdout.flush()\n\nif __name__ == \"__main__\":\n EchoAgent().run()\n```\n\n> **Note**: This demonstrates using the library's protocol helpers (`create_response`, `create_notification`, `TextContent`, etc.) instead of manual JSON construction. See `examples/echo_agent.py` for the complete implementation.\n\n### Example 2: Client with Session Updates\n\nCapture and handle streaming updates from agent:\n\n```python\n\"\"\"client_with_updates.py - Capture session/update notifications\"\"\"\nimport asyncio\nimport uuid\n\nimport anyio\n\nfrom chuk_acp import (\n stdio_transport,\n send_initialize,\n send_session_new,\n ClientInfo,\n ClientCapabilities,\n TextContent,\n)\nfrom chuk_acp.protocol import (\n create_request,\n JSONRPCNotification,\n JSONRPCResponse,\n METHOD_SESSION_PROMPT,\n METHOD_SESSION_UPDATE,\n)\n\nasync def main():\n async with stdio_transport(\"python\", [\"examples/echo_agent.py\"]) as (read, write):\n # Initialize\n init_result = await send_initialize(\n read, write,\n protocol_version=1,\n client_info=ClientInfo(name=\"client\", version=\"1.0.0\"),\n capabilities=ClientCapabilities()\n )\n print(f\"Connected to {init_result.agentInfo.name}\")\n\n # Create session\n session = await send_session_new(read, write, cwd=\"/tmp\")\n\n # Send prompt and capture notifications\n prompt_text = \"Write a hello world function\"\n print(f\"User: {prompt_text}\")\n\n request_id = str(uuid.uuid4())\n request = create_request(\n method=METHOD_SESSION_PROMPT,\n params={\n \"sessionId\": session.sessionId,\n \"prompt\": [TextContent(text=prompt_text).model_dump(exclude_none=True)],\n },\n id=request_id,\n )\n await write.send(request)\n\n # Collect notifications and response\n agent_messages = []\n stop_reason = None\n\n with anyio.fail_after(60.0):\n while stop_reason is None:\n message = await read.receive()\n\n # Handle session/update notifications\n if isinstance(message, JSONRPCNotification):\n if message.method == METHOD_SESSION_UPDATE:\n params = message.params or {}\n\n # Agent message chunks\n update = params.get(\"update\", {})\n if update.get(\"sessionUpdate\") == \"agent_message_chunk\":\n content = update.get(\"content\", {})\n if isinstance(content, dict) and \"text\" in content:\n agent_messages.append(content[\"text\"])\n\n # Thoughts (optional)\n if \"thought\" in params:\n print(f\"[Thinking: {params['thought']}]\")\n\n # Tool calls (optional)\n if \"toolCall\" in params:\n tool = params[\"toolCall\"]\n print(f\"[Calling: {tool.get('name')}]\")\n\n # Handle response\n elif isinstance(message, JSONRPCResponse):\n if message.id == request_id:\n result = message.result\n if isinstance(result, dict):\n stop_reason = result.get(\"stopReason\")\n\n # Display captured agent messages\n if agent_messages:\n print(f\"Agent: {''.join(agent_messages)}\")\n\n print(f\"Completed: {stop_reason}\")\n\nasyncio.run(main())\n```\n\n> **Key Point**: To capture `session/update` notifications, you need to manually handle the request/response loop instead of using `send_session_prompt()`, which discards notifications. See `examples/simple_client.py` for a complete working example.\n\n### Example 3: Agent with File System Access\n\nAgent that can read/write files:\n\n```python\n\"\"\"file_agent.py - Agent with filesystem capabilities\"\"\"\nfrom chuk_acp.protocol.types import AgentCapabilities\n\n# Declare filesystem capabilities\ncapabilities = AgentCapabilities(\n filesystem=True # Enables fs/read_text_file and fs/write_text_file\n)\n\nasync def handle_file_operation(session_id: str, operation: str, path: str):\n \"\"\"Request file access from client.\"\"\"\n\n # Request permission\n permission = await send_session_request_permission(\n read, write,\n session_id=session_id,\n request=PermissionRequest(\n id=\"perm-123\",\n description=f\"Read file: {path}\",\n tools=[{\"name\": \"fs/read_text_file\", \"arguments\": {\"path\": path}}]\n )\n )\n\n if permission.granted:\n # Read the file via client\n # (Client implements fs/read_text_file method)\n pass\n```\n\n### Example 4: Multi-Session Client\n\nManage multiple concurrent sessions:\n\n```python\n\"\"\"multi_session_client.py\"\"\"\nimport asyncio\nfrom chuk_acp import stdio_transport, send_session_new, send_session_prompt\n\nasync def create_and_run_session(read, write, cwd: str, prompt: str):\n \"\"\"Create a session and send a prompt.\"\"\"\n session = await send_session_new(read, write, cwd=cwd)\n result = await send_session_prompt(\n read, write,\n session_id=session.sessionId,\n prompt=[TextContent(text=prompt)]\n )\n return result\n\nasync def main():\n async with stdio_transport(\"python\", [\"my_agent.py\"]) as (read, write):\n # Initialize once\n await send_initialize(...)\n\n # Run multiple sessions concurrently\n tasks = [\n create_and_run_session(read, write, \"/project1\", \"Refactor auth\"),\n create_and_run_session(read, write, \"/project2\", \"Add tests\"),\n create_and_run_session(read, write, \"/project3\", \"Fix bug #123\"),\n ]\n\n results = await asyncio.gather(*tasks)\n print(f\"Completed {len(results)} sessions\")\n\nasyncio.run(main())\n```\n\n---\n\n## API Reference\n\n### High-Level Client\n\nThe `ACPClient` provides the simplest way to interact with ACP agents:\n\n#### Direct Usage\n\n```python\nfrom chuk_acp import ACPClient\n\nasync with ACPClient(\"python\", [\"agent.py\"]) as client:\n # Access agent information\n print(f\"Agent: {client.agent_info.name}\")\n print(f\"Session: {client.current_session.sessionId}\")\n\n # Send prompts\n result = await client.send_prompt(\"Hello!\")\n print(result.full_message) # Complete agent response\n print(result.stop_reason) # Why agent stopped\n\n # Create new sessions\n new_session = await client.new_session(cwd=\"/other/path\")\n```\n\n#### Configuration-Based Usage\n\nUse standard ACP configuration format (compatible with Zed, VSCode, etc.):\n\n```python\nfrom chuk_acp import ACPClient, AgentConfig, load_agent_config\n\n# Method 1: Create config directly\nconfig = AgentConfig(\n command=\"kimi\",\n args=[\"--acp\"],\n env={\"DEBUG\": \"true\"},\n cwd=\"/optional/path\"\n)\n\nasync with ACPClient.from_config(config) as client:\n result = await client.send_prompt(\"Hello!\")\n\n# Method 2: Load from JSON file\nconfig = load_agent_config(\"~/.config/my-app/agent.json\")\nasync with ACPClient.from_config(config) as client:\n result = await client.send_prompt(\"Hello!\")\n\n# Method 3: From dictionary (like editor configs)\nconfig = AgentConfig(**{\n \"command\": \"kimi\",\n \"args\": [\"--acp\"],\n \"env\": {}\n})\nasync with ACPClient.from_config(config) as client:\n result = await client.send_prompt(\"Hello!\")\n```\n\n**Example JSON config file:**\n```json\n{\n \"command\": \"kimi\",\n \"args\": [\"--acp\"],\n \"env\": {\n \"DEBUG\": \"true\",\n \"LOG_LEVEL\": \"info\"\n },\n \"cwd\": \"/optional/path\"\n}\n```\n\n**Key Classes:**\n- `ACPClient` - Main client class\n- `AgentConfig` - Standard ACP configuration format\n- `load_agent_config()` - Load config from JSON file\n- `PromptResult` - Contains response and all notifications\n- `SessionInfo` - Session information\n- `SessionUpdate` - Individual notification from agent\n\n### Low-Level Protocol API\n\nFor fine-grained control over the protocol:\n\n### Protocol Helpers\n\n#### JSON-RPC Message Helpers\n\nBuild protocol messages using library helpers:\n\n```python\nfrom chuk_acp.protocol import (\n create_request,\n create_response,\n create_error_response,\n create_notification,\n)\n\n# Create a request\nrequest = create_request(\n method=\"session/prompt\",\n params={\"sessionId\": \"session-1\", \"prompt\": [...]},\n id=\"req-123\"\n)\n\n# Create a response\nresponse = create_response(id=\"req-123\", result={\"stopReason\": \"end_turn\"})\n\n# Create an error response\nerror = create_error_response(id=\"req-123\", code=-32603, message=\"Internal error\")\n\n# Create a notification\nfrom chuk_acp.protocol.types import SessionUpdate, TextContent\n\nsession_update = SessionUpdate(\n sessionUpdate=\"agent_message_chunk\",\n content=TextContent(text=\"Hello!\")\n)\nnotification = create_notification(\n method=\"session/update\",\n params={\n \"sessionId\": \"session-1\",\n \"update\": session_update.model_dump(exclude_none=True)\n }\n)\n```\n\n#### Method Constants\n\nUse constants instead of string literals for protocol methods:\n\n```python\nfrom chuk_acp.protocol import (\n METHOD_INITIALIZE,\n METHOD_SESSION_NEW,\n METHOD_SESSION_PROMPT,\n METHOD_SESSION_UPDATE,\n METHOD_SESSION_CANCEL,\n METHOD_FS_READ_TEXT_FILE,\n METHOD_FS_WRITE_TEXT_FILE,\n METHOD_TERMINAL_CREATE,\n # ... and more\n)\n\n# Use in message routing\nif method == METHOD_INITIALIZE:\n # Handle initialize\n pass\nelif method == METHOD_SESSION_PROMPT:\n # Handle prompt\n pass\n```\n\n### Transport\n\n#### `stdio_transport(command, args)`\n\nCreate a stdio transport connection to an agent.\n\n```python\nasync with stdio_transport(\"python\", [\"agent.py\"]) as (read_stream, write_stream):\n # Use streams for communication\n pass\n```\n\n### Initialization\n\n#### `send_initialize(read, write, protocol_version, client_info, capabilities)`\n\nInitialize the connection and negotiate capabilities.\n\n```python\nresult = await send_initialize(\n read_stream,\n write_stream,\n protocol_version=1,\n client_info=ClientInfo(name=\"my-client\", version=\"1.0.0\"),\n capabilities=ClientCapabilities(filesystem=True)\n)\n# result.agentInfo, result.capabilities, result.protocolVersion\n```\n\n### Session Management\n\n#### `send_session_new(read, write, cwd, mcp_servers=None, mode=None)`\n\nCreate a new session.\n\n```python\nsession = await send_session_new(\n read_stream,\n write_stream,\n cwd=\"/absolute/path\",\n mode=\"code\" # Optional: ask, architect, code\n)\n# session.sessionId\n```\n\n#### `send_session_prompt(read, write, session_id, prompt)`\n\nSend a prompt to the agent.\n\n```python\nresult = await send_session_prompt(\n read_stream,\n write_stream,\n session_id=\"session-123\",\n prompt=[\n TextContent(text=\"Write a function\"),\n ImageContent(data=\"base64...\", mimeType=\"image/png\")\n ]\n)\n# result.stopReason: end_turn, max_tokens, cancelled, refusal\n```\n\n> **Note**: `send_session_prompt` discards `session/update` notifications from the agent. To capture agent responses (message chunks, thoughts, tool calls), manually handle the request/response loop. See Example 2 or `examples/simple_client.py` for details.\n\n#### `send_session_cancel(write, session_id)`\n\nCancel an ongoing prompt turn.\n\n```python\nawait send_session_cancel(write_stream, session_id=\"session-123\")\n```\n\n### Content Types\n\n#### `TextContent(text)`\n\nPlain text content.\n\n```python\ncontent = TextContent(text=\"Hello, world!\")\n```\n\n#### `ImageContent(data, mimeType)`\n\nBase64-encoded image.\n\n```python\ncontent = ImageContent(\n data=\"iVBORw0KGgoAAAANSUhEUgA...\",\n mimeType=\"image/png\"\n)\n```\n\n#### `AudioContent(data, mimeType)`\n\nBase64-encoded audio.\n\n```python\ncontent = AudioContent(\n data=\"SUQzBAA...\",\n mimeType=\"audio/mpeg\"\n)\n```\n\n---\n\n## Protocol Support\n\nchuk-acp implements the **complete ACP v1 specification**.\n\n### \u2705 Baseline Agent Methods (Required)\n\n| Method | Description | Status |\n|--------|-------------|--------|\n| `initialize` | Protocol handshake and capability negotiation | \u2705 |\n| `authenticate` | Optional authentication | \u2705 |\n| `session/new` | Create new conversation sessions | \u2705 |\n| `session/prompt` | Process user prompts | \u2705 |\n| `session/cancel` | Cancel ongoing operations | \u2705 |\n\n### \u2705 Optional Agent Methods\n\n| Method | Capability | Status |\n|--------|------------|--------|\n| `session/load` | Resume previous sessions | \u2705 |\n| `session/set_mode` | Change session modes | \u2705 |\n\n### \u2705 Client Methods (Callbacks)\n\n| Method | Description | Status |\n|--------|-------------|--------|\n| `session/request_permission` | Request user approval for actions | \u2705 |\n| `fs/read_text_file` | Read file contents | \u2705 |\n| `fs/write_text_file` | Write file contents | \u2705 |\n| `terminal/create` | Create terminal sessions | \u2705 |\n| `terminal/output` | Stream terminal output | \u2705 |\n| `terminal/release` | Release terminal control | \u2705 |\n| `terminal/wait_for_exit` | Wait for command completion | \u2705 |\n| `terminal/kill` | Terminate running commands | \u2705 |\n\n### \u2705 Content Types\n\n- Text content (baseline - always supported)\n- Image content (base64-encoded)\n- Audio content (base64-encoded)\n- Embedded resources\n- Resource links\n- Annotations\n\n### \u2705 Session Features\n\n- Session management (create, load, cancel)\n- Multiple parallel sessions\n- Session modes: `ask`, `architect`, `code`\n- Session history replay\n- MCP server integration\n\n### \u2705 Tool Integration\n\n- Tool calls with status tracking (`pending`, `in_progress`, `completed`, `failed`)\n- Permission requests\n- File location tracking\n- Structured output (diffs, terminals, content)\n- Slash commands (optional)\n\n### \u2705 Protocol Requirements\n\n- **File paths**: All paths must be absolute \u2705\n- **Line numbers**: 1-based indexing \u2705\n- **JSON-RPC 2.0**: Strict compliance \u2705\n- **Extensibility**: `_meta` fields and custom methods \u2705\n\n---\n\n## Architecture\n\n### Project Structure\n\n```\nchuk-acp/\n\u251c\u2500\u2500 src/chuk_acp/\n\u2502 \u251c\u2500\u2500 protocol/ # Core protocol implementation\n\u2502 \u2502 \u251c\u2500\u2500 jsonrpc.py # JSON-RPC 2.0 (requests, responses, errors)\n\u2502 \u2502 \u251c\u2500\u2500 acp_pydantic_base.py # Optional Pydantic support\n\u2502 \u2502 \u251c\u2500\u2500 types/ # Protocol type definitions\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 content.py # Content types (text, image, audio)\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 capabilities.py # Client/agent capabilities\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 session.py # Session types and modes\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 tools.py # Tool calls and permissions\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 plan.py # Task planning types\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 terminal.py # Terminal integration\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 ...\n\u2502 \u2502 \u2514\u2500\u2500 messages/ # Message handling\n\u2502 \u2502 \u251c\u2500\u2500 initialize.py # Initialize/authenticate\n\u2502 \u2502 \u251c\u2500\u2500 session.py # Session management\n\u2502 \u2502 \u251c\u2500\u2500 filesystem.py # File operations\n\u2502 \u2502 \u251c\u2500\u2500 terminal.py # Terminal operations\n\u2502 \u2502 \u2514\u2500\u2500 send_message.py # Core messaging utilities\n\u2502 \u2502\n\u2502 \u251c\u2500\u2500 transport/ # Transport layer\n\u2502 \u2502 \u251c\u2500\u2500 base.py # Abstract transport interface\n\u2502 \u2502 \u2514\u2500\u2500 stdio.py # Stdio transport (subprocess)\n\u2502 \u2502\n\u2502 \u2514\u2500\u2500 __init__.py # Public API exports\n\u2502\n\u251c\u2500\u2500 examples/ # Working examples\n\u2502 \u251c\u2500\u2500 echo_agent.py # Simple echo agent\n\u2502 \u251c\u2500\u2500 simple_client.py # Basic client\n\u2502 \u251c\u2500\u2500 quick_start.py # Getting started\n\u2502 \u2514\u2500\u2500 comprehensive_demo.py # Full-featured demo\n\u2502\n\u251c\u2500\u2500 tests/ # Test suite\n\u2502 \u251c\u2500\u2500 test_protocol_compliance.py # Spec compliance\n\u2502 \u251c\u2500\u2500 test_jsonrpc.py # JSON-RPC tests\n\u2502 \u251c\u2500\u2500 test_types.py # Type system tests\n\u2502 \u251c\u2500\u2500 test_messages.py # Message handling\n\u2502 \u2514\u2500\u2500 test_stdio_transport.py # Transport tests\n\u2502\n\u2514\u2500\u2500 .github/ # CI/CD workflows\n \u251c\u2500\u2500 workflows/\n \u2502 \u251c\u2500\u2500 ci.yml # Testing and linting\n \u2502 \u251c\u2500\u2500 publish.yml # PyPI publishing\n \u2502 \u2514\u2500\u2500 codeql.yml # Security scanning\n \u2514\u2500\u2500 ...\n```\n\n### Design Principles\n\n1. **Protocol First**: Strict adherence to ACP specification\n2. **Type Safety**: Comprehensive type hints throughout\n3. **Optional Dependencies**: Pydantic is optional, not required\n4. **Async by Default**: Built on `anyio` for async/await\n5. **Extensibility**: Custom methods and `_meta` fields supported\n6. **Testability**: Loosely coupled, dependency injection\n7. **Zero-Config**: Works out of the box with sensible defaults\n\n### Layer Separation\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 User Code (Agents/Clients) \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 High-Level API (messages/) \u2502 \u2190 send_initialize, send_prompt, etc.\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Protocol Layer (types/, jsonrpc) \u2502 \u2190 Content types, capabilities\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Transport Layer (transport/) \u2502 \u2190 Stdio, future: WebSocket, HTTP\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n---\n\n## Testing\n\n### Running Tests\n\n```bash\n# Run all tests\nmake test\n\n# Run with coverage\nmake test-cov\n\n# Run specific test file\nuv run pytest tests/test_protocol_compliance.py -v\n\n# Test without Pydantic (fallback mode)\nuv pip uninstall pydantic\nuv run pytest\n```\n\n### Test Categories\n\n- **Protocol Compliance** (`test_protocol_compliance.py`): Validates ACP spec adherence\n- **JSON-RPC** (`test_jsonrpc.py`): JSON-RPC 2.0 implementation\n- **Types** (`test_types.py`): Type system and content types\n- **Messages** (`test_messages.py`): Message handling and serialization\n- **Transport** (`test_stdio_transport.py`): Transport layer\n\n### Code Quality Checks\n\n```bash\n# Format code\nmake format\n\n# Lint\nmake lint\n\n# Type check\nmake mypy\n\n# Security scan\nmake security\n\n# All checks\nmake check\n```\n\n---\n\n## Relationship to MCP\n\n**ACP** and **MCP** (Model Context Protocol) are complementary protocols:\n\n| Protocol | Purpose | Focus |\n|----------|---------|-------|\n| **MCP** | What data/tools agents can access | Context & tools |\n| **ACP** | Where the agent lives in your workflow | Agent lifecycle |\n\n### Integration\n\nACP reuses MCP data structures for content types and resources:\n\n```python\nfrom chuk_acp.protocol.types import (\n TextContent, # From MCP\n ImageContent, # From MCP\n ResourceContent, # From MCP\n)\n\n# ACP sessions can specify MCP servers\nsession = await send_session_new(\n read, write,\n cwd=\"/project\",\n mcp_servers=[\n MCPServer(\n name=\"filesystem\",\n command=\"npx\",\n args=[\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path\"]\n )\n ]\n)\n```\n\n### When to Use What\n\n- **Use ACP** to build AI coding agents that integrate with editors\n- **Use MCP** to provide context and tools to language models\n- **Use both** for a complete AI-powered development environment\n\n---\n\n## Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for:\n\n- Development setup\n- Code style and standards\n- Testing requirements\n- Pull request process\n- Release workflow\n\n### Quick Start for Contributors\n\n```bash\n# Clone and setup\ngit clone https://github.com/chuk-ai/chuk-acp.git\ncd chuk-acp\nuv venv\nsource .venv/bin/activate\nuv pip install -e \".[dev,pydantic]\"\n\n# Run checks\nmake check\n\n# Run examples\ncd examples && python simple_client.py\n```\n\n### Areas for Contribution\n\n- \ud83d\udc1b Bug fixes and issue resolution\n- \u2728 New features (check ACP spec for ideas)\n- \ud83d\udcda Documentation improvements\n- \ud83e\uddea Additional test coverage\n- \ud83c\udf10 Additional transports (WebSocket, HTTP, etc.)\n- \ud83c\udfa8 Example agents and clients\n- \ud83d\udd27 Tooling and developer experience\n\n---\n\n## License\n\nThis project is licensed under the **Apache License 2.0**.\n\nSee [LICENSE](LICENSE) for full details.\n\n---\n\n## Links\n\n### Official Resources\n\n- **ACP Specification**: https://agentclientprotocol.com\n- **GitHub Repository**: https://github.com/chuk-ai/chuk-acp\n- **PyPI Package**: https://pypi.org/project/chuk-acp/\n- **Issue Tracker**: https://github.com/chuk-ai/chuk-acp/issues\n- **Discussions**: https://github.com/chuk-ai/chuk-acp/discussions\n- **CLI Documentation**: [CLI.md](CLI.md)\n\n### Related Projects\n\n**ACP Agents:**\n- **Claude Code**: https://github.com/zed-industries/claude-code-acp - Anthropic's official Claude adapter\n- **Kimi**: https://github.com/MoonshotAI/kimi-cli - AI coding agent from Moonshot AI\n\n**Protocols:**\n- **Model Context Protocol (MCP)**: https://modelcontextprotocol.io - Data & tool access for agents\n- **Language Server Protocol (LSP)**: https://microsoft.github.io/language-server-protocol/ - Inspiration for ACP\n\n### Community\n\n- Report bugs: [GitHub Issues](https://github.com/chuk-ai/chuk-acp/issues)\n- Ask questions: [GitHub Discussions](https://github.com/chuk-ai/chuk-acp/discussions)\n- Contribute: See [CONTRIBUTING.md](CONTRIBUTING.md)\n\n---\n\n<div align=\"center\">\n\n**Built with \u2764\ufe0f for the AI coding community**\n\n[\u2b50 Star us on GitHub](https://github.com/chuk-ai/chuk-acp) | [\ud83d\udce6 Install from PyPI](https://pypi.org/project/chuk-acp/) | [\ud83d\udcd6 Read the Spec](https://agentclientprotocol.com)\n\n</div>\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Agent Client Protocol (ACP) implementation for Python",
"version": "0.3.0",
"project_urls": {
"Documentation": "https://agentclientprotocol.com",
"Homepage": "https://github.com/chuk-ai/chuk-acp",
"Repository": "https://github.com/chuk-ai/chuk-acp"
},
"split_keywords": [
"acp",
" agent-client-protocol",
" ai",
" coding-agent",
" editor"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "211071a43af2f9c4548db58b7054f5a1283f9efe4e5e0b98dbfd112e180f318d",
"md5": "a96865e489d1158c297d9f472428b1c3",
"sha256": "f3df8763e20b5af57127b3bfc3c6b3fdda5d057dfd9c10cb64f30fc6094b1eb9"
},
"downloads": -1,
"filename": "chuk_acp-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a96865e489d1158c297d9f472428b1c3",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 16206,
"upload_time": "2025-11-09T12:18:31",
"upload_time_iso_8601": "2025-11-09T12:18:31.293852Z",
"url": "https://files.pythonhosted.org/packages/21/10/71a43af2f9c4548db58b7054f5a1283f9efe4e5e0b98dbfd112e180f318d/chuk_acp-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "29dc6698b6d148f768d7e238491aa46daf07139c01fae3a785d6a0c7f3b3b660",
"md5": "a571e06b5ffca80b9402cfedbad9db90",
"sha256": "61de553f9c1d2ff046b7d0514c1e8c6eda1199f4fa29c4b2e7ea59ba66115c48"
},
"downloads": -1,
"filename": "chuk_acp-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "a571e06b5ffca80b9402cfedbad9db90",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 29954,
"upload_time": "2025-11-09T12:18:32",
"upload_time_iso_8601": "2025-11-09T12:18:32.754019Z",
"url": "https://files.pythonhosted.org/packages/29/dc/6698b6d148f768d7e238491aa46daf07139c01fae3a785d6a0c7f3b3b660/chuk_acp-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-11-09 12:18:32",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "chuk-ai",
"github_project": "chuk-acp",
"github_not_found": true,
"lcname": "chuk-acp"
}