Agent Skills : le guide du SKILL.md pour Claude Code et Codex

Ce qu'est un skill, où chaque agent va le chercher, et ce qu'il change vraiment : un skill construit ligne à ligne, puis exécuté par Codex avec et sans lui.

Agent Skills : le guide du SKILL.md pour Claude Code et Codex
Réponse rapide

Un skill est un dossier contenant un SKILL.md : un frontmatter YAML (name, description) et des instructions Markdown, plus des scripts et des références chargés à la demande. Seule la description reste en contexte en permanence, et elle est tronquée, ce qui en fait le seul déclencheur qui compte. Le même dossier fonctionne dans Claude Code, Codex, Copilot et OpenCode, à condition de le poser dans le bon répertoire.

Un skill, c’est un dossier contenant un fichier SKILL.md. L’écrire est la partie facile. Le reste demande de savoir où le poser pour que l’agent le trouve, de vérifier qu’il se déclenche vraiment, et de mesurer ce qu’il coûte le reste du temps. Ce guide fait les trois, sur un skill construit et exécuté pour l’occasion.

Qu’est-ce qu’un skill, exactement ?

Le format Agent Skills a été créé par Anthropic puis publié comme standard ouvert, la spécification vit aujourd’hui sur agentskills.io. Elle tient en peu de choses : un dossier, un SKILL.md obligatoire, et ce que vous voulez à côté.

bash
regex-verifiee/
├── SKILL.md          # obligatoire : frontmatter YAML + instructions Markdown
├── scripts/          # optionnel : du code que l'agent exécute
├── references/       # optionnel : de la documentation chargée à la demande
└── examples/         # optionnel : gabarits, jeux de données

Le frontmatter est court et contraint. name : 64 caractères au plus, minuscules, chiffres et tirets uniquement, ni tiret en tête ou en fin, ni tiret double, et il doit être identique au nom du dossier parent. description : obligatoire, 1 024 caractères au plus, elle dit ce que fait le skill et quand l’utiliser. Trois champs facultatifs complètent le tout : license, compatibility (500 caractères) et metadata. Un sixième, allowed-tools, est marqué expérimental dans la spécification.

Le mécanisme qui rend l’affaire intéressante s’appelle la divulgation progressive, en trois niveaux. Au démarrage, l’agent ne charge que le name et la description de chaque skill, la spécification vise une centaine de tokens. Quand une tâche correspond, il lit le corps du SKILL.md (moins de 5 000 tokens recommandés, 500 lignes maximum). Ensuite seulement, s’il en a besoin, il ouvre les fichiers de scripts/, references/ ou assets/. Le billet d’ingénierie d’Anthropic du 16 octobre 2025 le formule dans l’autre sens : soignez le name et la description, parce que c’est là-dessus, et seulement là-dessus, que l’agent décide de déclencher le skill.

Un skill qui ne se déclenche jamais coûte donc quand même sa description, à chaque session, dans toutes les fenêtres de contexte. C’est exactement ce que mesure la commande /skill-doctor de Claude Code, et c’est le premier poste de dépense examiné dans le retour d’expérience de Spotify sur la facture de tokens.

Où chaque agent va-t-il chercher les skills ?

C’est la partie que personne n’écrit correctement, parce qu’elle change d’un outil à l’autre. Voici les chemins tels qu’ils figurent dans la documentation de chaque éditeur, ouverte le 7 septembre 2026.

Outil Projet Utilisateur
Claude Code .claude/skills/<nom>/SKILL.md ~/.claude/skills/<nom>/SKILL.md
Codex .agents/skills/ (et .codex/skills/, voir plus bas) $CODEX_HOME/skills, ~/.agents/skills
GitHub Copilot .github/skills, .claude/skills, .agents/skills ~/.copilot/skills, ~/.agents/skills
OpenCode .opencode/skills, .claude/skills, .agents/skills ~/.config/opencode/skills, ~/.claude/skills, ~/.agents/skills

Deux choses en découlent. .agents/skills est en train de devenir le chemin neutre commun, Codex, Copilot et OpenCode le lisent tous les trois. Et Copilot comme OpenCode lisent aussi .claude/skills, le dossier de Claude Code sert de format d’échange de fait. Un même dossier de skill peut donc servir plusieurs agents sans être dupliqué. Côté surfaces, GitHub annonce les skills pour l’agent cloud, la revue de code, Copilot CLI, l’application GitHub Copilot et le mode agent de VS Code et des IDE JetBrains.

Le 7 septembre 2026, la vitrine d’agentskills.io recense 46 produits compatibles, de Cursor à Goose en passant par Junie, Kiro, Roo Code, Laravel Boost, OpenCode et OpenClaw.

Construire un skill qui sert : regex-verifiee

Un bon skill encode une procédure que vous répétez et que l’agent saute quand on ne la lui impose pas. Le cas retenu ici : les expressions régulières. Un agent vous sort une regex en trois secondes, sans jamais l’exécuter sur un contre-exemple. Le skill regex-verifiee interdit cette réponse-là.

Le SKILL.md, en entier pour le frontmatter et le début du corps :

markdown
---
name: regex-verifiee
description: Écrire une expression régulière et la prouver avant de la livrer. À utiliser dès qu'une demande porte sur une regex, une expression régulière, une validation de format (code postal, SIRET, IBAN, e-mail, téléphone, slug, plaque), un preg_match, un preg_replace ou un RegExp. Impose un fichier de cas valides et invalides, son exécution dans le moteur cible (Node et PHP), puis la livraison regex + tableau de cas + limites.
---

# Regex vérifiée

Une regex qui n'a jamais tourné sur ses contre-exemples n'est pas une regex, c'est une intuition.
Suivez ces cinq étapes dans l'ordre. Ne sautez pas l'étape 4.

## Procédure

1. **Cadrer.** Demandez, ou décidez explicitement : le moteur (JavaScript, PCRE/PHP, POSIX), la
   chaîne testée (déjà nettoyée ou brute), et si la valeur peut être vide.
2. **Proposer.** Écrivez la regex ancrée et, en une phrase par groupe, ce que chaque partie accepte.
3. **Écrire les cas.** Créez un fichier JSON : au moins six valides et six invalides. Les invalides
   doivent inclure les pièges de `references/cas-types.md` pour le type de donnée concerné.
4. **Exécuter.** Lancez le script sur les deux moteurs et collez la sortie brute dans la réponse.
5. **Livrer.** Réponse finale = la regex + le tableau de cas produit par le script + les limites.

La description est délibérément bavarde en vocabulaire de déclenchement : « regex », « expression régulière », « code postal », « SIRET », « preg_match », « RegExp ». Ce sont les mots que le lecteur tape. Écrivez-la dans la langue dans laquelle on vous parle, pas dans celle de la documentation.

Le dossier contient ensuite un fichier de cas au format JSON, deux exécuteurs (un en Node, un en PHP) qui lisent le même fichier, et une référence references/cas-types.md qui liste les contre-exemples par type de donnée. Le fichier de cas ressemble à ceci :

json
{
  "name": "code postal français",
  "engine": "both",
  "pattern": "^(?:0[1-9]|[1-8]\\d|9[0-8])\\d{3}$",
  "flags": "",
  "valid": ["01000", "20000", "62500", "75001", "97400", "98000"],
  "invalid": ["", "00000", "99999", "7500", "750011", "75 001", "2A000", " 75001", "75001\n"]
}

Les deux exécuteurs affichent le même tableau et renvoient un code de sortie non nul dès qu’un cas échoue. C’est ce code de sortie qui fait le travail : l’agent ne peut pas conclure sur une commande en erreur.

Première surprise, obtenue en lançant le harnais moi-même avant même de brancher un agent : la même regex ne donne pas le même verdict dans les deux moteurs.

bash
$ node scripts/verifier.mjs examples/code-postal-fr.json
moteur : node v22.23.2
regex  : /^(?:0[1-9]|[1-8]\d|9[0-8])\d{3}$/
...
"75001\n"  false    false   ok

15 cas, 0 échec(s)

$ php scripts/verifier.php examples/code-postal-fr.json
moteur : PHP 8.4.19, PCRE 10.47 2025-10-21
regex  : /^(?:0[1-9]|[1-8]\d|9[0-8])\d{3}$/
...
"75001\n"  false    true    ECHEC

15 cas, 1 échec(s)

En PCRE, $ accepte un saut de ligne final, en JavaScript, non. Un champ de formulaire qui arrive avec un \n collé au bout passe donc la validation PHP et échoue la validation JavaScript, avec la même expression écrite dans les deux fichiers. Les deux corrections, l’une et l’autre vérifiées ici : le modificateur D côté PHP (preg_match('/^\d{5}$/D', "75001\n") renvoie 0), ou un ancrage portable (?![\s\S]) à la place de $, qui passe les quinze cas dans les deux moteurs.

Le tester avec Codex sans toucher à ~/.codex

La documentation de Codex décrit une pile de racines : $CWD/.agents/skills, les dossiers parents, $REPO_ROOT/.agents/skills, puis $HOME/.agents/skills, /etc/codex/skills et les skills livrés avec le CLI. Autrement dit, un skill de projet existe : pas besoin d’écrire dans ~/.codex/skills ni dans ~/.codex/config.toml pour l’essayer.

Reste à vérifier ce que le binaire fait réellement. Codex expose pour cela une commande de mise au point qui affiche le prompt tel que le modèle le reçoit, sans appeler le modèle :

bash
$ mkdir -p demo-projet/.codex/skills
$ cp -R regex-verifiee demo-projet/.codex/skills/
$ cd demo-projet && codex debug prompt-input "test"

### Skill roots
- `r0` = `/…/demo-projet/.codex/skills`
- `r1` = `/Users/gekkode/.codex/skills`
- `r2` = `/Users/gekkode/.agents/skills`
- `r3` = `/Users/gekkode/.codex/skills/.system`
- `r4` … `r10` = caches de plugins
### Available skills
- regex-verifiee: Écrire une expression régulière et la prouver avant de la livrer. À utiliser dès qu'une deman (file: r0/regex-verifiee/SKILL.md)

Le skill est vu, depuis <projet>/.codex/skills, un chemin que la documentation ne mentionne pas, mais que le binaire scanne bien, en première position. En déposant un second skill témoin dans <projet>/.agents/skills, une racine r11 est apparue avec ce chemin : les deux fonctionnent, et le dossier .codex/ passe en premier.

Vient l’essai réel. Même prompt, même modèle, même machine, à quelques minutes d’écart : une fois dans le projet qui contient le skill, une fois dans un dossier vide.

bash
codex exec -m gpt-6-astra -s workspace-write --skip-git-repo-check \
  "Dans un formulaire PHP, je dois valider le code postal saisi par le visiteur. Donne-moi l'expression reguliere a utiliser."

Sans le skill : 19 secondes, zéro commande exécutée, et cette réponse, preg_match('/\A[0-9]{5}\z/', $codePostal), avec une phrase disant que l’expression vérifie le format et non l’existence du code postal. Passée dans le harnais, cette regex échoue deux cas sur quinze : elle accepte 00000 et 99999.

Avec le skill : 106 secondes, dix commandes exécutées. Codex a lu le SKILL.md, puis les deux scripts, puis references/cas-types.md, la divulgation progressive au complet, niveau par niveau. Il a ensuite écrit son propre fichier de cas (dix-huit cas, dont "75001\n00000" et "2a000", repris de la référence), lancé les deux exécuteurs, et livré ceci :

php
$codePostal = $_POST['code_postal'] ?? '';

$valide = is_string($codePostal)
    && preg_match('/\A(?:0[1-9]|[1-8][0-9]|9[0-8])[0-9]{3}\z/', $codePostal) === 1;

Avec, en dessous, les deux tableaux de dix-huit cas et une section « limites ». Notez qu’il n’a pas utilisé la même expression dans les deux moteurs. \A … \z pour PCRE, ^ … (?![\s\S]) pour JavaScript. Le skill ne lui a jamais dit de faire ça, il l’a déduit en exécutant les cas.

Un skill d’une soixantaine de lignes a donc transformé une réponse en trois secondes, fausse sur deux cas, en une procédure de deux minutes dont le résultat est vérifiable. Le déclenchement s’est fait tout seul, sur la description : le prompt ne contient ni le mot « skill », ni le nom regex-verifiee. En Codex, on peut aussi forcer la main avec $regex-verifiee dans le prompt, en Claude Code, avec /regex-verifiee.

Combien coûte une description, et pourquoi elle est coupée

Pendant l’exécution, Codex a émis un avertissement que je n’attendais pas :

Skill descriptions were shortened to fit the skills context budget. Codex can still see every skill, but some descriptions are shorter. Disable unused skills or plugins to leave more room for the rest.

Vérification faite avec un skill témoin dont la description est une suite de trois cents caractères connus : sur cette machine, avec 146 skills installés, chaque description est coupée à 94 caractères. Ma description de 422 caractères arrive donc au modèle amputée aux deux tiers, au milieu du mot « demande ». Tout ce qui vient après, « SIRET », « IBAN », « preg_match », « RegExp », ne sert à rien pour le déclenchement.

Le budget est réglable. Codex accepte une clé skills.max_context_tokens, que l’on peut passer en surcharge sans écrire dans le fichier de configuration :

bash
codex debug prompt-input -c skills.max_context_tokens=16000 "test"
Budget Longueur de description conservée Taille du bloc de skills
2 000 40 caractères 8 202 caractères
4 000 54 caractères 16 492 caractères
5 000 82 caractères 20 482 caractères
par défaut 94 caractères 22 230 caractères
8 000 198 caractères 32 295 caractères
16 000 300 caractères (aucune coupe) 40 201 caractères

Deux règles en sortent. Mettez les mots de déclenchement dans les quatre-vingt-dix premiers caractères de la description, le reste est un bonus. Et sachez que plus vous installez de skills, plus vous rabotez la description de tous les autres. Le catalogue occupait ici 22 230 caractères de contexte, à chaque session, pour 146 skills dont je n’en utilise qu’une poignée. Désinstaller vaut mieux qu’augmenter le budget.

Claude Code applique le même principe avec des chiffres publiés. Son budget de liste vaut 1 % de la fenêtre de contexte du modèle, réglable par skillListingBudgetFraction ou par la variable d’environnement SLASH_COMMAND_TOOL_CHAR_BUDGET. Chaque entrée est de toute façon plafonnée : description et when_to_use concaténés sont coupés à 1 536 caractères, plafond réglable par skillListingMaxDescChars. Et quand la liste déborde, la documentation est explicite sur l’ordre de sacrifice : Claude Code supprime d’abord les descriptions des skills que vous invoquez le moins. Le nom, lui, reste toujours dans la liste.

Les deux outils offrent la même échappatoire : désactiver plutôt que gonfler le budget. Côté Claude Code, le réglage skillOverrides accepte quatre états par skill, on, name-only (le nom sans la description), user-invocable-only et off, et la commande /skills les écrit pour vous dans .claude/settings.local.json. Côté Codex, un bloc dans ~/.codex/config.toml :

toml
[[skills.config]]
path = "/chemin/vers/le/skill/SKILL.md"
enabled = false

Charger et distribuer le même skill dans Claude Code

Le dossier ne change pas. Deux emplacements, selon que le skill vous suit partout ou appartient au dépôt :

bash
cp -R regex-verifiee ~/.claude/skills/          # pour tous vos projets
cp -R regex-verifiee mon-projet/.claude/skills/ # versionné avec le dépôt

La documentation de Claude Code ajoute des champs de frontmatter absents de la spécification. disable-model-invocation: true empêche le déclenchement automatique et réserve le skill à un appel manuel par /nom, le bon réglage pour tout ce qui pousse, déploie ou supprime. allowed-tools accorde des permissions d’outils pour le seul tour de conversation qui invoque le skill, et la permission retombe au message suivant. user-invocable: false réserve le skill au modèle.

Pour distribuer le skill à une équipe, l’emballage est un plugin : un manifeste .claude-plugin/plugin.json à la racine, le skill dans le dossier skills/, et un fichier .claude-plugin/marketplace.json qui déclare la place de marché. L’installation se fait ensuite par /plugin marketplace add compte/depot puis /plugin install mon-plugin@ma-marketplace, et /reload-plugins recharge sans quitter la session.

Reste la question qui fâche. Votre skill se déclenche-t-il, et sert-il à quelque chose ? Claude Code répond aux deux moitiés. /skill-doctor, qui demande la version 2.1.252 ou plus récente, liste les skills chargés, leur nombre d’invocations et leur dernier usage, et signale ceux qui n’ont jamais servi, le rapport s’ouvre dans l’onglet Stats du gestionnaire de plugins, et s’imprime en texte brut en mode -p. Et claude plugin eval, en accès anticipé, automatise exactement la comparaison que j’ai faite à la main plus haut. L’aide de la commande, sur cette machine, est sans ambiguïté :

bash
$ claude plugin eval --help
Run eval cases (evals/**/case.yaml or evals/**/prompt.md + graders/*.md) against
a plugin and report scored results.

  --ablation <mode>   Run a no-plugin baseline arm and report the score delta
                      (none | with-without; default: with-without …)
  --runs <n>          Override per-case runs (default: case.runs ?? 3)
  --threshold <0..1>  Exit 1 if any case score is below this threshold
  --json              Emit aggregate-result.json to stdout (for CI)

Un cas d’évaluation est un dossier evals/<cas>/ contenant un prompt.md, un prompt réaliste qui ne nomme surtout pas le skill, et des correcteurs dans graders/. L’option --ablation with-without rejoue chaque cas avec et sans le plugin et affiche l’écart de score : c’est la seule façon honnête de prouver qu’un skill apporte quelque chose.

Partager un skill, et vérifier ceux des autres

Trois circuits de distribution cohabitent. Un dépôt Git nu, que l’on clone dans le bon dossier, le plus simple et le plus auditable. Un plugin, pour Claude Code comme pour Codex : côté Codex, chaque plugin vit sous plugins/<nom>/ avec un manifeste .codex-plugin/plugin.json obligatoire et des dossiers facultatifs skills/, .app.json, .mcp.json. Et les places de marché publiques : ClawHub, Skills.sh, SkillsMP.

Notez au passage que le catalogue github.com/openai/skills, encore cité partout, est marqué obsolète et renvoie vers github.com/openai/plugins. Le skill système $skill-installer, lui, installe toujours dans $CODEX_HOME/skills/<nom>.

Le troisième circuit demande de la méfiance. L’audit ToxicSkills publié par Snyk le 5 février 2026 a passé au crible 3 984 skills de ClawHub et de skills.sh : 1 467 d’entre eux (36,82 %) présentent au moins un défaut de sécurité, et 534, 13,4 % du total, au moins un défaut critique. Soixante-seize charges malveillantes ont été confirmées par revue humaine : vol d’identifiants, installation de porte dérobée, exfiltration de données, huit de ces skills étaient toujours en ligne le jour de la publication. Toutes les charges confirmées contiennent du code malveillant, et 91 % y ajoutent de l’injection de prompt.

Un skill est du texte que votre agent va suivre, plus des scripts qu’il exécutera avec vos droits. Avant d’en installer un, lisez le SKILL.md en entier, lisez chaque fichier de scripts/, cherchez les appels réseau et les chaînes encodées en base64, et refusez tout skill qui demande une clé d’API ou un jeton. Les mêmes réflexes que pour la sandbox et les permissions d’un agent de code.

Skills ou MCP ?

Skills et MCP ne répondent pas au même besoin. Un skill apporte une procédure et un savoir-faire, en Markdown, sans processus, sans réseau, sans authentification. Un serveur MCP apporte des outils et des données : il parle à une base, à une API, à un système de fichiers distant, avec les identifiants qui vont avec.

Le test le plus rapide tient en une phrase. Si votre besoin s’écrit « procède ainsi », c’est un skill. S’il s’écrit « va chercher ceci » ou « écris cela quelque part », c’est un serveur MCP. La différence de coût suit la même ligne : un skill inactif coûte sa description, quelques dizaines de tokens, tandis qu’un serveur MCP branché coûte la définition de tous ses outils, en permanence, à chaque session.

Les deux se combinent très bien : un skill qui dit dans quel ordre appeler les outils d’un serveur MCP est souvent le meilleur des deux mondes. C’est d’ailleurs la direction prise par le protocole lui-même, la révision 2026-07-28 de la spécification MCP liste un groupe de travail « Skills over MCP », dont l’objet est de découvrir et de consommer des instructions structurées par MCP. Pour la partie serveur, le guide du serveur MCP en PHP prend le relais.

Les quatre erreurs qui reviennent

Une description qui décrit le skill au lieu de dire quand l’utiliser. « Aide avec les regex » ne se déclenche jamais. Écrivez les mots que l’utilisateur tape, dans sa langue, et mettez-les au début, à cause de la troncature mesurée plus haut.

Un SKILL.md de deux mille lignes. Le corps entier entre en contexte au déclenchement. La spécification recommande de rester sous 500 lignes et de renvoyer le détail vers references/, chargé seulement si nécessaire. Dans l’essai ci-dessus, Codex n’a ouvert cas-types.md qu’au moment d’écrire ses cas.

Des secrets dans le skill. Un skill se partage, se versionne, se publie. Une clé d’API qui y traîne se retrouve dans un dépôt public. Le skill lit une variable d’environnement, il ne la contient pas.

Empiler les skills « au cas où ». Chaque skill installé raccourcit la description de tous les autres et grignote la fenêtre de contexte. Faites l’inventaire de ce qui ne s’est jamais déclenché et supprimez-le.

Ce qu’il faut retenir

  • Un skill = un dossier + un SKILL.md (name de 64 caractères au plus, description de 1 024 au plus) + ce que vous voulez à côté.
  • Seule la description est chargée en permanence, et elle est tronquée : les mots de déclenchement vont dans les 90 premiers caractères.
  • .agents/skills côté projet, plus .claude/skills lu par Copilot et OpenCode : un même dossier sert plusieurs agents.
  • Un skill de projet se teste sans rien installer chez soi : <projet>/.codex/skills/ pour Codex, <projet>/.claude/skills/ pour Claude Code.
  • Le bon skill impose une procédure vérifiable et un code de sortie, pas une consigne de style.
  • Lisez intégralement tout skill installé depuis une place de marché : 13,4 % de ceux audités par Snyk portent un défaut critique.

Erreurs fréquentes

Description trop vague « Aide avec les regex » ne se déclenche jamais. Nommez les cas d'usage et les mots que l'utilisateur tape, dans sa langue, et placez-les au début : Codex n'a gardé ici que les 94 premiers caractères.
SKILL.md interminable Le corps entier entre en contexte au déclenchement. Restez sous 500 lignes et déportez le détail dans references/, que l'agent n'ouvre que s'il en a besoin.
Nom du dossier différent du champ name La spécification impose l'égalité stricte, en minuscules, chiffres et tirets, sans tiret double ni tiret en tête ou en fin. Un écart et le skill est ignoré ou refusé à l'installation.
Un secret dans le skill Un skill se versionne et se publie : une clé d'API qui y traîne finit dans un dépôt public. Lisez une variable d'environnement à la place.
Skill installé sans être lu Un SKILL.md est une instruction que votre agent va suivre, et scripts/ du code qu'il va exécuter avec vos droits. Lisez tout avant, y compris les scripts.

Claude CodeCodexCopilot CLIOpenCodeSkills

Damien Flandrin Développeur web depuis 2010, créateur de Gekkode et d’Email Impact. Chaque article est testé sur un projet réel avant publication. Contact
Newsletter

Les nouveaux tests, tutoriels et projets, par e-mail.

Tests reproductibles, code versionné, résultats datés. Jamais de spam.