Skip to content

Feature: Agent Client Protocol (ACP) Server Mode — Run Hermes in Zed, JetBrains, Neovim, Toad & Any ACP-Compatible Editor #569

@teknium1

Description

@teknium1

Overview

Toad by Will McGugan (creator of Rich/Textual) is a unified TUI for AI coding agents that supports 18+ agents via the Agent Client Protocol (ACP). ACP is an open standard (Apache 2.0, by Zed) that standardizes communication between code editors/IDEs and AI agents — analogous to what LSP did for language servers.

Rather than building a custom Toad integration, the real opportunity is implementing ACP's agent-side interface so Hermes Agent becomes usable from every ACP-compatible editor and client — not just Toad, but Zed, JetBrains IDEs, Neovim, Emacs, Obsidian, marimo, and any future ACP client. This is a "implement once, work everywhere" distribution play.

ACP is backed by Zed and JetBrains (official partnership since Oct 2025), with Google's Gemini CLI as the reference implementation. Agents from Anthropic (Claude Code), OpenAI (Codex), GitHub (Copilot), and others already support it. The protocol reached v0.11.0 (March 4, 2026) and has 2.3k+ GitHub stars.


Research Findings

How ACP Works

ACP uses JSON-RPC 2.0 over stdio (stdin/stdout). The editor spawns the agent as a subprocess and they exchange newline-delimited JSON messages bidirectionally.

Lifecycle:

  1. initialize — Negotiate protocol version & capabilities (file system access, terminal, MCP)
  2. session/new — Create a new conversation (receives CWD, MCP server configs)
  3. session/prompt — Client sends user message as ContentBlock[] (text, image, audio)
  4. Agent streams back session/update notifications (message chunks, tool calls, plans)
  5. Agent may call back to client for file ops (fs/read_text_file, fs/write_text_file), terminal access (terminal/create), and permission requests (session/request_permission)
  6. Turn ends with session/prompt response + stop reason (end_turn, max_tokens, refusal, cancelled)

Agent-Side Methods (what Hermes would implement):

initialize(protocolVersion, clientCapabilities, clientInfo)
  -> InitializeResponse (agentCapabilities, authMethods, protocolVersion)

session/new(cwd, mcpServers)
  -> NewSessionResponse (sessionId, models?, modes?)

session/load(cwd, mcpServers, sessionId)        [optional - resume sessions]
  -> LoadSessionResponse (modes?)

session/prompt(prompt: ContentBlock[], sessionId)
  -> SessionPromptResponse (stopReason: end_turn|max_tokens|refusal|cancelled)

session/set_mode(sessionId, modeId)              [optional]
session/cancel(sessionId)                        [notification]

Client-Side Methods (what the editor provides to the agent):

session/update(sessionId, update: SessionUpdate)
  -> Handles: agent_message_chunk, agent_thought_chunk, tool_call,
     tool_call_update, plan, available_commands_update

session/request_permission(sessionId, options, toolCall)
  -> RequestPermissionResponse

fs/read_text_file(sessionId, path, line?, limit?)  -> {content}
fs/write_text_file(sessionId, path, content)       -> None

terminal/create(command, args?, cwd?, env?)        -> {terminalId}
terminal/output(sessionId, terminalId)             -> {output, exitStatus?}
terminal/wait_for_exit(sessionId, terminalId)      -> {exitCode, signal}
terminal/kill(sessionId, terminalId)
terminal/release(sessionId, terminalId)

Key Data Types:

  • ContentBlock = TextContent | ImageContent | AudioContent | EmbeddedResourceContent | ResourceLinkContent
  • SessionUpdate = UserMessageChunk | AgentMessageChunk | AgentThoughtChunk | ToolCall | ToolCallUpdate | Plan
  • ToolKind = "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other"
  • ToolCallContent = Content | Diff | Terminal (rich structured output for tool calls)

ACP Ecosystem (as of March 2026)

Compatible Editors/Clients (8+):

  • Zed (native, reference client)
  • JetBrains IDEs — IntelliJ, PyCharm, WebStorm, etc. (official partnership)
  • Neovim (via CodeCompanion and avante.nvim plugins)
  • Emacs (via agent-shell)
  • Obsidian (via plugin)
  • Toad (Will McGugan's terminal TUI, Python/Textual)
  • marimo (Python notebook environment)
  • Several community clients (AionUi, aizen)

Compatible Agents (18+):

  • Claude Code (Anthropic) — via claude-code-acp adapter
  • Codex CLI (OpenAI) — via @zed-industries/codex-acp NPX adapter
  • Gemini CLI (Google) — gemini --experimental-acp (reference impl)
  • GitHub Copilot — copilot --acp
  • Goose (Block) — goose acp
  • Amp Code (Sourcegraph), Kiro (AWS), Kimi (Moonshot AI), OpenCode, Mistral Vibe, OpenHands, Docker cagent, and more

Common ACP Launch Patterns:

  • Native subcommand: agent-name acp (Goose, Kiro, Kimi, OpenCode)
  • Flag-based: agent --acp or agent --experimental-acp (Copilot, Gemini)
  • Adapter binary: claude-code-acp, vibe-acp (separate ACP adapter)
  • NPX adapter: npx @zed-industries/codex-acp (Node.js wrappers)

Official SDKs:

  • Python: agent-client-protocol (PyPI, Pydantic models, asyncio)
  • TypeScript: @agentclientprotocol/sdk (npm)
  • Rust: agent-client-protocol (crates.io)
  • Kotlin: acp-kotlin (JVM)

ACP Registry:
Central registry at agentclientprotocol.com/registry. Agents register once and become available in all ACP clients. Zed is deprecating its proprietary extension approach in favor of ACP.

Protocol vs Protocol — Where ACP Fits

Protocol Purpose Hermes Status
MCP (Model Context Protocol) Agent ↔ Tools/Data ✅ Full client (tools/mcp_tool.py)
ACP (Agent Client Protocol) Editor ↔ Agent ❌ Not supported
A2A (Agent-to-Agent) Agent ↔ Agent ❌ Proposed (#514)

ACP is complementary to both — it's the missing "front door" protocol. MCP gives agents tools, A2A gives agents collaborators, ACP gives agents users via editors.

How Toad Implements ACP

Toad (repo: batrachianai/toad, Python 3.14, AGPL-3.0, 2.6k stars) acts as an ACP client:

  • Spawns agent subprocesses via asyncio.create_subprocess_shell()
  • JSON-RPC communication via jsonrpc.py (Server for incoming, API for outgoing)
  • Agent definitions stored as TOML files with: identity, name, run_command (per-OS), install actions
  • Permission system gates dangerous operations through the UI
  • 18 agents supported via TOML configs in src/toad/data/agents/
  • Ad-hoc agent support: toad acp "my-custom-agent-command"
  • Persistent PTY-based shell (separate from ACP agent shell)
  • Session persistence via SQLite

The toad acp "hermes acp" command would work out of the box once Hermes implements ACP.


Current State in Hermes Agent

What we have (relevant):

  • CLI mode (cli.py, ~1200 lines) — prompt_toolkit + Rich, fixed input area, streaming output, slash commands
  • Gateway mode (gateway/) — Platform adapters for Telegram, Discord, WhatsApp, Slack, Home Assistant
  • Platform adapter pattern (gateway/platforms/base.py) — ABC with handle_message(), send_response(), shared session management
  • Callback hooks in AIAgent: tool_progress_callback, clarify_callback, step_callback — these could be wired to ACP's session/update notifications
  • MCP client (tools/mcp_tool.py) — Full MCP support; ACP can forward MCP server configs from the editor to the agent
  • Session management (hermes_state.py, SessionDB) — SQLite-backed, supports save/load/resume

What's missing:

  • Zero ACP protocol support — no references in codebase
  • No JSON-RPC 2.0 server implementation
  • No stdio-based communication mode (CLI uses prompt_toolkit, not raw stdin/stdout JSON)
  • No way for external editors to launch Hermes as a subprocess agent
  • No permission-request callback to the editor/client

Related issues:


Implementation Plan

Skill vs. Tool Classification

This should be a core codebase change because:

  1. It requires a new execution entry point (hermes acp CLI subcommand) that runs the agent in a fundamentally different I/O mode (JSON-RPC over stdio vs interactive terminal)
  2. It needs to wrap the AIAgent execution loop with protocol-specific message framing, capability negotiation, and session lifecycle management
  3. It handles streaming data (real-time session/update notifications for every token chunk, tool call, and plan update)
  4. It requires integration with the existing callback system (tool_progress_callback, step_callback) to emit ACP events
  5. Cannot be expressed as instructions + shell commands — this is runtime protocol handling

Architecturally, this is a new interface mode alongside CLI and gateway — a "protocol adapter" that makes Hermes usable from any ACP-compatible editor.

What We'd Need

  1. New file: acp_server.py — ACP protocol handler (JSON-RPC 2.0 over stdio)

    • Read JSON-RPC from stdin, write to stdout (newline-delimited)
    • Handle: initialize, session/new, session/load, session/prompt, session/cancel, session/set_mode
    • Send: session/update notifications (message chunks, tool calls, plans)
    • Call back to client: fs/read_text_file, fs/write_text_file, terminal/*, session/request_permission
  2. New CLI subcommand: hermes acp — Entry point for ACP mode

    • Starts the ACP server on stdin/stdout
    • No TUI, no prompt — pure protocol mode
    • Editors would launch: hermes acp as their agent subprocess
  3. New dependency: agent-client-protocol (PyPI) — Official Python SDK

    • Pydantic models for all protocol types
    • Asyncio transport helpers for stdio streams
    • Protocol version negotiation utilities
  4. ACP-to-Hermes bridge layer — Maps between ACP events and AIAgent callbacks

    • session/promptagent.run_conversation()
    • AIAgent streaming tokens → session/update (agent_message_chunk)
    • AIAgent tool calls → session/update (tool_call + tool_call_update)
    • AIAgent reasoning → session/update (agent_thought_chunk)
    • session/request_permission ← AIAgent approval hook
  5. Optional: ACP Registry entry — TOML/JSON file describing Hermes for the ACP registry

    • identity: hermes.nousresearch.com
    • run_command: hermes acp
    • install action: pip install hermes-agent (or uv tool install hermes-agent)
  6. Tests: tests/test_acp_server.py — Protocol conformance tests

Phased Rollout

Phase 1: Basic ACP Server — Read/Respond via stdio

  • Implement JSON-RPC 2.0 reader/writer over stdin/stdout
  • Handle initialize with capability negotiation (advertise Hermes capabilities)
  • Handle session/new — create AIAgent session
  • Handle session/prompt — forward user message to AIAgent, stream back response via session/update notifications (agent_message_chunk)
  • Handle session/cancel — interrupt current generation
  • Map AIAgent's tool_progress_callback → ACP tool_call + tool_call_update events
  • Add hermes acp CLI subcommand as entry point
  • Hermes uses its OWN tools (terminal, file ops) — not the editor's
  • Result: Hermes works as an agent in Toad (toad acp "hermes acp") and Zed

Phase 2: Editor-Provided File/Terminal Access + Session Resume

  • Implement ACP client-side method calls (Hermes calling BACK to the editor)
  • Option to use editor's fs/read_text_file/fs/write_text_file instead of Hermes's own file tools — useful when the editor has unsaved changes the filesystem doesn't reflect
  • Option to use editor's terminal/create for command execution — enables editor-managed terminal output display
  • Implement session/request_permission for dangerous operations (respects editor's approval UI)
  • Implement session/load for resuming previous sessions (wire to Hermes's SessionDB)
  • Implement session/set_mode — map to Hermes operational modes if applicable
  • Pass-through MCP server configs from editor's session/new to Hermes's MCP client

Phase 3: ACP Registry, Modes & Polish

  • Submit Hermes to the ACP Registry for automatic discovery in Zed/JetBrains
  • Expose Hermes capabilities as ACP modes (e.g., coding mode, research mode, creative mode)
  • Expose model selection if supported by the editor
  • Plan generation — map Hermes's task planning (todo tool) to ACP Plan objects
  • Thought streaming — map reasoning content to agent_thought_chunk
  • Rich tool call content — structured diffs for patch tool, terminal output for terminal tool
  • Performance optimization for high-throughput streaming

Pros & Cons

Pros

  • Massive distribution: One implementation gives Hermes access to Zed, JetBrains (all IDEs), Neovim, Emacs, Toad, Obsidian, marimo — every major code editor. This is the most efficient way to expand Hermes's reach
  • Industry-standard protocol: ACP is backed by Zed and JetBrains with buy-in from Anthropic, OpenAI, Google, and GitHub. It's the emerging LSP-for-agents
  • Mature Python SDK: agent-client-protocol provides Pydantic models and asyncio transport — minimal custom protocol code needed
  • Complementary to existing interfaces: ACP doesn't replace CLI or gateway — it's a third interface mode. Users who prefer their editor can use Hermes there; users who prefer terminal/messaging keep what they have
  • MCP synergy: ACP is designed to be MCP-friendly. Editors can pass MCP server configs to the agent, which Hermes already knows how to use
  • Relatively scoped: Phase 1 is a focused ~500-line module — JSON-RPC handler + AIAgent bridge. Not a massive architectural change
  • ACP Registry: Once registered, Hermes appears in every ACP client's agent browser/store with zero additional effort

Cons / Risks

  • Pre-1.0 protocol: ACP is at v0.11.0. Breaking changes are possible before GA, though the core lifecycle is stable. Mitigation: pin SDK version, track changelog
  • stdio complexity: Logging, debug output, and anything else writing to stdout would corrupt the JSON-RPC stream. Hermes must redirect all non-protocol output to stderr. Mitigation: configure logging to stderr in ACP mode
  • Tool duality: In Phase 2, deciding whether to use Hermes's native file/terminal tools vs the editor's ACP-provided ones adds complexity. Mitigation: default to Hermes's own tools in Phase 1, add editor tools as opt-in in Phase 2
  • Python 3.14 concern: Toad requires Python 3.14, but ACP itself has no such requirement. Hermes's ACP implementation would work with any Python version the SDK supports
  • AGPL-3.0 caution: Toad itself is AGPL-3.0, but the ACP protocol spec and SDK are Apache 2.0. No license concerns for implementing ACP — just don't copy Toad's code
  • Testing: Protocol conformance testing requires mocking JSON-RPC stdin/stdout. Mitigation: the SDK likely provides test utilities, and Toad's echo_client.py is a reference

Open Questions

  • Should hermes acp be a subcommand of the main CLI, or a separate entry point script (like claude-code-acp)?
  • In Phase 2, should Hermes prefer its own file/terminal tools or the editor's? Or should it be configurable? (Using editor's tools means Hermes benefits from unsaved editor state but loses independence)
  • Should ACP mode load the same skills and memory as CLI mode, or should it have a reduced skill set tuned for coding tasks?
  • How should Hermes handle ACP's permission system? Should it always delegate to the editor's UI, or should it have its own approval logic?
  • Should we submit to the ACP Registry in Phase 1 (early visibility) or Phase 3 (after polish)?
  • How does ACP mode interact with Hermes's existing session persistence? Should ACP sessions be stored in the same SessionDB?

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions