
Org Health Diagnostic
- 81 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
org-health-diagnostic is a Claude Code skill that scores 8 organizational dimensions on a traffic-light scale with benchmarks and cascade analysis.
About
org-health-diagnostic is a skill for a cross-functional organizational health check that combines signals from all C-suite roles. It scores 8 dimensions (financial, revenue, product, engineering, people, operational, security, market) on a traffic-light scale against benchmarks, with drill-down recommendations and cascade analysis. A leader uses it when assessing company health, preparing for board reviews, or identifying at-risk functions.
- Scores 8 organizational dimensions on a traffic-light scale with real benchmarks
- Maps each dimension to a C-suite owner and core question
- Includes cascade analysis showing how one dimension's problems spread to others
Org Health Diagnostic by the numbers
- 81 all-time installs (skills.sh)
- Ranked #1,443 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
org-health-diagnostic capabilities & compatibility
- Capabilities
- outcome roadmap · health scorecard · benchmark analysis
- Use cases
- data analysis · planning
What org-health-diagnostic says it does
Cross-functional organizational health check combining signals from all
Scores 8 dimensions on a traffic-light scale with drill-down
shows how problems in one dimension cascade to others.
npx skills add https://github.com/borghei/claude-skills --skill org-health-diagnosticAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 81 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Score company health across 8 dimensions and surface at-risk functions before a board review.
Who is it for?
Assessing overall company health, preparing for board reviews, and identifying at-risk functions.
Skip if: Deep single-function financial modeling or software engineering tasks.
When should I use this skill?
You are assessing company health, preparing a board review, or diagnosing cross-functional problems.
What you get
An 8-dimension traffic-light health scorecard with drill-down recommendations and cascade analysis.
- 8-dimension health scorecard
- Drill-down recommendations
- Cross-dimension cascade analysis
By the numbers
- 8 dimensions scored
- 3-color traffic-light scale (Green/Yellow/Red)
- 5 metrics per dimension
Files
Org Health Diagnostic
Eight dimensions. Traffic lights. Real benchmarks. Surfaces the problems you do not know you have and shows how problems in one dimension cascade to others.
Keywords
org health, organizational health, health diagnostic, health dashboard, health check, company health, functional health, team health, startup health, health scorecard, health assessment, risk dashboard, cross-functional health, dimension cascade, stage benchmarks
---
The 8 Dimensions
Dimension Overview
| # | Dimension | C-Suite Owner | Core Question |
|---|---|---|---|
| 1 | Financial Health | CFO | Can we fund operations and invest in growth? |
| 2 | Revenue Health | CRO | Are customers staying, growing, and recommending us? |
| 3 | Product Health | CPO | Do customers love and use the product? |
| 4 | Engineering Health | CTO | Can we ship reliably and sustain velocity? |
| 5 | People Health | CHRO | Is the team stable, engaged, and growing? |
| 6 | Operational Health | COO | Are we executing our strategy with discipline? |
| 7 | Security Health | CISO | Are we protecting customers and maintaining compliance? |
| 8 | Market Health | CMO | Are we winning in the market and growing efficiently? |
---
Dimension 1: Financial Health (CFO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| Runway (months) | > 18 | 9-18 | < 9 |
| Burn multiple | < 1.5x | 1.5-2.5x | > 2.5x |
| Gross margin | > 70% | 55-70% | < 55% |
| Revenue concentration (top customer) | < 10% | 10-20% | > 20% |
| MoM growth rate | Above benchmark | At benchmark | Below benchmark |
Dimension 2: Revenue Health (CRO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| NRR | > 110% | 100-110% | < 100% |
| Logo churn (annual) | < 5% | 5-10% | > 10% |
| Pipeline coverage (next Q) | > 3x | 2-3x | < 2x |
| CAC payback | < 12 months | 12-18 months | > 18 months |
| Win rate | > 25% | 15-25% | < 15% |
Dimension 3: Product Health (CPO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| NPS | > 40 | 20-40 | < 20 |
| DAU/MAU ratio | > 40% | 20-40% | < 20% |
| Core feature adoption | > 60% | 30-60% | < 30% |
| Time to value | Decreasing QoQ | Stable | Increasing QoQ |
| CSAT | > 4.2/5 | 3.5-4.2 | < 3.5 |
Dimension 4: Engineering Health (CTO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| Deploy frequency | Daily | Weekly | Monthly or less |
| Change failure rate | < 5% | 5-15% | > 15% |
| MTTR | < 1 hour | 1-4 hours | > 4 hours |
| Tech debt ratio (% of sprint) | < 20% | 20-35% | > 35% |
| P0/P1 incidents per month | < 2 | 2-5 | > 5 |
Dimension 5: People Health (CHRO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| Regrettable attrition (annual) | < 10% | 10-20% | > 20% |
| eNPS | > 30 | 0-30 | < 0 |
| Time to fill (avg days) | < 45 | 45-90 | > 90 |
| Manager:IC ratio | 1:5-1:8 | 1:3-1:5 or 1:8-1:12 | Outside range |
| Internal promotion rate | > 30% | 15-30% | < 15% |
Dimension 6: Operational Health (COO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| OKR completion rate | > 70% | 50-70% | < 50% |
| Decision cycle time | < 48 hours | 48hrs-1 week | > 1 week |
| Meeting effectiveness | Clear outcomes | Mixed | No outcomes |
| Cross-functional initiative completion | > 80% on time | 50-80% | < 50% |
| Process documentation coverage | > 70% | 40-70% | < 40% |
Dimension 7: Security Health (CISO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| Security incidents (90 days) | 0 | 1-2 minor | 1+ major |
| Compliance status | All current | In progress | Overdue/lapsed |
| Critical vuln remediation SLA | 100% in SLA | > 90% | < 90% |
| Security training completion | > 95% | 80-95% | < 80% |
| Pen test recency | < 12 months | 12-24 months | > 24 months |
Dimension 8: Market Health (CMO)
| Metric | Green (7-10) | Yellow (4-6) | Red (1-3) |
|---|---|---|---|
| CAC trend | Improving QoQ | Stable | Worsening QoQ |
| Organic vs paid lead mix | > 50% organic | 30-50% organic | < 30% organic |
| Win rate vs competitors | Improving | Stable | Declining |
| Brand awareness (in ICP) | > 40% | 20-40% | < 20% |
| Pipeline contribution (marketing) | > 40% | 20-40% | < 20% |
---
Scoring System
Individual Dimension Score
Each dimension scores 1-10 based on weighted metrics:
Dimension Score = Sum(metric_score x metric_weight) / Sum(weights)
Traffic Light:
Green (7-10): Healthy -- maintain and optimize
Yellow (4-6): Watch -- trend matters (improving or declining?)
Red (1-3): Action required -- address within 30 daysOverall Health Score
Weighted average by company stage:
| Dimension | Seed Weight | Series A | Series B | Series C+ |
|---|---|---|---|---|
| Financial | 20% | 15% | 15% | 15% |
| Revenue | 10% | 20% | 20% | 20% |
| Product | 25% | 20% | 15% | 10% |
| Engineering | 15% | 15% | 15% | 10% |
| People | 10% | 10% | 15% | 15% |
| Operations | 5% | 10% | 10% | 15% |
| Security | 5% | 5% | 5% | 10% |
| Market | 10% | 5% | 5% | 5% |
Stage-Adjusted Benchmarks
Different stages have different healthy ranges. A Seed company with 6-month runway is normal; a Series C company with 6-month runway is a crisis.
| Stage | Runway Target | Burn Multiple | Team Size | Revenue Threshold |
|---|---|---|---|---|
| Seed | > 12 months | Not applicable | 2-10 | Pre-revenue acceptable |
| Series A | > 18 months | < 3x | 10-40 | > $500K ARR |
| Series B | > 18 months | < 2x | 30-100 | > $3M ARR |
| Series C+ | > 24 months | < 1.5x | 80-300 | > $15M ARR |
---
Cascade Analysis
How Dimension Failures Propagate
This is the most important part of the diagnostic. Problems in one dimension inevitably create problems in others.
| If This Is Red... | Watch These Next... | Why |
|---|---|---|
| Financial | People -> Engineering -> Product | Budget cuts -> hiring freeze -> velocity drops -> product stalls |
| Revenue | Financial -> People -> Market | Cash gap -> attrition risk -> positioning weakens |
| Product | Revenue -> Market -> People | NRR drops -> CAC rises -> top talent leaves |
| Engineering | Product -> Revenue | Features slip -> deals stall on missing features |
| People | Engineering -> Product -> Revenue | Velocity drops -> quality drops -> churn rises |
| Operations | ALL dimensions degrade over time | Execution failure cascades everywhere |
| Security | Revenue (enterprise) -> Financial | Enterprise deals blocked -> revenue impact |
| Market | Revenue -> Financial | Lead pipeline dries up -> sales suffers |
Cascade Risk Decision Tree
START: Dimension scores calculated
|
v
[Any dimension RED?]
|
+-- NO --> [Any dimension YELLOW with declining trend?]
| |
| +-- YES --> Monitor cascade. Check connected dimensions.
| +-- NO --> Healthy. Maintain current approach.
|
+-- YES --> [Check cascade connections]
|
v
[Are connected dimensions also Yellow/Red?]
|
+-- YES --> SYSTEMIC ISSUE. Root cause in the Red dimension.
| Address Red dimension first. Connected will improve.
|
+-- NO --> ISOLATED ISSUE. Fix Red dimension before it cascades.
Timeline: 30 days or cascade begins.---
Dashboard Output Format
ORG HEALTH DIAGNOSTIC -- [Company] -- [Date]
Stage: [Seed/A/B/C] Overall: [Score]/10 Trend: [Improving/Stable/Declining]
DIMENSION SCORES
------------------------------------------------------------
Financial [G] 8.2 Runway 14mo, burn 1.6x
Revenue [Y] 5.8 NRR 104%, pipeline thin (1.8x)
Product [G] 7.4 NPS 42, DAU/MAU 38%
Engineering [Y] 5.2 Debt at 30%, MTTR 3.2h
People [R] 3.8 Attrition 24%, eNPS -5
Operations [Y] 6.0 OKR 65% completion
Security [G] 7.8 SOC 2 complete, 0 incidents
Market [Y] 5.5 CAC rising, win rate 22%
------------------------------------------------------------
TOP PRIORITIES (address in order)
[R] 1. People: attrition at 24%
Impact: Engineering velocity drops in 60 days (cascade risk)
Action: Retention audit + intervention for top 5 at-risk
Owner: CHRO + CEO | Timeline: This week
[Y] 2. Revenue: pipeline at 1.8x
Impact: Q+1 miss risk is high
Action: Add 3 qualified opps in 30 days or adjust forecast
Owner: CRO | Timeline: 30 days
[Y] 3. Engineering: tech debt at 30%
Impact: Shipping velocity slows by Q3
Action: Dedicated debt sprint plan
Owner: CTO | Timeline: 45 days
CASCADE WARNING
People [R] --> Engineering [Y] cascade risk
If attrition continues: engineering velocity drops -> product delays
-> revenue impact in 2 quarters
DATA GAPS
[!] Market: Brand awareness data needed
[!] Operations: Meeting effectiveness not measured---
Graceful Degradation
Not all data is always available. The diagnostic handles partial data:
| Data Availability | Approach |
|---|---|
| All metrics available | Full scoring, all dimensions |
| Missing 1-2 metrics per dimension | Score available metrics, flag gaps |
| Missing entire dimension | Exclude from overall score, flag as "[data needed]" |
| Only 3-4 dimensions have data | Partial diagnostic, clearly marked |
---
Diagnostic Cadence
| Frequency | Scope | Audience |
|---|---|---|
| Weekly | Scorecard metrics only (2-3 per dimension) | Leadership team |
| Monthly | Full 8-dimension assessment | CEO + direct reports |
| Quarterly | Deep diagnostic with cascade analysis + benchmarks | Board-ready report |
| Annual | Full diagnostic + year-over-year comparison + strategy implications | Board + investors |
---
Red Flags
- Any dimension Red for 2+ consecutive months -- systemic problem, not a blip
- 3+ dimensions Yellow simultaneously -- organizational strain, prioritize ruthlessly
- Overall score declining 3+ months -- strategic review needed
- Cascade warning triggered and not addressed in 30 days -- will get worse
- Data gaps persist for 2+ cycles -- measurement culture problem
- Score improving but team sentiment declining -- measurement gaming
- No dimension ever Red -- either the company is exceptional or standards are too low
---
Integration with C-Suite
| Dimension | Owner Skill | Drill-Down |
|---|---|---|
| Financial | CFO Advisor (cfo-advisor) | Deep financial analysis |
| Revenue | CRO Advisor (cro-advisor) | Pipeline and retention analysis |
| Product | CPO Advisor (cpo-advisor) | PMF assessment and portfolio review |
| Engineering | CTO Advisor (cto-advisor) | Technical health and debt analysis |
| People | CHRO Advisor (chro-advisor) | Retention, engagement, org design |
| Operations | COO Advisor (coo-advisor) | Process maturity, execution cadence |
| Security | CISO Advisor (ciso-advisor) | Risk register, compliance status |
| Market | CMO Advisor (cmo-advisor) | Positioning, channel effectiveness |
---
Output Artifacts
| Request | Deliverable |
|---|---|
| "How healthy is the company?" | Full 8-dimension dashboard with traffic lights |
| "What should we fix first?" | Prioritized action list with cascade analysis |
| "Prepare health section for board" | Board-ready health summary with trends |
| "Compare to last quarter" | Quarter-over-quarter comparison with trend arrows |
| "Where are we at risk?" | Cascade risk map with interconnected failures |
| "What data do we need?" | Data gap analysis with collection recommendations |
---
Troubleshooting
| Problem | Likely Cause | Resolution |
|---|---|---|
| Scores consistently show all green but team sentiment is negative | Metrics being gamed or standards set too low; measurement doesn't capture reality | Cross-reference quantitative scores with qualitative signals (exit interviews, Glassdoor, skip-level conversations); raise benchmarks to industry-standard levels |
| Cascade analysis shows systemic issue but leadership disagrees | Red dimension owners resistant to acknowledging problems | Present cascade evidence with data: "People Red for 2 months → Engineering Yellow → Product delays in pipeline"; use McKinsey OHI principle of benchmarking against external data |
| Data gaps persist across multiple diagnostic cycles | No measurement infrastructure; teams don't prioritize data collection | Assign data collection to specific owners with deadlines; start with proxy metrics where direct measurement is unavailable |
| Diagnostic takes too long to produce (> 2 weeks) | Trying to measure everything perfectly instead of using available data | Apply graceful degradation: score what you have, flag gaps, iterate; a partial diagnostic now beats a perfect one in 6 weeks |
| Different stakeholders interpret traffic light scores differently | No shared understanding of what Green/Yellow/Red means operationally | Document specific thresholds for each metric in each dimension; share calibration examples ("Red runway = less than 9 months at current burn") |
| Quarterly diagnostic shows no change despite interventions | Wrong interventions, or interventions not given enough time, or measuring lagging indicators | Verify interventions target root cause not symptoms; check leading indicators alongside lagging ones; allow 2 quarters for structural changes to show in scores |
| Board wants a single number but diagnostic is multi-dimensional | Board unfamiliar with the 8-dimension model | Provide the weighted overall score (1-10) as headline with stage-adjusted weighting; drill-down dimensions available on request |
---
Success Criteria
- All 8 dimensions scored with traffic lights within 5 business days of data collection start
- Cascade analysis correctly predicts downstream impacts: when a Red dimension is not addressed, connected dimensions degrade within 2 quarters
- Stage-adjusted benchmarks applied correctly: Seed company not held to Series C standards and vice versa
- Top 3 priorities identified with specific owners, timelines, and verification methods
- Data gaps reduced by at least 50% between first and second diagnostic cycle
- Board-ready health summary produced quarterly with trend comparison to prior quarter
- Overall health score trending stable or improving over 3 consecutive quarters
---
Scope & Limitations
- In scope: 8-dimension organizational health scoring, traffic light dashboards, cascade analysis, stage-adjusted benchmarks, graceful degradation for partial data, diagnostic cadence recommendations, board-ready reporting
- Out of scope: Deep functional diagnostics within a single dimension (use the respective C-suite advisor skill); employee engagement survey design and administration (use CHRO Advisor); financial auditing (use external auditors); security penetration testing (use CISO Advisor)
- Limitation: Diagnostic quality depends on data accuracy; garbage in, garbage out applies -- verify data sources
- Limitation: McKinsey OHI benchmarks are based on large enterprise data; early-stage companies may need adjusted benchmarks
- Limitation: The 8-dimension model is a simplification; some organizations may need additional dimensions (e.g., ESG, regulatory) depending on industry
- Limitation: Cascade predictions are based on common patterns; specific organizations may have unique cascade paths
---
Integration Points
| Skill | Integration | Data Flow |
|---|---|---|
cfo-advisor | Financial Health dimension deep dive | Health financial score → CFO detailed analysis |
cro-advisor | Revenue Health dimension deep dive | Health revenue score → CRO pipeline review |
cpo-advisor | Product Health dimension deep dive | Health product score → CPO PMF assessment |
cto-advisor | Engineering Health dimension deep dive | Health engineering score → CTO tech debt plan |
chro-advisor | People Health dimension deep dive | Health people score → CHRO retention strategy |
coo-advisor | Operational Health dimension deep dive | Health operations score → COO process review |
ciso-advisor | Security Health dimension deep dive | Health security score → CISO risk register |
cmo-advisor | Market Health dimension deep dive | Health market score → CMO channel review |
strategic-alignment | Health scores inform alignment priorities | Health priorities → Alignment focus areas |
executive-mentor | Red dimensions trigger executive coaching focus | Health red flags → Mentor challenge areas |
---
Python Tools
| Tool | Purpose | Usage |
|---|---|---|
scripts/org_health_scorer.py | Score all 8 dimensions with traffic lights, stage-adjusted weighting, and overall health calculation | python scripts/org_health_scorer.py --stage series-a --financial 7.5 --revenue 5.8 --product 7.2 --engineering 5.0 --people 3.5 --operations 6.0 --security 7.8 --market 5.5 --json |
scripts/span_of_control_analyzer.py | Analyze manager-to-IC ratios across the organization and flag unhealthy spans | python scripts/span_of_control_analyzer.py --org-file org_structure.csv --json |
scripts/engagement_benchmarker.py | Benchmark engagement metrics against industry standards and flag gaps | python scripts/engagement_benchmarker.py --enps 15 --attrition 18 --time-to-fill 60 --promotion-rate 20 --industry saas --json |
#!/usr/bin/env python3
"""Engagement Benchmarker - Benchmark engagement metrics against industry standards.
Compares eNPS, attrition, time-to-fill, promotion rate, and other people metrics
against industry benchmarks. Flags gaps and provides improvement recommendations.
Usage:
python engagement_benchmarker.py --enps 15 --attrition 18 --time-to-fill 60 --promotion-rate 20 --industry saas
python engagement_benchmarker.py --enps -5 --attrition 28 --time-to-fill 90 --promotion-rate 10 --industry saas --json
"""
import argparse
import json
import sys
from datetime import datetime
BENCHMARKS = {
"saas": {
"industry_name": "SaaS / Technology",
"metrics": {
"enps": {"benchmark": 20, "green": 30, "yellow": 0, "unit": "score", "direction": "higher_is_better"},
"attrition": {"benchmark": 15, "green": 10, "yellow": 20, "unit": "% annual", "direction": "lower_is_better"},
"time_to_fill": {"benchmark": 45, "green": 35, "yellow": 75, "unit": "days", "direction": "lower_is_better"},
"promotion_rate": {"benchmark": 25, "green": 30, "yellow": 15, "unit": "% internal", "direction": "higher_is_better"},
"manager_ratio": {"benchmark": 7, "green_range": [5, 8], "unit": "ICs per manager"},
}
},
"fintech": {
"industry_name": "Fintech",
"metrics": {
"enps": {"benchmark": 18, "green": 25, "yellow": -5, "unit": "score", "direction": "higher_is_better"},
"attrition": {"benchmark": 18, "green": 12, "yellow": 25, "unit": "% annual", "direction": "lower_is_better"},
"time_to_fill": {"benchmark": 55, "green": 40, "yellow": 85, "unit": "days", "direction": "lower_is_better"},
"promotion_rate": {"benchmark": 22, "green": 28, "yellow": 12, "unit": "% internal", "direction": "higher_is_better"},
"manager_ratio": {"benchmark": 7, "green_range": [5, 8], "unit": "ICs per manager"},
}
},
"enterprise": {
"industry_name": "Enterprise Software",
"metrics": {
"enps": {"benchmark": 15, "green": 25, "yellow": -5, "unit": "score", "direction": "higher_is_better"},
"attrition": {"benchmark": 12, "green": 8, "yellow": 18, "unit": "% annual", "direction": "lower_is_better"},
"time_to_fill": {"benchmark": 50, "green": 40, "yellow": 80, "unit": "days", "direction": "lower_is_better"},
"promotion_rate": {"benchmark": 20, "green": 28, "yellow": 12, "unit": "% internal", "direction": "higher_is_better"},
"manager_ratio": {"benchmark": 6, "green_range": [5, 8], "unit": "ICs per manager"},
}
},
"startup": {
"industry_name": "Startup (Early Stage)",
"metrics": {
"enps": {"benchmark": 25, "green": 35, "yellow": 5, "unit": "score", "direction": "higher_is_better"},
"attrition": {"benchmark": 20, "green": 12, "yellow": 30, "unit": "% annual", "direction": "lower_is_better"},
"time_to_fill": {"benchmark": 40, "green": 30, "yellow": 70, "unit": "days", "direction": "lower_is_better"},
"promotion_rate": {"benchmark": 20, "green": 30, "yellow": 10, "unit": "% internal", "direction": "higher_is_better"},
"manager_ratio": {"benchmark": 7, "green_range": [5, 9], "unit": "ICs per manager"},
}
}
}
METRIC_RECOMMENDATIONS = {
"enps": {
"low": [
"Conduct stay interviews with top performers to understand concerns",
"Review and address top 3 themes from last engagement survey",
"Increase leadership visibility and communication frequency",
"Implement manager coaching program focused on team support"
],
"critical": [
"URGENT: Negative eNPS indicates fundamental engagement crisis",
"Conduct skip-level conversations within 2 weeks",
"CEO to address concerns directly at all-hands",
"Consider bringing in external engagement consultant"
]
},
"attrition": {
"low": [
"Review compensation against market data for at-risk roles",
"Implement retention bonuses for critical personnel",
"Improve career development and growth opportunities",
"Address exit interview themes systematically"
],
"critical": [
"URGENT: Attrition above 25% threatens operational continuity",
"Immediate retention package for top 10 at-risk employees",
"CEO conversation with each departing senior team member",
"Conduct emergency engagement pulse survey"
]
},
"time_to_fill": {
"low": [
"Review and streamline interview process (aim for < 3 weeks end-to-end)",
"Improve job descriptions and employer branding",
"Expand sourcing channels beyond current methods",
"Consider adding recruiter headcount"
],
"critical": [
"Hiring bottleneck affecting growth -- immediate process review",
"Consider temporary agency support for critical roles",
"Reduce interview stages to maximum 4",
"Implement hiring manager accountability metrics"
]
},
"promotion_rate": {
"low": [
"Review career ladder clarity -- are paths well-defined?",
"Implement quarterly development conversations",
"Create stretch assignments for high-potential employees",
"Audit promotion criteria for transparency and fairness"
],
"critical": [
"Low promotion rate signals development stagnation",
"Implement individual development plans for all ICs",
"Review if managers have development as part of their goals",
"Consider internal mobility program"
]
}
}
def benchmark(enps, attrition, time_to_fill, promotion_rate, industry):
industry_key = industry.lower()
if industry_key not in BENCHMARKS:
industry_key = "saas" # Default
bench = BENCHMARKS[industry_key]
results = []
metrics_input = {
"enps": enps,
"attrition": attrition,
"time_to_fill": time_to_fill,
"promotion_rate": promotion_rate
}
for metric_key, value in metrics_input.items():
b = bench["metrics"][metric_key]
direction = b["direction"]
if direction == "higher_is_better":
if value >= b["green"]:
status = "GREEN"
elif value >= b["yellow"]:
status = "YELLOW"
else:
status = "RED"
vs_benchmark = round(value - b["benchmark"], 1)
vs_label = f"{'+' if vs_benchmark > 0 else ''}{vs_benchmark} vs benchmark"
else: # lower_is_better
if value <= b["green"]:
status = "GREEN"
elif value <= b["yellow"]:
status = "YELLOW"
else:
status = "RED"
vs_benchmark = round(value - b["benchmark"], 1)
vs_label = f"{'+' if vs_benchmark > 0 else ''}{vs_benchmark} vs benchmark"
recs = []
if status in ("RED", "YELLOW"):
rec_key = "critical" if status == "RED" else "low"
recs = METRIC_RECOMMENDATIONS.get(metric_key, {}).get(rec_key, [])
results.append({
"metric": metric_key,
"value": value,
"unit": b["unit"],
"benchmark": b["benchmark"],
"vs_benchmark": vs_label,
"status": status,
"recommendations": recs
})
# Overall engagement health
red_count = sum(1 for r in results if r["status"] == "RED")
yellow_count = sum(1 for r in results if r["status"] == "YELLOW")
green_count = sum(1 for r in results if r["status"] == "GREEN")
if red_count >= 2:
overall = "CRITICAL"
elif red_count >= 1:
overall = "AT RISK"
elif yellow_count >= 2:
overall = "NEEDS ATTENTION"
else:
overall = "HEALTHY"
return {
"benchmark_date": datetime.now().strftime("%Y-%m-%d"),
"industry": bench["industry_name"],
"overall_status": overall,
"metrics": results,
"summary": {"green": green_count, "yellow": yellow_count, "red": red_count},
"priority_actions": [r["recommendations"][0] for r in results if r["status"] == "RED" and r["recommendations"]]
}
def print_human(result):
print(f"\n{'='*70}")
print(f"ENGAGEMENT BENCHMARKER - {result['industry']}")
print(f"Date: {result['benchmark_date']}")
print(f"Overall: {result['overall_status']}")
print(f"{'='*70}\n")
print("METRICS vs BENCHMARK:")
print("-" * 65)
for m in result["metrics"]:
status_icon = {"GREEN": "+", "YELLOW": "~", "RED": "!"}[m["status"]]
print(f" [{status_icon}] {m['metric']:<18s} {m['value']:>6} {m['unit']:<12s} (benchmark: {m['benchmark']}) {m['vs_benchmark']}")
for m in result["metrics"]:
if m["recommendations"]:
print(f"\n {m['metric'].upper()} [{m['status']}] Recommendations:")
for r in m["recommendations"]:
print(f" -> {r}")
if result["priority_actions"]:
print(f"\nPRIORITY ACTIONS:")
for a in result["priority_actions"]:
print(f" [!] {a}")
print()
def main():
parser = argparse.ArgumentParser(description="Benchmark engagement metrics against industry standards")
parser.add_argument("--enps", type=float, required=True, help="Employee NPS score")
parser.add_argument("--attrition", type=float, required=True, help="Annual attrition rate (%)")
parser.add_argument("--time-to-fill", type=float, required=True, help="Average days to fill a position")
parser.add_argument("--promotion-rate", type=float, required=True, help="Internal promotion rate (%)")
parser.add_argument("--industry", default="saas", choices=list(BENCHMARKS.keys()), help="Industry for benchmarking")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
result = benchmark(args.enps, args.attrition, args.time_to_fill, args.promotion_rate, args.industry)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human(result)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Org Health Scorer - Score 8 dimensions with traffic lights and stage-adjusted weighting.
Calculates overall organizational health from 8 dimension scores with stage-appropriate
weighting. Produces traffic light dashboard, cascade risk analysis, and priorities.
Usage:
python org_health_scorer.py --stage series-a --financial 7.5 --revenue 5.8 --product 7.2 --engineering 5.0 --people 3.5 --operations 6.0 --security 7.8 --market 5.5
python org_health_scorer.py --stage seed --financial 6 --revenue 4 --product 8 --engineering 7 --people 6 --operations 5 --security 4 --market 6 --json
"""
import argparse
import json
import sys
from datetime import datetime
DIMENSIONS = {
"financial": {"name": "Financial Health", "owner": "CFO", "cascade_to": ["people", "engineering", "product"]},
"revenue": {"name": "Revenue Health", "owner": "CRO", "cascade_to": ["financial", "people", "market"]},
"product": {"name": "Product Health", "owner": "CPO", "cascade_to": ["revenue", "market", "people"]},
"engineering": {"name": "Engineering Health", "owner": "CTO", "cascade_to": ["product", "revenue"]},
"people": {"name": "People Health", "owner": "CHRO", "cascade_to": ["engineering", "product", "revenue"]},
"operations": {"name": "Operational Health", "owner": "COO", "cascade_to": ["all"]},
"security": {"name": "Security Health", "owner": "CISO", "cascade_to": ["revenue", "financial"]},
"market": {"name": "Market Health", "owner": "CMO", "cascade_to": ["revenue", "financial"]}
}
STAGE_WEIGHTS = {
"seed": {"financial": 0.20, "revenue": 0.10, "product": 0.25, "engineering": 0.15, "people": 0.10, "operations": 0.05, "security": 0.05, "market": 0.10},
"series-a": {"financial": 0.15, "revenue": 0.20, "product": 0.20, "engineering": 0.15, "people": 0.10, "operations": 0.10, "security": 0.05, "market": 0.05},
"series-b": {"financial": 0.15, "revenue": 0.20, "product": 0.15, "engineering": 0.15, "people": 0.15, "operations": 0.10, "security": 0.05, "market": 0.05},
"series-c": {"financial": 0.15, "revenue": 0.20, "product": 0.10, "engineering": 0.10, "people": 0.15, "operations": 0.15, "security": 0.10, "market": 0.05},
"growth": {"financial": 0.15, "revenue": 0.20, "product": 0.10, "engineering": 0.10, "people": 0.15, "operations": 0.15, "security": 0.10, "market": 0.05}
}
def get_traffic_light(score):
if score >= 7:
return "GREEN"
elif score >= 4:
return "YELLOW"
return "RED"
def score_health(stage, scores):
weights = STAGE_WEIGHTS.get(stage, STAGE_WEIGHTS["series-a"])
dimension_results = []
weighted_total = 0.0
for dim_key, dim_info in DIMENSIONS.items():
score = scores.get(dim_key, 5.0)
weight = weights.get(dim_key, 0.1)
weighted_score = score * weight
weighted_total += weighted_score
traffic = get_traffic_light(score)
dimension_results.append({
"dimension": dim_info["name"],
"key": dim_key,
"owner": dim_info["owner"],
"score": score,
"weight": weight,
"weighted_score": round(weighted_score, 2),
"traffic_light": traffic
})
overall = round(weighted_total, 1)
overall_traffic = get_traffic_light(overall)
# Cascade analysis
red_dimensions = [d for d in dimension_results if d["traffic_light"] == "RED"]
yellow_dimensions = [d for d in dimension_results if d["traffic_light"] == "YELLOW"]
cascade_warnings = []
for red in red_dimensions:
cascades = DIMENSIONS[red["key"]]["cascade_to"]
at_risk = []
for cascade_key in cascades:
if cascade_key == "all":
at_risk = [d["dimension"] for d in dimension_results if d["key"] != red["key"]]
break
matching = [d for d in dimension_results if d["key"] == cascade_key and d["traffic_light"] in ("YELLOW", "RED")]
at_risk.extend([m["dimension"] for m in matching])
if at_risk:
cascade_warnings.append({
"source": red["dimension"],
"source_score": red["score"],
"at_risk_dimensions": at_risk,
"type": "SYSTEMIC" if len(at_risk) >= 2 else "ISOLATED",
"recommendation": f"Address {red['dimension']} ({red['owner']}) first -- cascading to {', '.join(at_risk)}"
})
# Priorities
priorities = sorted(dimension_results, key=lambda d: d["score"])
top_priorities = []
for p in priorities[:3]:
if p["traffic_light"] in ("RED", "YELLOW"):
top_priorities.append({
"dimension": p["dimension"],
"score": p["score"],
"traffic_light": p["traffic_light"],
"owner": p["owner"],
"urgency": "Immediate (30 days)" if p["traffic_light"] == "RED" else "This quarter"
})
# Data gaps (dimensions at exactly 5.0 might be defaults)
data_gaps = [d["dimension"] for d in dimension_results if d["score"] == 5.0]
return {
"diagnostic_date": datetime.now().strftime("%Y-%m-%d"),
"company_stage": stage,
"overall_score": overall,
"overall_traffic_light": overall_traffic,
"trend": "Requires baseline for trend analysis",
"dimensions": dimension_results,
"cascade_warnings": cascade_warnings,
"top_priorities": top_priorities,
"data_gaps": data_gaps,
"red_count": len(red_dimensions),
"yellow_count": len(yellow_dimensions),
"green_count": len([d for d in dimension_results if d["traffic_light"] == "GREEN"])
}
def print_human(result):
print(f"\n{'='*70}")
print(f"ORG HEALTH DIAGNOSTIC -- {result['diagnostic_date']}")
print(f"Stage: {result['company_stage']} Overall: {result['overall_score']}/10 [{result['overall_traffic_light']}]")
print(f"{'='*70}\n")
print("DIMENSION SCORES")
print("-" * 60)
for d in sorted(result["dimensions"], key=lambda x: -x["score"]):
light = {"GREEN": "G", "YELLOW": "Y", "RED": "R"}[d["traffic_light"]]
bar = "#" * int(d["score"]) + "." * (10 - int(d["score"]))
print(f" [{light}] {d['dimension']:<25s} {d['score']:>4.1f} {bar} ({d['owner']}, weight: {d['weight']})")
print(f"\n Summary: {result['green_count']} Green, {result['yellow_count']} Yellow, {result['red_count']} Red")
if result["top_priorities"]:
print(f"\nTOP PRIORITIES (address in order)")
print("-" * 60)
for i, p in enumerate(result["top_priorities"], 1):
print(f" [{p['traffic_light'][0]}] {i}. {p['dimension']}: {p['score']}/10")
print(f" Owner: {p['owner']} | Timeline: {p['urgency']}")
if result["cascade_warnings"]:
print(f"\nCASCADE WARNINGS")
print("-" * 60)
for cw in result["cascade_warnings"]:
print(f" [{cw['type']}] {cw['source']} ({cw['source_score']}/10) -> {', '.join(cw['at_risk_dimensions'])}")
print(f" {cw['recommendation']}")
if result["data_gaps"]:
print(f"\nDATA GAPS (scores at default 5.0 -- may need verification)")
for dg in result["data_gaps"]:
print(f" [?] {dg}")
print()
def main():
parser = argparse.ArgumentParser(description="Score organizational health across 8 dimensions")
parser.add_argument("--stage", required=True, choices=list(STAGE_WEIGHTS.keys()))
parser.add_argument("--financial", type=float, required=True, help="Financial health (1-10)")
parser.add_argument("--revenue", type=float, required=True, help="Revenue health (1-10)")
parser.add_argument("--product", type=float, required=True, help="Product health (1-10)")
parser.add_argument("--engineering", type=float, required=True, help="Engineering health (1-10)")
parser.add_argument("--people", type=float, required=True, help="People health (1-10)")
parser.add_argument("--operations", type=float, required=True, help="Operational health (1-10)")
parser.add_argument("--security", type=float, required=True, help="Security health (1-10)")
parser.add_argument("--market", type=float, required=True, help="Market health (1-10)")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
scores = {
"financial": args.financial, "revenue": args.revenue, "product": args.product,
"engineering": args.engineering, "people": args.people, "operations": args.operations,
"security": args.security, "market": args.market
}
for key, val in scores.items():
if val < 1 or val > 10:
print(f"Error: {key} must be between 1 and 10", file=sys.stderr)
sys.exit(1)
result = score_health(args.stage, scores)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human(result)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Span of Control Analyzer - Analyze manager-to-IC ratios across the organization.
Reads an organization structure (CSV or inline) and calculates span of control
metrics, flagging unhealthy ratios. Healthy range: 1:5 to 1:8 for most roles.
Usage:
python span_of_control_analyzer.py --org-file org_structure.csv
python span_of_control_analyzer.py --managers "CEO:5,VP Eng:8,VP Sales:12,Eng Manager:3,Sales Manager:15" --json
"""
import argparse
import csv
import json
import os
import sys
from datetime import datetime
HEALTHY_RANGE = {"min": 5, "max": 8}
ROLE_ADJUSTMENTS = {
"engineering": {"min": 5, "max": 9, "notes": "Engineering managers can handle slightly larger spans with senior ICs"},
"sales": {"min": 6, "max": 10, "notes": "Sales managers can manage larger teams with clear metrics"},
"support": {"min": 8, "max": 15, "notes": "Support teams can have larger spans with process-driven work"},
"executive": {"min": 4, "max": 7, "notes": "Executives need smaller spans for strategic leadership"},
"default": {"min": 5, "max": 8, "notes": "Standard management span"}
}
def classify_span(direct_reports, role_type="default"):
adj = ROLE_ADJUSTMENTS.get(role_type, ROLE_ADJUSTMENTS["default"])
if direct_reports < adj["min"]:
return {"status": "TOO_NARROW", "color": "YELLOW", "issue": f"Span too narrow ({direct_reports}); healthy range: {adj['min']}-{adj['max']}. Risk: management overhead, micromanagement"}
elif direct_reports > adj["max"]:
return {"status": "TOO_WIDE", "color": "RED" if direct_reports > adj["max"] * 1.5 else "YELLOW", "issue": f"Span too wide ({direct_reports}); healthy range: {adj['min']}-{adj['max']}. Risk: insufficient coaching, burnout"}
return {"status": "HEALTHY", "color": "GREEN", "issue": None}
def analyze_from_managers(managers_data):
"""Analyze from a dictionary of manager: direct_reports."""
results = []
for manager, reports in managers_data.items():
role_type = "default"
lower = manager.lower()
if any(k in lower for k in ["eng", "tech", "cto"]):
role_type = "engineering"
elif any(k in lower for k in ["sale", "cro", "revenue"]):
role_type = "sales"
elif any(k in lower for k in ["support", "cs ", "service"]):
role_type = "support"
elif any(k in lower for k in ["ceo", "coo", "cfo", "vp", "chief", "svp"]):
role_type = "executive"
classification = classify_span(reports, role_type)
results.append({
"manager": manager,
"direct_reports": reports,
"role_type": role_type,
"status": classification["status"],
"color": classification["color"],
"issue": classification["issue"]
})
return results
def analyze_from_csv(filepath):
"""Read CSV with columns: employee_name, manager_name, role."""
if not os.path.exists(filepath):
print(f"Error: File not found: {filepath}", file=sys.stderr)
sys.exit(1)
manager_counts = {}
manager_roles = {}
with open(filepath, "r") as f:
reader = csv.DictReader(f)
for row in reader:
mgr = row.get("manager_name", row.get("manager", "")).strip()
if mgr:
manager_counts[mgr] = manager_counts.get(mgr, 0) + 1
if mgr not in manager_roles:
manager_roles[mgr] = row.get("manager_role", row.get("role", "default"))
managers_data = {}
for mgr, count in manager_counts.items():
managers_data[mgr] = count
return analyze_from_managers(managers_data)
def generate_report(results):
total_managers = len(results)
healthy = [r for r in results if r["status"] == "HEALTHY"]
too_narrow = [r for r in results if r["status"] == "TOO_NARROW"]
too_wide = [r for r in results if r["status"] == "TOO_WIDE"]
avg_span = round(sum(r["direct_reports"] for r in results) / total_managers, 1) if total_managers > 0 else 0
median_span = sorted(r["direct_reports"] for r in results)[total_managers // 2] if total_managers > 0 else 0
health_pct = round(len(healthy) / total_managers * 100) if total_managers > 0 else 0
recommendations = []
for r in too_wide:
if r["direct_reports"] > 12:
recommendations.append(f"URGENT: {r['manager']} has {r['direct_reports']} reports -- split team or add manager layer")
else:
recommendations.append(f"{r['manager']} has {r['direct_reports']} reports -- consider adding team lead")
for r in too_narrow:
if r["direct_reports"] < 3:
recommendations.append(f"{r['manager']} has only {r['direct_reports']} reports -- consider merging teams or expanding scope")
return {
"analysis_date": datetime.now().strftime("%Y-%m-%d"),
"total_managers": total_managers,
"average_span": avg_span,
"median_span": median_span,
"healthy_percentage": health_pct,
"summary": {
"healthy": len(healthy),
"too_narrow": len(too_narrow),
"too_wide": len(too_wide)
},
"managers": sorted(results, key=lambda r: -r["direct_reports"]),
"recommendations": recommendations
}
def print_human(report):
print(f"\n{'='*70}")
print(f"SPAN OF CONTROL ANALYSIS")
print(f"Date: {report['analysis_date']}")
print(f"{'='*70}\n")
print(f"Managers Analyzed: {report['total_managers']}")
print(f"Average Span: {report['average_span']}")
print(f"Median Span: {report['median_span']}")
print(f"Healthy: {report['healthy_percentage']}%")
print(f" Green: {report['summary']['healthy']} | Narrow: {report['summary']['too_narrow']} | Wide: {report['summary']['too_wide']}\n")
print("MANAGER DETAILS:")
print("-" * 70)
for m in report["managers"]:
status_icon = {"GREEN": "+", "YELLOW": "~", "RED": "!"}[m["color"]]
print(f" [{status_icon}] {m['manager']:<30s} {m['direct_reports']:>3} reports ({m['role_type']}) {m['status']}")
if report["recommendations"]:
print(f"\nRECOMMENDATIONS:")
for r in report["recommendations"]:
print(f" -> {r}")
print()
def main():
parser = argparse.ArgumentParser(description="Analyze manager-to-IC span of control ratios")
parser.add_argument("--org-file", help="CSV file with employee_name, manager_name columns")
parser.add_argument("--managers", help="Inline format: 'Manager1:reports,Manager2:reports'")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
if args.org_file:
results = analyze_from_csv(args.org_file)
elif args.managers:
managers_data = {}
for pair in args.managers.split(","):
parts = pair.strip().rsplit(":", 1)
if len(parts) == 2:
managers_data[parts[0].strip()] = int(parts[1].strip())
results = analyze_from_managers(managers_data)
else:
print("Error: Provide either --org-file or --managers", file=sys.stderr)
sys.exit(1)
report = generate_report(results)
if args.json:
print(json.dumps(report, indent=2))
else:
print_human(report)
if __name__ == "__main__":
main()
Related skills
FAQ
How many dimensions does it score?
Eight: financial, revenue, product, engineering, people, operational, security, and market health, each owned by a C-suite role.
What scale does it use?
A traffic-light scale of Green (7-10), Yellow (4-6), and Red (1-3) against benchmark metrics.