
Premortem
- 27 installs
- 6 repo stars
- Updated July 22, 2026
- julianobarbosa/claude-code-skills
Helps with ai & agent building tasks.
About
premortem is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- premortem
- AI & Agent Building
- AI-coding skill
Premortem by the numbers
- 27 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #9,571 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/julianobarbosa/claude-code-skills --skill premortemAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 27 |
|---|---|
| repo stars | ★ 6 |
| Last updated | July 22, 2026 |
| Repository | julianobarbosa/claude-code-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Premortem
Imagine the plan already failed, then explain why. This "prospective hindsight" tense-shift (Klein, HBR 2007) generates ~30% more failure causes than asking "what could go wrong?" — and the causes are more specific. The skill turns that mechanism into a repeatable run that ends in a revised plan, not just a list of worries.
Workflow Routing
| Trigger | Workflow |
|---|---|
| "premortem this", "run a premortem", "what could kill this", high-stakes plan | Workflows/RunPremortem.md (full: parallel deep-dive agents) |
| "quick premortem", small/personal decision, fast gut-check, thin context | Workflows/QuickPremortem.md (solo single-pass, no fan-out) |
| "update the premortem skill", add/fix a workflow | Workflows/Update.md |
Default to `RunPremortem` for anything with real stakes. Drop to QuickPremortem only when the decision is small or the user explicitly wants speed.
The Mechanism (don't skip the framing)
The entire technique is one move: state that failure has already happened, with certainty, and ask what caused it. Everything else is delivery. If a step doesn't help the user inhabit "it already failed," cut it. Full evidence and citations: References/Methodology.md.
Quick Reference
- Frame in past tense. "It's [horizon]. [The plan] has failed. Here's why." Not "could fail."
- Generate causes independently first. In
RunPremortem, parallel agents must NOT see each
other's output — this is the anti-anchoring safeguard, and it is load-bearing.
- Demand plan-specific causes. Reject generic risks ("timeline slips"). Ground every cause in
actual plan details.
- Always land on action. Each retained risk → a mitigation + an early-warning signal. End with
a revised plan and a pre-launch checklist. A premortem with no follow-through is theater.
- Markdown is canonical. The transcript (
.md) is the record. HTML is an optional visual
artifact via Tools/GenerateReport.ts --html, never the primary output.
When NOT to run a premortem
- Vague concepts with no concrete plan — gather the plan first, or you'll generate generic risk.
- Decisions already irreversibly made — nothing to revise; value is low.
- Factual questions or creative feedback — wrong tool.
- Attacking an idea/argument in the abstract →
RedTeam. Current multi-view debate →Council.
Tools
Tools/GenerateReport.ts— turns a findings JSON (schema inReferences/Templates.md) into a
markdown report (default) or a self-contained HTML report (--html). Run with bun. See Tools/GenerateReport.help.md.
Gotchas
The highest-density part of this skill. Add to it after every run that surprises you.
- The "30%" stat is about quantity, not correctness. The 1989 Mitchell/Russo/Pennington study
found prospective hindsight produces ~30% more reasons generated — NOT 30% better at identifying the _correct_ reasons. Klein's HBR paraphrase ("correctly identify") overstates it. Never tell a user the premortem makes them "30% more accurate." It makes them more _prolific_ and _specific_. Citing it wrong makes the whole analysis look sloppy.
- Anchoring kills the run. If you generate causes sequentially (or let one agent see another's
output), the first failure named frames everything after it. Generate independently, then merge. This is why RunPremortem fans out parallel agents and explicitly forbids cross-talk.
- Generic risks are the #1 quality failure. "Budget overruns," "team gets distracted,"
"market shifts" apply to every plan and help no one. If a cause would survive find-and-replace of the subject, it's too generic — force it to cite a real plan detail.
- Run it BEFORE commitment. A premortem after the money is spent and the team is emotionally
bought in becomes a ritual. Its value is in _changing_ the plan, so it needs a changeable plan.
- Don't confuse it with RedTeam or Council. Premortem = imagined _future failure_ of a
_concrete plan_, ending in a revised plan. RedTeam = adversarial attack on an arbitrary idea. Council = multiple _current_ perspectives debating. Overlapping vocabulary, different mechanisms.
- Thin context → generic output. If you can't state (1) what's being premortemed in one
sentence, (2) who's affected, (3) what success means, STOP and ask one question at a time. Don't generate failures from nothing — that produces exactly the generic risk this technique exists to avoid.
- Failure ≠ pessimism. The output is specific causal stories with mitigations, not a doom mood.
If the run reads as "everything is risky," it failed.
- Likelihood and severity are different axes. The _most likely_ failure and the _most dangerous_
failure are usually not the same one. Surface both — that distinction is often the insight.
Customization
Before executing, check for user customizations at ~/.claude/PAI/USER/SKILLCUSTOMIZATIONS/Premortem/. If PREFERENCES.md exists, load and apply it (e.g. preferred default horizon, report theme, number of failure agents). These override defaults. If the directory does not exist, proceed with skill defaults. Do not put private/identity content in this skill body — it belongs in SKILLCUSTOMIZATIONS.
🚨 Voice Notification (run on invocation)
curl -s -X POST http://localhost:31337/notify \
-H "Content-Type: application/json" \
-d '{"message": "Running the WORKFLOWNAME workflow in the Premortem skill to ACTION"}' \
> /dev/null 2>&1 &Then output: Running the **WorkflowName** workflow in the **Premortem** skill to ACTION...
Examples
Example 1: Full premortem on a launch
User: "Premortem our paid-newsletter launch next month"
→ RunPremortem: gather context (what/who/success) → frame "it's 6 months out, the launch failed"
→ generate plan-specific causes → fan out 1 agent per cause (independent) → synthesize
most-likely + most-dangerous + hidden assumption + revised plan + checklist
→ write transcript .md, optionally GenerateReport.ts --html → 3-sentence chat summaryExample 2: Quick solo gut-check
User: "quick premortem on accepting this contractor role"
→ QuickPremortem: single-pass, no agents → past-tense framing → 5-8 specific causes with
likelihood/severity, hidden assumption, top mitigations → short markdown, no HTMLExample 3: Disambiguation from RedTeam
User: "poke holes in my argument that we should go remote-first"
→ This is attacking an ARGUMENT, not a plan-with-stakes → suggest RedTeam instead, or
reframe: "if you want to premortem the remote-first *rollout plan*, I can do that."Execution Log
After completing any workflow, append a single JSONL entry:
echo '{"ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","skill":"Premortem","workflow":"WORKFLOW_USED","input":"8_WORD_SUMMARY","status":"ok|error","duration_s":SECONDS}' >> ~/.claude/PAI/MEMORY/SKILLS/execution.jsonlPremortem — Methodology & Evidence
Reference material for the Premortem skill. Loaded on demand by the workflows. This file is the why behind the protocol; the workflows are the how.
---
1. Origins & Evidence
The premortem was named and popularized by cognitive psychologist Gary Klein in his September 2007 Harvard Business Review article "Performing a Project Premortem" (reprint F0709A). It rests on a single empirical foundation Klein cites:
"Research conducted in 1989 by Deborah J. Mitchell, of the Wharton School; Jay Russo,
of Cornell; and Nancy Pennington, of the University of Colorado, found that prospective
hindsight — imagining that an event has already occurred — increases the ability to
correctly identify reasons for future outcomes by 30%."
The underlying study: *Mitchell, D. J., Russo, J. E., & Pennington, N. (1989). "Back to the Future: Temporal Perspective in the Explanation of Events." Journal of Behavioral Decision Making, 2(1), 25–38* (doi:10.1002/bdm.3960020103).
⚠️ Citation-accuracy correction (important). The 1989 study measured that framing an
event in the past tense ("the event happened") rather than future/conditional
increased the number of reasons generated by roughly 30%. It did not measure that
the reasons were correctly identified. Klein's gloss ("correctly identify") subtly
overstates the finding. Use the defensible claim: "~30% more reasons generated." Never
tell a user the premortem makes them "30% better at finding the right reasons" — that is
not what the data shows, and stating it makes the whole analysis look sloppy.
Daniel Kahneman endorsed the premortem in Thinking, Fast and Slow (2011) as a partial remedy for overconfidence and the illusion of validity — which is largely why it entered mainstream business vocabulary.
Later support: Veinott, Klein & Wiggins (2010) found a premortem condition reduced overconfidence more reliably than plain critique, pros/cons, or cons-only conditions. The evidence base is still thin — be honest about that rather than overselling.
Organizations including Google, Goldman Sachs, and Procter & Gamble use premortems for major decisions.
---
2. The Mechanism — why it works
The premortem inverts the usual question. Instead of prospective foresight ("what could go wrong?"), it uses prospective hindsight: you stand at a fixed future point where failure has already happened with certainty and explain why.
Klein: "the premortem operates on the assumption that the 'patient' has died, and so asks what did go wrong."
Three cognitive effects:
- Overconfidence / planning fallacy — certainty of the outcome forces concrete causal
storytelling rather than vague hedging. Past-tense narrative is more specific than an abstract risk list.
- Groupthink & social pressure — there is "silent pressure not to surface doubts." The
premortem makes dissent the assigned task, so people compete on the quality of the problems they raise.
- Legitimizing the doubter — it gives knowledgeable skeptics permission to speak without
seeming disloyal.
This tense-shift is the entire mechanism. Every design choice in this skill serves it. If a step does not help the user inhabit "it already failed," it is decoration.
---
3. Canonical Process (Klein's facilitation)
The original group protocol, adapted in this skill for AI-assisted runs:
1. Set the scene. State explicitly: assume the project has failed — spectacularly. 2. Write independently first. Everyone lists every reason for the failure before anyone shares. This independent-then-share step is the anti-anchoring safeguard — it is load-bearing, not optional. (In the AI version, parallel agents must not see each other's output.) 3. Share round-robin. Each person reads one distinct reason until all are recorded; starting with the leader models candor. 4. Review & strengthen. Afterward, review the list for ways to strengthen the plan. 5. Revisit periodically — the list becomes an early-warning radar during execution.
Klein notes it can take as little as 20–30 minutes. Practitioner guidance: small cross-functional groups (~4–8) so every voice is heard; run it during planning, before commitment.
---
4. Variations & Adjacent Techniques
| Technique | Relationship to premortem |
|---|---|
| Pre-parade / "pre-mortem positive" | Imagine wild success and ask what made it happen (backcasting). Pairs with the failure version but can re-inflate optimism. |
| Postmortem | Same diagnostic logic, opposite timing. Premortem improves the plan; postmortem dissects the corpse. |
| Red teaming | Adversarial, externally staffed, resource-heavy. The premortem is fast, internal, and structured imagination. |
| SWOT | A balanced static inventory. The premortem is failure-focused and narrative — it surfaces risks SWOT's boxes flatten. |
| "Kill the company" (Stalk & Lachenauer) | The same prospective-hindsight engine scaled to existential/strategic threats. |
| Scenario planning / Tetlock-style judgment | Prospective hindsight underpins structured forecasting. |
---
5. Failure Modes & Gotchas (when running a premortem)
- Anchoring on the first failure named — skipping independent generation lets the
loudest voice (or the first agent) set the frame. Generate independently, then merge.
- Sandbagging / theater — going through the motions, or producing findings nobody owns.
A premortem with no mitigation follow-through is worthless.
- Running it too late — after psychological/financial commitment it becomes ritual, not
redirection. Run it while the plan is still changeable.
- Generic risks — "the timeline slips," "budget overruns." Plan-agnostic risks signal
weak engagement. Demand plan-specific, concrete causal chains.
- Irreversible decisions — value is low when nothing can change. Best applied where the
plan can still be revised.
- Confusing it with general pessimism — the goal is specific, actionable causal stories,
not a bad mood.
---
6. Practitioner Best Practices
- Make each failure specific and grounded — a concrete causal chain, not a category.
- Score it — assign likelihood × severity to prioritize.
- Derive early-warning indicators — for each top risk, define the observable signal that
it is materializing.
- Convert to mitigations + a pre-launch checklist — every retained risk gets an owner
and a preventive/contingent action.
- Facilitation — ideally a neutral facilitator; the leader speaks first to model candor
but should not dominate.
- Document and revisit — keep the risk list live; check it at milestones.
---
Sources
- Klein, G. (2007). "Performing a Project Premortem." Harvard Business Review, Sept 2007. <https://hbr.org/2007/09/performing-a-project-premortem>
- Mitchell, D. J., Russo, J. E., & Pennington, N. (1989). "Back to the Future: Temporal Perspective in the Explanation of Events." Journal of Behavioral Decision Making, 2(1), 25–38. <https://onlinelibrary.wiley.com/doi/10.1002/bdm.3960020103>
- Klein, G. (2021). "The Pre-Mortem Method." Psychology Today. <https://www.psychologytoday.com/us/blog/seeing-what-others-dont/202101/the-pre-mortem-method>
- Veinott, Klein & Wiggins (2010). "Evaluating the Effectiveness of the PreMortem Technique on Plan Confidence."
- Kahneman, D. (2011). Thinking, Fast and Slow.
- Jason Collins — evidence critique of the "30%" claim. <https://corporate.jasoncollins.blog/premortem>
Premortem — Templates
Copy-paste scaffolds for a premortem run: the findings JSON (consumed by Tools/GenerateReport.ts), the markdown transcript, and the per-agent prompt.
---
1. Findings JSON schema (contract with GenerateReport.ts)
This is the exact shape Tools/GenerateReport.ts consumes. Field names must match.
{
"subject": "One-line description of what was premortemed",
"successDefinition": "What winning looks like (optional)",
"stakeholders": "Who is affected (optional)",
"horizon": "6 months from now",
"timestamp": "2026-05-29T15:00:00Z",
"failures": [
{
"id": "F1",
"title": "Short failure name",
"likelihood": "low | medium | high",
"severity": "low | medium | high",
"story": "2-3 paragraph past-tense narrative of how this specific failure played out, grounded in plan details.",
"assumption": "One sentence naming the unquestioned premise that enabled this failure.",
"warningSigns": [
"Observable, measurable early signal #1",
"Observable, measurable early signal #2"
],
"mitigation": "Concrete, specific action that prevents or detects this failure mode.",
"owner": "Who is accountable for the mitigation (optional but strongly recommended)."
}
],
"synthesis": {
"mostLikely": "The probable failure scenario given the plan details.",
"mostDangerous": "The scenario causing maximum damage, even if less probable.",
"hiddenAssumption": "The single biggest unexamined assumption underlying the whole plan.",
"revisedPlan": [
"Specific, actionable modification #1",
"Specific, actionable modification #2"
],
"preLaunchChecklist": [
"Concrete verification step #1",
"Concrete verification step #2"
]
}
}Field notes
subject,failures,synthesisare required.successDefinition,stakeholders,
horizon, timestamp are optional (timestamp auto-fills to generation time if absent; the others render only if present).
likelihood/severity∈low | medium | high— drives the report's badges and the
most-likely / most-dangerous synthesis.
owneris optional but strongly recommended — an un-owned mitigation rarely happens. A
premortem that ends in a prioritized, owned action list produces decisions; one that ends in a list of fears produces anxiety. Prioritize failures by likelihood × severity.
warningSigns,revisedPlan,preLaunchChecklistare arrays of strings.
Render: bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts findings.json --out report.md HTML: bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts findings.json --html --out report.html
---
2. Markdown transcript template
premortem-transcript-<timestamp>.md — the canonical, human-readable record.
# Premortem Transcript — <subject>
> Horizon: <e.g. 6 months from now> · Generated: <ISO-8601>
## Context
- **What was premortemed:** <one sentence>
- **Stakeholders:** <who is affected>
- **Success definition:** <what winning looks like — failure is its inversion>
## Frame
It is <horizon>. <The plan> has failed. The following explains what went wrong.
## Raw Failure Causes (independent generation)
1. <plan-specific cause>
2. <plan-specific cause>
...
## Deep Dives
### F1 — <title> (likelihood: <l> · severity: <s>)
**Failure story.** <2-3 paragraphs>
**Hidden assumption.** <one sentence>
**Early-warning signs.** <1-2 observable signals>
**Mitigation.** <concrete action> · **Owner.** <who is accountable>
### F2 — <title> ...
## Synthesis
- **Most likely failure:** <...>
- **Most dangerous failure:** <...>
- **Biggest hidden assumption:** <...>
- **Revised plan:**
1. <change>
- **Pre-launch checklist:**
- [ ] <verification step>---
3. Per-agent deep-dive prompt (for the parallel fan-out in RunPremortem)
Give each agent exactly one failure cause. Agents run independently (anti-anchoring) — never let them see each other's output.
You are analyzing ONE failure mode of this plan. The plan has ALREADY FAILED — write in
past tense, with certainty, not "could."
PLAN CONTEXT:
<subject, success definition, stakeholders, key plan details>
YOUR ASSIGNED FAILURE CAUSE:
<the single cause>
Produce, in under 300 words, no hedging:
1. FAILURE STORY — 2-3 short paragraphs showing how this specific failure played out, using
real plan details.
2. HIDDEN ASSUMPTION — one sentence naming the unquestioned premise that enabled it.
3. EARLY-WARNING SIGNS — 1-2 observable, measurable signals that this mode is emerging.
4. LIKELIHOOD and SEVERITY — each one of: low | medium | high.
5. MITIGATION — one concrete, specific action (not "monitor closely").
6. OWNER — who should be accountable for the mitigation (role is fine if no name).
Return JSON matching the failure object schema: {id,title,likelihood,severity,story,
assumption,warningSigns[],mitigation,owner}.GenerateReport.ts — Help
Turns a premortem findings JSON file into a report. Markdown by default; self-contained HTML with --html. Runs on the Bun runtime, no external dependencies.
Usage
bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts <findings.json> [--html] [--out <path>]| Flag | Effect |
|---|---|
| (none) | Render a clean markdown report to stdout. |
--out <path> | Write the report to <path> instead of stdout. |
--html | Render a self-contained HTML report (dark theme, inline CSS, no external assets). |
--html --out <path> | Write the HTML report to <path>. |
--html (no --out) | Write to premortem-report-<timestamp>.html in the cwd and print the path. |
Examples
# Markdown to stdout
bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts findings.json
# Markdown to a file
bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts findings.json --out report.md
# Visual HTML report
bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts findings.json --html --out report.htmlInput
A findings JSON file matching the schema in References/Templates.md §1. Required keys: subject, failures[], synthesis. Optional: successDefinition, stakeholders, horizon, timestamp. Each failure: {id, title, likelihood, severity, story, assumption, warningSigns[], mitigation, owner?}.
Behavior
- Validates the input shape; on a missing file or malformed JSON it prints a helpful error to
stderr and exits 1. Success exits 0.
- The synthesis (most-likely, most-dangerous, hidden assumption, revised plan, pre-launch
checklist) is pinned at the top; one card/section per failure with likelihood + severity badges.
- HTML output escapes all user-supplied strings.
Note
Markdown is the canonical premortem record (PAI convention). Use --html only when a user wants a visual or shareable artifact.
#!/usr/bin/env bun
import { readFileSync, writeFileSync, writeSync } from "node:fs";
import { join, resolve } from "node:path";
type RiskLevel = "low" | "medium" | "high";
interface Failure {
id: string; title: string; likelihood: RiskLevel; severity: RiskLevel; story: string;
assumption: string; warningSigns: string[]; mitigation: string; owner?: string;
}
interface Synthesis {
mostLikely: string; mostDangerous: string; hiddenAssumption: string;
revisedPlan: string[]; preLaunchChecklist: string[];
}
interface PremortemData {
subject: string; successDefinition?: string; stakeholders?: string; horizon?: string;
timestamp?: string; failures: Failure[]; synthesis: Synthesis;
}
interface CliOptions { inputPath: string; html: boolean; outPath?: string; }
const usage = (): string => "Usage: bun GenerateReport.ts <findings.json> [--html] [--out <path>]";
const fail = (message: string): never => { writeSync(2, `${message}\n`); process.exit(1); };
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
const isString = (value: unknown): value is string => typeof value === "string";
const isRiskLevel = (value: unknown): value is RiskLevel => value === "low" || value === "medium" || value === "high";
const isStringArray = (value: unknown): value is string[] => Array.isArray(value) && value.every((item: unknown): item is string => isString(item));
const safeTimestamp = (now: Date): string => now.toISOString().replace(/[:.]/g, "-");
const escapeHtml = (value: string): string => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
const optionalText = (label: string, value?: string): string => typeof value === "string" && value.trim() !== "" ? `- **${label}:** ${value}` : "";
const optionalMeta = (label: string, value?: string): string => typeof value === "string" && value.trim() !== "" ? `<div><strong>${escapeHtml(label)}:</strong> ${escapeHtml(value)}</div>` : "";
function parseArgs(args: string[]): CliOptions {
let inputPath: string | undefined;
let html = false;
let outPath: string | undefined;
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
if (arg === "--html") {
html = true;
} else if (arg === "--out") {
const next = args[index + 1];
if (next === undefined || next.startsWith("--")) {
fail(`Missing value for --out.\n${usage()}`);
} else {
outPath = next;
index += 1;
}
} else if (arg.startsWith("--")) {
fail(`Unknown flag: ${arg}\n${usage()}`);
} else if (inputPath === undefined) {
inputPath = arg;
} else {
fail(`Unexpected extra argument: ${arg}\n${usage()}`);
}
}
if (inputPath === undefined) {
fail(`Missing required <findings.json> path.\n${usage()}`);
} else {
return { inputPath, html, outPath };
}
}
function expectString(value: unknown, path: string, errors: string[]): value is string {
if (isString(value)) { return true; } else { errors.push(`${path} must be a string`); return false; }
}
function expectOptionalString(value: unknown, path: string, errors: string[]): value is string | undefined {
if (value === undefined) { return true; }
if (isString(value)) { return true; } else { errors.push(`${path} must be a string when provided`); return false; }
}
function expectRiskLevel(value: unknown, path: string, errors: string[]): value is RiskLevel {
if (isRiskLevel(value)) { return true; } else { errors.push(`${path} must be one of: low, medium, high`); return false; }
}
function expectStringArray(value: unknown, path: string, errors: string[]): value is string[] {
if (isStringArray(value)) { return true; } else { errors.push(`${path} must be an array of strings`); return false; }
}
function isFailure(value: unknown, path: string, errors: string[]): value is Failure {
if (isRecord(value)) {
return [
expectString(value.id, `${path}.id`, errors),
expectString(value.title, `${path}.title`, errors),
expectRiskLevel(value.likelihood, `${path}.likelihood`, errors),
expectRiskLevel(value.severity, `${path}.severity`, errors),
expectString(value.story, `${path}.story`, errors),
expectString(value.assumption, `${path}.assumption`, errors),
expectStringArray(value.warningSigns, `${path}.warningSigns`, errors),
expectString(value.mitigation, `${path}.mitigation`, errors),
expectOptionalString(value.owner, `${path}.owner`, errors),
].every(Boolean);
} else {
errors.push(`${path} must be an object`);
return false;
}
}
function isSynthesis(value: unknown, path: string, errors: string[]): value is Synthesis {
if (isRecord(value)) {
return [
expectString(value.mostLikely, `${path}.mostLikely`, errors),
expectString(value.mostDangerous, `${path}.mostDangerous`, errors),
expectString(value.hiddenAssumption, `${path}.hiddenAssumption`, errors),
expectStringArray(value.revisedPlan, `${path}.revisedPlan`, errors),
expectStringArray(value.preLaunchChecklist, `${path}.preLaunchChecklist`, errors),
].every(Boolean);
} else {
errors.push(`${path} must be an object`);
return false;
}
}
function isPremortemData(value: unknown, errors: string[]): value is PremortemData {
if (isRecord(value)) {
const hasFailures = Array.isArray(value.failures) && value.failures.length > 0;
if (!hasFailures) { errors.push("failures must be a non-empty array"); }
const failuresValid = hasFailures
? value.failures.map((failure: unknown, index: number) => isFailure(failure, `failures[${index}]`, errors)).every(Boolean)
: false;
return [
expectString(value.subject, "subject", errors),
expectOptionalString(value.successDefinition, "successDefinition", errors),
expectOptionalString(value.stakeholders, "stakeholders", errors),
expectOptionalString(value.horizon, "horizon", errors),
expectOptionalString(value.timestamp, "timestamp", errors),
failuresValid,
isSynthesis(value.synthesis, "synthesis", errors),
].every(Boolean);
} else {
errors.push("root value must be an object");
return false;
}
}
function renderMarkdown(data: PremortemData): string {
const synthesis = [
"## Synthesis", "",
`- **Most Likely Failure:** ${data.synthesis.mostLikely}`,
`- **Most Dangerous Failure:** ${data.synthesis.mostDangerous}`,
`- **Hidden Assumption:** ${data.synthesis.hiddenAssumption}`, "",
"### Revised Plan", "", ...data.synthesis.revisedPlan.map((item: string) => `- ${item}`), "",
"### Pre-Launch Checklist", "", ...data.synthesis.preLaunchChecklist.map((item: string) => `- ${item}`),
];
const failures = data.failures.flatMap((failure: Failure) => [
`## ${failure.id}: ${failure.title}`, "",
`- **Likelihood:** ${failure.likelihood}`,
`- **Severity:** ${failure.severity}`, "",
"### Story", "", failure.story, "",
"### Hidden Assumption", "", failure.assumption, "",
"### Warning Signs", "", ...failure.warningSigns.map((sign: string) => `- ${sign}`), "",
"### Mitigation", "", failure.mitigation, "",
...(failure.owner && failure.owner.trim() !== "" ? [`**Owner:** ${failure.owner}`, ""] : []),
]);
return [
`# Premortem Report: ${data.subject}`, "",
`- **Timestamp:** ${data.timestamp}`,
optionalText("Success Definition", data.successDefinition),
optionalText("Stakeholders", data.stakeholders),
optionalText("Horizon", data.horizon),
"", ...synthesis, "", ...failures, "---", `Subject: ${data.subject}`, `Timestamp: ${data.timestamp}`,
].filter((line: string) => line !== "").join("\n");
}
function renderHtml(data: PremortemData): string {
const badge = (label: string, level: RiskLevel): string => `<span class="badge ${level}">${escapeHtml(label)}: ${escapeHtml(level)}</span>`;
const list = (items: string[]): string => `<ul>${items.map((item: string) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>`;
const cards = data.failures.map((failure: Failure) => `<article class="card"><div class="top"><h2>${escapeHtml(failure.id)}: ${escapeHtml(failure.title)}</h2><div class="badges">${badge("Likelihood", failure.likelihood)}${badge("Severity", failure.severity)}</div></div><section><h3>Story</h3><div class="story">${escapeHtml(failure.story)}</div></section><section><h3>Hidden Assumption</h3><p>${escapeHtml(failure.assumption)}</p></section><section><h3>Warning Signs</h3>${list(failure.warningSigns)}</section><section><h3>Mitigation</h3><p>${escapeHtml(failure.mitigation)}</p>${failure.owner && failure.owner.trim() !== "" ? `<p class="owner"><strong>Owner:</strong> ${escapeHtml(failure.owner)}</p>` : ""}</section></article>`).join("");
const css = `:root{color-scheme:dark;--bg:#0a0e1a;--panel:#131a2b;--panel2:#1a2338;--text:#edf2ff;--muted:#9fb0d1;--border:#2a3550;--low:#1f9d68;--medium:#d39b2a;--high:#d04f5f}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font:16px/1.6 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}.wrap{max-width:1100px;margin:0 auto;padding:32px 20px 48px}.hero,.card,footer{background:linear-gradient(180deg,rgba(255,255,255,.03),rgba(255,255,255,.01));border:1px solid var(--border);border-radius:18px}.hero{padding:24px;margin-bottom:24px;box-shadow:0 18px 40px rgba(0,0,0,.28)}.meta,.lists,.grid,section{display:grid;gap:10px}.grid{gap:20px}.card{padding:22px}.top{display:flex;gap:16px;justify-content:space-between;align-items:flex-start;margin-bottom:16px}.badges{display:flex;gap:10px;flex-wrap:wrap}.badge{border-radius:999px;padding:6px 10px;font-size:.9rem;font-weight:700;border:1px solid transparent}.low{background:rgba(31,157,104,.18);color:#7be0b0;border-color:rgba(31,157,104,.34)}.medium{background:rgba(211,155,42,.18);color:#ffd67c;border-color:rgba(211,155,42,.34)}.high{background:rgba(208,79,95,.18);color:#ff9cab;border-color:rgba(208,79,95,.34)}h1,h2,h3,p,ul{margin:0}h1{font-size:2rem;line-height:1.2}h2{font-size:1.35rem;line-height:1.2}h3{font-size:1rem;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}ul{padding-left:20px}.story{white-space:pre-wrap;background:var(--panel2);border-radius:12px;padding:14px}footer{margin-top:24px;padding:16px 20px;color:var(--muted)}@media (max-width:720px){.top{flex-direction:column}}`;
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Premortem Report - ${escapeHtml(data.subject)}</title><style>${css}</style></head><body><main class="wrap"><section class="hero"><h1>${escapeHtml(data.subject)}</h1><div class="meta"><div><strong>Timestamp:</strong> ${escapeHtml(data.timestamp)}</div>${optionalMeta("Success Definition", data.successDefinition)}${optionalMeta("Stakeholders", data.stakeholders)}${optionalMeta("Horizon", data.horizon)}</div><div class="lists"><section><h3>Most Likely Failure</h3><p>${escapeHtml(data.synthesis.mostLikely)}</p></section><section><h3>Most Dangerous Failure</h3><p>${escapeHtml(data.synthesis.mostDangerous)}</p></section><section><h3>Hidden Assumption</h3><p>${escapeHtml(data.synthesis.hiddenAssumption)}</p></section><section><h3>Revised Plan</h3>${list(data.synthesis.revisedPlan)}</section><section><h3>Pre-Launch Checklist</h3>${list(data.synthesis.preLaunchChecklist)}</section></div></section><section class="grid">${cards}</section><footer>Subject: ${escapeHtml(data.subject)} | Timestamp: ${escapeHtml(data.timestamp)}</footer></main></body></html>`;
}
function loadPremortemData(inputPath: string): PremortemData {
let rawText = "";
try { rawText = readFileSync(inputPath, "utf8"); }
catch (error: unknown) { fail(`Failed to read input file "${inputPath}": ${error instanceof Error ? error.message : "unknown read error"}`); }
let parsed: unknown;
try { parsed = JSON.parse(rawText); }
catch (error: unknown) { fail(`Invalid JSON in "${inputPath}": ${error instanceof Error ? error.message : "unknown parse error"}`); }
const errors: string[] = [];
if (isPremortemData(parsed, errors)) { return parsed; } else { fail(`Invalid findings JSON in "${inputPath}": ${errors.join("; ")}`); }
}
function writeTarget(path: string, content: string): void {
if (path === "/dev/stdout") {
writeSync(1, content);
} else if (path === "/dev/stderr") {
writeSync(2, content);
} else {
writeFileSync(path, content, "utf8");
}
}
function outputResult(content: string, options: CliOptions): void {
try {
if (options.html && options.outPath === undefined) {
const filePath = resolve(join(process.cwd(), `premortem-report-${safeTimestamp(new Date())}.html`));
writeTarget(filePath, content);
writeSync(1, `${filePath}\n`);
} else if (options.outPath !== undefined) {
writeTarget(options.outPath, content);
} else {
writeSync(1, content);
}
} catch (error: unknown) {
const target = options.html && options.outPath === undefined ? "generated HTML report" : options.outPath ?? "stdout";
fail(`Failed to write output to ${target}: ${error instanceof Error ? error.message : "unknown write error"}`);
}
}
function main(): void {
const options = parseArgs(Bun.argv.slice(2));
const data = loadPremortemData(options.inputPath);
if (data.timestamp === undefined || data.timestamp.trim() === "") { data.timestamp = new Date().toISOString(); }
outputResult(options.html ? renderHtml(data) : renderMarkdown(data), options);
}
main();
Workflow: QuickPremortem
The lightweight premortem — a single-pass, solo analysis with no parallel agents. Use for small or personal decisions, fast gut-checks, or when context is thin and a full fan-out would be overkill. Same mechanism (prospective hindsight), a fraction of the cost.
Voice on entry:
curl -s -X POST http://localhost:31337/notify -H "Content-Type: application/json" \
-d '{"message": "Running the QuickPremortem workflow in the Premortem skill for a fast failure check"}' > /dev/null 2>&1 &Then: Running the **QuickPremortem** workflow in the **Premortem** skill for a fast failure check...
---
How it differs from RunPremortem
| QuickPremortem | RunPremortem | |
|---|---|---|
| Cause analysis | Single pass, in one context | One parallel agent per cause |
| Anti-anchoring | Mitigated by generating the full cause list before analyzing any | Enforced by independent agents |
| Output | Short markdown in chat | Full transcript + optional HTML report |
| Use for | Small/personal/fast | High-stakes, needs depth + a record |
Steps
1. Confirm the basics (fast). One sentence: what is being decided, and what does success look like? If you can't state both, ask one question — don't generate from nothing.
2. Frame in past tense. "It's [horizon, default ~6 months out]. [The decision] turned out badly. Here's why." Inhabit the certainty.
3. List every cause first, then analyze. Write 5–8 plan-specific failure causes before elaborating on any of them — this is the solo substitute for the parallel anti-anchoring step. Reject generic risks; each must cite a real detail of the decision.
4. Score and deepen. For each cause give: likelihood (low/med/high), severity (low/med/high), the one hidden assumption behind it, and one concrete mitigation. Keep each tight.
5. Synthesize in three lines. Most-likely failure, most-dangerous failure, and the single biggest hidden assumption — then the top 1–3 changes worth making now.
6. Deliver as short markdown. No HTML, no saved report unless asked. Offer to escalate to RunPremortem if the stakes turn out higher than they looked.
7. Log. Append the execution-log JSONL entry (see SKILL.md → Execution Log).
Gotcha
- If the decision is genuinely high-stakes (irreversible, expensive, reputational), don't shortcut
it — switch to RunPremortem. Quick mode trades depth for speed; spend the depth where the cost of being wrong is high.
Workflow: RunPremortem
The full premortem — parallel deep-dive agents, synthesis, and a written record. Use for any plan, launch, hire, pricing change, partnership, or strategic decision where the cost of being wrong is high and the plan is still changeable.
Voice on entry:
curl -s -X POST http://localhost:31337/notify -H "Content-Type: application/json" \
-d '{"message": "Running the RunPremortem workflow in the Premortem skill to stress-test the plan"}' > /dev/null 2>&1 &Then: Running the **RunPremortem** workflow in the **Premortem** skill to stress-test the plan...
---
Step 0 — Context gathering & sufficiency gate (BLOCKING)
A premortem on thin context produces generic risk — exactly what the technique exists to avoid. First, scan existing context (~30s): the conversation, attached materials, and workspace planning files (CLAUDE.md, briefs, docs). Then confirm three things:
1. Clarity — what is being premortemed? State it in one sentence. 2. Stakeholders — who is affected? (audience, customers, team) 3. Success definition — what does winning look like? (failure is its inversion)
If any is missing and you cannot infer it, ask for the single most critical gap, one question at a time. Do not make the user fill a form. Do not proceed to Step 1 until all three are known.
Step 1 — Frame the failure (the mechanism)
State the premise explicitly and in past tense:
"It's [horizon — default 6 months from now]. [The plan] has failed. We're examining what went
wrong."
This is not optional flavor — the tense-shift is the entire technique. Carry this framing into every subsequent prompt: failure is certain; we explain it, we don't predict it.
Step 2 — Generate raw failure causes (independently)
Generate every genuine, plan-specific reason the plan failed. Each cause must be:
- Specific to this plan — would not survive find-and-replace of the subject.
- Grounded in the actual plan details from Step 0.
- A real threat — not trivial, not absurdly unlikely.
Aim for comprehensive coverage (typically 5–12), not padding. Do not yet analyze them.
Step 3 — Deep-dive fan-out (PARALLEL, INDEPENDENT)
Spawn one agent per failure cause, all at once, in a single message (Agent tool, or parallel() in a Workflow). Agents must run independently — never let one see another's output. This is the anti-anchoring safeguard from Klein's protocol; sequential analysis lets the first cause frame the rest.
Give each agent exactly one cause and the per-agent prompt from References/Templates.md §3. Each returns JSON: {id, title, likelihood, severity, story, assumption, warningSigns[], mitigation, owner?} — under 300 words, past tense, no hedging.
Degrees of freedom: for very large premortems, cap the fan-out (e.g. top 10 causes by stakes)
and say so in the transcript. Never silently drop causes.
Step 4 — Synthesis
Collect all agent results. First prioritize: rank failures by likelihood × severity so the synthesis spends attention where the expected cost is highest. Then produce:
1. Most likely failure — the probable scenario given the plan. 2. Most dangerous failure — maximum damage, even if less probable. (Usually not the same as most-likely — that gap is often the key insight.) 3. Biggest hidden assumption — the single unexamined premise underlying the whole plan. 4. Revised plan — specific, actionable modifications addressing the top failure modes, each with an owner. State "test a $X pilot with N people before committing," not "be careful." An un-owned mitigation rarely happens — assign accountability or the premortem becomes theater. 5. Pre-launch checklist — 3–5 concrete verification steps, each preventing or detecting a failure mode.
Step 5 — Write the record (markdown canonical)
Assemble a findings JSON (schema: References/Templates.md §1) and the markdown transcript (References/Templates.md §2). Save:
premortem-transcript-<timestamp>.md— canonical record (always).
Then, optionally, generate the report artifact:
bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts findings.json --out premortem-report-<timestamp>.md
# visual HTML (opt-in, not canonical):
bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts findings.json --html --out premortem-report-<timestamp>.htmlOnly produce HTML if the user wants a visual/shareable artifact — markdown is the default per PAI.
Step 6 — Chat summary
Give a three-sentence summary in chat: the most-likely failure, the biggest hidden assumption, and the single most important plan revision. Point to the saved transcript.
Step 7 — Log
Append the execution-log JSONL entry (see SKILL.md → Execution Log).
---
Gotchas (workflow-specific)
- If Step 3 agents come back with generic causes, the input plan was too thin — return to Step 0.
- Likelihood and severity are independent; sort by
severityfor "most dangerous," by
likelihood for "most likely."
- Don't let the fan-out balloon cost on a small decision — that's what
QuickPremortemis for.
Workflow: Update
Maintain and extend the Premortem skill itself — add a workflow, fix the tool, refine triggers, or record a new gotcha learned from a real run.
Voice on entry:
curl -s -X POST http://localhost:31337/notify -H "Content-Type: application/json" \
-d '{"message": "Running the Update workflow in the Premortem skill to maintain it"}' > /dev/null 2>&1 &Then: Running the **Update** workflow in the **Premortem** skill to maintain it...
---
When to use
- A real premortem run surfaced a recurring mistake → add it to
## Gotchasin SKILL.md. - A new use-case needs a dedicated workflow → add
Workflows/<Name>.mdand a routing-table row. - The report tool needs a new field or format → edit
Tools/GenerateReport.ts+ its help + the
schema in References/Templates.md (keep all three in sync).
- Triggers over/under-fire → refine the
description(see CreateSkill → OptimizeDescription).
Rules (do not break these)
1. Stay public-safe. This is a TitleCase public skill. No personal names, paths, domains, customers, or credentials in any file. User-specific tweaks go in ~/.claude/PAI/USER/SKILLCUSTOMIZATIONS/Premortem/, never the skill body. 2. Keep structure flat. Only Workflows/, Tools/, References/. Max 2 levels deep. 3. Keep SKILL.md < 500 lines. Push detail into References/; SKILL.md is a routing guide. 4. Schema is a contract. If you change the findings JSON shape, update GenerateReport.ts, GenerateReport.help.md, AND References/Templates.md together, then re-run the dry-run. 5. Citation honesty stays. Never "upgrade" the 30%-reasons-generated gotcha into a stronger claim than the 1989 study supports.
Steps
1. Make the change (workflow / tool / docs). 2. If the tool changed: bun ~/.claude/skills/Premortem/Tools/GenerateReport.ts <sample>.json in both markdown and --html modes — confirm exit 0. 3. Run the public pre-flight grep: rg -i "/Users/[a-z]+/|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}" ~/.claude/skills/Premortem/ — expect zero personal-data matches. 4. Optionally validate with Skill("CreateSkill", "validate skill Premortem"). 5. Append the execution-log JSONL entry.