system-droid: un guardián que revisa y repara mis sistemas por sí solo
Mis servicios locales morían en silencio: el informe matinal no llegaba, los tokens caducaban, la copia de seguridad se congelaba. Así que construí un droide sobre launchd que lo revisa todo cada dos horas, repara con un agente Claude lo que es seguro y me escribe solo cuando de verdad hace falta un humano.
TL;DR
system-droid es un pequeño programa en Go que launchd ejecuta cada dos horas y tras cada despertar del Mac. Recorre una lista de comprobaciones por todos mis servicios locales, guarda silencio mientras todo funciona y escribe por Telegram solo cuando algo se ha roto de verdad. Una vez al día envía un breve resumen de "todo en orden", para que el silencio nunca signifique "desconocido". Y cuando algo falla, primero intenta arreglarlo por su cuenta: un agente Claude (Opus) independiente localiza la causa y la corrige, y solo me llama si no lo consigue.
◆ Усі системи в нормі · 10/10 · 2026-08-17 09:00
— OpenClaw / Resonance
◆ styletts2-ua (tts) — локальний український TTS :8123
◆ openclaw gateway (:18789) — ядро агента Resonance (launchd + порт)
◆ openclaw hooks — hooks-ендпоінт увімкнено
— Інфраструктура
◆ cli-proxy Claude auth — робочий Claude-токен (валідність, авто-оновлення)
◆ system-droid — сам вартовий (надсилає ці звіти)
◆ otel-block — корпоративна телеметрія заблокована у firewall
◆ vault git backup — git-копія Obsidian-сховища на GitHubPor qué existe
En los últimos meses se me había acumulado, sin darme cuenta, toda una flota de automatización local: un agente OpenClaw ("Resonance"), un servidor de voz ucraniano StyleTTS2, un proxy LLM delante de Claude, generadores diarios de notas para Obsidian, una copia git de mi bóveda, una regla de cortafuegos que bloquea la telemetría corporativa. Cada una de estas piezas es útil exactamente mientras funciona. Y siempre se rompían de la misma manera: en silencio.
El informe matinal simplemente no llegaba, y yo no me daba cuenta hasta la noche. El planificador mataba un proceso, pero su última ejecución seguía pareciendo "exitosa". Un token de autenticación caducaba, y la generación podía pasarse semanas tirando de un texto de emergencia. Ninguno de estos fallos se anuncia: un servicio no se queja — simplemente desaparece. Necesitaba a alguien que lo notara por mí.
Cómo funciona
Todo el sistema es un binario más un config.json con dos tipos de comprobaciones: HTTP (el servicio responde en /health) y de comando (un script termina con código 0). launchd arranca el droide según el horario; este ejecuta las comprobaciones en paralelo y decide si hace falta molestarme siquiera. Poner un sistema nuevo bajo vigilancia es una línea en la configuración, sin recompilar.
El principio central es la economía de atención. Sin paneles que abrir, sin spam de "todo bien" cada dos horas. Hay exactamente tres tipos de mensajes: el resumen diario de que todo está en verde; "se rompió — lo arreglé yo"; y "se rompió — te necesito". Todo lo demás es silencio.
Autocuración
Cuando una comprobación falla, el droide no corre a avisarme de inmediato. Primero lanza un agente Claude con un conjunto de herramientas restringido y permiso de escritura solo en carpetas concretas. Antes de cada intento toma una instantánea git de todos los directorios de trabajo, así que cualquier cambio del agente se revierte con un solo comando — los hashes llegan en el propio mensaje:
🔧 system droid — полагоджено автоматично, 1 спроба (2026-08-02 07:41)
Було зламано:
• news digest freshness — застарілий дайджест: 2026-07-31 (2 дні тому)
✅ Зараз усі перевірки зелені.
↩️ Відкат змін агента (git reset --hard на знімок):
• ~/Developer/system-droid @ f037cfb
• ~/Developer/obsidian-cron @ e98746cY no es un juguete: el agente ha regenerado de verdad un resumen desactualizado tras un corte nocturno de red, ha recargado por sí mismo una tarea de launchd atascada y ha diagnosticado correctamente que un problema de token no se arreglaba sin mí. En el mensaje veo qué se rompió, qué hizo el agente y cómo terminó todo.
Lo que ya ha cazado
En siete semanas, el droide convirtió varios fallos silenciosos — cada uno podría haber vivido días — en mensajes que vi al instante:
- Un generador de informes muerto. El núcleo de macOS fusiló el proceso justo después de recompilar el binario — el informe matinal simplemente no habría salido, y nadie lo habría notado.
- Un refresh token caducado. El proxy dejó de renovar su token de acceso y cada llamada al LLM devolvía 401. El droide lo dijo claro: esto solo se arregla con un nuevo inicio de sesión — un comando, dos minutos.
- Un texto de relleno en vez de análisis. La generación terminaba "con éxito", pero la nota contenía un texto de emergencia en lugar del análisis de IA. Comprobar el contenido de la nota, no el código de salida, lo cazó el primer día.
- Una copia de seguridad congelada. El plugin de git seguía haciendo commits locales mientras el push a GitHub había muerto en silencio — la copia se habría quedado congelada, y se habría descubierto en el peor momento posible.
Lo que deliberadamente no arregla
La decisión más importante de este sistema no es qué automatizar, sino qué no. Algunas comprobaciones están marcadas como «solo avisar»: todo lo que toca la autenticación, los sistemas ajenos y las sesiones de mi propio agente. Un OAuth caducado no se "arregla" con un script — tiene que reemitirlo una persona en el navegador. Al agente le está expresamente prohibido tocar tokens, reiniciar mis servicios en marcha o retorcer una comprobación hasta que se ponga verde.
También hay un límite físico: el sanador es, a su vez, un CLI de Claude, y cuando cae la red o la autenticación, cae junto con todo lo demás. Lo que rompe el sistema rompe también las manos que lo reparan. Por eso el comportamiento honesto ahí no son reintentos heroicos, sino un claro "te necesito" con instrucciones exactas de qué hacer.
Los detalles que lo sostenían todo
Lo que más tiempo llevó no fueron las comprobaciones, sino la fiabilidad del propio vigilante. Primero: recompilar un binario de Go en su sitio cambia su firma, y launchd cachea los requisitos de firma — así que el sistema simplemente mata la siguiente ejecución programada. Ahora toda compilación termina recargando la tarea:
# Перезбирання бінарника на місці змінює його cdhash, а launchd кешує
# вимоги до підпису (LWCR) на момент bootstrap. Після збирання кеш
# застаріває — і наступний плановий запуск ядро вбиває (exit 9) або
# launchd відмовляється його запускати (exit 78 / EX_CONFIG).
# Тому збирання ЗАВЖДИ закінчується перезавантаженням задачі:
go build -o system-droid .
codesign --verify --strict system-droid
launchctl bootout "gui/$(id -u)/com.oleksii.system-droid" 2>/dev/null || true
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.oleksii.system-droid.plist
./check-self.sh # свіжий запуск має бути зеленимSegundo: en servicios con KeepAlive, el código de salida de la última ejecución es una métrica engañosa. Tras cada reinicio marca SIGTERM, y un servicio perfectamente vivo parece roto. La pregunta correcta no es "cómo terminó", sino "¿está funcionando ahora mismo?":
# У KeepAlive-демона LastExitStatus після КОЖНОГО перезапуску
# ненульовий (15/SIGTERM) — тож перевірка "останній запуск успішний"
# хибно валить цілком живий сервіс. Правильне питання інше:
# чи працює він ПРЯМО ЗАРАЗ?
info=$(launchctl list "$1" 2>/dev/null) || { echo "not loaded"; exit 1; }
pid=$(printf '%s\n' "$info" | awk -F'= ' '/"PID"/{gsub(/[ ;]/,"",$2);print $2}')
[ -n "$pid" ] && [ "$pid" != "0" ] && { echo "running (pid $pid)"; exit 0; }
echo "loaded but not running"; exit 1Tercero: hay que comprobar exactamente el objeto del que depende el sistema. Mi primera comprobación del token calculaba "fecha de emisión más un año" — y brillaba en verde mientras el token real llevaba un día devolviendo 401:
# Календарна перевірка сяяла зеленим — річному токену ще жити й жити:
claude oauth token — OK: valid, 365d left
# А справжній робочий токен тим часом помер, і логи проксі це знали:
token refresh failed: {"error":"invalid_grant","error_description":"Refresh token expired"}
POST /v1/chat/completions → 401 "OAuth access token has expired. Re-authenticate."Y cuarto: un corte de red de un solo ciclo a las tres de la madrugada no es motivo para despertar a nadie. La alarma de "se necesita intervención" ahora solo salta si el problema sobrevive dos ejecuciones seguidas. Los fallos puntuales se disuelven solos; los reales llegan igualmente — solo dos horas más tarde:
// Тривога "потрібне втручання" — лише якщо перевірка провалилася
// два запуски поспіль. Нічний обрив мережі, демон посеред перезапуску,
// пробудження зі сну — все це минає само до наступного циклу,
// і будити людину через таке не можна. Успішне лікування,
// навпаки, повідомляється одразу — це добра новина, а не шум.
counts := loadHealCounts() // ~/.system-droid-heal-state.json
for _, r := range stillFailing {
counts[r.Name]++
}
var persistent []Result
for _, r := range stillFailing {
if counts[r.Name] >= 2 { // поріг ескалації
persistent = append(persistent, r)
}
}
// сповіщення — лише якщо len(persistent) > 0Ojos para otro agente
Además de Telegram, el droide funciona también como servidor MCP. Eso significa que mi agente local puede preguntarle directamente por el estado de los sistemas: en vez de leer informes, digo "comprueba que todo funciona" — el agente llama a get_health, ejecuta cada comprobación en vivo y responde. La monitorización dejó de ser una página que se mira y pasó a ser un servicio al que se consulta.
# Дроїд працює і як MCP-сервер — локальний агент питає його сам:
Resonance › виклич get_health у system-droid і скажи, чи все зелене
get_health →
overall: 🟢 OK — 10/10 green (2026-08-17 09:00)
🟢 openclaw gateway (:18789) — ядро агента Resonance (launchd + порт)
🟢 cli-proxy Claude auth — робочий Claude-токен (валідність, авто-оновлення)
...Balance
Técnicamente no hay nada complicado aquí: Go, launchd, unos scripts de shell y un bot de Telegram. Pero justo esta combinación sencilla cambió la sensación de toda la flota de automatización: dejé de llevar en la cabeza la lista de cosas que "no hay que olvidar comprobar". Ahora ese es el trabajo del droide.
Durante siete semanas ha estado casi siempre en silencio. Cada mensaje que envió fue o una buena noticia sobre algo ya arreglado, o una indicación precisa de dónde hacían falta mis dos minutos. Eso es la comodidad: un sistema que cuida de otros sistemas — y respeta tu silencio.
¿Ves un error?
¿Un dato incorrecto, una traducción torpe, algo que suena falso en este artículo? Escríbeme — en tu propio idioma.