Incident Triage
Sentry → GitHub → Linear → Slack. End-to-end working example.
A real working pipeline: when Sentry surfaces an unresolved issue, find
the likely-bad commit, file a Linear ticket with context, post a Slack
summary. Total round-trip: one hrbr exec call, fully traced.
What you need
| Plugin | Used for |
|---|---|
sentry-mcp | Fetch the issue |
github-mcp | Search code for the culprit string |
linear-mcp | Create the ticket |
slack-mcp | Post the summary |
All four installed and in ready state — see
Install your first plugin
if needed.
The exec
const issue = await sentryMcp.getIssue({ id: input.issueId });
const matches = await githubMcp.searchCode({
query: issue.culprit,
repo: input.repo ?? "acme/api",
});
const owner = matches[0]?.path ?? "unknown";
const ticket = await linearMcp.createIssue({
teamId: input.teamId,
title: issue.title,
description: [
`**Sentry:** ${issue.url}`,
`**Suspect file:** \`${owner}\``,
"",
`\`\`\``,
issue.message.slice(0, 1_200),
`\`\`\``,
].join("\n"),
});
await slackMcp.postMessage({
channel: input.channel ?? "#incidents",
text: `Triage ready: ${ticket.url} (suspect: ${owner})`,
});
return { ticket: ticket.url, suspect: owner };Run it:
hrbr exec -f triage.ts \
--input '{ "issueId": "SENTRY-1234", "repo": "acme/api", "teamId": "ENG", "channel": "#incidents" }'Promote to a Function
Once it works, wrap in defineJob so anyone (or a scheduled cron) can
invoke it:
defineJob({
name: "triage-sentry-issue",
description: "Sentry alert → Linear ticket → Slack summary.",
handler: async (ctx, input: TriageInput) => {
/* … same body, ctx.plugins.<namespace>.<tool>(...) … */
},
});hrbr inspect -f ./triage-function.job.ts
hrbr inspect 'return await hrbr.jobs.inspect({ name: "triage-sentry-issue" })'Promote to a Skill
Wire it as a workflow-backed skill so the agent picks it up automatically when the user says "triage SENTRY-1234":
---
name: triage-sentry-issue
description: |
Use when the user references a Sentry issue (SENTRY-XXXX) and wants
it triaged into a Linear ticket.
harbor_workflow:
… # See Authoring → Skills
---See Your first Skill for the full walkthrough.
Why this is one trace, not four
Without Harbor, that's four tool calls, four model round-trips, four
network handshakes the agent had to babysit. With Harbor, the whole thing
is one exec run:
- One run, one trace, four child spans (one per plugin call)
- One agent decision: "here's the code; run it"
- Credentials never leave Harbor; the agent never sees a Sentry token
- Replayable from the Traces page
For multi-step pipelines that take longer than 30 s or need retries,
write step.do inside the handler — see
Multi-step with retries.