Authoring skills
July 17, 2026 · View on GitHub
How to create or edit a skill in this repository. Use the author-skill skill for
the general authoring workflow (draft → test → review → improve); this document is
the Spine-specific layer of conventions that workflow does not itself enforce, so
follow both.
Heads-up:
author-skillis derived from Anthropic'sskill-creator(Apache-2.0; license text inskills/author-skill/LICENSE.txt) and is being adapted and extended for this repository's needs, so expect it to diverge from the upstream over time. It doesn't yet match every convention here — notably, itsSKILL.mdkeeps the upstream guide's structure rather than theWorkflow/Repo Notes/Reportshape — so when authoring a new skill, treat this document (notauthor-skill's current form) as the source of truth.
Anatomy of a skill
skills/<name>/
├── SKILL.md # required — the skill definition
├── agents/
│ └── openai.yaml # required — Codex/OpenAI interface metadata
├── references/ # optional — long reference docs, loaded on demand
├── scripts/ # optional — deterministic helpers the skill runs
└── assets/ # optional — templates and other static files
Naming
- Lowercase, hyphen-separated (
raise-coverage, notraiseCoverage). - The directory name MUST equal the
name:in theSKILL.mdfrontmatter. - Avoid names reserved by other agents (e.g. Codex's
create-skill, Anthropic'sskill-creator). When unsure, choose a distinct verb or aspine-prefix.
SKILL.md
Frontmatter followed by the body:
---
name: <kebab-case-name> # == directory name
description: > # one folded paragraph, < 1024 chars, no angle brackets
What the skill does AND when to use it — this is the text an agent matches
a request against, so make the trigger conditions explicit.
---
# <Title>
## Workflow # numbered, deterministic steps
## Repo Notes # repo-specific pointers, e.g. `.agents/guidelines/<file>.md`
## Report # what the skill returns to the caller
Rules:
- Write the
description:as shown — a>folded scalar, even when the text would fit on one line — and wrap its lines near 80 columns (the hard limit is 100, per.agents/guidelines/coding.md). - Keep
SKILL.mdunder ~500 lines; move long material intoreferences/and link to it. - Reference shared guidance with repo-rooted paths
(
.agents/guidelines/<file>.md). These resolve here (via the in-repo dogfood symlinks) and in every consumer repo. - Write agent-neutral instructions that work for Claude, Codex, and Junie — don't hard-code a single runtime's slash-command syntax in the body.
- Never reference a task plan. No part of a skill —
SKILL.md,references/,scripts/,assets/, oragents/openai.yaml— may link to or cite a path under.agents/tasks/ortasks/. Task plans are volatile: they are deleted during or soon after the PR they track (see the lifecycle in.agents/tasks/README.md), so the reference rots. Point at a durable target instead — a.agents/guidelines/page, the relevant source, or its KDoc — or inline the stable fact.
agents/openai.yaml
interface:
display_name: "<Human Readable Name>"
short_description: "<one line>"
default_prompt: "Use $<name> to …" # refer to the skill as $<name>
Keep default_prompt short and aligned with the SKILL.md description.
Claude wrappers and model tiers
Claude Code consumes a skill through thin wrappers: claude/commands/ (slash
commands) and claude/agents/ (subagents). Model selection is a Claude-specific
concern, so it lives only in wrapper frontmatter — never in SKILL.md,
which other runtimes also parse.
- Declare models by alias (
haiku,sonnet,opus; agents may alsoinherit) — never by dated model ID. Consumers float tomaster, so a dated ID pins every repository to an aging snapshot that eventually retires; an alias upgrades for free. - Pick the cheapest tier that runs the skill reliably:
haiku— formulaic work: run a script, a deterministic pipeline, or a tightly specified procedure and relay the result (update-copyright,run-build,api-discovery,check-links,bump-version,version-bumped), or a checklist audit already optimized for batched tool calls (dependency-audit).sonnet— procedural edits and checklist reviews that involve some judgment (bump-gradle,dependency-update,move-files,proofread, and thespine-code-review,review-docs, andgradle-reviewagents).- omit the field (commands) or
inherit(agents) — deep-reasoning work where the user's session model should govern: code translation, test and prose authoring, and thekotlin-engineerreview.
- Leave
pre-prwithout a model: a command's model applies to the turn that runs it, and a subagent declaringinheritinherits from that turn — pinning the orchestrator would silently downgrade the reviewers it dispatches. - Tier paired wrappers together:
version-bumpedrunsbump-versionas its recovery path, so the guard must never sit on a lower tier than the action it embeds. - Some skills run inline at the session model by design:
author-skillandco-author-docsare interactive workflows that converse with the user, whilekotlin-jvm-testerandkotlin-engineer(when used directly as a skill for writing Kotlin, as opposed to its review-agent wrapper) are convention packs whose guidance must land in the calling context while it writes code. A wrapper cannot re-tier them without severing that interaction, so their cost deliberately follows the session.
Claude wrapper frontmatter
Wrappers under claude/commands/ and claude/agents/ are Markdown, so the
100-character line limit from .agents/guidelines/coding.md applies to them
(see .agents/guidelines/documentation.md). Two conventions follow:
- Always write
description:as a>block scalar — even when the text would fit on one line — wrapping its lines near 80 columns, the same idiomskills/*/SKILL.mdfiles use. YAML folds the lines back into a single-line string, so wrapping never changes the wording that drives command or agent dispatch, and the uniform shape keeps a later edit from drifting past the 100-character limit. allowed-tools:may stay on one line or be folded with>-— the field is machine-consumed as permission rules (likewise an agent'stools:field), and a>-folded scalar parses to the byte-identical single-line string, so both forms reach Claude Code the same way. This equivalence is verified — with a strict YAML parser over every wrapper, and by live command registration of folded wrappers — so fold the field when a line grows unwieldy, or leave a long line in place: it is exempt from the line-length limit.
Scripts & copyright
Put a skill's own helpers in skills/<name>/scripts/; promote a helper to the
top-level scripts/ only when more than one skill (or an agent hook) uses it.
Make scripts executable; write them as POSIX bash or Python. Source files that
carry code get the standard Apache/TeamDev copyright header. Python helpers should
rely only on the standard library so they run without extra installs.
Validate before opening a PR
- Directory name == frontmatter
name. description< 1024 characters;SKILL.md< ~500 lines.agents/openai.yamlpresent, with a$<name>default_prompt.- If a
claude/wrapper setsmodel:, the value is an alias — never a dated model ID:haiku/sonnet/opusfor commands and agents, plusinheritfor agents only (a command inherits by omitting the field). - Skill files and Claude wrappers stay within the 100-character line limit;
only
allowed-tools:/tools:lines are exempt, and everydescription:is a>block scalar wrapped near 80 columns (see "Claude wrapper frontmatter"). - Every
.agents/...reference resolves (check through the in-repo symlinks). - No skill file references a task plan:
grep -rnE '(^|[^[:alnum:]])(\.agents/)?tasks/' skills/<name>/returns nothing that links to or cites.agents/tasks/ortasks/(the boundary guard avoids matching unrelated words likesubtasks/). - Any shipped script parses — shell scripts with
bash -n, Python helpers withpython -m py_compile— and, where practical, has a test.
Remember: this is production
master floats to every Spine repository, so a merged change is live everywhere
on the next pull. Land changes through a reviewed pull request — never commit or
push directly unless explicitly asked.