# Writing a SKILL.md `description` that triggers reliably

The `description` field in a skill's frontmatter is the **only** signal that routes
natural language to a skill. The model picks a skill from the list of `name + description`
pairs — nothing else (not the body, not the file names) is read at selection time. A skill
that "doesn't trigger" almost always has a description that fails to cover how the user
actually phrased the request: wrong language, casual register, a synonym, or an imperative
verb that isn't listed.

This is the single source of truth for how to write that field. The deterministic lint
(`pysae-ai-tools internal scan-skill --check`) and `/clawd-skill-review` both enforce it.

## Anatomy of a strong description

A description has four parts, in this order:

1. **One "what + when" sentence.** What the skill does, on what object. Concrete, not vague.
   - ✅ « Deploy an application to an environment (prod, review, dev) or rollback production. »
   - ❌ « Helps with deployments. »

2. **A trigger-phrase bank.** `Use when the user says /alias, '<phrase>', '<phrase>', …`.
   This is what does the routing. Cover, for the *same* intent:
   - **Both languages** — FR **and** EN. The team works in French; the model is prompted in
     English. A description with only one language misses half the phrasings.
   - **Registers** — the canonical form *and* the imperative/casual ones people actually type:
     `'déploie'`, `'mets en prod'`, `'ça rame'`, `'la CI fail'`, `'fais une release'`.
   - **Synonyms** — the different words for the same thing (`'release' / 'nouvelle version' / 'bump version'`).

3. **Disambiguation** vs neighbouring skills, when two skills could both plausibly match a
   phrase. One sentence: `Distinct from /X, which …`.
   - Example (already shipped): `/code-profile` vs `/infra-perf` —
     « Distinct from /infra-perf (which monitors live API health via Datadog) —
     /code-profile runs a profiler on the code itself. »

4. **The slash alias(es)** — `/ci-deploy`, `/deploy`. Always list every alias the skill answers to.

## Rules of thumb

Derived from the strongest existing descriptions (`ci-deploy`, `ci-reports`, `code-profile`):

- **Aim for ≥ 6 trigger phrases and ≥ 40 words.** The best descriptions carry 7–23 phrases.
- **FR and EN both present.** Not one or the other.
- **Imperative/casual forms included**, not just the noun ("a release") — people type verbs
  ("release en prod", "déploie driver").
- **Disambiguate** every skill that competes with a sibling for the same phrasing.

### Enforced floor vs recommended target

The lint (`scan-skill --check`) **blocks** below an enforced floor — deliberately lower than
the recommended target so it flags genuinely-thin descriptions that fail to trigger, not
merely terse-but-working ones. A description must, at minimum:

- be **≥ 30 words**,
- carry **≥ 4 trigger phrases**,
- contain a **`use when`** clause and a **`/slash` alias**,
- carry **both** a French and an English trigger.

Clearing the floor is the bar to merge; hitting the ≥ 6 / FR+EN-rich target is what makes a
skill trigger *reliably*. Aim for the target, not the floor.

## Worked example

A weak description:

```yaml
description: >
  Create a GitLab merge request from the current branch.
  Use when the user says /glab-mr, /mr, 'create a MR', 'open a merge request',
  or needs to submit code for review.
```

The same description, reinforced:

```yaml
description: >
  Create a GitLab merge request from the current branch: resolve target branch,
  draft a Conventional-Commits title and description, set labels and assignee, then open it.
  Use when the user says /glab-mr, /mr, 'crée une MR', 'ouvre une merge request',
  'fais une MR', 'soumets pour review', 'create a MR', 'open a merge request',
  'submit this for review', 'PR cette branche', or wants to turn the current branch
  into a merge request. Distinct from /glab-mr-find (which locates an existing MR) and
  /code-implement (which writes the code first, then opens the MR at the end).
```

What changed: a concrete "what" clause, FR + EN trigger phrases in several registers, and an
explicit boundary against the two siblings most likely to steal the phrasing.

## Anti-patterns

- **English-only or French-only** trigger banks.
- **Only the canonical verb** — listing `'create a merge request'` but not `'fais une MR'`.
- **No disambiguation** between near-twins (the model picks one at random when both fit).
- **Vague "what"** (`'helps with X'`) — gives the router nothing to latch onto.
- **Slash alias as the only trigger** — `/infra-ops` had 13 slash aliases and zero natural
  phrases, so a user who says "le pod crash" instead of "/infra-ops" wouldn't reach it.
