Skip to content

Skill Authoring

FieldValue
TypeSkill Resource
Source~/.copilot/skills/skill-forge/references/skill-authoring.md
DescriptionNot specified

Source Content

Skill Authoring

How to design, scaffold, and tune a skill so it triggers reliably and stays under the 500-line limit.

The anatomy

Every skill follows the same shape, so a reader (or the standards linter) can audit any skill the same way.

skill-name/
├── SKILL.md # required — frontmatter + routing table + workflow
├── scripts/ # optional — deterministic operations
├── references/ # optional — loaded on demand
├── templates/ # optional — scaffolds (Taskfile.yml, story shells, etc.)
└── assets/ # optional — output templates, images

SKILL.md structure

SectionRule
Frontmattername matches directory, description carries every trigger phrase (max ~1,200 chars), optional license
Metadata tableDomain / Role / Output, four rows max
Route by taskThe routing table: You’re… / Read / Gate with. This makes it a front door.
House rulesNon-negotiables, numbered, each citing the ADR or reference
Use/Don’t-useSpell out what you do and don’t do. Redirect to other skills by name.
How I workThe workflow. Numbered steps. Validate step names the script.
Self-rubricCheckboxes. Last one: “validation script exits 0.”
ReferencesEvery references/, scripts/, templates/ path listed.

Size cap: 500 lines. Anything beyond the routing table and house rules moves to references/.

Writing the description / triggers

The description is the load-bearing step of every skill consolidation. It must carry every trigger phrase from every absorbed skill so the LLM routes correctly on “old” phrasing too.

Start with strongest signal:

  • Lead with the primary verb+object: “Create new Agent Skills”, not “A tool that can make skills”.
  • Pack concrete tool names, file patterns, domains: “Markdown/MDX files, Mermaid diagrams, code comments” signals more than “documentation.”
  • Add NOT-clauses so the LLM also knows when to skip you: “NOT for PRDs, user stories, PR descriptions”.

Merge absorbed skills’ trigger lists:

When consolidating two skills, copy both SKILL.md descriptions and extract every unique trigger phrase. Weave them into one paragraph, keeping the strongest signal at the top.

Example (skill-forge):

Create new Agent Skills, validate existing ones, and sync them across Claude Code,
Codex, and GitHub Copilot. Use this for authoring or editing a skill from scratch
(naming, frontmatter, triggers, references, templates), validating a skill's format
and standards compliance, or syncing and sharing skills across tools and team folders.
Triggers: "create a skill", "new skill", "edit this skill", "improve skill triggering",
"skill eval", "tune skill description", "validate this skill", "sync my skills",
"share this skill", "convert this skill", "share these skills with", "install this skill",
"package a skill", or "share only certain skills".

That’s ~260 chars — clear, searchable, and under the ~1,200 cap.

Progressive disclosure

Metadata + triggers — always in context.

SKILL.md body — loaded when the skill triggers (keep lean).

references/*.md — loaded only when the workflow needs them. One topic per file.

scripts/ — executed without loading into context. No size penalty.

When to split:

  • SKILL.md grows past ~500 lines → split.
  • A file in references/ grows past ~100 lines → add a table of contents at the top.

Naming

  • Directory name matches name: in frontmatter exactly.
  • Use lowercase kebab-case: skill-name, not SkillName or skill_name.
  • Keep it under 64 characters.

Frontmatter fields

Required:

name: skill-name
description: >-
One paragraph; every trigger phrase from absorbed skills; under ~1,200 chars.

Optional (preserved across tools unless you use --strict):

license: Complete terms in LICENSE.txt
metadata: ... # tool-specific labels, compatibility notes
triggers: [...] # Copilot-only; Claude/Codex ignore it
requires: ... # Copilot-only; required dependencies

Frontmatter validation

scripts/check_skill.py and scripts/standards_linter.py check:

  • SKILL.md exists with valid --- YAML frontmatter.
  • name is a valid slug (^[a-z0-9][a-z0-9-]*$, ≤ 64 chars) and equals the folder name.
  • description is present and under the character cap.
  • All relative links in SKILL.md resolve to existing files.
  • All references/, scripts/, templates/ paths mentioned in SKILL.md exist on disk.
  • Script entrypoints exist and are executable.

Routing table structure

Every front-door skill has a “Route by task” table near the top. The shape is:

You’re…ReadGate with
task 1references/file.mdscripts/check.py
task 2references/file.md → subheadingscripts/check.py --flag

What to notice:

  • Left column answers “what do you want to do?” Not “I want to use a skill,” but “I want to draw a diagram” or “sync all my skills.”
  • Middle column points to the reference file that unblocks that task. One topic per file; multiple rows can point to the same reference when different workflows feed it.
  • Right column names the validation script, flag, or ”—” if the task needs no automated check.

A routing table signals that this is a front door with internal material, not a thin wrapper.

The 500-line budget

Use wc -l SKILL.md to track. The limit is a gating rule: if a skill’s front-door body cannot fit in 500 lines, the domain is too large and needs a different design. Options:

  1. Split the routing table across multiple front doors (e.g., if frontend cannot hold 11 domains).
  2. Move deep workflows into references/ — only the trigger and routing line stay in the body.
  3. Reconsider whether this is truly one domain (it may not be).

The standards_linter.py script flags skills over 500 lines so you catch this at validation time.

The self-rubric

Every SKILL.md ends with a checkbox rubric. The last check is always:

- [ ] **Validated.** `scripts/standards_linter.py <skill-dir>` exits 0 — frontmatter valid, name matches directory, description under cap, routing table present, all paths exist, scripts are executable.

This makes the standards-linter output auditable and testable.

References inside a skill

Keep them inside the skill’s own references/, scripts/, or assets/, so a copy is portable on its own. Cross-skill links (e.g., ../adr/references/index.md) are acceptable when you always sync the whole tree but risky for an isolated --dir copy of one skill.

Constraints

  • Never include README.md, INSTALLATION_GUIDE.md, QUICK_REFERENCE.md, or CHANGELOG.md in a skill.
  • Never duplicate detail between SKILL.md and references/ — pick one home.
  • Never invent quotes or attributions; paraphrase if unsure.