К содержимому
ErgonLab
← Блог
Гайд · Автоматизация
· 7 мин

/loop dynamic — событийная автоматизация в одном окне

Паттерн, который превращает Claude Code в фонового исполнителя, реагирующего на события. ScheduleWakeup, Monitor, минимальные интервалы — без лишнего опроса.

Зачем нужен loop

Обычная сессия с Claude — это разговор: я пишу, он отвечает, цикл закрылся. Если задача требует ожидания — посмотреть статус CI через 5 минут, отследить новое сообщение в чате, дождаться завершения деплоя — обычная сессия не помогает. Я либо сижу и переспрашиваю руками, либо забываю и возвращаюсь через час.

/loop решает это. После того как Claude выполнил итерацию работы, он не закрывается, а засыпает. Через заданный интервал — или по сигналу — просыпается, делает следующую итерацию, опять засыпает. И так пока я не скажу «стоп».

Это не «фоновый процесс» в классическом смысле — это тот же чат, в том же окне, с тем же контекстом. Просто между итерациями harness держит сессию замороженной и оживляет её по триггеру.

Чем отличается от обычных режимов

Сравню три способа делать «длительную работу» в Claude Code.

Обычная задача:

  • Один промт → один ответ → конец.
  • Контекст уходит при закрытии окна.
  • Подходит для: «напиши функцию», «отрефакторь файл», «объясни концепт».

Background agent:

  • Запускается отдельно, в своём контексте.
  • Делает большую задачу автономно и возвращает результат.
  • Я в это время работаю в основном окне.
  • Подходит для: «исследуй такую тему», «прогони эти тесты».
  • Минус: не возвращается к разговору. Результат — один.

/loop dynamic:

  • Остаётся в моём окне.
  • Между итерациями засыпает.
  • На каждом цикле может прочитать что-то новое (файл, чат, лог) и среагировать.
  • Я могу в любой момент вмешаться: написать «стоп», задать вопрос, поменять задачу.
  • Подходит для: live-сессий, мониторинга, polling-задач.

/loop нужен именно тогда, когда работа разнесена во времени и каждая итерация может зависеть от события, которое ещё не случилось.

Два способа просыпаться

ScheduleWakeup — заснул на N секунд

Самый простой вариант. Claude в конце итерации говорит harness'у: «разбуди меня через 60 секунд». Через минуту просыпается, делает следующий цикл.

Подходит, когда нет внешнего сигнала, но нужно периодически что-то проверять:

  • Каждые 5 минут смотреть статус CI на GitHub
  • Каждые 30 минут проверять, не пришёл ли новый коммит в ветку
  • Раз в час пересобирать дашборд

Минус: даже если ничего не меняется, цикл всё равно срабатывает — это polling. На больших интервалах ок, на маленьких — лишний нагрев.

Monitor — реагирую на событие

Альтернатива polling'у. Я запускаю фоновый процесс (например, tail -f на лог, или какой-то демон), и Monitor следит за его stdout. Каждая строка в stdout будит Claude.

Это event-driven подход: пока процесс молчит — Claude спит, ничего не тратит. Появилась строка — мгновенно проснулся и среагировал.

Подходит, когда есть источник событий, который сам шлёт сигналы:

  • Telegram-демон, который пишет в лог каждое новое сообщение
  • CI, который шлёт webhook → файл
  • Любой tail -f на «событийный» лог

В live-сессии Ланы (см. отдельную статью про Live Session) у меня именно этот паттерн: демон brain_poll.py стучит в stdout, как только в чате клиента что-то происходит, и Claude мгновенно формулирует ответ.

Как выбирать интервал

Это важно, и не очевидно. У Claude Code есть кэширование промтов: повторные запросы с тем же системным промтом дешевле в разы (cache hit). Если интервал между итерациями короткий, кэш ещё тёплый — итерация дешёвая. Если длинный, кэш истёк — итерация дорогая.

Правила, которыми я живу:

  • Меньше 5 минут — окей, кэш почти всегда тёплый. Можно гонять часто без дорогих счетов.
  • 5-60 минут — cache miss оправдан, если задача не очень частая. Норм для polling раз в полчаса.
  • Около 5 минут ровноизбегаю. Это серая зона, где кэш может быть и тёплым, и холодным, и счёт получается непредсказуемый. Лучше уйти либо ниже (например, 3 минуты), либо выше (10).
  • Больше часа — практически всегда новый prompt. Используй только если событие очень редкое.

Если задача event-driven (реальный сигнал, не polling) — лучше Monitor, а не ScheduleWakeup. Тогда вопрос интервала вообще не стоит: спишь, пока ничего не происходит.

Реальный пример: Лана в чате с клиентом

Я веду Live Session с несколькими клиентами параллельно. У каждого свой инстанс, свой чат, своя карточка. Архитектура одна и та же, и каждая сессия держится на /loop dynamic.

Что внутри одной итерации:

  1. Просыпаюсь (по сигналу от brain_poll.py — Monitor видит новую строку).
  2. Читаю новые сообщения из inbox (tg_read.py --client <name> --auto).
  3. Смотрю карточку клиента в clients/<client>.md.
  4. Решаю: отвечать самой или эскалировать (цены, сроки, формат → к Николаю).
  5. Если отвечать — формирую короткие сообщения, кладу в outbox JSON.
  6. Если эскалировать — пишу в моё личное окно «вот что клиент написал, я думаю ответить так — отправляем?».
  7. Обновляю карточку клиента, если узнала новый факт.
  8. Засыпаю до следующего сигнала.

Это работает 24/7 (для домашнего чата) и 8-22 (для клиентских) уже месяц. Между итерациями Claude не существует — нет фонового процесса с нагрузкой. Просто проснулся → сделал → заснул.

Стоп-условия:

  • В чате появляется слово «Николай» или «лично» — выхожу из цикла, жду меня.
  • Я в личном окне пишу «остановись» — фиксирую контекст в LIVE_IDEAS.md, шлю прощальное «выхожу, контекст сохранён», и /loop закрывается.

Похожий паттерн в других проектах

То же самое работает в Бюро Тезис (другой мой проект) — в группе с партнёром Сергеем. Тот же /loop, та же связка tg_read.py → решение → tg_send.py, только chat_id и промты другие. Доказательство, что паттерн не вшит в Лану — он переиспользуется.

В HealthCompanion (трекинг здоровья через бота) тот же /loop потенциально можно использовать для напоминаний по KBJU. Пока не сделал, но архитектура такая же: polling с интервалом 1-3 часа или event-driven через лог бота.

В Evolventa (платформа управления ремонтом) /loop не нужен — там обычные REST endpoints и UI. Это к вопросу «когда не нужен loop» — об этом ниже.

Когда не нужен /loop

Три анти-сценария:

1. Batch-задача

«Прогони все 30 файлов через рефакторинг» — это не loop, это обычная итеративная задача, которую Claude сделает за один проход. Loop там лишний.

2. Однократный вопрос

«Объясни мне как работает gRPC» — нет события, на которое реагировать. Это обычный чат.

3. Можно делегировать в background agent

Если задача автономная и не требует моих вмешательств — лучше отправить её в subagent (например, web-researcher или quality-guardian). Background agent работает в своём контексте, не засоряя мой, и возвращает сжатый результат. Loop остаётся в моём контексте, и каждая итерация съедает токены здесь.

Правило: если в задаче нет ожидания событий и нет периодичности — это не loop.

Что сделать прямо сейчас

  1. Поймай задачу, в которой ты сам периодически проверяешь что-то руками. Деплой, CI, чат, статус процесса. Это кандидат на /loop.
  2. Реши: polling это (ScheduleWakeup на 1-5 минут) или event-driven (Monitor на лог фонового процесса). Event-driven всегда лучше, если есть источник событий.
  3. Запусти /loop с короткой инструкцией: что читать, как реагировать, на каком слове выходить.
  4. Не забудь стоп-слово. Live-сессия без стоп-слова — это runaway-процесс.

/loop dynamic — это не «фича для разработчиков ботов». Это базовый паттерн для любой задачи, где «между итерациями нужно подождать». В моих проектах он закрыл 4-5 разных классов работ — от ведения чатов с клиентами до мониторинга деплоев. И в каждом случае это одно окно Claude, в котором я могу вмешаться в любой момент.

Соседние посты

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

← Предыдущий
Skills vs Agents vs Hooks — что когда выбирать
Следующий →
Hooks — когда автоматизировать поведение AI
Все материалы
Принимаю заказы

Понравилось?
Обсудим задачу?

Напишите коротко — ответим в течение дня.

Написать в Telegram
@ergonlab_bot