AACWorkflow Docs

Автопилоты

Настройте автоматический запуск агентов по cron-расписанию, входящему вебхуку или вручную через UI или CLI.

Автопилоты позволяют агентам начинать работу автоматически по расписанию — настройте cron-выражение и часовой пояс, и AACWorkflow самостоятельно создаст task, без вашего участия. Это подходит для периодических проверок, повторяющихся отчётов и ночных задач очистки — работа в формате «постоянного поручения». В отличие от трёх других способов запуска (назначение, @-упоминание и чат, где инициатором выступаете вы), главное отличие автопилотов — они управляются временем.

Настройка автопилота

Создайте новый автопилот на странице Автопилот рабочего пространства. Вы задаёте:

  • Название — отображаемое имя
  • Агент — кому направляется запуск
  • Приоритет — наследуется создаваемым task (та же семантика, что у приоритета задач)
  • Описание / промпт — описание работы, которое агент получает при каждом запуске
  • Режим выполнения — см. ниже
  • Триггеры — минимум один schedule (cron + часовой пояс) или webhook

Выбор режима выполнения

У автопилота два режима. Начните с режима «создать задачу».

  • Режим создания задачи (create_issue) — по умолчанию, рекомендуется. Каждый запуск сначала создаёт задачу в рабочем пространстве (заголовок в данный момент поддерживает единственный плейсхолдер: {{date}}, который заменяется на дату UTC в формате YYYY-MM-DD; любые другие токены {{...}} отклоняются при создании, так что опечатка не может незаметно оказаться буквальной строкой в заголовках ваших задач), затем назначает задачу агенту через обычный поток назначения. Вся работа попадает на доску задач с той же историей, комментариями и статусом, что и у задачи, назначенной вручную.
  • Режим «только выполнить» (run_only) — пропускает создание задачи и ставит task в очередь напрямую. Запуск невидим на доске — вы можете увидеть его только в истории запусков автопилота.

Запуск по расписанию

Каждому автопилоту нужен минимум один триггер schedule. Cron использует стандартный 5-польный формат (минута час день месяц день_недели), с минимальной гранулярностью 1 минута (без секунд). Часовой пояс — в формате IANA (например, Asia/Shanghai) и определяет, в каком часовом поясе интерпретируется cron-выражение.

Несколько примеров:

  • 0 9 * * 1-5, Asia/Shanghai — 9:00 по пекинскому времени в будни
  • */30 * * * *, UTC — каждые 30 минут
  • 0 3 * * *, UTC — каждый день в 3:00 UTC

Сервер AACWorkflow проверяет триггеры каждые 30 секундфактическое время запуска может отставать до 30 секунд, а не срабатывать с точностью до секунды. Если сервер перезапускается во время пропущенного срабатывания, он навёрстывает пропущенные триггеры при старте (ничего не теряется, но они срабатывают сразу).

Ручной запуск

Чтобы не ждать cron при отладке автопилота, запустите его вручную:

  • UI: нажмите «Запустить сейчас» на странице автопилота
  • CLI:
aacworkflow autopilot trigger <autopilot-id>

Ручной запуск проходит через тот же поток выполнения, что и триггер schedule — только поле source в записи запуска помечается как manual.

Запуск через вебхук

Автопилоты также могут срабатывать по входящим HTTP-вебхукам. Добавьте триггер Webhook на странице автопилота; AACWorkflow сгенерирует уникальный URL вида:

https://<your-aacworkflow-host>/api/webhooks/autopilots/awt_…

Отправьте POST-запрос с любым JSON на этот URL — AACWorkflow запишет запуск с source = webhook, сохранит тело запроса как trigger_payload этого запуска и отправит агента ровно так же, как это сделал бы триггер по расписанию.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d '{"event":"demo.received","eventPayload":{"message":"hello"}}'

В режиме создания задачи входящая полезная нагрузка добавляется в описание новой задачи, чтобы агент мог прочитать её непосредственно. В режиме «только выполнить» полезная нагрузка является частью контекста запуска, который демон передаёт агенту.

Формат полезной нагрузки

Вы можете отправить собственную обёртку:

{ "event": "github.pull_request.opened", "eventPayload": { } }

…или любой JSON-объект/массив. AACWorkflow нормализует его во внутреннюю обёртку:

{
  "event": "<inferred>",
  "eventPayload": <your body>,
  "request": { "receivedAt": "<rfc3339>", "contentType": "application/json" }
}

Когда вы не передаёте поле event, AACWorkflow определяет его из распространённых заголовков и полей тела (X-GitHub-Event + поле action тела, X-Gitlab-Event, X-Event-Type, поля тела event/type/action). Если ничего не совпало, событием будет webhook.received.

При настройке GitHub или аналогичных источников установите тип содержимого application/json — вебхуки в form-encoded формате не принимаются.

Фильтры событий

Новый вебхук-триггер срабатывает на каждый входящий POST-запрос, что нормально для одноцелевого URL, но создаёт много шума для источников с множеством типов событий (GitHub — очевидный пример: один вебхук репозитория может доставлять push, pull_request, workflow_run, check_suite и другие). Раздел Фильтры событий на триггере вебхука позволяет ограничить, какие события фактически запускают выполнение; всё остальное записывается в историю доставки со статусом status = ignored и reason = event_filtered, и никакой запуск или задача не создаётся.

Каждая строка — это одно правило: имя события и опциональный список действий через запятую. AACWorkflow разрешает вебхук, если любая строка совпадает; оставьте раздел пустым, чтобы принимать всё (поведение до применения фильтра).

Примеры:

Имя событияДействияСовпадение
workflow_runcompleted, failedСобытия workflow_run с action: completed или action: failed только
workflow_run(пусто)Все события workflow_run, независимо от действия
push(пусто)Все события push

Откуда берутся имя события и действие

AACWorkflow определяет имя event и action из входящего запроса в следующем порядке — первое совпадение побеждает.

1. Обёртка тела запроса. Если тело запроса — JSON-объект со строковым полем event, это значение становится именем события напрямую. Затем из необязательного объекта eventPayload извлекаются кандидаты действия из полей action / state / conclusion / status.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{"event":"trigger","eventPayload":{"action":"true"}}'
# inferred: event = trigger, action candidate = true

2. Заголовки. Когда обёртка тела отсутствует, AACWorkflow считывает следующие известные заголовки провайдеров:

  • X-GitHub-Event: <event> — комбинируется с полем action верхнего уровня тела (при его наличии) для формирования github.<event>.<action>.
  • X-Gitlab-Event: <event> — становится gitlab.<event>.
  • X-Event-Type: <event> — передаётся дословно.
# GitHub-style: header gives the event name, body gives the action.
curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'X-GitHub-Event: workflow_run' \
  -H 'Content-Type: application/json' \
  -d '{"action":"completed"}'
# inferred: event = github.workflow_run.completed
#        → matches a filter row of workflow_run / completed

# Generic event-type header — no body fields needed.
curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'X-Event-Type: trigger.true' \
  -H 'Content-Type: application/json' \
  -d '{}'
# inferred: event = trigger.true → matches trigger / true

3. Резервный вариант по телу запроса. Если нет ни обёртки тела, ни известного заголовка, AACWorkflow обращается к строковым полям верхнего уровня тела в следующем порядке: eventtypeaction.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{"type":"trigger","action":"true"}'
# inferred: event = trigger (from `type`), action candidate = true

4. Значение по умолчанию. Если ничто из перечисленного не совпало, событием становится webhook.received и кандидатов действия нет.

Кандидаты действия — полный список. После определения события AACWorkflow рассматривает каждое из следующих значений как возможное совпадение действия:

  • Суффикс имени события, когда событие имеет форму provider.event.<action> (например, github.workflow_run.completedcompleted).
  • Поля тела action, state, conclusion и statusтолько если они являются JSON-строками. Логическое значение ({"action": true}) или число не подходят, поэтому фильтр, ожидающий event=trigger, action=true, никогда не совпадёт с телом {"trigger": true}, потому что true — это bool, а не строка.

Частая ловушка. Строка фильтра вида Event name: trigger / Actions: true не означает «срабатывать, когда в теле есть trigger: true» — фильтры событий сопоставляют определённые события и действия, а не произвольные поля тела. Отправьте trigger.true через X-Event-Type (или используйте обёртку тела, показанную выше), чтобы попасть в фильтр. Окружающие пробелы в сохранённых строках фильтра (" workflow_run ") сохраняются как есть и никогда не совпадут — обрезайте пробелы перед сохранением.

Быстрая проверка

После настройки фильтра вы можете проверить обе ветки с помощью curl:

# Allowed — header drives event=workflow_run, body drives action=completed
curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'X-GitHub-Event: workflow_run' \
  -H 'Content-Type: application/json' \
  -d '{"action":"completed"}'
# → 200 {"status":"accepted", ...}

# Filtered — same event, action not in allowlist
curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'X-GitHub-Event: workflow_run' \
  -H 'Content-Type: application/json' \
  -d '{"action":"in_progress"}'
# → 200 {"status":"ignored","reason":"event_filtered"}

Примеры провайдеров

Вебхук-триггер не зависит от провайдера: он принимает любое JSON-тело, поэтому один и тот же URL подходит для GitHub, трекеров ошибок, событий биллинга, CI/CD, мониторинга доступности и RSS-мостов. В каждом примере ниже показаны входящий payload, строки фильтра событий (оставьте пустыми, чтобы принимать всё) и то, что агент получает в trigger_payload.

GitHub — открыт pull request

GitHub передаёт тип события в заголовке X-GitHub-Event, а подсобытие — в поле action тела, поэтому выведенное событие — github.<event>.<action>.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'X-GitHub-Event: pull_request' \
  -H 'Content-Type: application/json' \
  -d '{"action":"opened","pull_request":{"number":42,"title":"Add billing webhook"}}'
# выведено: event = github.pull_request.opened
Имя событияДействияСрабатывает на
pull_requestopenedтолько новые PR (не правки/закрытия)
check_suitecompletedзавершении CI-прогона на PR

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

Sentry — алерт по ошибке

Вебхуки алертов Sentry не несут заголовка провайдера, поэтому добавьте конверт event (или положитесь на запасной webhook.received). Направьте действие алерта Sentry на URL автопилота.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{
        "event": "sentry.issue_alert",
        "eventPayload": {
          "action": "triggered",
          "data": { "issue": { "title": "TypeError: cannot read x", "culprit": "api/handler.go" } }
        }
      }'
# выведено: event = sentry.issue_alert, кандидат действия = triggered
Имя событияДействияСрабатывает на
sentry.issue_alerttriggeredтолько новые алерты

Агент получает заголовок стек-трейса и culprit в payload — в паре с режимом создания issue баг заводится автоматически.

Stripe / Lago — событие биллинга

Stripe кладёт имя события в поле type тела; Lago использует webhook_type. Для Stripe запасной разбор тела берёт событие из type. Для Lago оберните его в конверт, чтобы имя события было явным.

# Stripe — запасной разбор тела читает `type`
curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{"type":"invoice.payment_failed","data":{"object":{"customer":"cus_123"}}}'
# выведено: event = invoice.payment_failed

# Lago — явный конверт
curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{"event":"lago.invoice.payment_failure","eventPayload":{"status":"failed"}}'
# выведено: event = lago.invoice.payment_failure, кандидат действия = failed
Имя событияДействияСрабатывает на
invoice.payment_failed(пусто)каждый сбой оплаты в Stripe
lago.invoice.payment_failurefailedсбои оплаты в Lago

Деплой упал — CI/CD-пайплайн

Большинство CI-провайдеров могут отправить произвольное JSON-тело при завершении пайплайна. Используйте конверт event + eventPayload.status, чтобы фильтровать успех и неудачу.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{
        "event": "deploy",
        "eventPayload": { "status": "failed", "environment": "production", "commit": "1a2b3c" }
      }'
# выведено: event = deploy, кандидат действия = failed
Имя событияДействияСрабатывает на
deployfailedтолько упавшие деплои (не ok)

Алерт доступности — монитор недоступен

Сервисы мониторинга (UptimeRobot, Better Stack, Pingdom) отправляют небольшое JSON-тело. Добавьте конверт event и фильтруйте по состоянию.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{"event":"uptime","eventPayload":{"status":"down","monitor":"api.example.com"}}'
# выведено: event = uptime, кандидат действия = down
Имя событияДействияСрабатывает на
uptimedownтолько алерты «down»

В паре с режимом только запуска агент расследует проблему, не заводя дублирующий инцидент при каждом мигании.

RSS-монитор — новая запись

Нативной поддержки RSS нет, но крошечная плановая задача (cron, GitHub Action или шаг Zapier/n8n) может опрашивать ленту и отправлять каждую новую запись на URL вебхука.

curl -X POST "$AACWORKFLOW_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{
        "event": "rss.item",
        "eventPayload": { "title": "v2.0 released", "link": "https://example.com/blog/v2", "published": "2026-06-20T09:00:00Z" }
      }'
# выведено: event = rss.item
Имя событияДействияСрабатывает на
rss.item(пусто)каждую опубликованную запись

Используйте режим создания issue, чтобы превращать каждую запись ленты в отслеживаемую issue.

URL является bearer-секретом

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

  • Не вставляйте его в публичные обсуждения задач, скриншоты или историю чата.
  • Смените URL при утечке — нажмите «Сменить URL» в строке триггера или выполните aacworkflow autopilot trigger-rotate-url <autopilot-id> <trigger-id>. Старый URL перестаёт работать немедленно.
  • Для источников, требующих строгой аутентификации, ожидайте проверку HMAC-подписи для каждого триггера; эта v1 URL использует только bearer-аутентификацию.
  • Участники рабочего пространства, которые могут просматривать автопилот, пока что могут читать его вебхук-URL — более строгая видимость секретов по ролям появится позднее.

Семантика кодов состояния

AACWorkflow возвращает 200 OK с полем status для обычных сценариев без ошибок, чтобы механизм повторных попыток вашего провайдера не продолжал долбить URL:

  • {"status":"accepted","run_id":"…","autopilot_id":"…","trigger_id":"…"} — запуск отправлен.
  • {"status":"skipped","run_id":"…","reason":"agent runtime is offline at dispatch time"} — среда выполнения назначенного агента отключена; записано как запуск со статусом skipped.
  • {"status":"ignored","reason":"trigger_disabled"} — триггер отключён.
  • {"status":"ignored","reason":"autopilot_paused"} — автопилот приостановлен.
  • {"status":"ignored","reason":"autopilot_archived"} — автопилот архивирован.

Ответы не 2xx охватывают реальные ошибки:

  • 400 — неверный JSON, скалярное тело или пустое тело.
  • 404 — неизвестный токен ({"error":"webhook not found"}).
  • 413 — полезная нагрузка превышает 256 КБ.
  • 429 — превышение лимита запросов для токена (по умолчанию 60 запр/мин).

Откуда берётся webhook URL

В AACWorkflow Cloud ответ триггера всегда включает абсолютный webhook_url (построенный на основе https://aacworkflow.com), а UI показывает URL, готовый к копированию. AACWorkflow намеренно не выводит публичный хост из заголовков Host / X-Forwarded-Host, поэтому подделанный запрос не сможет обманом заставить сервер создать вебхук-URL, указывающий на хост, контролируемый злоумышленником.

Просмотр истории запусков

Каждый триггер создаёт запись запуска, видимую на вкладке «История» на странице автопилота:

  • Источник триггера (schedule / manual / webhook)
  • Время начала, время завершения
  • Статус (issue_created / running / completed / failed / skipped)
  • Связанная задача (режим создания задачи) или task (режим «только выполнить»)
  • Причина сбоя (если failed или skipped)

Что происходит при сбое автопилота

Сбои автопилотов не повторяются автоматически и не отправляют уведомления в папку «Входящие». При сбое в истории запусков остаётся запись со статусом failed — нет системного повторного помещения в очередь, как при назначении или @-упоминании, и никаких уведомлений. Если автопилот периодический, следующий cron-запуск вызовет новое выполнение, но работа, завершившаяся сбоем, автоматически не перезапускается.

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

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

Что пока недоступно

Триггеры типа API не подключены. Схема триггеров резервирует тип api, но ни один входящий маршрут его не запускает; UI показывает значок «Устарело» для существующих строк и не предлагает возможностей копирования/смены. Проверка HMAC-подписи для каждого триггера, списки разрешённых IP и предустановки событий для конкретных провайдеров запланированы на будущее; v1 URL работают только с bearer-аутентификацией.

Далее