Multica Docs

Autopilots

Agent начинают работу по cron, inbound webhook или однократно вручную через UI или CLI.

Autopilot позволяют agent начинать работу автоматически по расписанию — настройте cron expression и timezone, Multica dispatch task сам, без вашего trigger. Подходит периодическим проверкам, recurring reports и overnight cleanup — форма «standing order». По сравнению с тремя другими path (assign, @-mention, chat, где kick-off делаете вы), у Autopilot core difference — time-driven.

Настройка autopilot

Создайте autopilot на странице Autopilot workspace. Задаёте:

  • Name — display name
  • Agent — кому dispatch run
  • Priority — наследуется task (та же семантика, что priority issue)
  • Description / prompt — описание работы agent на каждый run
  • Execution mode — см. ниже
  • Triggers — минимум один schedule (cron + timezone) или webhook

Выбор execution mode

У autopilot два execution mode. Начните с mode «create issue».

  • Create issue mode (create_issue) — default, recommended. Каждый trigger сначала создаёт issue в workspace (title сейчас поддерживает один placeholder, {{date}}, интерполируется в UTC date YYYY-MM-DD; любой другой {{...}} token rejected at create-time, чтобы typo не попал literal string в title), затем assign issue agent через обычный assignment flow. Вся работа на issue board с той же history, comments и status, что при manual assign.
  • Run-only mode (run_only) — без создания issue, enqueue task напрямую. Run невидим на board — только в run history autopilot.

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

Каждому autopilot нужен минимум один schedule trigger. Cron — standard 5-field format (minute hour day month weekday), минимальная granularity 1 минута (без seconds). Timezone в формате IANA (например Asia/Shanghai) определяет, в какой timezone интерпретируется cron.

Примеры:

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

Сервер Multica сканирует due triggers каждые 30 секундфактическое время fire может отставать до 30 секунд, не до секунды. Если сервер перезапустили через fire time, missed triggers догоняются при startup (ничего не теряется, но fire сразу).

Однократный manual trigger

Чтобы не ждать cron при отладке autopilot:

  • UI: «Run now» на detail page autopilot
  • CLI:
multica autopilot trigger <autopilot-id>

Manual trigger проходит тот же execution flow, что schedule trigger — только поле source в run record помечено manual.

Trigger из webhook

Autopilot могут fire на inbound HTTP webhooks. Добавьте trigger Webhook на detail page; Multica генерирует unique URL вида:

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

POST любого JSON на этот URL — Multica записывает run с source = webhook, сохраняет body как trigger_payload run и dispatch agent так же, как schedule trigger.

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

В create issue mode inbound payload append к description нового issue, чтобы agent читал inline. В run-only mode payload — часть run context, который daemon передаёт agent.

Payload shape

Можно отправить свой envelope:

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

…или любой JSON object/array. Multica нормализует во internal envelope:

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

Если поля event нет, Multica infer из common headers и body fields (X-GitHub-Event + body action, X-Gitlab-Event, X-Event-Type, body event/type/action). Если ничего не match — event webhook.received.

Для GitHub и подобных sources задайте content type application/json — form-encoded webhook payloads не принимаются.

Event filters

Новый webhook trigger fire на каждый inbound POST — нормально для single-purpose URL, но шумно для sources с множеством event types (GitHub — один repo webhook может deliver push, pull_request, workflow_run, check_suite и др.). Секция Event filters на webhook trigger ограничивает, какие events реально dispatch run; остальное в delivery history с status = ignored и reason = event_filtered, без run или issue.

Каждая строка — одно правило: event name плюс optional comma-separated actions list. Multica разрешает webhook, если любая строка match; пустая секция — accept everything (pre-filter behavior).

Примеры:

Event nameActionsMatches
workflow_runcompleted, failedworkflow_run events с action: completed или action: failed only
workflow_run(empty)каждый workflow_run event, любой action
push(empty)каждый push event

Откуда берутся event name и action

Multica derive event name и action из inbound request в этом порядке — first match wins.

1. Body envelope. Если body — JSON object со string field event, это event name напрямую. Optional eventPayload object даёт action candidates из fields action / state / conclusion / status.

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

2. Headers. Если body envelope нет, Multica читает well-known provider headers:

  • X-GitHub-Event: <event> — вместе с top-level body field action (если есть) формирует github.<event>.<action>.
  • X-Gitlab-Event: <event> — становится gitlab.<event>.
  • X-Event-Type: <event> — verbatim.
# GitHub-style: header даёт event name, body — action.
curl -X POST "$MULTICA_WEBHOOK_URL" \
  -H 'X-GitHub-Event: workflow_run' \
  -H 'Content-Type: application/json' \
  -d '{"action":"completed"}'
# inferred: event = github.workflow_run.completed
#        → matches filter row workflow_run / completed

# Generic event-type header — body fields не нужны.
curl -X POST "$MULTICA_WEBHOOK_URL" \
  -H 'X-Event-Type: trigger.true' \
  -H 'Content-Type: application/json' \
  -d '{}'
# inferred: event = trigger.true → matches trigger / true

3. Body fallback. Если нет body envelope и known header, Multica fallback на top-level body string fields: eventtypeaction.

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

4. Default. Если ничего не match — event webhook.received, action candidates нет.

Action candidates, полный список. После определения event Multica считает possible action match каждое значение ниже:

  • Suffix event name, когда event формы provider.event.<action> (например github.workflow_run.completedcompleted).
  • Body fields action, state, conclusion, statusтолько JSON strings. Boolean ({"action": true}) или number не qualify, поэтому filter event=trigger, action=true never match body {"trigger": true}true bool, не string.

Common gotcha. Filter row Event name: trigger / Actions: true не означает «fire когда body содержит trigger: true» — Event filters match inferred event and action, не arbitrary body fields. Отправьте trigger.true через X-Event-Type (или body envelope выше). Whitespace в saved filter rows (" workflow_run ") хранится verbatim и never match — trim перед save.

Quick test

После настройки filter проверьте обе ветки через curl:

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

# Filtered — тот же event, action не в allowlist
curl -X POST "$MULTICA_WEBHOOK_URL" \
  -H 'X-GitHub-Event: workflow_run' \
  -H 'Content-Type: application/json' \
  -d '{"action":"in_progress"}'
# → 200 {"status":"ignored","reason":"event_filtered"}

URL — bearer secret

Generated URL и есть credential. Любой с URL может fire autopilot. Относитесь как к token:

  • Не вставляйте в public issue threads, screenshots или chat history.
  • Rotate при утечке — «Rotate URL» на trigger row или multica autopilot trigger-rotate-url <autopilot-id> <trigger-id>. Старый URL перестаёт работать сразу.
  • Для sources с strong source authentication ждите per-trigger HMAC signature verification; v1 URL только bearer.
  • Workspace members с доступом к autopilot пока могут читать webhook URLs — tighter per-role secret visibility в follow-up.

Status-code semantics

Multica возвращает 200 OK с полем status для normal no-op outcomes, чтобы webhook-retry machinery provider не hammer URL:

  • {"status":"accepted","run_id":"…","autopilot_id":"…","trigger_id":"…"} — run dispatched.
  • {"status":"skipped","run_id":"…","reason":"agent runtime is offline at dispatch time"} — runtime assignee offline; recorded как skipped run.
  • {"status":"ignored","reason":"trigger_disabled"} — trigger disabled.
  • {"status":"ignored","reason":"autopilot_paused"} — autopilot paused.
  • {"status":"ignored","reason":"autopilot_archived"} — autopilot archived.

Non-2xx — real failures:

  • 400 — invalid JSON, scalar body или empty body.
  • 404 — unknown token ({"error":"webhook not found"}).
  • 413 — payload превысил 256 KiB.
  • 429 — per-token rate limit exceeded (default 60 req/min).

Self-hosted: public URL

Когда на сервере задан MULTICA_PUBLIC_URL (например https://multica.example.com), trigger response включает absolute webhook_url, UI показывает ready-to-copy URL. Без него UI compose URL из client API origin — нормально для desktop и same-origin web, но не для custom self-hosted reverse proxies. Multica намеренно не derive public host из Host / X-Forwarded-Host, чтобы misconfigured reverse proxy не заставил сервер mint webhook URLs на attacker-controlled host.

Run history

Каждый trigger создаёт run record, видимый на вкладке «History» detail page autopilot:

  • Trigger source (schedule / manual / webhook)
  • Start time, completion time
  • Status (issue_created / running / completed / failed / skipped)
  • Linked issue (create issue mode) или task (run-only mode)
  • Failure reason (если failed или skipped)

Что происходит при failure autopilot

Failure autopilot не auto-retry и не шлют inbox notifications. Failure оставляет failed entry в run history — без system-level re-enqueue как assign или @-mention и без notification кому-либо. Если autopilot periodic, следующий cron fire запустит new run, но failed work не re-run автоматически.

Если autopilot важен, спроектируйте monitoring — например, agent post comment при success, failures ловите по missing comments.

Почему нет auto-retry: autopilot уже periodic; system-level retries наслаивались бы на следующий scheduled run и создавали duplicate executions. Schedule полностью на cron — чище.

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

API-kind triggers не подключены. Trigger schema резервирует kind api, но ingress route его не fire; UI показывает Deprecated badge для existing rows без copy/rotate affordances. Per-trigger HMAC signature verification, IP allowlists и provider-specific event presets — follow-ups; v1 URLs только bearer.

Далее