# How `extract-summaries.ps1` Dynamically Generates the `SKILL.md` Index

> Learn how extract-summaries.ps1 dynamically generates the SKILL.md index by parsing YAML front-matter and assembling a sorted markdown index with zero manual maintenance.

- Repository: [ZhaoXu/reverse-skill](https://github.com/zhaoxuya520/reverse-skill)
- Tags: how-to-guide
- Published: 2026-08-18

---

**`extract-summaries.ps1` automatically builds [`skills/INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/INDEX.md) by recursively discovering every [`SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/SKILL.md) file, parsing its YAML front-matter, and assembling a sorted markdown index with zero manual maintenance required.**

This PowerShell automation eliminates stale documentation in the `zhaoxuya520/reverse-skill` repository by ensuring the skill index always reflects the actual filesystem state. The script runs on-demand or via CI/CD to regenerate the central navigation file that both human readers and routing engines depend on.

## How the Three-Phase Discovery Pipeline Works

The `extract-summaries.ps1` script implements a deterministic three-stage pipeline: **Discovery**, **Extraction**, and **Generation**. Each phase uses native PowerShell cmdlets with no external dependencies beyond standard YAML parsing.

### Phase 1: Recursive File Discovery

The script locates all skill definitions using `Get-ChildItem` with strict filtering:

```powershell
$skillFiles = Get-ChildItem -Path "$PSScriptRoot\..\skills" -Recurse -Filter "SKILL.md"

```

Key parameters:
- `-Recurse` traverses nested category folders like `windows-ad/`, `wifi-wireless/`, `ida-reverse/`
- `-Filter "SKILL.md"` matches exactly—no false positives from [`README.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/README.md) or other markdown files
- `$PSScriptRoot` anchors to the script's location in `skills/scripts/`

### Phase 2: Front-Matter Extraction

For each [`SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/SKILL.md), the script extracts structured metadata using regex and `ConvertFrom-Yaml`:

```powershell
$fileContent = Get-Content $skillFile -Raw
if ($fileContent -match '^---\s*(?<yaml>[\s\S]*?)\s*---') {
    $yamlBlock = $Matches.yaml
    $metadata  = $yamlBlock | ConvertFrom-Yaml
}

```

The regex `'^---\s*(?<yaml>[\s\S]*?)\s*---'` captures the YAML block between document start/end markers. Parsed fields typically include:
- **title** — display name for the index
- **description** — one-line summary
- **tags** — categorical keywords for filtering
- **client** — optional multi-tenant routing hints

### Phase 3: Markdown Index Generation

Collected metadata is sorted and rendered into [`skills/INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/INDEX.md):

```powershell
$indexLines = @()
$indexLines += "# Skill Index`n"

foreach ($item in $skillData | Sort-Object Directory, Title) {
    $relPath = $item.Path.Replace("$PSScriptRoot\..\", "")
    $indexLines += "- [$($item.Title)]($relPath) – $($item.Description)"
}

$indexPath = "$PSScriptRoot\..\skills\INDEX.md"
$indexLines | Out-File -FilePath $indexPath -Encoding utf8

```

The `Sort-Object Directory, Title` operation groups skills by filesystem hierarchy before alphabetical sorting, producing intuitive navigation.

## Complete Script Implementation

The full `extract-summaries.ps1` orchestrates all phases in a single pipeline:

```powershell

# 1. Discover all SKILL.md files

$skillFiles = Get-ChildItem -Recurse -Filter "SKILL.md"

# 2. Extract metadata from each

$skillData = foreach ($f in $skillFiles) {
    $c = Get-Content $f -Raw
    if ($c -match '^---\s*(?<yaml>[\s\S]*?)\s*---') {
        $meta = $Matches.yaml | ConvertFrom-Yaml
        [PSCustomObject]@{
            Title       = $meta.title
            Description = $meta.description
            Path        = $f.FullName
            Directory   = $f.DirectoryName
        }
    }
}

# 3. Generate and write INDEX.md

$indexPath = Join-Path $PSScriptRoot "..\skills\INDEX.md"
$skillData | Sort-Object Directory, Title |
    ForEach-Object {
        $rel = $_.Path.Replace("$PSScriptRoot\..\", "")
        "- [$($_.Title)]($rel) – $($_.Description)"
    } | Set-Content $indexPath

```

This implementation guarantees **idempotent output**: running the script twice produces identical [`INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/INDEX.md) if source files are unchanged.

## Key Files in the Indexing System

| File | Purpose | Path |
|------|---------|------|
| `extract-summaries.ps1` | PowerShell automation script | `skills/scripts/extract-summaries.ps1` |
| [`INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/INDEX.md) | Generated markdown navigation (overwritten each run) | [`skills/INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/INDEX.md) |
| `**/SKILL.md` | Source skill definitions with YAML front-matter | [`skills/windows-ad/SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/windows-ad/SKILL.md), [`skills/ida-reverse/SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/ida-reverse/SKILL.md), etc. |
| [`routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/routing.json) | Routing engine configuration consuming the index | [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) |

## Runtime Characteristics and Synchronization Benefits

Deterministic regeneration prevents documentation drift common in manually-maintained repositories. Because `extract-summaries.ps1` derives all output from filesystem state:

- **New skills** appear in [`INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/INDEX.md) immediately upon adding [`SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/SKILL.md)
- **Renamed skills** update their links automatically
- **Deleted skills** disappear without orphaning references
- **Routing consistency** is maintained when [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) references index-generated paths

## Summary

- **`extract-summaries.ps1`** implements a three-phase pipeline: discover → extract → generate
- **Discovery** uses `Get-ChildItem -Recurse -Filter "SKILL.md"` for precise targeting
- **Extraction** parses YAML front-matter via regex capture and `ConvertFrom-Yaml`
- **Generation** sorts by directory hierarchy and outputs UTF-8 markdown to [`skills/INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/INDEX.md)
- Zero manual maintenance required—the script guarantees index synchronization with filesystem reality

## Frequently Asked Questions

### What happens if a SKILL.md file lacks YAML front-matter?

The regex match `^---\s*[\s\S]*?\s*---` fails, and that file is silently skipped. The script processes only well-formed skill definitions, ensuring [`INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/INDEX.md) contains valid, metadata-rich entries.

### Does the script preserve existing INDEX.md content?

No—the script performs **complete overwrite** via `Set-Content` or `Out-File`. Any manual edits to [`skills/INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/INDEX.md) are destroyed on regeneration, which enforces single-source-of-truth from [`SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/SKILL.md) files.

### How do directory hierarchies affect sorting?

`Sort-Object Directory, Title` produces grouped listings: all skills in `windows-ad/` appear before `wifi-wireless/`, with alphabetical ordering within each group. This matches the physical repository structure for intuitive navigation.

### Can the script run in CI/CD pipelines?

Yes—all operations use core PowerShell modules. The script requires no interactive prompts and exits cleanly, making it suitable for GitHub Actions, Azure Pipelines, or pre-commit hooks that validate documentation freshness.