>_devkit
devkit-skill-authoring
skills/devkit-skill-authoring/

references/writing-well.md

Writing a body Claude actually follows

Validation gets a skill into the registry. It does nothing to make the skill useful. These are the parts that decide whether it changes any behaviour once installed.

The description is a matcher, not a summary

Claude sees the description and nothing else when deciding whether to load the skill. So it has to contain the words that will be in the situation, not the words that describe the document.

# loads when it should
description: Use when setting up or changing CI/CD for a service - branch model, pipeline, promotion and rollback.

# never loads
description: Our CI/CD best practices.

A working test: read your description and ask "what would somebody have to be doing for this to match?" If the answer is "know that this skill exists", rewrite it. Name the artefacts (Dockerfile, .gitlab-ci.yml), the verbs (deploy, roll back), and the nouns (pipeline, runner) that will actually be on screen.

Lead with when, not what

The first section should be the trigger conditions restated in more detail than the description could hold. Somebody skimming, and a model deciding whether to keep reading, both need to know in one screen whether this applies.

Say why, not just what

A rule without its reason gets dropped the first time it is inconvenient, because nothing tells the reader what breaks if they skip it. A rule with its reason survives, and - more useful - can be applied correctly to a case you did not write down.

# forgettable
Set `FF_NETWORK_PER_BUILD: "true"`.

# survives contact
Set `FF_NETWORK_PER_BUILD: "true"`. Without it, service containers from
different jobs share one bridge, and cleaning up a finished job can take the
network out from under a job still running.

This is the single biggest difference between a skill that shapes output and a skill that gets skimmed.

Be concrete, and be current

Prefer a real command, a real path, a real error string. Anything a reader can paste is worth more than a paragraph describing it. Anything you invented is a liability - a plausible-looking flag that does not exist costs more than saying nothing.

If you are documenting a tool, run it and paste what it printed.

Keep SKILL.md short, and put depth in references/

The body is loaded whole. Long bodies crowd out the actual task. The pattern that works:

  • SKILL.md — when it applies, the shape of the work, the decisions and their

reasons, and pointers

  • references/*.md — tables, exhaustive option lists, error catalogues, worked

examples

Point at them explicitly, with the path, so they get read on demand:

For every field and every error message, read `references/frontmatter.md`.

A reference nothing links to will not be read.

Write for two readers

The body is what Claude loads and what the catalogue renders. Both want the same thing - headings that say what is under them, short paragraphs, tables for anything enumerable, fenced code with a language tag. Neither wants a wall of prose.

Things worth including

  • The failure this skill exists to prevent, stated once, early
  • Commands, with their output where the output is the point
  • A checklist near the end, if there is a procedure
  • The boundaries: when this skill does not apply, and what to use instead

Things to leave out

  • Restating what the tool's --help already says, unless you are correcting it
  • Hedging. "You might consider possibly" is instruction the reader cannot act on
  • Anything you have not verified
  • Secrets, tokens, internal hostnames - every file is published

Before you call it done

Read the body as though you had never seen the tool. If a step assumes something you happen to know, either write that down or link it. The reader has your text and nothing else.