Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,19 @@ agentready assess-batch \

**Feature**: Extract high-quality skills from assessments using Claude API

The `learn` command analyzes assessment results to identify successful patterns and generates Claude Code skills. With `--enable-llm`, it uses Claude Sonnet 4.5 to create detailed, context-aware skill documentation.
The `extract-skills` command analyzes assessment results to identify successful patterns and generates Claude Code skills. With `--enable-llm`, it uses Claude Sonnet 4.5 to create detailed, context-aware skill documentation.

### Basic Usage (Heuristic)

```bash
# Extract skills using heuristic pattern extraction
agentready learn .
agentready extract-skills .

# Generate SKILL.md files
agentready learn . --output-format skill_md
agentready extract-skills . --output-format skill_md

# Create GitHub issue templates
agentready learn . --output-format github_issues
agentready extract-skills . --output-format github_issues
```

### LLM-Powered Enrichment
Expand All @@ -142,16 +142,16 @@ agentready learn . --output-format github_issues
export ANTHROPIC_API_KEY=sk-ant-api03-...

# Extract skills with LLM enrichment (top 5 skills)
agentready learn . --enable-llm
agentready extract-skills . --enable-llm

# Enrich more skills with custom budget
agentready learn . --enable-llm --llm-budget 10
agentready extract-skills . --enable-llm --llm-budget 10

# Bypass cache for fresh analysis
agentready learn . --enable-llm --llm-no-cache
agentready extract-skills . --enable-llm --llm-no-cache

# Generate all formats with LLM enrichment
agentready learn . --enable-llm --output-format all
agentready extract-skills . --enable-llm --output-format all
```

### LLM Enrichment Features
Expand Down
14 changes: 7 additions & 7 deletions specs/llm-pattern-extraction.md
Original file line number Diff line number Diff line change
Expand Up @@ -815,10 +815,10 @@ def run_full_workflow(

### Phase 3: CLI Enhancement

**File**: `src/agentready/cli/learn.py` (modifications)
**File**: `src/agentready/cli/extract_skills.py` (modifications)

```python
# Add new options to learn command
# Add new options to extract-skills command
@click.option(
"--enable-llm",
is_flag=True,
Expand All @@ -835,7 +835,7 @@ def run_full_workflow(
is_flag=True,
help="Bypass LLM response cache (always call API)",
)
def learn(repository, output_format, output_dir, attribute, min_confidence, verbose, enable_llm, llm_budget, llm_no_cache):
def extract_skills(repository, output_format, output_dir, attribute, min_confidence, verbose, enable_llm, llm_budget, llm_no_cache):
"""Extract reusable patterns and generate Claude Code skills.

... existing docstring ...
Expand Down Expand Up @@ -1056,7 +1056,7 @@ dependencies = [
## Success Criteria

1. **LLM Integration Works**:
- `agentready learn . --enable-llm` successfully calls Claude API
- `agentready extract-skills . --enable-llm` successfully calls Claude API
- Enriched skills have detailed instructions (5-10 steps)
- Code examples include real file paths from repository

Expand Down Expand Up @@ -1092,10 +1092,10 @@ export ANTHROPIC_API_KEY=sk-ant-api03-...
agentready assess .

# Extract skills with LLM enrichment
agentready learn . --enable-llm --llm-budget 5 --verbose
agentready extract-skills . --enable-llm --llm-budget 5 --verbose

# Expected output:
# 🧠 AgentReady Learning Loop
# 🧠 AgentReady Skill Extraction
# ==================================================
# Repository: /Users/jeder/repos/agentready
# LLM enrichment: ENABLED (budget: 5 skills)
Expand All @@ -1118,7 +1118,7 @@ agentready learn . --enable-llm --llm-budget 5 --verbose
- [ ] Create `src/agentready/services/llm_cache.py`
- [ ] Create `src/agentready/learners/llm_enricher.py`
- [ ] Modify `src/agentready/services/learning_service.py`
- [ ] Modify `src/agentready/cli/learn.py`
- [ ] Modify `src/agentready/cli/extract_skills.py`
- [ ] Create `tests/unit/learners/test_llm_enricher.py`
- [ ] Run linters (black, isort, ruff)
- [ ] Test on AgentReady repository (dogfooding)
Expand Down
241 changes: 241 additions & 0 deletions src/agentready/cli/extract_skills.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
"""Extract-skills command for extracting patterns and generating skills."""

import os
import sys
from pathlib import Path

import click

from ..services.learning_service import LearningService


@click.command("extract-skills")
@click.argument("repository", type=click.Path(exists=True), default=".")
@click.option(
"--output-format",
type=click.Choice(
["json", "skill_md", "github_issues", "markdown", "all"], case_sensitive=False
),
default="json",
help="Output format for discovered skills (default: json)",
)
@click.option(
"--output-dir",
type=click.Path(),
default=".skills-proposals",
help="Directory for generated skill files (default: .skills-proposals)",
)
@click.option(
"--attribute",
multiple=True,
help="Specific attribute(s) to extract (can be specified multiple times)",
)
@click.option(
"--min-confidence",
type=int,
default=70,
help="Minimum confidence score to include skills (default: 70)",
)
@click.option(
"--verbose",
"-v",
is_flag=True,
help="Enable verbose output with detailed skill information",
)
@click.option(
"--enable-llm",
is_flag=True,
help="Enable LLM-powered skill enrichment (requires ANTHROPIC_API_KEY)",
)
@click.option(
"--llm-budget",
type=int,
default=5,
help="Maximum number of skills to enrich with LLM (default: 5)",
)
@click.option(
"--llm-no-cache",
is_flag=True,
help="Bypass LLM response cache (always call API)",
)
def extract_skills(
repository,
output_format,
output_dir,
attribute,
min_confidence,
verbose,
enable_llm,
llm_budget,
llm_no_cache,
):
"""Extract reusable patterns and generate Claude Code skills.

Analyzes assessment results to identify successful patterns that could
be extracted as reusable Claude Code skills for other repositories.

This command looks for the most recent assessment in .agentready/ and
extracts skills from high-scoring attributes (default: ≥70% confidence).

REPOSITORY: Path to repository (default: current directory)

Examples:

\b
# Discover skills from current repository
agentready extract-skills .

\b
# Generate SKILL.md files
agentready extract-skills . --output-format skill_md

\b
# Create GitHub issue templates
agentready extract-skills . --output-format github_issues

\b
# Extract specific attributes only
agentready extract-skills . --attribute claude_md_file --attribute type_annotations

\b
# Generate all formats with higher confidence threshold
agentready extract-skills . --output-format all --min-confidence 85
"""
repo_path = Path(repository).resolve()

# Validate repository exists
if not repo_path.exists():
click.echo(f"Error: Repository not found: {repo_path}", err=True)
sys.exit(1)

# Find latest assessment file
agentready_dir = repo_path / ".agentready"
if not agentready_dir.exists():
click.echo(
"Error: No assessment found in .agentready/\n"
"Run 'agentready assess .' first to generate an assessment.",
err=True,
)
sys.exit(1)

# Look for assessment files
assessment_files = sorted(agentready_dir.glob("assessment-*.json"))
if not assessment_files:
click.echo(
"Error: No assessment files found in .agentready/\n"
"Run 'agentready assess .' first to generate an assessment.",
err=True,
)
sys.exit(1)

# Use most recent assessment
assessment_file = assessment_files[-1]

# Display header
click.echo("🧠 AgentReady Skill Extraction")
click.echo("=" * 50)
click.echo(f"\nRepository: {repo_path}")
click.echo(f"Assessment: {assessment_file.name}")
click.echo(f"Output format: {output_format}")
click.echo(f"Min confidence: {min_confidence}%")
if attribute:
click.echo(f"Filtering attributes: {', '.join(attribute)}")

# Display LLM status
if enable_llm:
api_key = os.environ.get("ANTHROPIC_API_KEY")
if api_key:
click.echo(f"LLM enrichment: ENABLED (budget: {llm_budget} skills)")
if llm_no_cache:
click.echo("LLM cache: DISABLED")
else:
click.echo("⚠️ LLM enrichment: DISABLED (ANTHROPIC_API_KEY not set)")
enable_llm = False
click.echo()

# Create learning service
learning_service = LearningService(
min_confidence=min_confidence,
output_dir=output_dir,
)

# Run learning workflow
try:
results = learning_service.run_full_workflow(
assessment_file=assessment_file,
output_format=output_format,
attribute_ids=list(attribute) if attribute else None,
enable_llm=enable_llm,
llm_budget=llm_budget,
)
except Exception as e:
click.echo(f"\nError during skill extraction: {str(e)}", err=True)
if verbose:
import traceback

traceback.print_exc()
sys.exit(1)

# Display results
skills_count = results["skills_discovered"]
generated_files = results["generated_files"]

click.echo("=" * 50)
click.echo(
f"\n✅ Discovered {skills_count} skill(s) with confidence ≥{min_confidence}%\n"
)

# Show LLM info if used
if enable_llm and skills_count > 0:
enriched_count = min(llm_budget, skills_count)
click.echo(f"🤖 LLM-enriched {enriched_count} skill(s)\n")

if skills_count == 0:
click.echo("No skills met the confidence threshold.")
click.echo(
f"Try lowering --min-confidence (current: {min_confidence}) "
"or run assessment on a higher-scoring repository."
)
return

# Display discovered skills
if verbose:
click.echo("Discovered Skills:")
click.echo("-" * 50)
for skill in results["skills"]:
click.echo(f"\n📚 {skill.name}")
click.echo(f" ID: {skill.skill_id}")
click.echo(f" Confidence: {skill.confidence}%")
click.echo(f" Impact: +{skill.impact_score} pts")
click.echo(f" Reusability: {skill.reusability_score}%")
click.echo(f" Source: {skill.source_attribute_id}")
click.echo(f"\n {skill.pattern_summary}")
click.echo()

# Display generated files
click.echo("\nGenerated Files:")
click.echo("-" * 50)
for file_path in generated_files:
click.echo(f" ✓ {file_path}")

# Next steps
click.echo("\n" + "=" * 50)
click.echo("\n📖 Next Steps:\n")

if output_format in ["skill_md", "all"]:
click.echo(" 1. Review generated SKILL.md files in " + output_dir)
click.echo(" 2. Test skills on 3-5 repositories")
click.echo(" 3. Refine instructions based on testing")
click.echo(" 4. Copy to ~/.claude/skills/ or .claude/skills/")

if output_format in ["github_issues", "all"]:
click.echo(f" 1. Review issue templates in {output_dir}")
click.echo(" 2. Create GitHub issues:")
click.echo(" gh issue create --body-file .skills-proposals/skill-*.md")

if output_format == "json":
click.echo(f" 1. Review discovered-skills.json in {output_dir}")
click.echo(" 2. Generate other formats:")
click.echo(" agentready extract-skills . --output-format all")

click.echo()
4 changes: 2 additions & 2 deletions src/agentready/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
from .assess_batch import assess_batch
from .bootstrap import bootstrap
from .demo import demo
from .learn import learn
from .extract_skills import extract_skills
from .repomix import repomix_generate
from .research import research
from .schema import migrate_report, validate_report
Expand Down Expand Up @@ -493,7 +493,7 @@ def generate_config():
cli.add_command(assess_batch)
cli.add_command(bootstrap)
cli.add_command(demo)
cli.add_command(learn)
cli.add_command(extract_skills)
cli.add_command(migrate_report)
cli.add_command(repomix_generate)
cli.add_command(research)
Expand Down
Loading
Loading