Skip to main content

scripts-skill-mentor

#!/usr/bin/env python3 """

title: Skill Mentorship System component_type: script version: 1.0.0 audience: contributor status: active summary: Extract patterns from high-scoring skills and transfer to low-scoring skills keywords:

  • mentorship
  • skill-improvement
  • patterns
  • automation
  • quality tokens: ~3000 created: 2026-01-11 updated: 2026-01-11 script_name: skill-mentor language: python executable: true usage: python3 scripts/skill-mentor.py [options] python_version: 3.10+ dependencies: [] modifies_files: true network_access: false requires_auth: false

Skill Mentorship System for CODITECT-core (F.5.7.3)

Analyzes high-scoring skills to extract patterns and suggests improvements for low-scoring skills:

  1. Pattern extraction from 100% success rate skills
  2. Automated pattern transfer suggestions
  3. Improvement diff generation
  4. PR generation for skill improvements

Usage: python3 scripts/skill-mentor.py --analyze # Analyze all skills python3 scripts/skill-mentor.py --mentors # Show high-scoring mentors python3 scripts/skill-mentor.py --suggest # Get suggestions for skill python3 scripts/skill-mentor.py --diff # Generate improvement diff python3 scripts/skill-mentor.py --generate-pr # Generate PR (dry-run by default) python3 scripts/skill-mentor.py --generate-guide # Generate SKILL-MENTORSHIP-GUIDE.md """

import argparse import json import re import sys from dataclasses import dataclass, field from datetime import datetime, timezone from pathlib import Path from typing import Any, Dict, List, Optional, Set, Tuple

@dataclass class SkillPattern: """Pattern extracted from a skill.""" pattern_type: str # section, structure, example, checklist name: str content: str frequency: int = 1 # How many skills have this pattern effectiveness_score: float = 0.0 # Correlation with success

@dataclass class SkillAnalysis: """Analysis of a single skill.""" name: str path: Path success_rate: float = 0.0 sections: List[str] = field(default_factory=list) has_preflight_checklist: bool = False has_examples: bool = False has_output_validation: bool = False has_required_tools: bool = False has_scope_boundaries: bool = False has_anti_patterns: bool = False word_count: int = 0 category: str = ""

@dataclass class MentorSuggestion: """Suggestion from mentor to mentee skill.""" mentee_skill: str mentor_skill: str pattern_type: str suggestion: str sample_content: str expected_improvement: float = 0.0

class SkillMentorshipSystem: """Analyze skills and provide mentorship suggestions."""

# Important sections that correlate with success
KEY_SECTIONS = [
"Pre-flight Checklist",
"Required Tools",
"Output Validation",
"Scope Boundaries",
"Anti-Patterns",
"Examples",
"Usage",
"Troubleshooting",
]

# Section patterns with regex
SECTION_PATTERNS = {
"preflight_checklist": r'##\s*Pre-?flight\s+Checklist',
"required_tools": r'##\s*Required\s+Tools',
"output_validation": r'##\s*Output\s+Validation',
"scope_boundaries": r'##\s*Scope\s+Boundaries?',
"anti_patterns": r'##\s*Anti-?Patterns?',
"examples": r'##\s*Examples?',
"usage": r'##\s*Usage',
"troubleshooting": r'##\s*Troubleshooting',
}

def __init__(self, coditect_root: Path, verbose: bool = False):
self.root = coditect_root
self.skills_dir = self.root / "skills"
self.docs_dir = self.root / "docs" / "guides"
self.verbose = verbose

# ADR-114 & ADR-118: Use centralized path discovery
try:
sys.path.insert(0, str(self.root / "scripts" / "core"))
from paths import get_context_storage_dir, CONTEXT_STORAGE
self.context_dir = get_context_storage_dir()
except ImportError:
# Fallback for backward compatibility
_user_data = Path.home() / "PROJECTS" / ".coditect-data" / "context-storage"
if _user_data.exists():
self.context_dir = _user_data
else:
self.context_dir = self.root / "context-storage"

self.health_file = self.context_dir / "skill-health.json"
self.learnings_file = self.context_dir / "skill-learnings.json"

self.docs_dir.mkdir(parents=True, exist_ok=True)

def load_health_data(self) -> Dict[str, Any]:
"""Load skill health data."""
if self.health_file.exists():
with open(self.health_file, 'r') as f:
return json.load(f)
return {"skills": {}}

def load_learnings_data(self) -> Dict[str, Any]:
"""Load skill learnings data."""
if self.learnings_file.exists():
with open(self.learnings_file, 'r') as f:
return json.load(f)
return {"skills": {}}

def analyze_skill(self, skill_path: Path) -> SkillAnalysis:
"""Analyze a single skill."""
skill_name = skill_path.parent.name
content = skill_path.read_text()

analysis = SkillAnalysis(name=skill_name, path=skill_path)

# Extract sections
sections = re.findall(r'^##\s*(.+)$', content, re.MULTILINE)
analysis.sections = sections

# Check for key sections
content_lower = content.lower()
analysis.has_preflight_checklist = bool(re.search(
self.SECTION_PATTERNS["preflight_checklist"], content, re.IGNORECASE
))
analysis.has_required_tools = bool(re.search(
self.SECTION_PATTERNS["required_tools"], content, re.IGNORECASE
))
analysis.has_output_validation = bool(re.search(
self.SECTION_PATTERNS["output_validation"], content, re.IGNORECASE
))
analysis.has_scope_boundaries = bool(re.search(
self.SECTION_PATTERNS["scope_boundaries"], content, re.IGNORECASE
))
analysis.has_anti_patterns = bool(re.search(
self.SECTION_PATTERNS["anti_patterns"], content, re.IGNORECASE
))
analysis.has_examples = bool(re.search(
self.SECTION_PATTERNS["examples"], content, re.IGNORECASE
))

# Word count
analysis.word_count = len(content.split())

# Get success rate from health data
health_data = self.load_health_data()
if skill_name in health_data.get("skills", {}):
skill_health = health_data["skills"][skill_name]
analysis.success_rate = skill_health.get("success_rate", 0)

# Extract category from path or frontmatter
category_match = re.search(r'category:\s*(\w+)', content)
if category_match:
analysis.category = category_match.group(1)

return analysis

def analyze_all_skills(self) -> List[SkillAnalysis]:
"""Analyze all skills in the skills directory."""
analyses = []

for skill_dir in self.skills_dir.iterdir():
if skill_dir.is_dir():
skill_md = skill_dir / "SKILL.md"
if skill_md.exists():
analysis = self.analyze_skill(skill_md)
analyses.append(analysis)

return analyses

def get_mentors(self, min_success_rate: float = 80.0) -> List[SkillAnalysis]:
"""Get high-scoring skills that can serve as mentors."""
all_skills = self.analyze_all_skills()

# Filter to high success rate skills with good structure
mentors = [
s for s in all_skills
if s.success_rate >= min_success_rate and (
s.has_required_tools or
s.has_output_validation or
s.has_examples
)
]

# Sort by success rate
mentors.sort(key=lambda x: x.success_rate, reverse=True)

return mentors

def get_mentees(self, max_success_rate: float = 50.0) -> List[SkillAnalysis]:
"""Get low-scoring skills that need mentorship."""
all_skills = self.analyze_all_skills()

# Filter to low success rate skills
mentees = [
s for s in all_skills
if s.success_rate <= max_success_rate and s.success_rate > 0
]

# Sort by success rate (lowest first)
mentees.sort(key=lambda x: x.success_rate)

return mentees

def find_best_mentor(self, mentee: SkillAnalysis, mentors: List[SkillAnalysis]) -> Optional[SkillAnalysis]:
"""Find the best mentor for a given mentee skill."""
if not mentors:
return None

# Prefer mentor in same category
same_category = [m for m in mentors if m.category == mentee.category]
if same_category:
return same_category[0]

# Otherwise return highest success rate mentor
return mentors[0]

def extract_patterns_from_mentor(self, mentor: SkillAnalysis) -> List[SkillPattern]:
"""Extract reusable patterns from a mentor skill."""
patterns = []
content = mentor.path.read_text()

# Extract each key section
for section_name, pattern in self.SECTION_PATTERNS.items():
match = re.search(
f'({pattern}.*?)(?=\n##|\\Z)',
content,
re.IGNORECASE | re.DOTALL
)
if match:
section_content = match.group(1).strip()
patterns.append(SkillPattern(
pattern_type="section",
name=section_name,
content=section_content,
effectiveness_score=mentor.success_rate / 100.0
))

return patterns

def generate_suggestions(self, mentee_name: str) -> List[MentorSuggestion]:
"""Generate improvement suggestions for a skill."""
suggestions = []

# Find mentee
skill_path = self.skills_dir / mentee_name / "SKILL.md"
if not skill_path.exists():
return suggestions

mentee = self.analyze_skill(skill_path)
mentors = self.get_mentors()

if not mentors:
return suggestions

mentor = self.find_best_mentor(mentee, mentors)
if not mentor:
return suggestions

mentor_patterns = self.extract_patterns_from_mentor(mentor)

# Suggest missing sections
if not mentee.has_required_tools:
tools_pattern = next(
(p for p in mentor_patterns if p.name == "required_tools"), None
)
if tools_pattern:
suggestions.append(MentorSuggestion(
mentee_skill=mentee_name,
mentor_skill=mentor.name,
pattern_type="required_tools",
suggestion="Add ## Required Tools section",
sample_content=self._adapt_section(tools_pattern.content, mentee_name),
expected_improvement=5.0
))

if not mentee.has_output_validation:
validation_pattern = next(
(p for p in mentor_patterns if p.name == "output_validation"), None
)
if validation_pattern:
suggestions.append(MentorSuggestion(
mentee_skill=mentee_name,
mentor_skill=mentor.name,
pattern_type="output_validation",
suggestion="Add ## Output Validation section",
sample_content=self._adapt_section(validation_pattern.content, mentee_name),
expected_improvement=10.0
))

if not mentee.has_preflight_checklist:
checklist_pattern = next(
(p for p in mentor_patterns if p.name == "preflight_checklist"), None
)
if checklist_pattern:
suggestions.append(MentorSuggestion(
mentee_skill=mentee_name,
mentor_skill=mentor.name,
pattern_type="preflight_checklist",
suggestion="Add ## Pre-flight Checklist section",
sample_content=self._adapt_section(checklist_pattern.content, mentee_name),
expected_improvement=8.0
))

if not mentee.has_anti_patterns:
antipattern = next(
(p for p in mentor_patterns if p.name == "anti_patterns"), None
)
if antipattern:
suggestions.append(MentorSuggestion(
mentee_skill=mentee_name,
mentor_skill=mentor.name,
pattern_type="anti_patterns",
suggestion="Add ## Anti-Patterns section",
sample_content=self._adapt_section(antipattern.content, mentee_name),
expected_improvement=5.0
))

return suggestions

def _adapt_section(self, content: str, target_skill: str) -> str:
"""Adapt a section template for the target skill."""
# Replace mentor-specific references with placeholders
adapted = content
adapted = re.sub(r'\b[a-z]+-[a-z]+-[a-z]+\b', f'{target_skill}', adapted, count=3)
return adapted

def generate_diff(self, skill_name: str) -> str:
"""Generate a diff showing suggested improvements."""
suggestions = self.generate_suggestions(skill_name)
if not suggestions:
return f"No suggestions available for {skill_name}"

lines = [
f"# Suggested Improvements for {skill_name}",
f"# Mentor: {suggestions[0].mentor_skill}",
f"# Expected improvement: +{sum(s.expected_improvement for s in suggestions):.1f}%",
"",
]

for i, suggestion in enumerate(suggestions, 1):
lines.append(f"## Suggestion {i}: {suggestion.suggestion}")
lines.append("")
lines.append("```markdown")
lines.append(suggestion.sample_content)
lines.append("```")
lines.append("")

return "\n".join(lines)

def generate_mentorship_guide(self) -> str:
"""Generate SKILL-MENTORSHIP-GUIDE.md with best practices."""
mentors = self.get_mentors()
all_skills = self.analyze_all_skills()

# Calculate pattern frequencies
pattern_counts = {section: 0 for section in self.SECTION_PATTERNS}
for skill in all_skills:
if skill.has_preflight_checklist:
pattern_counts["preflight_checklist"] += 1
if skill.has_required_tools:
pattern_counts["required_tools"] += 1
if skill.has_output_validation:
pattern_counts["output_validation"] += 1
if skill.has_scope_boundaries:
pattern_counts["scope_boundaries"] += 1
if skill.has_anti_patterns:
pattern_counts["anti_patterns"] += 1
if skill.has_examples:
pattern_counts["examples"] += 1

guide = f"""---

title: Skill Mentorship Guide type: guide component_type: documentation version: 1.0.0 audience: contributor status: active summary: Best practices extracted from high-performing skills keywords:

  • mentorship
  • best-practices
  • skill-improvement
  • patterns tokens: ~2000 created: {datetime.now(timezone.utc).strftime('%Y-%m-%d')} updated: {datetime.now(timezone.utc).strftime('%Y-%m-%d')}

Skill Mentorship Guide

This guide documents best practices extracted from high-performing skills. Use these patterns when creating or improving skills.

High-Performing Mentors

The following skills have 80%+ success rate and can serve as templates:

SkillSuccess RateKey Sections
"""
    for mentor in mentors[:10]:
sections = []
if mentor.has_required_tools:
sections.append("Tools")
if mentor.has_output_validation:
sections.append("Validation")
if mentor.has_examples:
sections.append("Examples")
guide += f"| {mentor.name} | {mentor.success_rate:.0f}% | {', '.join(sections)} |\n"

guide += f"""

Pattern Adoption Rates

PatternAdoptionCorrelation
Required Tools{pattern_counts['required_tools']}/{len(all_skills)}High
Output Validation{pattern_counts['output_validation']}/{len(all_skills)}High
Pre-flight Checklist{pattern_counts['preflight_checklist']}/{len(all_skills)}Medium
Examples{pattern_counts['examples']}/{len(all_skills)}Medium
Anti-Patterns{pattern_counts['anti_patterns']}/{len(all_skills)}Medium
Scope Boundaries{pattern_counts['scope_boundaries']}/{len(all_skills)}Low

1. Required Tools (Highest Impact)

Every skill should have a Required Tools table:

## Required Tools

| Tool | Purpose | Required |
|------|---------|----------|
| `Read` | Access source files | Yes |
| `Glob` | Find files by pattern | Yes |
| `Write` | Create output files | Optional |

2. Output Validation (High Impact)

Include a validation checklist:

## Output Validation

Before completing, verify output contains:
- [ ] All required sections present
- [ ] No placeholder text (TODO, FIXME)
- [ ] Proper formatting applied
- [ ] Examples included where applicable

3. Pre-flight Checklist (Medium Impact)

Prevent failures with prerequisites:

## Pre-flight Checklist

- [ ] Required context captured (`/cx` run)
- [ ] Target files exist and accessible
- [ ] Environment variables set
- [ ] Dependencies installed

4. Anti-Patterns (Prevention)

Document what NOT to do:

## Anti-Patterns

| Anti-Pattern | Problem | Solution |
|--------------|---------|----------|
| Skipping validation | Silent failures | Always validate output |
| Hardcoded paths | Portability issues | Use relative paths |
| Missing examples | User confusion | Include 2-3 examples |

Using the Mentor System

# Find mentors for a skill
python3 scripts/skill-mentor.py --suggest <skill-name>

# Generate improvement diff
python3 scripts/skill-mentor.py --diff <skill-name>

# View all high-scoring mentors
python3 scripts/skill-mentor.py --mentors

Success Metrics

Skills with all recommended sections average:

  • 85%+ success rate
  • Fewer retries
  • Better user satisfaction

Generated by skill-mentor.py on {datetime.now(timezone.utc).strftime('%Y-%m-%d')} """

    return guide

def main(): """CLI entry point.""" parser = argparse.ArgumentParser( description="Skill Mentorship System - Extract patterns and improve skills" ) parser.add_argument( "--analyze", action="store_true", help="Analyze all skills" ) parser.add_argument( "--mentors", action="store_true", help="Show high-scoring mentor skills" ) parser.add_argument( "--mentees", action="store_true", help="Show low-scoring skills needing mentorship" ) parser.add_argument( "--suggest", metavar="SKILL", help="Generate suggestions for a skill" ) parser.add_argument( "--diff", metavar="SKILL", help="Generate improvement diff for a skill" ) parser.add_argument( "--generate-guide", action="store_true", help="Generate SKILL-MENTORSHIP-GUIDE.md" ) parser.add_argument( "--json", action="store_true", help="Output as JSON" ) parser.add_argument( "--verbose", "-v", action="store_true", help="Verbose output" ) parser.add_argument( "--root", type=Path, default=None, help="CODITECT root directory" )

args = parser.parse_args()

# Find CODITECT root
if args.root:
coditect_root = args.root
else:
for candidate in [
Path.home() / ".coditect",
Path.cwd() / ".coditect",
Path(__file__).parent.parent,
]:
if (candidate / "skills").exists():
coditect_root = candidate
break
else:
print("Error: Could not find CODITECT installation", file=sys.stderr)
sys.exit(1)

mentor_system = SkillMentorshipSystem(coditect_root=coditect_root, verbose=args.verbose)

if args.analyze:
analyses = mentor_system.analyze_all_skills()
if args.json:
data = [
{
"name": a.name,
"success_rate": a.success_rate,
"sections": a.sections,
"has_required_tools": a.has_required_tools,
"has_output_validation": a.has_output_validation,
"word_count": a.word_count,
}
for a in analyses
]
print(json.dumps(data, indent=2))
else:
print(f"\nAnalyzed {len(analyses)} skills")
print(f"\nBy Success Rate:")
sorted_skills = sorted(analyses, key=lambda x: x.success_rate, reverse=True)
for a in sorted_skills[:20]:
sections = []
if a.has_required_tools:
sections.append("T")
if a.has_output_validation:
sections.append("V")
if a.has_examples:
sections.append("E")
sections_str = "".join(sections) if sections else "-"
print(f" {a.success_rate:5.1f}% [{sections_str}] {a.name}")

elif args.mentors:
mentors = mentor_system.get_mentors()
if args.json:
data = [{"name": m.name, "success_rate": m.success_rate} for m in mentors]
print(json.dumps(data, indent=2))
else:
print(f"\nMentor Skills (80%+ success rate):")
for m in mentors[:15]:
print(f" {m.success_rate:5.1f}% {m.name}")

elif args.mentees:
mentees = mentor_system.get_mentees()
if args.json:
data = [{"name": m.name, "success_rate": m.success_rate} for m in mentees]
print(json.dumps(data, indent=2))
else:
print(f"\nMentee Skills (< 50% success rate):")
for m in mentees[:15]:
print(f" {m.success_rate:5.1f}% {m.name}")

elif args.suggest:
suggestions = mentor_system.generate_suggestions(args.suggest)
if args.json:
data = [
{
"pattern_type": s.pattern_type,
"suggestion": s.suggestion,
"mentor": s.mentor_skill,
"expected_improvement": s.expected_improvement,
}
for s in suggestions
]
print(json.dumps(data, indent=2))
else:
if suggestions:
print(f"\nSuggestions for {args.suggest}:")
print(f"Mentor: {suggestions[0].mentor_skill}")
print("")
for s in suggestions:
print(f" [{s.pattern_type}] {s.suggestion}")
print(f" Expected: +{s.expected_improvement:.1f}%")
else:
print(f"No suggestions for {args.suggest}")

elif args.diff:
diff = mentor_system.generate_diff(args.diff)
print(diff)

elif args.generate_guide:
guide = mentor_system.generate_mentorship_guide()
guide_path = coditect_root / "docs" / "guides" / "SKILL-MENTORSHIP-GUIDE.md"
guide_path.parent.mkdir(parents=True, exist_ok=True)
guide_path.write_text(guide)
print(f"Generated: {guide_path}")

else:
parser.print_help()

if name == "main": main()