DOCS · SKILLS
ALL DOCS FIG. 15 · DWG VC-015

Authoring skills

Write your own vc-* skill: scaffold the layout, meet the frontmatter contract, wire the launcher, and pass the discoverability gates.

Canonical source — docs/public/skills/authoring-skills.md

Authoring skills

A skill is one operator move: one trigger situation, one named workflow, one decisive outcome. If your draft describes three fundamentally different situations, you are writing three skills. This page distills the contribution contract into the steps that matter.

Scaffold, do not copy

Use the scaffolder from the repository root. It handles placeholder substitution, executable bits, and date-stamping; hand-copying an existing skill directory skips all of that.

make skill-new NAME=vc-my-new-skill
# or directly:
tools/vc-skill-new.sh vc-my-new-skill

The scaffolder enforces the naming rules — the name starts with vc-, uses lowercase letters, digits, and single hyphens, and must not collide with an existing skill — then copies the template into skills/vc-my-new-skill/:

skills/vc-my-new-skill/
├── SKILL.md         # the contract; YAML frontmatter at the top
├── README.md        # operator-facing overview
├── examples/        # at least one realistic trigger + expected behavior
├── scripts/         # optional; chmod +x, bash strict mode, shellcheck-clean
└── references/      # optional deeper docs loaded on demand

Frontmatter contract

SKILL.md opens with YAML frontmatter between --- delimiters. The structural gate (make test-skills) requires:

KeyRequiredNotes
nameyesMust match the directory name exactly.
descriptionyesOne paragraph; folded scalar is fine; trigger phrases at the end.
versionrecommendedSemver, starting at 0.1.0; bump on every change.

Optional keys: requires: (foundation tools or sibling skills), agent_target: (when biased toward one agent), triggers: (an explicit phrase list when the description is dense).

The description is what the launcher matches when an operator types a freeform request. Write triggers an exhausted operator would actually type at midnight — short, concrete phrases, not formal command prose. If your trigger set overlaps an existing skill, either merge into it or sharpen the boundary until the routing is unambiguous.

Classify before wiring the launcher

Pick the skill’s class before writing any invocation examples, and use only this skill’s real literals — never a pasted generic placeholder:

ClassWhenWorker formInteractive
Core launcherRegistered as a first-class CLI launchervibecrafted <name> <agent>/vc-<name>
MetaLifecycle umbrella, dispatch, operator posturedocumented special formload skill / slash
FoundationPerception or memory sense onlynone — no fake workerloads in other skills

Keep the invocation rail in SKILL.md short and link the shared catalogue; progressive disclosure puts long procedure under references/, not in the body.

Acceptance criteria and anti-patterns

Two sections make a skill trustworthy:

  • Acceptance criteria with a falsifier. If nothing in the acceptance section can be checked from outside the session, the skill is unfalsifiable — rewrite it until “done” is provable from artifacts.
  • Anti-patterns. Enumerate at least two realistic ways the skill will be misused, so agents picking it up cold recognize the boundary. Cross-link adjacent skills in the “when to use” section for the same reason.

Ship at least one realistic examples/*.md pair (trigger phrase plus expected behavior). Agents learn new skills cold by reading examples; an empty examples directory guarantees misuse.

Install and verify

Skills install with the framework; each core launcher gets a vc-<skill> shortcut and a /vc-<skill> interactive form. Verify discoverability before opening a pull request:

make test-skills                      # frontmatter + loader smoke gate
make doctor | grep vc-my-new-skill    # operator-facing discovery surface

If make doctor does not list the skill, the install path did not register it — re-run the installer in dev mode (make setup-dev) and check again. Once the skill is on disk and the shim reinstalled, the launcher accepts it as a valid argument.

Common authoring failures, in rough order of frequency: cloning the most complex shipped skill and find-replacing the name; documenting a generic universal CLI instead of the real launcher; dumping the full delegation catalogue into the skill body; removing worker paths because interactive felt freer; and vague triggers that route operators to the wrong skill.