Babysitter root-cause-analyzer
Systematic root cause analysis skill with multiple investigation methodologies.
install
source · Clone the upstream repo
git clone https://github.com/a5c-ai/babysitter
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/a5c-ai/babysitter "$T" && mkdir -p ~/.claude/skills && cp -r "$T/library/specializations/domains/science/industrial-engineering/skills/root-cause-analyzer" ~/.claude/skills/a5c-ai-babysitter-root-cause-analyzer-0c1954 && rm -rf "$T"
manifest:
library/specializations/domains/science/industrial-engineering/skills/root-cause-analyzer/SKILL.mdsource content
root-cause-analyzer
You are root-cause-analyzer - a specialized skill for systematic problem investigation and root cause identification.
Overview
This skill enables AI-powered root cause analysis including:
- Is/Is Not analysis for problem definition
- 5 Whys facilitation and documentation
- Ishikawa (fishbone) diagram generation
- Fault tree analysis (FTA) construction
- Pareto chart generation
- Hypothesis testing for cause verification
- Corrective action development
- Effectiveness verification planning
Capabilities
1. Is/Is Not Problem Definition
from dataclasses import dataclass from typing import List, Optional @dataclass class IsIsNotAnalysis: """ Structured problem definition using Is/Is Not """ # What what_is: str # What is the problem/defect? what_is_not: str # What similar problems are NOT occurring? # Where where_is: str # Where is the problem observed? where_is_not: str # Where could it occur but doesn't? # When when_is: str # When does the problem occur? when_is_not: str # When could it occur but doesn't? # Extent extent_is: str # How big, how many, how often? extent_is_not: str # How big/many/often could it be but isn't? distinctions: List[str] = None # What's unique about the IS vs IS NOT? changes: List[str] = None # What changed around the time problem started? def generate_problem_statement(self): return f""" PROBLEM STATEMENT: {self.what_is} is occurring at {self.where_is}. The problem was first observed {self.when_is}. The extent is: {self.extent_is}. DISTINCTIONS: This occurs at {self.where_is} but NOT at {self.where_is_not}. This happens {self.when_is} but NOT {self.when_is_not}. KEY DISTINCTIONS: {', '.join(self.distinctions or [])} RECENT CHANGES: {', '.join(self.changes or [])} """
2. 5 Whys Analysis
@dataclass class WhyStep: level: int question: str answer: str evidence: str = "" verified: bool = False class FiveWhysAnalysis: """ 5 Whys root cause analysis """ def __init__(self, problem_statement: str): self.problem_statement = problem_statement self.why_chain: List[WhyStep] = [] def add_why(self, answer: str, evidence: str = ""): level = len(self.why_chain) + 1 if level == 1: question = f"Why did {self.problem_statement} occur?" else: prev_answer = self.why_chain[-1].answer question = f"Why did {prev_answer}?" self.why_chain.append(WhyStep( level=level, question=question, answer=answer, evidence=evidence )) def get_root_cause(self): if self.why_chain: return self.why_chain[-1].answer return None def validate_chain(self): """ Validate 5 Whys chain by reading backwards Should make logical sense: "Therefore..." """ if len(self.why_chain) < 2: return {"valid": True, "message": "Chain too short to validate"} for i in range(len(self.why_chain) - 1, 0, -1): cause = self.why_chain[i].answer effect = self.why_chain[i-1].answer # Logic check: cause should logically lead to effect return { "valid": True, "root_cause": self.get_root_cause(), "chain_length": len(self.why_chain) } def to_dict(self): return { "problem": self.problem_statement, "why_chain": [ { "level": w.level, "question": w.question, "answer": w.answer, "evidence": w.evidence, "verified": w.verified } for w in self.why_chain ], "root_cause": self.get_root_cause() }
3. Ishikawa (Fishbone) Diagram
class IshikawaDiagram: """ Cause and Effect (Fishbone) Diagram """ # Standard 6M categories for manufacturing MANUFACTURING_6M = [ "Manpower", "Method", "Machine", "Material", "Measurement", "Mother Nature (Environment)" ] # Standard categories for service SERVICE_CATEGORIES = [ "People", "Process", "Policy", "Place", "Procedure", "Product" ] def __init__(self, effect: str, categories: List[str] = None): self.effect = effect self.categories = categories or self.MANUFACTURING_6M self.causes = {cat: [] for cat in self.categories} def add_cause(self, category: str, cause: str, sub_causes: List[str] = None): if category in self.causes: self.causes[category].append({ "cause": cause, "sub_causes": sub_causes or [] }) def render_text(self): """Generate text representation of fishbone""" lines = [] lines.append(f"EFFECT: {self.effect}") lines.append("=" * 50) for category in self.categories: lines.append(f"\n{category}:") for cause_item in self.causes[category]: lines.append(f" - {cause_item['cause']}") for sub in cause_item['sub_causes']: lines.append(f" - {sub}") return "\n".join(lines) def to_dict(self): return { "effect": self.effect, "categories": self.categories, "causes": self.causes } def prioritize_causes(self, team_rankings: dict): """ Prioritize causes based on team rankings team_rankings: {cause: score} where score is 1-5 """ all_causes = [] for category, causes in self.causes.items(): for cause_item in causes: cause = cause_item['cause'] score = team_rankings.get(cause, 0) all_causes.append({ "category": category, "cause": cause, "score": score }) return sorted(all_causes, key=lambda x: x['score'], reverse=True)
4. Fault Tree Analysis
from enum import Enum class GateType(Enum): AND = "AND" # All inputs must occur OR = "OR" # Any input can cause event @dataclass class FaultTreeNode: event: str gate: Optional[GateType] = None probability: Optional[float] = None children: List['FaultTreeNode'] = None def calculate_probability(self): """ Calculate top event probability """ if not self.children: return self.probability or 0 child_probs = [c.calculate_probability() for c in self.children] if self.gate == GateType.AND: # P(A AND B) = P(A) * P(B) for independent events result = 1 for p in child_probs: result *= p return result elif self.gate == GateType.OR: # P(A OR B) = 1 - (1-P(A)) * (1-P(B)) result = 1 for p in child_probs: result *= (1 - p) return 1 - result return 0 class FaultTreeAnalysis: """ Fault Tree Analysis for systematic failure analysis """ def __init__(self, top_event: str): self.root = FaultTreeNode(event=top_event) def add_gate(self, parent_event: str, gate_type: GateType, child_events: List[str]): """Add a gate with children to the tree""" parent = self._find_node(self.root, parent_event) if parent: parent.gate = gate_type parent.children = [FaultTreeNode(event=e) for e in child_events] def set_probability(self, event: str, probability: float): """Set probability for a basic event""" node = self._find_node(self.root, event) if node: node.probability = probability def _find_node(self, node: FaultTreeNode, event: str) -> Optional[FaultTreeNode]: if node.event == event: return node if node.children: for child in node.children: found = self._find_node(child, event) if found: return found return None def calculate_top_probability(self): return self.root.calculate_probability() def get_minimal_cut_sets(self): """ Find minimal cut sets (combinations that cause top event) """ # Simplified - return basic events under OR gates cut_sets = [] self._find_cut_sets(self.root, [], cut_sets) return cut_sets def _find_cut_sets(self, node, current_set, all_sets): if not node.children: all_sets.append(current_set + [node.event]) return if node.gate == GateType.OR: for child in node.children: self._find_cut_sets(child, current_set, all_sets) elif node.gate == GateType.AND: combined = current_set for child in node.children: if not child.children: combined.append(child.event) all_sets.append(combined)
5. Pareto Analysis
import numpy as np def pareto_analysis(data: dict, cumulative_threshold: float = 80): """ Pareto analysis to identify vital few data: {category: count} """ # Sort by count descending sorted_data = sorted(data.items(), key=lambda x: x[1], reverse=True) total = sum(data.values()) cumulative = 0 cumulative_pct = 0 results = [] vital_few = [] for category, count in sorted_data: pct = count / total * 100 cumulative += count cumulative_pct = cumulative / total * 100 entry = { "category": category, "count": count, "percent": round(pct, 1), "cumulative_count": cumulative, "cumulative_percent": round(cumulative_pct, 1) } results.append(entry) if cumulative_pct <= cumulative_threshold: vital_few.append(category) return { "data": results, "vital_few": vital_few, "vital_few_count": len(vital_few), "vital_few_percent": round(sum(data[c] for c in vital_few) / total * 100, 1), "trivial_many_count": len(data) - len(vital_few), "threshold_used": cumulative_threshold }
6. Corrective Action Planning
@dataclass class CorrectiveAction: root_cause: str action_type: str # containment, corrective, preventive description: str responsible: str target_date: str verification_method: str status: str = "Open" effectiveness: Optional[str] = None def develop_corrective_actions(root_causes: List[str]): """ Guide development of corrective actions for root causes """ action_plan = { "containment_actions": [], "corrective_actions": [], "preventive_actions": [] } for rc in root_causes: # Containment - immediate action to protect customer action_plan["containment_actions"].append({ "root_cause": rc, "prompt": f"What immediate action can contain the effect of '{rc}'?", "examples": ["100% inspection", "Quarantine suspect product", "Sort and rework"] }) # Corrective - eliminate the root cause action_plan["corrective_actions"].append({ "root_cause": rc, "prompt": f"What action will eliminate '{rc}' from occurring?", "examples": ["Process change", "Equipment modification", "Training"] }) # Preventive - prevent similar issues action_plan["preventive_actions"].append({ "root_cause": rc, "prompt": f"How can we prevent similar issues related to '{rc}'?", "examples": ["Update FMEA", "Poka-yoke", "Standard work revision"] }) return action_plan
Process Integration
This skill integrates with the following processes:
root-cause-analysis-investigation.jsfailure-mode-effects-analysis.jskaizen-event-facilitation.js
Output Format
{ "problem_statement": "Defective welds on assembly line 3", "is_is_not": { "what_is": "Incomplete weld penetration", "where_is": "Station 3B only", "when_is": "Since January 15" }, "five_whys": { "root_cause": "Worn electrode tips not replaced per schedule", "chain_length": 5 }, "pareto": { "vital_few": ["Electrode condition", "Gas flow"], "vital_few_percent": 78 }, "corrective_actions": [ { "action": "Implement electrode tip change schedule", "type": "corrective", "target_date": "2024-02-15" } ] }
Best Practices
- Define problem clearly - Use Is/Is Not
- Go to gemba - Observe the actual problem
- Use data - Don't guess at causes
- Verify each why - Evidence-based chain
- Address true root cause - Not symptoms
- Verify effectiveness - Measure improvement
Constraints
- Document all evidence
- Include cross-functional team
- Verify containment effectiveness
- Track action completion