ACP: Agent Client Protocol
ACP es un protocolo JSON-RPC 2.0 sobre stdio que permite a los editores e IDEs controlar un agente ZeroClaw en ejecución como host de sesión. JSON delimitado por saltos de línea, ligero, transmisible en streaming y fácil de conectar a un subproceso.
Piénsalo como “LSP para agentes”: el editor lanza zeroclaw acp, envía prompts a través de stdin y recibe actualizaciones de sesión en stdout.
Para qué lo usarías
- Una extensión del editor que ofrece un comando “preguntar al agente sobre este archivo”
- Una integración de multiplexor de terminal que abre un panel lateral con una sesión de agente
- Un corredor de CI que controla el agente de forma programática sin una configuración completa de la puerta de enlace
- Cualquier cosa que desee sesiones de agente sin HTTP y sin vincular un puerto
Forma del protocolo: v1
Todos los mensajes son JSON-RPC 2.0 (delimitados por saltos de línea). ZeroClaw implementa la versión 1 del protocolo.
initialize
Handshake. Devuelve las capacidades del servidor.
→ {"jsonrpc":"2.0","id":1,"método":"inicializar"}
← {"jsonrpc":"2.0","id":1,"resultado":{
"protocolVersion": 1,
agentCapabilities: {
loadSession: true,
promptCapabilities: {image: false, audio: false, "embeddedContext": true},
mcpCapabilities: {http: false, sse: false},
sessionCapabilities: {reanudar: {}, cerrar: {}}
},
agentInfo: {
"nombre": zeroclaw-acp,
title: ZeroClaw ACP,
versión: 0.7.x
},
authMethods: [],
"_meta": {
zeroclaw: {
"modeloPredeterminado": anthropic/claude-sonnet-4.6,
"maxSessions": 10,
`sessionTimeoutSecs`: 3600
}
}
}}
loadSession: true y sessionCapabilities: {"resume": {}, "close": {}} indican que la persistencia de sesiones está activa. Si el almacén SQLite no se pudo abrir al inicio, los tres están ausentes o son false y session/load, session/resume y session/close devolverán errores SESSION_NOT_FOUND.
_meta.zeroclaw contiene campos de extensión específicos de ZeroClaw que no están en la especificación base de ACP. Los clientes que solo implementan la especificación base pueden ignorar este objeto.
promptCapabilities.embeddedContext: true significa que los clientes pueden enviar bloques resource incrustados con un blob en base64 en session/prompt (ver abajo). image y audio permanecen en false por ahora. Los ContentBlocks nativos de Image/Audio de ACP aún no se anuncian.
El servidor siempre responde protocolVersion: 1. Si envías un protocolVersion: 0 desde el lado del cliente, igualmente recibirás 1 de vuelta; los clientes v0 verán errores de análisis en las nuevas estructuras de mensajes; consulta compatibilidad de versiones más abajo.
session/new
Abre una sesión de agente aislada.
agentAlias indica qué entrada [agents.<alias>] configurada se utilizará. Es obligatorio cuando hay más de un agente configurado; cuando existe exactamente un agente, se selecciona automáticamente y el campo puede omitirse. El alias acepta la forma camelCase agentAlias, la forma snake_case agent_alias o la forma abreviada agent.
Al conectar a través del endpoint del gateway WebSocket, la URL de conexión también puede incluir un parámetro de consulta ?agent=<alias>. Ese valor es un predeterminado con ámbito de conexión, no un cambio de configuración. La resolución de alias para session/new sigue esta precedencia:
agentAlias/agent_alias/agentexplícito en los parámetros desession/new?agent=<alias>de gateway en la URL de WebSocket[acp].default_agent- única entrada
[agents.<alias>]configurada cuando existe exactamente una - error cuando no se puede resolver ningún alias
Cada alias resuelto, sin importar qué paso lo seleccionó, debe nombrar un agente habilitado y despachable. Los alias desconocidos y los agentes configurados pero deshabilitados hacen que session/new falle con -32602 INVALID_PARAMS. Un ?agent= vacío o compuesto solo de espacios en blanco se trata como ausente y pasa al siguiente paso.
El modo independiente zeroclaw acp (subproceso stdio) no lee ?agent=; usa un agentAlias explícito o [acp].default_agent en su lugar.
El parámetro opcional cwd (alias: workspaceDir, workspace_dir) fija el límite de acceso a archivos por sesión; se convierte en workspace_dir dentro de SecurityPolicy, que aplican todas las herramientas de archivos. No reubica el estado persistente propio del agente: el estado en texto plano por agente (MEMORY.md, IDENTITY.md, SOUL.md) se encuentra en el espacio de trabajo del agente resuelto (agent_workspace_dir(<alias>), es decir, el espacio de trabajo de [agents.<alias>]), que sigue siendo una raíz permitida adicional; los almacenes SQLite compartidos y el estado de cron se encuentran en config.data_dir. Ninguno de estos es un único workspace_dir a nivel del daemon.
→ {"jsonrpc":"2.0","id":2,"método":"sesión/nueva","parámetros":{
"agentAlias": "myagent",
"cwd": "/ruta/al/proyecto"
}}
← {"jsonrpc":"2.0","id":2,"resultado":{
"sessionId": "s-ab12cd",
workspaceDir: "/ruta/al/proyecto"
}}
cwd se canoniza al recibirlo; la navegación mediante ../ no puede escapar de la raíz prevista. Un cwd explícito se respeta exactamente como límite de la sesión, incluido un subdirectorio más restringido dentro del espacio de trabajo del agente.
Si se omite cwd, el servidor usa el directorio del espacio de trabajo del agente resuelto (espacio de trabajo de [agents.<alias>]), no el directorio desde el que se inició el demonio. La única excepción es un cwd que se canonicaliza a la propia raíz de instalación: clientes como Thunderbolt envían . como marcador de posición, que se resuelve en el directorio de trabajo del demonio. Ese único marcador de posición se trata como «ningún cwd significativo» y también recurre al espacio de trabajo del agente correspondiente, de modo que las cargas y el entorno aislado de la herramienta permanecen fuera de la raíz del demonio. Cualquier otra ruta explícita, incluida una situada por debajo de la raíz de instalación, queda fijada tal como se indica y nunca se amplía.
sesión/indicación
Envía un prompt. La respuesta es una secuencia de notificaciones session/update que se transmiten de vuelta, finalizada por el resultado de session/prompt.
El parámetro prompt acepta una cadena de texto simple o un array de partes de contenido:
"prompt": "Resume los cambios del último commit."- Array: cada elemento es una parte de texto
{"text": "..."}o un bloque de recurso ACP:- Recurso de texto:
{"type": "resource", "resource": {"uri": "file:///path/to/file.rs", "text": "<file contents>"}}. Adjuntos con notación@del editor con texto en línea. - Recurso Blob:
{"type": "resource", "resource": {"uri": "file:///path/to/report.pdf", "mimeType": "application/pdf", "blob": "<base64>"}}. Incrustaciones binarias (PDF, DOCX, imágenes, etc.). ZeroClaw decodifica el blob, lo escribe en{session.workspaceDir}/uploads/(con nombre SHA) y muestra un marcador en el prompt del agente ([Document: …]o[IMAGE: …]paraimage/*). El tamaño máximo decodificado es de 10 MB; los blobs con base64 no válido o de tamaño excesivo devuelvenINVALID_PARAMS.
- Recurso de texto:
Las partes se unen con saltos de línea dobles en el orden en que aparecen. La recepción de blobs es independiente del almacén (no llama a RPC file/attach). La misma función auxiliar de materialización se usa cuando los resultados de herramientas de MCP contienen contenido resource+blob (consulta blobs de recursos incrustados de MCP).
→ {"jsonrpc":"2.0","id":3,"método":"sesión/indicación","parámetros":{
"sessionId": "s-ab12cd",
"prompt": "Resumen de los cambios en el último commit."
}}
← {"jsonrpc":"2.0","método":"session/update","parámetros":{
"sessionId": "s-ab12cd",
actualizar: {sessionUpdate: agent_message_chunk, "contenido": {"tipo":"texto","texto":"El último commit..."}}
}}
← {"jsonrpc":"2.0","método":"session/update","parámetros":{
"sessionId": "s-ab12cd",
actualizar: {sessionUpdate: "llamada_herramienta", toolCallId: tc-1, title: "shell",
"tipo": ejecutar, "estado": "pending", rawInput: {...}}
}}
← {"jsonrpc":"2.0","método":"session/update","parámetros":{
"sessionId": "s-ab12cd",
actualizar: {sessionUpdate: "tool_call_update", toolCallId: tc-1,
"estado": completado, rawOutput: "..."}
}}
← {"jsonrpc":"2.0","id":3,"resultado":{
"sessionId": "s-ab12cd",
"stopReason": "end_turn",
"contenido": "El último commit introduce..."
}}
stopReason es "end_turn" en una finalización normal y "cancelled" cuando el turno fue interrumpido por session/cancel. La señal de finalización de ACP es stopReason; ZeroClaw también incluye la cadena content final actual para los clientes existentes.
Errores:
| Código | Significado |
|---|---|
-32000 SESSION_NOT_FOUND | No hay ninguna sesión activa con el sessionId proporcionado |
-32002 SESSION_BUSY | Un turno de prompt ya está en curso para esta sesión, espera a que se complete o cancélalo primero |
-32602 INVALID_PARAMS | Falta o tiene un formato incorrecto sessionId / prompt |
-32603 INTERNAL_ERROR | La tarea del agente generó un panic o el turno falló |
Notificaciones de session/update (agente → cliente)
ZeroClaw envía cuatro tipos de notificación session/update durante un turno de mensaje. El discriminante es el campo sessionUpdate dentro de update:
Valor de sessionUpdate | Cuando se emite | Campos clave |
|---|---|---|
agent_message_chunk | Cada token de texto en streaming | content.type = "text", content.text |
agent_thought_chunk | Tokens de razonamiento interno (cuando está habilitado) | content.type = "text", content.text |
tool_call | Llamada de herramienta iniciada | toolCallId, title, kind, status: "pending", rawInput |
tool_call_update | Llamada a herramienta completada | toolCallId, status: "completed", rawOutput, content[] |
toolCallId en tool_call y tool_call_update son estables y están correlacionados; la actualización que completa una llamada lleva el mismo toolCallId que la que la abrió.
El campo name en tool_call_update es una extensión de ZeroClaw (no requerida por la especificación base de ACP). Los clientes pueden usarlo para visualización; es seguro ignorarlo.
Entrega de archivos al cliente (deliver_file)
Cuando el agente deba entregar un archivo del espacio de trabajo para su descarga o vista previa, invoca la herramienta deliver_file (path, mimeType opcional, title opcional). Al finalizar, ZeroClaw emite un tool_call_update normal cuyos rawOutput / body permanecen reducidos (un breve resumen legible, sin volcado base64 y sin metadatos de máquina; todos los campos de entrega viajan estructuralmente en el artefacto de herramienta tipado). El tool_call_update.title estándar lleva una etiqueta de chat legible: el title del llamador (cualquier texto, p. ej. "Quarterly report") o el nombre de archivo de forma predeterminada. El arreglo content incluye además un recurso incrustado ACP estándar:
{
"tipo": "contenido",
"contenido": {
"tipo": recurso,
recurso: {
uri: attachment://deliver/9f2c1a7b0e4d5f6a3b8c2d1e0f4a5b6c7d8e9f0a1b2c3d4e5f60718293a4b5c6d.pdf,
mimeType: application/pdf,
blob: "<base64>"
}
}
}
El uri es una identidad opaca basada en contenido direccionado: attachment://deliver/<sha256>.<ext>, el resumen SHA-256 hexadecimal completo de los bytes del archivo. Es seguro para URI y resistente a colisiones con la fortaleza completa del resumen de 256 bits, y nunca se deriva del nombre de archivo proporcionado por el llamador. El mismo resumen completo es el nombre de almacenamiento en disco en uploads/, por lo que contenido distinto nunca genera alias para un archivo ni para un uri. El mismo uri se transporta estructuralmente en el resultado de la herramienta (campo JSON uri) y en el artefacto tipado de la herramienta; no hay trailer de máquina en el texto orientado al modelo. Antes de incrustar el blob, la capa ACP vuelve a leer el archivo y recalcula este hash, rechazando adjuntarlo cuando ya no coincide; un intercambio entre la validación de la herramienta y la entrega es detectado, no confiado. Los clientes como Thunderbolt materializan el blob saliente y construyen un mapa de referencia de citas indexado por ese uri; los agentes deben copiar el uri devuelto en las citas <widget:document-result fileId="…"> / [N] y no deben inventar prefijos. El nombre de visualización en el chat es el tool_call_update.title estándar (el title del llamador, o bien el nombre de archivo). No existe un campo filename en el objeto resource de ACP, y el title es solo para visualización, nunca el nombre en disco.
El archivo debe permanecer dentro del espacio de trabajo de la sesión (mismo entorno aislado que file_read); los archivos de tamaño excesivo (>10 MB) son rechazados por la herramienta.
session/request_permission (agente → cliente, solicitud saliente)
Cuando una herramienta requiere la aprobación del usuario (a través de always_ask en la configuración de autonomía, o las herramientas ask_user/escalate_to_human), ZeroClaw emite una solicitud JSON-RPC del agente al cliente. El cliente debe responder con un resultado antes de que la llamada a la herramienta continúe.
← {"jsonrpc":"2.0","id":zc-out-0,"método":"session/request_permission","parámetros":{
"sessionId": "s-ab12cd",
"options": [
{optionId: "allow-once", "nombre": "Permitir una vez", "tipo": allow_once},
{optionId: allow-always,"nombre": "Permitir siempre","tipo": allow_always},
{optionId: "reject-once", "nombre": "Rechazar", "tipo": reject_once}
],
toolCall: {
toolCallId: "approval-...",
title: ¿Aprobar shell?,
"tipo": ejecutar,
"estado": "pending",
rawInput: {herramienta: "shell", resumen: git status --short},
"contenido": [{"tipo": "contenido", "contenido": {"tipo": "texto", "texto": git status --short}}]
}
}}
→ {"jsonrpc":"2.0","id":zc-out-0,"resultado":{
resultado: {resultado: "seleccionado", optionId: "allow-once"}
}}
El id emitido por el servidor ("zc-out-N") siempre es una cadena con el prefijo zc-out-. La correlación es direccional: cada par coteja las respuestas únicamente con su propio mapa de solicitudes pendientes, por lo que el mismo id textual puede estar en curso de forma independiente en ambas direcciones.
Forma de la respuesta:
{"outcome": {"outcome": "selected", "optionId": "<id>"}}, el usuario seleccionó una opción{"outcome": {"outcome": "cancelled"}}, el usuario descartó el aviso
Si el cliente nunca responde (caída, pérdida de red, el usuario cierra el IDE), la solicitud expira después de sessionTimeoutSecs y se deniega la llamada a la herramienta.
ask_user utiliza el mismo mecanismo session/request_permission, asignando las choices de la pregunta a opciones de permiso. El ask_user de forma libre (sin choices) no es compatible hasta que se implemente la RFD de elicitación de ACP. Llamar a ask_user sin choices en una sesión ACP falla rápidamente con un error claro.
session/cancel (extensión de ZeroClaw)
Aborta un turno de session/prompt en curso. Este método es una extensión de ZeroClaw, no forma parte de la especificación base de ACP. Si ACP estandariza más adelante un session/cancel que entre en conflicto, ZeroClaw moverá su extensión a _meta/session/cancel.
Cancelar vs. detener: session/cancel aborta un turno de prompt en curso y devuelve stopReason: "cancelled" con cualquier texto transmitido acumulado hasta el punto de interrupción. session/stop finaliza la sesión de forma ordenada después de que se complete el turno actual, espera a que el turno termine en lugar de interrumpirlo.
El parámetro canónico es sessionId; session_id se acepta como alias de compatibilidad.
→ {"jsonrpc":"2.0","método":session/cancel,"parámetros":{"sessionId":"s-ab12cd"}}
← {"jsonrpc":"2.0","método":"session/update","parámetros":{
"sessionId": "s-ab12cd",
actualizar: {sessionUpdate: agent_message_chunk, "contenido": {"tipo":"texto","texto":parcial...}}
}}
← {"jsonrpc":"2.0","id":3,"resultado":{
"sessionId": "s-ab12cd",
"stopReason": cancelado,
"contenido": parcial...\n\n[turno cancelado a través del cliente]
}}
Si no hay ningún turno activo para la sesión, la cancelación es una operación nula (noop): se realiza correctamente de forma silenciosa sin error. Esto sigue la semántica de notificaciones de ACP: las notificaciones no deben producir errores.
session/stop (extensión de ZeroClaw)
Finalizar limpiamente una sesión. No está en la especificación base de ACP: es específico de ZeroClaw. Si una futura revisión de la especificación ACP añade session/stop con semántica diferente, esto será renombrado a _meta/session/stop.
→ {"jsonrpc":"2.0","id":4,"método":"session/stop","parámetros":{"sessionId":"s-ab12cd"}}
← {"jsonrpc":"2.0","id":4,"resultado":{"sessionId": "s-ab12cd", "detenido":true}}
session/update (cliente → servidor) (extensión ZeroClaw)
ZeroClaw también acepta notificaciones entrantes session/update (y el alias heredado session/event) desde el cliente para la inyección de eventos personalizados. No forma parte de la especificación base de ACP: es específico de ZeroClaw. Si la especificación de ACP define más adelante un session/update entrante con semántica diferente, este se renombrará a _meta/session/update.
Persistencia de sesión
ZeroClaw persiste automáticamente las sesiones ACP en SQLite. No se requiere configuración, el almacén se abre en <workspace_dir>/sessions/acp-sessions.db cada vez que zeroclaw acp se inicia o se acepta una conexión ACP WebSocket del gateway. Si el archivo no puede crearse (sistema de archivos de solo lectura, permisos incorrectos), el servidor recurre a sesiones solo en memoria y loadSession reporta false en la respuesta de initialize.
Qué se conserva:
- Metadatos de sesión:
sessionId,workspaceDir,created_at,last_activity - Historial completo de la conversación: cada
ConversationMessageescrito después de cada turnosession/promptcompletado, en una transacción atómica por turno
Las sesiones sobreviven a los reinicios de procesos. Una sesión creada en una invocación de zeroclaw acp puede cargarse o reanudarse en una posterior, siempre que se utilice el mismo workspace_dir (y, por lo tanto, el mismo archivo acp-sessions.db).
Las sesiones no se eliminan automáticamente. Usa session/close para desactivar una sesión sin eliminarla, y luego session/load o session/resume para recuperarla.
session/load (extensión de ZeroClaw)
Restaura una sesión previamente persistida con reproducción completa del historial. El servidor inicializa el agente con el historial de conversación almacenado y, a continuación, transmite ese historial de vuelta al cliente como una secuencia de notificaciones session/update antes de retornar. El cliente recibe el mismo flujo de actualizaciones que habría visto si la sesión nunca hubiera terminado.
→ {"jsonrpc":"2.0","id":5,"método":session/load,"parámetros":{"sessionId":"s-ab12cd"}}
← {"jsonrpc":"2.0","método":"session/update","parámetros":{
"sessionId": "s-ab12cd",
actualizar: {sessionUpdate: agent_message_chunk, "contenido": {"tipo":"texto","texto":"El último commit..."}}
}}
← ... (remaining stored messages replayed as session/update notifications)
← {"jsonrpc":"2.0","id":5,"resultado":{}}
Una vez que session/load retorna, la sesión está activa y lista para aceptar llamadas a session/prompt.
Al restaurar una sesión persistida, el servidor reutiliza el alias de propietario almacenado solo si ese agente sigue siendo despachable. De lo contrario, recurre en cadena a [acp].default_agent controlado por el operador → agente único, omitiendo los alias deshabilitados en el camino. El parámetro ?agent= del Gateway es solo un valor predeterminado de session/new y no vuelve a vincular la restauración.
session_id se acepta como alias en snake_case para sessionId.
Errores:
| Código | Significado |
|---|---|
-32000 SESSION_NOT_FOUND | No existe ningún registro para el sessionId proporcionado en el almacén |
-32001 SESSION_LIMIT_REACHED | max_sessions sesiones activas ya en curso |
-32602 INVALID_PARAMS | La sesión ya está activa, llame primero a session/close |
-32603 INTERNAL_ERROR | Error de lectura de SQLite |
session/resume (extensión de ZeroClaw)
Restaura una sesión previamente persistida sin repetición del historial. El agente se inicializa con el historial de conversación almacenado para que tenga el contexto completo del siguiente turno, pero no se emiten notificaciones session/update. Usa esto cuando el cliente ya tiene el historial de una conexión anterior y solo necesita que se restaure el estado del agente.
→ {"jsonrpc":"2.0","id":5,"método":session/resume,"parámetros":{"sessionId":"s-ab12cd"}}
← {"jsonrpc":"2.0","id":5,"resultado":{}}
Después de que session/resume devuelve, la sesión está activa y lista para aceptar llamadas a session/prompt. Los mismos errores que session/load. La selección del alias de restauración sigue las mismas reglas de respaldo del propietario despachable que session/load.
Carga vs. reanudación: usa session/load al reconectar tras una desconexión inesperada y el cliente necesita reconstruir su interfaz a partir del historial almacenado. Usa session/resume cuando el cliente ya tiene el historial (p. ej., lo almacenó localmente) y solo necesita restaurar el estado del agente del lado del servidor.
session/close (extensión de ZeroClaw)
Desactiva una sesión activa: cancela cualquier turno en curso, elimina la sesión del conjunto activo en memoria y anula el registro del canal de retorno ACP. El registro de la sesión en el almacén SQLite no se elimina; la sesión aún puede restaurarse más adelante con session/load o session/resume.
→ {"jsonrpc":"2.0","id":6,"método":session/close,"parámetros":{"sessionId":"s-ab12cd"}}
← {"jsonrpc":"2.0","id":6,"resultado":{}}
session_id se acepta como alias en snake_case para sessionId.
Devuelve SESSION_NOT_FOUND (-32000) si la sesión no está activa actualmente (puede que aún exista en el almacén).
Cerrar vs. detener: session/close desactiva la sesión a la vez que conserva su registro persistente para recargarla más tarde. session/stop también elimina la sesión de la memoria, pero tiene el mismo efecto en el almacén. Ninguno elimina el registro de SQLite.
Configuración
default_agent
Alias del agente que se usará cuando session/new omita agentAlias y haya más de un agente configurado. Cuando existe exactamente un agente, se selecciona automáticamente independientemente de este campo.
Colócalo sobre cualquier superficie:
Panel de control del gateway
Abre /config/acp y configura el campo acp.default_agent.
zerocode
En el panel Config, configure el campo acp.default_agent.
zeroclaw config
zeroclaw config set acp.default_agent <value>
Variable de entorno
Exporte la anulación (shells POSIX; colóquelo en ~/.bashrc, ~/.zshrc, .env o un Dockerfile). Reemplace <alias> con el alias literal:
export ZEROCLAW_acp__default_agent=
max_sessions
Número máximo de sesiones ACP concurrentes. Predeterminado: 10.
Colócalo sobre cualquier superficie:
Panel de control del gateway
Abre /config/acp y configura el campo acp.max_sessions.
zerocode
En el panel Config, configure el campo acp.max_sessions.
zeroclaw config
zeroclaw config set acp.max_sessions <value>
Variable de entorno
Exporte la anulación (shells POSIX; colóquelo en ~/.bashrc, ~/.zshrc, .env o un Dockerfile). Reemplace <alias> con el alias literal:
export ZEROCLAW_acp__max_sessions=
session_timeout_secs
Tiempo de espera de sesión inactiva en segundos. Las sesiones sin actividad durante este período son elegibles para desalojo. Predeterminado: 3600 (1 hora).
Colócalo sobre cualquier superficie:
Panel de control del gateway
Abre /config/acp y configura el campo acp.session_timeout_secs.
zerocode
En el panel Config, establece el campo acp.session_timeout_secs.
zeroclaw config
zeroclaw config set acp.session_timeout_secs <value>
Variable de entorno
Exporte la anulación (shells POSIX; colóquelo en ~/.bashrc, ~/.zshrc, .env o un Dockerfile). Reemplace <alias> con el alias literal:
export ZEROCLAW_acp__session_timeout_secs=
default_agent se consulta cuando session/new omite agentAlias y hay más de un agente configurado; si está ausente y existe exactamente una entrada [agents.<alias>], ese agente se selecciona automáticamente.
Al ejecutar zeroclaw acp como subproceso, el comando inicia el servidor de forma incondicional. Al ejecutarse como demonio, la puerta de enlace expone ACP a través de WebSocket en /acp sin necesidad de configuración adicional. Los clientes de la puerta de enlace pueden agregar ?agent=<alias> a esa URL para que cada agente configurado pueda ser direccionado desde un cliente estándar de la especificación con un agente por punto de conexión; la autenticación (Authorization, Sec-WebSocket-Protocol o ?token=) se aplica antes de que se actualice la conexión, y el parámetro de consulta no otorga ningún acceso más allá de seleccionar entre los agentes ya configurados.
Ejecutando
Como un subproceso (integración típica de IDE):
sh
zeroclaw acp
El binario lee desde stdin, escribe en stdout y sale al recibir EOF.
A través de la puerta de enlace del daemon (remoto o en el mismo host):
Inicie el daemon normalmente. El gateway siempre expone ACP sobre WebSocket en /acp, no se requiere ningún indicador de configuración adicional. Los clientes se conectan directamente: para instalaciones multiagente, use una URL como ws://127.0.0.1:8080/acp?agent=myagent de modo que session/new pueda omitir agentAlias, o a través de zeroclaw-acp-bridge, que conecta el protocolo stdio ACP con el WebSocket del gateway:
sh
zeroclaw-acp-bridge
El bridge lee la dirección del gateway y el token de autenticación desde la misma configuración que el daemon. Cuando el daemon se ejecuta con un directorio de configuración no predeterminado (p. ej., --config-dir /tmp/zeroclaw), apunte el bridge al mismo directorio:
sh
zeroclaw-acp-bridge --config-dir /tmp/zeroclaw
# o equivalentemente:
zeroclaw-acp-bridge --config-dir=/tmp/zeroclaw
También puedes proporcionar el token de portador directamente a través de ZEROCLAW_ACP_BRIDGE_TOKEN si prefieres no depender del archivo de token en caché.
Compatibilidad de versiones
Los clientes de ACP v0 (que usan la respuesta de initialize plana {streaming, maxSessions, ...} y la forma de session/update kind: "text"|"tool_call") verán errores de deserialización al conectarse a un servidor v1. Los discriminantes y las formas de envoltura cambiaron de manera incompatible. Pasos para actualizar:
- Usa
sessionUpdate(nokind) para discriminar las notificacionessession/update. - Analiza los resultados de
session/promptcomo{sessionId, stopReason, content}(no{finished, usage}). - Implementar el manejo de respuestas de
session/request_permission: el mecanismo de aprobación pasó de ser una notificación del servidor a una RPC respondida por el cliente. - Elimina el parámetro
systemPromptdesession/new, no se lee.
Seguridad
ACP hereda el nivel de autonomía de la configuración en ejecución. Cuando [autonomy] level = "supervised", las llamadas a herramientas de riesgo medio activan la aprobación a través del canal de retorno de ACP, una solicitud saliente session/request_permission que el cliente debe confirmar. En el modo full, las llamadas a herramientas se ejecutan sin aprobación y workspace_only queda implícitamente deshabilitado (el agente puede acceder a rutas fuera del cwd de la sesión); forbidden_paths sigue aplicándose.
El cwd de session/new se convierte en el límite del espacio de trabajo de SecurityPolicy que utilizan todas las herramientas de archivos y shell de esa sesión. El prompt del sistema del agente refleja ese mismo espacio de trabajo efectivo de la sesión: el “Directorio de trabajo” del prompt se genera a partir de SecurityPolicy.workspace_dir (el cwd de la sesión o el espacio de trabajo del agente cuando se omite cwd), mientras que la identidad y personalidad del agente (IDENTITY.md, SOUL.md) se cargan desde el espacio de trabajo independiente del agente. Por lo tanto, el modelo ve el directorio que realmente sirve como raíz para sus herramientas de archivos y shell.
Autoridad de archivos con dos raíces. Configurar el cwd de la sesión limita las rutas de archivos y herramientas de shell (lectura/escritura/listado, CWD de inicio del shell y uploads/ de recursos incrustados) a ese directorio. No convierte la sesión en una jaula exclusiva: el espacio de trabajo resuelto del agente sigue siendo una raíz permitida, por lo que los recursos propios del agente (habilidades, identidad y estado por agente en [agents.<alias>]) siguen siendo accesibles independientemente del cwd de la sesión. En otras palabras, workspaceDir controla dónde se establece la raíz de las operaciones de archivos de la sesión, mientras que el espacio de trabajo del agente sigue siendo la base de los recursos propios del agente con ámbito de configuración. Cuando se omite cwd (o es el marcador de posición de la raíz de instalación), ambas coinciden porque la sesión tiene como raíz el propio espacio de trabajo del agente.
Memoria
Las sesiones ACP no interactúan con el sistema de memoria persistente del agente. Esta es una decisión de diseño deliberada: ACP está pensado para tareas de programación dirigidas desde el IDE, no para construir relaciones a largo plazo.
Qué heredan las sesiones de ACP de la configuración del agente: personalidad, habilidades, perfil de riesgo, perfil de ejecución, proveedor del modelo y todas las herramientas que no son de memoria.
Lo que excluyen las sesiones ACP:
- Las herramientas de memoria (
memory_recall,memory_store,memory_forget,memory_export,memory_purge) no están disponibles - La recuperación automática de memoria (el preámbulo de contexto construido a partir de la memoria a largo plazo en cada turno) está deshabilitada
- La copia automática de conversaciones en el almacén de memoria del agente está deshabilitada
El contexto de sesión proviene del historial de conversación persistido en acp-sessions.db. Las sesiones son persistentes, reanudables y eliminables; el historial de sesión sirve como contexto de trabajo, no como la memoria a largo plazo del agente.
Esta separación garantiza que las conversaciones efímeras de asistencia de programación no contaminen la memoria a largo plazo del agente, y que el conocimiento no relacionado de los canales de chat no se filtre en las sesiones de ACP.
Referencia de código
- Servidor ACP:
crates/zeroclaw-channels/src/orchestrator/acp_server.rs - ACP back-channel:
crates/zeroclaw-channels/src/acp_channel.rs - Almacén de sesiones (SQLite):
crates/zeroclaw-infra/src/acp_session_store.rs - Endpoint ACP-over-WebSocket de Gateway:
crates/zeroclaw-gateway/src/acp.rs - Aplicación de rutas por sesión:
crates/zeroclaw-config/src/policy.rs(SecurityPolicy::from_config),crates/zeroclaw-runtime/src/agent/agent.rs(from_config_with_session_cwd_and_mcp) - Detección/backends de sandbox a nivel de SO:
crates/zeroclaw-runtime/src/security/detect.rs,landlock.rs,bubblewrap.rs,seatbelt.rs
Ver también
- Canal → Descripción general
- Tools → MCP: clientes que proporcionan herramientas al agente; ACP es lo inverso
- Seguridad → Autonomía
- Seguridad → Resumen