Vibe Coding
Back to Multica

Multica / Collaborate with agents

Autopilots

Let the agent start its own work according to the cron schedule, or be triggered when the webhook arrives - it can also be triggered manually through the UI/CLI.

Autopilots key concepts infographic
Autopilots key concepts infographic

Overview

Autopilots allows the agent to automatically start work according to the schedule - configure the cron and time zone, and when the time comes, Multica will dispatch the task itself, without you needing to trigger it every time. It is suitable for "standing order" scenarios such as regular inspections, periodic reports, and early morning cleaning tasks. Compared with the first three triggering methods (assignment/@mention/conversation, you actively shout), the core difference of Autopilots is time-driven.

Configure an Autopilot

Create a new autopilot on the Autopilot page of the workspace and set the following settings:

  • Name — display name
  • Execution Agent — to whom it will be assigned at the point
  • Priority — inherited from the task it generates (same semantics as issue priority)
  • Description / Prompt — The work description the agent gets every time it executes
  • Execution Mode — see next section
  • Trigger — add at least one schedule (cron + time zone) or webhook

Select execution mode

Autopilot has two execution modes. It is recommended to start with the "build issue first mode":

  • Create issue mode first (create_issue) - Default, recommended. Each time it is triggered, first create an issue in the workspace (the title currently supports only one placeholder {{date}}, which will be interpolated into the UTC date YYYY-MM-DD; other placeholders in the form of {{...}} will be rejected when created to avoid misspellings and silently treating the original text as the issue title), and then assign the issue to the agent according to the allocation process. All work falls on the issue board, and the history, comments, status and manually assigned issues are exactly the same.
  • Direct run mode (run_only) - No issue is created, and a task is directly added to the queue. This run is not visible on the dashboard - only in Autopilot's run history.

Let it run according to time

Each Autopilot requires at least one schedule trigger. Cron is a standard 5-field format (minute, hour, day, month, week) with a minimum granularity of 1 minute (no second level). The time zone is in IANA format (e.g. Asia/Shanghai) and determines the time zone in which cron expressions are interpreted.

A few examples:

  • 0 9 * * 1-5, Asia/Shanghai - 9 am Beijing time on weekdays
  • */30 * * * *, UTC - every 30 minutes
  • 0 3 * * *, UTC — 3 AM UTC every day

The Multica server scans for expired triggers every 30 seconds - the triggering time is delayed by up to 30 seconds**, which is not second-level accuracy. If the trigger point happens to be missed when the server restarts, the missed trigger will be scanned at startup (the trigger will not be lost, but the missed trigger will be made up immediately).

Manually trigger once

If you don’t want to wait for cron when debugging Autopilot, you can trigger it manually:

  • UI: Click "Manual Run" on the Autopilot details page
  • CLI:
multica autopilot trigger <autopilot-id>

Manual triggering has exactly the same execution process as schedule triggering, except that the source field in the run record is marked as manual.

Triggered via webhook

Autopilot can also be triggered by inbound HTTP webhooks. Add a Webhook trigger to the details page, and Multica will generate a unique URL:

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

POST any JSON to this URL - Multica will log a source = webhook run, save the request body as trigger_payload of run, and then press and schedule the trigger Distributed to agents in exactly the same way.

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

In build issue first mode, the inbound payload will be appended to the description of the new issue for the agent Read directly; in direct run mode, the payload will also be handed over to the daemon along with the run.

Payload form

You can send your own package:

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

You can also directly send any JSON object/array. Multica normalizes to an internal encapsulation:

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

Without the event field, Multica will select common header and body fields in the following order Inference: X-GitHub-Event + body action, X-Gitlab-Event, X-Event-Type, event / type / action in body. Event when neither hit The name has degenerated to webhook.received.

When configuring sources like GitHub, set the content type to application/json—— Form-encoded webhook payloads are not accepted in v1.

Event filtering

The new webhook trigger will fire for every inbound POST, which is the case for single-purpose URLs. That's fine, but for sources that fan out a lot of event types (typically GitHub - A repository webhook will issue push, pull_request, workflow_run, check_suite etc.) will be very noisy. The event filter block on the webhook trigger is used to Limit which events are actually dispatched once; others are only recorded in the delivery history. status = ignored, reason = event_filtered, no issue or run will be created.

Each line is a rule: an event name followed by an optional, comma-separated list of actions. If any row is hit, it will be released; if the block is left blank, all events will be accepted (that is, the behavior before filtering).

example:| Event name | Actions | Hit range | |---------------- | ------------------- | ------------------------------------------------------------------------------- | | workflow_run | completed, failed | Only workflow_run events where action is completed or failed | | workflow_run | (leave blank) | All workflow_run events, not limited to actions | | push | (leave blank) | all push events |

Where do event names and actions come from?

Multica infers event and action from inbound requests in the following order, first hit first.

**1. Body envelope. ** If body is a JSON object with string fields event, just use it as the event name directly. The optional eventPayload object then Provided from own action / state / conclusion / status fields action candidate.

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

**2. Request header. ** When there is no body envelope, the following head recognition is used:

  • X-GitHub-Event: <event> - Combined with the action field at the top level of body (if any), spell it as github.<event>.<action>.
  • X-Gitlab-Event: <event> — spelled gitlab.<event>.
  • X-Event-Type: <event> - Use as-is.
# GitHub style: event name comes from header, action comes from body.
curl -X POST "$MULTICA_WEBHOOK_URL" \
  -H 'X-GitHub-Event: workflow_run' \
  -H 'Content-Type: application/json' \-d '{"action":"completed"}'
# Inference result: event = github.workflow_run.completed
# → Hit the filter rule of workflow_run / completed

# Generic event-type header - no body field required.
curl -X POST "$MULTICA_WEBHOOK_URL" \
  -H 'X-Event-Type: trigger.true' \
  -H 'Content-Type: application/json' \
  -d '{}'
# Inference result: event = trigger.true → hit trigger / true

**3. Body. ** When neither the Body envelope nor the above header is available, Search from the top-level string field of body in order: eventtypeaction.

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

**4. Default value. ** When none of the above are hit, the event name is webhook.received, There are no action candidates.

**Complete list of action candidates. ** After the event name is determined, the following values will be listed as Possible actions:

  • Event name suffix, when the event is in the form of provider.event.<action> (e.g. github.workflow_run.completedcompleted).
  • The four fields action, state, conclusion and status in the body—— Must be a JSON string. Neither booleans ({"action": true}) nor numbers count Candidate, so the filtering rule of event=trigger, action=true can never be hit** {"trigger": true} This kind of body, because true is a bool not a string.

**Common misunderstandings. ** A rule of Event name: trigger / Actions: true Not "If trigger: true appears in the body, let it pass" - the event filtering matches Inferred events and actions, not arbitrary body fields. To hit it, use Send trigger.true in the X-Event-Type header, or use the body envelope above. Values with spaces when saved (e.g. " workflow_run ") are saved unchanged, but always hit No - please trim before saving.

Quick verification

After configuring filtering, you can use curl to verify both the "hit" and "filtered" paths at the same time:

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

#Filtered - the same event, but action is not in the whitelist
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 is bearer secret

The generated URL is the certificate, and anyone who gets it can trigger this Autopilot. Please treat it as token:

  • **Do not post in public issue comments, screenshots, or chat history. **
  • Regenerate immediately after leak - click "Regenerate URL" on the trigger, or run multica autopilot trigger-rotate-url <autopilot-id> <trigger-id>. The old URL becomes invalid immediately.
  • For sources that require strong source authentication, wait until per-trigger HMAC signature verification comes online; v1 URL only bearer.
  • Workspace members currently able to view Autopilot can see its webhook URL - more detailed Permission visibility is a follow-up.

Status code semantics

Normal no-op paths return 200 OK plus the status field to avoid external webhook retries. The mechanism repeatedly hits:

  • {"status":"accepted","run_id":"…","autopilot_id":"…","trigger_id":"…"} ——A run has been dispatched.
  • {"status":"skipped","run_id":"…","reason":"agent runtime is offline at dispatch time"} ——The runtime of the dispatched agent is offline, recorded as skipped run.
  • {"status":"ignored","reason":"trigger_disabled"} - The trigger is disabled.
  • {"status":"ignored","reason":"autopilot_paused"} - Autopilot has been paused.
  • {"status":"ignored","reason":"autopilot_archived"} - Autopilot has been archived.

Non-2xx are real failures:

  • 400 - Invalid JSON, scalar body, empty body.- 404 - Unknown token ({"error":"webhook not found"}).
  • 413 - Request body exceeds 256 KiB.
  • 429 - Single token rate limit (default 60 times/minute).

Self-hosted: Configure public URL

After setting MULTICA_PUBLIC_URL (for example https://multica.example.com) on the server side, The trigger response will contain an absolute webhook_url, and the UI will directly display the copyable URL. Not set When , the UI will use the client's API origin to spell out the URL - desktop and same-origin web are no problem. But custom reverse proxy does not work. Multica intentionally does not start from Host/ X-Forwarded-Host header infers the public host to avoid being induced to generate reverse generation when configuration errors occur. A webhook URL pointing to the attacker's domain name.

View running history

Each trigger will generate a run record (run), which can be seen in the "History" tab of the Autopilot details page:

  • Trigger source (schedule / manual / webhook)
  • Start time, finish time
  • Status (issue_created / running / completed / failed / skipped)
  • Associated issue (build first issue mode) or task (direct run mode)
  • Reason for failure (when failed or skipped)

What happens if Autopilot fails?

The reason for not automatically retrying: Autopilot itself is cyclical, and automatic retrying at the system level can easily overlap with the next schedule, resulting in repeated execution. It is cleanest to leave the scheduling power entirely to cron.

**If Autopilot fails, it will not be automatically retried and no inbox notification will be sent. ** Only a failed record will be left in the run history after failure - it will not be requeued by the system like allocation / @mentions, and no notification will be sent to anyone. If this Autopilot is a periodic task, it will be retriggered the next time cron arrives (a new run), but the failed work this time will not be automatically rerun. If Autopilot is important, design monitoring yourself - for example, have the agent send itself a comment when it succeeds, and detect failures by missing comments.

Capabilities that are temporarily unavailable

API type trigger has not been connected yet. The api type is retained in the trigger schema but no inbound route will trigger it; the UI will label existing such records as Deprecated and will not display copy / rotate operations. Per-trigger HMAC signature verification, IP allowlist, per-provider event presets are follow-up; v1 URL bearer only.

Next step