← Блог

Персональная корпорация: ставим агентов на расписание

Сережа Рис · 25 February 2026

автоматизацияmacosclaude code

launchd — встроенный планировщик macOS, который запускает задачи по расписанию. В отличие от cron, он помнит пропущенные запуски: закрыл крышку ноутбука в 18:55, открыл в 21:00 — задача на 19:00 всё равно выполнится. Попросить Claude Code настроить launchd проще, чем разбираться в его XML-конфигах самому.

Зачем вайбкодеру планировщик

У каждого, кто автоматизирует рутину через агентов, накапливаются задачи на повтор. Отправить пост в Telegram в 19:00. Собрать аналитику чата утром. Почистить временные файлы раз в неделю.

Первое время запускаешь руками. Потом забываешь. Потом злишься, что забыл.

Мне это надоело после третьего пропущенного поста. Подробнее писал в как я автоматизировал публикацию постов — там автопостер уже работал, но запускал его я сам. Нужно было убрать последнее звено — себя.

Что такое launchd

launchd — это PID 1. Первый процесс, который запускается при загрузке macOS. Буквально — всё остальное запускается через него. Finder, Dock, Wi-Fi, обновления системы. Всё.

Apple заменил им и cron, и init, и ещё пачку старых демонов. cron на macOS формально ещё работает, но он устаревший — Apple пометила его как deprecated и рекомендует launchd.

Ключевое свойство: launchd помнит расписание даже когда мак спит. Если задача должна была запуститься в 19:00, а ноутбук проснулся в 22:00 — задача выполнится. cron бы просто пропустил.

Для вайбкодера с MacBook это критично. Ноутбук закрывают. Берут в кафе. Забывают зарядить. А задачи должны выполняться.

Анатомия plist — на живом примере

Конфиг launchd — это XML-файл с расширением .plist. Живёт в ~/Library/LaunchAgents/. Вот мой реальный конфиг, который отправляет посты в Telegram каждый день:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.serejaris.telegram-queue</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/ris/.claude/skills/blog-to-telegram/send_scheduled.sh</string>
    </array>
    <key>WorkingDirectory</key>
    <string>/Users/ris/.claude/skills/blog-to-telegram</string>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>7</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/Users/ris/Library/Logs/telegram-queue.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/ris/Library/Logs/telegram-queue.log</string>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>

XML выглядит устрашающе, но внутри всего шесть параметров.

Label — уникальное имя задачи. Используется обратный DNS:

com.serejaris.telegram-queue
 │       │          │
 │       │          └── задача
 │       └───────────── автор
 └───────────────────── домен

ProgramArguments — что запускать. Полный путь к скрипту.

WorkingDirectory — откуда запускать. Важно, если скрипт читает файлы рядом с собой.

StartCalendarInterval — расписание. Hour: 7, Minute: 0 означает каждый день в 7:00 по локальному времени системы. Не UTC — launchd использует часовой пояс мака. У меня стоит America/Buenos_Aires, 7 утра там — это 13:00 по Москве. Если бы мак был настроен на московское время, поставил бы Hour: 13 напрямую.

StandardOutPath / StandardErrorPath — куда писать логи. Без них ошибки уходят в никуда, и отладка превращается в гадание.

RunAtLoad — запустить ли задачу сразу при загрузке агента. Для расписания ставлю false — пусть ждёт своего времени.

Как попросить агента создать

Не нужно запоминать структуру XML. Не нужно гуглить параметры. Достаточно описать что хочешь.

Когда мне понадобился автопостер по расписанию, написал Claude Code на Opus 4.6:

Настрой launchd, чтобы каждый день в 19:00 по Москве запускался скрипт отправки постов в Telegram. Логи в ~/Library/Logs/. Скрипт лежит в ~/.claude/skills/blog-to-telegram/send_scheduled.sh

Агент создал plist-файл, положил в ~/Library/LaunchAgents/, загрузил через launchctl и проверил статус. Я не открывал ни одного XML-файла.

Когда понадобилось добавить ежедневную аналитику — тот же подход. Подробнее про саму аналитику писал в когда аналитика просыпается по расписанию.

Написал Claude Code:

Добавь ещё один launchd-агент: каждое утро в 9:00 МСК запускай скрипт сбора статистики из Telegram-чата. По аналогии с telegram-queue — такой же формат, логи рядом.

Три минуты. Готово. Второй агент в расписании.

Если что-то не работает — не отлаживаю сам. Говорю:

launchd-агент telegram-queue не запустился вчера. Проверь статус, посмотри логи, почини.

Агент запускает launchctl list, читает лог-файл, находит проблему, чинит. Мне не нужно помнить ни одной команды launchctl.

Персональная корпорация на расписании

Каждый launchd-агент — это сотрудник, который приходит на работу в одно и то же время. Не опаздывает. Не забывает. Не просит повышения.

Пока у меня один такой “сотрудник” — com.serejaris.telegram-queue. Отправляет посты в Telegram-канал каждый день в 13:00 МСК. Но принцип масштабируется:

  ~/Library/LaunchAgents/
  │
  ├── com.serejaris.telegram-queue   ← посты в канал
  ├── com.serejaris.daily-digest     ← утренняя сводка
  ├── com.serejaris.weekly-backup    ← бэкап по понедельникам
  └── ...

Каждая новая задача — один промпт агенту. Попросил — появился ещё один plist в папке. Подробнее про философию “личной корпорации” и когда полный цикл работает без моего участия — это тот же принцип, только с видео.

Моё правило: если процесс повторяется больше двух раз — делегировать. Сначала агенту. Потом расписанию.

Под капотом: что делает агент

Когда просишь агента “загрузи планировщик” или “проверь, работает ли” — он выполняет команды launchctl. Три основных:

Ноль в первой колонке — задача работает. Другое число — код ошибки, агент смотрит в логи.

Я эти команды не набираю. Но знать что они существуют — полезно, чтобы понимать, что агент делает под капотом.

Аналоги на Windows и Linux

launchd — штука macOS. Если ты на другой системе, вот аналоги.

Windows: Task Scheduler. Графический интерфейс через taskschd.msc, командная строка через schtasks, PowerShell через Register-ScheduledTask. Умеет будить компьютер для задачи, но catch-up пропущенных задач работает не так надёжно.

Linux: systemd timers. Ближайший аналог launchd. Параметр Persistent=true делает то же самое — запускает пропущенную задачу после пробуждения. Если дистрибутив без systemd — старый добрый cron, но без catch-up.

Принцип тот же: описываешь агенту что хочешь, он настраивает под твою систему.

FAQ

Что будет, если мак был в режиме сна?

launchd запустит пропущенную задачу при пробуждении. Но если мак был полностью выключен (shutdown, а не sleep) — задача не запустится. Для ноутбуков это обычно не проблема: крышку закрыл — это sleep, не shutdown.

Чем это отличается от cron?

Три отличия. Первое: launchd ловит пропущенные задачи, cron — нет. Второе: cron на macOS устаревший, Apple рекомендует launchd. Третье: launchd умеет следить за файлами и папками, а не только за временем — можно запустить скрипт, когда файл изменился.

А если я хочу запускать каждые 30 минут, а не по расписанию?

Используй StartInterval вместо StartCalendarInterval. Значение в секундах: 1800 — это 30 минут. Но для большинства задач хватает расписания по времени.

Где посмотреть, что пошло не так?

Логи — в файле, который указал в StandardOutPath. У меня все логи в ~/Library/Logs/. Открыл файл — видишь вывод скрипта, включая ошибки.

Можно ли запускать агента Claude Code по расписанию?

Да. Скрипт может вызывать claude через CLI. Но тут нужно думать про лимиты токенов и стоимость — если агент запускается каждый час, расход будет заметным.

Как удалить задачу?

Выгрузить агент через launchctl unload и удалить plist-файл. Или попросить агента: “убери задачу telegram-queue из расписания”.


Мак может работать на тебя, пока ты не за компьютером. Один промпт — задача в расписании. Дальше система сама.

Подписаться на обновления — @sereja_tech