Skip to content

From ECC to Explorer

The ECC repository contains 213 tools (125 skills, 60 commands, 28 agents) as markdown files scattered across directories. Each file has its own format, varying frontmatter, and implicit relationships to other tools.

The problem: Raw files lack:

  • Grouping by workflow stage (which tools go together?)
  • Use-case context (when would I use this?)
  • Input/output documentation (what goes in, what comes out?)
  • Cross-references (which command invokes which agent?)

The solution: A build-time pipeline that reads the raw files, enriches them with structured metadata from a registry, and generates a navigable documentation site.

everything-claude-code/
├── skills/
│ ├── python-patterns/
│ │ └── SKILL.md # Has frontmatter: name, description, origin
│ ├── tdd-workflow/
│ │ └── SKILL.md
│ └── ... (125 directories)
├── agents/
│ ├── architect.md # Has frontmatter: name, description, tools, model
│ ├── planner.md
│ └── ... (28 files)
├── commands/
│ ├── plan.md # Has frontmatter (some files)
│ ├── build-fix.md # No frontmatter (21 files)
│ └── ... (60 files)
└── CHANGELOG.md

Key observations:

  • Skills live in subdirectories with SKILL.md files
  • Agents are flat markdown files with rich frontmatter (name, description, tools, model)
  • Commands have inconsistent frontmatter - about 21 of 60 have none at all
  • No metadata connects tools to each other or to workflow stages

The scripts/sync-content.mjs script runs before every dev and build. Here’s what it does, step by step:

Uses the same logic as scripts/ci/catalog.js (the CI validation script):

// Skills: directories containing SKILL.md
skills/ -> find directories -> check for SKILL.md -> 125 found
// Agents: markdown files in agents/
agents/ -> list *.md files -> 28 found
// Commands: markdown files in commands/
commands/ -> list *.md files -> 60 found

Each file is parsed with gray-matter. A fallback parser handles files where YAML chokes on unquoted colons in descriptions:

// Primary: gray-matter (standard YAML parser)
// Fallback: regex-based parser that extracts key: value pairs
// between --- delimiters

Missing fields are filled in:

  • Commands without frontmatter: name derived from # heading, description from first paragraph
  • All files: slug and category fields injected

Output: normalized markdown files written to src/content/generated/{skills,agents,commands}/

The registry file (_explorer/data/catalog-registry.json) is loaded and each tool is looked up by category:slug:

// For each catalog entry:
const enrichment = registry.tools[`${category}:${slug}`];
// Merge: domain, triggerQuestion, input, output, relatedTools, profileRelevance

Tools without registry entries get null for enrichment fields.

Everything merges into src/content/generated/catalog.json:

{
"skills": [ /* 125 enriched entries */ ],
"agents": [ /* 28 enriched entries */ ],
"commands": [ /* 60 enriched entries */ ],
"domains": [ /* from registry */ ],
"profiles": [ /* from registry */ ]
}

The script checks:

  • Unregistered tools: In catalog but not in registry (warned, not blocked)
  • Stale entries: In registry but not in catalog (errored - tool was removed)
  • Coverage: Percentage of tools with registry entries

Output:

[sync] 125 skills, 60 commands, 28 agents (213 total)
[sync] WARN: 175 tools without registry entry
[sync] Registry coverage: 38/213 (17.8%)

A detailed report is written to _explorer/data/sync-report.json (gitignored).

Astro + Starlight turns the generated content into a static site:

  • src/content/generated/skills/*.md -> Astro content collection (Zod-validated)
  • src/content/generated/agents/*.md -> Astro content collection
  • src/content/generated/commands/*.md -> Astro content collection
Route patternCountSource
/catalog/skills/[slug]/125Generated skill markdown
/catalog/agents/[slug]/28Generated agent markdown
/catalog/commands/[slug]/60Generated command markdown
/catalog/domains/[domain]/7Registry domains
/catalog/profiles/[profile]/4Registry profiles
/guides/*, /architecture/*~15Hand-authored MDX
Total~250

Starlight’s Pagefind integration indexes all generated HTML at build time, providing full-text search across all 250+ pages.

1. Someone adds skills/new-skill/SKILL.md to the repo
2. Next sync: script discovers it, generates markdown + catalog entry
3. Sync warns: "[sync] WARN: skill:new-skill has no registry entry"
4. Someone adds an entry to catalog-registry.json with domain, I/O, etc.
5. Next build: tool appears in the right domain group with full metadata
1. Someone modifies agents/architect.md (new description)
2. Next sync: script picks up the change automatically
3. Generated markdown and catalog.json reflect the new description
4. Registry enrichment (triggerQuestion, I/O) may need manual review
1. Someone deletes commands/old-command.md
2. Next sync: script no longer finds it
3. Sync errors: "[sync] ERROR: registry references command:old-command which no longer exists"
4. Someone removes the entry from catalog-registry.json
FileRoleCommitted?
data/catalog-registry.jsonHand-authored enrichment dataYes
scripts/sync-content.mjsBuild-time pipelineYes
src/content/generated/*.mdNormalized markdownNo (gitignored)
src/content/generated/catalog.jsonMerged catalog manifestNo (gitignored)
data/sync-report.jsonValidation reportNo (gitignored)