Skip to content

Data Structure Reference

The Explorer documentation system uses a two-layer data model: base data from the ECC source files, enriched with structured metadata from a registry file. These merge at build time into a unified catalog.

Source Files (base) + Registry (enrichment) = Merged Catalog
skills/SKILL.md catalog-registry.json catalog.json
agents/*.md + generated/*.md
commands/*.md

Each ECC source file has YAML frontmatter. The fields vary by type.

FieldTypeRequiredExample
namestringyes"python-patterns"
descriptionstringyes"Pythonic idioms and best practices..."
originstringno (default: "ECC")"ECC", "Community"
FieldTypeRequiredExample
namestringyes"architect"
descriptionstringyes"Software architecture specialist..."
toolsstring[]yes["Read", "Grep", "Glob"]
modelenumyes"opus", "sonnet", "haiku"
FieldTypeRequiredExample
descriptionstringsometimes"Create implementation plan"

File: _explorer/data/catalog-registry.json

The registry adds structured metadata that doesn’t belong in source file frontmatter: domain assignment, trigger questions, I/O contracts, profile relevance, and tool relationships.

{
"version": 1,
"domains": [ ... ],
"tools": { ... },
"profiles": [ ... ]
}

Domains represent workflow stages. Each tool belongs to one primary domain.

FieldTypeDescription
idstringURL-safe slug: "planning", "implementation", "review"
labelstringDisplay name: "Planning & Architecture"
iconstringStarlight icon name
descriptionstringOne paragraph explaining this domain’s purpose
orderintegerSort order in navigation and listings

Tools are keyed by category:slug (e.g., "skill:python-patterns", "command:tdd", "agent:architect").

FieldTypeRequiredDescription
domainstringyesDomain ID this tool belongs to
triggerQuestionstringnoThe question a human asks that leads to this tool
input.contextstringnoWhat you feed the tool
input.prerequisitesstring[]noWhat must exist before using it
output.artifactstringnoWhat the tool produces
output.formatstringnoHow the output is delivered (code files, markdown, etc.)
relatedToolsstring[]noOther category:slug refs that pair well
profileRelevancestring[]noProfile IDs this tool is relevant to

Profiles represent human roles with recommended workflow steps.

FieldTypeDescription
idstringURL-safe slug: "junior-dev", "senior-dev", "architect", "qa-lead"
labelstringDisplay name: "Junior Developer"
descriptionstringRole description
workflowStepsarrayOrdered steps in the workflow
workflowSteps[].orderintegerStep sequence number
workflowSteps[].toolRefstringcategory:slug reference to a tool
workflowSteps[].actionstringWhat the user does at this step

The sync script merges both layers into src/content/generated/catalog.json:

{
"skills": [
{
"name": "python-patterns",
"description": "Pythonic idioms...",
"slug": "python-patterns",
"origin": "ECC",
"domain": "language",
"triggerQuestion": "What's the Pythonic way to write this?",
"input": { "context": "Python code", "prerequisites": [] },
"output": { "artifact": "Guidance on idioms...", "format": "knowledge" },
"relatedTools": ["skill:python-testing", "agent:python-reviewer"],
"profileRelevance": ["junior-dev", "senior-dev"]
}
],
"agents": [ ... ],
"commands": [ ... ],
"domains": [ ... ],
"profiles": [ ... ]
}

Tools without registry entries get null for enrichment fields:

{
"name": "some-unregistered-skill",
"domain": null,
"triggerQuestion": null,
"input": null,
"output": null,
"relatedTools": [],
"profileRelevance": []
}

The Astro content collections validate generated markdown files using Zod schemas in src/content.config.ts:

// Skills collection
z.object({
name: z.string(),
description: z.string(),
origin: z.string().optional(),
slug: z.string().optional(),
category: z.string().optional(),
})
// Agents collection
z.object({
name: z.string(),
description: z.string(),
tools: z.string().optional(), // JSON-stringified array
model: z.string().optional(), // "opus" | "sonnet" | "haiku"
slug: z.string().optional(),
category: z.string().optional(),
})
// Commands collection
z.object({
name: z.string(),
description: z.string(),
slug: z.string().optional(),
category: z.string().optional(),
})
  1. Tool keys use category:slug format to avoid collisions between a command and skill with the same name (e.g., command:eval vs skill:eval-harness).

  2. One primary domain per tool. Cross-references are handled by relatedTools, not multiple domain assignments.

  3. Registry is committed to git, not generated. It’s hand-authored enrichment data that evolves independently of source files.

  4. catalog.json is generated and gitignored. It’s rebuilt on every sync. Components read it directly.