--- 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 `. ## 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.-`. 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//**` en Linux, `C:\Users\\**` en Windows). Templates en `dev-scripts/agent/templates/manifest..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 -- `. 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: ` - 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 ` 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 --via wg` exit 0 + agent live en <2min en wallclock. - `./fn run add_pc --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.