El launcher salia con status=0 cuando todos los runners (Agent/Robot)
terminaban su Run() de forma natural — por ejemplo tras una rotacion de
token de Matrix o un drop del sync. systemd, configurado con
Restart=on-failure, no relanzaba el proceso al ver salida limpia y los
bots quedaban caidos hasta una intervencion manual.
Solucion: nueva rutina superviseUntilCanceled en agentRegistry que
bloquea sobre waitAll, y si el ctx padre sigue vivo, espera un backoff
y llama reloadAll para recrear los runners. Solo cuando el ctx padre
se cancela (SIGINT/SIGTERM) la rutina retorna y el launcher sale.
main.go pasa a invocar este supervisor en lugar de waitAll directo.
Tests:
- TestSuperviseUntilCanceled_ReturnsWhenCtxCanceledFirst — empty registry
- TestSuperviseUntilCanceled_ReturnsAfterCtxCancelDuringBackoff — cancel
durante el backoff debe desbloquear inmediatamente
- TestSuperviseUntilCanceled_CallsReloadOnAgentExit — supervisor sigue
vivo todo el deadline aunque reload falle por cfgPath invalido
Diagnostico: tras varias horas el journalctl mostraba "Deactivated
successfully" sin "Stopping" previo (Apr 13 18:22 tras 23h corriendo)
y el log del agent registraba "context canceled" tras "starting matrix
sync" — sintoma de que mautrix.SyncWithContext salio limpiamente y el
ctx.cancel se propago al cerrar la goroutine sin que systemd hubiera
enviado SIGTERM. El bucle supervisado lo arregla recreando los runners
sin tocar la unit ni depender del Restart de systemd.
Introduce la separacion Robot vs Agent en el sistema:
- agents/types.go: interfaz Runner comun (Run, Stop, Done, RegisterCommand)
que tanto Agent como Robot satisfacen
- agents/robot.go: struct Robot — runtime minimo que solo conecta a Matrix
y despacha comandos. Sin LLM, reglas, memoria, knowledge, skills ni tools.
Mensajes normales se ignoran silenciosamente
- internal/config/schema.go: campo Type en AgentMeta ("agent"|"robot")
- cmd/launcher: usa Runner interface para manejar ambos tipos uniformemente.
Si cfg.Agent.Type == "robot" crea NewRobot en vez de New (tanto en
arranque como en hot-reload)
- agents/_template_robot/config.yaml: plantilla minima (~55 lineas) para
robots command-only
El Robot soporta built-in commands reducidos (help, ping, status, info,
version) y comandos custom via RegisterCommand. No incluye tools, tool,
clear ni prompts ya que no tiene LLM ni memoria.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Migrar admin a security/user-groups.yaml (admins group)
- agents.New() ahora acepta acl.ACL pre-resuelta como parámetro;
elimina construcción interna desde cfg.Security.Roles
- cmd/launcher: carga shellsecurity.Load("security/") al arranque;
si falla, WARN + política vacía (open access). Para cada agente
llama pksecurity.ResolveACL y pasa la ACL a agents.New()
- cmd/launcher/registry.go: stores secPolicy en launchDeps para
que reload() también resuelva ACL centralmente
- shell/matrix/listener.go: elimina invite gating y allowlist check
basados en AllowedUsers; el control de acceso lo hace el runtime
- internal/config/schema.go: depreca campos Roles y AllowedUsers
(backward compat, no eliminados)
- agents/*/config.yaml: elimina bloques security.roles y allowed_users
- dev/feature_flags.json: activa centralized-security-groups (enabled: true)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implementa el mecanismo de hot-reload descrito en el issue 0013:
- agents/runtime.go: añade Agent.Stop() y Agent.Done() para ciclo de vida
individual. Run() crea un contexto hijo cancelable y cierra el canal
done al retornar.
- cmd/launcher/registry.go (nuevo): agentRegistry rastrea agentes vivos
por ID. Métodos: register, stopAndWait, reload, reloadAll, waitAll,
cleanupLogs. reload() sigue el flujo completo: stop→wait→unsubscribe
→reload config→recreate→rewire bus/orch→start nueva goroutine.
- cmd/launcher/main.go: usa agentRegistry en lugar de sync.WaitGroup.
Añade handler de SIGHUP en goroutine separada que lee run/reload.txt
para determinar el agente objetivo (* o vacío = todos). Tras leer,
borra run/reload.txt para no afectar el siguiente SIGHUP.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>