Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docusaurus/.claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"enableAllProjectMcpServers": true,
"enabledMcpjsonServers": [
"playwright"
],
"enableAllProjectMcpServers": true
"permissions": {
"allow": [
"Skill(git-commit-push)"
]
}
}
112 changes: 112 additions & 0 deletions docusaurus/docs/features/acp-runners.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
sidebar_position: 4
title: ACP Runners
description: Execute spec tasks via external ACP (Agent Communication Protocol) tools. DevoxxGenie communicates with ACP-compatible CLIs using JSON-RPC 2.0 over stdin/stdout for structured agent interactions.
keywords: [devoxxgenie, acp runners, agent communication protocol, json-rpc, claude, kimi, gemini, kilocode, agent loop, spec-driven development]
image: /img/devoxxgenie-social-card.jpg
---

# ACP Runners

ACP (Agent Communication Protocol) Runners let you execute spec tasks via **external CLI tools** that speak the ACP protocol — a structured, bidirectional communication layer built on **JSON-RPC 2.0 over stdin/stdout**. Unlike [CLI Runners](cli-runners.md) which pipe plain-text prompts and read stdout, ACP provides typed messages, capability negotiation, and structured streaming.

ACP Runners integrate with both [Spec-driven Development](spec-driven-development.md) (single task execution) and the [Agent Loop](sdd-agent-loop.md) (batch task execution).

## How It Works

DevoxxGenie spawns the ACP tool as a child process and communicates over stdin/stdout using JSON-RPC 2.0. The protocol begins with a capability handshake, then DevoxxGenie sends task prompts as structured messages and receives streaming responses.

```
┌──────────────────┐ JSON-RPC 2.0 ┌──────────────────────┐
│ DevoxxGenie │◀═══════════════▶│ ACP Tool │
│ (ACP Client) │ stdin/stdout │ (Claude/Kimi/...) │
└──────────────────┘ └──────────────────────┘
│ │
1. Spawns process 2. Handshake (initialize)
3. Sends prompt via 4. Streams structured
ACP message response chunks back
5. Receives completion 6. Process stays alive
with metadata for next message
```

### Protocol Flow

1. **Initialize** — Client sends `initialize` with supported capabilities; the tool responds with its capabilities
2. **Send Prompt** — Client sends the task prompt as a structured ACP message
3. **Receive Response** — Tool streams response chunks back, including text, file operations, and terminal commands
4. **Completion** — Tool signals completion; client processes the final result

## Supported ACP Tools

| ACP Tool | Executable | Description |
|----------|-----------|-------------|
| **Claude** | `claude-code-acp` | Claude Code via the [claude-code-acp](https://github.com/zed-industries/claude-code-acp) bridge by Zed Industries |
| **Copilot** | `copilot --acp` | GitHub Copilot CLI in ACP mode |
| **Kimi** | `kimi` | Moonshot AI's coding assistant with ACP support |
| **Gemini CLI** | `gemini` | Google's Gemini CLI with ACP protocol mode |
| **Kilocode** | `kilocode` | Kilocode's AI coding agent |
| **Custom** | *(user-defined)* | Any ACP-compatible tool |

## Setup

1. Open **Settings** > **Tools** > **DevoxxGenie** > **CLI/ACP Runners**
2. Scroll to the **ACP Runners** section
3. Click **+** to add a new ACP tool
4. Select the **Type** from the dropdown — the executable path is pre-filled with sensible defaults
5. Adjust the **Executable path** if your CLI is installed in a different location
6. Click **Test Connection** to verify the ACP handshake succeeds
7. Click **OK**, then **Apply**

### Claude via claude-code-acp

Claude Code doesn't natively speak ACP, but Zed Industries maintains the [claude-code-acp](https://github.com/zed-industries/claude-code-acp) bridge that wraps Claude Code in an ACP-compatible interface.

To set it up:

1. Install the bridge: `npm install -g @anthropic-ai/claude-code-acp` (or follow the repository instructions)
2. In DevoxxGenie, add a new ACP tool with **Type: Claude** — the executable path auto-fills to `claude-code-acp`
3. Ensure Claude Code is installed and authenticated (`claude --version` should work)
4. Click **Test Connection** to verify the ACP handshake

## Configuration Reference

| Field | Description |
|-------|-------------|
| **Type** | Preset type (Claude, Copilot, Kimi, Gemini, Kilocode, Custom). Selecting a type auto-fills the executable path. |
| **Executable path** | Path to the ACP-compatible CLI binary (e.g., `claude-code-acp`, `copilot`, `kimi`, `gemini`) |
| **Enabled** | Toggle to enable/disable a tool without deleting its configuration |

## ACP vs CLI Runners

| Feature | CLI Runners | ACP Runners |
|---------|-------------|-------------|
| **Communication** | Plain text over stdin/stdout | JSON-RPC 2.0 over stdin/stdout |
| **Protocol** | One-shot process per task | Persistent process with structured messages |
| **Streaming** | Raw stdout stream | Typed response chunks |
| **Capability negotiation** | None | Handshake with capability exchange |
| **MCP integration** | Auto-generated MCP config file | Not required (protocol handles context) |
| **Process lifecycle** | Spawned and terminated per task | Stays alive for multiple interactions |

:::tip
Claude Code is available both as a **CLI Runner** (direct stdin/stdout) and as an **ACP Runner** (via the claude-code-acp bridge). The ACP mode provides structured communication and richer streaming, while the CLI mode is simpler to set up.
:::

## Selecting the Execution Mode

The **DevoxxGenie Specs** toolbar contains an execution mode dropdown:

- **LLM Provider** — uses the built-in LLM agent (default)
- **CLI: Claude** / **CLI: Copilot** / etc. — uses CLI runners
- **ACP: Claude** / **ACP: Copilot** / **ACP: Kimi** / **ACP: Gemini** / etc. — uses ACP runners

The selection is persisted across IDE restarts.

## Troubleshooting

| Issue | Cause | Solution |
|-------|-------|----------|
| ACP handshake fails | Tool not installed or wrong path | Check the executable path in **Settings > CLI/ACP Runners**, use **Test Connection** to verify |
| "Connection refused" error | Tool doesn't support ACP protocol | Verify the tool version supports ACP. Some tools require a specific flag or version for ACP mode |
| No response after prompt | Process started but not responding | Check that the tool is authenticated. Try running the executable manually with `--version` to verify installation |
| Test Connection times out | Tool is slow to initialize | Some tools need to download models on first run. Try running the tool manually first to complete initial setup |
| Claude ACP bridge not found | `claude-code-acp` not installed globally | Install via `npm install -g @anthropic-ai/claude-code-acp` and ensure it's on your PATH |
2 changes: 1 addition & 1 deletion docusaurus/docs/features/cli-runners.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Codex CLI does not support MCP, so it cannot update task status directly. The ta

## Setup

1. Open **Settings** > **Tools** > **DevoxxGenie** > **Spec Driven Dev**
1. Open **Settings** > **Tools** > **DevoxxGenie** > **CLI/ACP Runners**
2. Scroll to the **CLI Runners** section
3. Click **+** to add a new CLI tool
4. Select the **Type** from the dropdown — all fields are pre-filled with sensible defaults
Expand Down
1 change: 1 addition & 0 deletions docusaurus/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const sidebars = {
'llm-providers/local-models',
'llm-providers/cloud-models',
'llm-providers/custom-providers',
'features/acp-runners',
'features/cli-runners',
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.devoxx.genie.chatmodel.local.customopenai.CustomOpenAIChatModelFactory;
import com.devoxx.genie.chatmodel.local.gpt4all.GPT4AllChatModelFactory;
import com.devoxx.genie.chatmodel.local.jan.JanChatModelFactory;
import com.devoxx.genie.chatmodel.local.acprunners.AcpRunnersChatModelFactory;
import com.devoxx.genie.chatmodel.local.clirunners.CliRunnersChatModelFactory;
import com.devoxx.genie.chatmodel.local.llamacpp.LlamaChatModelFactory;
import com.devoxx.genie.chatmodel.local.lmstudio.LMStudioChatModelFactory;
Expand Down Expand Up @@ -67,6 +68,7 @@ private ChatModelFactoryProvider() {
case "Kimi" -> new KimiChatModelFactory();
case "GLM" -> new GLMChatModelFactory();
case "CLI Runners" -> new CliRunnersChatModelFactory();
case "ACP Runners" -> new AcpRunnersChatModelFactory();
default -> null;
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.devoxx.genie.chatmodel.local.acprunners;

import com.devoxx.genie.chatmodel.ChatModelFactory;
import com.devoxx.genie.model.CustomChatModel;
import com.devoxx.genie.model.LanguageModel;
import com.devoxx.genie.model.enumarations.ModelProvider;
import com.devoxx.genie.model.spec.AcpToolConfig;
import com.devoxx.genie.ui.settings.DevoxxGenieStateService;
import dev.langchain4j.model.chat.ChatModel;

import java.util.List;

/**
* ChatModelFactory for ACP Runners provider.
* Returns enabled ACP tools as LanguageModel entries.
* ACP Runners bypass Langchain4J entirely — createChatModel/createStreamingChatModel return null.
*/
public class AcpRunnersChatModelFactory implements ChatModelFactory {

@Override
public ChatModel createChatModel(CustomChatModel customChatModel) {
return null;
}

@Override
public List<LanguageModel> getModels() {
return DevoxxGenieStateService.getInstance().getAcpTools().stream()
.filter(AcpToolConfig::isEnabled)
.map(tool -> LanguageModel.builder()
.provider(ModelProvider.ACPRunners)
.modelName(tool.getName())
.displayName(tool.getName())
.apiKeyUsed(false)
.inputCost(0)
.outputCost(0)
.inputMaxTokens(0)
.outputMaxTokens(0)
.build())
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ private LanguageModel createDefaultLanguageModel(@NotNull DevoxxGenieSettingsSer
.outputCost(0)
.inputMaxTokens(0)
.build();
} else if (selectedProvider != null && selectedProvider.equals(ACPRunners)) {
return LanguageModel.builder()
.provider(ACPRunners)
.modelName("")
.displayName("ACP Runner")
.apiKeyUsed(false)
.inputCost(0)
.outputCost(0)
.inputMaxTokens(0)
.build();
} else if (selectedProvider != null &&
(selectedProvider.equals(LMStudio) ||
selectedProvider.equals(GPT4All) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum ModelProvider {
LMStudio("LMStudio", Type.LOCAL),
Ollama("Ollama", Type.LOCAL),
CLIRunners("CLI Runners", Type.LOCAL),
ACPRunners("ACP Runners", Type.LOCAL),

OpenAI("OpenAI", Type.CLOUD),
Anthropic("Anthropic", Type.CLOUD),
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/com/devoxx/genie/model/spec/AcpToolConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.devoxx.genie.model.spec;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AcpToolConfig {

@Getter
public enum AcpType {
CLAUDE("Claude", "claude-code-acp", "acp"),
COPILOT("Copilot", "copilot", "--acp"),
KIMI("Kimi", "kimi", "acp"),
GEMINI("Gemini", "gemini", "acp"),
KILOCODE("Kilocode", "kilocode", "acp"),
CUSTOM("Custom", "", "acp");

private final String displayName;
private final String defaultExecutablePath;
private final String defaultAcpFlag;

AcpType(String displayName, String defaultExecutablePath, String defaultAcpFlag) {
this.displayName = displayName;
this.defaultExecutablePath = defaultExecutablePath;
this.defaultAcpFlag = defaultAcpFlag;
}
}

@Builder.Default
private AcpType type = AcpType.CUSTOM;
@Builder.Default
private String name = "";
@Builder.Default
private String executablePath = "";
@Builder.Default
private String acpFlag = "acp";
@Builder.Default
private boolean enabled = true;
}
11 changes: 11 additions & 0 deletions src/main/java/com/devoxx/genie/service/LLMProviderService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.devoxx.genie.model.LanguageModel;
import com.devoxx.genie.model.enumarations.ModelProvider;
import com.devoxx.genie.model.spec.AcpToolConfig;
import com.devoxx.genie.model.spec.CliToolConfig;
import com.devoxx.genie.service.models.LLMModelRegistryService;
import com.devoxx.genie.ui.settings.DevoxxGenieStateService;
Expand Down Expand Up @@ -48,6 +49,7 @@ public List<ModelProvider> getAvailableModelProviders() {
providers.addAll(getLocalModelProviders());
providers.addAll(getOptionalProviders());
providers.addAll(getCliRunnersProvider());
providers.addAll(getAcpRunnersProvider());

return providers;
}
Expand Down Expand Up @@ -89,6 +91,15 @@ private List<ModelProvider> getModelProvidersWithApiKeyConfigured() {
return optionalModelProviders;
}

private @NotNull List<ModelProvider> getAcpRunnersProvider() {
boolean hasEnabledAcpTool = DevoxxGenieStateService.getInstance().getAcpTools().stream()
.anyMatch(AcpToolConfig::isEnabled);
if (hasEnabledAcpTool) {
return List.of(ModelProvider.ACPRunners);
}
return List.of();
}

private @NotNull List<ModelProvider> getCliRunnersProvider() {
boolean hasEnabledCliTool = DevoxxGenieStateService.getInstance().getCliTools().stream()
.anyMatch(CliToolConfig::isEnabled);
Expand Down
Loading
Loading