7. Skills are data under the layer's skills section, and every surface that shows one is a projection
Extends ADR 2 and ADR 5.
Context
The manifest has named a skills section since the layer existed, and it held a README
and nothing else. The operator asked for the first skill, repo-review, and for the
condition that the next one must cost nothing but its own files: no registry, no site
list, no MCP entry, no provider file, no Rust match arm to touch. The source material of
this tool is the warning: a catalogue of five hundred and forty-six agents of which one
was registered with anything that ran, because existing and being registered were two
acts and only one of them was ever done.
Decision
- A skill is a directory.
.ai/repo/skills/<id>/SKILL.md— YAML front matter undershare/schemas/skill.schema.json(schema: skill/v1,idequal to the directory, integerversion,title,description,statusfrom a closed set, optionaltags,related,inputs,outputs) over a Markdown body with non-empty# Purpose,# Procedureand# Outputsections — with optionalexamples/*.md. - Discovery is the existing one, declared once.
share/kinds.yamldeclares the kindskill; the source classesskillandskill_examplein.ai/repo/knowledge/sources.yaml(and the skeleton a freshinitwrites) say which tracked files carry it. The Rust executable indexes them as it indexes every kind and servesmajordomus://skill/<id>with no code that names the kind; the shell tool'slib/skills.shderives one catalogue from the same class throughmj_knowledge_discover, validating against the allow-listmajordomus generate allowderives from the same schema. - Every surface reads the catalogue.
majordomus skills list|show|check, the doctrinemajordomus.skill-integrity(dispatched bydoctorandwatch), andscripts/generate-site-data, which writessite/data/generated/skills.jsonand one page per skill undersite/content/skills/and replaces that directory whole. The site's templates render from those two files and the section's own pages; the navigation names the section, never a skill. - Drift fails.
generate --checkrefuses a stale allow-list or registry dataset;generate-site-data --checkrefuses stale site data;skills checkanddoctorrefuse a skill that breaks its contract, name the file and every reason, and report the counts of what they examined; a repository with no skills is aWARN, not a pass. - Nothing is registered by name. No file in the repository lists skills by hand. The
test
test/cases/95_skills.shadds, breaks, renames and removes a skill and asserts that the command, doctor, the Rust index over MCP, the site data and the built pages follow, and that no page outlives its file.
Consequences
Adding a skill is writing its directory and tracking it. The cost of the decision is in
the contract: a skill that lacks a section or names a related skill that does not exist
fails doctor for everyone, which is intended. Two readers (shell and Rust) parse the
same front matter with the same schema; the shell reads the schema's projection, the Rust
executable reads the schema, and the case proves they refuse the same file for the same
reason. What is not decided here: which skill a task should load (the generated
instructions say "the ones the task is about"), and whether a skill is any good.