agent-chat
Resumen
Las sesiones de agentes pares se coordinan intercambiando archivos Markdown en carpetas de canal compartidas — sin supervisor, sin intermediario de mensajes, sin RAM compartida entre ellas. Cada canal es un "chat grupal". Todo el hilo es Markdown plano: commiteable en Git, legible por humanos, reproducible. Una sesión que falla no pierde nada — los archivos son el estado.
La CLI basada únicamente en la stdlib (chat.py más el paquete agent_chat/) funciona en Windows, WSL y Linux. wait duerme entre comprobaciones del sistema de archivos y no realiza llamadas a modelos.
Principio fundamental: hablar a través de archivos, no a través del otro. Resúmenes como artefactos, no transcripciones completas enviadas de un lado a otro.
Esta es una capa de datos de coordinación local, no un servidor MCP ni un ejecutor de agentes. Los mensajes, tareas, leases, bloqueos de rutas, eventos de capacidad/estado y estado derivado no realizan llamadas de completado, embedding, rerank, servicio de grafos ni de relay/proveedor.
Cuándo usarlo
- Varias sesiones de agentes compatibles con OMP (u otros) que trabajan en el mismo problema como iguales.
- Una sesión necesita que otra haga algo y luego espera el resultado.
- Deseas un registro auditable de una negociación entre agentes.
- Necesitas varios chats grupales independientes (uno por tema/equipo) — crea un canal para cada uno.
Cuándo NO usarlo: un solo agente con subagentes baratos es más económico y simple — este patrón intercambia tokens por paralelismo, tolerancia a fallos y auditabilidad. Si el presupuesto de tokens es ajustado, usa solo la ruta asíncrona/traspaso (publica un resumen al final de la sesión; la siguiente sesión lo lee) — ese modo cuesta casi nada.
Referencia rápida
Usa agent-chat <cmd> después de pipx install agent-chat-plugin, o
uvx --from agent-chat-plugin agent-chat <cmd> para cada invocación única.
uvx no instala un comando persistente. Con una habilidad independiente, mantén
SKILL.md, chat.py y todo el directorio agent_chat/ juntos y ejecuta
python "/ruta/a/la/habilidad/chat.py" <cmd>. Los ejemplos abreviarán esto como chat.py.
El plugin de Claude Code usa python "${CLAUDE_PLUGIN_ROOT}/chat.py" <cmd>.
Otros hosts usan una ruta de checkout real, no una variable de plugin asumida.
La precedencia de raíz es --root > $AGENT_CHAT_ROOT > ~/agent-chat; pon --root
antes del subcomando. Las raíces predeterminadas de máquinas separadas no están sincronizadas.
La instalación desde PyPI solo incluye los módulos CLI/runtime. Los hooks/*.py opcionales vienen del
checkout/plugin y necesitan cableado explícito del ciclo de vida del host. Sus puntos de entrada
Python son portables; su registro y contrato de salida no es automáticamente una integración OMP.
Los avisos de sesión/prompt son texto; Stop emite systemMessage JSON compatible con Claude.
Los hooks miran sin avanzar cursores y siempre salen con 0;
CLAUDE_PLUGIN_ROOT no resuelto o raíces de plugin relativas al script se omiten con un
diagnóstico de una línea en stderr.
| Haz esto | Comando |
|---|---|
| Crear un chat grupal | chat.py init review --members alice,bob --topic "..." |
| Listar todos los chats grupales | chat.py channels |
| Publicar un mensaje | chat.py post review --from alice --to bob --title "Esquema v0.2" --body-file msg.md |
| Transmitir al grupo | chat.py post review --from alice --to all --title "..." (u omite --to) |
| Leer lo nuevo para mí | chat.py read review --as bob |
| Esperar una respuesta (0 tokens) | chat.py wait review --as alice --timeout 900 |
| Vislumbrar reciente, mantener cursor | chat.py peek review -n 3 |
| Reclamar un marcador de tarea | chat.py claim work task-12.md --as bob |
| Bloquear rutas del espacio de trabajo | chat.py lock review src/main.py --as alice --lease-seconds 300 |
| Verificar conflictos de rutas | chat.py check review src/main.py |
| Liberar bloqueo de ruta | chat.py unlock review <lock-id-o-ruta> --as alice |
| Recuperar bloqueo obsoleto | chat.py recover review <lock-id-o-ruta> --as bob --reason "obsoleto" |
| Recuperar transacción de ruta pendiente | chat.py recover-pending review --as alice |
| Renderizar estado del canal | chat.py state review |
| Compactar estado del canal | chat.py compact review --as alice |
| Publicar evento de capacidad/estado | chat.py event post review --from alice --type capability --harness omp |
| Leer eventos del adaptador | chat.py event read review --type capability |
Los eventos neutrales al adaptador usan la versión de esquema 1 y se transportan como cuerpos JSON en
mensajes de canal ordinarios. Los eventos de capacidad anuncian solo las primitivas portables
messages, cursors, wait, tasks, dependencies, leases,
path_locks y state_summary. Los eventos de estado usan ready, busy, idle,
blocked o stopped, con detalle opcional. Los campos, primitivas, versiones, marcas de tiempo, identidades y estados desconocidos fallan con errores EVENT_* estables.
Este protocolo no reclama MCP, ACP, puente de activación ni ejecución de agentes.
Las tareas estructuradas usan la misma raíz de canal y escriben registros JSON autoritativos bajo
<raíz>/<canal>/tasks/; los registros de lease activos viven bajo
<raíz>/<canal>/claims/<id-tarea>.<propietario>.json. Cada mutación exitosa de tarea o lease
también publica un evento de auditoría a través del protocolo de mensajes existente:
chat.py task create <canal> <id-tarea> --from <agente> --title <título>
chat.py task list <canal>
chat.py task show <canal> <id-tarea>
chat.py task update <canal> <id-tarea> --as <agente> [campos...]
chat.py task claim <canal> <id-tarea> --as <agente> --lease-seconds 300
chat.py task renew <canal> <id-tarea> --as <agente> --lease-seconds 300
chat.py task done <canal> <id-tarea> --as <agente>
chat.py task block <canal> <id-tarea> --as <agente>
chat.py task release <canal> <id-tarea> --as <agente>
chat.py task recover <canal> <id-tarea> --as <agente> \
--reason "sesión obsoleta" --lease-seconds 300
chat.py task recover-pending <canal> --as <agente> \
[--resolve-publication rollback|published]
claim, renew y recover obsoleto aceptan --lease-seconds, --lease, o
--ttl; el valor debe ser una duración finita positiva. claim avanza una tarea
lista a in_progress, asigna el propietario y escribe su vencimiento atómicamente con el
registro de claim. Solo el propietario puede renovar, liberar o completar un claim
no vencido. task done limpia un claim activo atómicamente; cuando no existe ningún claim, preserva
la transición directa de Tarea 3. task release preserva de manera similar la transición de Tarea 3 no adquirida. Un claim vencido nunca se roba en silencio:
task recover obsoleto requiere un nuevo propietario y una razón no vacía y registra
previous_owner, previous_lease_expires_at y recovery_reason.
Después de un fallo, task recover-pending <canal> --as <agente> finaliza explícitamente
la limpieza/reversión del marcador de transacción duradera; nunca roba ni reasigna
en silencio una tarea obsoleta. Los marcadores applied heredados v1 cuya publicación de auditoría no se puede probar fallan cerrados con LEASE_TRANSACTION_PUBLICATION_UNKNOWN;
vuelve a ejecutar el comando con --resolve-publication rollback o published después de la
inspección del operador.
create acepta --owner, --depends-on, --files-hint, --acceptance y
--branch. Repite las opciones de lista para añadir múltiples valores. update acepta
--title, --owner, --depends-on, --files-hint, --acceptance,
--branch y --status; usa --clear-owner o --clear-branch para establecer
campos anulables de vuelta a null. Las actualizaciones genéricas no pueden mutar un lease
activo; usa los comandos de lease en su lugar. Los valores de lista también pueden estar separados por comas.
Los estados de tarea son open, in_progress, blocked, done y cancelled.
done y cancelled son terminales. Las transiciones permiten open -> in_progress |
blocked | cancelled, in_progress -> open | blocked | done |
cancelled, y blocked -> open | in_progress | cancelled. Las escrituras del mismo
estado son intencionadamente idempotentes. task done mueve in_progress (o
done idempotente) a done; task block mueve open, in_progress o
blocked a blocked; y task release mueve blocked, in_progress o
open a open. Una tarea puede avanzar a in_progress o done solo cuando
cada ID en depends_on tiene un registro de tarea cuyo estado es done. La preparación se
calcula a partir de los registros JSON de tareas, nunca del texto del mensaje.
Los fallos de tarea y lease son distintos de cero (código de salida 2) e incluyen un código estable.
Los códigos de tarea incluyen TASK_INVALID_COMMAND, TASK_INVALID_ARGUMENT,
TASK_INVALID_CHANNEL, TASK_CHANNEL_NOT_FOUND, TASK_NOT_FOUND,
TASK_ALREADY_EXISTS, TASK_INVALID_STATUS, TASK_INVALID_UPDATE,
TASK_INVALID_TRANSITION, TASK_DEPENDENCY_NOT_READY,
TASK_UNKNOWN_DEPENDENCY, TASK_DEPENDENCY_CYCLE,
TASK_PATH_OUTSIDE_WORKSPACE, TASK_LOCK_TIMEOUT, TASK_IO_ERROR y
TASK_AUDIT_FAILED. Los códigos de lease incluyen LEASE_CONFLICT,
LEASE_RECOVERY_REQUIRED, LEASE_OWNER_MISMATCH, LEASE_NOT_EXPIRED,
LEASE_NOT_FOUND, LEASE_INCONSISTENT, LEASE_MUTATION_REQUIRED,
LEASE_INVALID_OWNER, LEASE_INVALID_TASK_ID, LEASE_INVALID_CHANNEL,
LEASE_INVALID_REASON, LEASE_INVALID_DURATION, LEASE_INVALID_TIMESTAMP,
LEASE_INVALID_RECORD, LEASE_REQUIRED_FIELD_MISSING, LEASE_UNKNOWN_FIELD,
LEASE_RECORD_ID_MISMATCH, LEASE_STORAGE_INVALID,
LEASE_PATH_OUTSIDE_WORKSPACE, LEASE_TRANSACTION_PENDING,
LEASE_TRANSACTION_CLEANUP_FAILED, LEASE_TRANSACTION_PUBLICATION_UNKNOWN,
LEASE_TRANSACTION_INVALID, LEASE_TRANSACTION_NOT_FOUND,
LEASE_TRANSACTION_RECOVERY_FAILED,
LEASE_AUDIT_FAILED y LEASE_AUDIT_ROLLBACK_FAILED. Las escrituras de lease usan un
marcador de transacción duradera con fases preparada/aplicada/publicada; después de un
fallo o error de limpieza, el acceso falla cerrado hasta que
task recover-pending/LeaseStore.recover_pending() explícitamente revierte
o finaliza la transacción publicada.
Los bloqueos de ruta coordinan el acceso exclusivo a archivos y directorios relativos al espacio de trabajo:
chat.py lock <canal> <rutas...> --as <agente> [--lease-seconds 300]
chat.py check <canal> <rutas...> [--as <agente>]
chat.py unlock <canal> <id-bloqueo-o-ruta> --as <agente>
chat.py recover <canal> <id-bloqueo-o-ruta> --as <agente> \
--reason "sesión obsoleta" [--lease-seconds 300]
chat.py recover-pending <canal> --as <agente> \
[--resolve-publication rollback|published]
lock y recover aceptan --lease-seconds, --lease o --ttl. El objetivo puede
ser el ID de bloqueo o la ruta exacta normalizada. La normalización resuelve las rutas relativas al espacio de trabajo,
previene la salida de raíz/canal/symlink, aplica reglas de mayúsculas/minúsculas de la plataforma
(sin distinción en Windows) y rechaza nombres reservados de Windows, puntos/espacios finales, caracteres de control y suplentes solitarios.
Los conflictos de archivo/archivo y las superposiciones de directorio/archivo provocan conflictos.
Solo el propietario puede desbloquear un bloqueo activo; los bloqueos vencidos requieren un recover explícito que registre
previous_owner, previous_expires_at y recovery_reason. Las mutaciones usan
publicación de archivos atómica de contenido, bloqueos de archivos de asesoramiento y diario de transacciones a prueba de fallos.
Los errores de bloqueo de ruta salen con código distinto de cero y códigos estables como
PATH_LOCK_INVALID_PATH, PATH_LOCK_PATH_OUTSIDE_WORKSPACE,
PATH_LOCK_CONFLICT, PATH_LOCK_RECOVERY_REQUIRED,
PATH_LOCK_OWNER_MISMATCH, PATH_LOCK_NOT_FOUND, PATH_LOCK_NOT_STALE,
PATH_LOCK_INVALID_OWNER, PATH_LOCK_INVALID_LOCK_ID,
PATH_LOCK_INVALID_CHANNEL, PATH_LOCK_INVALID_REASON,
PATH_LOCK_INVALID_DURATION, PATH_LOCK_INVALID_TIMESTAMP,
PATH_LOCK_INVALID_RECORD, PATH_LOCK_STORAGE_INVALID,
PATH_LOCK_STORAGE_ERROR, PATH_LOCK_TIMEOUT,
PATH_LOCK_TRANSACTION_PENDING, PATH_LOCK_TRANSACTION_CLEANUP_FAILED,
PATH_LOCK_TRANSACTION_INVALID, PATH_LOCK_AUDIT_FAILED y
PATH_LOCK_AUDIT_ROLLBACK_FAILED.
El resumen del estado del canal y la compactación derivan un artefacto state.md determinista:
chat.py state <canal> [--write] [--json] [--strict]
chat.py compact <canal> [--as <agente>] [--no-audit] [--json] [--strict]
state renderiza o imprime el resumen del canal derivado que contiene:
- Objetivo / Tema (de
_meta.json) - Decisiones (extraídas de mensajes y registros estructurados)
- Tareas abiertas (de
tasks/*.json, incluyendo estado, propietario, lease, dependencias) - Bloqueadores (bloqueadores de dependencias de tareas, estados de tarea bloqueados y mensajes bloqueadores)
- Propietarios y Leases (claims activos, propiedades de tareas y bloqueos de ruta)
- Bloqueos de Ruta (bloqueos de ruta activos de
locks/*.json) - Última Evidencia de Verificación (criterios de aceptación y mensajes de verificación)
compact escribe el resumen derivado en <raíz>/<canal>/state.md usando un reemplazo
atómico de archivo temporal hermano (.state.md.tmp.*) y, por defecto, publica un evento de mensaje
state.compacted auditable en el canal.
state.md es estrictamente un artefacto derivado y nunca es autoritativo.
La compactación no es destructiva: nunca elimina, muta o trunca ningún archivo de mensaje,
registro de tarea, claim activo, bloqueo de ruta o cursor de lectura. Todos los registros fuente permanecen como la
verdad fundamental inmutable.
Los errores de estado salen con código distinto de cero y códigos estables como STATE_INVALID_CHANNEL,
STATE_CHANNEL_NOT_FOUND, STATE_INVALID_RECORD, STATE_MALFORMED_SOURCE,
STATE_RECORD_NOT_FOUND, STATE_IO_ERROR y STATE_AUDIT_FAILED.
--reply <seq> enhebra un mensaje a uno anterior. python chat.py <cmd> --help para todas las banderas.
Comandos de eventos neutrales al adaptador:
chat.py event post <canal> --from <agente> --type capability --harness <harness>
chat.py event post <canal> --from <agente> --type status --harness <harness> --status ready
chat.py event read <canal> [--type capability|status]
El cuerpo del evento es JSON versionado validado contra
schemas/agent-chat-event.schema.json. Los mensajes Markdown ordinarios permanecen
sin cambios y son ignorados por event read.
Estructura de carpetas
<raíz>/
review/ # un canal = un chat grupal
_meta.json # miembros, tema, creado
state.md # resumen de estado derivado (no autoritativo)
0001-alice-schema-draft.md # NNNN-<de>-<slug>.md, frontmatter + cuerpo
0002-bob-schema-review.md
tasks/ # registros de tareas estructuradas
claims/ # registros de lease activos
locks/ # bloqueos de ruta del espacio de trabajo activos
.cursors/bob.txt # "último seq leído" por agente
deploy/ # un SEGUNDO chat grupal, espacio de secuencia separado
...