ACP Internals

The ACP adapter wraps Hermes’ synchronous AIAgent in an async JSON-RPC stdio server.

Key implementation files:

Boot flow

hermes acp / hermes-acp / python -m acp_adapter
  -> acp_adapter.entry.main()
  -> load ~/.hermes/.env
  -> configure stderr logging
  -> construct HermesACPAgent
  -> acp.run_agent(agent)

Stdout is reserved for ACP JSON-RPC transport. Human-readable logs go to stderr.

Major components

HermesACPAgent

acp_adapter/server.py implements the ACP agent protocol.

Responsibilities:

SessionManager

acp_adapter/session.py tracks live ACP sessions.

Each session stores:

The manager is thread-safe and supports:

Event bridge

acp_adapter/events.py converts AIAgent callbacks into ACP session_update events.

Bridged callbacks:

Because AIAgent runs in a worker thread while ACP I/O lives on the main event loop, the bridge uses:

asyncio.run_coroutine_threadsafe(...)

Permission bridge

acp_adapter/permissions.py adapts dangerous terminal approval prompts into ACP permission requests.

Mapping:

Timeouts and bridge failures deny by default.

Tool rendering helpers

acp_adapter/tools.py maps Hermes tools to ACP tool kinds and builds editor-facing content.

Examples:

Session lifecycle

new_session(cwd)
  -> create SessionState
  -> create AIAgent(platform="acp", enabled_toolsets=["hermes-acp"])
  -> bind task_id/session_id to cwd override

prompt(..., session_id)
  -> extract text from ACP content blocks
  -> reset cancel event
  -> install callbacks + approval bridge
  -> run AIAgent in ThreadPoolExecutor
  -> update session history
  -> emit final agent message chunk

Cancelation

cancel(session_id):

Forking

fork_session() deep-copies message history into a new live session, preserving conversation state while giving the fork its own session ID and cwd.

Provider/auth behavior

ACP does not implement its own auth store.

Instead it reuses Hermes’ runtime resolver:

So ACP advertises and uses the currently configured Hermes provider/credentials.

Working directory binding

ACP sessions carry an editor cwd.

The session manager binds that cwd to the ACP session ID via task-scoped terminal/file overrides, so file and terminal tools operate relative to the editor workspace.

Duplicate same-name tool calls

The event bridge tracks tool IDs FIFO per tool name, not just one ID per name. This is important for:

Without FIFO queues, completion events would attach to the wrong tool invocation.

Approval callback restoration

ACP temporarily installs an approval callback on the terminal tool during prompt execution, then restores the previous callback afterward. This avoids leaving ACP session-specific approval handlers installed globally forever.

Current limitations