--- name: unifi description: Diagnostica y consulta la red UniFi del beneficio Rio Frio (UDM Pro en 192.168.87.5) en lenguaje natural. Úsala cuando el usuario pregunte sobre dispositivos conectados, APs, switches, clientes WiFi, estado de la red local, si tal báscula/impresora/ESP32 está online, ancho de banda, MACs, IPs del LAN 192.168.87.0/24, o cualquier diagnóstico del UDM Pro. Ejemplos: "qué hay conectado al WiFi", "está online la impresora del patio", "qué AP tiene más clientes", "muéstrame los dispositivos del laboratorio", "qué IP tiene la báscula tolva_bodega", "cuántos APs tengo y están todos arriba", "quién está chupándose el internet", "qué pasó con la conexión hace un rato". allowed-tools: Bash, Read, Grep --- # UniFi UDM Pro — skill de diagnóstico local ## Qué es esto Skill 100% local que consulta el **UDM Pro** del beneficio Rio Frio (`192.168.87.5`) usando la **Integration API oficial** de UniFi Network (≥ v9.3.43, X-API-KEY stateless). No hay servidor intermedio, no hay MCP server, no hay nada en el Swarm. Solo `curl` desde tu PC contra el UDM Pro vía la LAN o a través del DNS interno. - **Base URL**: `https://192.168.87.5/proxy/network/integration/v1` - **Auth**: header `X-API-KEY: $UNIFI_API_KEY` - **El API key vive en**: `~/.claude/skills/unifi/.env` (local, no versionado) - **Scope**: read-only (Integration API write está en preview, no lo tocamos) ## Cómo invocarla correctamente Antes de cualquier query: 1. Verifica que `~/.claude/skills/unifi/.env` exista. Si no, avísale al usuario y dale el comando para crearlo (ver "Setup inicial" más abajo). 2. Verifica conectividad básica con un `GET /sites`. Si falla con 401/403 → API key inválida o caducada. Si falla con conexión rechazada/timeout → no estás en la LAN del beneficio (recordá que `192.168.87.5` no es ruteable desde fuera). ## Dos APIs, dos scripts | Script | API | Auth | Cuándo usar | |---|---|---|---| | `query.sh` | Integration API v1 | `X-API-KEY` (stateless) | devices, clients (sin bytes/signal), networks, vouchers, statistics/latest | | `query-classic.sh` | Classic API | session cookie + CSRF (login flow, cache 25 min) | health, eventos, alarmas, **bytes por cliente**, **SSID/signal**, configs (WLANs, firewall, port forwards) | ### query.sh (Integration API) ```bash ~/.claude/skills/unifi/scripts/query.sh /sites ~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/devices" ~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/clients" ``` > El placeholder `{site}` se expande automáticamente al UUID del site (`$UNIFI_SITE` > en `.env`). La Integration API exige UUID, NO el nombre `default`. **Siempre comillas > dobles** alrededor del path para que la shell no interprete las llaves. ### query-classic.sh (Classic API — para todo lo que la Integration no expone) ```bash ~/.claude/skills/unifi/scripts/query-classic.sh /stat/health # WAN/WLAN/LAN/UDM stats ~/.claude/skills/unifi/scripts/query-classic.sh /stat/sta # clientes CON bytes/signal/SSID ~/.claude/skills/unifi/scripts/query-classic.sh /stat/event # eventos (login, roaming, etc) ~/.claude/skills/unifi/scripts/query-classic.sh /stat/alarm # alarmas ~/.claude/skills/unifi/scripts/query-classic.sh /list/wlanconf # WLANs / SSIDs ~/.claude/skills/unifi/scripts/query-classic.sh /rest/firewallrule ``` El path corto (`/stat/...`) se prefija a `/proxy/network/api/s/$UNIFI_SITE_NAME` automáticamente. La sesión se cachea 25 min en `.cache/cookies.txt` + `.cache/csrf` (chmod 600). ## Read-only por diseño — modelo de seguridad Tres capas, en orden de fuerza: 1. **Server-side (la que importa)**: la cuenta `claudecode0` tiene rol **"Site View Only"** en Network. El UDM responde **403** a cualquier POST/PUT/DELETE sin importar qué cliente intente, vía API key o via Classic. Esto es lo que te garantiza no romper nada. 2. **Guard en los scripts**: `query.sh` y `query-classic.sh` rechazan flags `-X POST/PUT/DELETE/PATCH` y `-d/--data` con exit 3 antes de salir a la red. Defensa en profundidad — falla rápido con error claro. 3. **Doc**: esta sección. Si Claude (yo o cualquier futura sesión) lee esto y aún así intenta escribir, el server lo bloqueará igual. > ⚠️ La API Key del `.env` la generó el Owner del UDM (no `claudecode0`, porque > View Only no puede crear keys). Técnicamente esa key tiene scope completo — > el guard del script y la convención son lo único que evitan que alguien la > use para escribir vía Integration API. Si querés blindaje total ahí también, > pedile al Owner que regenere una key suya y revoque la actual. ## Si no tenés `jq` Los ejemplos de `endpoints.md` usan `jq` por brevedad. Si no está instalado (ej. git bash en Windows sin extras), tenés dos opciones: 1. **Instalar jq** (recomendado, una vez): ```bash winget install jqlang.jq # o: choco install jq ``` 2. **Usar Python como filtro** (ya viene con la PC): ```bash ~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/devices" \ | python -c "import json,sys; d=json.load(sys.stdin); [print(x['name'], x['state']) for x in d['data']]" ``` ## Flujos típicos de diagnóstico ### "¿qué está conectado a la red?" ```bash ~/.claude/skills/unifi/scripts/query.sh /sites/{site}/clients | jq '.data | length' ~/.claude/skills/unifi/scripts/query.sh /sites/{site}/clients | jq '.data[] | {name, mac, ip, type, uplinkDeviceId, lastSeen}' ``` Filtra por `type` (`WIRED` vs `WIRELESS`) y por `uplinkDeviceId` para saber a qué AP/switch está pegado cada uno. ### "¿están todos los APs online?" ```bash ~/.claude/skills/unifi/scripts/query.sh /sites/{site}/devices | jq '.data[] | {name, model, state, ip, mac, uptime}' ``` `state`: `ONLINE | OFFLINE | PROVISIONING | UPGRADING | ...`. Reporta cualquier device con state ≠ ONLINE. ### "¿la báscula `sacos_bodega` (o impresora `patio`, etc.) está conectada?" 1. Busca el equipo en `topology.md` (mapeo nombre → MAC). 2. Si no está mapeado todavía: lista clientes y proponé al usuario el match más probable basándote en el nombre o en la IP fija conocida (las impresoras del manifest tienen IP fija: `printerCentral` cubre `192.168.87.142, .147, .150, .220, .221`). 3. Una vez tengas el MAC: `query.sh /sites/{site}/clients | jq '.data[] | select(.mac == "AA:BB:...")'` 4. Si lo encontrás, agregá el mapeo a `topology.md` para futuras queries. ### "¿qué AP cubre tal facility?" Combiná `topology.md` (zonas físicas → AP esperado) + el listado real de `devices` filtrado por nombre/ubicación que tengan configurado en el UDM. ### "¿qué carga tiene cada AP / cuál está saturado?" La Integration API NO devuelve bytes ni count de clientes en `/clients` ni en `/devices`. Lo que SÍ tenés es `statistics/latest` por device, con CPU%, RAM%, uplink tx/rxBps y % de retransmisiones por radio (indicador de saturación inalámbrica): ```bash ~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/devices//statistics/latest" ``` Para ranking de clientes por bytes consumidos NO hay endpoint — necesita Classic API. ### "muéstrame el estado del WAN / uplink" **No está en la Integration API.** Por device sí podés ver `uplink.txRateBps/rxRateBps` en `statistics/latest`, pero el health agregado del WAN (latencia, drops, ISP status) solo está en Classic API. Si el usuario insiste, avisale que toca extender la skill con `query-classic.sh` (login flow). No lo improvises sin avisar. ## Setup inicial (lo hace el usuario UNA vez) 1. **Generar API Key en el UDM Pro UI:** - Abrí `https://192.168.87.5` en el navegador (o el dominio interno si lo tenés mapeado). - Loggéate con admin local (NO cuenta cloud). - UniFi Network → Settings → **Control Plane** → **Integrations**. - "Create API Key", copiá el valor (solo se muestra una vez). 2. **Crear el `.env`:** ```bash cp ~/.claude/skills/unifi/.env.example ~/.claude/skills/unifi/.env # Editar y pegar el API key: # UNIFI_API_KEY= ``` 3. **Probar:** ```bash ~/.claude/skills/unifi/scripts/query.sh /sites ``` Esperado: JSON con un array `data` que contenga al menos `default`. ## Notas sobre red - El UDM Pro está SOLO accesible desde la LAN (192.168.87.0/24). Si vas a usar esta skill desde fuera del beneficio, necesitás VPN/Tailscale o un túnel. - El cert TLS del UDM Pro es self-signed → el helper usa `curl -k`. Es aceptable para tráfico en la LAN, pero no copies ese patrón a apps en producción. - DNS interno (`*.interno`) lo sirve este mismo UDM. Si la skill empieza a fallar en resolución, probá apuntar a la IP cruda `192.168.87.5`. ## Qué NO hace esta skill - No escribe (no bloquea/desbloquea clientes, no provisiona VLANs, no reinicia APs). Read-only por diseño. - No habla con UniFi Protect, Access ni Talk. Solo Network. - No mantiene cache local. Cada query golpea el UDM Pro. - No expone MCP — es Bash + curl. Si más adelante querés exponerla a Claude Desktop o a la `agentUI`, ahí sí justifica un sidecar Bun en el Swarm. ## Referencias - `endpoints.md` — cheat sheet de los 15 endpoints Integration API v1 + algunos Classic útiles - `topology.md` — mapa de MACs/IPs → equipo del beneficio (jala del manifest, se llena con uso) - Doc oficial: https://developer.ui.com/ (Integration API)