
Scenario War Room
- 87 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Scenario War Room is a Claude skill that models cascading what-if risk scenarios across all business functions and outputs concrete hedges with costs, owners and deadlines.
About
Scenario War Room is a strategic what-if modeling framework for compound adversity. Instead of single-assumption stress tests, it models how one problem cascades into the next across every business function (finance, revenue, product, engineering, people, operations, market, legal). It uses a 6-step cascade model to name death-spiral patterns and their interruption points, and each scenario produces concrete hedges with costs, owners and deadlines. Leadership uses it for pre-mortems, board 'what's the worst case' questions, and quarterly risk reviews.
- Models cascading what-if scenarios across finance, revenue, product, engineering, people and market
- Uses a 6-step cascade model that maps how one problem triggers the next
- Every scenario produces concrete hedges with costs, owners and deadlines
Scenario War Room by the numbers
- 87 all-time installs (skills.sh)
- Ranked #1,412 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
scenario-war-room capabilities & compatibility
Free; a documentation-driven reasoning framework with helper scripts, no API keys.
- Use cases
- planning · research
- Pricing
- Free
What scenario-war-room says it does
Cross-functional what-if modeling for compound adversity -- shows how one problem cascades into the next.
Every scenario produces concrete hedges with costs, owners, and deadlines.
More than 3 variables creates analysis paralysis, not insight.
npx skills add https://github.com/borghei/claude-skills --skill scenario-war-roomAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 87 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Model compound business risk scenarios and their cascades to produce concrete hedges before major decisions.
Who is it for?
Leadership teams running pre-mortems, quarterly risk reviews, or answering 'what's the worst case' before a major commitment.
Skip if: Single-variable financial sensitivity analysis, routine project risk, or technical failure-mode analysis.
When should I use this skill?
You face complex, multi-variable risk or a strategic decision with major downside and need to model how threats cascade.
What you get
Named cascade scenarios with interruption points and concrete hedges carrying costs, owners and deadlines.
- Cascade scenario map
- Named cascade patterns with interruption points
- Hedges with costs, owners and deadlines
By the numbers
- 6-step cascade model
- maximum of 3 scenario variables
- 8-domain impact map (Finance, Revenue, Product, Engineering, People, Operations, Market, Legal)
Files
Scenario War Room
Tier: POWERFUL Category: C-Level Advisory Tags: scenario planning, war room, risk modeling, cascade effects, contingency planning, pre-mortem, crisis simulation
Overview
The Scenario War Room models cascading what-if scenarios across all business functions. Not single-assumption stress tests -- compound adversity that shows how one problem creates the next, and where the cascade can be interrupted. Every scenario produces concrete hedges with costs, owners, and deadlines.
---
When to Use
- A major risk has probability above 15% and impact above 20% of ARR
- Two or more threats could plausibly co-occur
- A strategic decision has significant downside if wrong
- Board or investors are asking "what's the worst case?"
- Pre-mortem before a major commitment (fundraise, acquisition, market entry)
- Quarterly risk review for leadership team
When NOT to Use
- Single-variable financial sensitivity analysis (use CFO Advisor stress testing)
- Routine project risk assessment (use project management risk frameworks)
- Technical failure mode analysis (use engineering incident planning)
---
Clarify First
Before generating, confirm these inputs. If any is unknown or vague, ASK — do not assume:
- [ ] The (maximum 3) variables that actually keep leadership awake — the entire model is built around these; the wrong variables produce a useless scenario
- [ ] Probability, timeline, and quantified impact for each variable — "revenue drops" is not actionable; "$420K ARR at risk over 60 days" is, and severity levels depend on it
- [ ] Current baseline (ARR, runway in months, headcount) — cascade and severity math (e.g., runway going 14→8 months) requires the starting numbers
- [ ] Company stage — common scenario patterns and what counts as existential differ by stage
Stop rule: ask only the 2-3 that most change the output. If the user says "just draft it," proceed and list your assumptions at the top of the artifact.
---
The 6-Step Cascade Model
Step 1: Define Scenario Variables (Maximum 3)
More than 3 variables creates analysis paralysis, not insight. Choose the 3 that actually keep leadership awake at night.
For each variable, specify:
| Field | Description | Example |
|---|---|---|
| What changes | Specific, quantified | "Top customer (28% of ARR) gives 60-day termination notice" |
| Probability | Your best estimate | 15% |
| Timeline | When it could hit | Within 90 days |
| Detection signal | How you would know it is happening | Sponsor goes dark, usage drops 25% MoM |
Variable Template:
Variable A: [Specific change]
Probability: [X]% | Timeline: [When]
Detection: [Early warning signal]
First-order impact: [Immediate consequence]
Variable B: [Specific change]
Probability: [X]% | Timeline: [When]
Detection: [Early warning signal]
First-order impact: [Immediate consequence]
Variable C: [Specific change]
Probability: [X]% | Timeline: [When]
Detection: [Early warning signal]
First-order impact: [Immediate consequence]Step 2: Domain Impact Mapping
For each variable, assess impact across every business function:
| Domain | Key Questions | Typical Impact Areas |
|---|---|---|
| Finance (CFO) | Burn impact? Runway change? Bridge options? | Cash, runway, covenant triggers |
| Revenue (CRO) | ARR gap? Churn cascade? Pipeline affected? | NRR, expansion, new logo risk |
| Product (CPO) | Roadmap derailed? PMF at risk? Customer need shift? | Delivery timeline, feature priority |
| Engineering (CTO) | Velocity hit? Key person risk? Technical debt impact? | Capacity, architecture, hiring |
| People (CHRO) | Attrition cascade? Hiring freeze? Morale impact? | Retention, culture, bench strength |
| Operations (COO) | Capacity affected? Process breaks? OKR impact? | SLAs, efficiency, scale |
| Market (CMO) | CAC affected? Competitive exposure? Brand risk? | Pipeline generation, positioning |
| Legal/Compliance | Regulatory timeline risk? Contract exposure? | Obligations, deadlines, penalties |
Step 3: Cascade Mapping (The Core)
This is the most valuable step. Map how Variable A triggers consequences that amplify Variable B.
Cascade Diagram:
TRIGGER: Customer churn ($560K ARR)
│
├──▶ CFO: Runway drops 14 → 8 months
│ │
│ └──▶ CHRO: Hiring freeze imposed
│ │
│ └──▶ CTO: 3 open engineering reqs frozen, roadmap slips 2 months
│ │
│ └──▶ CPO: Q4 feature launch delayed → 2 more customers at risk
│ │
│ └──▶ CRO: NRR drops → additional churn risk (DEATH SPIRAL ENTRY)
│
└──▶ CRO: Revenue concentration increases (next largest = 22%)
│
└──▶ Investors: Concentration risk flagged → Series A terms worsenName the cascades explicitly. Common cascade patterns:
| Cascade Pattern | Description | Interruption Point |
|---|---|---|
| Revenue-to-Runway Death Spiral | Customer churn → lower runway → hiring freeze → slower product → more churn | Emergency revenue diversification |
| Key Person Cascade | Star leaves → team morale drops → followers leave → velocity collapses | Retention bonuses before departure |
| Market Squeeze | Competitor raises → price war → margins compress → can't invest in product | Differentiation, not price matching |
| Trust Cascade | Incident → customer concern → churn → press → more churn | Swift, transparent communication |
| Fundraise-Burn Spiral | Miss target → raise delayed → bridge at bad terms → burn cuts → team loss | Parallel fundraise tracks |
Step 4: Severity Matrix
Model three scenarios with increasing severity:
| Scenario | Variables Hit | Definition | Recovery Difficulty |
|---|---|---|---|
| Base | 1 of 3 | Single shock, others don't materialize | Manageable with prepared response |
| Stress | 2 of 3 | Compound shock, cascade begins | Requires significant pivot, board involvement |
| Severe | All 3 | Full cascade, existential territory | Requires emergency action, may need board intervention |
For each severity level, quantify:
BASE SCENARIO (Variable A only):
Runway impact: [X] months → [Y] months
ARR impact: -$[X] ([Y]% of total)
Headcount impact: [freeze / reduction / none]
Timeline to critical: [X] months
Recovery plan: [specific actions]
STRESS SCENARIO (Variables A + B):
Runway impact: [X] months → [Y] months
ARR impact: -$[X] ([Y]% of total)
Headcount impact: [specifics]
Timeline to critical: [X] months
Recovery plan: [specific actions]
SEVERE SCENARIO (All three):
Runway impact: [X] months → [Y] months
ARR impact: -$[X] ([Y]% of total)
Headcount impact: [specifics]
Timeline to critical: [X] months
Existential: [yes/no]
Emergency plan: [specific actions requiring board approval]Step 5: Early Warning Signals (Trigger Points)
Define measurable signals that tell you a scenario is unfolding BEFORE it is confirmed. The value of this exercise is acting early, not reacting late.
Signal Design Criteria:
- Observable (you can actually measure it)
- Leading (appears before the full impact)
- Specific (not just "things feel off")
- Actionable (triggers a specific response)
| Variable | Signal | Threshold | Response |
|---|---|---|---|
| Customer churn | Sponsor stops responding | > 3 weeks silence | Exec escalation, QBR request |
| Customer churn | Usage drops | > 25% MoM decline | CS outreach, value review |
| Fundraise delay | Term sheets | < 3 after 60 days in process | Parallel bridge conversations |
| Fundraise delay | Investor requests | > 30 day DD extension | Reduce burn, extend runway |
| Key person departure | Market compensation | Counter-offer required in last 90 days | Retention package, succession plan |
| Key person departure | External engagement | Engineer presenting at conferences for competitors | Direct conversation, role expansion |
Step 6: Hedging Strategies
For each scenario: actions to take NOW (before the scenario materializes) that reduce impact if it does. Hedges have costs -- the goal is cheap insurance, not paranoia.
Hedge Evaluation Criteria:
| Criterion | Question |
|---|---|
| Cost | What does this hedge cost to implement? |
| Reversibility | Can we undo it if the scenario doesn't happen? |
| Lead time | How long to implement? (Must be shorter than detection-to-impact window) |
| Coverage | Which scenarios does this hedge protect against? |
| Side effects | Does this hedge cause other problems? |
Hedge Table Template:
| Hedge | Cost | Protects Against | Owner | Deadline | Status |
|---|---|---|---|---|---|
| Establish $500K credit line | $5K/year | Runway shortfall (Base + Stress) | CFO | 60 days | Not started |
| 12-month retention bonus for 3 key engineers | $90K | Key person departure (all scenarios) | CHRO | 30 days | In progress |
| Diversify to <20% revenue per customer | Sales effort (6 months) | Single-customer dependency | CRO | 2 quarters | Planning |
| Start parallel fundraise track | CEO time (10 hrs/week) | Fundraise delay (Stress + Severe) | CEO | Immediate | Not started |
| Pre-negotiate bridge terms with existing investors | 2 board conversations | Runway crisis (Severe) | CFO + CEO | 45 days | Not started |
| Document architecture for bus factor reduction | 2 engineering weeks | Key person departure | CTO | 30 days | Not started |
---
Output Format
Every war room session produces this structured output:
SCENARIO: [Name]
DATE: [Date of analysis]
PARTICIPANTS: [Who was involved]
VARIABLES:
A: [Description] — Probability: [X]%, Timeline: [When]
B: [Description] — Probability: [X]%, Timeline: [When]
C: [Description] — Probability: [X]%, Timeline: [When]
MOST LIKELY PATH: [Which combination actually plays out, with reasoning]
SEVERITY LEVELS:
Base (A only): Runway [X]→[Y]mo, ARR impact -$[X]
Recovery: [2-3 specific actions]
Stress (A+B): Runway [X]→[Y]mo, ARR impact -$[X]
Recovery: [3-4 specific actions]
Severe (A+B+C): Runway [X]→[Y]mo, ARR impact -$[X]
Existential: [yes/no]
Emergency: [actions requiring board approval]
CASCADE MAP:
[A] → [domain impact] → [triggers B amplification] → [domain impact] → [end state]
Interruption points: [where cascade can be broken]
EARLY WARNING SIGNALS:
1. [Signal] → indicates [scenario], threshold: [specific]
2. [Signal] → indicates [scenario], threshold: [specific]
3. [Signal] → indicates [scenario], threshold: [specific]
HEDGES (implement now):
1. [Action] — cost: $[X] — protects: [scenarios] — owner: [role] — deadline: [date]
2. [Action] — cost: $[X] — protects: [scenarios] — owner: [role] — deadline: [date]
3. [Action] — cost: $[X] — protects: [scenarios] — owner: [role] — deadline: [date]
RECOMMENDED DECISION:
[One paragraph: what to do, in what order, and why]
REVIEW DATE: [When to re-run this analysis — typically 90 days or after any variable shifts]---
Common Scenarios by Company Stage
Seed Stage
- Co-founder departure + product misses launch deadline
- Runway runs out + bridge terms are predatory
- Key technical hire falls through + competitor ships first
Series A
- Miss ARR target + fundraise delayed
- Top customer churns + competitor raises large round
- Key engineer leaves + critical feature deadline
Series B+
- Market contraction + burn multiple spikes above 3x
- Lead investor wants strategic pivot + team resists
- Regulatory change + product requires rearchitecture
---
War Room Ground Rules
1. Maximum 3 variables per scenario. More is noise. Model the ones that actually matter. 2. Quantify or estimate. "Revenue drops" is not useful. "$420K ARR at risk over 60 days" is. Use ranges if uncertain. 3. Don't stop at first-order effects. The real damage is always in the cascade. 4. Model recovery, not just impact. Every scenario must have a "what we do" path. 5. Separate base case from sensitivity. Don't conflate "what probably happens" with "what could happen." 6. 3-4 scenarios per planning cycle. More creates analysis paralysis. 7. Review every 90 days. Probabilities and variables change. Stale scenarios give false comfort. 8. No judgment-free zone. People must feel safe naming ugly scenarios.
---
Related Skills
| Skill | Use When |
|---|---|
| ceo-advisor | Strategic decisions that scenarios inform |
| cfo-advisor | Financial modeling for scenario impacts |
| coo-advisor | Operational contingency planning |
| internal-narrative | Communicating scenario outcomes to stakeholders |
| cs-onboard | Company context that feeds scenario variables |
---
Troubleshooting
| Problem | Likely Cause | Resolution |
|---|---|---|
| Scenarios feel too abstract to act on | Variables not specific or quantified enough | Require dollar amounts, percentages, and timelines for every variable; "revenue drops" is not actionable, "$420K ARR at risk over 60 days" is |
| Team generates only obvious, low-probability scenarios | Conformity bias; not applying Shell scenario planning method of challenging mental models | Use inversion technique: "What would guarantee our failure?"; bring in external perspective; reference industry-specific historical precedents |
| Cascade mapping stops at first-order effects | Facilitator not pushing past immediate consequences | Require minimum 3 levels of cascade for each variable; use "and then what?" prompting for each domain impact |
| Hedges identified but never implemented | No ownership, deadline, or cost attached | Every hedge must have: cost estimate, owner name, deadline, and status tracking; review in weekly leadership meeting |
| War room sessions take too long (> 4 hours) | Too many variables or trying to model every scenario | Enforce maximum 3 variables and 3-4 scenarios per session; use severity matrix to focus on highest-impact combinations |
| Early warning signals not being monitored | Signals assigned but not integrated into existing reporting | Add signals to existing dashboards and weekly scorecards; assign specific person to monitor each signal |
| Participants reluctant to name worst-case scenarios | Fear of being seen as negative or alarmist | Establish ground rules explicitly; cite Shell's experience: "the value is in surfacing what others won't say"; reward naming hard truths |
---
Success Criteria
- Each scenario session produces exactly 3 variables, 3 severity levels, and a cascade map with interruption points identified
- Early warning signals are specific enough to be monitored: observable, leading, and actionable with defined thresholds
- Hedges are costed, owned, and have deadlines within 7 days of the war room session
- At least one hedge per scenario is implemented (not just planned) within 30 days
- Scenario review conducted every 90 days with probability updates based on new information
- When an early warning signal fires, the pre-planned response is executed within the defined timeline
- War room output is concise enough for board consumption: one-page summary per scenario
---
Scope & Limitations
- In scope: Multi-variable scenario construction, cascade modeling across all business functions, severity matrix analysis, early warning signal design, hedge strategy with cost-benefit analysis, scenario review cadence
- Out of scope: Single-variable financial sensitivity analysis (use CFO Advisor stress testing); technical failure mode analysis (use engineering incident planning); routine project risk assessment (use project management frameworks); insurance and risk transfer (use specialized broker)
- Limitation: Scenario probabilities are subjective estimates, not actuarial calculations; value is in preparedness, not prediction accuracy
- Limitation: Framework assumes scenarios are independent or correlated; black swan events by definition are not modelable
- Limitation: Cascade mapping is based on common organizational patterns; unique company structures may have different cascade paths
- Limitation: Maximum 3 variables per scenario is a deliberate constraint; more variables create analysis paralysis, not better insight
---
Integration Points
| Skill | Integration | Data Flow |
|---|---|---|
ceo-advisor | Strategic decisions informed by scenario analysis | War room scenarios → CEO decision inputs |
cfo-advisor | Financial modeling for scenario impacts and hedge costs | War room financial impacts → CFO stress test models |
coo-advisor | Operational contingency planning and cascade interruption | War room cascade map → COO contingency plans |
executive-mentor | Pre-mortem failure modes feed into scenario variables | Mentor failure modes → War room variables |
internal-narrative | Crisis scenarios require pre-built communication plans | War room crisis scenarios → Narrative crisis templates |
org-health-diagnostic | Health dimension scores surface scenario variables | Health red flags → War room variable candidates |
strategic-alignment | Scenario outcomes may require strategic realignment | War room outcomes → Alignment reassessment |
---
Python Tools
| Tool | Purpose | Usage |
|---|---|---|
scripts/scenario_builder.py | Build structured scenarios with variables, probabilities, detection signals, and severity levels | python scripts/scenario_builder.py --name "Customer Concentration Risk" --variable "Top customer churns" --probability 20 --impact 500000 --timeline 90 --json |
scripts/impact_matrix_calculator.py | Calculate compound impact across multiple variables with severity matrix and cascade risk scoring | python scripts/impact_matrix_calculator.py --variables "churn:500000:0.2" "fundraise_delay:0:0.3" "key_departure:0:0.15" --arr 2000000 --runway-months 14 --json |
scripts/decision_tree_analyzer.py | Build and evaluate decision trees with expected value calculations for strategic options | python scripts/decision_tree_analyzer.py --decision "Enter Japan market" --option "Direct:0.6:2000000:-500000" --option "Partnership:0.75:1000000:-200000" --option "Wait:1.0:0:0" --json |
#!/usr/bin/env python3
"""Decision Tree Analyzer - Build and evaluate decision trees with expected value calculations.
Models strategic decisions with multiple options, each having probability of success,
upside value, and downside cost. Calculates expected value to guide decision-making.
Usage:
python decision_tree_analyzer.py --decision "Enter Japan market" --option "Direct:0.6:2000000:-500000" --option "Partnership:0.75:1000000:-200000" --option "Wait:1.0:0:0"
python decision_tree_analyzer.py --decision "Acquire CompanyX" --option "Full acquisition:0.7:5000000:-2000000" --option "Acqui-hire:0.85:1500000:-500000" --option "Build internally:0.5:3000000:-800000" --json
"""
import argparse
import json
import sys
from datetime import datetime
def parse_option(option_str):
"""Parse option in format 'name:probability_success:upside:downside'."""
parts = option_str.split(":")
if len(parts) < 4:
print(f"Error: Option must be 'name:probability:upside:downside'. Got: {option_str}", file=sys.stderr)
sys.exit(1)
return {
"name": parts[0].strip(),
"probability_success": float(parts[1]),
"upside": float(parts[2]),
"downside": float(parts[3])
}
def analyze_decision(decision_name, options):
"""Analyze all options and compute expected values."""
analyzed = []
for opt in options:
p_success = opt["probability_success"]
p_failure = 1 - p_success
upside = opt["upside"]
downside = opt["downside"]
expected_value = round(p_success * upside + p_failure * downside)
expected_upside = round(p_success * upside)
expected_downside = round(p_failure * downside)
risk_reward_ratio = round(abs(upside / downside), 2) if downside != 0 else float('inf')
max_regret = abs(downside)
analyzed.append({
"name": opt["name"],
"probability_success": f"{int(p_success * 100)}%",
"probability_success_raw": p_success,
"upside": upside,
"downside": downside,
"expected_value": expected_value,
"expected_upside": expected_upside,
"expected_downside": expected_downside,
"risk_reward_ratio": risk_reward_ratio,
"max_regret": max_regret,
"reversible": abs(downside) < 100000 # Heuristic
})
# Sort by expected value (best first)
analyzed.sort(key=lambda x: -x["expected_value"])
# Determine recommendation
best_ev = analyzed[0]
lowest_risk = min(analyzed, key=lambda x: x["max_regret"])
highest_upside = max(analyzed, key=lambda x: x["upside"])
# Sensitivity check: how much would probability need to change to change the ranking?
sensitivity = []
if len(analyzed) >= 2:
first = analyzed[0]
second = analyzed[1]
# At what probability does the second option become better?
# EV1 = p1 * up1 + (1-p1) * down1
# EV2 = p2 * up2 + (1-p2) * down2
# We vary p1: find p where EV1 = EV2_current
ev2 = second["expected_value"]
up1 = first["upside"]
down1 = first["downside"]
if up1 != down1:
breakeven_p = (ev2 - down1) / (up1 - down1)
if 0 <= breakeven_p <= 1:
sensitivity.append({
"insight": f"If '{first['name']}' success probability drops to {int(breakeven_p * 100)}%, '{second['name']}' becomes the better option",
"current_probability": first["probability_success"],
"breakeven_probability": f"{int(breakeven_p * 100)}%",
"margin": f"{int((first['probability_success_raw'] - breakeven_p) * 100)} percentage points"
})
return {
"analysis_date": datetime.now().strftime("%Y-%m-%d"),
"decision": decision_name,
"options_analyzed": len(analyzed),
"options": analyzed,
"recommendation": {
"best_expected_value": {"option": best_ev["name"], "ev": best_ev["expected_value"]},
"lowest_risk": {"option": lowest_risk["name"], "max_regret": lowest_risk["max_regret"]},
"highest_upside": {"option": highest_upside["name"], "upside": highest_upside["upside"]}
},
"sensitivity": sensitivity,
"decision_framework": {
"if_reversible": f"Go with '{best_ev['name']}' (highest EV). Speed matters more than perfection for reversible decisions.",
"if_irreversible": f"Consider '{lowest_risk['name']}' (lowest regret) unless EV difference with '{best_ev['name']}' justifies the risk.",
"if_constrained": f"'{lowest_risk['name']}' minimizes downside exposure."
}
}
def print_human(result):
print(f"\n{'='*70}")
print(f"DECISION TREE ANALYSIS: {result['decision']}")
print(f"Date: {result['analysis_date']}")
print(f"{'='*70}\n")
print("OPTIONS (ranked by Expected Value):")
print("-" * 70)
for i, opt in enumerate(result["options"], 1):
ev_bar_width = max(0, min(20, int(opt["expected_value"] / max(abs(o["expected_value"]) for o in result["options"]) * 20))) if any(o["expected_value"] != 0 for o in result["options"]) else 0
ev_bar = "#" * ev_bar_width
print(f"\n {i}. {opt['name']}")
print(f" Success Probability: {opt['probability_success']}")
print(f" Upside: ${opt['upside']:>12,}")
print(f" Downside: ${opt['downside']:>12,}")
print(f" Expected Value: ${opt['expected_value']:>10,} {ev_bar}")
print(f" Risk/Reward: {opt['risk_reward_ratio']}x | Max Regret: ${opt['max_regret']:,}")
rec = result["recommendation"]
print(f"\nRECOMMENDATION:")
print("-" * 50)
print(f" Best EV: {rec['best_expected_value']['option']} (EV: ${rec['best_expected_value']['ev']:,})")
print(f" Lowest Risk: {rec['lowest_risk']['option']} (Max Regret: ${rec['lowest_risk']['max_regret']:,})")
print(f" Highest Upside: {rec['highest_upside']['option']} (${rec['highest_upside']['upside']:,})")
df = result["decision_framework"]
print(f"\nDECISION FRAMEWORK:")
print(f" If reversible: {df['if_reversible']}")
print(f" If irreversible: {df['if_irreversible']}")
print(f" If constrained: {df['if_constrained']}")
if result["sensitivity"]:
print(f"\nSENSITIVITY ANALYSIS:")
for s in result["sensitivity"]:
print(f" {s['insight']}")
print(f" Current: {s['current_probability']} | Breakeven: {s['breakeven_probability']} | Margin: {s['margin']}")
print()
def main():
parser = argparse.ArgumentParser(description="Build and evaluate decision trees with expected value")
parser.add_argument("--decision", required=True, help="Decision being analyzed")
parser.add_argument("--option", action="append", required=True,
help="Option in format 'name:probability_success:upside:downside' (multiple allowed)")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
if len(args.option) < 2:
print("Error: At least 2 options required for meaningful comparison", file=sys.stderr)
sys.exit(1)
options = [parse_option(o) for o in args.option]
result = analyze_decision(args.decision, options)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human(result)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Impact Matrix Calculator - Calculate compound impact across multiple risk variables.
Models compound risk when multiple adverse events co-occur. Calculates expected value,
worst-case scenarios, and cascade risk scores for strategic decision-making.
Usage:
python impact_matrix_calculator.py --variables "churn:500000:0.2" "fundraise_delay:0:0.3" "key_departure:0:0.15" --arr 2000000 --runway-months 14
python impact_matrix_calculator.py --variables "market_shift:300000:0.25" "pricing_pressure:200000:0.35" --arr 5000000 --runway-months 18 --json
"""
import argparse
import json
import sys
from datetime import datetime
from itertools import combinations
def parse_variable(var_str):
"""Parse 'name:impact:probability' format."""
parts = var_str.split(":")
if len(parts) < 3:
print(f"Error: Variable must be in format 'name:impact:probability'. Got: {var_str}", file=sys.stderr)
sys.exit(1)
return {
"name": parts[0].strip(),
"impact": float(parts[1]),
"probability": float(parts[2])
}
def calculate_combinations(variables):
"""Calculate all possible combinations of variables occurring."""
combos = []
# Individual variables
for v in variables:
combos.append({
"variables": [v["name"]],
"combined_probability": v["probability"],
"total_impact": v["impact"],
"severity": "base"
})
# Pairs
if len(variables) >= 2:
for pair in combinations(variables, 2):
combined_prob = pair[0]["probability"] * pair[1]["probability"]
total_impact = sum(p["impact"] for p in pair)
# Cascade multiplier: compound events are worse than sum of parts
cascade_multiplier = 1.3
combos.append({
"variables": [p["name"] for p in pair],
"combined_probability": round(combined_prob, 4),
"total_impact": round(total_impact * cascade_multiplier),
"cascade_multiplier": cascade_multiplier,
"severity": "stress"
})
# All three
if len(variables) >= 3:
combined_prob = 1.0
for v in variables:
combined_prob *= v["probability"]
total_impact = sum(v["impact"] for v in variables)
cascade_multiplier = 1.6 # Full cascade is significantly worse
combos.append({
"variables": [v["name"] for v in variables],
"combined_probability": round(combined_prob, 4),
"total_impact": round(total_impact * cascade_multiplier),
"cascade_multiplier": cascade_multiplier,
"severity": "severe"
})
return combos
def calculate_expected_values(variables, combos, arr, runway_months):
"""Calculate expected values and risk-adjusted impacts."""
monthly_burn = arr / 12 * 1.5 if arr > 0 else 50000
# Expected value (probability-weighted average impact)
expected_value = sum(v["impact"] * v["probability"] for v in variables)
# Risk-adjusted scenarios
scenarios = []
for combo in combos:
runway_impact = combo["total_impact"] / monthly_burn if monthly_burn > 0 else 0
new_runway = runway_months - runway_impact
scenarios.append({
"variables": combo["variables"],
"severity": combo["severity"],
"probability": f"{combo['combined_probability'] * 100:.1f}%",
"probability_raw": combo["combined_probability"],
"total_impact": combo["total_impact"],
"arr_impact_pct": round(combo["total_impact"] / arr * 100, 1) if arr > 0 else 0,
"runway_change": round(-runway_impact, 1),
"new_runway": round(new_runway, 1),
"existential": new_runway < 6,
"expected_value": round(combo["total_impact"] * combo["combined_probability"])
})
# Risk score (0-100)
max_impact = max(c["total_impact"] for c in combos) if combos else 0
max_prob = max(v["probability"] for v in variables) if variables else 0
risk_score = round(min(100, (max_impact / arr * 50 if arr > 0 else 50) + (max_prob * 50)))
# Determine risk level
if risk_score >= 70:
risk_level = "CRITICAL"
elif risk_score >= 50:
risk_level = "HIGH"
elif risk_score >= 30:
risk_level = "MODERATE"
else:
risk_level = "LOW"
return {
"calculation_date": datetime.now().strftime("%Y-%m-%d"),
"inputs": {
"variables": [{"name": v["name"], "impact": v["impact"], "probability": f"{v['probability']*100:.0f}%"} for v in variables],
"arr": arr,
"runway_months": runway_months,
"estimated_monthly_burn": round(monthly_burn)
},
"expected_value": round(expected_value),
"expected_value_pct_arr": round(expected_value / arr * 100, 1) if arr > 0 else 0,
"risk_score": risk_score,
"risk_level": risk_level,
"worst_case_impact": max_impact,
"worst_case_pct_arr": round(max_impact / arr * 100, 1) if arr > 0 else 0,
"scenarios": sorted(scenarios, key=lambda s: -s["total_impact"]),
"key_insights": generate_insights(variables, scenarios, arr, runway_months, risk_level)
}
def generate_insights(variables, scenarios, arr, runway_months, risk_level):
insights = []
existential = [s for s in scenarios if s.get("existential")]
if existential:
insights.append(f"EXISTENTIAL RISK: {len(existential)} scenario(s) reduce runway below 6 months")
high_prob = [v for v in variables if v["probability"] > 0.25]
if high_prob:
insights.append(f"HIGH PROBABILITY: {', '.join(v['name'] for v in high_prob)} have >25% likelihood")
high_impact = [v for v in variables if arr > 0 and v["impact"] / arr > 0.15]
if high_impact:
insights.append(f"HIGH IMPACT: {', '.join(v['name'] for v in high_impact)} would affect >15% of ARR")
if risk_level in ("CRITICAL", "HIGH"):
insights.append("Recommend immediate war room session with full leadership team")
insights.append("Implement hedging strategies before next board meeting")
return insights
def print_human(result):
print(f"\n{'='*70}")
print(f"IMPACT MATRIX ANALYSIS")
print(f"Date: {result['calculation_date']}")
print(f"{'='*70}\n")
inp = result["inputs"]
print(f"Context: ARR ${inp['arr']:,} | Runway: {inp['runway_months']} months | Burn: ${inp['estimated_monthly_burn']:,}/mo\n")
print(f"RISK SCORE: {result['risk_score']}/100 ({result['risk_level']})")
print(f"Expected Value of Loss: ${result['expected_value']:,} ({result['expected_value_pct_arr']}% of ARR)")
print(f"Worst Case Impact: ${result['worst_case_impact']:,} ({result['worst_case_pct_arr']}% of ARR)\n")
print("INPUT VARIABLES:")
print("-" * 50)
for v in result["inputs"]["variables"]:
print(f" {v['name']:<30s} Impact: ${v['impact']:>10,} Prob: {v['probability']}")
print(f"\nSCENARIO MATRIX:")
print("-" * 70)
for s in result["scenarios"]:
existential_flag = " [EXISTENTIAL]" if s.get("existential") else ""
print(f" [{s['severity'].upper():<8s}] {' + '.join(s['variables'])}")
print(f" Probability: {s['probability']:>6s} Impact: ${s['total_impact']:>10,} Runway: {s['new_runway']:>5.1f}mo EV: ${s['expected_value']:>8,}{existential_flag}")
if result["key_insights"]:
print(f"\nKEY INSIGHTS:")
for i in result["key_insights"]:
print(f" -> {i}")
print()
def main():
parser = argparse.ArgumentParser(description="Calculate compound risk impact across multiple variables")
parser.add_argument("--variables", nargs="+", required=True, help="Variables in format 'name:impact:probability'")
parser.add_argument("--arr", type=float, required=True, help="Current ARR ($)")
parser.add_argument("--runway-months", type=float, required=True, help="Current runway in months")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
variables = [parse_variable(v) for v in args.variables]
if len(variables) > 3:
print("Warning: Maximum 3 variables. Using first 3.", file=sys.stderr)
variables = variables[:3]
combos = calculate_combinations(variables)
result = calculate_expected_values(variables, combos, args.arr, args.runway_months)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human(result)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Scenario Builder - Build structured scenarios with variables, probabilities, and severity levels.
Creates war room scenarios following the 6-step cascade model with variables,
detection signals, severity matrix, and hedge recommendations.
Usage:
python scenario_builder.py --name "Customer Concentration Risk" --variable "Top customer churns" --probability 20 --impact 500000 --timeline 90
python scenario_builder.py --name "Fundraise Risk" --variable "Series A delayed 6 months:0.3:0:180" --variable "Key engineer leaves:0.15:100000:60" --variable "Competitor raises $50M:0.25:0:90" --arr 2000000 --runway-months 14 --json
"""
import argparse
import json
import sys
from datetime import datetime
CASCADE_PATTERNS = {
"revenue_death_spiral": {
"name": "Revenue-to-Runway Death Spiral",
"pattern": "Customer churn -> lower runway -> hiring freeze -> slower product -> more churn",
"interruption": "Emergency revenue diversification or bridge financing"
},
"key_person_cascade": {
"name": "Key Person Cascade",
"pattern": "Star leaves -> team morale drops -> followers leave -> velocity collapses",
"interruption": "Retention bonuses before departure, succession planning"
},
"market_squeeze": {
"name": "Market Squeeze",
"pattern": "Competitor raises -> price war -> margins compress -> can't invest in product",
"interruption": "Differentiation (not price matching), niche down"
},
"trust_cascade": {
"name": "Trust Cascade",
"pattern": "Incident -> customer concern -> churn -> press -> more churn",
"interruption": "Swift, transparent communication"
},
"fundraise_burn_spiral": {
"name": "Fundraise-Burn Spiral",
"pattern": "Miss target -> raise delayed -> bridge at bad terms -> burn cuts -> team loss",
"interruption": "Parallel fundraise tracks, pre-negotiated bridge terms"
}
}
def parse_variable(var_str, default_probability=0.2, default_impact=0, default_timeline=90):
"""Parse variable string in format 'description:probability:impact:timeline_days' or just 'description'."""
parts = var_str.split(":")
desc = parts[0].strip()
prob = float(parts[1]) if len(parts) > 1 else default_probability
impact = float(parts[2]) if len(parts) > 2 else default_impact
timeline = int(parts[3]) if len(parts) > 3 else default_timeline
return {"description": desc, "probability": prob, "impact": impact, "timeline_days": timeline}
def identify_cascade_patterns(variables):
"""Identify likely cascade patterns based on variable descriptions."""
patterns = []
descriptions = " ".join(v["description"].lower() for v in variables)
if any(word in descriptions for word in ["churn", "customer", "cancel", "terminate"]):
patterns.append(CASCADE_PATTERNS["revenue_death_spiral"])
if any(word in descriptions for word in ["leave", "depart", "quit", "engineer", "key person"]):
patterns.append(CASCADE_PATTERNS["key_person_cascade"])
if any(word in descriptions for word in ["competitor", "raise", "funding", "market"]):
patterns.append(CASCADE_PATTERNS["market_squeeze"])
if any(word in descriptions for word in ["incident", "breach", "security", "trust"]):
patterns.append(CASCADE_PATTERNS["trust_cascade"])
if any(word in descriptions for word in ["fundraise", "series", "round", "investor"]):
patterns.append(CASCADE_PATTERNS["fundraise_burn_spiral"])
return patterns if patterns else [CASCADE_PATTERNS["revenue_death_spiral"]]
def build_scenario(name, variables, arr, runway_months):
if len(variables) > 3:
print("Warning: Maximum 3 variables recommended. Using first 3.", file=sys.stderr)
variables = variables[:3]
# Calculate severity levels
total_impact = sum(v["impact"] for v in variables)
monthly_burn = arr / 12 * 1.5 if arr > 0 else 50000 # Estimate burn from ARR
# Base scenario (1 variable hits)
base = {
"name": "Base (single shock)",
"variables_hit": 1,
"arr_impact": variables[0]["impact"] if variables else 0,
"arr_impact_pct": round(variables[0]["impact"] / arr * 100, 1) if arr > 0 and variables else 0,
"runway_impact_months": round(variables[0]["impact"] / monthly_burn, 1) if monthly_burn > 0 and variables else 0,
"new_runway": round(runway_months - (variables[0]["impact"] / monthly_burn), 1) if monthly_burn > 0 and variables else runway_months,
"recovery": "Manageable with prepared response"
}
# Stress scenario (2 variables)
stress_impact = sum(v["impact"] for v in variables[:2])
stress = {
"name": "Stress (compound shock)",
"variables_hit": min(2, len(variables)),
"arr_impact": stress_impact,
"arr_impact_pct": round(stress_impact / arr * 100, 1) if arr > 0 else 0,
"runway_impact_months": round(stress_impact / monthly_burn, 1) if monthly_burn > 0 else 0,
"new_runway": round(runway_months - (stress_impact / monthly_burn), 1) if monthly_burn > 0 else runway_months,
"recovery": "Requires significant pivot, board involvement"
}
# Severe scenario (all variables)
severe = {
"name": "Severe (full cascade)",
"variables_hit": len(variables),
"arr_impact": total_impact,
"arr_impact_pct": round(total_impact / arr * 100, 1) if arr > 0 else 0,
"runway_impact_months": round(total_impact / monthly_burn, 1) if monthly_burn > 0 else 0,
"new_runway": round(runway_months - (total_impact / monthly_burn), 1) if monthly_burn > 0 else runway_months,
"existential": severe_new_runway < 6 if (severe_new_runway := round(runway_months - (total_impact / monthly_burn), 1) if monthly_burn > 0 else runway_months) else False,
"recovery": "Emergency action required, board intervention"
}
# Cascade patterns
cascade_patterns = identify_cascade_patterns(variables)
# Early warning signals
signals = []
for v in variables:
signals.append({
"variable": v["description"],
"signal": f"Monitor for early indicators of: {v['description']}",
"threshold": f"Probability rises above {int(v['probability'] * 100 + 10)}%",
"response_window": f"{max(7, v['timeline_days'] // 4)} days to respond"
})
# Hedges
hedges = []
if any(v["impact"] > 0 for v in variables):
hedges.append({"hedge": "Establish credit line or bridge financing option", "cost": "$5K-15K/year", "protects_against": "Runway shortfall", "owner": "CFO", "deadline": "60 days"})
if any("key" in v["description"].lower() or "leave" in v["description"].lower() or "engineer" in v["description"].lower() for v in variables):
hedges.append({"hedge": "Retention bonuses for critical team members", "cost": "$50K-150K", "protects_against": "Key person departure", "owner": "CHRO", "deadline": "30 days"})
if any("customer" in v["description"].lower() or "churn" in v["description"].lower() for v in variables):
hedges.append({"hedge": "Diversify revenue concentration below 20% per customer", "cost": "Sales effort", "protects_against": "Customer concentration risk", "owner": "CRO", "deadline": "2 quarters"})
if any("fundraise" in v["description"].lower() or "series" in v["description"].lower() for v in variables):
hedges.append({"hedge": "Pre-negotiate bridge terms with existing investors", "cost": "CEO time", "protects_against": "Fundraise delay", "owner": "CEO", "deadline": "45 days"})
if not hedges:
hedges.append({"hedge": "Document contingency response plan", "cost": "Leadership time", "protects_against": "General preparedness", "owner": "COO", "deadline": "30 days"})
return {
"scenario_date": datetime.now().strftime("%Y-%m-%d"),
"scenario_name": name,
"review_date": (datetime.now().replace(month=datetime.now().month % 12 + 1) if datetime.now().month < 12
else datetime.now().replace(year=datetime.now().year + 1, month=1)).strftime("%Y-%m-%d"),
"company_context": {
"arr": arr,
"runway_months": runway_months,
"estimated_monthly_burn": round(monthly_burn)
},
"variables": [
{
"id": chr(65 + i),
"description": v["description"],
"probability": f"{int(v['probability'] * 100)}%",
"probability_raw": v["probability"],
"impact": v["impact"],
"timeline_days": v["timeline_days"]
}
for i, v in enumerate(variables)
],
"severity_matrix": {
"base": base,
"stress": stress,
"severe": severe
},
"cascade_patterns": [{"name": p["name"], "pattern": p["pattern"], "interruption_point": p["interruption"]} for p in cascade_patterns],
"early_warning_signals": signals,
"hedges": hedges,
"ground_rules": [
"Maximum 3 variables per scenario",
"Quantify everything: dollar amounts, percentages, timelines",
"Don't stop at first-order effects -- trace the cascade",
"Every scenario must have a recovery path",
"Review every 90 days or after any variable shifts"
]
}
def print_human(result):
print(f"\n{'='*70}")
print(f"SCENARIO: {result['scenario_name']}")
print(f"Date: {result['scenario_date']} | Review by: {result['review_date']}")
print(f"{'='*70}\n")
ctx = result["company_context"]
print(f"Context: ARR ${ctx['arr']:,} | Runway: {ctx['runway_months']} months | Burn: ${ctx['estimated_monthly_burn']:,}/mo\n")
print("VARIABLES:")
print("-" * 60)
for v in result["variables"]:
print(f" [{v['id']}] {v['description']}")
print(f" Probability: {v['probability']} | Impact: ${v['impact']:,} | Timeline: {v['timeline_days']} days")
print(f"\nSEVERITY MATRIX:")
print("-" * 60)
for level in ["base", "stress", "severe"]:
s = result["severity_matrix"][level]
existential = " [EXISTENTIAL]" if s.get("existential") else ""
print(f" {s['name'].upper()}: ARR impact -${s['arr_impact']:,} ({s['arr_impact_pct']}%), Runway: {s['new_runway']} months{existential}")
print(f" Recovery: {s['recovery']}")
print(f"\nCASCADE PATTERNS:")
for cp in result["cascade_patterns"]:
print(f" {cp['name']}: {cp['pattern']}")
print(f" Interruption: {cp['interruption_point']}")
print(f"\nEARLY WARNING SIGNALS:")
for s in result["early_warning_signals"]:
print(f" -> {s['variable']}: {s['threshold']} (respond within {s['response_window']})")
print(f"\nHEDGES (implement now):")
for h in result["hedges"]:
print(f" [{h['deadline']:<10s}] {h['hedge']} (cost: {h['cost']}, owner: {h['owner']})")
print()
def main():
parser = argparse.ArgumentParser(description="Build structured war room scenarios")
parser.add_argument("--name", required=True, help="Scenario name")
parser.add_argument("--variable", action="append", required=True,
help="Variable in format 'description:probability:impact:timeline_days' (multiple allowed)")
parser.add_argument("--arr", type=float, default=2000000, help="Current ARR ($)")
parser.add_argument("--runway-months", type=float, default=14, help="Current runway in months")
# Legacy single-variable args
parser.add_argument("--probability", type=float, help="Probability (0-1) for single variable mode")
parser.add_argument("--impact", type=float, help="Impact ($) for single variable mode")
parser.add_argument("--timeline", type=int, help="Timeline (days) for single variable mode")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
variables = []
for var_str in args.variable:
v = parse_variable(
var_str,
default_probability=args.probability or 0.2,
default_impact=args.impact or 0,
default_timeline=args.timeline or 90
)
variables.append(v)
result = build_scenario(args.name, variables, args.arr, args.runway_months)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human(result)
if __name__ == "__main__":
main()
Related skills
FAQ
When should I use it?
When a major risk has meaningful probability and impact, when two or more threats could co-occur, or before a big commitment like a fundraise or acquisition.
How many scenario variables does it use?
A maximum of three, chosen as the ones that actually keep leadership awake, to avoid analysis paralysis.