Перейти до основного вмісту
Знижка 50% усі плани, обмежений час. Від $2.48/mo
15 min left
AI та машинне навчання

Як запланувати нічний запуск ШІ-агентів на 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
AI та машинне навчання

Як насправді рахують оцінки «ризику втрати роботи через ШІ»

Оцінки ризику для професій через ШІ будуються за різними методиками, від теоретичної вразливості до спостережуваного використання, і жодна не передбачає втрату роботи напряму. Розб

Bruce 10 хв читання
Провідні компанії ШІ-чипів: відеокарта, модуль прискорювача, кремнієва пластина та серверні плати на темно-червоному тлі
AI та машинне навчання

Провідні компанії та виробники ШІ-чипів: альтернативи NVIDIA, які справді постачаються

Провідні компанії ШІ-чипів у порівнянні за реальним доступом: дивіться, які прискорювачі у 2026 році можна орендувати, купити, використати через API або отримати лише через корпора

Jeremy 16 хв читання

Готові розгортати? Від $2,48/міс.

Незалежна хмара з 2008 року. AMD EPYC, NVMe, 40 Gbps. Повернення коштів за 14 днів.