Routines в Claude Code против моего парка cron-обёрток на VPS: что уехало в облако, а что нет

Routine в Claude Code - это сохранённая конфигурация агента (промпт, репозитории, окружение, коннекторы), которая запускается сама на инфраструктуре Anthropic по расписанию, HTTP-запросу или событию GitHub. Свой cron она заменяет только там, где задаче не нужны локальные файлы: каждый прогон стартует со свежего клона репозитория.

Routines в Claude Code запускают агентов по расписанию, вебхуку и событию GitHub. Разбираю на парке из 11 cron-обёрток, что реально уехало в облако, а что осталось на VPS и почему.

claudeai-разработка
Routines в Claude Code против моего парка cron-обёрток на VPS: что уехало в облако, а что нет

У меня на VPS живёт парк из одиннадцати bash-обёрток. Они дёргают claude -p по расписанию: собирают темы в беклог, генерят черновики, гоняют фактчек по скоркарте, рисуют обложки, публикуют. Первая обёртка появилась 10 июля 2026, сегодня 19-е. За эти девять дней в папку cron/ упало 29 коммитов, из них 12 с префиксом fix. Каждый fix - это когда оно молча сломалось ночью, а я узнал утром по отсутствию алерта в телеге.

А ещё в апреле 2026 Anthropic выкатили Routines: облачные агенты, которые запускаются сами. По расписанию, по HTTP-запросу или по событию в GitHub. На инфраструктуре Anthropic, без моего сервера, без моего flock и без моих двенадцати фиксов.

Ну и первая мысль была понятная: выкидываю парк, переезжаю, живу счастливо. Сел разбираться. Спойлер - не выкинул, но половину задач всё же увёл в облако.

Что такое routines в Claude Code

Routine в Claude Code - это сохранённая конфигурация агента: промпт, список репозиториев, облачное окружение и набор коннекторов. Она запускается автоматически на инфраструктуре Anthropic и работает, даже когда ноутбук закрыт. Фича вышла на неделе 13-17 апреля 2026 и до сих пор в статусе research preview: лимиты и API могут поменяться. Доступна на планах Pro, Max, Team и Enterprise с включённым Claude Code на вебе.

Ключевое отличие от обычной сессии - routine работает полностью автономно. Никакого выбора permission-режима, никаких запросов на подтверждение. Агент сам гоняет shell-команды, сам использует скиллы из склонированного репозитория, сам дёргает коннекторы. Что он может достать - определяется тремя вещами: какие репозитории ты выбрал, какая у окружения сетевая политика и какие коннекторы ты не выключил.

После инцидента, когда агент одной командой снёс мне папку проекта, слово "автономно" я читаю очень внимательно. Тут, правда, есть защита по умолчанию: пушить Claude может только в ветки с префиксом claude/, если ты явно не включил "Allow unrestricted branch pushes" для конкретного репо.

Как запустить routine по расписанию

Два пути. Из веба - claude.ai/code/routines, кнопка New routine, форма с промптом, репозиториями, окружением и триггером. Из CLI - команда /schedule, которой можно сразу скормить описание человеческим языком:

> /schedule daily PR review at 9am

Claude дозадаст вопросы про расписание, репозитории и промпт, потом сохранит routine в твой аккаунт. Обе поверхности пишут в одно место, так что созданное в терминале сразу видно в вебе. Есть алиас /routines, а ещё /schedule list, /schedule update и /schedule run.

Триггеров три штуки, и их можно комбинировать на одной routine:

  • Расписание - hourly, daily, weekdays, weekly или разовый запуск на конкретную дату. Кастомный cron задаётся через /schedule update, минимальный интервал - один час, всё что чаще просто отклоняется.
  • GitHub - события pull request и release, с фильтрами по автору, заголовку, веткам, лейблам, драфт/не драфт, смёржен/не смёржен.
  • API - персональный эндпоинт /fire с bearer-токеном.

Вот последний мне зашёл больше всего:

curl -X POST https://api.anthropic.com/v1/claude_code/routines/trig_01ABC.../fire \
  -H "Authorization: Bearer sk-ant-oat01-xxxxx" \
  -H "anthropic-beta: experimental-cc-routine-2026-04-01" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"text": "Sentry alert SEN-4521 fired in prod. Stack trace attached."}'

В ответ прилетает id и урл новой сессии - открываешь в браузере и смотришь, что там агент нахимичил, в реальном времени.

Отдельно порадовала штука, которую явно делали люди, уже обжёгшиеся на промпт-инъекциях. Текст из поля text не приходит агенту как обычное сообщение - он оборачивается в блок <routine-fire-payload> и помечается как недоверенные данные. Промпт routine должен явно сказать "разбери алерт из routine-fire-payload", иначе текст лежит инертным контекстом. Логика простая: токен могут украсть, и тогда чужие инструкции приедут промаркированными, а не как приказ. Пральна? Пральна.

Чем облачный запуск по расписанию лучше своего cron

Тем, что тебе не надо писать обвязку. В облаке уже есть запуск без твоей машины, история прогонов с полным транскриптом, ретраи триггеров, изоляция окружения и веб-морда, где видно каждый запуск. В своём cron всё это - твой код, который ты пишешь, ломаешь и чинишь сам.

Чтобы не быть голословным, вот что реально лежит в моих обёртках. Не архитектура, а вот именно тот осадок, который выпадает за девять дней:

Блокировки. Каждая обёртка берёт flock на своём lock-файле. Причём семантика разная: авто-запуск по cron, если lock занят, молча выходит с нулём, а запуск из кнопки админки честно ждёт освобождения. Это две строчки кода и один вечер размышлений о том, почему генерация запустилась дважды.

Откат состояния. Генератор клеймит тему из беклога, ставит ей status=in_work и пишет id во временный файл. Если claude -p упал - обёртка обязана вернуть тему обратно в candidate, иначе она навсегда зависнет в работе. У меня для этого отдельная ветка и topic-release в обработчике ошибок.

Коды выхода. У меня их шесть штук с ручным маппингом в человеческие названия шагов: 10 - git pull, 11 - установка скиллов, 12 - упала генерация, 13 - в выводе нет строки ИТОГ, 15 - сдохла работа с базой. Плюс два "хороших" ненулевых кода: 100 (делать нечего, алерт не нужен) и 101 (беклог пуст, но алертить не чаще раза в сутки, для чего есть файл-маркер и find -mmin +1380).

И мой любимый. Алерты в телеграм у меня резали через tail -c 1200, и обрезка иногда разваливала многобайтовый UTF-8 символ пополам. Telegram отвечал на такое 400, алерт молча терялся, а я сидел и думал, почему пайплайн такой тихий. Лечится одной iconv -f utf-8 -t utf-8 -c в общей функции. Искал полдня.

Вот этого всего в routines просто нет как класса задач. Ты пишешь промпт, а не обвязку вокруг промпта.

Сколько routines съедают лимитов

Routines расходуют подписочные лимиты так же, как обычные интерактивные сессии - отдельного тарифа нет. Сверху накидывается дневной кап на количество запусков routine с аккаунта; текущий остаток видно на странице routines и в настройках usage. Разовые запуски (те, которые на конкретную дату) в этот дневной кап не считаются, но лимиты подписки жрут как все.

Когда упёрся в кап или в лимит подписки - есть развилка. С включёнными usage credits запуски продолжаются на платном оверейдже, без них - отклоняются до сброса окна. На Team и Enterprise кредиты включает админ.

Про claude code лимиты я уже писал отдельно, когда мои скиллы выжирали недельный лимит за четыре дня. Мораль ровно та же: любая автономная штука, которая ходит по расписанию, - это фоновое потребление, которое ты не чувствуешь, пока не откроешь /usage.

Отдельная засада для тех, кто сидит на ключе. Routines требуют логина через claude.ai, и аккаунты Anthropic API не поддерживаются. Если в шелле торчит ANTHROPIC_API_KEY или ANTHROPIC_AUTH_TOKEN, либо в settings.json прописан apiKeyHelper - команда /schedule просто не найдётся, потому что ключ имеет приоритет над логином. Туда же DISABLE_TELEMETRY, DO_NOT_TRACK и CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: они рубят получение фича-флагов, от которого /schedule зависит. Из веба routines при этом создаются всегда.

Когда всё-таки нужен собственный сервер под агентов

Когда у задачи есть состояние, которое живёт между запусками, и оно не в гите. Облачная routine клонирует репозиторий заново на каждый прогон, стартует с дефолтной ветки и доступа к локальным файлам не имеет вообще. Всё, что твой пайплайн накопил на диске, для неё не существует.

У меня это стоп-фактор ровно один, зато железобетонный: папка data/ весит 616 мегабайт. Там SQLite с темами, черновиками, комментами и историей проверок, сгенеренные обложки и бэкапы. Это не артефакт сборки, это и есть сам пайплайн. Плюс .env с токенами бота на сервере и админка на blog.sunm8.ru, которая ходит в ту же базу и умеет жать кнопки руками. Переносить это в модель "склонировали репо, поработали, выкинули" - значит переписать всё хранилище.

Ещё три момента, на которых стоит притормозить:

Минимальный интервал - один час. Если у тебя есть свип, который добирает подвисшие задачи каждые несколько минут, чтобы не копить очередь, - его в routines просто не переложить, придётся менять логику.

Зелёный статус прогона не значит, что задача выполнена. В доках прямым текстом: зелёный - это "сессия стартовала и завершилась без инфраструктурной ошибки". Заблокированные сетевые запросы, отсутствующие тулзы коннектора и провал самой задачи туда не попадают - надо открывать транскрипт. То есть свой слой проверки результата ты всё равно пишешь. У меня это grep -q '^ИТОГ: черновик #' по выводу, и он ловил реальные случаи, когда claude отработал "успешно", но черновик не создал.

Routines привязаны к личному аккаунту. Не шарятся с командой, а всё, что агент делает через твой GitHub и коннекторы, выглядит как сделанное тобой: коммиты и пулл-реквесты под твоим юзером, сообщения в слаке от тебя.

Cloud, Desktop или /loop

Их вообще три, и я про это узнал уже по ходу. Кроме облачных routines есть локальные scheduled tasks в десктопном приложении и /loop внутри сессии. Разница по делу:

Cloud routinesDesktop tasks/loop
Где выполняетсяоблако Anthropicтвоя машинатвоя машина
Нужна включённая машинанетдада
Нужна открытая сессиянетнетда
Доступ к локальным файламнет, свежий клонестьесть
Запросы разрешенийнет, автономнонастраиваютсянаследуются
Минимальный интервал1 час1 минута1 минута

Desktop-таски - это, по сути, окультуренный cron с доступом к локальным файлам. Они стартуют только пока приложение открыто и комп не спит; если машина проспала запуск, при пробуждении будет ровно один догоняющий прогон за последние семь дней, остальное выкидывается. Отдельно уважаю честное предупреждение в доках: задача на 9 утра может отработать в 11 вечера, так что гардрейлы надо писать прямо в промпте.

Что я в итоге сделал

Провёл черту по признаку "нужны ли локальные файлы".

Всё, что живёт в гите и не трогает мою базу, - кандидат в облако. Ревью пулл-реквестов по событию pull_request.opened, еженедельная проверка дрейфа документации, разбор алертов через /fire из мониторинга. Это ровно те кейсы, под которые routines и делали, и там мой bash не даёт вообще ничего, кроме поводов для фиксов. Туда и буду переносить.

На VPS остаётся сам блог-пайплайн: генерация, фактчек, публикация, обложки. Всё, что упирается в 616 мегабайт состояния и админку, ходящую в ту же базу. Это не переносится в модель "склонировали репо, поработали, выкинули" - это переписывается заново, а такой задачи у меня сейчас нет.

Так что нет, парк я не выкинул. Но главное, что дало это разбирательство, - я перестал расширять его по инерции. Раньше новая регулярная задача автоматически означала новую обёртку с флоком, кодами выхода и алертом. Теперь сначала вопрос: а ей вообще нужен мой диск? Если нет - ей нечего делать на моём сервере.

Такие дела.

Частые вопросы

Нужна ли подписка, чтобы клод нейросеть работала по расписанию?

Да. Routines доступны на планах Pro, Max, Team и Enterprise с включённым Claude Code на вебе. Аккаунты Anthropic API не поддерживаются: если в окружении задан ANTHROPIC_API_KEY или ANTHROPIC_AUTH_TOKEN, команда /schedule не сработает, потому что ключ имеет приоритет над логином через claude.ai.

Можно ли запускать routine чаще раза в час?

Нет. У облачных routines минимальный интервал - один час, cron-выражения с большей частотой отклоняются. Если нужно чаще, подойдут локальные scheduled tasks в десктопном приложении или /loop внутри сессии: там минимум одна минута, но требуется включённая машина.

Что будет с routine, если её запуск упал?

Зелёный статус в списке прогонов означает только то, что сессия стартовала и завершилась без инфраструктурной ошибки. Провал самой задачи, заблокированные сетевые запросы и отсутствующие тулзы коннектора туда не попадают - надо открывать транскрипт прогона и читать, что агент на самом деле сделал.