---
name: meta-skill-writer
description: Use when creating new skills, editing existing skills, structuring SKILL.md files, writing skill frontmatter, testing skills with subagents, deploying skills, or verifying skills work before deployment
---

# Writing Skills

> Adapted from the superpowers plugin (MIT).

## Overview

**Writing skills IS Test-Driven Development applied to process documentation.**

**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.agents/skills/` for Codex)** 

**if there is a skill in the current directory, work on AND test THAT skill, not `~/.claude/skills` or `~/.agents/skills/`**

You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes).

**Core principle:** If you didn't watch an agent fail without the skill, you don't know if the skill teaches the right thing.

**REQUIRED BACKGROUND:** You MUST understand bitranox:process-test-driven-development before using this skill. That skill defines the fundamental RED-GREEN-REFACTOR cycle. This skill adapts TDD to documentation.

**Official guidance:** For Anthropic's official skill authoring best practices, see anthropic-best-practices.md. This document provides additional patterns and guidelines that complement the TDD-focused approach in this skill.

## Reference Files

| Topic                                                                      | File                             |
|----------------------------------------------------------------------------|----------------------------------|
| Testing methodology - pressure scenarios, RED/GREEN/REFACTOR, meta-testing | testing-skills-with-subagents.md |
| Persuasion principles - authority, commitment, scarcity, social proof      | persuasion-principles.md         |
| Anthropic official best practices - conciseness, freedom, structure        | anthropic-best-practices.md      |
| Graphviz conventions - node shapes, edge labels, naming patterns           | graphviz-conventions.dot         |
| Flowchart rendering - SVG output from dot diagrams                         | render-graphs.js                 |
| Worked example - full test campaign testing CLAUDE.md variants             | examples/CLAUDE_MD_TESTING.md    |

Use the Read tool to load referenced files identified as relevant for full details.

## What is a Skill?

A **skill** is a reference guide for proven techniques, patterns, or tools. Skills help future Claude instances find and apply effective approaches.

**Skills are:** Reusable techniques, patterns, tools, reference guides

**Skills are NOT:** Narratives about how you solved a problem once

## TDD Mapping for Skills

| TDD Concept             | Skill Creation                                   |
|-------------------------|--------------------------------------------------|
| **Test case**           | Pressure scenario with subagent                  |
| **Production code**     | Skill document (SKILL.md)                        |
| **Test fails (RED)**    | Agent violates rule without skill (baseline)     |
| **Test passes (GREEN)** | Agent complies with skill present                |
| **Refactor**            | Close loopholes while maintaining compliance     |
| **Write test first**    | Run baseline scenario BEFORE writing skill       |
| **Watch it fail**       | Document exact rationalizations agent uses       |
| **Minimal code**        | Write skill addressing those specific violations |
| **Watch it pass**       | Verify agent now complies                        |
| **Refactor cycle**      | Find new rationalizations -> plug -> re-verify   |

The entire skill creation process follows RED-GREEN-REFACTOR.

## When to Create a Skill

**Create when:**
- Technique wasn't intuitively obvious to you
- You'd reference this again across projects
- Pattern applies broadly (not project-specific)
- Others would benefit

**Don't create for:**
- One-off solutions
- Standard practices well-documented elsewhere
- Project-specific conventions (put in project instructions file: CLAUDE.md / AGENTS.md)
- Mechanical constraints (if it's enforceable with regex/validation, automate it - save documentation for judgment calls)

## Skill Types

### Technique
Concrete method with steps to follow (condition-based-waiting, root-cause-tracing)

### Pattern
Way of thinking about problems (flatten-with-flags, test-invariants)

### Reference
API docs, syntax guides, tool documentation (office docs)

## Directory Structure


```
skills/
  skill-name/
    SKILL.md              # Main reference (required)
    supporting-file.*     # Only if needed
```

**Flat namespace** - all skills in one searchable namespace

**Separate files for:**
1. **Heavy reference** (100+ lines) - API docs, comprehensive syntax
2. **Reusable tools** - Scripts, utilities, templates

**Keep inline:**
- Principles and concepts
- Code patterns (< 50 lines)
- Everything else

**Hub skills with supporting files:** When SKILL.md is an index that points to separate reference files, add an explicit instruction in the body (not frontmatter) telling Claude to use the Read tool. This prevents Claude from trying to answer from summary tables alone instead of loading the detailed file.

```markdown
Use the Read tool to load referenced files identified as relevant for full details.
```

Only add this for hub/reference skills with supporting files. Self-contained skills (where everything is in SKILL.md) don't need it - the full body is already loaded when invoked.

**Upstream doc linking:** When hub skills consolidate content from original source documents in subdirectories (e.g., `docs/`, `tutorial/`, `api/`), include a two-tier routing table in SKILL.md:
1. **Tier 1** - distilled reference files (same directory as SKILL.md)
2. **Tier 2** - original upstream docs (subdirectory paths for deeper detail)

Don't rely on passive `> Source:` annotations in supporting files - agents treat these as attribution, not as actionable links. The hub must provide an explicit routing table for upstream docs.

```markdown
## Reference Files

| Topic                                           | Distilled reference | Upstream source (full detail)      |
|-------------------------------------------------|---------------------|------------------------------------|
| Core API - Client, Session, request(), stream() | api-reference.md    | docs/api/full-reference.md         |
| Config - Settings, env vars, pyproject section  | configuration.md    | docs/guides/configuration.md       |
| Tutorials - quickstart, first app, deployment   | quick-start.md      | tutorial/getting-started/README.md |

Use the Read tool to load a distilled reference first.
If it lacks the detail you need, load the upstream source.
```

The upstream table should work as a comprehensive index so an agent can jump straight to the right file for any specific class, function, or method. Each row needs to list the concrete API symbols the file covers, not just a prose summary.

```markdown
| Topic                                                   | Upstream source |
|---------------------------------------------------------|-----------------|
| NO Widgets                                              | docs/widgets.md |
| OK Widgets - DataTable, Tree, OptionList, Select, Input | docs/widgets.md |
```

**Building routing tables:** For each supporting file, use `grep -E '^#{2,3} ' filename.md` to extract H2/H3 headings. For tier 1 (distilled reference) rows, list the 3-5 most important headings, class names, or function names as the topic description. If a file covers more than 5 key terms, pick the ones an agent is most likely to search for and add an "etc." or "and more" suffix. For tier 2 (upstream source) rows, list all classes, functions, API endpoints, and key concepts - the upstream column serves as a comprehensive index, so every symbol must be findable through the topic description.

**Evaluating routing descriptions:** For each row in a routing table, ask: given a realistic user query, could Claude pick the right file from the topic description alone? If two rows sound equally plausible for the same query, the descriptions need more differentiation.

Common failures:
- Topic names too generic ("API", "Config") - Claude can't distinguish files
- Overlapping scope - two files both sound relevant for the same query
- Missing subtopics - key content buried inside a file isn't mentioned in the description

Fix: expand topic descriptions to include 2-3 disambiguating subtopics or keywords.

```markdown
| Topic                                         | Distilled reference |
|-----------------------------------------------|---------------------|
| NO API                                        | api-reference.md    |
| NO Config                                     | configuration.md    |
| OK Core API - endpoints, auth, rate limits    | api-reference.md    |
| OK Config - env vars, CLI flags, config files | configuration.md    |
```

**Verifying routing tables:** After writing a routing table, run two checks to confirm it is both complete and accurate. For two-tier tables, run both checks independently for the distilled reference column and the upstream source column:

1. **Coverage check (file -> table):** For each referenced file, run `grep -E '^#{2,3} ' filename.md` to extract its headings. For each heading or key term, confirm it appears in the routing table's topic description for that file. Missing terms = content agents can't find through the table.
2. **Accuracy check (table -> file):** For each search term listed in the routing table, run `grep -i "term" filename.md` to confirm the file actually contains it. Mismatches = stale entries that route agents to the wrong file.

A routing table passes when every key term in the file appears in the table (coverage) and every term in the table appears in the file (accuracy). For tier 1 rows with 10+ headings, coverage is sufficient if the top 5 most-queried terms are represented. For tier 2 rows, coverage requires all classes, functions, and API endpoints - no "top 5" shortcut. Both columns must pass independently.

Example:

```markdown
Referenced file `widgets.md` contains headings: DataTable, Tree, Select, Input, OptionList

OK Coverage check passes - routing table says:
| Widgets - DataTable, Tree, OptionList, Select, Input | widgets.md |

NO Coverage check fails - routing table says:
| Widgets                                              | widgets.md |
(agent searching for "DataTable" won't find the right file)

OK Accuracy check passes - grep widgets.md for "DataTable" -> found
NO Accuracy check fails - routing table lists "TreeView" but file only contains "Tree"
```

Tier 2 example (upstream source column):

```markdown
Routing table row:
| Core API - Client, Session, request(), stream() | api-reference.md | docs/api/full-reference.md  |

Upstream file `docs/api/full-reference.md` contains headings: Client, Session, request, stream, Connection, Retry

NO Tier 2 coverage check fails - topic lists 4 of 6 symbols; missing Connection and Retry -> add them to topic description
NO Tier 2 accuracy check fails - topic lists "stream()" but upstream file heading is "Streaming" -> fix topic or confirm alias

Fixed topic: Core API - Client, Session, request(), Streaming, Connection, Retry
```

**Presence gate:** Before checking coverage and accuracy, first confirm a tier 2 table exists at all. Run `find <upstream-dirs> -name '*.md'` to list all upstream files. If any exist but the routing table has no tier 2 (upstream source) column, the skill is incomplete - add the column and populate it before proceeding with coverage/accuracy checks.

## SKILL.md Structure

**Frontmatter (YAML):**
- Only two fields supported: `name` and `description` (custom fields are stripped by Claude Code)
- Caps are PER FIELD, not combined: `name` 64 characters, `description` 1024
- **Over the cap is not refused, it is silently truncated.** No warning, no error, and nothing in the
  file to see: the SKILL.md still reads perfectly while the injected available-skills listing cuts
  the description mid-word and ends it with an ellipsis, so every trigger past the cut is invisible
  to the router. The skill then behaves as if its newest triggers were never written - documented,
  tested, listed in its own table, and never suggested.
  - **Measure the field, do not eyeball it:** extract the frontmatter `description` and take `len()`.
    This repo's commit gate measures it too and fails over the cap, so the rule is mechanical rather
    than remembered.
  - **The observed cut falls LATER than 1024, not earlier.** A 1060-character description was
    delivered whole; a 2124-character one lost its last 597 characters. So nothing under the
    documented cap is at risk, and the reason to stay under it is that the real boundary is a
    harness detail that can move - not that your 900-character description is in danger. Do not
    probe for the knife; the 500-character target below is the margin worth aiming at.
  - **A bloated description is a REWRITE, not an append.** An appended trigger lands in the dead
    tail, and inserting one early only pushes a different one out.
  - To see where a live session actually cut, ask a running agent to quote its own available-skills
    entry for that skill verbatim, and diff it against the field in the file. The listing is
    injected into the system prompt, so it cannot be read off disk.
- `name`: Use letters, numbers, and hyphens only (no parentheses, special chars)
- `description`: Third-person, describes ONLY when to use (NOT what it does)
  - Start with "Use when..." to focus on triggering conditions
  - Include specific symptoms, situations, and contexts
  - **NEVER summarize the skill's process or workflow** (see CSO section for why)
  - Keep under 500 characters if possible

```markdown
---
name: skill-name-with-hyphens
description: Use when [specific triggering conditions and symptoms]
---

# Skill Name

## Overview
What is this? Core principle in 1-2 sentences.

## When to Use
[Small inline flowchart IF decision non-obvious]

Bullet list with SYMPTOMS and use cases
When NOT to use

## Core Pattern (for techniques/patterns)
Before/after code comparison

## Quick Reference
Table or bullets for scanning common operations

## Implementation
Inline code for simple patterns
Link to file for heavy reference or reusable tools

## Common Mistakes
What goes wrong + fixes

## Real-World Impact (optional)
Concrete results
```


## Claude Search Optimization (CSO)

**Critical for discovery:** Future Claude needs to FIND your skill

### 1. Rich Description Field

**Purpose:** Claude reads description to decide which skills to load for a given task. Make it answer: "Should I read this skill right now?"

**Format:** Start with "Use when..." to focus on triggering conditions

**CRITICAL: Description = When to Use, NOT What the Skill Does**

The description should ONLY describe triggering conditions. Do NOT summarize the skill's process or workflow in the description.

**Why this matters:** Testing revealed that when a description summarizes the skill's workflow, Claude may follow the description instead of reading the full skill content. A description saying "code review between tasks" caused Claude to do ONE review, even though the skill's flowchart clearly showed TWO reviews (spec compliance then code quality).

When the description was changed to just "Use when executing implementation plans with independent tasks" (no workflow summary), Claude correctly read the flowchart and followed the two-stage review process.

**The trap:** Descriptions that summarize workflow create a shortcut Claude will take. The skill body becomes documentation Claude skips.

```yaml
# NO BAD: Summarizes workflow - Claude may follow this instead of reading skill
description: Use when executing plans - dispatches subagent per task with code review between tasks

# NO BAD: Too much process detail
description: Use for TDD - write test first, watch it fail, write minimal code, refactor

# OK GOOD: Just triggering conditions, no workflow summary
description: Use when executing implementation plans with independent tasks in the current session

# OK GOOD: Triggering conditions only
description: Use when implementing any feature or bugfix, before writing implementation code
```

**Content:**
- Use concrete triggers, symptoms, and situations that signal this skill applies
- Describe the *problem* (race conditions, inconsistent behavior) not *language-specific symptoms* (setTimeout, sleep)
- Keep triggers technology-agnostic unless the skill itself is technology-specific
- If skill is technology-specific, make that explicit in the trigger
- Write in third person (injected into system prompt)
- **NEVER summarize the skill's process or workflow**

```yaml
# NO BAD: Too abstract, vague, doesn't include when to use
description: For async testing

# NO BAD: First person
description: I can help you with async tests when they're flaky

# NO BAD: Mentions technology but skill isn't specific to it
description: Use when tests use setTimeout/sleep and are flaky

# OK GOOD: Starts with "Use when", describes problem, no workflow
description: Use when tests have race conditions, timing dependencies, or pass/fail inconsistently

# OK GOOD: Technology-specific skill with explicit trigger
description: Use when using React Router and handling authentication redirects
```

### 2. Keyword Coverage

Use words Claude would search for:
- Error messages: "Hook timed out", "ENOTEMPTY", "race condition"
- Symptoms: "flaky", "hanging", "zombie", "pollution"
- Synonyms: "timeout/hang/freeze", "cleanup/teardown/afterEach"
- Tools: Actual commands, library names, file types

### 3. Descriptive Naming

**Use active voice, verb-first:**
- OK `creating-skills` not `skill-creation`
- OK `condition-based-waiting` not `async-test-helpers`

**If the target marketplace defines a naming registry, follow it.** Some marketplaces enforce a
category-prefix scheme (e.g. `<category>-[<sub>-]<name>` like `coding-python-...`, `marketing-...`)
via a registry file and a contribution gate. When contributing there, pick the category per that
repo's rules and keep the verb-first/descriptive style for the `<name>` part. The scheme itself is
repo-specific - see that repo's `CONTRIBUTING.md` (for this marketplace, `skill-taxonomy.json`).

### 4. Token Efficiency (Critical)

**Problem:** getting-started and frequently-referenced skills load into EVERY conversation. Every token counts.

**Target word counts (tiered by skill type):**
- getting-started workflows: <150 words each
- Frequently-loaded / process skills: <200 words total
- Other process/technique skills: <500 words (still be concise)
- Reference/hub skills (routing tables + supporting files): MAY exceed 500 words, but keep the SKILL.md lean - push detail into reference files and let the body stay an index. This skill-writer is itself a hub skill and legitimately runs long.

**Techniques:**

**Move details to tool help:**
```bash
# NO BAD: Document all flags in SKILL.md
search-conversations supports --text, --both, --after DATE, --before DATE, --limit N

# OK GOOD: Reference --help
search-conversations supports multiple modes and filters. Run --help for details.
```

**Use cross-references:**
```markdown
# NO BAD: Repeat workflow details
When searching, dispatch subagent with template...
[20 lines of repeated instructions]

# OK GOOD: Reference other skill
Always use subagents (50-100x context savings). REQUIRED: Use [other-skill-name] for workflow.
```

**Compress examples:**
```markdown
# NO BAD: Verbose example (42 words)
your human partner: "How did we handle authentication errors in React Router before?"
You: I'll search past conversations for React Router authentication patterns.
[Dispatch subagent with search query: "React Router authentication error handling 401"]

# OK GOOD: Minimal example (20 words)
Partner: "How did we handle auth errors in React Router?"
You: Searching...
[Dispatch subagent -> synthesis]
```

**Eliminate redundancy:**
- Don't repeat what's in cross-referenced skills
- Don't explain what's obvious from command
- Don't include multiple examples of same pattern

**Verification:**
```bash
wc -w skills/path/SKILL.md
# getting-started workflows: aim for <150 each
# Other frequently-loaded: aim for <200 total
```

**Name by what you DO or core insight:**
- OK `condition-based-waiting` > `async-test-helpers`
- OK `using-skills` not `skill-usage`
- OK `flatten-with-flags` > `data-structure-refactoring`
- OK `root-cause-tracing` > `debugging-techniques`

**Gerunds (-ing) work well for processes:**
- `creating-skills`, `testing-skills`, `debugging-with-logs`
- Active, describes the action you're taking

### 5. Cross-Referencing Other Skills

**When writing documentation that references other skills:**

Use skill name only, with explicit requirement markers:
- OK Good: `**REQUIRED SUB-SKILL:** Use bitranox:process-test-driven-development`
- OK Good: `**REQUIRED BACKGROUND:** You MUST understand bitranox:process-debug-systematic`
- NO Bad: `See skills/testing/test-driven-development` (unclear if required)
- NO Bad: `@skills/testing/test-driven-development/SKILL.md` (force-loads, burns context)

**Why no @ links:** `@` syntax force-loads files immediately, consuming 200k+ context before you need them.

**Referencing a SCRIPT is the opposite of referencing a skill: state the home path.** A skill name
resolves through the skill system; a script filename resolves through nothing. A bare
`helper.py --check` in prose is unrunnable for a reader whose context lacks the owning skill's base
directory, and it reads as NOT SHIPPED to anyone auditing the plugin (they search the path-qualified
locations, e.g. `hooks/`, and conclude the file is missing).

- OK Good: `` `reconcile_memory_index.py --check` (home: `<plugin>/skills/meta-self-improve/`, launch via `hooks/run-python.sh`) ``
- NO Bad: `` run `reconcile_memory_index.py --check` `` (bare filename - where? how?)

Rules: state the home (`skills/<owner>/<script>`) and the launch shim at the point of use; when a
family of skills shares a core reference file, single-source the homes there (a "Script homes"
section) and let the members cite it; a script referenced from OUTSIDE its owning skill is the case
that always needs the path - within its own skill's SKILL.md the announced base directory resolves a
bare name.

**Referencing external DOCS must be INSTALL-REACHABLE (the same rule, applied to docs).** A skill
teaching a tool or library usually points at that project's fuller docs (its `README`, a `docs/`
folder). But the skill ships ALONE - only its own directory - and a package's `README`/`docs/` are
usually STRIPPED from the installed wheel (the wheel ships `src/` + `py.typed`, not docs). So a bare
`see docs/api.md` or "the package's README" is a DANGLING pointer on any machine that installed the
skill: it resolves to nothing. This shipped for real in more than one skill. Every reference you send
a reader to must resolve FROM AN INSTALL, by one of:

- **Install-local discovery FIRST - the installed code's own truth (zero rot, no network, always the
  reader's version).** For CLI options, the skill must direct the reader/LLM to RUN `<tool> --help`
  (and `<tool> <subcommand> --help`) instead of freezing a flag list that goes stale; for the API,
  `python -c "import mod; help(mod)"` / docstrings. When a command's flags or an API signature are in
  question, running `--help`/`help()` beats reading any doc - it is the authoritative, always-current
  source. Author every tool/library skill this way: do NOT enumerate every flag in the SKILL.md when
  `--help` covers it - point the reader at `--help` and keep the body to the judgment `--help` cannot
  give.
- **For narrative docs not in `--help`, link the LATEST docs (the default branch).** Tools here are
  installed/updated via `uv`/`uvx`, so the reader is normally on the latest release and latest docs
  match: `https://github.com/<owner>/<repo>/blob/<default-branch>/docs/x.md` (use the repo's real
  default branch - `master` or `main`; `blob/HEAD/...` is branch-name-agnostic and survives a
  default-branch rename). The one fragility: a deep file link 404s if that file is later renamed or
  moved - mitigate by linking the `docs/` dir or repo root when the file set is unstable. Do NOT
  hard-code a version tag as the default - it silently goes STALE as the tool moves past it. Use a
  tag-anchored URL plus a "swap `<tag>` for your installed version" hint ONLY when the skill is pinned
  to one library version or version drift would actively mislead.
- **A DISTILLED copy bundled in the skill dir** (it then ships with the skill) - use when offline use
  matters or the skill is pinned to one library version; stamp it with the source URL + version so it
  can be refreshed, and keep it distilled so drift stays bounded.
- **NEVER a bare package-local path** (`docs/api.md`, "its `docs/`") that is neither shipped in the
  skill dir nor a URL.

First make the SKILL.md SELF-SUFFICIENT for the common path, so any external reference is for the
deep minority of cases only: then a rotted link or a stale bundle degrades gracefully instead of
breaking the skill. Neither a URL (network + link-rot) nor a bundle (drift) is free - the
self-sufficient body is what makes either safe.

Verify before shipping: `grep -nE '(docs/|README|see [^ ]*\.md|its .docs.)' SKILL.md | grep -v http`
should surface only references that (a) ship as files in the skill dir (`ls` them) or (b) are
install-local `--help`/`help()`. Any remaining bare package-local path is the bug.

## Flowchart Usage

```dot
digraph when_flowchart {
    "Need to show information?" [shape=diamond];
    "Decision where I might go wrong?" [shape=diamond];
    "Use markdown" [shape=box];
    "Small inline flowchart" [shape=box];

    "Need to show information?" -> "Decision where I might go wrong?" [label="yes"];
    "Decision where I might go wrong?" -> "Small inline flowchart" [label="yes"];
    "Decision where I might go wrong?" -> "Use markdown" [label="no"];
}
```

**Use flowcharts ONLY for:**
- Non-obvious decision points
- Process loops where you might stop too early
- "When to use A vs B" decisions

**Never use flowcharts for:**
- Reference material -> Tables, lists
- Code examples -> Markdown blocks
- Linear instructions -> Numbered lists
- Labels without semantic meaning (step1, helper2)

**REFERENCE:** See graphviz-conventions.dot for graphviz style rules.

**Visualizing for your human partner:** Use `render-graphs.js` in this directory to render a skill's flowcharts to SVG:
```bash
./render-graphs.js ../some-skill           # Each diagram separately
./render-graphs.js ../some-skill --combine # All diagrams in one SVG
```
It exits 1 when any diagram fails to render, after an `N rendered, M failed` line. `--combine`
merges only `digraph` blocks and refuses, with exit 1, a block of bare statements with no wrapper,
an undirected `graph` block, and two blocks that share a node id (dot node names are global, so a
`start` in both would become one node with the edges of both). Render those without `--combine`:
separate mode renders every `digraph` block, shared node ids included.

## Code Examples

**One excellent example beats many mediocre ones**

Choose most relevant language:
- Testing techniques -> TypeScript/JavaScript
- System debugging -> Shell/Python
- Data processing -> Python

**Good example:**
- Complete and runnable
- Well-commented explaining WHY
- From real scenario
- Shows pattern clearly
- Ready to adapt (not generic template)

**Don't:**
- Implement in 5+ languages
- Create fill-in-the-blank templates
- Write contrived examples

You're good at porting - one great example is enough.

### An example from a real scenario is not a real address

"From a real scenario" means the SHAPE is real, never that the values are. A skill ships to every
install and to a public repo, so an address, MAC, hostname, user or path copied out of the machine
you developed on is published with it - and it reads as authoritative, so readers paste it back.
Substitute the reserved documentation values, which look real and name nothing:

| For               | Use                                                 | Reserved by |
|-------------------|-----------------------------------------------------|-------------|
| IPv4              | `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24` | RFC 5737    |
| IPv6              | `2001:db8::/32`                                     | RFC 3849    |
| MAC               | `00:00:5e:00:53:00` .. `:ff`                        | RFC 7042    |
| IPv6 link-local   | the EUI-64 form of one, `fe80::200:5eff:fe00:53af`  | (derived)   |
| Hostname / domain | `example.com`, `host.example`                       | RFC 2606    |
| Path              | `/path/to/project`, `~/project`                     | -           |

Vendored upstream documentation keeps its own examples - rewriting them would make the copy
disagree with its source. This rule is about values YOU add.

### Write the skill and its artifacts in the present tense, not as a story

A skill says what is true now. A review artifact says what was verified. Neither is a session log,
and the reader has neither your transcript nor your machine.

**Keep out of both:** what the operator instructed, permitted or changed their mind about; which
tool or agent you reached for and when; scratch and temp paths; how the skill looked before this
edit; who caught what. **Keep in the artifact:** the claim tested, how it was tested, and the
outcome - a verbatim line of agent output earns its place when it IS the evidence, a paragraph of
narrative around it does not.

The trap is that provenance feels like rigour while you are writing it, because it is what you
just lived through. Test it by reading a line back and asking what a reader DOES differently
knowing it. "The operator lifted a restriction mid-session" changes nothing for anyone; "a
subagent on the old text wrote the call the library refuses" is the test result.

<Bad>
```markdown
- [x] Subagent scenarios run, both arms, after the operator lifted the standing no-dispatch
      instruction mid-session. Verified with a script at /tmp/scratch-9f2/verify.py on the dev
      box, whose LAN address is 192.0.2.139.
```
</Bad>

<Good>
```markdown
- [x] RED: a subagent given the pre-change text wrote `ping(entry.ip)`, which the library refuses.
      GREEN: given the new text, `ping(entry.scoped)`.
- [x] Every code block executed against the real library, not reviewed.
```
</Good>

## File Organization

### Self-Contained Skill
```
defense-in-depth/
  SKILL.md    # Everything inline
```
When: All content fits, no heavy reference needed

### Skill with Reusable Tool
```
condition-based-waiting/
  SKILL.md    # Overview + patterns
  example.ts  # Working helpers to adapt
```
When: Tool is reusable code, not just narrative

### Skill with Heavy Reference
```
pptx/
  SKILL.md       # Overview + workflows
  pptxgenjs.md   # 600 lines API reference
  ooxml.md       # 500 lines XML structure
  scripts/       # Executable tools
```
When: Reference material too large for inline

### Bundled scripts and hooks: keep them cross-platform

Any script you ship inside a skill or as a hook (a `.sh`, `.py`, `.js`, scripts in
`scripts/`, or a hook command) runs on a user's machine that may be Windows. Author it
so Windows does not silently break it:

- **Write the logic in Python, not bash or `jq`.** A script's or hook's real work belongs in a
  typed, testable language (Python with the standard library is the default); use bash only as a
  thin launcher shim. Bash/`jq` pipelines are hard to unit-test, behave differently across OSes,
  and are the usual source of silent Windows breakage.
- **Line endings: LF only.** Commit a `.gitattributes` that pins `*.sh text eol=lf`
  (and `*.py`/`*.json` for stable hashing). A CRLF `.sh` makes Git Bash on Windows fail
  with "cannot execute: required file not found" or `$'\r': command not found`, and a
  Stop/PreToolUse hook that exits cleanly on failure then disappears with no error.
- **Force UTF-8 in launched interpreters.** A non-UTF-8 Windows locale (e.g. German
  cp1252) corrupts IO. For Python set `PYTHONUTF8=1` and `PYTHONIOENCODING=utf-8`
  before exec; read/write files with explicit `encoding="utf-8"`.
- **Do not assume an interpreter name resolves.** On Windows `python3` is usually the
  Microsoft Store stub (exits non-zero in a subprocess), `python` may be Python 2, and
  `py -3` is Windows-only. Launch Python through a small bash shim that probes
  `python3 -> python -> py -3` and converts the script's own path with `cygpath` when present
  (only that path: the script's arguments are its own business).
  The plugin's `hooks/run-python.sh` is the working reference; reuse it. It is strict by default:
  when it cannot run the script (missing file, no Python 3, an unexpected shell) it exits 3, so
  a hook registration must pass `--hook` as the FIRST shim argument, before the script path, to
  get the exit-0 contract below. Copy the exact command form from any entry in the plugin's
  `hooks/hooks.json`; a skill step that launches a script never passes `--hook`.
- **Git Bash on Windows.** Write hooks for Git Bash (Git for Windows). `run-python.sh` also
  runs them under Cygwin, best-effort and untested there. WSL reports `Linux` to `uname -s`, so
  nothing can tell it apart from Linux; it runs as Linux and resolves a Linux interpreter. Guard
  `uname -s` and skip loudly to stderr under any other shell.
- **A hook must never wedge a turn.** Every failure path exits 0; degrade silently
  (with a one-line stderr note) rather than erroring. Through `run-python.sh` that holds only with
  `--hook`; a CLI or gate call leaves it off, so a mistyped path there fails loudly.
- **Set the executable bit in git, not the working tree.** A file run directly (`./script`, or a
  hook invoked by path with a `#!` shebang) needs its exec bit recorded in git. A working-tree
  `chmod +x` does NOT persist when `core.fileMode = false`; set it in the index with
  `git update-index --chmod=+x <file>` and verify with `git ls-files -s` (mode `100755`).
  Interpreter-run files with no shebang (a `.py`/`.js` run as `python x.py`) are never `./`-run,
  so they stay `100644`.
- **Match signals to their source.** A gate that scans transcript text for a trigger
  must run intent/correction patterns against the *user* role and self-admission
  patterns against the *assistant* role; matching both over concatenated text fires on
  ordinary assistant phrasing.
- **Do real work in this preference order; drop a level only when the one above cannot do it:**
  1. **A modern, well-maintained library for the job.** Consult the
     **`bitranox:coding-python-use-modern-libraries`** skill and use its pick (httpx2 for HTTP, orjson for
     JSON, rtoml for TOML, ruamel.yaml for YAML, and so on). Do not fall back to dated
     defaults (`urllib`/`requests`, stdlib `json`) when a clearly better library exists.
     Declare deps via `uv` so they land in an isolated, reproducible environment, never the
     user's system Python: a CLI tool via `uvx <tool>`, or a script with PEP-723 inline
     metadata run by `uv run script.py` (uv fetches the deps on run, no prompt).
     - **Libraries on the `bitranox:coding-python-use-modern-libraries` list are pre-approved** - use them and
       let `uv` fetch them; do NOT ask first.
     - For a library NOT on that list, first vet it: trustworthy (reputable maintainer or
       community, not a typo-squat), common (widely adopted), and modern (actively maintained,
       current releases). If it passes, propose adding it to the `bitranox:coding-python-use-modern-libraries`
       list so the curated set grows. Each new entry needs: a proper one-line description of
       what it is for, the older library/libraries it replaces, and why it is better. Then use
       it. If it fails vetting, prefer a curated alternative or stdlib. Either way surface the
       choice to the user (name it, say why, note it is new to the list).
     - `uv` itself is the one prerequisite: if it is not installed, STOP and ask permission to
       install it (explaining what for) rather than installing it silently.
  2. **Standard library when no third-party library is warranted** (small glue, no hot path,
     or the stdlib module is genuinely the best tool: `pathlib`, `dataclasses`, `zoneinfo`,
     `re`, `subprocess`). The goal is the best tool, not the most dependencies.
  3. **An external command (last resort).** Only when neither of the above fits. Shelling out
     is the least portable choice because the program and its flags differ per OS:
     - **It must EXIST on every target OS.** Windows usually has no `grep`, `sed`, `awk`,
       `curl`, `jq`, `timeout`, or `make`. Probe with `shutil.which(prog)` and fail with a
       clear message (or fall back to stdlib) instead of crashing with "file not found".
     - **Its flags must be valid for THAT OS's build.** The same tool name is often a
       different program with different options (GNU vs BSD/macOS `sed`/`date`/`stat`; the
       Windows port of a tool; PowerShell vs `cmd.exe` builtins). Do not assume a Linux flag
       works elsewhere; stick to the common documented subset or branch per platform.
     - **Pass an argv list, never a shell string.** Use `subprocess.run([...])`, not
       `shell=True`. A shell string (pipes, `||`, `$?`, redirects, `case`) is POSIX-only,
       breaks under Windows `cmd.exe`, and is a command-injection risk. Decide success from
       the return code plus an output-file or output-text check in your own code, not shell
       glue. If you must accept a user-supplied command template, parse it once with
       `shlex.split` and substitute placeholders into the list elements (no shell).

### Ship tests for every script (and they MUST pass)

A skill that bundles Python scripts MUST also ship a `tests/` directory with pytest tests, and
those tests MUST pass before the skill is considered done. This is not optional.

- **Cover every important/main function** - each script's public/main functions need a test
  with decent coverage (happy path plus the key edge cases), not just an import smoke test.
- **Tests must pass.** Run them (`uv run --with pytest pytest tests/` or the project's runner)
  and confirm green. A skill with failing or missing tests does not ship.
- **Test by behaviour with real inputs:** build a tiny fixture project/data, run the function,
  assert on the actual output (e.g. the analyzer flags the planted case and skips the
  decorated/compiled one). Writing the tests routinely surfaces real bugs (argv ignored,
  order-sensitive regex, wrong thresholds) - fix the script, do not weaken the test.
- **Keep scripts import-safe** so they can be tested: all run-time work behind
  `if __name__ == "__main__":`, never at module top level (a script that executes on import
  cannot be unit-tested and will run side effects when imported).
- **A bundled script must IMPORT in a BARE environment.** The contribution gate (and any plain
  `pytest`) imports your test modules with the interpreter as-is - it does NOT provision a script's
  PEP 723 `dependencies`; only `uv run <script>` does. So a hard top-level `import orjson` collects
  fine under `uv run` yet fails the gate with `ModuleNotFoundError` on a clean runner. Guard every
  third-party import with a stdlib fallback (`try: import orjson ... except ModuleNotFoundError:
  import json as ...`) - keep the fast path, import anywhere. VERIFY in a fresh venv that has ONLY
  pytest, not your deps (`uv venv x && uv pip install --python x pytest && x/bin/python -m pytest`);
  your own machine having the dep installed is exactly what hides this until CI.
- A `tests/conftest.py` that puts the skill dir on `sys.path` lets tests `import <script>` by
  module name.

### Universal rules vs. marketplace plumbing

Everything in this skill (CSO/description craft, structure, flowcharts, cross-platform scripts,
tests, library choices) applies to **any** skill you author - a standalone skill for your own
machine just as much as one you contribute to a marketplace. Follow it either way.

A skill you contribute to a **specific plugin marketplace** has EXTRA rules layered on top, and
those are repo-specific, so they live in that repo's `CONTRIBUTING.md` (and `CLAUDE.md`), not
here. Typically: a release/versioning policy, a contribution gate (pre-commit/CI check), an
index or registry to update when you add a skill, and a git-history policy. Read that repo's
`CONTRIBUTING.md` before contributing.

When you discover a NEW authoring rule: if it helps any skill author (a portability gotcha, a
testing habit, a structural pattern), it belongs **here** in `skill-writer`; if it only matters
for one repo's release machinery, it belongs in **that repo's** `CONTRIBUTING.md`.

### Persisting durable state: use the curated store, not a hand-rolled backend

If the skill you author persists durable facts, learnings, preferences, or state across sessions,
use the bitranox memory backend rather than inventing one - and never route learnings through a
memory MCP as their home. The model is a per-altitude POINTER BLOCK plus CENTRAL BODIES: each
level's `CLAUDE.local.md` carries a managed fenced block of one-line pointers
(`- [Title](mem:<slug>) - hook`, the hook TRIGGER-FIRST: "When <situation>, <directive>") that
loads as always-in-context cascade text, and every fact body lives centrally at
`<anchor>/.claude-memory/facts/<slug>.md` (the anchor = the knowledge tree's top directory),
framed as a native memory entry (frontmatter, then **Why:** / **How to apply:**), read on demand
via the retrieval recipe the block itself carries. Write ONLY through the engine -
`hooks/memory_engine.py add ...` launched via `hooks/run-python.sh` (it upserts by slug, enforces
tree-unique slugs and the 500-char hook cap, frames the body, locks, stays mtime-neutral); never
hand-edit the block or a body (a PreToolUse guard denies it).

A memory MCP (`basic-memory`) is NOT a backend/home - only an OPTIONAL, read-only full-text+graph
SEARCH index OVER those local files, to sharpen cross-project recall; when absent, recall falls back
to a keyword scan (never a hard dependency). Wire one only through the `update-config` skill. The
full storage spec (tiers, altitudes, trees, capture flow) lives in `bitranox:meta-self-improve` -
cross-reference it rather than restating it.

## The Iron Law (Same as TDD)

```
NO SKILL WITHOUT A FAILING TEST FIRST
```

This applies to NEW skills AND EDITS to existing skills.

Write skill before testing? Delete it. Start over.
Edit skill without testing? Same violation.

**No exceptions:**
- Not for "simple additions"
- Not for "just adding a section"
- Not for "documentation updates"
- Don't keep untested changes as "reference"
- Don't "adapt" while running tests
- Delete means delete

Every item on that list is a JUDGEMENT - "this one is small enough to skip". The list forbids the
judgement, not the existence of a carve-out, and there is exactly one carve-out, decided by a proof
you can run rather than by how the change feels:

**One named exception, defined by a mechanical proof rather than by judgement: a SYNTAX-ONLY
FRONT-MATTER REPAIR.** A change that makes the front matter parse while altering nothing a reader
or the router sees is tested by a parser and the derived artifacts, not by a pressure scenario.
There is no behaviour to watch an agent get wrong, so a RED run has nothing to fail on - the RED
step exists to show what agents naturally do before there is teaching content, and a syntax repair
adds none.

It applies ONLY when all three hold, and the review artifact must state each one - three
conditions that were true but never written down do not count, because the artifact is
where the proof lives:

- a real parser REJECTS the front matter before the change and ACCEPTS it after;
- the derived trigger artifact regenerates BYTE-IDENTICAL, so no routing keyword moved;
- the diff touches the front matter only - no body line, no `name:`, no trigger added or removed.

Fail any one of the three and the Iron Law applies unchanged. The byte-identical regeneration IS
the test; "the change is obviously inert" is not, and neither is a unit test you wrote yourself.
Rewording a description to say something DIFFERENT is never this exception, however small the edit
looks - that changes what the router matches, which is behaviour.

**REQUIRED BACKGROUND:** The bitranox:process-test-driven-development skill explains why this matters. Same principles apply to documentation.

## Testing All Skill Types

Different skill types need different test approaches:

### Discipline-Enforcing Skills (rules/requirements)

**Examples:** TDD, verification-before-completion, designing-before-coding

**Test with:**
- Academic questions: Do they understand the rules?
- Pressure scenarios: Do they comply under stress?
- Multiple pressures combined: time + sunk cost + exhaustion
- Identify rationalizations and add explicit counters

**Success criteria:** Agent follows rule under maximum pressure

### Technique Skills (how-to guides)

**Examples:** condition-based-waiting, root-cause-tracing, defensive-programming

**Test with:**
- Application scenarios: Can they apply the technique correctly?
- Variation scenarios: Do they handle edge cases?
- Missing information tests: Do instructions have gaps?

**Success criteria:** Agent successfully applies technique to new scenario

### Pattern Skills (mental models)

**Examples:** reducing-complexity, information-hiding concepts

**Test with:**
- Recognition scenarios: Do they recognize when pattern applies?
- Application scenarios: Can they use the mental model?
- Counter-examples: Do they know when NOT to apply?

**Success criteria:** Agent correctly identifies when/how to apply pattern

### Reference Skills (documentation/APIs)

**Examples:** API documentation, command references, library guides

**Test with:**
- Retrieval scenarios: Can they find the right information?
- Application scenarios: Can they use what they found correctly?
- Gap testing: Are common use cases covered?

**Success criteria:** Agent finds and correctly applies reference information

## Common Rationalizations for Skipping Testing

| Excuse                         | Reality                                                          |
|--------------------------------|------------------------------------------------------------------|
| "Skill is obviously clear"     | Clear to you  is not  clear to other agents. Test it.            |
| "It's just a reference"        | References can have gaps, unclear sections. Test retrieval.      |
| "Testing is overkill"          | Untested skills have issues. Always. 15 min testing saves hours. |
| "I'll test if problems emerge" | Problems = agents can't use skill. Test BEFORE deploying.        |
| "Too tedious to test"          | Testing is less tedious than debugging bad skill in production.  |
| "I'm confident it's good"      | Overconfidence guarantees issues. Test anyway.                   |
| "Academic review is enough"    | Reading  is not  using. Test application scenarios.              |
| "No time to test"              | Deploying untested skill wastes more time fixing it later.       |

**All of these mean: Test before deploying. No exceptions.**

## Bulletproofing Skills Against Rationalization

Skills that enforce discipline (like TDD) need to resist rationalization. Agents are smart and will find loopholes when under pressure.

**Psychology note:** Understanding WHY persuasion techniques work helps you apply them systematically. See persuasion-principles.md for research foundation (Cialdini, 2021; Meincke et al., 2025) on authority, commitment, scarcity, social proof, and unity principles.

### Close Every Loophole Explicitly

Don't just state the rule - forbid specific workarounds:

<Bad>
```markdown
Write code before test? Delete it.
```
</Bad>

<Good>
```markdown
Write code before test? Delete it. Start over.

**No exceptions:**
- Don't keep it as "reference"
- Don't "adapt" it while writing tests
- Don't look at it
- Delete means delete
```
</Good>

### Address "Spirit vs Letter" Arguments

Add foundational principle early:

```markdown
**Violating the letter of the rules is violating the spirit of the rules.**
```

This cuts off entire class of "I'm following the spirit" rationalizations.

### Build Rationalization Table

Capture rationalizations from baseline testing (see Testing section below). Every excuse agents make goes in the table:

```markdown
| Excuse                           | Reality                                                                 |
|----------------------------------|-------------------------------------------------------------------------|
| "Too simple to test"             | Simple code breaks. Test takes 30 seconds.                              |
| "I'll test after"                | Tests passing immediately prove nothing.                                |
| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
```

### Create Red Flags List

Make it easy for agents to self-check when rationalizing:

```markdown
## Red Flags - STOP and Start Over

- Code before test
- "I already manually tested it"
- "Tests after achieve the same purpose"
- "It's about spirit not ritual"
- "This is different because..."

**All of these mean: Delete code. Start over with TDD.**
```

### Update CSO for Violation Symptoms

Add to description: symptoms of when you're ABOUT to violate the rule:

```yaml
description: use when implementing any feature or bugfix, before writing implementation code
```

## Planning Before You Start

**Step 0 - issue the session receipt (FIRST, before anything else):** run
`bash <plugin>/hooks/run-python.sh <plugin>/hooks/skill_receipt.py start meta-skill-writer`.
The skill-edit guard denies SKILL.md edits without a fresh receipt - holding one proves this
procedure was ENTERED, not merely listed. A marketplace repo may additionally require a committed
review artifact (a `.skillwriter/checklist-<date>.md` next to the SKILL.md, all boxes checked)
co-changed with any SKILL.md change - its commit gate enforces that; see the repo's CONTRIBUTING.

**Before writing any skill, plan the work.** Use your task/todo tooling (e.g. TodoWrite) to build a task list, then execute it step by step. This prevents skipping steps and makes progress visible.

### Survey prior art first

Before planning a new skill, survey what already exists across the public Claude skill/plugin catalogs. The goal is not to avoid a duplicate but to LEARN from prior art: find the skills nearest your intended domain and mine them for ideas, useful hints, and proven procedures, then fold the good ones into your design.

Catalogs worth reading (2026):

- `github.com/anthropics/skills` - official Anthropic Agent Skills (canonical reference set; also a plugin marketplace)
- `github.com/anthropics/claude-plugins-official` - official plugin directory
- `github.com/rohitg00/awesome-claude-code-toolkit` - large plugins + skills toolkit
- `github.com/ComposioHQ/awesome-claude-plugins` and `github.com/ComposioHQ/awesome-claude-skills`
- `github.com/hesreallyhim/awesome-claude-code`, `github.com/jqueryscript/awesome-claude-code` - broad community lists
- aggregators: `awesome-skills.com`, `awesomeclaude.ai`

### Step 0: Create a Plan

1. **Identify skill type** - Is this a discipline skill, technique, pattern, or reference? (See "Skill Types" above.) This determines the test approach.
2. **Choose test approach** - Discipline skills need pressure scenarios with 3+ combined pressures. Technique skills need application scenarios. Reference skills need retrieval scenarios. (See "Testing All Skill Types" below.)
3. **List pressure scenarios** - Draft 2-3 scenario descriptions before writing anything.
4. **Estimate scope** - Self-contained SKILL.md or hub with supporting files?
5. **Create task list** - Use your task/todo tooling (e.g. TodoWrite) with one task per phase:

```
TaskCreate: "RED - Write and run baseline pressure scenarios"
TaskCreate: "GREEN - Write minimal SKILL.md addressing baseline failures"
TaskCreate: "REFACTOR - Close loopholes from GREEN testing"
TaskCreate: "Deploy - Commit, push, verify discoverability"
```

### Using Agent Teams for Skill Creation

For complex skills, if you have agent-team tooling available, you can parallelize work:

```
TeamCreate: team_name="skill-creation"

Task (subagent_type="general-purpose", team_name="skill-creation"):
  "Run 3 baseline pressure scenarios WITHOUT the skill, document rationalizations"

Task (subagent_type="general-purpose", team_name="skill-creation"):
  "Draft SKILL.md structure: frontmatter, overview, core pattern sections"
```

**Parallelizable work:**
- Multiple pressure scenarios can run as separate subagents simultaneously
- Routing table coverage and accuracy checks can run in parallel per file
- Different test types (pressure, application, retrieval) can run concurrently

**Sequential work (must wait for previous step):**
- GREEN phase depends on RED phase results (you need baseline failures to address)
- REFACTOR depends on GREEN test results (you need new rationalizations to counter)
- Deployment depends on all tests passing

## RED-GREEN-REFACTOR for Skills

Follow the TDD cycle:

### RED: Write Failing Test (Baseline)

Run pressure scenario with subagent WITHOUT the skill. Document exact behavior:
- What choices did they make?
- What rationalizations did they use (verbatim)?
- Which pressures triggered violations?

**How to dispatch a baseline test:**

```
Task tool call:
  subagent_type: "general-purpose"
  model: "sonnet"   # pin a tier; never inherit the session model (often opus). See note below.
  prompt: |
    IMPORTANT: This is a real scenario. Choose and act.
    [Your pressure scenario here]

    Choose A, B, or C. Be honest.

  # Do NOT include the skill in the prompt - this is the baseline test.
  # The subagent must work without skill guidance to reveal natural behavior.
```

**If a skill you author dispatches subagents, it MUST pin a `model` tier per dispatch** (haiku /
sonnet / opus by task - see "Concrete tiers" in `bitranox:process-agents-subagent-driven-development`),
never inherit the session model. Default fan-out to `sonnet`; `opus` only for deep-reasoning roles.

**Design-time, first decide WHETHER the skill should dispatch to subagents at all.** Before settling on a
single-process tool, ask: does this skill do heavy, parallelizable, or context-bloating work - an audit or
scan over many files/pages/items, a multi-source sweep, or work whose raw output you only need a verdict
from? If so, fan that work across SUBAGENTS for context isolation (each returns only its findings, not the
raw output) and parallel speed (cross-ref `bitranox:process-agents-dispatching-parallel`), and bake the
fan-out into the skill's WORKFLOW rather than bolting it on later. Then pin the model tier per the rule
above. A skill that runs a worklist is the default candidate; a skill that only emits guidance is not.

This is "watch the test fail" - you must see what agents naturally do before writing the skill.

**A baseline that PASSES is a result to investigate, not a verdict.** Before concluding "no gap",
rule out all three ways it falsely passes: a CAPABLE model reasoned around the rigid rule (re-run
pinned to a weak, literal tier), the SCENARIO spelled the answer out (re-run realistically,
withholding the trap), or the ENVIRONMENT supplied it - the agent explored its way to the answer,
or injected context handed it over. That third one is silent and a scratch directory does not close
it; the tell is a quoted sentence you cannot find in the file you supplied. See
testing-skills-with-subagents.md, "Watch for baseline contamination", before trusting a pass.

**An inert probe agent type bounds TOOLS, not CONTEXT.** Stripping Bash, Read and Write stops an
agent exploring its way to the answer; it does not stop it already knowing. A dispatched subagent
still inherits the CLAUDE.md cascade and always-loaded memory index of the machine it runs on, so
when the lesson under test is ALREADY recorded there, the RED cannot fail honestly. Check that
before trusting it with `redcheck --corpus-cascade <dir>` from
`bitranox:process-test-driven-development`, which assembles that machine's cascade and memory fact
bodies itself and names the document that already teaches your scenario. Read a hit as strong
evidence, a clean result as only "not caught", and exit 3 as "the corpus was empty, nothing was
checked". If it is inherited, either make the coverage check against the skill FILE the
evidence (a text check of the artifact, immune to inherited context) or de-telegraph the
behavioural arm into a domain that text does not teach - and state in the review artifact which
route you took. A RED that does not flip is a reportable outcome, not a reason to escalate the
scenario until something fails.

### GREEN: Write Minimal Skill

Write skill that addresses those specific rationalizations. Don't add extra content for hypothetical cases.

> **CRITICAL: Test the version you are editing, not a stale installed copy.**
>
> When developing a skill in the current directory (e.g., `./my-skill/SKILL.md`), GREEN and REFACTOR tests MUST use that file - not whatever may be installed at `~/.claude/skills/`. Two approaches:
> 1. **Paste content into prompt** (subagent testing): Read the current `./SKILL.md` and paste its full content into the subagent prompt.
> 2. **Copy to project skills dir** (live-agent testing): `cp -r ./my-skill/ .claude/skills/my-skill/` - project-level skills take priority over user-space.

**How to dispatch a verification test:**

```
Task tool call:
  subagent_type: "general-purpose"
  prompt: |
    You have access to this skill:
    [Paste the full SKILL.md content here]

    IMPORTANT: This is a real scenario. Choose and act.
    [Same pressure scenario as baseline]

    Choose A, B, or C. Be honest.

  # Include the full skill content in the prompt so the subagent can follow it.
```

Agent should now comply. If agent still fails: skill is unclear or incomplete - revise and re-test.

**Require a `Skill gaps` section from every test subagent, RED and GREEN.** End each dispatch
prompt with:

```
End your reply with a section headed "Skill gaps": what you could not turn into a concrete
action, what you had to guess, and anywhere the text was silent or said two different things.
```

Compliance is the weakest thing a GREEN run tells you. An agent that followed the new text
successfully may have guessed at three other things on the way, and it will not mention them
unless asked - so a GREEN with nothing reported is indistinguishable from a GREEN that was never
asked. This matters most for technique and reference skills, whose dominant failure is not a
violated rule but a SILENT or SELF-CONTRADICTORY one.

Ask for the evidence the run produces, never its verdict. "No problems found" is cheap to assert
without looking, so a required success statement converts a silent miss into a confident
all-clear. Require the concrete artifact instead: the quoted line it acted on, the command it
actually ran, the question it could not answer from the text.

### REFACTOR: Close Loopholes

Agent found new rationalization? Add explicit counter. Re-test until bulletproof.

**GREEN's gaps list is REFACTOR input, not a pass.** A GREEN that closes every RED gap routinely
opens new ones, and the edit itself is what opens them: the new rule now sits beside older text
written for the old behaviour, and the two disagree. Work the list before you ship - a gap GREEN
reported is a gap that reached a reader.

**Diff GREEN against RED in BOTH directions - what appeared, and what DISAPPEARED.** A new step
does not add to the agent's attention, it competes for it, so an edit that works can still cost a
result the baseline produced. Line the two outputs up item by item and account for every baseline
item that is missing from GREEN. Do this even when GREEN is obviously richer: more findings, or
the exact findings you wrote the step to produce, is what a net-negative edit looks like from the
gained side alone.

A lost result is a REFACTOR requirement, not an acceptable trade - rank by value, not by count.
One correctness finding traded for four style findings is a worse review, and the edit ships as an
improvement because the tally went up.

Confirm the loss reproduces before you restructure anything. One run per condition shows a
mechanism is plausible, never that it is stable, so a single absence is a hypothesis with three
live rivals: the edit displaced it, the run varied, or the baseline item was wrong to begin with.
Re-run the same arm and keep everything else fixed - same model, same prompt, same input. An
absence that survives is a lost result; one that does not is noise, and restructuring the skill
around noise costs you the version you already had.

When the lost item was a JUDGEMENT that had to follow a mechanical step, making the rule more
emphatic will not bring it back. Anything optional after a satisfying mechanical action gets
skipped, and a rule stated as prose after a concrete table reads as commentary on the table.
Make the judgement a REQUIRED OUTPUT of the step instead: the row reports its verdict, not only
its count.

**Where the loop stops:** every gap on the list is either CLOSED in the text or DECLINED in the
review artifact with a reason (out of scope, owned by another skill, judgement the skill should
leave open). A surviving gap is fine; a surviving gap nobody decided about is not, so the exit
condition is an empty undecided list, never an empty list. Re-test only the questions your fix
touched, not the whole skill - a full re-run costs a cycle and answers nothing you changed.

**Verify each fix by quote-back.** Re-ask the contested question and require the answer to be a
DIRECT QUOTE of the governing text, or the single word NONE. A paraphrase proves the model can
reason to the answer; only a quote proves the skill says it. NONE means you have not written the
rule yet, however clear it felt while editing.

**REQUIRED REFERENCE:** See testing-skills-with-subagents.md for the complete testing methodology:
- How to write pressure scenarios
- Pressure types (time, sunk cost, authority, exhaustion)
- Plugging holes systematically
- Meta-testing techniques

## Anti-Patterns

### NO Narrative Example
"In session 2025-10-03, we found empty projectDir caused..."
**Why bad:** Too specific, not reusable

### NO Multi-Language Dilution
example-js.js, example-py.py, example-go.go
**Why bad:** Mediocre quality, maintenance burden

### NO Code in Flowcharts
```text
step1 [label="import fs"];
step2 [label="read file"];
```
(Fenced `text`, not `dot`, on purpose: `render-graphs.js` renders every ` ```dot ` block, and
these two bare statements have no `digraph {}` wrapper, so a `dot` fence makes the tool fail
(exit 1) on this very file. Fence an illustration that is not a renderable diagram as `text`.)
**Why bad:** Can't copy-paste, hard to read

### NO Generic Labels
helper1, helper2, step3, pattern4
**Why bad:** Labels should have semantic meaning

## STOP: Before Moving to Next Skill

**After writing ANY skill, you MUST STOP and complete the deployment process.**

**Do NOT:**
- Create multiple skills in batch without testing each
- Move to next skill before current one is verified
- Skip testing because "batching is more efficient"

**The deployment checklist below is MANDATORY for EACH skill.**

**Gate enforcement:** Use your task/todo tooling (e.g. TodoWrite) to track the deployment checklist. Do NOT mark the final deployment task as completed until you have verified the skill is discoverable in a fresh session. Only after the deployment task is completed may you begin the next skill.

Deploying untested skills = deploying untested code. It's a violation of quality standards.

## Skill Creation Checklist (TDD Adapted)

**IMPORTANT: Use your task/todo tooling (e.g. TodoWrite) to create tasks for EACH checklist item below.** For complex skills, if agent-team tooling is available, parallelize testing work across subagents.

**PLAN Phase - Before Writing Anything:**
- [ ] Identify skill type (discipline, technique, pattern, or reference)
- [ ] Choose test approach based on skill type (see "Testing All Skill Types")
- [ ] Draft 2-3 pressure/application/retrieval scenarios
- [ ] Decide scope: self-contained SKILL.md or hub with supporting files
- [ ] Create task list with your task/todo tooling, e.g. TodoWrite (one task per phase)

**RED Phase - Write Failing Test:**
- [ ] Create pressure scenarios (3+ combined pressures for discipline skills)
- [ ] Run scenarios WITHOUT skill - document baseline behavior verbatim
- [ ] Checked whether the lesson under test is already in the CLAUDE.md cascade or memory store on
      this machine, with `redcheck --corpus-cascade <dir>`; if it is, recorded which route replaced
      the behavioural RED (coverage check against the skill file, or a de-telegraphed arm in a
      domain that text does not teach)
- [ ] Identify patterns in rationalizations/failures

**GREEN Phase - Write Minimal Skill:**
- [ ] Name uses only letters, numbers, hyphens (no parentheses/special chars)
- [ ] YAML frontmatter with only name and description (`name` <= 64 chars, `description` <= 1024)
- [ ] Description length MEASURED with `len()`, not eyeballed - over the cap is truncated silently,
      not refused, and the lost triggers never reach the router
- [ ] Description starts with "Use when..." and includes specific triggers/symptoms
- [ ] Description does NOT summarize workflow (triggers only - see CSO section)
- [ ] Description written in third person
- [ ] Keywords throughout for search (errors, symptoms, tools)
- [ ] Clear overview with core principle
- [ ] Address specific baseline failures identified in RED
- [ ] Code inline OR link to separate file
- [ ] One excellent example (not multi-language)
- [ ] Cross-references use skill name with REQUIRED markers (no `@` links)
- [ ] Test uses current working-directory version (not a stale copy at `~/.claude/skills/`)
- [ ] Run scenarios WITH skill - verify agents now comply

**REFACTOR Phase - Close Loopholes:**
- [ ] Every RED and GREEN dispatch asked for a `Skill gaps` section, and each reply's list is
      recorded - a GREEN that reported nothing because it was never asked is not a pass
- [ ] Every gap GREEN reported is closed or explicitly declined with a reason
- [ ] GREEN diffed against RED in BOTH directions, with every baseline result missing from GREEN
      accounted for - a lost result is a REFACTOR requirement, not a trade
- [ ] Each fix verified by quote-back (a direct quote of the governing text, or NONE)
- [ ] Identify NEW rationalizations from testing
- [ ] Add explicit counters (if discipline skill)
- [ ] Build rationalization table from all test iterations
- [ ] Create red flags list
- [ ] Re-test until bulletproof

**Quality Checks:**
- [ ] Small flowchart only if decision non-obvious
- [ ] Quick reference table
- [ ] Common mistakes section
- [ ] No narrative storytelling
- [ ] No session narrative or private provenance in the skill OR its review artifact (operator instructions, which tool you reached for and when, scratch/temp paths, how it looked before the edit) - see "Write the skill and its artifacts in the present tense"
- [ ] Every address, MAC, hostname and path YOU added is a reserved documentation value, not one from your machine - see "An example from a real scenario is not a real address". Verify: `grep -nE '([0-9]{1,3}\.){3}[0-9]{1,3}|([0-9a-f]{2}:){5}[0-9a-f]{2}|/home/|/Users/|/tmp/' SKILL.md`
- [ ] Supporting files only for tools or heavy reference
- [ ] Hub skills: routing table with topic descriptions for each supporting file
- [ ] Hub skills: "Use the Read tool..." instruction in body
- [ ] Hub skills: routing table passes coverage check (file -> table) and accuracy check (table -> file) for all columns (both distilled reference and upstream source if tier 2 exists)
- [ ] Hub skills: if upstream reference documents exist in subdirectories (e.g., `docs/`, `tutorial/`, `api/`), tier 2 table is present and lists every upstream file with concrete API symbols - run `find docs/ tutorial/ api/ -name '*.md'` (adjust paths) and confirm each result has a row in the tier 2 column
- [ ] Token budget (tiered): `wc -w SKILL.md` body under 500 words for process/technique skills; reference/hub skills may exceed but keep the body a lean index and push detail to reference files
- [ ] External doc references are INSTALL-REACHABLE (see "Referencing external DOCS"): every `README`/`docs/`/`see ...md` the reader is sent to either ships in the skill dir, is a version-pinned URL, or is install-local `--help`/`help()` - no bare package-local path. Verify: `grep -nE '(docs/|README|see [^ ]*\.md)' SKILL.md | grep -v http` shows only bundled-or-discoverable hits

**Deployment:**
- [ ] Place skill in the correct directory:
  - **Project skills** (shared with team): `<project-root>/.claude/skills/skill-name/SKILL.md`
  - **Personal skills** (your own): `~/.claude/skills/skill-name/SKILL.md`
- [ ] Verify frontmatter parses: `head -5 SKILL.md` - confirm `---` delimiters and valid YAML
- [ ] Check token budget: `wc -w SKILL.md` - target under 500 words for process/technique SKILL.md bodies; reference/hub skills may exceed but should keep the body lean and push detail to reference files
- [ ] **If the skill ships Python scripts: `tests/` exists, covers every main function, and PASSES** (`uv run --with pytest pytest tests/`). Do not ship with missing or failing tests.
- [ ] **Security review before any PR/push:** review the full diff for secrets, credentials, private hostnames/IPs, internal paths, PII, and unsafe code (`shell=True` on untrusted input, `eval`/`exec`, command injection, path traversal, unpinned `curl | sh`). Run the `security-review` skill/command on the change. Fix findings before opening the PR.
- [ ] Commit skill to git: `git add skills/skill-name/ && git commit -m "Add skill-name skill"`
- [ ] Push to remote (if configured): `git push`
- [ ] **Verify discoverability:** Start a fresh Claude session, describe a problem the skill should match, and confirm Claude selects and loads the skill
- [ ] Consider contributing back via PR (if broadly useful)

## Discovery Workflow

How future Claude finds your skill:

1. **Encounters problem** ("tests are flaky")
2. **Searches skills** (description keywords match query)
3. **Finds SKILL** (description matches)
4. **Scans overview** (is this relevant?)
5. **Reads patterns** (quick reference table)
6. **Loads example** (only when implementing)

**Optimize for this flow** - put searchable terms early and often.

## The Bottom Line

**Creating skills IS TDD for process documentation.**

Same Iron Law: No skill without failing test first.
Same cycle: RED (baseline) -> GREEN (write skill) -> REFACTOR (close loopholes).
Same benefits: Better quality, fewer surprises, bulletproof results.

If you follow TDD for code, follow it for skills. It's the same discipline applied to documentation.
