system-droid: en vakthund som selv sjekker og reparerer systemene mine
De lokale tjenestene mine døde alltid lydløst — morgenrapporten kom ikke, tokens utløp, backupen frøs. Så jeg bygde en launchd-droid som sjekker alt annenhver time, reparerer det som trygt kan fikses via en Claude-agent, og skriver til meg bare når et menneske virkelig trengs.
TL;DR
system-droid er et lite Go-program som launchd starter annenhver time og etter hver gang Macen våkner fra dvale. Det går gjennom en liste med kontroller av alle mine lokale tjenester, holder seg taus så lenge alt virker, og skriver til Telegram bare når noe faktisk er ødelagt. Én gang om dagen sender det en kort oppsummering om at alt er grønt, slik at stillhet aldri betyr "ukjent". Og når noe først ryker, prøver det å fikse det selv: en egen Claude-agent (Opus) sporer opp årsaken og retter den — og tilkaller meg bare hvis den mislykkes.
◆ Усі системи в нормі · 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-сховища на GitHubHvorfor det finnes
I løpet av de siste månedene hadde jeg i det stille samlet en hel flåte av lokal automatisering: en OpenClaw-agent ("Resonance"), en ukrainsk StyleTTS2-stemmeserver, en LLM-proxy foran Claude, daglige notatgeneratorer for Obsidian, en git-kopi av hvelvet mitt, en brannmurregel som blokkerer bedriftstelemetri. Hver av disse er nyttig nøyaktig så lenge den kjører. Og de røk alltid på samme måte — lydløst.
Morgenrapporten kom rett og slett ikke, og jeg merket det først om kvelden. Planleggeren drepte en prosess, men siste kjøring så likevel "vellykket" ut. En påloggingstoken utløp, og genereringen kunne leve i ukevis på en nødløsning. Ingen av disse feilene melder fra om seg selv: en tjeneste klager ikke — den bare forsvinner. Jeg trengte noen som la merke til det for meg.
Hvordan det virker
Hele systemet er én binær pluss en config.json med to typer kontroller: HTTP (tjenesten svarer på /health) og kommando (et skript avslutter med kode 0). launchd starter droiden etter planen; den kjører kontrollene parallelt og avgjør om jeg i det hele tatt må forstyrres. Å sette et nytt system under oppsyn er én linje i konfigurasjonen — uten omkompilering.
Kjerneprinsippet er å økonomisere med oppmerksomheten. Ingen dashbord som må åpnes, ingen "alt vel"-støy annenhver time. Det finnes nøyaktig tre typer meldinger: den daglige oppsummeringen om at alt er grønt; "det røk — jeg fikset det"; og "det røk — jeg trenger deg". Alt annet er stillhet.
Selvhelbredelse
Når en kontroll feiler, løper ikke droiden straks til meg. Først starter den en Claude-agent med et begrenset verktøysett og skriverettigheter bare i bestemte mapper. Før hvert forsøk tas et git-øyeblikksbilde av alle arbeidskatalogene, så alt agenten endrer kan rulles tilbake med én kommando — hashene kommer rett i meldingen:
🔧 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 @ e98746cOg det er ikke noe leketøy: agenten har faktisk regenerert et utdatert sammendrag etter et nattlig nettbrudd, selv lastet en fastlåst launchd-jobb inn på nytt, og selv stilt diagnosen at et tokenproblem ikke lot seg løse uten meg. I meldingen ser jeg hva som var ødelagt, hva agenten gjorde og hvordan det endte.
Hva den allerede har fanget
På sju uker har droiden gjort flere lydløse havarier — hvert av dem kunne ha levd i dagevis — om til meldinger jeg så umiddelbart:
- En drept rapportgenerator. macOS-kjernen skjøt prosessen rett etter en ombygging av binæren — morgenrapporten ville rett og slett aldri gått ut, og ingen ville merket det.
- En utløpt refresh-token. Proxyen sluttet å fornye tilgangstokenet sitt, og hvert LLM-kall kom tilbake med 401. Droiden sa det rett ut: dette løses bare med ny pålogging — én kommando, to minutter.
- En plassholder i stedet for analyse. Genereringen endte "vellykket", men notatet inneholdt reservetekst i stedet for AI-analyse. Å sjekke innholdet, ikke exitkoden, fanget det første dagen.
- En fastfrossen hvelv-backup. Git-pluginen fortsatte å committe lokalt mens pushen til GitHub stille hadde dødd — sikkerhetskopien ville frosset, og det ville blitt oppdaget på det verst tenkelige tidspunktet.
Hva den bevisst ikke fikser
Den viktigste beslutningen i dette systemet er ikke hva som skal automatiseres, men hva som ikke skal det. Noen kontroller er merket kun-varsle: alt som gjelder autentisering, andres systemer og min egen agents økter. En utløpt OAuth "fikses" ikke av et skript — et menneske må utstede den på nytt i nettleseren. Agenten har uttrykkelig forbud mot å røre tokens, starte mine kjørende tjenester på nytt eller jukse med en kontroll til den blir grønn.
Det finnes også en fysisk grense: legen er selv en Claude-CLI, og når nettet eller påloggingen går ned, går den ned sammen med alt annet. Det som knekker systemet, knekker også hendene som reparerer det. Ærlig oppførsel der er ikke heroiske forsøk, men et tydelig "jeg trenger deg" — med nøyaktig beskjed om hva som må gjøres.
Småtingene alt hvilte på
Det som tok mest tid var ikke kontrollene, men vaktens egen pålitelighet. For det første: å bygge en Go-binær om på stedet endrer signaturen dens, og launchd cacher signaturkrav — så systemet dreper rett og slett neste planlagte kjøring. Et bygg ender nå alltid med at jobben lastes inn på nytt:
# Перезбирання бінарника на місці змінює його 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 # свіжий запуск має бути зеленимFor det andre: for KeepAlive-tjenester er siste kjørings exitkode et villedende mål. Etter hver omstart står det SIGTERM der, og en fullt levende tjeneste ser ødelagt ut. Riktig spørsmål er ikke "hvordan avsluttet den", men "kjører den akkurat nå":
# У 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 1For det tredje: sjekk nøyaktig det objektet systemet avhenger av. Min første tokenkontroll regnet "utstedelsesdato pluss ett år" — og lyste grønt mens den ekte tokenen hadde svart 401 i et døgn:
# Календарна перевірка сяяла зеленим — річному токену ще жити й жити:
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."Og for det fjerde: et nettbrudd på én enkelt syklus klokka tre om natten er ingen grunn til å vekke et menneske. Alarmen "inngripen kreves" sendes nå bare hvis problemet overlever to kjøringer på rad. Engangsfeil løser seg selv; ekte feil når likevel fram — bare to timer senere:
// Тривога "потрібне втручання" — лише якщо перевірка провалилася
// два запуски поспіль. Нічний обрив мережі, демон посеред перезапуску,
// пробудження зі сну — все це минає само до наступного циклу,
// і будити людину через таке не можна. Успішне лікування,
// навпаки, повідомляється одразу — це добра новина, а не шум.
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) > 0Øyne til en annen agent
I tillegg til Telegram kjører droiden også som MCP-server. Det betyr at min lokale agent selv kan spørre den om systemenes tilstand: i stedet for å lese rapporter sier jeg "sjekk at alt virker" — agenten kaller get_health, kjører hver kontroll live og svarer. Overvåkingen sluttet å være en side man ser på, og ble en tjeneste man rådfører seg med.
# Дроїд працює і як 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-токен (валідність, авто-оновлення)
...Oppsummering
Teknisk er det ingenting komplisert her: Go, launchd, noen skallskript og en Telegram-bot. Men nettopp denne enkle pakken endret følelsen av hele automatiseringsflåten: jeg sluttet å bære på en mental liste over ting jeg "ikke må glemme å sjekke". Det er droidens jobb nå.
I sju uker har den stort sett vært taus. Hver melding den likevel sendte var enten en god nyhet om noe som alt var fikset, eller en presis pekepinn på hvor mine to minutter trengtes. Det er det bekvemmelighet betyr: et system som vokter andre systemer — og respekterer stillheten din.
Fant du en feil?
Et feil faktum, en skjev oversettelse, noe som virker usant i denne artikkelen? Skriv til meg — på ditt eget språk.