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.
This commit is contained in:
@@ -87,3 +87,166 @@ Muestra todos los agentes registrados con su estado (running/stopped/disabled),
|
||||
# 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).
|
||||
|
||||
```bash
|
||||
./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
|
||||
|
||||
```bash
|
||||
./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):
|
||||
|
||||
```bash
|
||||
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.sh` reusa el flow). Si el operador prefiere zero-knowledge, puede borrarla manualmente del `.env` despues — el agent solo necesita el `access_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-wsl` → `package agenthomewsl`.
|
||||
|
||||
### Output JSON
|
||||
|
||||
Al final, el script imprime un JSON con: `agent_id`, `matrix_user`, `device_id`, `host`, `mode`, `ts`. Util para pipelining.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user