Help us improve
Share bugs, ideas, or general feedback.
From incident-postmortem
Reconstructs a chronological incident timeline from chat messages, tracker events, Datadog logs, and merged PRs. Each entry includes a UTC timestamp, description, source citation, and evidence tag.
npx claudepluginhub incubyte/ai-pluginsHow this skill is triggered — by the user, by Claude, or both
Slash command
/incident-postmortem:incident-timeline-builderThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Take a bundle of evidence collected during an incident's investigation phase and produce a chronological timeline that a postmortem can be built on. Every event in the timeline carries a UTC timestamp, a short description, a source citation, and an evidence tag. Events without a verifiable timestamp are flagged `[UNKNOWN]` rather than guessed.
Classifies incidents by severity (SEV1-4), constructs timelines, assesses impact, performs 5 Whys root cause analysis, and generates blameless post-mortems for production issues.
Guides SREs through postmortem creation: builds timeline, action items, and drafts a Google Doc from incident context.
Structures blameless post-mortems with incident timelines, impact assessment, root cause analysis, response evaluation, action items, and lessons learned. Useful after production incidents or outages.
Share bugs, ideas, or general feedback.
Take a bundle of evidence collected during an incident's investigation phase and produce a chronological timeline that a postmortem can be built on. Every event in the timeline carries a UTC timestamp, a short description, a source citation, and an evidence tag. Events without a verifiable timestamp are flagged [UNKNOWN] rather than guessed.
This skill investigates nothing on its own. The caller (the incident-postmortem agent in Phase 2, or a user invoking the skill directly) hands the skill a structured payload of pre-gathered evidence; the skill organizes it.
The skill runs without user interaction. It produces a single chronological timeline as its only output.
[VERIFIED], [OBSERVED], [INFERRED], [UNKNOWN].updateFields, addComment, etc.), no file writes. Posting and saving are the caller's job.The caller passes a payload describing the incident and four pools of evidence:
{
"incident": {
"id": "12345",
"url": "https://dev.azure.com/<org>/<project>/_workitems/edit/12345",
"title": "Payment processing outage for US properties",
"created_at": "2026-04-29T14:32:00Z",
"resolved_at": "2026-04-29T16:08:00Z",
"severity": "1 - Critical"
},
"chat_messages": [
{ "timestamp": "...", "author": "...", "channel": "...", "message_url": "...", "text": "..." }
],
"tracker_events": [
{ "id": 12348, "url": "...", "title": "...", "state_change": "Active -> Resolved", "changed_at": "...", "changed_by": "..." }
],
"datadog_logs": [
{ "timestamp": "...", "service": "...", "level": "error", "message": "...", "logs_url": "..." }
],
"merged_prs": [
{ "id": 999, "url": "...", "title": "...", "merged_at": "...", "merged_by": "...", "repo": "..." }
]
}
Any of chat_messages, tracker_events, datadog_logs, or merged_prs may be empty (the corresponding source was not gathered or returned no results). The skill produces a timeline from whichever pools are populated and notes the empty pools in a brief preamble before the table.
The shape is tracker-agnostic. The incident.id and tracker_events[].id may be numeric (Azure DevOps), a key like INC-456 (Jira), or any other identifier. The skill does not interpret tracker-specific semantics — it organizes timestamps.
The skill runs five ordered steps.
Compute the incident time window: from incident.created_at to incident.resolved_at (or now() when the incident is unresolved). This is the in-scope window. Events outside the window should still appear in the timeline if the caller passed them in (the caller has already filtered for relevance), but flag them with (out-of-window) in the description so the postmortem author can decide whether to keep them.
If incident.created_at is missing or unparseable, halt and tell the caller. The skill cannot order events without a baseline.
Convert every event's timestamp to UTC ISO-8601 form (YYYY-MM-DDTHH:MM:SSZ). Tolerate input variations: epoch milliseconds, AzDO's 2026-04-29T14:32:18.123Z form, Jira's 2026-04-29T14:32:18.123+0000, Datadog's 2026-04-29T14:32:18.123456Z, Slack/Teams' 2026-04-29T14:32:18.000+00:00. When a timestamp is ambiguous (e.g., a Datadog log with millisecond precision but no timezone marker — defaults to UTC by the MCP), keep the event but tag it [OBSERVED] instead of [VERIFIED] because the timestamp's precision matters for the postmortem.
Events with no timestamp at all (sometimes the case for chat messages or comments where the MCP didn't return one) get the placeholder ?? UTC in the Time column and an [UNKNOWN] tag. They sort to the end of the timeline (after the last verified event) so they don't disrupt the chronological reading.
For each evidence item across the four pools, build one timeline entry. Use the rules below per source.
Chat messages. Description: lead with the author and one-sentence paraphrase of the message. Source citation: the message URL. Evidence tag: [VERIFIED] if the message is from a known incident response thread (the caller filtered for this); [OBSERVED] otherwise.
Example:
14:35 UTC | @alice "PagerDuty alert just fired for the payments service" | [chat thread](slack://...) | [VERIFIED]
Tracker events. Description: the state transition (e.g., New -> Active, Active -> Resolved) plus the actor. Source citation: the issue URL with a revision fragment when known. Evidence tag: [VERIFIED] (state changes are first-class data on both AzDO and Jira).
Example:
15:02 UTC | INC-456 transitioned New -> Active by @bob | [INC-456](...) | [VERIFIED]
Datadog log entries. Description: the log level, the service, and a truncated message (max 100 characters; truncate with … mid-string when needed). Source citation: the Datadog logs URL filtered to the timestamp. Evidence tag: [VERIFIED] when the message includes a stack trace or specific error string; [OBSERVED] for plain INFO/WARN entries that match a pattern.
Example:
14:32 UTC | ERRORpayments: Stripe::APIConnectionError "Connection refused (errno: ECONNREFUSED)" | [Datadog](...) | [VERIFIED]
Merged pull requests. Description: lead with the PR title, the merger, and the repo. Source citation: the PR URL. Evidence tag: [VERIFIED] for the merge time itself; [INFERRED] when the entry represents a possible cause (the PR merged before the incident started and changed code in the failing path).
Example:
13:58 UTC | PR !4567 "Refactor token rotation" merged by @alice intoauth-service| [PR !4567](...) | [VERIFIED]
Sort the combined event list ascending by timestamp. Within the same timestamp (down to the second), sort by source priority: tracker state change > PR merge > chat message > Datadog log. This ordering reflects "the team's record of what changed" first and "what was happening in the system" second.
Dedupe near-identical entries: when two Datadog log entries have the same service, level, and message-prefix within a 60-second window, collapse them into one entry with a count suffix ((× 47 occurrences in the next 60 seconds)). This prevents a noisy log channel from drowning out the real timeline.
Output a markdown table with these exact columns (in this order):
| Time (UTC) | Event | Source | Tag |
|---|
Lead the output with a one-line preamble naming the in-scope window and any pools that came back empty:
Timeline for incident
WI #12345(14:32 UTCto16:08 UTC). Datadog returned no results; the timeline is built from chat, tracker, and merged PRs only.
Append a one-line summary after the table when more than one event ran in parallel (same minute, different sources):
Multiple sources captured events at
14:32 UTC; the table preserves them in source-priority order.
When no evidence was passed in at all (every pool empty), output a single-row table with one row noting the empty input and the [UNKNOWN] tag, and a preamble explaining that the postmortem will need to be built from manual recall.
Always render as a single markdown table with the four columns shown above, no nesting, no extra structural elements, no JSON. The agent's Phase 4 (postmortem-writer) consumes the table directly into the postmortem's "Timeline (UTC)" section.
Examples of well-formed entries (mixed AzDO and Jira to show portability):
| Time (UTC) | Event | Source | Tag |
|---|---|---|---|
| 13:58 | PR !4567 "Refactor token rotation" merged by @alice into auth-service | PR !4567 | [VERIFIED] |
| 14:32 | INC-456 created by @oncall: "Payment processing outage for US properties" | INC-456 | [VERIFIED] |
| 14:32 | ERROR payments-api: Stripe::APIConnectionError "Connection refused (errno: ECONNREFUSED)" (× 47 occurrences in the next 60 seconds) | Datadog | [VERIFIED] |
| 14:35 | @alice in #incident-payments: "PagerDuty alert just fired for the payments service" | chat thread | [VERIFIED] |
| 14:42 | @bob in #incident-payments: "Reverting !4567 now" | chat thread | [VERIFIED] |
| 14:48 | PR !4568 "Revert PR !4567" merged by @bob into auth-service | PR !4568 | [VERIFIED] |
| 16:08 | INC-456 transitioned Active -> Resolved by @bob | INC-456 | [VERIFIED] |
These adjust the output without changing the column layout.
... (15 events omitted; see source links for full sequence) .... The truncated section preserves chronological order on both sides of the omission.YYYY-MM-DD HH:MM instead of HH:MM so the day is unambiguous. Include a date-change row between days: --- 2026-04-30 ---.(out-of-window) to the description.These apply to all text the skill produces (descriptions and preamble lines).