---
name: skill-forge
description: Turns a workflow you have repeated several times into a SKILL.md, then measures whether it actually triggers — building an eval set that includes prompts the skill must ignore, and validating description changes against a held-out split before accepting them. Use when writing a new skill, fixing one that fires at the wrong time, or packaging repeated work.
license: MIT
compatibility: Any agent harness that loads SKILL.md files with YAML frontmatter (Claude Code, Codex, Cursor, Windsurf, OpenClaw).
metadata:
  category: productivity
  version: "1.0.0"
---

# Skill Forge

Most skills fail in one of two ways, and neither is about the quality of the instructions. Either the
skill never fires when it should, or it fires constantly when it should not. Both are failures of the
**description**, which is the only part the router sees — and almost nobody tests it.

This skill treats a SKILL.md as an artifact with a measurable trigger rate, not as a document.

## 1. Harvest

Write a skill when the same work has happened **three times** and the outcome varied because of how it
was approached, not because of what was asked. Twice is a coincidence; varying outcomes is what a
skill fixes.

From the transcripts or your own recollection, extract:

- The steps that were the same every time, in order.
- The corrections the user made — these are the actual content, because they are where default
  behaviour was wrong.
- The checks that caught mistakes.
- The judgement calls, and what tipped them each way. Skills that only cover the happy path get
  abandoned at the first fork.

If nothing varied and nothing was corrected, do not write a skill. You have a script; write that.

## 2. Draft

Structure that survives contact:

- **Frontmatter**: `name` (kebab-case, matching the directory), `description`, `license`,
  `compatibility`, and `metadata` with `category` and `version`.
- **An opening paragraph with a point of view** — why the default approach fails. A skill that opens
  with "This skill helps you..." has wasted the position where attention is highest.
- **Numbered procedure.** Imperative, in execution order.
- **Judgement calls.** The forks, and how to decide.
- **A verification gate** — a checklist that must pass before the work is claimed done, requiring
  pasted command output rather than recollection.

**Budget: `SKILL.md` under about 150 lines.** Everything longer goes in `references/` and gets loaded
on demand. The main file is loaded to decide *whether* to act; the references are read once you have.

## 3. Write the description last, and treat it as the router

The description is the only thing that decides whether the skill loads. Write it as
**"Does X, Y and Z. Use when <concrete trigger>, <concrete trigger>, or <concrete trigger>."**

- Name the artifacts and commands a user would actually mention — `tsconfig`, `golangci-lint`,
  `flaky test`, `Dockerfile`. Routing matches on vocabulary; abstractions match nothing.
- State the triggers, not the value. "Use when tightening tsconfig or reviewing types in a PR" routes.
  "Helps you write better TypeScript" does not.
- **Say what it is not for** when a sibling skill is adjacent. This is the cheapest fix for two skills
  fighting over the same prompts.

## 4. Build the eval set — including negatives

Write 12–20 prompts in the user's own voice, split three ways:

- **Positives** (~8): the skill must fire. Include oblique phrasings, not just the obvious one.
- **Negatives** (~6): the skill must stay silent. **This is the half everyone skips**, and it is where
  over-triggering is caught. Draw negatives from adjacent territory — for a TypeScript skill, use
  JavaScript questions and questions about a different language's types.
- **Boundary cases** (~4): genuinely ambiguous, where either answer is defensible. Track these but do
  not tune on them.

Hold back a third as a **validation split you do not look at while iterating**. Tuning against every
example you have produces a description fitted to those examples and nothing else.

## 5. Measure, then iterate

Run the positives and the negatives. Record fired / did not fire for each. The metric is both rates
together: 100% trigger with 50% false positives is a worse skill than 80% with none, because a skill
that fires constantly gets uninstalled.

Change **one thing at a time** — usually a phrase in the description — and re-run. Accept a change only
if it improves the working set *and* holds on the validation split. Keep the rejected candidates in a
comment or a `references/` note; the record of what did not work is worth more than it costs.

## Judgement calls

- **Skill or instruction file?** Always relevant → instruction file. Relevant to one kind of task →
  skill. If it applies on every turn, a skill is the wrong shape and costs you a routing decision.
- **One skill or two?** Split when the triggers are genuinely different, even if the content overlaps.
  Merge when you find yourself writing "see also" in both directions.
- **How prescriptive?** Prescriptive where there is a right answer and the default is wrong.
  Descriptive where it depends. A skill that dictates a judgement call gets overridden and then
  distrusted everywhere else.

## Verification gate

- [ ] `SKILL.md` under ~150 lines; anything longer moved to `references/`.
- [ ] Frontmatter `name` matches the directory name exactly.
- [ ] The description names concrete triggers, not benefits.
- [ ] The eval set contains at least six negatives.
- [ ] Trigger and false-positive rates recorded for the final version, on the held-out split.
- [ ] The procedure was followed end to end on one real task before shipping.
