Files
egutierrez 4c5bf95def feat(0144b): provision-agent-user.sh script idempotente + templates
Bash script que provisiona Matrix user via Synapse admin API + login para
access_token + scaffold completo (config.yaml, agent.go, prompts/system.md).
6 templates (user/sudo x config/agent.go/prompt). 20 tests bash pasan.
Genera .env con AGENT_<ID>_TOKEN/PASSWORD/PICKLE/DEVICE_ID + URL mesh.
2026-05-24 14:07:13 +02:00

10 KiB

dev-scripts/agent

Scripts para crear, registrar, verificar y gestionar agentes individuales en el sistema Matrix.

Scripts

new-agent.sh

Genera el scaffold completo para un nuevo agente: config.yaml, agent.go (reglas puras), directorio de prompts y data. También registra automáticamente el import y la entrada en rulesRegistry de cmd/launcher/main.go.

./dev-scripts/agent/new-agent.sh <agent-id> "Display Name"
./dev-scripts/agent/new-agent.sh monitor-bot "Monitor Agent"

register.sh

Registra un nuevo bot en el servidor Matrix via Synapse admin API. Genera y guarda en .env: access token (MATRIX_TOKEN_*), password (MATRIX_PASSWORD_*) y pickle key (PICKLE_KEY_*).

Requiere MATRIX_ADMIN_TOKEN y MATRIX_HOMESERVER en .env.

./dev-scripts/agent/register.sh <agent-id> "Display Name"
./dev-scripts/agent/register.sh assistant-bot "Assistant"

verify.sh

Verifica o regenera los dispositivos E2EE de los agentes. Genera cross-signing keys, firma el device y guarda el recovery key en .env. Sin este paso, los mensajes del bot aparecen como "not verified by its owner".

./dev-scripts/agent/verify.sh                   # verifica todos los habilitados con E2EE
./dev-scripts/agent/verify.sh assistant-bot     # verifica uno específico

avatar.sh

Sube una imagen como avatar del bot en Matrix y sincroniza el displayname desde el config.yaml.

./dev-scripts/agent/avatar.sh <agent-id> <image-path>
./dev-scripts/agent/avatar.sh assistant-bot static/assistant.jpg

reset-password.sh

Resetea la contraseña de un bot existente via Synapse admin API sin crear nueva sesión ni cambiar el device ID. El access token actual sigue siendo válido.

./dev-scripts/agent/reset-password.sh <agent-id>
./dev-scripts/agent/reset-password.sh assistant-bot

remove.sh

Deshabilita un agente marcándolo como enabled: false en su config.yaml. No borra datos — los preserva en agents/<id>/data/.

./dev-scripts/agent/remove.sh <agent-id>

list.sh

Muestra todos los agentes registrados con su estado (running/stopped/disabled), versión y descripción en una tabla formateada.

./dev-scripts/agent/list.sh

Flujo típico para un nuevo agente

# 1. Crear scaffold
./dev-scripts/agent/new-agent.sh mi-bot "Mi Bot"

# 2. Editar config, reglas y prompt
#    agents/mi-bot/config.yaml
#    agents/mi-bot/agent.go
#    agents/mi-bot/prompts/system.md

# 3. Registrar en Matrix
./dev-scripts/agent/register.sh mi-bot "Mi Bot"

# 4. Verificar E2EE
./dev-scripts/agent/verify.sh mi-bot

# 5. Arrancar
./dev-scripts/server/start.sh

provision-agent-user.sh (issue 0144b)

Provisiona un agent LLM per machine del flow 0009 — Matrix user + scaffold completo (config.yaml + agent.go + prompts/system.md) listo para ser lanzado por cmd/launcher/. Issue 0144 introduce dos agents por PC: agent-<host> (user-scope) y agent-<host>-sudo (sudo-scope con approval gate).

./dev-scripts/agent/provision-agent-user.sh <agent-id> <host> <mode>
# agent-id  ^agent-[a-z0-9-]+$
# host      identificador fisico (home-wsl, aurgi-pc, rpi-garage, ...)
# mode      user | sudo

# Ejemplos:
./dev-scripts/agent/provision-agent-user.sh agent-home-wsl       home-wsl  user
./dev-scripts/agent/provision-agent-user.sh agent-home-wsl-sudo  home-wsl  sudo

Diferencia con new-agent.sh: new-agent.sh copia el _template generico (LLM standard, sin device mesh). provision-agent-user.sh aplica plantillas especificas del flow 0009 con:

  • bloque device_mesh: declarado (manifest_id, tools_allowed, rate_limit)
  • system prompt host-specific (manifest, capability whitelist, sudo policy)
  • agent.go minimal que delega TODA decision al LLM (no rules)
  • secrets persistidos en .env con upsert idempotente y chmod 0600

Que crea

agents/<agent-id>/
  config.yaml           ← rendered from dev-scripts/agent/templates/config.<mode>.yaml.tmpl
  agent.go              ← rendered from dev-scripts/agent/templates/agent.<mode>.go.tmpl
  prompts/system.md     ← rendered from dev-scripts/agent/templates/prompts/system.<mode>.md.tmpl
  data/                 ← mode 0700, gitignored, alberga crypto/ + memory.db

.env (append/upsert):
  MATRIX_TOKEN_<AGENT_ID_UPPER>
  MATRIX_PASSWORD_<AGENT_ID_UPPER>
  PICKLE_KEY_<AGENT_ID_UPPER>
  MATRIX_DEVICE_ID_<AGENT_ID_UPPER>
  <AGENT_ID_UPPER>_DEVICE_MESH_URL

Env vars requeridos en .env

Var Para que Como obtener
MATRIX_HOMESERVER URL completa del homeserver Synapse ej. https://matrix-af2f3d.organic-machine.com
MATRIX_SERVER_NAME server_name (sin https://) ej. matrix-af2f3d.organic-machine.com
MATRIX_ADMIN_TOKEN Bearer token de un user admin Synapse registration_shared_secret + register_new_matrix_user, o login como admin existente y copiar token. Element → Settings → Help & About → Advanced → Access Token
OPERATOR_MATRIX_ID Matrix ID del humano dueno del device ej. @lucas:matrix-af2f3d.organic-machine.com
<AGENT_ID_UPPER>_DEVICE_MESH_URL URL HTTP del device_agent en la mesh opcional; default http://10.42.0.10:7474

Idempotencia

Si agents/<agent-id>/config.yaml ya existe, el script imprime Already provisioned y sale con exit 0 sin tocar nada. Para re-provisionar (Matrix user recreado, plantillas cambiadas, etc.), revoca primero con el flujo de cleanup mas abajo y vuelve a correr.

Idempotencia interna del Synapse PUT

PUT /_synapse/admin/v2/users/<userId> es idempotente por contrato Synapse: 200 si el user ya existe + se actualiza, 201 si es nuevo. Esto evita races cuando dos PCs corren el script casi a la vez.

Templates

Las plantillas viven en dev-scripts/agent/templates/. Editarlas afecta a TODO agente futuro provisionado — los existentes no se tocan (no es regenerador, es scaffolder).

dev-scripts/agent/templates/
  config.user.yaml.tmpl              ← user-scope (DM/mention → LLM con tools user|both)
  config.sudo.yaml.tmpl              ← sudo-scope (approval flow obligatorio)
  agent.user.go.tmpl                 ← rules: LLM-all on DM/mention
  agent.sudo.go.tmpl                 ← rules: LLM-all on DM/mention/delegation
  prompts/system.user.md.tmpl        ← system prompt user
  prompts/system.sudo.md.tmpl        ← system prompt sudo

Variables que el script interpola (sed s#token#value#g):

Token Ejemplo
{{AGENT_ID}} agent-home-wsl
{{AGENT_ID_UPPER}} AGENT_HOME_WSL
{{HOST}} home-wsl
{{MODE}} user o sudo
{{PACKAGE}} agenthomewsl (sin guiones)
{{DISPLAY_NAME}} Agent Home Wsl
{{MATRIX_HOMESERVER}} https://matrix-af2f3d.organic-machine.com
{{MATRIX_SERVER_NAME}} matrix-af2f3d.organic-machine.com
{{MATRIX_DEVICE_ID}} IVECMVQWNZ (devuelto por /v3/login)
{{OPERATOR_MATRIX_ID}} @lucas:matrix-af2f3d.organic-machine.com

Tests

./dev-scripts/agent/provision-agent-user_test.sh

20+ assertions cubriendo:

  • provision exitoso user + sudo
  • idempotencia (re-run sale 0 sin tocar)
  • validacion de agent-id regex y mode enum
  • MATRIX_ADMIN_TOKEN requerido
  • permisos .env = 0600
  • tags correctos en config por mode
  • requires_approval: true solo en sudo

Mockea PUT /_synapse/admin/v2/users y POST /_matrix/client/v3/login con un servidor python local. No toca Matrix real.

Que NO hace este script (delegado a otros)

Tarea Script
Cross-signing E2EE (recovery key) ./dev-scripts/agent/verify.sh <agent-id>
Avatar + displayname final en Matrix ./dev-scripts/agent/avatar.sh <agent-id> <img>
Blank import en cmd/launcher/main.go issue 0144c (wiring multi-agent)
Invitar al operador al room #<host> manual via Element o futura tool del bot dispatcher
Build + start del binario go build -tags goolm ./... && ./dev-scripts/server/start.sh

Como revocar / eliminar un agent provisionado

Checklist de cleanup (revierte todos los efectos del script):

AGENT_ID=agent-home-wsl
AGENT_ID_UPPER=$(echo "$AGENT_ID" | tr '[:lower:]-' '[:upper:]_')

# 1. Stop the launcher si esta corriendo
./dev-scripts/server/stop.sh || true

# 2. Desactivar Matrix user (soft delete)
./dev-scripts/agent/deactivate-matrix.sh "$AGENT_ID"
# o hard:
# curl -X POST "${MATRIX_HOMESERVER}/_synapse/admin/v1/deactivate/@${AGENT_ID}:${MATRIX_SERVER_NAME}" \
#   -H "Authorization: Bearer $MATRIX_ADMIN_TOKEN" -d '{"erase": true}'

# 3. Eliminar env vars
for var in MATRIX_TOKEN_${AGENT_ID_UPPER} MATRIX_PASSWORD_${AGENT_ID_UPPER} \
           PICKLE_KEY_${AGENT_ID_UPPER} MATRIX_DEVICE_ID_${AGENT_ID_UPPER} \
           SSSS_RECOVERY_KEY_${AGENT_ID_UPPER} ${AGENT_ID_UPPER}_DEVICE_MESH_URL; do
  sed -i "/^${var}=/d" .env
done

# 4. Eliminar scaffold
rm -rf "agents/$AGENT_ID/"

# 5. Eliminar blank import del launcher (si se anadio)
./dev-scripts/agent/remove-launcher-import.sh "$AGENT_ID"

# 6. Rebuild
go build -tags goolm ./...

Decisiones de diseno

  • Idempotencia por presencia de config.yaml y no por hash: si re-provisionas, los secrets nuevos en .env se actualizarian via upsert pero las plantillas locales podrian no reflejar cambios. Soft contract: re-provisionar requiere cleanup primero.
  • **Password persistida en .env con MATRIX_PASSWORD_***: necesaria para recovery (reset-password.shreusa el flow). Si el operador prefiere zero-knowledge, puede borrarla manualmente del.envdespues — el agent solo necesita elaccess_token`.
  • No BIP39 recovery_key: el script original §5.1 del 0144 listaba SSSS_RECOVERY_KEY_<...> BIP39. La generacion real de cross-signing keys ocurre en verify.sh (cmd Go con cliente Matrix completo), no aqui. Mantenemos separacion limpia.
  • No invita al room: el dispatcher del bot (0144c) gestiona invites a #<host> cuando el agent arranca. Hacerlo aqui requeriria login + join + check de room existence, fuera del scope de "provisioning de identidad".
  • Templates en dev-scripts/agent/templates/ (no en agents/_template_devicemesh/) para no contaminar el listado de agents reales. El scaffolder es metadata del proceso, no un agente.
  • {{PACKAGE}} sin guiones: Go no acepta - en nombres de paquete. agent-home-wslpackage agenthomewsl.

Output JSON

Al final, el script imprime un JSON con: agent_id, matrix_user, device_id, host, mode, ts. Util para pipelining.