oss-skill
Agent instruction · canonical source
Build reliable Agent Skills
Section titled “Build reliable Agent Skills”Fix the mechanics that decide whether a skill loads, then verify that it improves the task it claims to handle. Format conformance cannot prove output quality, and model behavior is nondeterministic, so never infer reliable behavior from a validator exit code alone.
Most of what this skill fixes is mechanical, and the validator this skill ships at scripts/validate.mjs in its own directory names the fault precisely (R-SKL-02). It reads files, needs nothing installed, and runs on Node or Bun: node scripts/validate.mjs <repository>. Run it before reading further into any repository; its output tells you which of the rules below is in play.
The SKL rules belong here: R-SKL-01 layout, R-SKL-02 specification conformance, R-SKL-03 body size, R-SKL-04 licensing, R-SKL-05 portable scripts, R-SKL-06 install paths, and R-SKL-07 focused procedures with progressive disclosure.
Neighbouring work belongs elsewhere. Wiring the validator into CI is R-CI-02, owned by oss-ci, because the rule already requires CI to run the same linter the contributing guide gives to humans, and for a skills repository that linter is the validator. Keeping every host manifest on one version is R-CHG-03, owned by oss-changelog. The README’s install command and runnable example are R-DOC-02, and its links to the license, changelog, and contributing guide are R-DOC-03, both owned by oss-readme. The sentences inside any file are R-DOC-05, owned by oss-writing. Note what a repository needs and hand it to the owning skill rather than doing that work from here.
Use oss-writing for sentence-level prose and oss-readme for repository documentation. This skill owns whether the skill itself has a focused trigger, an efficient procedure, conditional references, and a verification loop.
Step 1: Find every skill in the repository
Section titled “Step 1: Find every skill in the repository”Locate every SKILL.md in the repository. Resolve symlinked directories to their target first: a repository may commit .claude/skills and .agents/skills as symlinks pointing at one real skills/ directory, and a search that follows them reports every skill two or three times.
Sort what you find into three cases. A SKILL.md that is a direct child of a top-level skills/<name>/ satisfies R-SKL-01. A SKILL.md reached only through a symlink to that directory is the same file and not a finding. A SKILL.md anywhere else is a real finding.
Fix a real finding by moving the whole skill directory under skills/, keeping its references/ and assets/ subdirectories with it, and by pointing every host manifest that names a skills path at skills/. Read references/hosts.md for which manifest each host reads. Moving the directory without updating the manifests trades one loading failure for another.
Where a repository ships skills only as a plugin and keeps them under a nested plugin directory, say so plainly rather than moving them: that layout loads in the plugin host and fails the skills CLI installer, and choosing between them is the maintainer’s call, not yours.
Step 2: Validate against the specification (R-SKL-02)
Section titled “Step 2: Validate against the specification (R-SKL-02)”Run the bundled validator over the repository and fix what it names:
node scripts/validate.mjs /path/to/repositoryIt needs Node 22 or later, or Bun, and nothing installed. It reads files: it writes nothing, spawns nothing, and makes no network call. It reports an error for every violation of R-SKL-01 through R-SKL-05, warns where a frontmatter construct is one it does not read, and exits 1 if any error was found.
The faults come in a small set.
A name and directory mismatch means the frontmatter name and the directory name differ. The specification requires them to match exactly. Decide which one is correct by looking at what already references the skill: a name in the README table, in a plugin manifest, or in another skill’s prose is a name people already use. Rename the other one.
An invalid name means the value breaks the character rules: 1 to 64 characters, lowercase letters, digits, and hyphens only, no leading or trailing hyphen, no consecutive hyphens. Rewrite it and rename the directory to match.
An over-long description means the field exceeds 1024 characters. Cut the parts a reader already knows, keeping both halves the field must carry: what the skill does, and when to use it. Cutting the when half to fit the limit produces a skill that validates and never triggers.
A missing required field means name or description is absent or empty. Both are required and neither has a default.
Frontmatter that fails to parse needs a YAML fix, not a guessed rewrite. Quote single-line descriptions as the repository convention. If the bundled validator warns that it cannot read a valid YAML construct such as a block scalar, check that construct with a strict YAML parser before changing it.
Step 3: Bring an oversized body under the ceiling (R-SKL-03)
Section titled “Step 3: Bring an oversized body under the ceiling (R-SKL-03)”Count the lines of each SKILL.md. Where one exceeds 500, the fix is to move material into that skill’s own references/ directory, not to compress the prose until it fits.
Decide what moves by asking what the reader needs on every run against what they need only sometimes. The procedure, the decisions, and the facts that defy assumption stay in SKILL.md. Long tables, per-platform detail, worked examples, and anything consulted only in one branch of the work move out.
Name each reference file from SKILL.md at the point the reader would need it, and say what makes it worth opening. A pointer at the top of the file listing every reference at once loads nothing usefully, because the reader has no way to tell which one this task needs.
Keep references one level deep. A reference file that sends the reader to a third file costs two loads before the first useful sentence.
Step 4: Declare the license in every skill (R-SKL-04)
Section titled “Step 4: Declare the license in every skill (R-SKL-04)”Add a license: line to every SKILL.md, naming the license that applies to that skill. Use the repository license when it covers every skill. If one skill has different terms, bundle its license file inside that skill and reference the file from frontmatter. Where the evidence conflicts, stop and ask which terms apply.
The Agent Skills specification makes license optional and accepts either a name or a bundled file reference. R-SKL-04 deliberately requires it because an installer may extract one skill directory without the repository license.
Step 5: Keep a shipped script runnable (R-SKL-05)
Section titled “Step 5: Keep a shipped script runnable (R-SKL-05)”Where a skill ships a scripts/ directory, check what its files assume. A script runs on the reader’s machine, so an interpreter they lack or a dependency they cannot install fails the task the skill was invoked for.
A script file needs a shebang naming portable sh or node; documentation and data files under scripts/, such as a README or fixture, need no shebang. Ship JavaScript, not TypeScript, because Node 22 does not provide the type-stripping behavior this repository would need. JavaScript may import real Node built-ins or sibling files by relative path, but no package. No dependency manifest, lockfile, node_modules, runtime-specific module, or Bun or Deno global travels with the skill.
The specification permits Python, Bash, TypeScript, dependencies, and other host-supported choices. R-SKL-05 is deliberately stricter so one shipped script runs unchanged under the repository’s Node 22 floor or a POSIX shell. Where a skill needs another runtime, report the conflict and let the maintainer choose rather than silently rewriting working code.
Fix a violation by rewriting the script against Node built-ins, or by moving the work into the skill’s prose where an agent performs it directly.
Step 6: Make the procedure earn its context (R-SKL-07)
Section titled “Step 6: Make the procedure earn its context (R-SKL-07)”Start from real task evidence: upstream documentation, project artifacts, recurring corrections, and failure cases. Remove generic knowledge the agent already has. Keep one coherent unit of work whose output and boundary can be stated precisely.
Write the description for activation. State what outcome the skill produces and when to use it, using the language a user is likely to use. Include adjacent cases only when the skill truly handles them. Test near-miss prompts too, because a description that triggers on unrelated work wastes the whole body load.
Inside the body:
- Give a default path, not a menu of equal choices.
- Match control to risk. Prescribe fragile sequences; explain intent where several correct approaches exist.
- Keep non-obvious gotchas before the point where they cause failure.
- Name capabilities and observable evidence, not a host’s tool names.
- Load a direct reference only at the branch that needs it. Do not chain references.
- Bundle a tested script only when repeated runs otherwise recreate the same deterministic logic.
- End state-changing work with validation, correction, and re-validation.
Evaluate behavior separately from format. Start with two or three realistic tasks, including an edge case, and define observable success before running them. Run each in a clean context with the skill and against a no-skill or previous-version baseline. Grade assertions with concrete evidence, review the execution trace for wasted steps, and record time and token cost. Keep a change only when it improves the target result enough to justify its cost. For trigger tuning, use varied positive prompts and near-miss negatives, repeat runs because activation is nondeterministic, and keep a held-out validation set.
Step 7: Check the install path behind every claimed host
Section titled “Step 7: Check the install path behind every claimed host”Read the README and the install documentation it links to, and list every host named there. For each one, find the manifest that host reads, at the path that host reads it from, or the documented command that installs without a manifest. A host with neither is an R-SKL-06 finding: either ship the manifest or stop naming the host. Do not accept a manifest at a path no host reads as evidence.
Renaming a skill breaks installs
Section titled “Renaming a skill breaks installs”A skill’s name is its identity everywhere downstream: in an installer command, in a plugin manifest, in a user’s local configuration, and in any other skill that names it. Renaming one to satisfy R-SKL-02 is correct and is also a breaking change for anyone who installed it.
Treat it as one. Say so when proposing the rename, and hand the changelog entry and the version decision to oss-changelog rather than deciding the bump here.
Report what you changed
Section titled “Report what you changed”List every skill you touched, the rule each change satisfies, and every fault the validator reported that you did not fix, with the reason. Name the rename separately from the mechanical fixes, since it is the only one with downstream cost.
Upstream sources
Section titled “Upstream sources”Use the current Agent Skills specification, creator best practices, evaluation guide, description optimization guide, and script guide. Recheck them before changing a rule because the format and host implementations continue to evolve.