mcpbeat Sign in

Writing Agent Skill House Style

Write an agent skill that survives an adversarial review — a description carrying both the trigger and the error symptom the reader is staring at, a short orientation, a Traps section that dominates the file, and verification commands you have actually run. Use when authoring or reviewing a SKILL.md, when a skill reads like documentation instead of hard-won advice, or when review keeps finding claims the source repository does not support.

2k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
100
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/maxrave-dev/kotlin-footguns --skill writing-agent-skill-house-style

The instruction itself

4 sections, as written by the author

Writing an agent skill in this house style

A skill is not a tutorial and not an API reference. It is the note you would leave for the next

person about to lose two days to the same thing. Everything in the format follows from that.

The shape. Frontmatter, a short orientation, a Traps section taking most of the file, then

Verifying it. Roughly 60–140 lines. Orientation exists only to make the traps legible.

The description does two jobs — when to load the skill, and what symptom the reader is

staring at, so the match happens on the error rather than the topic. The exemplar in the mined

repository ends its description "…or hitting ImageVector/Painter type errors": that last clause

is the one that fires when somebody is confused rather than curious.

Teach how to verify a value, never list values that go stale. The same exemplar sends readers

to the upstream code-point list rather than listing names. A list goes stale; a procedure does not.

The Traps section is the product. Each trap opens with the wrong move in bold, then what

happens, then what to do instead — so a reader scanning bold lines finds their own situation.

What review actually catches

Across four closed review batches, adversarial review kept finding a different character of error

each time — which is the order your own drafts will fail in:

  • Content errors — claims the source repository does not support. Caught by opening the file

the skill cites.

  • Prose-versus-artifact errors — a claim sourced from a comment or a changelog entry, where

the code beside it had already moved on. Caught by re-deriving from the artifact.

  • Unrunnable verification commands — plausible but never executed: wrong flag order, a glob

the shell ate, an anchored pattern that silently matched nothing.

  • Mechanism not re-derived — the trap was real, the stated reason a guess. Caught by asking

"how do you know *that* is why?" of every rationale.

Round 3 is the cheapest to prevent: **run every command in the Verifying section, verbatim,

against the real repository, before shipping.** A command never run is a claim, not a check.

Traps

A description that names only the topic. "Icons in this project" matches nothing a confused

reader would type. Include the trigger *and* the symptom they are staring at.

Frontmatter name that does not match the folder. Two separate strings, and nothing in a

text editor compares them. A mismatch makes the skill unloadable while looking perfect.

Orientation that grows into a tutorial. If the first third could have been read in the

framework's own docs, stop. Assume the reader knows the technology and does not know this trap.

Counts written from memory. "There are 59 icons" is wrong a week later and cannot be checked

by a reader. Give the command that produces it — likewise file, call-site and version counts.

Marking an excerpt "adapted" when it is verbatim, or the reverse. Load bearing: a reader who

believes an excerpt is real will grep for it. Renamed anything → // adapted; recheck after edits.

Sourcing a claim from a comment. A comment records what somebody believed then. In the mined

repository a control stayed hidden on one platform under a comment saying the media engine lacked

support — true when written, false months later. Such prose is a *lead*; confirm against artifact.

Stating a rationale you have not re-derived. "It fails because X" written from plausibility

survives longest: it reads exactly like the version that was checked. Trace every "because".

Unquoted globs and bare find predicates. grep -r *.kt is expanded by the shell before

grep sees it; find . -name *.kt fails the same way. Quote every glob.

A Verifying section made of prose. "Check that the configuration is correct" is not a check.

Every step is a command with a stated pass condition, or an artifact plus what you expect in it.

Verifying it

Run these from the root of the skills collection.

  • Frontmatter name matches the folder, for every skill:
   for f in skills/*/SKILL.md; do
     n=$(awk -F': ' '/^name: /{print $2; exit}' "$f")
     d=$(basename "$(dirname "$f")")
     [ "$n" = "$d" ] || echo "MISMATCH folder=$d name=$n"
   done

Pass condition: no output.

  • Every description carries a trigger clause — match the clause, not one spelling of it.

Anchoring on a single phrasing measures house style, not the property you care about:

   awk '/^description:/ && !/[Uu]se when/ && !/[Rr]each for (it|this) when/ {print FILENAME}' \
     skills/*/SKILL.md

Pass condition: open every file printed. Dropping the second alternation — the narrow check

this replaced — reports 29 of these 140 as untriggered, every one of them a false positive.

  • Length is inside the band:
   wc -l skills/*/SKILL.md | sort -n | awk '$1<60 || ($1>140 && $2!="total")'
  • The Traps section dominates. Report the share of each file that sits at or after the traps

heading:

   for f in skills/*/SKILL.md; do
     t=$(wc -l < "$f")
     s=$(grep -n '^## Traps' "$f" | cut -d: -f1)
     [ -n "$s" ] && printf '%3d%%  %s\n' $(( (t - s) * 100 / t )) "$f"
   done | sort -n | head -20

A file well under half is usually an orientation that outgrew its job.

  • Every skill ends in a verification section. ## Verifying it is the canonical heading, not

a universal fact — a file printed here may use a variant heading or truly lack the section:

   grep -L '^## Verifying it' skills/*/SKILL.md
  • Run each fenced command yourself — the round-3 check. The leading [[:space:]]* is not

optional: list fences are indented, and an anchored ^ extracts almost nothing, looking fine.

   awk '/^[[:space:]]*```bash/{f=1;next} /^[[:space:]]*```/{f=0} f' skills/*/SKILL.md | sed '/^\s*$/d'
  • Confirm every cross-referenced skill exists on disk, by name, before shipping:
   grep -ho '`[a-z0-9]\+\(-[a-z0-9]\+\)\{1,\}`' skills/*/SKILL.md | tr -d '`' | sort -u \
     | while read -r n; do [ -d "skills/$n" ] || echo "MISSING $n"; done

Not a clean zero: the pattern also catches hyphenated non-skill tokens, so the pass condition

is that every line printed is visibly not a skill name. A real one here is a broken reference.

How to use it

Copy the folder

Take maxrave-dev/writing-agent-skill-house-style from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.