.agents/skills/<name>/ containing a single SKILL.md. Skills follow the agentskills.io convention so they install cleanly into Claude Code, Cursor, Codex, and Copilot through ralphy skill install. This page is the wire-format spec: frontmatter fields, body sections, the lint that enforces both, and the description discipline that keeps the slash-command menu scannable.
Full example
A valid.agents/skills/evaluator/SKILL.md:
bun run lint:skills and renders correctly in every supported agent.
Where skills live
name: field — the lint rejects a mismatch. The folder is yours; drop scripts, templates, or worked-example files alongside SKILL.md and they ship with the skill on install.
Frontmatter contract
The frontmatter is a YAML block between--- fences. scripts/lint-skills.ts enforces:
| Field | Required | Validation | Notes |
|---|---|---|---|
name | yes | /^[a-z][a-z0-9-]*$/, matches folder name | kebab-case |
description | yes | length ≤ 1536 chars | agentskills.io hard cap |
namespace | no | user or maintainer | drives install wizard visibility |
when_to_use | no | free-form string | downstream filter tag (e.g. post-render) |
allowed-tools | no | string array | tool allowlist |
disable-model-invocation | no | boolean | true makes the skill docs-only |
paths | no | string array | workspace paths the skill touches |
context | no | free-form string | label for “suggest this skill” surfaces |
argument-hint | no | free-form string | shown next to the slash command in Claude Code |
arguments | no | YAML literal | positional-arg schema (future MCP use) |
key: value and the folded key: >- block used for multi-line description.
The name rule, in source
The description cap, in source
The namespace whitelist
| Namespace | Audience | Examples |
|---|---|---|
user | end users | evaluator, researcher, templater, install |
maintainer | maintainers / contributors | dev-release, dev-tasks |
ralphy skill install installs only user skills by default. --dev opts into the maintainer set. The agents-md lint (scripts/lint-agents-md.ts) reads namespace: and skips the “is this skill referenced from the routing table” check for maintainer skills — maintainer skills are explicit-invocation-only.
Body structure
The lint warns (does not error) when section headings are missing. Every non-trivial skill should hit this order:## heading starting with Trigger, Hard invariants, Workflow, Outputs, or Cookbook (case-insensitive prefix match). It only warns when none of them are present, so an intentionally minimal skill-creator-style body does not generate noise.
Writing a great description
The description is the user-facing summary of the skill, not an auto-route trigger phrase list. Claude Code renders it in the/<skill> slash-command menu, the “suggest this skill” surface, and the ralphy skill list output. A scannable paragraph beats a wall of synonyms.
Good: ~300 chars
Bad: ~1800 chars (rejected by the cap)
Structure that works
One paragraph, optionally broken into “what / when” sentences:- First sentence. What the skill does and what it produces.
- Second sentence. When the user reaches for it.
- (Optional) Third sentence. What it does not do — the closest adjacent skill the user might confuse it with.
## Trigger section. The body is where the agent looks once the skill fires; the description is where the user looks before invoking it.
The agentskills.io cap (1536) and the menu-budget reality (~1500 soft) are not the same number on purpose. Hard cap stops the worst case; soft ceiling is the discipline.
ALSO FIRE / DO NOT FIRE / HARD INVARIANTS
For longer skills (the existingevaluator and researcher), the description ends with See body for ALSO FIRE / DO NOT FIRE / HARD INVARIANTS. and those clauses move into the body under ## Trigger refinements and ## Hard invariants. This pattern keeps the description scannable while preserving the routing-fidelity detail the agent needs once the skill fires.
The rule of thumb: if a clause is longer than half a sentence, move it from the description into the body. The description’s job is “should this skill fire?”; the body’s job is “now that it fired, what do I do?”
Lint
.agents/skills/*/SKILL.md and checks:
- Frontmatter parses cleanly (a
---…---block with valid YAML). namematches/^[a-z][a-z0-9-]*$/and equals the folder name.descriptionis present and ≤ 1536 chars.namespace, if set, isuserormaintainer.- (Warning) The body has at least one
##section heading.
lint:skills on every PR. A failing lint blocks merge.
Installing skills
ralphy skill install is the cross-agent installer in cli/lib/skill/installer.ts. It supports four targets:
| Target | What lands |
|---|---|
claude | Copies (or symlinks) the bundle into ~/.claude/skills/ralphy/ (user) or ./.claude/skills/ralphy/ (project), then sentinel-merges a routing pointer into CLAUDE.md. |
cursor | Writes .cursor/rules/ralphy.mdc with the playbook routing block. |
codex | Sentinel-merges a Ralphy section into AGENTS.md at the project root. |
copilot | Same sentinel-merge pattern. |
<!-- ralphy:start v=1 --> … <!-- ralphy:end -->) makes re-runs idempotent. A second ralphy skill install swaps the inner content without duplicating the block.
Related
- Concepts: playbooks & skills — when to write a skill vs a playbook.
- Skills gallery — every built-in skill with trigger phrases and contracts.
docs/skills-format.md— the source-of-truth authoring guide.scripts/lint-skills.ts— the lint source.cli/lib/skill/installer.ts— the cross-agent installer.