# Progressive Disclosure

> Progressive Disclosure Meta-Skill

- Skill: `wesley1600/progressive-disclosure` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add wesley1600/progressive-disclosure`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wesley1600/progressive-disclosure/raw
- Safety review: pending (external: skill-scanner PASS, skillspector WARNING)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Wesley1600 (https://skillmd.com/u/wesley1600)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/wesley1600/progressive-disclosure

---

# Progressive Disclosure Meta-Skill

<!-- METADATA: Always loaded -->
## Metadata

**Skill Name:** Progressive Disclosure Manager
**Type:** Meta-skill
**Version:** 1.0.0
**Purpose:** Manages the progressive disclosure of skill content to optimize context window usage
**Triggers:** Invoked when determining which level of skill content to load
**Dependencies:** None
**Context Cost:** Low (metadata only), Medium (with instructions), High (full resources)

**Quick Summary:**
This meta-skill determines which level of a skill (metadata, instructions, or resources) should be loaded based on task relevance, ensuring only necessary context occupies the context window.

---

<!-- INSTRUCTIONS: Loaded when skill is actively being used -->
## Instructions

### Overview

The Progressive Disclosure Manager operates on a three-tier system for skill content:

1. **Level 1: Metadata** - Basic information about what the skill does
2. **Level 2: Instructions** - How to use the skill and when to apply it
3. **Level 3: Resources** - Detailed implementation guidance, examples, and edge cases

### Decision Framework

Use this decision tree to determine which level to load:

```
┌─────────────────────────────────────┐
│ Is skill potentially relevant?      │
│ (keywords, topic match)              │
└─────────┬───────────────────────────┘
          │
          ├─ NO ──> Skip entirely
          │
          ├─ MAYBE ──> Load METADATA only
          │             • Skill name
          │             • One-line description
          │             • Triggers/keywords
          │
          ├─ YES ──> Load INSTRUCTIONS
          │             • How to use it
          │             • When to apply it
          │             • Basic examples
          │
          └─ CRITICAL ──> Load FULL RESOURCES
                          • Detailed algorithms
                          • Edge case handling
                          • Complete examples
                          • Performance considerations
```

### Relevance Detection Algorithm

**Step 1: Extract Context Signals**
- Parse user query for keywords and intent
- Identify task type (implementation, debugging, analysis, etc.)
- Assess complexity level (simple, moderate, complex)

**Step 2: Score Skill Relevance**

For each available skill, calculate relevance score:

```
relevance_score = (
    keyword_match * 0.3 +        # Direct keyword overlap
    topic_similarity * 0.3 +      # Semantic topic alignment
    task_type_match * 0.2 +       # Does skill type match task?
    complexity_alignment * 0.2     # Skill complexity matches need?
)
```

**Step 3: Load Appropriate Level**

```python
if relevance_score < 0.2:
    return None  # Skip skill entirely
elif relevance_score < 0.5:
    return "metadata"  # Light context
elif relevance_score < 0.8:
    return "instructions"  # Medium context
else:
    return "resources"  # Full context
```

### Usage Examples

#### Example 1: User asks about UMAP embeddings

**Query:** "How do I optimize UMAP for large datasets?"

**Analysis:**
- Keywords: "UMAP", "optimize", "large datasets"
- Task type: Performance optimization
- Complexity: Moderate to high

**Skills evaluated:**
- `umap-optimization` skill → Score: 0.9 → Load **FULL RESOURCES**
- `data-processing` skill → Score: 0.4 → Load **METADATA** only
- `neural-networks` skill → Score: 0.1 → **SKIP**

#### Example 2: User asks about string manipulation

**Query:** "Convert this string to uppercase"

**Analysis:**
- Keywords: "string", "uppercase"
- Task type: Simple transformation
- Complexity: Low

**Skills evaluated:**
- `text-processing` skill → Score: 0.6 → Load **INSTRUCTIONS**
- `regex-patterns` skill → Score: 0.3 → Load **METADATA** only
- `nlp-pipeline` skill → Score: 0.1 → **SKIP**

### Integration with Task Execution

```yaml
# Before starting task
1. Parse user request
2. Identify candidate skills
3. For each skill:
   a. Calculate relevance score
   b. Load appropriate level
   c. Add to context window
4. Proceed with task using loaded skills

# During task execution
- If need more detail → Upgrade skill level (metadata → instructions → resources)
- If skill unused → Downgrade or remove from context
- Monitor context window usage → Prioritize high-relevance skills
```

### Context Window Management

**Budget Allocation Strategy:**

```
Total Context: 200K tokens

Reserved:
- User query & history: 10-20K tokens
- Code being edited: 20-40K tokens
- Tool outputs: 10-30K tokens
- Response generation: 10-20K tokens

Available for skills: ~100-120K tokens

Allocation:
- High relevance (0.8+): Up to 20K tokens each (full resources)
- Medium relevance (0.5-0.8): Up to 5K tokens each (instructions)
- Low relevance (0.2-0.5): Up to 1K tokens each (metadata)
```

---

<!-- RESOURCES: Loaded only when detailed implementation is needed -->
## Resources

### Detailed Implementation Guide

#### 1. Skill Structure Requirements

Each skill should be structured with clear progressive disclosure markers:

```markdown
# Skill Name

<!-- LEVEL: METADATA -->
## Metadata
- Skill name
- One-line description
- Triggers/keywords
- Dependencies
- Context cost estimate

<!-- LEVEL: INSTRUCTIONS -->
## Instructions
- How to use the skill
- When to apply it
- Basic workflow
- Simple examples

<!-- LEVEL: RESOURCES -->
## Resources
- Detailed algorithms
- Complex examples
- Edge case handling
- Performance optimization
- Troubleshooting guide
```

#### 2. Parsing Algorithm

**Pseudocode for loading specific level:**

```python
def load_skill_level(skill_path: str, level: str) -> str:
    """
    Load only the specified level of a skill.

    Args:
        skill_path: Path to skill markdown file
        level: One of "metadata", "instructions", "resources"

    Returns:
        Extracted content for the specified level
    """
    content = read_file(skill_path)

    # Define level boundaries
    levels = {
        "metadata": ("<!-- LEVEL: METADATA -->", "<!-- LEVEL: INSTRUCTIONS -->"),
        "instructions": ("<!-- LEVEL: INSTRUCTIONS -->", "<!-- LEVEL: RESOURCES -->"),
        "resources": ("<!-- LEVEL: RESOURCES -->", None)
    }

    start_marker, end_marker = levels[level]

    # Extract section
    start_idx = content.find(start_marker)
    if start_idx == -1:
        return ""

    if end_marker:
        end_idx = content.find(end_marker, start_idx)
        if end_idx == -1:
            return content[start_idx:]
        return content[start_idx:end_idx]
    else:
        return content[start_idx:]

def load_skill_progressive(skill_path: str, relevance_score: float) -> str:
    """
    Load skill content based on relevance score.
    """
    levels_to_load = []

    if relevance_score >= 0.2:
        levels_to_load.append("metadata")
    if relevance_score >= 0.5:
        levels_to_load.append("instructions")
    if relevance_score >= 0.8:
        levels_to_load.append("resources")

    content_parts = []
    for level in levels_to_load:
        content_parts.append(load_skill_level(skill_path, level))

    return "\n\n".join(content_parts)
```

#### 3. Relevance Scoring Implementation

**Detailed scoring function:**

```python
from typing import List, Dict, Set
import math

def calculate_relevance(
    query: str,
    skill: Dict[str, any],
    context: Dict[str, any]
) -> float:
    """
    Calculate how relevant a skill is to the current task.

    Args:
        query: User's query/request
        skill: Skill metadata and keywords
        context: Current task context (file types, complexity, etc.)

    Returns:
        Relevance score between 0.0 and 1.0
    """

    # 1. Keyword matching (30% weight)
    query_tokens = set(tokenize(query.lower()))
    skill_keywords = set(skill.get("keywords", []))

    keyword_overlap = len(query_tokens & skill_keywords)
    keyword_score = min(1.0, keyword_overlap / max(1, len(skill_keywords) * 0.3))

    # 2. Topic similarity (30% weight)
    # Using semantic similarity (cosine similarity of embeddings)
    query_embedding = get_embedding(query)
    skill_embedding = get_embedding(skill["description"])
    topic_score = cosine_similarity(query_embedding, skill_embedding)

    # 3. Task type matching (20% weight)
    task_type = identify_task_type(query)  # "implement", "debug", "optimize", etc.
    skill_types = skill.get("task_types", [])
    type_score = 1.0 if task_type in skill_types else 0.0

    # 4. Complexity alignment (20% weight)
    query_complexity = estimate_complexity(query)  # 0.0 to 1.0
    skill_complexity = skill.get("complexity", 0.5)  # 0.0 to 1.0

    # Prefer skills that match complexity level
    complexity_diff = abs(query_complexity - skill_complexity)
    complexity_score = 1.0 - complexity_diff

    # Weighted combination
    total_score = (
        keyword_score * 0.3 +
        topic_score * 0.3 +
        type_score * 0.2 +
        complexity_score * 0.2
    )

    return total_score

def tokenize(text: str) -> List[str]:
    """Simple tokenization for keyword matching."""
    return [word.strip(".,!?;:") for word in text.split()]

def identify_task_type(query: str) -> str:
    """Identify the type of task from query."""
    query_lower = query.lower()

    task_patterns = {
        "implement": ["implement", "create", "add", "build", "write"],
        "debug": ["debug", "fix", "error", "bug", "issue", "problem"],
        "optimize": ["optimize", "improve", "faster", "performance", "speed"],
        "analyze": ["analyze", "understand", "explain", "how does", "what is"],
        "refactor": ["refactor", "clean", "reorganize", "restructure"],
        "test": ["test", "verify", "validate", "check"],
    }

    for task_type, keywords in task_patterns.items():
        if any(kw in query_lower for kw in keywords):
            return task_type

    return "general"

def estimate_complexity(query: str) -> float:
    """
    Estimate task complexity from query.
    Returns value between 0.0 (simple) and 1.0 (complex).
    """
    complexity_signals = {
        "simple": ["simple", "basic", "quick", "just", "only"],
        "moderate": ["need", "want", "should", "could"],
        "complex": ["complex", "advanced", "comprehensive", "full", "production"]
    }

    query_lower = query.lower()

    if any(kw in query_lower for kw in complexity_signals["simple"]):
        return 0.2
    elif any(kw in query_lower for kw in complexity_signals["complex"]):
        return 0.9
    else:
        # Moderate complexity, or estimate by query length
        word_count = len(query.split())
        if word_count < 10:
            return 0.3
        elif word_count < 30:
            return 0.5
        else:
            return 0.7
```

#### 4. Dynamic Level Upgrading

**When to upgrade skill level during execution:**

```python
class SkillManager:
    def __init__(self):
        self.loaded_skills = {}  # skill_name -> current_level
        self.usage_count = {}     # skill_name -> times referenced

    def upgrade_skill_if_needed(self, skill_name: str):
        """
        Upgrade skill level if it's being heavily used.
        """
        current_level = self.loaded_skills.get(skill_name, "none")
        usage = self.usage_count.get(skill_name, 0)

        # Upgrade criteria
        if usage >= 3 and current_level == "metadata":
            self.load_level(skill_name, "instructions")
            print(f"Upgraded {skill_name} to instructions level")

        elif usage >= 5 and current_level == "instructions":
            self.load_level(skill_name, "resources")
            print(f"Upgraded {skill_name} to full resources level")

    def track_usage(self, skill_name: str):
        """Track when a skill is referenced."""
        self.usage_count[skill_name] = self.usage_count.get(skill_name, 0) + 1
        self.upgrade_skill_if_needed(skill_name)
```

#### 5. Context Window Monitoring

**Real-time context management:**

```python
class ContextWindowManager:
    def __init__(self, max_tokens: int = 200000):
        self.max_tokens = max_tokens
        self.reserved_tokens = 60000  # For query, code, responses
        self.available_tokens = max_tokens - self.reserved_tokens
        self.current_usage = {}  # skill_name -> token_count

    def can_load_level(self, skill_name: str, level: str) -> bool:
        """Check if we have budget to load this level."""
        estimated_cost = self.estimate_level_cost(skill_name, level)
        current_total = sum(self.current_usage.values())

        return (current_total + estimated_cost) <= self.available_tokens

    def estimate_level_cost(self, skill_name: str, level: str) -> int:
        """Estimate token cost for a skill level."""
        costs = {
            "metadata": 500,       # ~500 tokens
            "instructions": 3000,  # ~3K tokens
            "resources": 15000     # ~15K tokens
        }
        return costs.get(level, 0)

    def prioritize_skills(self, skills: List[Dict]) -> List[Dict]:
        """
        Prioritize which skills to keep loaded when approaching limit.
        """
        # Sort by relevance score descending
        sorted_skills = sorted(
            skills,
            key=lambda s: s["relevance_score"],
            reverse=True
        )

        budget_remaining = self.available_tokens
        loaded_skills = []

        for skill in sorted_skills:
            level = self.determine_level(skill["relevance_score"])
            cost = self.estimate_level_cost(skill["name"], level)

            if cost <= budget_remaining:
                loaded_skills.append({
                    **skill,
                    "level": level,
                    "cost": cost
                })
                budget_remaining -= cost
            else:
                # Try to load at a lower level
                if level == "resources" and self.can_downgrade(skill):
                    level = "instructions"
                    cost = self.estimate_level_cost(skill["name"], level)
                    if cost <= budget_remaining:
                        loaded_skills.append({
                            **skill,
                            "level": level,
                            "cost": cost
                        })
                        budget_remaining -= cost

        return loaded_skills

    def determine_level(self, relevance_score: float) -> str:
        """Determine which level to load based on relevance."""
        if relevance_score >= 0.8:
            return "resources"
        elif relevance_score >= 0.5:
            return "instructions"
        else:
            return "metadata"
```

#### 6. Performance Metrics

**Tracking progressive disclosure effectiveness:**

```python
class DisclosureMetrics:
    def __init__(self):
        self.total_tasks = 0
        self.total_tokens_used = 0
        self.tokens_by_level = {"metadata": 0, "instructions": 0, "resources": 0}
        self.level_upgrades = 0
        self.level_downgrades = 0

    def record_skill_load(self, level: str, tokens: int):
        """Record when a skill level is loaded."""
        self.tokens_by_level[level] += tokens
        self.total_tokens_used += tokens

    def record_level_change(self, from_level: str, to_level: str):
        """Record when a skill level is changed."""
        levels = ["metadata", "instructions", "resources"]
        if levels.index(to_level) > levels.index(from_level):
            self.level_upgrades += 1
        else:
            self.level_downgrades += 1

    def get_efficiency_report(self) -> Dict:
        """Generate efficiency report."""
        return {
            "total_tasks": self.total_tasks,
            "avg_tokens_per_task": self.total_tokens_used / max(1, self.total_tasks),
            "tokens_by_level": self.tokens_by_level,
            "level_distribution": {
                level: (count / max(1, self.total_tokens_used)) * 100
                for level, count in self.tokens_by_level.items()
            },
            "upgrades": self.level_upgrades,
            "downgrades": self.level_downgrades,
            "efficiency_score": self.calculate_efficiency()
        }

    def calculate_efficiency(self) -> float:
        """
        Calculate efficiency score.
        Higher score = better use of progressive disclosure.
        """
        total = sum(self.tokens_by_level.values())
        if total == 0:
            return 0.0

        # Ideal: Most tokens at metadata/instructions, fewer at resources
        # Score: weighted by level (metadata best, resources worst)
        weighted_sum = (
            self.tokens_by_level["metadata"] * 1.0 +
            self.tokens_by_level["instructions"] * 0.7 +
            self.tokens_by_level["resources"] * 0.4
        )

        return weighted_sum / total
```

### Advanced Features

#### 7. Skill Dependency Resolution

Some skills depend on others. Handle dependencies carefully:

```python
def resolve_dependencies(skill: Dict, all_skills: Dict) -> List[str]:
    """
    Resolve skill dependencies and determine what to load.

    Returns list of skill names to load (including dependencies).
    """
    to_load = [skill["name"]]
    dependencies = skill.get("dependencies", [])

    for dep_name in dependencies:
        if dep_name in all_skills:
            # Recursively resolve
            to_load.extend(resolve_dependencies(all_skills[dep_name], all_skills))

    # Remove duplicates, preserve order
    return list(dict.fromkeys(to_load))

def load_with_dependencies(
    skill_name: str,
    relevance_score: float,
    all_skills: Dict,
    context_manager: ContextWindowManager
) -> Dict[str, str]:
    """
    Load skill with its dependencies at appropriate levels.

    Returns dict mapping skill_name to loaded content.
    """
    skill = all_skills[skill_name]
    deps = resolve_dependencies(skill, all_skills)

    loaded_content = {}

    # Main skill gets level based on relevance
    main_level = context_manager.determine_level(relevance_score)

    for dep_skill_name in deps:
        if dep_skill_name == skill_name:
            # Main skill
            level = main_level
        else:
            # Dependencies get loaded at lower level (metadata/instructions only)
            level = "metadata" if main_level == "instructions" else "instructions"

        # Check budget
        if context_manager.can_load_level(dep_skill_name, level):
            loaded_content[dep_skill_name] = load_skill_level(
                f".claude/skills/{dep_skill_name}/skill.md",
                level
            )
            context_manager.current_usage[dep_skill_name] = (
                context_manager.estimate_level_cost(dep_skill_name, level)
            )

    return loaded_content
```

#### 8. Caching Strategy

Cache loaded skills to avoid re-parsing:

```python
from functools import lru_cache
import hashlib
from typing import Tuple

class SkillCache:
    def __init__(self, max_size: int = 100):
        self.cache = {}  # (skill_path, level, file_hash) -> content
        self.max_size = max_size
        self.access_count = {}  # key -> count

    def get_file_hash(self, file_path: str) -> str:
        """Get hash of file for cache invalidation."""
        with open(file_path, 'rb') as f:
            return hashlib.md5(f.read()).hexdigest()

    def get(self, skill_path: str, level: str) -> str | None:
        """Get cached skill content if available and valid."""
        file_hash = self.get_file_hash(skill_path)
        key = (skill_path, level, file_hash)

        if key in self.cache:
            self.access_count[key] = self.access_count.get(key, 0) + 1
            return self.cache[key]

        return None

    def set(self, skill_path: str, level: str, content: str):
        """Cache skill content."""
        file_hash = self.get_file_hash(skill_path)
        key = (skill_path, level, file_hash)

        # Evict least-used if at capacity
        if len(self.cache) >= self.max_size:
            least_used = min(self.access_count.items(), key=lambda x: x[1])[0]
            del self.cache[least_used]
            del self.access_count[least_used]

        self.cache[key] = content
        self.access_count[key] = 1
```

### Testing Guidelines

#### Test Cases

1. **Test relevance scoring:**
   - High relevance query → Loads full resources
   - Medium relevance → Loads instructions only
   - Low relevance → Loads metadata only
   - No relevance → Skips skill

2. **Test context window management:**
   - Multiple skills fit within budget
   - Skills exceed budget → Prioritization kicks in
   - Dynamic upgrading when skill heavily used

3. **Test dependency resolution:**
   - Skill with dependencies loads deps at lower level
   - Circular dependencies handled gracefully
   - Missing dependencies don't break loading

4. **Test caching:**
   - Same skill+level loaded from cache
   - File changes invalidate cache
   - LRU eviction works correctly

### Integration Example

```python
# Complete workflow
def process_user_query(query: str):
    # 1. Initialize managers
    context_mgr = ContextWindowManager(max_tokens=200000)
    skill_cache = SkillCache()
    metrics = DisclosureMetrics()

    # 2. Identify candidate skills
    all_skills = discover_skills(".claude/skills/")

    # 3. Score relevance
    scored_skills = []
    for skill in all_skills:
        score = calculate_relevance(query, skill, {})
        if score >= 0.2:  # Only consider relevant skills
            scored_skills.append({
                "name": skill["name"],
                "path": skill["path"],
                "relevance_score": score,
                **skill
            })

    # 4. Prioritize and load
    prioritized = context_mgr.prioritize_skills(scored_skills)

    loaded_skills = {}
    for skill in prioritized:
        # Check cache first
        cached = skill_cache.get(skill["path"], skill["level"])
        if cached:
            content = cached
        else:
            # Load dependencies if any
            content_map = load_with_dependencies(
                skill["name"],
                skill["relevance_score"],
                {s["name"]: s for s in all_skills},
                context_mgr
            )
            content = content_map[skill["name"]]
            skill_cache.set(skill["path"], skill["level"], content)

        loaded_skills[skill["name"]] = content
        metrics.record_skill_load(skill["level"], skill["cost"])

    # 5. Execute task with loaded skills
    response = execute_task(query, loaded_skills)

    # 6. Generate efficiency report
    metrics.total_tasks += 1
    report = metrics.get_efficiency_report()

    return response, report
```

---

## Appendix

### A. Standard Skill Template

Use this template when creating new skills:

```markdown
# [Skill Name]

<!-- LEVEL: METADATA -->
## Metadata

**Skill Name:** [Name]
**Type:** [implementation|debugging|analysis|optimization|etc.]
**Version:** [Semantic version]
**Purpose:** [One-line description]
**Triggers:** [Comma-separated keywords]
**Dependencies:** [List of required skills, if any]
**Context Cost:** [Low|Medium|High]
**Complexity:** [0.0-1.0 scale]

**Quick Summary:**
[2-3 sentence overview]

---

<!-- LEVEL: INSTRUCTIONS -->
## Instructions

### When to Use This Skill

[Describe scenarios where this skill applies]

### Basic Workflow

1. [Step 1]
2. [Step 2]
3. [Step 3]

### Simple Example

\`\`\`
[Code or example]
\`\`\`

---

<!-- LEVEL: RESOURCES -->
## Resources

### Detailed Implementation

[Comprehensive guide with algorithms, patterns, etc.]

### Complex Examples

[Multiple examples showing edge cases]

### Troubleshooting

[Common issues and solutions]

### Performance Considerations

[Optimization tips]
```

### B. Skill Discovery

```python
import os
from pathlib import Path
from typing import List, Dict

def discover_skills(skills_dir: str) -> List[Dict]:
    """
    Discover all skills in the skills directory.

    Returns list of skill metadata dictionaries.
    """
    skills = []
    skills_path = Path(skills_dir)

    for skill_dir in skills_path.iterdir():
        if not skill_dir.is_dir():
            continue

        skill_file = skill_dir / "skill.md"
        if not skill_file.exists():
            continue

        # Parse metadata
        metadata = parse_skill_metadata(str(skill_file))
        metadata["path"] = str(skill_file)
        skills.append(metadata)

    return skills

def parse_skill_metadata(skill_file: str) -> Dict:
    """
    Parse metadata section from skill file.
    """
    with open(skill_file, 'r') as f:
        content = f.read()

    # Extract metadata section
    metadata_section = load_skill_level(skill_file, "metadata")

    # Parse fields
    metadata = {}
    for line in metadata_section.split('\n'):
        if line.startswith('**') and ':**' in line:
            key = line.split('**')[1].replace(':', '').strip()
            value = line.split(':**')[1].strip().replace('**', '')
            metadata[key.lower().replace(' ', '_')] = value

    return metadata
```

### C. Performance Benchmarks

Expected performance characteristics:

| Metric | Target | Actual (Typical) |
|--------|--------|------------------|
| Relevance scoring | < 10ms per skill | ~5ms |
| Skill loading (cached) | < 1ms | ~0.5ms |
| Skill loading (uncached) | < 50ms | ~30ms |
| Context window check | < 1ms | ~0.3ms |
| Dependency resolution | < 20ms | ~10ms |
| Cache hit rate | > 80% | ~85% |

### D. Future Enhancements

1. **Machine Learning-Based Relevance**
   - Train a model to predict relevance from historical data
   - Learn which skills are actually helpful for which queries

2. **Automatic Skill Generation**
   - Extract common patterns from codebase
   - Generate skills automatically from documentation

3. **Collaborative Filtering**
   - "Users who loaded skill A also loaded skill B"
   - Suggest related skills

4. **Real-Time Adaptation**
   - Monitor which skills are actually used in responses
   - Automatically adjust relevance scoring

5. **Skill Versioning**
   - Support multiple versions of same skill
   - Automatic migration between versions

---

**End of Progressive Disclosure Meta-Skill**

*This skill itself demonstrates progressive disclosure: metadata for quick reference, instructions for usage, and detailed resources for implementation.*

