Перейти к основному содержанию
Скидка 50% все планы, ограниченное время. Начиная от $2.48/mo
15 min left
ИИ и машинное обучение

Как запускать ИИ-агентов по расписанию ночью на VPS

S Автор: Sajjad 15 мин чтения
Schedule AI Agents Overnight: a dark terminal showing a 02:00 timestamp and a green exit code 0 line, next to a clock and a completed job card

В 2 часа ночи на VPS, который никогда не засыпал, срабатывает запланированная задача. Headless-запуск claude -p обрабатывает задачу из очереди в клонированном репозитории, ни у кого ничего не спрашивая, и завершается. Утром вас ждёт коммит, отчёт или лог, показывающий, где именно всё остановилось и почему. Никто за этим не наблюдал.

Это совсем не то же самое, что оставить терминал открытым на всю ночь и надеяться, что SSH-соединение выживет. Частая точка отказа при ночном запуске агента — сам хост: ноутбук уходит в сон, крышка закрывается, сеть отваливается или обновление ОС перезагружает машину посреди задачи. Сбои аутентификации, ошибки API и зависания на запросах разрешений всё ещё могут убить задачу, но всегда включённый хост убирает самый простой сценарий отказа.

Это руководство описывает сам механизм: headless-флаги, которые есть у каждой крупной CLI агента для кода, два способа запустить задачу по расписанию и какой из них выбрать, что нужно хосту под ней, и те ограничители, которые не дают запуску без присмотра стоить или сломать больше, чем вы захотите потом объяснять.

Кратко

  • Каждая крупная CLI агента для кода имеет документированный неинтерактивный режим, который выполняет один запрос до конца и завершается. У Claude Code это claude -p, у Codex CLI — codex exec, а у Gemini CLI — gemini -p. Это не обходной путь, а штатная возможность.
  • У Claude Code есть и собственное планирование: Routines, запланированные задачи Desktop и /loop. Некоторым читателям этого действительно достаточно, и поддерживать это проще, чем VPS.
  • Cron прекрасно подходит для ночной задачи. Таймер systemd лучше подходит по умолчанию на машине, которая может перезагрузиться, потому что Persistent=true подхватывает запуск, который cron просто молча пропустил бы.
  • Сама CLI лёгкая, потому что вывод модели выполняется на API провайдера. Подбирайте VPS под команды, которые он будет запускать (тесты, сборки, контейнеры, параллельные задачи), а не под модель.
  • Безопасно оставить расписание без присмотра позволяют именно ограничители: суженный набор инструментов, лимит ходов, ветвление по коду выхода. Само расписание механизмом безопасности не является.

Что вам понадобится

Подготовьте эти пять вещей до того, как напишете первую строку crontab или файл юнита:

  • VPS с доступом по SSH и дистрибутивом Linux на базе systemd.
  • Установленная на этом VPS CLI агента: Claude Code, Codex CLI или Gemini CLI.
  • Неинтерактивные учётные данные для выбранной CLI. Режим bare в Claude Code не читает вход в аккаунт, поэтому ему нужен ANTHROPIC_API_KEY в переменных окружения или apiKeyHelper в его настройках. Обычный запуск в print-режиме, Codex и Gemini могут также использовать документированные учётные данные аккаунта.
  • Репозиторий или рабочий каталог, с которым будет работать агент.
  • Доступ к shell с правами править crontab или создавать unit-файл systemd.

Запуск агента без прикреплённой сессии

Сравнение headless-режимов: Claude Code запускает claude -p с выводом text, json или stream-json, Codex CLI запускает codex exec с потоком JSONL и политикой песочницы, а Gemini CLI запускает gemini -p без TTY

Каждая крупная CLI агента для кода имеет неинтерактивный режим, созданный ровно для этого. Claude Code принимает -p, он же --print. Codex CLI принимает codex exec. Gemini CLI принимает -p, он же --prompt. Каждый принимает запрос, выполняет его до конца и завершается. Никакого чат-цикла, никакого терминала, который надо держать открытым, и ничего, к чему нужно переподключаться.

Может ли Claude Code работать без активной сессии? Да. Передача -p запускает запрос в неинтерактивном режиме: Claude Code выполняет его до конца, печатает результат и завершается. Нет ни чат-цикла, ни чего-либо, что нужно поддерживать, и работает это на том же Agent SDK, что и интерактивная CLI, согласно собственная документация Anthropic по headless-режиму.

CLIНеинтерактивный флагПоведениеСтруктурированный вывод
Claude Code-p / --printВыполняет запрос до конца, печатает результат, завершается--output-format со значением text, json или stream-json
Codex CLIcodex execТранслирует прогресс в stderr, пишет финальное сообщение в stdout, завершается--json для потока событий JSONL
Gemini CLI-p / --promptВыполняет запрос неинтерактивно, завершается--output-format json

Здесь важнее всего собственные флаги Claude Code, потому что именно под них вы и будете писать скрипты. Два из них позволяют запуску идти дальше, не останавливаясь на запрос разрешения, которое некому выдать посреди ночи: --allowedTools, который заранее разрешает конкретные инструменты, и --permission-mode, который задаёт базовый уровень для всего запуска. --max-turns ограничивает число агентных ходов, которые может сделать запуск, прежде чем завершиться с ошибкой.

--bare пропускает хуки, skills, плагины, MCP-серверы и проектные инструкции вроде CLAUDE.md, ради более быстрого и предсказуемого запуска из скрипта. Это значит и то, что каждая инструкция, от которой зависит задача, должна быть в самом запросе или команде. Режим bare также не читает вход в ваш аккаунт, поэтому документация Anthropic советует задать ключ API в переменных окружения перед запуском. Claude Code отклоняет --bg напрямую, если он скомбинирован с -p, и отклоняет --cloud точно так же, если передать ему описание задачи. Он называет конфликт и останавливается, вместо того чтобы сделать что-то неоднозначное.

Готовый пример вызова, адаптируйте запрос и список инструментов под свою задачу:

claude --bare -p "Review open PRs in this repo and summarize any blockers in NOTES.md" \
  --allowedTools "Bash(gh pr list *),Bash(gh pr view *),Bash(gh pr diff *),Read,Edit" \
  --permission-mode dontAsk \
  --max-turns 8 \
  --max-budget-usd 5.00 \
  --output-format json

Подгоните бюджет и шаблоны команд под задачу; в этом примере также предполагается, что аутентификация GitHub CLI уже настроена для запускающей учётной записи.

Если вы настраиваете Claude Code на новом VPS и хотите пошаговую инструкцию по аутентификации на машине без браузера, это разобрано отдельно в как аутентифицировать Claude Code на headless-сервере; краткой версии выше достаточно, чтобы запланированный запуск заработал.

Режим exec в Codex CLI, описанный в документация OpenAI по неинтерактивному режиму, принимает --sandbox для выбора политики. read-only используется по умолчанию, workspace-write разрешает агенту писать внутри своего рабочего каталога, а --json превращает stdout в машиночитаемый поток событий вместо простого текста. Избегайте danger-full-access в задаче без присмотра, если только процесс не изолирован и этот риск не принят осознанно.

Headless-режим Gemini CLI, описанный в собственная headless-документация проекта, включается автоматически в окружении без TTY или явно через -p. Он завершается конкретным ненулевым кодом для общей ошибки, ошибки ввода или достижения лимита ходов, а не одним универсальным кодом сбоя.

Где должно жить расписание

До всей этой настройки: возможно, поставщик агента уже умеет планировать это за вас. У Claude Code есть три встроенных варианта, и один из них действительно может подойти лучше, чем самостоятельно управляемый VPS.

Облако (Routines)Запланированная задача Desktop/loop
Где выполняетсяОблако AnthropicВаша машинаВаша машина
Машина должна быть включенаНе требуетсяОбязательноОбязательно
Нужна открытая сессияНе требуетсяНе требуетсяОбязательно
Минимальный интервал1 час1 минута1 минута
Доступ к локальным файламНет, запускается из свежего клонаПолный доступПолный доступ

Собственная документация Anthropic по запланированным задачам подаёт это как настоящий выбор из трёх вариантов, а не как иерархию с VPS на вершине. Если вашей задаче не нужно локальное состояние, её устраивает минимум в час и вы пользуетесь только Claude Code, Routines требует меньше обслуживания, чем всё описанное ниже: Anthropic запускает его в облаке из свежего клона, пока ваша машина выключена.

/loop стоит знать, но для этого сценария он не подходит, потому что требует открытой простаивающей сессии, а это как раз то ограничение, от которого вы пытаетесь избавиться. Та же документация упоминает и GitHub Actions как четвёртый вариант, для команд, чей триггер уже живёт в CI, а не в расписании, привязанном к одной конкретной машине.

Самостоятельно управляемый VPS оправдывает себя, когда задаче нужен полный доступ к локальной файловой системе и инструментам, когда вы хотите, чтобы один и тот же механизм одинаково работал в Claude Code, Codex CLI и Gemini CLI, или когда допустимый интервал Routines слишком грубый. Обычная serverless-функция здесь обычно неудобна, потому что ей приходится восстанавливать учётные данные, клонировать репозиторий и уложиться в лимиты времени выполнения платформы. Эфемерный CI-раннер вроде GitHub Actions остаётся полноценным третьим путём, если свежий checkout на каждый запуск вас устраивает. Если у вас уже есть простаивающее всегда включённое железо, домашняя лаборатория тоже подойдёт; платой будет надёжность домашней сети и удалённого доступа вместо провайдерской.

Cron или таймер systemd?

Cron против таймера systemd: слева одна строка crontab и пропущенный запуск, который просто теряется; справа пара .service и .timer с наверстыванием через Persistent=true, логированием в journald и контролем пересечений через единственный экземпляр

Оба инструмента могут запускать одну и ту же команду по одному и тому же расписанию, но расходятся в том, что происходит при перезагрузке машины и сколько стоит настройка каждого:

cronтаймер systemd
Объём настройкиОдна строка crontabФайл .timer и файл .service
Наверстывание пропущенных запусковНет, пропущенный запуск просто теряетсяPersistent=true запускает его сразу, как только система снова поднялась
ЛогированиеВручную, вы сами перенаправляете выводАвтоматически, всё пишет journald
Порядок зависимостейНичегоПолный порядок systemd через After= и Requires=

Обычного cron вполне достаточно для ночной задачи на машине, которая редко перезагружается. Подвох в окружении: cron стартует с минимальным PATH, не заходит в ваш репозиторий за вас и охотно запустит вторую копию, пока первая ещё работает. Вынесите путь к репозиторию, суженную команду агента и загрузку учётных данных в защищённый скрипт-обёртку, а затем используйте flock , чтобы не допустить пересекающихся запусков.

# /usr/local/bin/agent-nightly
#!/usr/bin/env bash
set -euo pipefail
export PATH=/usr/local/bin:/usr/bin:/bin
export ANTHROPIC_API_KEY="$(
  cat "$HOME/.config/agent-nightly/anthropic_api_key"
)"
cd /srv/myrepo
exec /usr/local/bin/claude --bare -p \
  "Run the nightly dependency audit and write the findings to NOTES.md" \
  --allowedTools "Bash(npm audit *),Read,Edit" \
  --permission-mode dontAsk \
  --max-turns 8 \
  --max-budget-usd 5.00 \
  --output-format json
# crontab -e
0 2 * * * /usr/bin/flock -n "$HOME/.local/state/agent-runs/nightly.lock" /usr/local/bin/agent-nightly >> "$HOME/.local/state/agent-runs/nightly.log" 2>&1

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

install -d -m 700 \
  "$HOME/.config/agent-nightly" \
  "$HOME/.local/state/agent-runs"
touch "$HOME/.config/agent-nightly/anthropic_api_key"
chmod 600 "$HOME/.config/agent-nightly/anthropic_api_key"
"${EDITOR:-nano}" \
  "$HOME/.config/agent-nightly/anthropic_api_key"
sudo chmod 755 /usr/local/bin/agent-nightly

Вставьте в файл учётных данных только ключ API. Не пишите его прямо в crontab.

Таймер systemd требует больше настройки и даёт две вещи, которых нет у cron: логирование через journald без самодельных перенаправлений и Persistent=true. В примере ниже предполагается, что выделенная учётная запись agent-runner владеет каталогом /srv/myrepo. Храните ключ API в файле, доступном только root, вместо того чтобы вшивать его в юнит.

По данным руководство systemd.timer, установка Persistent=true означает, что «сервисный юнит запускается немедленно, если он должен был бы запуститься хотя бы раз за то время, пока таймер был неактивен». Так что запуск, который случился бы, пока ваш VPS перезагружался ради обновления ядра, стартует сразу после возвращения, а не исчезает молча до следующего слота.

Создайте доступный только root файл учётных данных, который использует сервис:

sudo install -d -m 700 /etc/agent-nightly
sudo touch /etc/agent-nightly/anthropic_api_key
sudo chmod 600 /etc/agent-nightly/anthropic_api_key
sudoedit /etc/agent-nightly/anthropic_api_key

Вставьте в файл только ключ API.

# /etc/systemd/system/agent-nightly.service
[Unit]
Description=Nightly scoped agent run
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=agent-runner
Group=agent-runner
WorkingDirectory=/srv/myrepo
Environment=HOME=/home/agent-runner
Environment=PATH=/usr/local/bin:/usr/bin:/bin
LoadCredential=anthropic_api_key:/etc/agent-nightly/anthropic_api_key
ExecStart=/bin/sh -c 'export ANTHROPIC_API_KEY="$(cat "$CREDENTIALS_DIRECTORY/anthropic_api_key")"; exec /usr/local/bin/claude --bare -p "Run the nightly dependency audit and write the findings to NOTES.md" --allowedTools "Bash(npm audit *),Read,Edit" --permission-mode dontAsk --max-turns 8 --max-budget-usd 5.00 --output-format json'
StandardOutput=journal
StandardError=journal
UMask=0077
# /etc/systemd/system/agent-nightly.timer
[Unit]
Description=Run agent-nightly.service at 2am daily, catching up missed runs

[Timer]
# Uses the VPS's configured local timezone
OnCalendar=*-*-* 02:00:00
Persistent=true
Unit=agent-nightly.service

[Install]
WantedBy=timers.target

Перезагрузите конфигурацию systemd, включите таймер и один раз сразу запустите сервис, чтобы проблемы с учётными данными, правами и путями всплыли сейчас, а не в 2 часа ночи:

sudo systemctl daemon-reload
sudo systemctl enable --now agent-nightly.timer
sudo systemctl start agent-nightly.service
systemctl list-timers agent-nightly.timer
sudo journalctl \
  -u agent-nightly.service \
  -n 100 \
  --no-pager

Persistent=true — решающее отличие: таймер помнит о пропущенном календарном запуске, а не отбрасывает его молча.

Что на самом деле нужно VPS

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

Возьмите 1–2 vCPU и 2–4 ГБ ОЗУ с NVMe-накопителем как отправную точку для одной лёгкой запланированной задачи. Большие репозитории, компиляторы, сборки Docker, наборы тестов или параллельные запуски могут потребовать намного больше. Наращивать ресурсы заставляет самая тяжёлая локальная команда, которую запустит агент, а не модель за API. Если вы уже гоняете Docker-нагрузки на этом VPS и хотите более полную картину бюджета, подбор ресурсов и защита сборочной машины разбирает тот же компромисс для другой рабочей нагрузки без присмотра.

Ещё одно, что стоит предусмотреть: запуск без присмотра каждую ночь производит логи, независимо от того, случилось что-то или нет. Добавьте logrotate , если cron пишет в файл, и проверьте лимиты хранения journald, вместо того чтобы считать, что его настройки по умолчанию подходят диску VPS.

Весь подход держится на хосте, который бодрствует в 2 часа ночи и продолжает работать независимо от того, что делает ваш ноутбук. Это ровно та задача, для которой создан Linux VPS с root-доступом. Ничто его не усыпляет, и вы не делите его с чужими cron-задачами.

Посмотреть тарифы Linux

Разрабатывайте на Linux VPS с root-доступом, NVMe и мощью AMD EPYC.

Посмотреть тарифы Linux

Как не дать запуску без присмотра пойти не так

Главное различие между работающим запуском по расписанию и неработающим — достаточно ли узко очерчена задача, чтобы завершиться без человека, отвечающего на вопрос посреди работы. Амбициозные запросы застревают в ожидании решения, которое некому принять; узкие, самодостаточные задачи завершаются и чисто выходят.

Два флага разрешений существуют, чтобы запуск не завис на запросе в 2 часа ночи, но голый доступ к Bash не является узким ограничителем: он может почти всё, что может сервисная учётная запись. Предпочитайте правила под конкретные команды, например Bash(git status *), сочетайте их с --permission-mode dontAsk и запускайте сервис под отдельной непривилегированной учётной записью. У числа ходов и у расходов есть свои собственные потолки: --max-turns ограничивает, сколько агент может блуждать, а --max-budget-usd ограничивает, сколько один запуск может потратить на вызовы API.

Совет: запускайте с --output-format json и записывайте поле total_cost_usd каждого вызова. Это самый чистый способ отслеживать, во сколько на самом деле обходится запуск за ночь, и получать оповещение, когда один запуск стоит заметно больше остальных. Пять минут на настройку того стоят: отслеживается ваш счёт, а не абстракция.

Перерасход в задачах без присмотра — не гипотетическая угроза. В одном посте на Hacker News, пользователь сообщил о валовом счёте AWS Bedrock на 37 901,73 доллара из-за ежедневного рабочего процесса с агентом для кода, где кеширование запросов работало лишь частично и около 6,47 миллиарда входных токенов остались без кеша. Это случилось в другом стеке, а не в headless-режиме Claude Code, но показывает, почему логирование расходов и жёсткий бюджет на запуск должны быть частью расписания.

Совет: Claude Code завершается с кодом 0 при успехе и ненулевым кодом при сбое. Скрипт-обёртка, проверяющий код выхода, может отправлять вам уведомление при неудаче, так что плохая ночь всплывёт наутро, а не через три дня, когда вы случайно заглянете в логи.

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

Безопасно оставить расписание в покое позволяют именно ограничители: само расписание механизмом безопасности не является.

Когда cron перестаёт хватать

Одному запросу по таймеру не нужно ничего сверх описанного здесь. Три связанных шага с условием, повтором и уведомлением в Slack — это уже другое дело.

Стоит знать три варианта, каждый из которых поднимает планку по-своему:

  • Dagu — самый лёгкий шаг вверх: самодостаточные задачи, описанные в YAML, с DAG-зависимостями, повторами и веб-интерфейсом, где видно, что отработало.
  • n8n лучше всего подходит, когда запуск агента — лишь один узел среди нескольких интеграций и уведомлений, а не весь рабочий процесс.
  • Kestra — самый тяжёлый из трёх, создан для оркестрации конвейеров данных и инфраструктуры, и он верный ответ, когда запуск агента по расписанию — часть большего конвейера, а не его цель.

Для читателя, который запускает один ночной запрос, все три избыточны, и это стоит сказать прямо, а не уговаривать вас на более тяжёлую конструкцию, чем нужно. Если цепочка шагов всё же однажды оправдает один из них, Dagu, n8n, и Kestra разворачиваются в один клик, и это реальное удобство ровно в тот момент, когда вы решаете, стоит ли овчинка выделки.

Фреймворки мультиагентной оркестрации вроде LangChain или CrewAI — это совсем другая тема: построение агентных систем, а не запуск по расписанию уже существующей CLI.

Часто задаваемые вопросы

Может ли Claude Code работать без активной сессии?

Да. Передача -p запускает запрос в неинтерактивном режиме: Claude Code выполняет его до конца, печатает результат и завершается, без чат-цикла и без сессии, которую надо держать открытой.

Нужен ли VPS, если у Claude Code уже есть Routines?

Не всегда. Routines работает в облаке Anthropic при выключенной машине и стартует со свежего клона, но не может обратиться к файлам, которые есть только у вас на машине, и имеет минимальный интервал в один час. Самостоятельно управляемый VPS оправдан, когда задаче нужны локальные файлы, произвольные интервалы или механизм, одинаково работающий с CLI нескольких вендоров.

Что использовать для агента по расписанию: cron или таймер systemd?

Таймер systemd, если VPS хоть иногда перезагружается на обслуживание. Persistent=true запускает задачу, которая должна была сработать во время простоя, сразу после возвращения системы, а у cron ничего подобного нет. Для ночной задачи на машине, которая не выключается, cron вполне подходит.

Сколько оперативной памяти нужно ИИ-агенту по расписанию на VPS?

Начните с 1–2 vCPU и 2–4 ГБ ОЗУ для одной лёгкой запланированной задачи, а дальше подбирайте под самую тяжёлую локальную команду, которую запустит агент. Сборки, тесты, Docker, крупные репозитории и параллельные запуски значат куда больше, чем удалённый инференс модели.

Меняется ли тарификация, если запускать агента по расписанию?

Планирование не создаёт отдельного режима тарификации. Claude Code -p может использовать данные подписки или ключ API, но --bare игнорирует вход по подписке, поэтому ему нужен ANTHROPIC_API_KEY в переменных окружения или apiKeyHelper в его настройках. Codex и Gemini используют тот метод аутентификации, который вы настроили для их CLI. Поскольку цены и условия использования быстро меняются, при настройке сверяйтесь с текущими тарифами провайдера и собственными данными об использовании. Для запусков Claude Code через API можно также записывать поле total_cost_usd из вывода в формате JSON.

Поделиться

Обсуждение

Комментарии

Войдите, чтобы присоединиться к обсуждению.

Ещё в блоге

Читайте дальше.

Illustration for how AI job risk scores are calculated: a desk computer linked to a gauge of work-task icons and to a timeline of the same tasks
ИИ и машинное обучение

Как на самом деле считают оценки «риска потери работы из-за ИИ»

Оценки риска для профессий из-за ИИ строятся по разным методикам, от теоретической подверженности до наблюдаемого использования, и ни одна напрямую не предсказывает потерю работы.

Bruce 10 мин чтения
Ведущие компании ИИ-чипов: видеокарта, модуль ускорителя, кремниевая пластина и серверные платы на тёмно-красном фоне
ИИ и машинное обучение

Ведущие компании и производители ИИ-чипов: альтернативы NVIDIA, которые реально поставляются

Ведущие компании ИИ-чипов в сравнении по реальному доступу: смотрите, какие ускорители можно арендовать, купить, использовать через API или получить только через корпоративные прод

Jeremy 16 мин чтения

Готовы к развёртыванию? От $2,48/мес.

Независимое облако с 2008 года. AMD EPYC, NVMe, 40 Gbps. Возврат денег в течение 14 дней.