
Coo Advisor
- 189 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Pressure-test operational plans, org design, and execution scope with a COO-style advisor before committing engineering and hiring resources.
About
The coo-advisor skill simulates a Chief Operating Officer reviewing how a venture will actually run day to day: team structure, process design, vendor choices, milestone sequencing, and operational risk before code ships at scale. Founders and leads use it during validation to tighten scope, avoid overbuilding org complexity early, and align product bets with sustainable execution capacity.
- COO lens on ops model and execution risk
- Clarifies sequencing of people, process, and tooling
- Surfaces bottlenecks before scale breaks the team
- Useful for founders planning second-phase operations
- Complements product strategy with run-the-business view
Coo Advisor by the numbers
- 189 all-time installs (skills.sh)
- Ranked #1,074 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/borghei/claude-skills --skill coo-advisorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 189 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Pressure-test operational plans, org design, and execution scope with a COO-style advisor before committing engineering and hiring resources.
Files
COO Advisor
The agent acts as a fractional COO, providing operational strategy and process design grounded in maturity-model thinking and data-driven optimization.
Workflow
1. Assess operational maturity -- Place the organization on the Operations Maturity Model (Levels 1-4). Validate the assessment by checking for documented processes, KPI dashboards, and automation coverage. 2. Map critical processes -- Identify the top 5 processes by volume or business impact. Document each using the Process Documentation Standard. 3. Identify waste -- For each mapped process, catalogue waiting time, rework loops, manual steps, and approval bottlenecks. Quantify cycle time and cost per transaction. 4. Prioritize improvements -- Plot identified improvements on the Automation Priority Matrix. Select quick wins (high value, low effort) for immediate action. 5. Design operating rhythm -- Establish the meeting cadence (daily, weekly, monthly, quarterly) and assign owners. Verify each meeting has a defined purpose and output. 6. Build capacity model -- Apply the headcount formula to forecast resource needs. Factor in attrition, ramp time, and seasonal variation. 7. Establish metrics and reporting -- Configure the Operational Dashboard and set targets for efficiency, quality, and scalability KPIs.
Operations Maturity Model
| Level | Name | Characteristics |
|---|---|---|
| 1 | Ad Hoc | Informal processes, tribal knowledge, reactive problem solving |
| 2 | Defined | Documented processes, basic metrics, some automation |
| 3 | Managed | KPI dashboards, regular reviews, continuous improvement |
| 4 | Optimized | Data-driven decisions, automated workflows, industry-leading efficiency |
Process Documentation Standard
# Process Name
## Purpose
[Why this process exists]
## Owner
[Single accountable person]
## Trigger
[What initiates this process]
## Inputs
[What is needed to start]
## Steps
1. [Step with responsible party]
2. [Step with responsible party]
3. [Step with responsible party]
## Outputs
[What is produced]
## SLAs
[Time and quality expectations]
## Exceptions
[How to handle edge cases]Operating Rhythm
| Meeting | Frequency | Duration | Attendees | Purpose |
|---|---|---|---|---|
| Standup | Daily | 15 min | Team | Issue escalation, key metrics |
| Dept Sync | Weekly | 45 min | Dept heads | Cross-functional coordination |
| Leadership Sync | Weekly | 60 min | Execs | Alignment |
| Business Review | Monthly | 90 min | Leadership | Performance deep-dive |
| QBR | Quarterly | Half day | Leadership | Strategy and OKR assessment |
Headcount Capacity Model
Required HC = Volume / (Productivity x Utilization)
Volume: Work units per period
Productivity: Units per person per period
Utilization: Available time percentage (typically 75-85%)Adjustment factors: Attrition rate (10-20%), ramp time for new hires, seasonal variation, growth assumptions.
Automation Priority Matrix
High Value
|
Quick Wins -----+----- Strategic Projects
(Do First) | (Plan Carefully)
|
Low Effort ---------+--------- High Effort
|
Fill-ins -----+----- Reconsider
(Do When Available) | (May Not Be Worth It)
|
Low ValueOperational KPIs
| Category | Metrics |
|---|---|
| Efficiency | Process cycle time, first-time completion rate, cost per transaction, automation rate |
| Quality | Error rate, rework %, customer satisfaction, SLA compliance |
| Scalability | Volume growth handling, cost per unit trend, capacity utilization, bottleneck count |
Operational Dashboard Structure
OPERATIONAL HEALTH
+-- Volume metrics (transactions, requests, tickets)
+-- Quality metrics (errors, rework, satisfaction)
+-- Efficiency metrics (cycle time, cost per unit)
+-- Capacity metrics (utilization, backlog)
TEAM PERFORMANCE
+-- Productivity per person
+-- SLA achievement
+-- Training completion
+-- Engagement score
SYSTEM HEALTH
+-- System uptime
+-- Integration status
+-- Processing latency
+-- Error ratesIncident Classification
| Level | Impact | Response Time | Communication |
|---|---|---|---|
| P1 | Business critical | 15 min | Exec + all stakeholders |
| P2 | Major impact | 1 hour | Leadership + affected teams |
| P3 | Moderate impact | 4 hours | Team leads |
| P4 | Minor impact | 24 hours | Direct reports |
Vendor Management
Selection criteria: Capability fit, financial stability, reference quality, service levels, pricing competitiveness, contract flexibility.
Review cadence: Weekly (operational issues), Monthly (performance metrics), Quarterly (business review), Annual (contract renewal).
BCP Framework
1. Risk assessment -- Identify critical processes, assess disruption impact, determine recovery priorities, document dependencies. 2. Continuity planning -- Define RTO/RPO, identify alternate resources, document procedures, assign responsibilities. 3. Testing -- Annual tabletop exercises, periodic recovery drills, plan updates after changes, post-incident reviews.
Example: Scaling Customer Onboarding (Series B SaaS)
A Series-B SaaS company onboards 40 new customers/month with a 5-person onboarding team. Current cycle time is 21 days.
Current state:
Volume: 40 customers/month
Productivity: 8 customers/person/month
Utilization: 80%
Required HC: 40 / (8 x 0.80) = 6.25 -> 7 FTEs (gap: 2 hires)
Optimization targets:
Automate provisioning step (saves 3 days) -> cycle time: 18 days
Self-serve data migration portal (saves 2 days) -> cycle time: 16 days
Revised productivity: 10 customers/person/month
Required HC at 80 customers/month: 80 / (10 x 0.80) = 10 FTEs
Investment: 1 eng sprint for automation + $15K/yr portal tooling
ROI: Handles 2x volume with 43% fewer incremental hiresBudget Variance Analysis
1. Compare actual vs budget by category (personnel, technology, facilities, services, travel) 2. Identify root causes for variances exceeding 10% 3. Adjust rolling forecast 4. Document corrective actions with owners and deadlines
Scripts
# Process efficiency analyzer
python scripts/process_analyzer.py --process onboarding
# Capacity planning calculator
python scripts/capacity_planner.py --forecast demand.csv
# Vendor scorecard generator
python scripts/vendor_scorecard.py --vendors vendors.yaml
# Operational dashboard builder
python scripts/ops_dashboard.py --metrics metrics.jsonReferences
references/process_templates.md-- Standard process documentationreferences/scaling_playbook.md-- Scaling operations guidereferences/vendor_management.md-- Vendor relationship frameworkreferences/bcp_template.md-- Business continuity planning
---
Tool Reference
1. operational_kpi_tracker.py
Tracks operational KPIs across efficiency, quality, and scalability categories. Calculates health scores, detects trends, flags at-risk metrics, and generates improvement recommendations.
python scripts/operational_kpi_tracker.py --input kpi_data.json --json
python scripts/operational_kpi_tracker.py --input kpi_data.json| Flag | Type | Description |
|---|---|---|
--input | required | Path to JSON file with KPI categories, metrics, targets, and actuals over time |
--json | optional | Output in JSON format instead of human-readable text |
2. process_efficiency_scorer.py
Scores process efficiency across cycle time, first-time completion rate, cost per transaction, automation rate, error rate, and rework percentage. Identifies bottlenecks and prioritizes improvement opportunities.
python scripts/process_efficiency_scorer.py --input processes.json --json
python scripts/process_efficiency_scorer.py --input processes.json| Flag | Type | Description |
|---|---|---|
--input | required | Path to JSON file with process definitions, step-level metrics, and benchmarks |
--json | optional | Output in JSON format instead of human-readable text |
3. capacity_modeler.py
Models headcount capacity requirements using the formula: Required HC = Volume / (Productivity x Utilization). Factors in attrition, ramp time, seasonal variation, and growth projections.
python scripts/capacity_modeler.py --input capacity_data.json --json
python scripts/capacity_modeler.py --input capacity_data.json| Flag | Type | Description |
|---|---|---|
--input | required | Path to JSON file with volume forecasts, productivity rates, utilization targets, and adjustment factors |
--json | optional | Output in JSON format instead of human-readable text |
---
Troubleshooting
| Problem | Likely Cause | Resolution |
|---|---|---|
| KPI dashboard shows green but operations feel broken | Metrics not measuring what matters or targets set too loosely | Audit KPIs against actual customer/team complaints; tighten targets to match industry benchmarks |
| Process documentation exists but nobody follows it | Documentation created top-down without practitioner input | Rebuild SOPs with process owners; validate with frontline team; schedule quarterly reviews |
| Automation projects stall after initial wins | Quick wins captured but strategic projects lack sustained investment | Use Automation Priority Matrix; assign dedicated owners to strategic projects; protect automation budget |
| Capacity model consistently under-predicts needs | Ramp time, attrition, or seasonal variation not factored | Add adjustment factors for attrition (10-20%), ramp time (3-6 months), and seasonal peaks |
| Operating rhythm meetings feel unproductive | Meetings lack defined purpose, output, or decision rights | Redesign each meeting using the Operating Rhythm table; require agenda, output artifact, and decision owner |
| Vendor performance degrading without consequence | No SLA monitoring or regular performance reviews | Implement quarterly vendor scorecards; tie contract renewal to SLA compliance |
---
Success Criteria
- Operations Maturity Model level increases by at least 1 level within 12 months
- Top 5 processes documented with owners, SLAs, and exception handling
- Process cycle time reduced by 20%+ for at least 2 critical processes
- Automation rate exceeds 40% for high-volume, low-complexity processes
- Headcount capacity model accuracy within 10% of actual needs
- Incident response meets SLA targets for P1 (15 min) and P2 (1 hour) consistently
- Budget variance stays within 10% for all operational categories
---
Scope & Limitations
In scope: Operations maturity assessment, process documentation and optimization, headcount capacity modeling, operational KPI tracking and dashboarding, automation prioritization, vendor management frameworks, incident classification and response, business continuity planning, budget variance analysis, and operating rhythm design.
Out of scope: IT infrastructure management (use engineering/ skills), HR policy design (use hr-operations/ skills), financial planning and FP&A (use finance/ skills), product operations (use cpo-advisor), and real-time monitoring system implementation. Tools analyze operational data snapshots; continuous monitoring requires integration with operational platforms.
Limitations: Capacity modeling assumes stable productivity rates; significant process changes invalidate projections. KPI benchmarks are based on aggregate industry data and vary by company size, vertical, and operating model. Process efficiency scoring requires accurate step-level timing data that may not be available without process mining tools.
---
Integration Points
- ceo-advisor -- Operational health metrics feed into strategic decision-making and board reporting
- cfo-advisor -- Budget variance analysis and capacity costs inform financial planning
- cro-advisor -- RevOps staffing and commission infrastructure depend on operational capacity
- cpo-advisor -- Product operations and delivery capacity affect roadmap execution
- chro-advisor -- Headcount planning and team scaling require HR partnership
- ciso-advisor -- BCP and incident response intersect with security operations
#!/usr/bin/env python3
"""
Capacity Modeler - Model headcount capacity requirements.
Uses formula: Required HC = Volume / (Productivity x Utilization).
Factors in attrition, ramp time, seasonal variation, and growth projections.
Generates quarterly hiring plans with cost estimates.
Usage:
python capacity_modeler.py --input capacity_data.json
python capacity_modeler.py --input capacity_data.json --json
"""
import argparse
import json
import math
import sys
from datetime import datetime
def load_data(path):
with open(path, "r") as f:
return json.load(f)
def calculate_required_hc(volume, productivity, utilization):
"""Core capacity formula: Required HC = Volume / (Productivity x Utilization)."""
if productivity <= 0 or utilization <= 0:
return 0
return volume / (productivity * utilization)
def apply_adjustments(base_hc, adjustments):
"""Apply adjustment factors to base headcount."""
attrition_rate = adjustments.get("attrition_rate_pct", 15) / 100
ramp_factor = adjustments.get("ramp_factor", 0.85)
buffer_pct = adjustments.get("buffer_pct", 10) / 100
# Attrition adjustment: need extra HC to cover expected departures
attrition_adjusted = base_hc / (1 - attrition_rate)
# Ramp adjustment: new hires not at full productivity
ramp_adjusted = attrition_adjusted / ramp_factor
# Buffer for unexpected demand
buffered = ramp_adjusted * (1 + buffer_pct)
return {
"base_hc": round(base_hc, 1),
"after_attrition": round(attrition_adjusted, 1),
"after_ramp": round(ramp_adjusted, 1),
"with_buffer": round(buffered, 1),
"final_required": math.ceil(buffered),
}
def model_quarters(data):
"""Model capacity across multiple quarters with growth."""
teams = data.get("teams", [])
quarters = data.get("quarters", 4)
growth_rate_pct = data.get("quarterly_growth_rate_pct", 10)
adjustments = data.get("adjustments", {})
cost_per_fte = data.get("cost_per_fte_annual", 80000)
seasonal_factors = data.get("seasonal_factors", [1.0] * quarters)
results = {
"timestamp": datetime.now().isoformat(),
"organization": data.get("organization", "Organization"),
"quarters_modeled": quarters,
"team_models": [],
"quarterly_totals": [],
"hiring_plan": [],
"cost_projection": {},
"summary": {},
"recommendations": [],
}
grand_total_current = 0
grand_total_required = 0
total_hiring_cost = 0
for team in teams:
team_name = team.get("name", "Team")
current_hc = team.get("current_headcount", 0)
base_volume = team.get("volume_per_period", 0)
productivity = team.get("productivity_per_person", 1)
utilization = team.get("utilization_pct", 80) / 100
grand_total_current += current_hc
team_quarters = []
prev_required = current_hc
for q in range(quarters):
growth_mult = (1 + growth_rate_pct / 100) ** q
seasonal = seasonal_factors[q] if q < len(seasonal_factors) else 1.0
projected_volume = base_volume * growth_mult * seasonal
raw_hc = calculate_required_hc(projected_volume, productivity, utilization)
adjusted = apply_adjustments(raw_hc, adjustments)
gap = adjusted["final_required"] - current_hc if q == 0 else adjusted["final_required"] - prev_required
hires_needed = max(0, gap)
team_quarters.append({
"quarter": f"Q{q + 1}",
"projected_volume": round(projected_volume, 0),
"raw_required": round(raw_hc, 1),
"adjusted_required": adjusted["final_required"],
"gap": gap,
"hires_needed": math.ceil(hires_needed) if hires_needed > 0 else 0,
"adjustments": adjusted,
})
prev_required = adjusted["final_required"]
total_hires = sum(q["hires_needed"] for q in team_quarters)
final_hc = team_quarters[-1]["adjusted_required"] if team_quarters else current_hc
team_model = {
"name": team_name,
"current_headcount": current_hc,
"final_required": final_hc,
"total_hires_needed": total_hires,
"quarters": team_quarters,
}
results["team_models"].append(team_model)
grand_total_required += final_hc
# Aggregate quarterly totals
for q in range(quarters):
q_total_required = 0
q_total_hires = 0
for team in results["team_models"]:
if q < len(team["quarters"]):
q_total_required += team["quarters"][q]["adjusted_required"]
q_total_hires += team["quarters"][q]["hires_needed"]
results["quarterly_totals"].append({
"quarter": f"Q{q + 1}",
"total_required": q_total_required,
"total_hires": q_total_hires,
"quarterly_cost": round(q_total_hires * cost_per_fte * 0.25, 0),
})
# Cost projection
total_hires = sum(qt["total_hires"] for qt in results["quarterly_totals"])
total_hiring_cost = total_hires * cost_per_fte
recruiting_cost = total_hires * cost_per_fte * 0.2
onboarding_cost = total_hires * 10000
results["cost_projection"] = {
"total_new_hires": total_hires,
"annual_salary_cost": round(total_hiring_cost, 0),
"recruiting_cost": round(recruiting_cost, 0),
"onboarding_cost": round(onboarding_cost, 0),
"total_investment": round(total_hiring_cost + recruiting_cost + onboarding_cost, 0),
"cost_per_fte": cost_per_fte,
}
# Summary
results["summary"] = {
"current_total_hc": grand_total_current,
"projected_required_hc": grand_total_required,
"total_hiring_gap": grand_total_required - grand_total_current,
"growth_percentage": round(((grand_total_required / max(grand_total_current, 1)) - 1) * 100, 1),
"teams_modeled": len(teams),
}
# Recommendations
recs = results["recommendations"]
growth = results["summary"]["growth_percentage"]
if growth > 50:
recs.append(f"High growth ({growth}%) -- implement structured onboarding and mentorship programs")
recs.append("Consider phased hiring to avoid diluting team quality")
if growth > 100:
recs.append("CAUTION: >100% growth planned -- review if timeline is realistic given recruiting capacity")
max_quarterly_hires = max((qt["total_hires"] for qt in results["quarterly_totals"]), default=0)
if max_quarterly_hires > grand_total_current * 0.25:
recs.append(f"Peak quarter needs {max_quarterly_hires} hires -- ensure recruiting capacity (1 recruiter per 15-20 hires/quarter)")
attrition = adjustments.get("attrition_rate_pct", 15)
if attrition > 20:
recs.append(f"Attrition rate {attrition}% is high -- address retention before scaling")
return results
def format_text(results):
lines = [
"=" * 60,
"CAPACITY MODEL",
"=" * 60,
f"Organization: {results['organization']}",
f"Quarters Modeled: {results['quarters_modeled']}",
f"Analysis Date: {results['timestamp'][:10]}",
"",
"SUMMARY",
f" Current Headcount: {results['summary']['current_total_hc']}",
f" Projected Required: {results['summary']['projected_required_hc']}",
f" Hiring Gap: {results['summary']['total_hiring_gap']}",
f" Growth: {results['summary']['growth_percentage']}%",
"",
"QUARTERLY TOTALS",
]
for qt in results["quarterly_totals"]:
lines.append(f" {qt['quarter']}: {qt['total_required']} required (+{qt['total_hires']} hires, ${qt['quarterly_cost']:,.0f})")
lines.append("")
lines.append("TEAM DETAIL")
for team in results["team_models"]:
lines.append(f"\n {team['name']}")
lines.append(f" Current: {team['current_headcount']} | Target: {team['final_required']} | Hires: {team['total_hires_needed']}")
for q in team["quarters"]:
lines.append(
f" {q['quarter']}: volume={q['projected_volume']:.0f}, "
f"required={q['adjusted_required']}, hires={q['hires_needed']}"
)
lines.append("")
lines.append("COST PROJECTION")
cp = results["cost_projection"]
lines.append(f" Total New Hires: {cp['total_new_hires']}")
lines.append(f" Annual Salary Cost: ${cp['annual_salary_cost']:,.0f}")
lines.append(f" Recruiting Cost: ${cp['recruiting_cost']:,.0f}")
lines.append(f" Onboarding Cost: ${cp['onboarding_cost']:,.0f}")
lines.append(f" Total Investment: ${cp['total_investment']:,.0f}")
if results["recommendations"]:
lines.append("")
lines.append("RECOMMENDATIONS")
for rec in results["recommendations"]:
lines.append(f" * {rec}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Model headcount capacity requirements with growth projections")
parser.add_argument("--input", required=True, help="Path to JSON capacity data file")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
try:
data = load_data(args.input)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"Error loading input file: {e}", file=sys.stderr)
sys.exit(1)
results = model_quarters(data)
if args.json:
print(json.dumps(results, indent=2))
else:
print(format_text(results))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Operational KPI Tracker - Track operational KPIs across efficiency, quality, scalability.
Calculates health scores, detects trends, flags at-risk metrics, and generates
improvement recommendations based on operational maturity level.
Usage:
python operational_kpi_tracker.py --input kpi_data.json
python operational_kpi_tracker.py --input kpi_data.json --json
"""
import argparse
import json
import sys
from datetime import datetime
KPI_CATEGORIES = {
"efficiency": {
"weight": 0.35,
"metrics": ["cycle_time", "first_time_completion", "cost_per_transaction", "automation_rate"],
},
"quality": {
"weight": 0.35,
"metrics": ["error_rate", "rework_pct", "customer_satisfaction", "sla_compliance"],
},
"scalability": {
"weight": 0.30,
"metrics": ["volume_growth_handling", "cost_per_unit_trend", "capacity_utilization", "bottleneck_count"],
},
}
def load_data(path):
with open(path, "r") as f:
return json.load(f)
def score_metric(metric_name, actual, target, direction="lower_better"):
"""Score a single metric 0-100 based on target achievement."""
if target == 0:
return 50.0
if direction == "lower_better":
# For metrics where lower is better (error_rate, cycle_time, cost)
if actual <= target:
return min(100, round((target / max(actual, 0.01)) * 50 + 50, 1))
else:
return max(0, round((target / actual) * 50, 1))
else:
# For metrics where higher is better (satisfaction, completion rate)
if actual >= target:
return min(100, round((actual / target) * 50 + 50, 1))
else:
return max(0, round((actual / max(target, 0.01)) * 50, 1))
METRIC_DIRECTIONS = {
"cycle_time": "lower_better",
"first_time_completion": "higher_better",
"cost_per_transaction": "lower_better",
"automation_rate": "higher_better",
"error_rate": "lower_better",
"rework_pct": "lower_better",
"customer_satisfaction": "higher_better",
"sla_compliance": "higher_better",
"volume_growth_handling": "higher_better",
"cost_per_unit_trend": "lower_better",
"capacity_utilization": "higher_better",
"bottleneck_count": "lower_better",
}
def get_health_label(score):
if score >= 80:
return "Healthy"
elif score >= 60:
return "Acceptable"
elif score >= 40:
return "At Risk"
else:
return "Critical"
def detect_trend(periods):
"""Detect trend direction from period-over-period data."""
if len(periods) < 2:
return "insufficient_data"
last = periods[-1]
prev = periods[-2]
if last > prev * 1.05:
return "improving" if last > prev else "declining"
elif last < prev * 0.95:
return "declining" if last < prev else "improving"
return "stable"
def analyze_kpis(data):
"""Run full KPI analysis."""
org_name = data.get("organization", "Organization")
maturity_level = data.get("maturity_level", 2)
kpi_data = data.get("kpis", {})
periods = data.get("periods", [])
results = {
"timestamp": datetime.now().isoformat(),
"organization": org_name,
"maturity_level": maturity_level,
"overall_health_score": 0,
"overall_health_label": "",
"category_scores": {},
"metric_details": [],
"at_risk_metrics": [],
"trends": [],
"recommendations": [],
}
total_weighted_score = 0
for category, config in KPI_CATEGORIES.items():
cat_data = kpi_data.get(category, {})
cat_scores = []
for metric_name in config["metrics"]:
metric_info = cat_data.get(metric_name, {})
actual = metric_info.get("actual", 0)
target = metric_info.get("target", 0)
direction = METRIC_DIRECTIONS.get(metric_name, "lower_better")
history = metric_info.get("history", [])
score = score_metric(metric_name, actual, target, direction)
cat_scores.append(score)
trend = detect_trend(history) if history else "no_data"
detail = {
"category": category,
"metric": metric_name,
"actual": actual,
"target": target,
"score": score,
"health": get_health_label(score),
"trend": trend,
}
results["metric_details"].append(detail)
if score < 50:
results["at_risk_metrics"].append({
"metric": metric_name,
"category": category,
"score": score,
"actual": actual,
"target": target,
"gap": round(abs(actual - target), 2),
})
if trend in ("improving", "declining"):
results["trends"].append({
"metric": metric_name,
"trend": trend,
"current": actual,
})
cat_avg = round(sum(cat_scores) / max(len(cat_scores), 1), 1)
weighted = round(cat_avg * config["weight"], 1)
total_weighted_score += weighted
results["category_scores"][category] = {
"score": cat_avg,
"weighted_score": weighted,
"health": get_health_label(cat_avg),
"metrics_count": len(cat_scores),
}
results["overall_health_score"] = round(total_weighted_score, 1)
results["overall_health_label"] = get_health_label(total_weighted_score)
# Sort at-risk by score (worst first)
results["at_risk_metrics"].sort(key=lambda x: x["score"])
# Generate recommendations
recs = results["recommendations"]
if total_weighted_score < 40:
recs.append("CRITICAL: Overall operational health below 40 -- immediate leadership attention required")
if maturity_level < 3 and total_weighted_score > 60:
recs.append("Consider advancing to Maturity Level 3 (Managed) -- metrics support the transition")
for ar in results["at_risk_metrics"][:3]:
if ar["category"] == "efficiency":
recs.append(f"Improve {ar['metric']}: current {ar['actual']} vs target {ar['target']} -- review process automation opportunities")
elif ar["category"] == "quality":
recs.append(f"Address {ar['metric']}: current {ar['actual']} vs target {ar['target']} -- implement quality gates and root cause analysis")
elif ar["category"] == "scalability":
recs.append(f"Scale {ar['metric']}: current {ar['actual']} vs target {ar['target']} -- evaluate capacity and infrastructure")
declining = [t for t in results["trends"] if t["trend"] == "declining"]
if declining:
recs.append(f"Declining trends detected in: {', '.join(t['metric'] for t in declining[:3])}")
return results
def format_text(results):
lines = [
"=" * 60,
"OPERATIONAL KPI DASHBOARD",
"=" * 60,
f"Organization: {results['organization']}",
f"Maturity Level: {results['maturity_level']}/4",
f"Analysis Date: {results['timestamp'][:10]}",
"",
f"OVERALL HEALTH: {results['overall_health_score']}/100 ({results['overall_health_label']})",
"",
"CATEGORY SCORES",
]
for cat, scores in results["category_scores"].items():
lines.append(f" {cat.title()}: {scores['score']}/100 ({scores['health']})")
if results["at_risk_metrics"]:
lines.append("")
lines.append("AT-RISK METRICS")
for ar in results["at_risk_metrics"]:
lines.append(f" {ar['metric']} ({ar['category']}): score={ar['score']}, actual={ar['actual']}, target={ar['target']}")
lines.append("")
lines.append("METRIC DETAILS")
for detail in results["metric_details"]:
trend_arrow = {"improving": "+", "declining": "-", "stable": "=", "no_data": "?", "insufficient_data": "?"}
lines.append(
f" [{trend_arrow.get(detail['trend'], '?')}] {detail['metric']}: "
f"{detail['actual']} (target: {detail['target']}) -- {detail['health']}"
)
if results["recommendations"]:
lines.append("")
lines.append("RECOMMENDATIONS")
for rec in results["recommendations"]:
lines.append(f" * {rec}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Track operational KPIs with health scoring and trend detection")
parser.add_argument("--input", required=True, help="Path to JSON KPI data file")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
try:
data = load_data(args.input)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"Error loading input file: {e}", file=sys.stderr)
sys.exit(1)
results = analyze_kpis(data)
if args.json:
print(json.dumps(results, indent=2))
else:
print(format_text(results))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Process Efficiency Scorer - Score process efficiency and identify bottlenecks.
Evaluates processes across cycle time, first-time completion, cost per transaction,
automation rate, error rate, and rework. Identifies bottlenecks and prioritizes
improvement opportunities using the Automation Priority Matrix.
Usage:
python process_efficiency_scorer.py --input processes.json
python process_efficiency_scorer.py --input processes.json --json
"""
import argparse
import json
import sys
from datetime import datetime
def load_data(path):
with open(path, "r") as f:
return json.load(f)
def score_dimension(actual, target, lower_is_better=True):
"""Score a dimension 0-100."""
if target == 0:
return 50
if lower_is_better:
ratio = target / max(actual, 0.001)
else:
ratio = actual / max(target, 0.001)
return max(0, min(100, round(ratio * 100, 1)))
def identify_bottlenecks(steps):
"""Identify bottleneck steps in a process."""
if not steps:
return []
bottlenecks = []
avg_time = sum(s.get("duration_hours", 0) for s in steps) / max(len(steps), 1)
for step in steps:
duration = step.get("duration_hours", 0)
wait_time = step.get("wait_time_hours", 0)
error_rate = step.get("error_rate_pct", 0)
is_manual = step.get("is_manual", True)
issues = []
if duration > avg_time * 1.5:
issues.append(f"Duration {duration}h exceeds avg {avg_time:.1f}h by {((duration/avg_time)-1)*100:.0f}%")
if wait_time > duration * 0.5:
issues.append(f"Wait time {wait_time}h is {(wait_time/max(duration,0.1))*100:.0f}% of step duration")
if error_rate > 5:
issues.append(f"Error rate {error_rate}% exceeds 5% threshold")
if is_manual and duration > 2:
issues.append("Manual step taking >2 hours -- automation candidate")
if issues:
bottlenecks.append({
"step": step.get("name", "Unknown"),
"severity": "high" if len(issues) >= 2 else "medium",
"issues": issues,
"duration_hours": duration,
"wait_time_hours": wait_time,
"is_manual": is_manual,
})
bottlenecks.sort(key=lambda x: 0 if x["severity"] == "high" else 1)
return bottlenecks
def classify_automation_priority(value_score, effort_score):
"""Classify using the Automation Priority Matrix."""
if value_score >= 60 and effort_score <= 40:
return "Quick Win (Do First)"
elif value_score >= 60 and effort_score > 40:
return "Strategic Project (Plan Carefully)"
elif value_score < 60 and effort_score <= 40:
return "Fill-in (Do When Available)"
else:
return "Reconsider (May Not Be Worth It)"
def analyze_processes(data):
"""Analyze all processes."""
processes = data.get("processes", [])
org_name = data.get("organization", "Organization")
results = {
"timestamp": datetime.now().isoformat(),
"organization": org_name,
"process_count": len(processes),
"processes": [],
"overall_efficiency_score": 0,
"top_bottlenecks": [],
"automation_opportunities": [],
"recommendations": [],
}
total_scores = []
for proc in processes:
name = proc.get("name", "Unknown Process")
metrics = proc.get("metrics", {})
steps = proc.get("steps", [])
benchmarks = proc.get("benchmarks", {})
# Score each dimension
dimensions = {}
dimension_list = [
("cycle_time", metrics.get("cycle_time_hours", 0), benchmarks.get("cycle_time_hours", 24), True),
("first_time_completion", metrics.get("first_time_completion_pct", 0), benchmarks.get("first_time_completion_pct", 90), False),
("cost_per_transaction", metrics.get("cost_per_transaction", 0), benchmarks.get("cost_per_transaction", 50), True),
("automation_rate", metrics.get("automation_rate_pct", 0), benchmarks.get("automation_rate_pct", 60), False),
("error_rate", metrics.get("error_rate_pct", 0), benchmarks.get("error_rate_pct", 2), True),
("rework_pct", metrics.get("rework_pct", 0), benchmarks.get("rework_pct", 5), True),
]
for dim_name, actual, target, lower_better in dimension_list:
score = score_dimension(actual, target, lower_better)
dimensions[dim_name] = {
"actual": actual,
"target": target,
"score": score,
}
avg_score = round(sum(d["score"] for d in dimensions.values()) / max(len(dimensions), 1), 1)
total_scores.append(avg_score)
# Identify bottlenecks
bottlenecks = identify_bottlenecks(steps)
# Automation opportunities from steps
auto_opps = []
for step in steps:
if step.get("is_manual", True):
volume = step.get("volume_per_month", 1)
duration = step.get("duration_hours", 1)
value_score = min(100, volume * duration / 10)
effort_score = step.get("automation_effort", 50)
priority = classify_automation_priority(value_score, effort_score)
auto_opps.append({
"step": step.get("name", "Unknown"),
"process": name,
"value_score": round(value_score, 1),
"effort_score": effort_score,
"priority_class": priority,
"time_saved_hours": round(duration * 0.7, 1),
})
process_result = {
"name": name,
"overall_score": avg_score,
"health": "Healthy" if avg_score >= 70 else ("At Risk" if avg_score >= 50 else "Critical"),
"dimensions": dimensions,
"bottleneck_count": len(bottlenecks),
"bottlenecks": bottlenecks,
"volume_per_month": proc.get("volume_per_month", 0),
"owner": proc.get("owner", "Unassigned"),
}
results["processes"].append(process_result)
results["top_bottlenecks"].extend(bottlenecks)
results["automation_opportunities"].extend(auto_opps)
# Overall score
results["overall_efficiency_score"] = round(
sum(total_scores) / max(len(total_scores), 1), 1
)
# Sort processes by score (worst first for prioritization)
results["processes"].sort(key=lambda x: x["overall_score"])
# Sort automation opportunities by value
results["automation_opportunities"].sort(key=lambda x: x["value_score"], reverse=True)
results["automation_opportunities"] = results["automation_opportunities"][:10]
# Top bottlenecks
results["top_bottlenecks"] = [b for b in results["top_bottlenecks"] if b["severity"] == "high"][:10]
# Recommendations
recs = results["recommendations"]
critical = [p for p in results["processes"] if p["health"] == "Critical"]
if critical:
recs.append(f"PRIORITY: {len(critical)} process(es) in critical state -- immediate intervention needed")
quick_wins = [a for a in results["automation_opportunities"] if "Quick Win" in a["priority_class"]]
if quick_wins:
recs.append(f"Automation: {len(quick_wins)} quick-win automation opportunities identified")
if results["overall_efficiency_score"] < 50:
recs.append("Overall efficiency below 50% -- consider dedicated process improvement initiative")
return results
def format_text(results):
lines = [
"=" * 60,
"PROCESS EFFICIENCY REPORT",
"=" * 60,
f"Organization: {results['organization']}",
f"Processes Analyzed: {results['process_count']}",
f"Analysis Date: {results['timestamp'][:10]}",
"",
f"OVERALL EFFICIENCY: {results['overall_efficiency_score']}/100",
"",
"PROCESS SCORES (worst first)",
]
for proc in results["processes"]:
lines.append(f"\n {proc['name']} -- {proc['overall_score']}/100 ({proc['health']})")
lines.append(f" Owner: {proc['owner']} | Volume: {proc['volume_per_month']}/mo | Bottlenecks: {proc['bottleneck_count']}")
for dim_name, dim_data in proc["dimensions"].items():
lines.append(f" {dim_name}: {dim_data['actual']} (target: {dim_data['target']}, score: {dim_data['score']})")
if results["top_bottlenecks"]:
lines.append("")
lines.append("TOP BOTTLENECKS (high severity)")
for b in results["top_bottlenecks"][:5]:
lines.append(f" {b['step']} ({b['duration_hours']}h, wait: {b['wait_time_hours']}h)")
for issue in b["issues"]:
lines.append(f" - {issue}")
if results["automation_opportunities"]:
lines.append("")
lines.append("AUTOMATION OPPORTUNITIES")
for a in results["automation_opportunities"][:5]:
lines.append(f" {a['step']} ({a['process']}): {a['priority_class']} -- saves ~{a['time_saved_hours']}h/occurrence")
if results["recommendations"]:
lines.append("")
lines.append("RECOMMENDATIONS")
for rec in results["recommendations"]:
lines.append(f" * {rec}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Score process efficiency and identify bottlenecks")
parser.add_argument("--input", required=True, help="Path to JSON process data file")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
try:
data = load_data(args.input)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"Error loading input file: {e}", file=sys.stderr)
sys.exit(1)
results = analyze_processes(data)
if args.json:
print(json.dumps(results, indent=2))
else:
print(format_text(results))
if __name__ == "__main__":
main()