Files
fn_registry/dev/issues/0146-add-pc-oneshot-mesh-scaling.md
T
egutierrez 621e8895c9 feat(infra): auto-commit con 86 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 19:38:15 +02:00

233 lines
12 KiB
Markdown

---
id: "0146"
title: "add-pc one-shot: añade PC al mesh + agente LLM en <2min desde movil"
status: pending
priority: high
created: 2026-05-24
related_flows: ["0009"]
related_issues: ["0134", "0144", "0145"]
dependencies: []
tags: [mesh, wireguard, ssh, scaffolder, agents, llm, scaling, dx]
---
## Objetivo
Reducir de 8 pasos manuales (~15min) a **1 comando (<2min)** el flujo de añadir un PC nuevo al mesh con su propio agente LLM conversacional. Goal final: chatear desde Element movil con cualquier PC del usuario tras un `./fn run add_pc <name>`.
## Estado actual (post-0145)
Pipeline manual funcional pero verboso:
1. Instalar wireguard en PC nuevo.
2. wg_keygen.
3. wg_peer_add en hub (organic-machine.com).
4. wg_client_config + wg_client_install.
5. Build/scp device_agent binario.
6. Manifest YAML local.
7. systemd unit.
8. provision-agent-user.sh + edit launcher main.go + rebuild + restart agents_and_robots.
Solo agent-wsl-lucas existe. Bloqueado por friccion de pasos para escalar a aurgi-pc, windows-lucas, raspberry, etc.
## Vision
```
operador$ ./fn run add_pc aurgi-pc --via wg
[1/9] generating WG keypair...
[2/9] enrolling peer at hub (10.42.0.21)...
[3/9] cross-compiling device_agent for linux/amd64...
[4/9] uploading binary + manifest + systemd unit via SSH...
[5/9] starting WG + device_agent on remote...
[6/9] provisioning Matrix user @agent-aurgi-pc...
[7/9] generating agent config + system prompt...
[8/9] wiring launcher + rebuild...
[9/9] restarting agents_and_robots.service...
✓ agent-aurgi-pc live. Send a DM from your Matrix client.
```
Y para hosts sin posibilidad de instalar binary:
```
operador$ ./fn run add_pc customer-vps-01 --via ssh --ssh-alias customer-prod
✓ agent-customer-vps-01 live (ssh-backed). Send a DM.
```
## Arquitectura
Dos backends para un mismo UX:
### Backend A — WG + device_agent (mesh nativo)
- PC tiene WG client + binary device_agent corriendo.
- Comandos viajan VPS → WG → device_agent → exec local → audit chain LOCAL.
- 14 capabilities completas (fs.*, git.*, docker.*, pkg.*, proc.*, shell.exec, shell.eval).
- Para tus PCs (laptop, desktop, raspberry, mac, movil rooted).
### Backend B — SSH-only (sin binary remoto)
- PC tiene solo SSH server. VPS tiene SSH key autorizada.
- Comandos viajan VPS → ssh.Executor → exec remoto → audit en VPS.
- Tools reducidos: `ssh_exec(argv)`, `ssh_fs_read`, `ssh_fs_list`. Sin docker/git/pkg salvo wrapper.
- Para customer servers, VPS terceros, throwaway boxes.
LLM agent ve diferentes tool sets segun backend. Mismo system prompt template.
## Tareas
### Fase 1 — Pipeline `add_pc_wg_bash_pipelines`
1.1. Cross-compile device_agent matrices:
- `GOOS=linux GOARCH=amd64` (default)
- `GOOS=linux GOARCH=arm64` (raspberry pi4+, mac M-series via Linux)
- `GOOS=windows GOARCH=amd64`
- `GOOS=darwin GOARCH=arm64`
- Reusa `nohup` cgo-free build (swap mattn/go-sqlite3 → modernc.org/sqlite si no esta hecho ya).
- Output: `cpp/build/cross/device_agent.<os>-<arch>`.
1.2. Funcion `cross_compile_device_agent_bash_infra(target_os, target_arch)` que devuelve path al binario.
1.3. Funcion `add_pc_wg_bash_pipelines(name, ssh_alias, target_os?, target_arch?)`. Compone:
- wg_keygen_go_infra (hub side: priv hub + psk; client side: priv cliente)
- wg_peer_add_go_infra (en hub via SSH al VPS)
- wg_client_config_go_infra (genera client.conf)
- ensure_remote_wireguard_installed (SSH al target, apt/dnf install wireguard si falta)
- wg_client_install_bash_infra (en target via SSH push)
- cross_compile_device_agent_bash_infra (local)
- rsync_device_agent_bundle (binary + manifest template + systemd unit → target ~/.local/bin/ + ~/.config/device_agent/)
- start_device_agent_service (systemctl --user enable --now device_agent)
- provision_agent_user (ssh al VPS, ejecuta dev-scripts/agent/provision-agent-user.sh con --mode user)
- wire_launcher_import (edita cmd/launcher/main.go en VPS, anade blank import, git commit + rebuild + restart service)
- assert_dm_received (espera 30s a que el bot mande "hola" via notify-developer.sh)
1.4. Manifest template Y matrix per-OS: paths_allowed difieren (`/home/<user>/**` en Linux, `C:\Users\<user>\**` en Windows). Templates en `dev-scripts/agent/templates/manifest.<os>.yaml.tmpl`.
1.5. Idempotente: re-run con mismo name → no-op + verificar state. Si peer existe pero device_agent caido, restart.
1.6. Rollback: si paso N falla, deshacer 1..N-1. Estado parcial NO debe quedar (peer huerfano, Matrix user sin agent, etc).
### Fase 2 — Pipeline `add_pc_ssh_bash_pipelines` (backend B)
2.1. Funcion `ssh_exec_capability_go_infra` — wrapper que recibe `{argv, host}` y hace `ssh <host> -- <argv...>`. Whitelist binaries opcional. Audit en VPS (`apps/agents_and_robots/ssh_audit.db` o similar).
2.2. Funcion `ssh_fs_read_capability_go_infra`, `ssh_fs_list_capability_go_infra` (read-only, no write para evitar accidentes en customer boxes).
2.3. Tool registry adapter: cuando agent config tiene `device_mesh.backend: ssh`, el adapter no apunta a HTTP device_agent — apunta a las funciones `ssh_*` directamente. Mantener interface ToolRegistry pero swap implementation.
2.4. `add_pc_ssh_bash_pipelines(name, ssh_alias)` compone:
- assert_ssh_reachable (BatchMode yes connect test)
- provision_agent_user --mode user --backend ssh
- generate agent config con `device_mesh.backend: ssh, ssh_alias: <alias>`
- wire launcher + restart
NO toca el remote — solo VPS.
### Fase 3 — Cross-compile device_agent CGO-free
3.1. Swap mattn/go-sqlite3 (CGO) → modernc.org/sqlite (pure Go) en device_agent. Tests verde tras swap.
3.2. `cross_compile_device_agent_bash_infra` produce 4 binarios en <30s.
3.3. Bundle script `make-bundle.sh <os> <arch>` empaqueta zip con binario + manifest.template + systemd-unit/launchd-plist/Task-Scheduler.xml segun OS.
### Fase 4 — agents_dashboard "Add device" panel C++
4.1. Modal nuevo en panel "Devices" con:
- Input: nombre del PC.
- Dropdown backend: WG mesh / SSH-only.
- Si WG: SSH alias para upload + OS/arch detect via uname remote.
- Si SSH: solo alias.
- Boton "Add". Spawn pipeline en background. Stream logs en TextLog.
4.2. Grid de status: device_id, IP mesh, last handshake, capabilities count, last command ts, audit chain integrity.
4.3. Boton "Revoke" por device → llama wg_peer_revoke + deactivate Matrix user + remove launcher import + restart. Confirmacion doble.
### Fase 5 — Health monitor cron + alertas
5.1. Cron 5min `monitor_mesh_health_bash_pipelines`:
- wg_status → cada peer con last_handshake > 600s → mark stale.
- HTTP GET /health a cada device_agent IP del mesh → si falla → mark unreachable.
- verify_hash_chain por device → si rota → mark corrupted.
5.2. Alertas Matrix a `#operator-alerts` (room a crear) con mensaje formato:
```
[ALERT] device_id=aurgi-pc status=stale (handshake 8min ago)
[ALERT] device_id=home-wsl status=hash_chain_corrupted (id=47 broken)
```
5.3. Dashboard tab "Health" muestra el feed SSE.
### Fase 6 — Movil UX validation
6.1. Test en Element movil iOS/Android:
- Lista de rooms con 1 per device.
- Notifications activas → push cuando agent responde.
- Smoke tests de capabilities mas comunes via voice-to-text.
6.2. Documentar `docs/mobile-control.md` con flujo recomendado:
- Como agrupar rooms por device en Element favorites.
- Comandos comunes ("status", "deploy X", "que esta caido").
- Tiempos esperados (claude-code latency 3-5s + tool exec 0.1-2s).
## Aceptacion (DoD triada)
### Mecanica
- `./fn run add_pc <name> --via wg` exit 0 + agent live en <2min en wallclock.
- `./fn run add_pc <name> --via ssh` exit 0 + agent live en <30s.
- Tests unit + integration verde en `bash/functions/pipelines/add_pc_*`.
### Cobertura
- Smoke matrix: 4 target OS (linux/amd64, linux/arm64, windows/amd64, darwin/arm64) cada uno con add_pc_wg flujo end-to-end.
- Rollback: simular falla en paso 5 (binary upload corrupted) → assert estado limpio (no peer huerfano, no Matrix user, no entry en launcher).
- SSH backend: target solo con SSH + sin sudo → agent funciona con tools ssh_exec read-only.
- Anti-criterio A3 (heredado de 0009): tras add_pc, smoke real via Matrix → audit DB en device tiene entries reales (no bot hallucination).
### Vida util
- 5 PCs reales añadidos durante 7 dias.
- 0 revokes manuales por error de provision.
- Operador usa Element movil >=1 sesion/dia interactuando con >=2 devices distintos.
- Health monitor detecta peer caido en <10min (test con `wg-quick down` aleatorio).
### Anti-criterios
- Si add_pc deja estado parcial (peer en wg0 + no agent en launcher) → invalida.
- Si SSH backend ejecuta comandos sin audit en VPS → invalida (no fake "ssh OK" sin log).
- Si dashboard muestra device "online" pero ultimo handshake >24h → invalida (false positive grave).
## Sub-issues planificados
| ID | Titulo | Esfuerzo |
|---|---|---|
| 0146a | cross_compile_device_agent + CGO-free swap a modernc.org/sqlite | 2h ✅ |
| 0146b | add_pc_wg_bash_pipelines (Fase 1) | 4h |
| 0146c | add_pc_ssh_bash_pipelines + ssh_exec_capability (Fase 2) | 3h |
| 0146d | Bundle script multi-OS + manifest templates (Fase 3) | 2h |
| 0146e | agents_dashboard panel "Add device" + status grid (Fase 4) | 4h |
| 0146f | monitor_mesh_health pipeline + alertas Matrix (Fase 5) | 1.5h |
| 0146g | Movil UX doc + smoke real con 4 devices fisicos (Fase 6) | 1h+observacion 7d |
Total: ~17h dev + 7d observacion.
## Decisiones de diseño
1. **Pipeline en bash compose funciones del registry**, no codigo Go monolitico. Permite que cada paso sea trazable + reusable individualmente.
2. **modernc.org/sqlite** vs mattn/go-sqlite3: pure Go elimina CGO + cross-compile trivial. Performance es comparable (modernc benchmarks dentro del 10% para nuestro workload de audit append).
3. **Backend SSH NO replica el manifest enforcement remoto** — el manifest vive en VPS y filtra antes de SSH. Trade-off aceptable: SSH backend = "trust the VPS sudo enforcement". Para PCs propios usa WG backend.
4. **Cada device = un agent Matrix separado** (NO un agent multi-device). Razon: aislamiento blast radius + room por device = UX claro en Element + capability manifest distinto por device. Coste: mas Matrix users + mas claude-code subprocesses.
5. **NO usar Ansible/Terraform** para este flujo. Pipeline bash + funciones del registry es suficiente y evita la dep externa. Si crece a >50 PCs, reconsiderar.
## Riesgos
- **Cross-compile + CGO-free**: el swap a modernc puede romper audit en runtime si schemas no migran. Mitigar con test golden DB + WAL mode check.
- **Windows systemd equivalente**: Task Scheduler es feo. Considera nssm.exe para autostart fiable. Documentar bien en bundle.
- **SSH key trust amplification**: backend B requiere SSH agent del VPS confiable a TODOS los target hosts. Si VPS comprometido → todos los SSH targets caen. Reforzar con SSH key per-host + revocacion centralizada.
- **Mac iCloud signing**: device_agent.app necesitaria notarization para auto-launch en macOS reciente. Skip para POC, abordar si añadimos Mac al mesh real.
- **Movil notifications**: Element push depends on FCM (Android) / APNs (iOS). Sin push, el operador puede perderse approvals time-sensitive. Doc sobre alternativas (NTFY, Gotify).
## Notas
- **2026-05-24 — 0146a done**: swap mattn/go-sqlite3 → modernc.org/sqlite v1.50.1 (pure Go). 4 binarios cross-compile OK (linux-amd64 11MB, linux-arm64 10MB, windows-amd64 11MB, darwin-arm64 10MB), todos stripped + statically linked. Build script idempotente en `apps/device_agent/build_all.sh`. Self-test pass en linux-amd64 nativo. Quedan smoke tests reales en windows/darwin/arm cuando 0146b despliegue a peers fisicos.
- `./fn run add_pc` deberia llamar via mcp__registry__fn_run para que telemetria de issue 0085 quede registrada.
- Aprovechar 0144b provision-agent-user.sh que ya esta hecho — solo compone, no reescribe.
- Sub-issue 0146g (UX movil) cierra el flow 0009 completo al fin: "humano controla N maquinas desde movil".
- Si esto funciona, abrir issue 0147 para "voice control" — Element soporta voice messages; usar transcripcion (Whisper local en VPS) → inyectar como texto al agent.