ggcode supports the Agent Client Protocol (ACP), allowing it to be used as an AI coding agent in JetBrains IDEs, Zed, and other ACP-compatible editors.
For the extracted standalone ACP client/runtime library and ggcode-side adapter boundary, see docs/acp-go-integration.md.
ACP is a standard protocol developed by JetBrains and Zed Industries for communication between IDEs (clients) and AI coding agents. It uses JSON-RPC 2.0 over stdio.
# Go install
go install github.com/topcheer/ggcode/cmd/ggcode@latest
# Or download from GitHub ReleasesSet up your API key in ~/.ggcode/ggcode.yaml:
vendor: openai
endpoint: default
vendors:
openai:
endpoints:
default:
protocol: openai
base_url: https://api.openai.com/v1
api_key: ${OPENAI_API_KEY}- Open Settings → Tools → Agent Client Protocol
- Click "Add Agent"
- Set the command to:
ggcode acp - Click OK
Add to your Zed settings.json:
{
"agent": {
"providers": [
{
"name": "ggcode",
"command": "ggcode",
"args": ["acp"]
}
]
}
}When you open a chat panel in your IDE, the IDE starts a ggcode acp process and communicates via JSON-RPC 2.0 over stdin/stdout:
┌─────────────────────────┐
│ IDE (JetBrains / Zed) │
│ Chat Panel │
└───────────┬─────────────┘
│ stdin/stdout (JSON-RPC 2.0)
▼
┌─────────────────────────┐
│ ggcode acp │
│ │
│ Transport │◄── initialize, session/new
│ Protocol Handler │◄── session/prompt (user messages)
│ Agent Loop │◄── session/cancel
│ ├── Streaming events │──► session/update (text, tool calls)
│ ├── Tool formatting │──► "Read /tmp/test.go" (not "read_file")
│ ├── ask_user routing │──► session/request_permission (choices)
│ └── Permission checks│──► session/request_permission (approve)
│ Tool System │
│ Session Persistence │
└─────────────────────────┘
- IDE → ggcode:
initialize→ exchange capabilities - IDE → ggcode:
session/new→ create session with project CWD - IDE → ggcode:
session/prompt→ user sends a message - ggcode → IDE:
session/update(agent_message_chunk) → streaming text response - ggcode → IDE:
session/update(tool_call) → tool starts executing - ggcode → IDE:
session/update(tool_call_update) → tool completed/failed with formatted title - ggcode → IDE:
session/request_permission→ ask for approval (dangerous tools) - Repeat 3–7 until the task is done
Tool calls appear in the IDE with human-readable titles, the same format as the TUI:
| Raw tool call | IDE displays |
|---|---|
read_file {"path":"/src/main.go"} |
Read /src/main.go |
edit_file {"file_path":"/src/main.go",...} |
Edit /src/main.go |
write_file {"path":"/src/new.go",...} |
Write /src/new.go |
run_command {"command":"go test ./..."} |
go test ./... |
search_files {"pattern":"TODO"} |
Search TODO |
git_diff {"cached":true} |
Diff --cached |
web_search {"query":"golang"} |
Search golang |
ask_user {"prompt":"Which file?"} |
Shows choice dialog in IDE |
Status updates show pending → completed or failed. Tool results are not sent to the IDE — only the formatted title and status.
When the LLM needs to ask a question, it uses the ask_user tool. In ACP mode this is routed to the IDE:
- Single/multi choice questions → displayed as options in a permission dialog
- Text input questions → not supported by the permission UI, so the LLM falls back to asking in plain text within the conversation
- User cancels → the LLM is told the user dismissed the question and re-asks in plain text
| Mode | Behavior |
|---|---|
auto (default) |
Safe operations auto-approved; dangerous tools ask via IDE permission dialog |
bypass / autopilot |
All tools auto-approved (no dialogs) |
manual |
Every tool call requires IDE approval |
ggcode implements ACP protocol version 1 with the following capabilities:
| Feature | Status |
|---|---|
initialize |
✅ Supported |
authenticate |
✅ Supported (env_var + agent) |
session/new |
✅ Supported (with CWD validation) |
session/prompt |
✅ Supported (streaming) |
session/cancel |
✅ Supported |
session/load |
✅ Supported |
session/set_mode |
✅ Supported |
session/update notifications |
✅ Streaming (flat spec v1 format) |
session/request_permission |
✅ Supported (tool approval + ask_user) |
| MCP servers | ✅ Dynamic connection |
| Tool calls | ✅ Full tool system with formatted display |
| ask_user | ✅ Routed through IDE permission dialog |
| Image support | ✅ Vision models |
| Session persistence | ✅ JSON-based |
Set your API key as an environment variable:
export GGCODE_API_KEY=your-api-keyWhen using ACP with an IDE, you can authenticate through ggcode's built-in GitHub Device Flow. The IDE will display a code and URL for you to complete authentication.
acp:
enabled: true
log_level: infosystem_prompt: "You are a helpful coding assistant."In ACP mode, ggcode uses auto permissions by default. Safe operations (read, search, list) are auto-approved; dangerous operations (write, execute) require IDE approval via session/request_permission.
ggcode ACP fully supports running multiple instances simultaneously. Each IDE window starts its own independent ggcode acp process via stdio, so there is no conflict between instances.
JetBrains Window A (Project X) JetBrains Window B (Project Y)
│ │
ggcode acp ggcode acp
│ │
Session CWD: /projects/x Session CWD: /projects/y
Sessions: ~/.ggcode/acp-sessions/a1b2c3/ Sessions: ~/.ggcode/acp-sessions/d4e5f6/
Each instance is completely independent — no shared state, no IM bridge, no daemon dependency.
Option 1: Project-level config file (auto-discovered)
Create ggcode.yaml or .ggcode/ggcode.yaml in your project root:
# .ggcode/ggcode.yaml — project-specific config
vendor: anthropic
model: claude-sonnet-4-20250514
system_prompt: "You are an expert in this project's codebase."
allowed_dirs:
- .ggcode will automatically discover this config when started from the project directory.
Option 2: Explicit config via --config flag
Configure the IDE agent command as:
ggcode --config /path/to/project-config.yaml acp
Option 3: Per-instance flags
ggcode acp --vendor anthropic --model claude-sonnet-4-20250514
Each session/new request can specify its own MCP servers:
{
"method": "session/new",
"params": {
"cwd": "/projects/my-app",
"mcpServers": [
{
"name": "project-tools",
"command": "node",
"args": ["mcp-server.js"],
"env": [{"name": "PROJECT_ROOT", "value": "/projects/my-app"}]
}
]
}
}- Sessions are persisted per-workspace under
~/.ggcode/acp-sessions/<workspace-hash>/ - Session IDs are cryptographically random (128-bit) — no collision risk
- Each process instance manages its own sessions independently
ACP mode is a focused IDE integration. The following features from daemon/TUI mode are intentionally excluded:
| Feature | Available in ACP? | Why |
|---|---|---|
| TUI (terminal UI) | ❌ | IDE provides the chat UI |
| IM (instant messaging) | ❌ | IDE is the communication channel |
| WebUI | ❌ | IDE provides the interface |
| A2A (agent-to-agent) | ❌ | Single-agent per IDE window |
| Daemon bridge | ❌ | Stateless process per IDE window |
If you need IM, WebUI, or A2A features, use ggcode (TUI) or ggcode daemon mode instead.
Ensure your API key is configured in ggcode.yaml or set as an environment variable.
Check stderr for error messages:
ggcode acp 2>acp.logACP uses stdout exclusively for JSON-RPC messages. If you see non-JSON output on stdout, please report it as a bug.
Make sure your IDE supports ACP v1 and displays session/update notifications with tool_call / tool_call_update types.