Ghosty
Blog

ACP, parte 2 — el día que el relé pasó mensajes que no conocía

Después de implementar A2A completo, implementamos ACP. Uno nos costó 250 líneas de traductor y 28 tests; el otro fue una tubería de líneas JSON. La diferencia se vio en la primera prueba real, cuando por el cable llegaron eventos que nuestro código nunca había oído nombrar.

7 min de lecturaFixter
  • agentes
  • ACP
  • A2A
  • MCP
  • protocolos
  • microVM
  • Ghosty Teams
Grabado renacentista del taller de un grabador: varios artesanos trabajan planchas de cobre en la misma mesa, cada uno en la suya
Sculptura in Aes, Stradanus, c. 1591 — Cleveland Museum of Art (CC0)

En el post anterior contamos cómo implementamos A2A de punta a punta contra el a2a.proto normativo. La parte más cara de ese trabajo no fue el transporte ni la autenticación: fue el traductor. Nuestro agente habla su propio dialecto de eventos, y para que del otro lado llegara A2A legítimo hubo que escribir un mapeo campo por campo — alrededor de 250 líneas y 28 tests que existen para garantizar que la traducción no pierda nada.

Esta semana implementamos ACP. El traductor no existe.

Primero, la confusión de siglas

Antes de nada hay que desactivar una mina que está por todo internet. Hubo otro ACP: Agent Communication Protocol, de IBM y Cisco, que sí competía de frente con A2A. Se descontinuó en agosto de 2025 y su equipo se sumó a A2A. Buena parte del contenido que hoy encuentras buscando "ACP vs A2A" habla de ése, no del vivo.

El ACP del que hablamos aquí es el Agent Client Protocol, nacido en Zed. Y no compite con nada, porque los tres protocolos que importan hoy resuelven ejes distintos:

                MCP                     ACP                     A2A        agente ↔ herramientas   persona ↔ agente        agente ↔ agente                                (su editor)             (de otra organización)
        "dame acceso a           "quiero trabajar        "delega esta tarea         la base de datos"        con este agente         a un tercero"                                  dentro de mi IDE"

Un agente serio los usa los tres, en capas. Preguntarse cuál gana es como preguntarse si gana HTTP o SQL.

Los números, medidos hoy

Antes de escribir código fuimos a la API de GitHub y a npm. Agosto de 2026:

ProtocoloEstrellas del repo de la specDescargas npm / mes
MCP8,991195,971,908
A2A25,4026,853,239
ACP4,00861,142

Los números de A2A cuentan algo incómodo: más estrellas que MCP y 28 veces menos uso. Interés que todavía no se convierte en implementación.

Los de ACP miden mal, y hay que decirlo: ACP se implementa en Rust, compilado dentro del binario del editor o del agente. Nadie lo instala como dependencia de npm, así que el contador de descargas ve una fracción del mundo real.

La adopción hay que buscarla en otro lado. El repo ya no vive en zed-industries: migró a una organización neutral, agentclientprotocol. Tiene 100+ contribuidores y 243 commits en los últimos 30 días. Entre quienes más commits mandan hay gente de JetBrains y de Microsoft — un dev advocate de VS Code — aunque la línea oficial de Microsoft siga siendo únicamente MCP.

Del lado de los clientes: Zed nativo, JetBrains AI Assistant, cuatro plugins de neovim, emacs, extensiones de VS Code de terceros, Qt Creator, Obsidian, Jupyter. Y del lado de los agentes hay un registro oficial con 38 que hablan ACP nativo: Goose, opencode, Claude Code vía wrapper, Codex, Gemini CLI con --acp, Qwen, Cline, Kimi, Copilot CLI.

Para contrastar: el audit más reciente de A2A rastreó 20,185 hosts en internet y encontró alrededor de 10 agent cards válidos.

Lo que construimos

Un template de microVM Firecracker con Goose dentro —el agente de Block, ahora en la Agentic AI Foundation, Apache-2.0— y un relé de Node que hace WebSocket ↔ stdio.

Ese relé existe por una sola razón. ACP asume que el cliente lanza al agente como proceso hijo y le habla por stdin/stdout. Cruzando la red no hay relación padre-hijo; eso es lo único que falta, no el stdio. Así que el relé es el padre dentro de la caja, y retransmite:

navegador ──WebSocket──▶ Caddy ──▶ router ──▶ proxy ──▶ [ microVM ]                                                          relé (padre)                                                            │ stdin/stdout                                                          goose --acp

Funcionó a la primera. initializesession/newsession/prompt → PONG, atravesando Caddy, el router y el proxy público, con DeepSeek detrás — Goose trae DeepSeek de primera clase, su definición declara deepseek-v4-flash y deepseek-v4-pro. Cero cambios en Go: el WebSocket ya pasaba.

La diferencia que lo decidió todo

Aquí es donde los dos protocolos se separan de verdad.

Para A2A hubo que traducir, porque nuestro agente no habla A2A. Para ACP no hay nada que traducir, porque Goose ya lo habla nativo. El relé no interpreta: mueve líneas de JSON-RPC de un lado a otro.

Y eso se notó en la primera prueba real. Por el cable llegaron agent_thought_chunk —el razonamiento del modelo, en vivo—, usage_update, available_commands_update, session_info_update. El relé los pasó sin conocer ninguno.

Con un traductor de por medio, cada uno de esos eventos habría que mapearlo a mano, y lo que no está mapeado no llega: se pierde en silencio, sin error, sin log. Una tubería no tiene esa clase de fugas.

Grabado de San Jerónimo trabajando concentrado en su estudio, rodeado de sus herramientas, con un león dormido a sus pies

El agente en su celda, con sus propias herramientas a la mano.

Tres decisiones del relé que no eran obvias

/busy se mide por sockets, no por turnos. Nuestro supervisor consulta ese endpoint antes de congelar una microVM. Una sesión ACP abierta es trabajo aunque esté callada: el agente está pensando, o el humano está leyendo. Con el criterio de turnos la VM se congelaría con la sesión viva.

Auth por ticket firmado, no por Bearer. Un new WebSocket() de navegador no puede poner el header Authorization — la API no lo permite, punto. El ticket viaja en el query string con HMAC y ventana de tiempo.

Heartbeat propio. No es precaución teórica: el sidecar de colaboración (Hocuspocus) de esa misma flota ya descubrió que sin ping/pong algo en el camino corta las conexiones ociosas. En ACP la conexión ociosa es el caso normal, no el raro.

El detalle que valida toda la arquitectura de cajas

En ACP hay tres familias de métodos que van al revés de lo que uno esperaría: fs/read_text_file, fs/write_text_file y terminal/* son cosas que el agente le pide al cliente. Tiene sentido en el caso de origen: el editor es quien tiene los archivos, incluidos los buffers sin guardar.

Son opcionales y se negocian en initialize. Si el cliente no las declara, el agente usa su propio filesystem y su propia terminal — que es exactamente nuestro caso, con una microVM aislada.

Y hay un RFD para ACP v2 que las elimina, con el argumento literal de que "many Agents are moving toward their own sandboxing and execution configuration instead". El protocolo camina hacia donde ya estábamos parados.

Lo que hoy es stdio, mañana puede no serlo

Lo único estandarizado hoy es stdio, pero la spec dice explícitamente que es transport-agnostic y permite transportes propios. Existe un Transports Working Group con un RFD en borrador de Streamable HTTP + WebSocket: endpoint único /acp, con el upgrade a WebSocket como perfil de primera clase.

El día que aterrice, nuestro relé sobra. Y eso está perfectamente bien: escribimos 400 líneas para tapar un hueco temporal del protocolo, no para casarnos con ellas.

La crítica que sí hay que hacerle

Circula mucho la analogía "ACP es el LSP de los agentes". La propia comunidad la ha puesto en duda en Hacker News, con razón: un language server reporta sobre el código; un agente lo modifica. Eso arrastra diffs, aprobaciones y flujos con estado que LSP nunca tuvo que modelar. La analogía ayuda a entender la forma —un protocolo entre editores y motores— y estorba en cuanto entras al detalle.

El veredicto

No son alternativas. A2A y ACP resuelven ejes distintos y ninguno sustituye al otro. Pero si la pregunta es "¿con cuántas contrapartes puedo hablar mañana?", ACP tiene 38 agentes y varios editores reales, y A2A tiene diez agent cards en todo internet.

En corto:

  • Tu producto es un agente que debe vivir dentro del editor de alguien → ACP.
  • Tu producto conecta agentes entre organizaciones → A2A.
  • Sólo necesitas darle herramientas a tu agente → ninguno de los dos, MCP y ya.

Lo que sigue

Nos quedamos pensando en algo. Si el "cliente" de ACP puede ser cualquier cosa que hable el protocolo, no tiene por qué ser un editor. Puede ser un chat de equipo.

En ese mundo, session/request_permission deja de ser un modal y se convierte en un mensaje con botones. Y un hilo resulta ser mejor superficie de aprobación que un modal en un IDE por tres razones: es asíncrono, es de todo el equipo, y el hilo mismo queda como bitácora de auditoría.

Eso es lo próximo que vamos a construir.*

Pruébalo gratis hoy

Sin código. Sin complicaciones. Crea tu agente y ponlo a trabajar en minutos.

Ghosty ® 2026. Todos los derechos reservados.