> ## Documentation Index
> Fetch the complete documentation index at: https://docs.incident.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Delegating agents

> Hand code changes to your team's own coding agent instead of incident.io's built-in one.

By default, incident.io writes code changes with its own built-in agent. If your team already runs a coding agent, you can delegate the work to it instead. incident.io still owns everything around the change: the investigation, the conversation in the channel, the progress updates, and linking the finished pull request back to the incident. It hands off only the step of writing the code.

The point of delegating is that the change is made with all the setup you've already built in that tool: your rules and conventions, the MCP servers you've connected (including incident.io's own, so the agent can pull live incident context), and your development environment. The fix comes from the agent your team has already tuned to your codebase, rather than a generic one.

## Choosing which agent runs

Which agent writes the change is an explicit choice. In **Settings → AI SRE → Code changes** you pick one of three options: incident.io's built-in agent, Cursor, or your own custom platform. The one you select runs for every code change, so connecting more than one is fine. Your selection is always what's used.

## Cursor

Connect Cursor with an API key, and code change requests are handed to a Cursor cloud agent that makes the change and opens the pull request. It runs with your Cursor configuration, including any MCP servers you've set up for your repositories, and the resulting pull request is linked back to the incident exactly as the built-in flow would.

<Note>
  If you'd like us to support another hosted agent out of the box, such as Devin, [get in
  touch](mailto:support@incident.io) and we'll work with you.
</Note>

## Your own platform

If you run an internal coding agent platform, you can connect it directly by implementing the small HTTP interface specified below. **We call you** to launch and steer agent runs, and **you call us back** (or let us poll) with status. Your agent opens the pull request with its own credentials in your own infrastructure. We only ever need read access to the repository to attach the finished PR to the incident.

<Note>
  Connect your platform from **Settings → AI SRE → Code changes → Custom agent** in the dashboard. You'll need your
  platform's endpoint URL (which must start with `https://`) and a bearer token it issued for us. Everything else, including the webhook signing secret,
  is handled automatically. You can also give the connection a display name, which Slack uses when narrating the agent's progress.

  Each organization can connect one custom agent platform today. If your agents are split across several internal systems, put a thin router in front of them and connect that. The `repository` field on each launch tells you where to route. [Get in touch](mailto:support@incident.io) if you'd like first-class support for multiple connections.
</Note>

### How a delegated task flows

1. A responder asks for a code change (for example from the incident channel), and we render a self-contained markdown **brief**: the incident title and reference, the repository, the user's instructions, our expectations for the PR, and a snapshot of the investigation so far.
2. We call `POST /agents` on your platform with the brief and structured identifiers, plus a per-launch webhook URL and signing secret.
3. Your platform starts a run and responds with a run ID and a link to its own UI, which we surface in Slack.
4. While the run is in flight, you send signed status callbacks to the webhook, or we poll `GET /agents/{id}` every 2 minutes. Both work.
5. Your agent opens a **draft PR** with its own GitHub credentials and reports `finished` with the PR URL. We attach the PR to the incident and move the task into review.
6. If a responder asks for changes, we call `POST /agents/{id}/followup` with the new instructions, and the same run updates the same PR.

### The interface you implement

All endpoints are served from the base URL you configure, authenticated with the bearer token you issue us (`Authorization: Bearer <token>`). Every request we send carries an `X-Incident-Interface-Version` header (currently `2026-06-12`) so you can tell which revision of this contract you're being called with. Breaking changes ship under a new version value, announced ahead of time.

| Endpoint                     | Required?            | Purpose                                          |
| ---------------------------- | -------------------- | ------------------------------------------------ |
| `POST /agents`               | Required             | Launch a run                                     |
| `GET /agents/{id}`           | Required             | Report run status                                |
| `POST /agents/{id}/followup` | Strongly recommended | Send follow-up instructions to a run             |
| `POST /agents/{id}/stop`     | Optional             | Cancel a run (best effort)                       |
| `GET /ping`                  | Optional             | Used by the dashboard's "Test connection" button |
| Webhook (you call us)        | Recommended          | Push status instead of waiting for our poll      |

#### `POST /agents`: launch

```json theme={null}
{
  "task_id": "01JXAMPLE7AXZ2C93K61WBPYEH",
  "prompt": "<self-contained markdown brief>",
  "incident_id": "01JXAMPLE0INCIDENT0ID0000",
  "reference": "INC-123",
  "investigation_id": "01JXAMPLE0INVESTIGATION00",
  "repository": "acme/payments-service",
  "webhook": {
    "url": "https://app.incident.io/webhooks/code-agent/custom/<org_id>",
    "secret": "<hmac secret>"
  }
}
```

* `task_id` is our identifier for the request. Treat it as an **idempotency key**: if you receive a second launch with a `task_id` you've already started, return the existing run rather than starting another.
* `prompt` is the rendered brief. It's self-contained, so an agent with no other context can act on it.
* `incident_id`, `reference` and `investigation_id` are also embedded in the prompt, but exposed as structured fields so your harness can fetch live data through our [MCP server](/ai/remote-mcp) without parsing markdown. They're omitted when the task has no incident or investigation.
* `webhook` is where to send status callbacks for **this run**, and the secret to sign them with. You may ignore it and rely on polling, but webhook-driven updates feel noticeably faster in Slack.

Respond within **10 seconds**:

```json theme={null}
{ "id": "run_8f2k1", "url": "https://agents.example.com/runs/run_8f2k1" }
```

* `id` is your opaque run identifier. We include it in every subsequent call.
* `url` (optional) links to your platform's UI for the run and is shown to responders in Slack.

If launching takes longer than that, accept the request, return the run ID immediately, and do the heavy lifting asynchronously.

#### `GET /agents/{id}`: status

```json theme={null}
{
  "id": "run_8f2k1",
  "status": "running",
  "summary": "Reproduced the bug, writing a regression test",
  "pr_url": "",
  "branch": ""
}
```

* `status` is one of `running`, `finished` or `error`.
* `summary` is a short progress message. We show the latest one in Slack, so keep it human-readable and current.
* `pr_url` is **required when reporting `finished`**. A `finished` status without a PR URL is treated as a failure, not as "almost done", so report `running` until the PR exists.
* `branch` (optional) is the feature branch the agent pushed to.

#### `POST /agents/{id}/followup`: iteration

```json theme={null}
{ "instructions": "Also handle the retry case in the worker" }
```

The run picks up the new instructions and finishes by updating the **same PR**. Implementing this is strongly recommended: it's what powers "request changes" from the incident channel. Respond `running` to status calls while the follow-up is in progress, then `finished` with the same `pr_url` once the PR is updated.

#### `POST /agents/{id}/stop`: cancel

Best effort, no body. We call it when a responder abandons or retries a task. Returning `404` for a run you've already cleaned up is fine.

#### `GET /ping`: connection test

Return `200` to confirm the endpoint is reachable and the bearer token is valid. The dashboard's "Test connection" button calls this; platforms that don't implement it still work, but admins lose the ability to verify the connection before the first real launch.

### The webhook you send us

POST the **same JSON body as the status response** to the per-launch webhook URL, signed with the per-launch secret:

```
X-Webhook-Signature: sha256=<hex(HMAC-SHA256(secret, raw request body))>
```

* Send one whenever the run meaningfully progresses: on completion at minimum, and ideally on summary changes too.
* Our handling is **idempotent**, and the webhook and our poller converge on the same logic, so duplicate or out-of-order deliveries are harmless.
* You don't need a retry pipeline: if a delivery fails, our 2-minute poll picks the status up. (Retries are welcome all the same.)
* We respond `200` even for runs we no longer track, so you can fire-and-forget.

### Timing expectations

| What                         | Expectation                                         |
| ---------------------------- | --------------------------------------------------- |
| Response to any of our calls | Within 10 seconds                                   |
| Our polling cadence          | Every 2 minutes per active run                      |
| Maximum run length           | **2 hours**, after which we mark the task as failed |
| Webhook deliveries           | Any time during a run; completion at minimum        |

### What this interface doesn't do

Instructions flow one way. There is no way for your agent to ask the responder a question mid-run (no elicitation step). If the brief is ambiguous, the agent should make a reasonable choice and explain it in the PR description. Responders iterate after the fact through follow-ups, which is the intended loop.

### Giving your agent live incident data

The brief embeds an investigation snapshot capped at 30,000 characters. For full, current context, configure your agent harness with access to our [MCP server](/ai/remote-mcp) using an incident.io API key:

* `investigation_sync` downloads the complete investigation (findings, hypotheses, check outputs) as an archive via a short-lived signed URL.
* `incident_show` and `alert_show` fetch the live incident and related alerts.

The brief tells the agent to prefer these tools when they're available and to fall back to the embedded snapshot otherwise, so MCP access is an upgrade, not a requirement.

### Security model

There are three credentials in play, each scoped to one direction:

1. **Us → your API**: the bearer token you issue and paste into our dashboard. We store it encrypted and send it on every call. Rotate it by reconnecting with a new token.
2. **You → our webhook**: the HMAC secret we generate when you connect, delivered to you inside each launch request. You never need to store it long-term. Sign each run's callbacks with the secret that run was launched with.
3. **Your agent → our MCP**: an incident.io API key you create and configure into your agent environment, governed by the same scopes as any other API key.

Your platform must be reachable from the public internet over HTTPS. If it isn't, [talk to us](mailto:support@incident.io).

## Related

<CardGroup cols={2}>
  <Card title="Making code changes" icon="code-pull-request" href="/investigations/connect/code/making-code-changes">
    How responders ask for a fix from the incident channel.
  </Card>

  <Card title="Remote MCP" icon="plug" href="/ai/remote-mcp">
    Give your agent live incident and investigation data.
  </Card>
</CardGroup>
