Skip to content

Documentation navigation

GitHub and CI triggers

Select pull requests, issues, branch pushes and workflow results with signed local testing.

#Start agents from GitHub and CI events

Use a saved GitHub connection to react to pull requests, issues, pushes or completed workflows. Presets select the repository and event details before the agent runs. They do not install a GitHub App, change repository permissions or configure a webhook for you.

#Save the connection

In Studio, open Config → Triggers → Connections → Add a connection. In the Developer Portal, open your project's Integrations → Connections. Choose GitHub, name the connection and privately enter the webhook signing secret you will use in GitHub. Save the connection ID and receiver path.

The setup screen offers When to run, Repository and the relevant branch or workflow fields. Copy the declaration into your app. Creating a connection does not register a trigger or start an agent. Portal users run their app from the terminal; the Portal cannot serve an agent on your computer.

For terminal-only setup, the existing human connection API accepts setup_kind: "github_app" and a privately supplied webhook_secret. The signing secret is separate from your project's API key. Never place it in source, a copied command or a public URL.

#Choose a source

Python
opened = agent.on_pull_request(
    "conn_your_github", action="opened", repository="owner/repo", branch="main"
)
merged = agent.on_pull_request(
    "conn_your_github", action="closed", repository="owner/repo", merged=True
)
issue = agent.on_issue("conn_your_github", action="opened", repository="owner/repo")
push = agent.on_push("conn_your_github", repository="owner/repo", branch="main")
failed_ci = agent.on_workflow_run(
    "conn_your_github", repository="owner/repo", branch="main",
    workflow="CI", conclusion="failure"
)
SourceSupported choicesMeaning of branch
Pull requestopened, reopened, synchronize, closedDestination/base branch
Issueopened, reopened, closed, labeledNo branch filter
PushpushExact branch under refs/heads/; tags do not match
Workflow runcompletedBranch the workflow ran on

Repository names match owner/repo exactly. Optional filters are literal matches, not glob patterns. Omit a filter to accept any value; a missing payload field cannot satisfy a specified filter. A push with no branch filter includes tag pushes. closed includes both merged and unmerged pull requests; use merged=True or merged=False to distinguish them.

Workflow names match exactly. Conclusions are success, failure, cancelled, timed_out, neutral, skipped, action_required, stale or startup_failure. Omit conclusion to accept any completed workflow. Completion does not imply success. GitHub documents the underlying event payloads.

.where() adds a condition without dropping these selectors. Existing generic agent.on_connection() sources remain available for other supported event types. Importing a declaration does not register it or call a model.

#Register and serve

Finish your chosen source with a stable key, a target and a prompt:

Python
ci_alert = (
    failed_ci.key("failed-ci")
    .named("CI failed")
    .target("ci-helper", version=1)
    .asking(
        "Explain this workflow result without assuming access to its logs: "
        "{{event.payload.workflow_run.name}} finished with "
        "{{event.payload.workflow_run.conclusion}} on "
        "{{event.payload.workflow_run.head_branch}}."
    )
    .display_in_app()
)

For pull requests, use nested fields such as {{event.payload.pull_request.title}}; issue titles are {{event.payload.issue.title}}. Delivery titles and other text are untrusted input. The receiver does not fetch repository files, CI logs or attachments.

In Studio, discover your app, choose its project, Run it from Studio, and Turn on the declaration. Without Studio, configure the current project key and plane origins, then serve your agent. After the process reports Announced, call ci_alert.invoke() from an explicit registration script. Keep the serving process running.

#Test without a GitHub account

With the local stack, connection and target ready, run this from tooling/mock-gateway in the source checkout. It prompts privately for the same signing secret:

Plain text
uv run --frozen maivn-mock-gateway replay-github --connection-id conn_your_github --repository owner/repo --event workflow_run --branch main --workflow CI --conclusion failure --delivery-id 78ee3d51-cecd-4d49-bc68-5ce80ac5dd84 --repeat 2

The command sends synthetic signed events to the real local receiver. It does not create a GitHub issue, run GitHub Actions or require a tunnel. A registered matching agent can still incur ordinary model usage. The repeated delivery should produce one event and one run. Use --new-delivery-id for a separate run. Try a different repository or --conclusion success to prove that this failed-CI trigger stays quiet. Inspect the receiver outcome and completed run separately.

#Test a real GitHub delivery locally

Start the free receiver-only HTTPS tunnel for this connection. In the repository's webhook settings, use its public receiver URL, JSON content type and the same secret saved above. Subscribe only to the events you need: Pull requests, Issues, Pushes or Workflow runs. Use your existing repository access; these presets do not request a new OAuth grant or install an App. GitHub signs the exact request body using HMAC-SHA256.

Perform one matching action in a repository you control. Check GitHub's recent delivery response, then the trigger's completed run and actual output. Redeliver the same delivery to verify that its run count stays unchanged. The delivery receipt means the receiver accepted it; it does not mean the agent completed.

Keep both tunnel and agent running. Temporary tunnel URLs may change after a restart, requiring you to update the saved GitHub URL. GitHub does not automatically retry failed deliveries: after recovery, use Redeliver in GitHub for a delivery the receiver never accepted. An already accepted event has the platform's durable dispatch path and does not need a new delivery ID.

When finished, pause the trigger and stop the tunnel and agent. Disable the test webhook in GitHub if it is no longer needed, and revoke disposable platform connections. Existing legacy GitHub ingress remains compatible; new setup uses the saved connection receiver.