system-droid: менің жүйелерімді өзі тексеріп, өзі жөндейтін күзетші
Жергілікті сервистерім үнемі үнсіз өліп қалатын: таңғы шолу келмей қалады, токендердің мерзімі бітеді, сақтық көшірме қатып қалады — мен соңғы болып білетінмін. Сондықтан launchd-та дроид жасадым: әр екі сағат сайын бәрін тексереді, қауіпсізін Claude агенті арқылы жөндейді, ал маған адам шынымен керек болғанда ғана жазады.
TL;DR
system-droid — launchd әр екі сағат сайын және Mac ұйқыдан оянған сайын іске қосатын шағын Go бағдарламасы. Ол менің барлық жергілікті сервистерімді тексеру тізімі бойынша аралап шығады, бәрі жұмыс істеп тұрғанда үндемейді, ал Telegram-ға тек бірдеңе шынымен сынғанда ғана жазады. Күніне бір рет «бәрі жұмыс істейді» деген қысқа есеп жібереді — тыныштық ешқашан «белгісіз» дегенді білдірмеуі үшін. Ал бірдеңе құласа, алдымен өзі жөндеп көреді: жеке Claude (Opus) агенті себебін тауып, жояды, тек жөндей алмаса ғана мені шақырады.
◆ Усі системи в нормі · 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-сховища на GitHubМұның бәрі не үшін
Соңғы айларда менде байқаусыз тұтас жергілікті автоматтандыру паркі жиналып қалды: OpenClaw агенті («Резонанс»), украин тіліндегі StyleTTS2 дауыс сервері, Claude алдындағы LLM-прокси, Obsidian үшін күнделікті жазба генераторлары, қойманың git-көшірмесі, корпоративтік телеметрияны бөгейтін firewall ережесі. Бұлардың әрқайсысы жұмыс істеп тұрғанда ғана пайдалы. Ал сынған кезде — бәрі бірдей сынатын: үнсіз.
Таңғы шолу жай ғана келмей қалатын — мен оны кешке ғана байқайтынмын. Жоспарлағыш процесті өлтіретін, бірақ соңғы іске қосылу бәрібір «сәтті» көрінетін. Авторизация токенінің мерзімі бітіп, генерация апталап апаттық мәтінмен өмір сүре беретін. Бұл ақаулардың ешқайсысы өзі туралы хабарламайды: сервис шағымданбайды — жай ғана жоғалады. Маған мұны мен үшін байқайтын біреу керек болды.
Қалай құрылған
Бүкіл жүйе — бір бинар және екі түрлі тексеруден тұратын config.json: HTTP (сервис /health-ке жауап береді) және командалық (скрипт 0 кодымен аяқталады). launchd дроидты кесте бойынша қосады; ол тексерулерді қатар жүргізіп, мені мазалау керек пе, жоқ па — өзі шешеді. Жаңа жүйені бақылауға қою — конфигурациядағы бір жол, қайта компиляциясыз.
Басты қағида — назарды үнемдеу. Ашып қарайтын дашбордтар жоқ, әр екі сағат сайынғы «бәрі жақсы» ағыны жоқ. Хабарламаның дәл үш түрі бар: бәрі жасыл екені туралы күнделікті қорытынды; «сынды — өзім жөндедім»; және «сынды — сен керексің». Қалғанының бәрі — тыныштық.
Өзін-өзі емдеу
Тексеру құлағанда дроид бірден маған жүгірмейді. Алдымен құралдары шектеулі, тек белгілі қалталарға ғана жаза алатын Claude агентін қосады. Әр әрекеттің алдында барлық жұмыс каталогтарының git-суреті түсіріледі, сондықтан агенттің кез келген өзгерісін бір командамен кері қайтаруға болады — суреттердің хештері хабарламаның өзінде тұрады:
🔧 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 @ e98746cБұл ойыншық емес: агент түнгі желі үзілісінен кейін ескірген шолуды шынымен қайта жасады, тұрып қалған launchd-тапсырманы өзі қайта жүктеді және токен мәселесі менсіз шешілмейтінін өзі анықтады. Хабарламадан не сынғанын, агент не істегенін және бәрі немен біткенін көремін.
Ол қазірдің өзінде нені ұстады
Жеті аптада дроид бірнеше үнсіз ақауды — әрқайсысы күндеп өмір сүре алатын еді — мен бірден көрген хабарламаларға айналдырды:
- Өлтірілген шолу генераторы. Бинар қайта құрастырылғаннан кейін macOS ядросы процесті бірден атып тастады — таңғы шолу жай ғана шықпай қалатын еді, оны ешкім байқамас еді.
- Мерзімі біткен refresh-токен. Прокси қатынау токенін жаңартуды тоқтатты, барлық LLM-шақырулар 401 қайтара бастады. Дроид тура айтты: бұл тек қайта кірумен шешіледі — бір команда, екі минут.
- Талдаудың орнына апаттық мәтін. Генерация «сәтті» аяқталатын, бірақ жазбада AI-талдаудың орнына резервтік мәтін тұрған. Шығу кодын емес, жазба мазмұнын тексеру мұны бірінші күні-ақ ұстады.
- Қатып қалған қойма көшірмесі. Git-плагин жергілікті коммиттерін жасай берген, ал GitHub-қа push үнсіз өліп қалған — резервтік көшірме қатып қалып, бұл ең қолайсыз сәтте белгілі болар еді.
Нені әдейі емдемейді
Бұл жүйедегі ең маңызды шешім — нені автоматтандыру емес, нені автоматтандырмау. Тексерулердің бір бөлігі «тек хабарла» деп белгіленген: авторизацияға, бөтен жүйелерге және өз агентімнің сессияларына қатыстының бәрі. Мерзімі біткен OAuth скриптпен «жөнделмейді» — оны адам браузерде қайта шығаруы керек. Агентке токендерге тиюге, менің жұмыс сервистерімді қайта қосуға және тексеруді жасыл болғанша «бұрап қоюға» тікелей тыйым салынған.
Физикалық шек те бар: емші — сол Claude CLI-дің өзі, желі немесе авторизация құласа, ол да бәрімен бірге құлайды. Жүйені сындырған нәрсе оны жөндейтін қолдарды да сындырады. Мұндайда адал мінез — ерлікпен қайталай беру емес, нақты не істеу керегін түсіндірген анық «сен керексің».
Бәрі сүйенген ұсақ-түйектер
Ең көп уақытты тексерулер емес, күзетшінің өз сенімділігі алды. Біріншісі: Go бинарын орнында қайта құрастыру оның қолтаңбасын өзгертеді, ал launchd қолтаңба талаптарын кэштейді — сондықтан жүйе келесі жоспарлы іске қосуды жай ғана өлтіреді. Енді құрастыру әрқашан тапсырманы қайта жүктеумен аяқталады:
# Перезбирання бінарника на місці змінює його 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 # свіжий запуск має бути зеленимЕкіншісі: KeepAlive-сервистер үшін соңғы іске қосылудың шығу коды — алдамшы өлшем. Әр қайта қосылудан кейін онда SIGTERM тұрады, әбден тірі сервис сынған сияқты көрінеді. Дұрыс сұрақ — «ол қалай аяқталды» емес, «ол дәл қазір жұмыс істеп тұр ма»:
# У 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 1Үшіншісі: жүйе шынымен тәуелді болатын объектінің дәл өзін тексеру керек. Менің алғашқы токен-тексеруім «берілген күн қосу бір жыл» деп есептейтін — нағыз токен бір тәулік бойы 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."Төртіншісі: түнгі үштегі бір циклдік желі үзілісі — адамды оятуға себеп емес. «Араласу керек» дабылы енді мәселе қатарынан екі іске қосылудан аман өткенде ғана жіберіледі. Бір реттік ақаулар өздігінен тарқайды; шынайылары бәрібір жетеді — тек екі сағат кешігіп:
// Тривога "потрібне втручання" — лише якщо перевірка провалилася
// два запуски поспіль. Нічний обрив мережі, демон посеред перезапуску,
// пробудження зі сну — все це минає само до наступного циклу,
// і будити людину через таке не можна. Успішне лікування,
// навпаки, повідомляється одразу — це добра новина, а не шум.
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Басқа агентке арналған көз
Telegram-нан бөлек, дроид MCP-сервер ретінде де жұмыс істейді. Яғни менің жергілікті агентім жүйелердің күйін одан өзі сұрай алады: есептерді оқудың орнына «бәрі жұмыс істеп тұр ма, тексерші» деймін — агент get_health-ті шақырып, әр тексеруді тікелей жүргізіп, жауап береді. Мониторинг қарайтын бет болудан қалып, жүгінетін сервиске айналды.
# Дроїд працює і як 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-токен (валідність, авто-оновлення)
...Қорытынды
Техникалық жағынан мұнда күрделі ештеңе жоқ: Go, launchd, бірнеше shell-скрипт және Telegram-бот. Бірақ дәл осы қарапайым байлам бүкіл автоматтандыру паркіне деген сезімімді өзгертті: «тексеруді ұмытпау керек» нәрселердің тізімін басымда ұстауды қойдым. Енді ол — дроидтың жұмысы.
Жеті апта бойы ол негізінен үнсіз. Осы уақытта жіберген әр хабарламасы не жөнделіп қойған нәрсе туралы жақсы жаңалық, не менің екі минутым қай жерде керегін дәл көрсету болды. Ыңғайлылық деген осы: басқа жүйелерді күзететін — әрі сенің тыныштығыңды құрметтейтін жүйе.
Қате байқадыңыз ба?
Осы мақалада қате факт, олқы аударма немесе жалған естілетін нәрсе бар ма? Маған жазыңыз — өз тіліңізде.