A2A v1.0 — lo que aprendimos implementando un estándar que casi nadie implementa

Nuestro AgentCard estuvo inválido en producción durante semanas y no teníamos forma de saberlo. Se servía con 200, tenía el JSON bien formado, los campos que pide la documentación, y cualquier cliente casero lo leía sin quejarse. El día que lo pasamos por el SDK oficial de Python —cuyos tipos son literalmente el protobuf generado de la spec— lo rechazó de dos maneras distintas.
Esa tarde entendimos algo sobre A2A que ningún tutorial dice.
Primero: el material que hay enseña un dialecto muerto
A2A —Agent2Agent, el protocolo para que agentes de distintos proveedores se hablen entre sí— llegó a v1.0 en abril de 2026 bajo la Linux Foundation. La v1.0 rompió con la 0.3 en casi todo lo que se toca al escribir un cliente:
Ahora la parte incómoda. El curso de A2A de DeepLearning.AI —hecho con Google Cloud e IBM— es de enero de 2026. Es anterior al release de v1.0. Los codelabs de Google, casi todos, igual. Lo de Udemy, igual. Quien estudie hoy con el material que sale primero en cualquier búsqueda va a escribir un cliente que no habla con nada.
No es un detalle de purista: un SendMessage contra un servidor que espera
message/send no degrada, no negocia, no avisa. Simplemente no existe.
Segundo: el .proto manda sobre la documentación, y la documentación no lo sabe
La spec dice en su §1.4 que specification/a2a.proto es "the single authoritative
normative definition". Es una frase que uno lee como formalidad legal y sigue
adelante. Es literal, y sus propios ejemplos la contradicen.
Los dos rechazos que nos comió el validador:
Dos cosas pasan aquí. La primera es que la forma del ejemplo está mal, y es la forma
que uno escribiría de memoria porque es la de OpenAPI. La segunda duele más: el
alias security no existe en el proto. Emitirlo no es un campo de más que un
parser ignora — un parser estricto rechaza el card entero por campo desconocido.
Un campo que salió de la documentación oficial invalidaba todo el documento.
La lección práctica cabe en una línea: si vas a implementar A2A, tu prueba de humo no es "mi card carga en el navegador", es "el SDK oficial parsea mi card". Nosotros usamos el de Python, 1.1.2, porque sus tipos vienen del protobuf y no de la prosa.
Tercero: ¿cuánta gente está del otro lado?
Aquí es donde la investigación dejó de ser técnica. Un audit de API Evangelist del 29 de julio de 2026 sondeó 20,185 hosts buscando agent cards.
Diez. En todo el sondeo. Y hay un detalle que resume el estado del ecosistema mejor
que cualquier gráfica: a2a-registry.org publica un card que declara
protocolVersion: 1.0 y tiene url en la raíz. Es decir, un card 0.3 diciendo que
es 1.0. El registro central del protocolo no pasa su propia validación.
Contra el otro estándar de la casa, medido con la API de GitHub y la de npm en agosto de 2026:
Casi tres veces más estrellas y veintiocho veces menos uso. Eso no es una métrica de adopción, es una métrica de interés.
Cuarto: lo que dice la gente que sí lo probó
El documento más útil que encontramos no fue un post de ingeniería sino un . Hay quien lo corre en producción y lo describe bien —"es como microservicios para agentes"—, pero las dos frases que se repiten en el hilo son:
"Lo probamos y nos quedamos con patrones agent-behind-MCP."
"Nos dimos cuenta de que no necesitábamos un agente del otro lado."
Nadie está enojado con A2A. El sentimiento dominante en ese hilo no es hostilidad: es indiferencia, que es un problema bastante peor para un estándar cuyo valor entero depende de que haya alguien a quien llamar.
Lo comprobamos por otro lado: ningún agente de código publica un AgentCard. Ni Codex, ni opencode, ni Roo Code —estos dos con issues abiertas pidiéndolo—, ni siquiera Goose, que vive en la misma fundación que A2A e implementó ACP en su lugar. Ese mundo entero eligió MCP para herramientas y ACP para editores.
Lo que hicimos con ese hueco
Un hueco documentado es una invitación. Publicamos (MIT): el agente de código en Rust —binario estático de 4.29 MiB— con AgentCard propio y A2A v1.0 completo.
No lo forkeamos, y la razón es interesante. noob tiene en su CI un tope duro de
8 MiB de binario y 45 crates, y renuncia al runtime async a propósito. Meterle un
servidor HTTP con streaming habría violado las tres cosas. Entonces el agente expone
un modo serve que habla frames JSON por línea sobre un contrato versionado, y un
sidecar traduce.
Y el mapeo salió casi identidad, que es la mejor señal de que un protocolo está bien diseñado:
Esos dos últimos merecen una nota. STEER —inyectar contexto en un turno vivo— es de
esas cosas de la spec que uno lee y piensa "¿quién necesita esto?", hasta que ya
tenías exactamente esa primitiva con otro nombre. Y ask es el único caso real
de INPUT_REQUIRED que hemos visto en la práctica: el agente bloquea el turno
esperando un sí o un no. Todo lo demás que se documenta como input-required suele ser
en realidad una tarea nueva.
La trampa que costó dos bugs
Al reabrir una sesión, noob serve reproduce todos los frames previos. Nuestro
primer intento fue tragar el replay hasta el primer turn.start. No funciona: ese
turn.start es el del turno viejo, así que el cliente veía la conversación
entera repetida en cada mensaje.
El segundo intento fue un reloj de silencio —cuando dejen de llegar frames por un rato, el replay terminó— arrancado en el spawn. Tampoco: el proceso tarda unos 100 ms en levantar, y para cuando el reloj empieza a contar, el replay ya se coló.
Lo que sí funciona es de una obviedad que sólo llega después: el reloj lo arranca el primer frame, no el spawn.
Cinco bugs que sólo aparecen cuando despliegas de verdad
Nuestros agentes corren en microVMs Firecracker aisladas, y ahí el protocolo dejó de ser el problema:
- Alpine no arrancaba. El horneado de la imagen declara units de systemd; en
Alpine
/sbin/inites busybox y no sabe nada de units. - El unit no se declaraba con
CMDsino con unruntime.yaml— que es exactamente el tipo de cosa que no aparece en ningún error, sólo en un silencio. spawn('noob')dabaENOENT. ElPATHde systemd no incluye/usr/local/bin.- systemd no hereda los
ENVdel Dockerfile, así que el sidecar caía a un workspace inexistente. Y aquí está la trampa cruel de Node:spawncon uncwdque no existe reportaENOENTseñalando al binario, no al directorio. Se pierde un buen rato diagnosticando la pieza equivocada. - Un fallo de spawn sin manejar el evento
'error'es excepción no capturada en Node, y tumbaba todas las sesiones del proceso, no sólo la que falló.
Ninguno de los cinco es culpa de A2A. Todos son el costo real de "implementamos el protocolo", y ninguno sale en la spec.
El veredicto honesto
A2A no fue un error. Es un estándar de la Linux Foundation con AWS, Microsoft, Google, Salesforce y SAP en el comité técnico; es una casilla que abre conversaciones empresariales que sin ella no se abren; costó días, no meses; y no excluye nada —MCP sigue, nuestros formatos propios siguen.
Tampoco es un motor de crecimiento, y decirlo importa. El riesgo real no es que A2A falle: es que se quede donde están esos estándares que todos "soportan" en la nota de prensa mientras la integración de verdad sigue siendo a medida, caso por caso.
Hay un antecedente que se parece demasiado. UDDI proponía directorios centrales de servicios descritos en un formato común para que los sistemas se descubrieran solos. Agent cards firmadas más registros centrales es, estructuralmente, lo mismo. UDDI murió por falta de servicios que registrar — que es exactamente lo que dice el sondeo de los 20,185 hosts.
Nosotros apostamos a que el hueco se llena por abajo, con implementaciones que
funcionen de verdad, no con anuncios. Por eso noob-a2a es MIT y por eso Ghosty
Teams ya consume cards de terceros: si vas a publicar uno, ya tienes con quién
probarlo.
Parte 2: ACP, el otro protocolo — el que sí eligieron los agentes de código. La comparación de primera mano da un resultado distinto, y esa es una historia con menos ruinas.