Skip to content

Triage a PagerDuty incident ​

A workflow can read a PagerDuty incident, have an agent look into it, and add what the agent found to the incident as a note. It needs the factory's PagerDuty app set up first.

The incident steps ​

#jigs/steps has two PagerDuty steps:

  • fetchIncidentSnapshot({ installationName, incidentId }) reads the incident: its number, title, status, urgency, creation time and URL, and its service, assignees and escalation policy, each with an id, a name and a link. Later steps in the run work from this copy; a run that resumes reads the incident afresh.
  • postIncidentNote({ installationName, incidentId, content }) adds a note and returns its noteId. The note is attributed to the from user set on the installation in the hub, and ends in a line such as Run wrun_01K…, so a responder can find the run with jigs status. PagerDuty shows markup as literal text, so write plain sentences.

postIncidentNote is tried only once. If PagerDuty's reply is lost, the note may already have been added, and a retry could add it twice. So a failed post fails the step, and the run with it unless the workflow catches the error.

The steps read and write through the PagerDuty installation they name. An agent that needs more than the snapshot, such as alerts or log entries, gets it from PagerDuty's MCP server, acting as the same app.

An observer workflow ​

This workflow looks at an incident and adds a note. It changes nothing else on the incident. Save it as workflows/incident-triage/incident-triage.ts:

ts
// workflows/incident-triage/incident-triage.ts
import {
  defineWorkflow,
  harnesses,
  models,
  pagerdutyMcp,
  type WorkflowInputs,
} from "@jigs-ai/jigs";
import { z } from "zod";
import { runAgent } from "#jigs/routines";
import { createRunDirectory, fetchIncidentSnapshot, postIncidentNote } from "#jigs/steps";

const inputs = z.object({ installationName: z.string().min(1), incident: z.string().min(1) });

const agents = {
  triager: harnesses.pi(models.openaiCodex("gpt-5.5"), {
    pagerduty: { installationName: "pagerduty-acme" },
    mcpServers: {
      pagerduty: pagerdutyMcp({
        tools: ["get_incident", "list_alerts_from_incident", "list_log_entries"],
      }),
    },
  }),
};

const findings = z.object({
  summary: z.string(),
  likelyCause: z.string(),
  nextStep: z.string(),
});

export async function incidentTriage(input: WorkflowInputs<typeof inputs>) {
  "use workflow";

  const { installationName } = input;
  const incident = await fetchIncidentSnapshot({ installationName, incidentId: input.incident });
  if (incident.status === "resolved") return { skipped: "already resolved" };

  const directory = await createRunDirectory();
  const triage = await runAgent({
    harness: agents.triager,
    cwd: directory,
    prompt: [
      `Triage PagerDuty incident #${incident.number} (${incident.id}): ${incident.title}.`,
      `Service: ${incident.service.name}. Urgency: ${incident.urgency}. Opened ${incident.createdAt}.`,
      "Use the PagerDuty tools to read its alerts and log entries.",
      "Do not change the incident. Say what is happening, the likely cause and one next step.",
    ].join("\n"),
    output: findings,
  });

  const note = await postIncidentNote({
    installationName,
    incidentId: incident.id,
    content: [
      `Summary: ${triage.output.summary}`,
      `Likely cause: ${triage.output.likelyCause}`,
      `Suggested next step: ${triage.output.nextStep}`,
    ].join("\n"),
  });
  return { noteId: note.noteId, ...triage.output };
}

export default defineWorkflow({
  inputs,
  requires: { agents, integrations: ["pagerduty"] },
  workflow: incidentTriage,
});

The agent's PagerDuty access ​

The triager is a Pi agent. Its pagerduty option names the installation it acts through, and jigs gives it that installation's token from the hub when it starts. A harness is fixed in code, so name the installation your trigger passes. pagerdutyMcp() connects it to PagerDuty's hosted MCP server with that token, and the tools list narrows what it may call to the reads it needs. See Linear and PagerDuty access for agents.

The token belongs to the app, not a person, so the agent can read and update incidents and read users, but tools that answer for a user, such as get_user_data, do not work. Past and related incidents are left out: they failed with a permission error on an account tested with this workflow.

Start it from each new incident ​

Register incident-triage in the factory and give it an event trigger on the pagerduty.incidents source, which starts one run for each new incident on the services you name:

ts
// jigs.config.ts
import { defineFactory, pagerduty } from "@jigs-ai/jigs";

export default defineFactory({
  hub: { url: "https://hub.example.com" },
  workflows: {
    "incident-triage": () => import("./workflows/incident-triage/incident-triage.ts"),
  },
  triggers: {
    "triage-checkout": {
      active: process.env.TRIAGE_CHECKOUT_ACTIVE === "true",
      workflow: "incident-triage",
      source: pagerduty.incidents({ installationName: "pagerduty-acme", services: ["PABC123"] }),
    },
  },
});

Each run gets the incident's id as incident, and the trigger's installation as installationName. Every new incident starts a run, even one acknowledged or resolved before the service saw it, which is why the workflow checks the status in its snapshot and skips one that is already resolved. Rebuild and start the service with pnpm exec jigs up.

A run starts within seconds of PagerDuty's incident.triggered event, which reaches the service through the hub. An incident whose event arrives twice still starts one run.

To try the workflow by hand, start a run with an incident's id, the part of its URL after /incidents/:

sh
pnpm exec jigs run incident-triage --input installationName=pagerduty-acme --input incident=Q1ABCDEFGHIJKL

Before the run starts, preflight checks that Pi is installed and that the agent's installation is on the hub. The snapshot's installation comes from the run's inputs, so the run's first step checks it. The agent step checks PagerDuty's MCP server with the agent's token before the agent starts.

Follow the run with pnpm exec jigs watch. When it finishes, the note is on the incident's timeline.