Skip to main content
Early access. GitHub and Slack runs start in a cloud sandbox operated by Mutagent, and cloud sandboxes are not open to every account yet: we are letting accounts in gradually while we test. There is nothing to host, and nobody has to be at a terminal.
A trigger listens for an event and runs an instruction. A routine runs an instruction on a schedule. Both belong to a workspace, both usually work on a repository, and both appear in the same runs history.

Trigger kinds

Pass one of these to --on. trace.threshold requires both --threshold (1 to 1,000,000) and --window (a duration such as 60m, 24h or 7d). Omitting either is refused before the request is sent. Narrow it further with --service <name> or --session <id>, or count only the traces of some agents, skills or services with --subject, for example --subject agent:support-bot.

Built-in mention triggers

A connected workspace answers mentions of the app without any trigger being created:
  • On GitHub, a mention of the app in an issue or an issue comment, on every repository the app can reach. Mentions on pull requests do not start a run.
  • In Slack, a mention of the app in a channel it is in. The run’s repository is picked from the message, the thread or the channel. See Which repository a mention runs on.
mutagent gateway triggers lists these built-in triggers alongside yours. A built-in trigger is always on and cannot be changed or replaced:
  • triggers create --on github.mention is refused with TRIGGER_KIND_BUILTIN_ONLY. Use another kind, such as github.issue.opened.
  • A slack.mention trigger of your own answers only in the channels you give it with --channel. The built-in keeps answering everywhere else. A channel that another enabled trigger already holds is refused with TRIGGER_CONFLICT, and a slack.mention trigger with no channel is refused too.

Creating a trigger

To check a trigger without starting a run, pass it a sample event:
It reports whether the sample would match, and why not if it would not. It has no side effects. triggers update <id> changes the instruction, name, channels, threshold, stage or Environment of a trigger you created. The kind and the repository cannot be changed: create a new trigger for those, then delete this one.

Choosing the repository

There is no default repository. A trigger or routine chooses its repository when you create it: github.issue.opened, github.ci-failed and slack.mention triggers always run on a repository. When no repository is chosen, the command is refused with REPOSITORY_REQUIRED, and the error lists the linked repositories you can name. A repository the app cannot reach is refused, with the instruction to give the app access to it on GitHub first (mutagent gateway repos grant-more prints the page).

Routines

A routine is a schedule, a timezone, a repository and an instruction.
A routine chooses its repository the same way a trigger does: --repo owner/name, your directory’s GitHub remote, or --no-repo for a routine that needs no code. See Choosing the repository. --env <name> loads a workspace Environment into every run, and --key <key> makes a retry return the same routine instead of creating a second. Give exactly one of --every or --cron. --every takes a plain-language schedule; --cron takes a cron expression. Either way, the output shows the normalized cron, the timezone, and the next three fire times.
--tz is required, and it must be an IANA timezone such as Europe/Berlin. Omitting it is refused locally, before any request is sent, with TIMEZONE_REQUIRED and exit code 1. There is no default: the cloud has no “local time”, so daylight-saving behaviour has to be stated rather than guessed.
A routine fires once per due time. routines run-now fires once per call, and --wait polls that run to completion.
routines update <id> changes the schedule, timezone, instruction, name, stage or Environment. The repository cannot be changed. routines pause stops a routine firing without deleting it; routines resume starts it again. A routine whose repository you unlink is paused visibly, with the reason shown in routines show.

Webhook deliveries

A webhook trigger listens on a per-workspace webhook URL with its own secret. You create the webhook source in the web app and choose its secret there (16 to 512 visible ASCII characters). Mutagent stores the secret encrypted and never shows it again, so keep your own copy. Sign each delivery: compute an HMAC-SHA256 with that secret over v1:<delivery-id>: followed by the raw body, and send the result as x-gateway-signature: sha256=<hex>. <delivery-id> is the value of your x-gateway-delivery-id header, or empty (v1::) when you send no such header. A delivery id the signature was not computed over is refused.

Two identical deliveries are one event

A delivery is recognised by what it contains, not by when it arrived. Two deliveries carrying identical bytes and no x-gateway-delivery-id header are one event, however far apart they arrive — hours or days later makes no difference. Nothing in the identity comes from a clock. To have a second occurrence start a second run, say so in the request. There are two ways:
  • Send x-gateway-delivery-id with a fresh value. A new id is a new event. The value may be up to 256 characters of letters, digits, - and _. This is how a caller states “this is a new occurrence, not a retry”.
  • Put something distinguishing in the body, such as a timestamp or a sequence number.
The reason is cost. A trigger starts a real agent run in a sandbox. When a request carries neither a delivery id nor anything distinguishing in its body, nothing in it tells a retry from a fresh occurrence — so it is treated as a retry.

Pressing Redeliver does not start a second run

GitHub mints a new delivery id every time you press Redeliver in the App’s Advanced → Recent Deliveries page. That new id does not make it a new event: the gateway recognises GitHub deliveries by their content, which a redelivery replays byte for byte, so the redelivered event is collapsed into the first one and no second run starts. This is deliberate, and for the same reason as above — a redelivery of the same comment would otherwise start a second paid run in a second sandbox.
Genuinely repeated actions still run each time. Reopening the same issue twice is two events, because each reopen carries its own timestamp.