Au bout de quelques jours d'usage, les mêmes prompts reviennent : la revue avant commit, l'ajout d'une entrée dans un fichier de données, la préparation d'une version. Un skill enregistre cette procédure dans un fichier que l'agent exécute quand vous l'appelez, ou quand il juge lui-même qu'elle s'applique. On parle aussi de macro-prompt.
| Niveau | Ce que c'est | Qui l'écrit |
|---|---|---|
| Commandes intégrées | /clear, /context, /model, /permissions. Elles pilotent l'outil. |
Anthropic |
| Skills livrés | /code-review, /simplify, /loop. Des procédures fournies avec Claude Code. |
Anthropic |
| Vos skills | Tout ce que vous mettez dans .claude/skills/, et les fichiers hérités de .claude/commands/. |
Vous et votre équipe |
Les commandes personnalisées ont été fusionnées dans les skills : .claude/commands/revue.md et .claude/skills/revue/SKILL.md produisent la même commande /revue et se comportent à l'identique. Les fichiers déjà écrits dans .claude/commands/ continuent de fonctionner, mais c'est l'ancien format ; un skill écrit aujourd'hui prend la forme d'un dossier, seul à accepter des fichiers annexes ainsi que les champs name et paths.
Les deux dernières lignes reposent sur le même mécanisme, un fichier markdown avec un en-tête YAML, et un skill de projet remplace un skill livré du même nom. /context liste les skills chargés et leur provenance : au tag tp1-depart, aucun fichier de projet n'existe, et les treize lignes du tableau sont livrées avec l'outil. En voici cinq.
| Skill | Source | Tokens |
|-------|--------|--------|
| dataviz | Built-in | ~480 |
| code-review | Built-in | ~270 |
| simplify | Built-in | ~60 |
| loop | Built-in | ~120 |
| claude-api | Built-in | ~360 |
Un skill est un dossier qui contient un fichier SKILL.md obligatoire, et autant de fichiers annexes que la procédure en demande.
Le dépôt de référence QuizOps embarque un skill nouvelle-question à partir du tag tp9-depart.
$ git ls-tree -r --name-only tp9-depart .claude
.claude/commands/revue.md
.claude/hooks/garde-fou.sh
.claude/settings.json
.claude/skills/nouvelle-question/SKILL.md
.claude/skills/nouvelle-question/modele.json
.claude/skills/nouvelle-question/verifier.py
Le fichier SKILL.md combine un en-tête YAML et des instructions en markdown.
---
name: nouvelle-question
description: Ajoute une question au quiz QuizOps dans data/questions.json puis vérifie le fichier. À utiliser quand on demande d'ajouter, de créer ou d'insérer une question de quiz.
argument-hint: "[énoncé de la question]"
allowed-tools: Read, Edit, Bash(uv run python *)
---
Ajoute une question au quiz QuizOps.
1. Lis `data/questions.json` et repère le plus grand `id`.
2. Rédige la question à partir de la demande : $ARGUMENTS. Si la catégorie n'est pas évidente, demande-la (`docker` ou `kubernetes`). Quatre propositions plausibles, une seule juste ; `reponse` est l'index de la bonne réponse, de 0 à 3. Suis le gabarit `modele.json` de ce dossier.
3. Ajoute l'objet à la fin du tableau, avec `id` égal au plus grand id plus un.
4. Lance `uv run python ${CLAUDE_SKILL_DIR}/verifier.py` et corrige jusqu'à obtenir `0 erreur`.
5. Affiche la question ajoutée et le résultat de la vérification. Ne committe pas.
Le gabarit modele.json que ce fichier cite décrit le format à la place d'un paragraphe.
{
"id": 99,
"categorie": "kubernetes",
"question": "Énoncé court, qui se termine par un point d'interrogation ?",
"propositions": ["proposition A", "proposition B", "proposition C", "proposition D"],
"reponse": 2
}
Seuls name et description comptent vraiment, name valant par défaut le nom du dossier. Les autres champs se justifient un par un.
| Champ | Ce qu'il fait | Quand s'en servir |
|---|---|---|
name |
Le nom du skill, qui devient la commande /nom |
Toujours, en minuscules et tirets |
description |
Ce que fait le skill et quand l'employer. Seul élément chargé en permanence | Toujours, avec les mots que vous emploierez |
argument-hint |
Le texte d'aide affiché dans l'autocomplétion après /nom |
Quand le skill attend un argument |
disable-model-invocation |
À true, l'agent ne peut plus le déclencher seul |
Migration, publication, tout ce qui doit rester manuel |
user-invocable |
À false, le skill disparaît de la liste des / |
Procédure interne appelée par un autre skill |
allowed-tools |
Pré-autorise et restreint les outils pendant l'exécution | Skill qui écrit dans des fichiers de données |
model |
Force le modèle employé pour ce skill | Tâche mécanique où Haiku suffit |
effort |
Force le niveau de réflexion, de low à max |
Skill d'analyse où la vitesse importe peu |
context: fork et agent |
Exécute le skill dans un sous-agent isolé, du type indiqué par agent |
Procédure longue dont seul le résultat compte |
paths |
Motifs de fichiers qui activent le skill | Monorepo, skill propre à un sous-projet |
hooks |
Hooks enregistrés le temps du skill | Vérification imposée à chaque édition |
Le corps du fichier accepte des variables, remplacées avant d'être données au modèle.
| Variable | Valeur |
|---|---|
$ARGUMENTS |
Tout ce qui suit /nom sur la ligne |
$0, $1, $2 |
Les arguments pris un par un, dans l'ordre |
${CLAUDE_SKILL_DIR} |
Le dossier du skill, quel que soit le répertoire courant. C'est ce qui rend verifier.py appelable depuis la racine du projet |
${CLAUDE_PROJECT_DIR} |
La racine du projet |
Un skill se déclenche en tapant /nom, ou parce que l'agent a rapproché votre demande de la description et décidé que la procédure s'appliquait.
Sur la branche solution/tp9, la demande ne cite aucune commande. Le transcript est abrégé ; la première ligne montre le skill retenu par l'agent.
> Ajoute une question sur docker compose up au quiz.
⏺ Skill(nouvelle-question)
⎿ Execute skill: nouvelle-question
⏺ Read(~/projets/quizops/.claude/skills/nouvelle-question/SKILL.md)
⎿ 1 --- (+13 lignes)
⏺ Read(~/projets/quizops/.claude/skills/nouvelle-question/modele.json)
⎿ 1 { (+7 lignes)
⏺ Read(~/projets/quizops/data/questions.json)
⎿ 1 [ (+93 lignes)
⏺ Max id is 13, category is "docker". Now I'll add the new question.
⏺ Edit(~/projets/quizops/data/questions.json)
⏺ Bash(uv run python .claude/skills/nouvelle-question/verifier.py)
⎿ 14 questions, 0 erreur
⏺ Vérification réussie : 14 questions, 0 erreur.
L'appel explicite produit la même séquence sans la ligne Skill(...), puisque le skill est déjà désigné.
> /nouvelle-question Quel port etcd écoute-t-il par défaut ?
⏺ Read(~/projets/quizops/data/questions.json)
⎿ 1 [ (+93 lignes)
⏺ Read(~/projets/quizops/.claude/skills/nouvelle-question/modele.json)
⎿ 1 { (+7 lignes)
⏺ Edit(~/projets/quizops/data/questions.json)
⏺ Bash(uv run python .claude/skills/nouvelle-question/verifier.py)
⎿ 14 questions, 0 erreur
⏺ Question ajoutée (id 14, catégorie `kubernetes`) :
Quel port etcd écoute-t-il par défaut pour les requêtes client ?
["6443", "2379", "10250", "2380"], reponse 1
Le champ description est le seul élément que l'agent lit en permanence. Une description vague ne se déclenche jamais, ou se déclenche à tort.
description: Gère les questions du quiz.
Celle-ci fonctionne, parce qu'elle dit ce que fait le skill puis avec quels mots l'utilisateur va le demander.
description: Ajoute une question au quiz QuizOps dans
data/questions.json. À utiliser quand l'utilisateur veut ajouter,
créer ou proposer une nouvelle question de quiz.
Avant la fusion, une procédure sans fichier annexe se déposait directement dans .claude/commands/. Ces fichiers restent valides et acceptent le même en-tête YAML, name et paths exceptés. QuizOps y range encore sa grille de relecture ; écrite aujourd'hui, elle irait dans .claude/skills/revue/SKILL.md avec exactement le même contenu.
---
description: Relit les modifications non committées avec la grille du projet et classe les constats par gravité.
disable-model-invocation: true
---
Relis les modifications non committées : `git diff` puis `git diff --staged`.
Pour chaque fichier modifié, réponds aux six questions de la grille :
1. Fait-il ce qui a été demandé ?
2. Fait-il autre chose (fichier créé en plus, dépendance ajoutée, fonction renommée) ?
3. Que se passe-t-il aux bords : liste vide, `None`, zéro, entrée invalide ?
4. Les erreurs sont-elles traitées ou avalées ?
5. Y a-t-il un risque de sécurité : entrée non validée, secret en dur, SQL assemblé ?
6. Est-ce maintenable dans six mois : noms explicites, fonctions courtes, cohérence avec le reste ?
Rends un tableau `constat | fichier:ligne | gravité` avec trois gravités : bloquant, à corriger, remarque.
Ne modifie aucun fichier.
Après uv run outils/saboter.py 4, qui injecte deux fonctions douteuses dans app/quiz.py, l'appel explicite rend la grille attendue. Le tableau réel compte cinq constats, en voici trois.
> /revue
⏺ Bash(git diff && echo "---STAGED---" && git diff --staged)
⎿ diff --git a/app/quiz.py b/app/quiz.py (+22 lignes)
| constat | fichier:ligne | gravité |
|---|---|---|
| Comparaison d'identité `is` au lieu d'égalité `==` sur des chaînes | app/quiz.py:16 | bloquant |
| `categorie_docker` duplique exactement la logique de `categorie_est_docker` | app/quiz.py:19-23 | à corriger |
| Les deux fonctions sont du code mort : aucun appelant dans `app/` ni dans `tests/` | app/quiz.py:15-23 | à corriger |
La même demande formulée en français ne déclenche pas le skill, à cause de disable-model-invocation: true. Aucune ligne d'appel n'apparaît, et le résultat n'a ni les six questions ni les gravités.
> Relis mon diff.
⏺ Bash(git diff)
⎿ diff --git a/app/quiz.py b/app/quiz.py (+21 lignes)
⏺ Cinq lignes :
1. `categorie_est_docker` utilise `is "docker"` au lieu de `==`.
2. `categorie_docker` fait la même chose via un `if/else` verbeux.
3. Deux fonctions redondantes pour un seul besoin.
4. Aucune docstring en français, contrairement aux autres fonctions du fichier.
Un même skill peut venir de cinq emplacements, du plus imposé au plus proche du fichier édité.
| Emplacement | Portée | Versionné | Cas d'usage |
|---|---|---|---|
| Répertoire de réglages gérés | Imposée à tous les postes, par un administrateur | Par la DSI | Règles de conformité non contournables |
~/.claude/skills/ |
Tous vos projets | Non | Vos habitudes personnelles |
.claude/skills/ du projet |
Ce projet, toute l'équipe | Oui | Procédures propres au projet |
| Skill d'un plugin | Là où le plugin est installé | Via le plugin | Distribution en équipe, voir le module 07 |
.claude/skills/ d'un sous-dossier |
Ce sous-dossier | Oui | Monorepo, une équipe par dossier |
Un skill de plugin garde le nom du plugin en préfixe, ce qui le distingue d'un homonyme de projet. Après installation de quizops-kit, /context affiche les deux, invocables par /quizops-kit:nouvelle-question et /nouvelle-question.
| Skill | Source | Tokens |
|-------|--------|--------|
| nouvelle-question | Project | ~60 |
| quizops-kit:nouvelle-question | Plugin (quizops-kit) | ~70 |
| dataviz | Built-in | ~480 |
Quand deux skills portent le même nom, celui des réglages gérés par l'entreprise l'emporte, puis celui de votre dossier personnel, puis celui du projet. Un dossier de .claude/skills/ remplace un fichier de .claude/commands/ portant le même nom, et un skill de projet remplace un skill livré sans remplacer ses alias : /code-review peut être repris par le projet, /review continue de pointer sur le skill livré.
Neuf skills sont fournis avec l'outil. Ils s'invoquent comme les vôtres, et répondent en anglais par défaut même dans un projet francophone : les sorties ci-dessous sont reproduites telles quelles.
| Skill | Ce qu'il fait |
|---|---|
/code-review (alias /review) |
Relit un diff, une branche ou une pull request et remonte bugs et simplifications, sans rien modifier |
/simplify |
Relit le code modifié pour le simplifier, puis applique les corrections |
/batch |
Décompose une tâche répétitive en sous-tâches indépendantes, menées en parallèle dans des worktrees Git |
/loop |
Rejoue un prompt ou une commande à l'intervalle donné, ici toutes les dix minutes |
/debug |
Active la journalisation de débogage de Claude Code et relit le fichier produit |
/claude-api |
Charge en contexte la référence de l'API Anthropic |
/security-review |
Revue de sécurité des modifications en cours de la branche |
/verify |
Construit et lance le projet pour confirmer qu'un changement marche, et retient la recette |
/run |
Lance l'application du projet, en déduisant la commande du README ou du gestionnaire de paquets |
/code-reviewAprès uv run outils/saboter.py 4, la revue rend une liste de constats en JSON. Les deux premiers sont reproduits ici, sur quatre.
[
{
"file": "app/quiz.py",
"line": 16,
"summary": "categorie_est_docker compares strings with `is` instead of `==`, so it returns False even for questions whose category actually is \"docker\".",
"failure_scenario": "Questions come from data/questions.json via json.load in app/donnees.py, which builds a fresh str object for each \"categorie\" value; that object is not the same object as the \"docker\" literal interned in quiz.py, so `question[\"categorie\"] is \"docker\"` evaluates to False for a genuine Docker question, making the function unusable for its stated purpose."
},
{
"file": "app/quiz.py",
"line": 19,
"summary": "categorie_docker duplicates categorie_est_docker: two functions with near-identical names implement the same \"is this a docker question\" check, only one of them correct.",
"failure_scenario": "A future caller can import either name; picking categorie_est_docker silently gets the broken `is`-based version while categorie_docker works, with nothing in the code signaling which one is right."
}
]
/simplifySur le même diff, /simplify lance quatre sous-agents de relecture en parallèle, attend leurs retours, applique la suppression et relance les tests. Le transcript est abrégé.
> /simplify
⏺ Bash(git diff HEAD -- app/quiz.py)
⎿ diff --git a/app/quiz.py b/app/quiz.py (+21 lignes)
⏺ Agent(general-purpose: Reuse review of quiz.py diff)
⏺ Agent(general-purpose: Simplification review of quiz.py diff)
⏺ Agent(general-purpose: Efficiency review of quiz.py diff)
⏺ Agent(general-purpose: Altitude review of quiz.py diff)
⏺ All four agents agree: `categorie_est_docker` and `categorie_docker` are dead
code (unused anywhere in the app), duplicate each other, and duplicate the
existing general-purpose `filtrer_par_categorie`. Removing both.
⏺ Edit(~/projets/quizops/app/quiz.py)
⏺ Bash(uv run pytest -q)
⎿ ............................... [100%]
31 passed in 0.21s
⏺ Tests pass. Fixed: removed `categorie_est_docker` and `categorie_docker` from
`app/quiz.py`. Nothing was skipped.
/code-review cherche des bugs et ne modifie rien, sauf avec --fix ; on le lance avant de fusionner. /simplify cherche des simplifications et les applique ; on le lance après avoir fait marcher quelque chose. Sur un dépôt propre, ni l'un ni l'autre n'a de quoi travailler.
/loop> /loop 10m uv run pytest -q
All 31 tests pass. The loop will re-run this every 10 minutes for up to 7 days.
/debug/debug ouvre un fichier de journalisation et attend la description du problème pour le relire. La sortie est abrégée.
> /debug
Debug logging is now active at `~/.claude/debug/<identifiant>.txt`.
However, no log file exists yet and you haven't described a specific issue.
Alternatively, if you want to capture logs from the very start of a session,
you can restart with `claude --debug`.
/batch n'a pas été capturé ici. On le lance sur une tâche mécanique et répétitive, par exemple /batch ajoute une docstring de module à chaque fichier de tests/ : il découpe le travail en lots indépendants, ouvre un worktree Git par lot et les fait avancer en parallèle.
Un skill se crée à la main, ou par entretien guidé avec le plugin officiel skill-creator.
# 1. Le dossier, nommé comme la future commande
$ mkdir -p .claude/skills/nouvelle-question
# 2. Le fichier d'instructions, avec name et description
$ $EDITOR .claude/skills/nouvelle-question/SKILL.md
# 3. Les fichiers annexes, gabarit et script
$ cp modele.json verifier.py .claude/skills/nouvelle-question/
La détection se fait à chaud : un skill créé pendant une session est disponible sans redémarrer, sauf s'il s'agit du premier skill du projet et que .claude/skills/ n'existait pas au lancement. Testez d'abord /nouvelle-question, puis une demande en langage naturel qui devrait le déclencher seul ; si la seconde échoue, la description manque des verbes que vous avez employés.
$ claude
> /plugin install skill-creator@claude-plugins-official
> Crée un skill qui prépare une version : numéro, changelog, tag Git.
L'agent vous interroge sur ce que le skill doit faire et sur les mots avec lesquels vous le demanderez, puis écrit l'arborescence complète. Cette séquence n'a pas été capturée ici ; le module 07 montre l'installation d'un plugin de bout en bout.
Une consigne en français est suivie la plupart du temps, un script s'exécute toujours pareil. Quand le résultat doit être exact, il va dans un fichier que l'agent lance, pas dans une phrase du SKILL.md. Voici verifier.py abrégé à sa charpente.
CHEMIN = Path("data/questions.json")
CATEGORIES = {"docker", "kubernetes"}
CHAMPS = ("id", "categorie", "question", "propositions", "reponse")
def verifier(questions: list[dict]) -> list[str]:
erreurs = []
identifiants: set[int] = set()
for question in questions:
identifiant = question.get("id", "?")
for champ in CHAMPS:
if champ not in question:
erreurs.append(f"question {identifiant} : champ '{champ}' manquant")
# quatre autres contrôles : identifiant en double, catégorie inconnue,
# nombre de propositions, index de la bonne réponse
return erreurs
Sur le fichier de questions du tag tp9-depart, la vérification passe et le code de retour vaut 0.
$ uv run python .claude/skills/nouvelle-question/verifier.py
13 questions, 0 erreur
Sur une question mal formée, le script énumère les défauts et sort en 1, ce qui donne à l'agent de quoi corriger sans rien interpréter.
$ uv run python .claude/skills/nouvelle-question/verifier.py
- question 13 : identifiant en double
- question 13 : catégorie inconnue 'helm'
- question 13 : 3 propositions au lieu de 4
- question 13 : réponse 5 hors de 0 à 3
- question 13 : l'énoncé ne se termine pas par un point d'interrogation
14 questions, 5 erreurs
Chaque skill installé occupe du contexte sans être utilisé, puisque sa description est chargée en permanence. Sur la branche solution/tp9, avec un skill de projet, deux sous-agents et le serveur MCP Playwright, les skills pèsent 2,1 k tokens sur une fenêtre de 1 M.
| Category | Tokens | Percentage |
|----------|--------|------------|
| System prompt | 8.9k | 0.9% |
| System tools | 13.1k | 1.3% |
| MCP tools (deferred) | 5.9k | 0.6% |
| Custom agents | 136 | 0.0% |
| Memory files | 484 | 0.0% |
| Skills | 2.1k | 0.2% |
| Free space | 942.2k | 94.2% |
Le skill de projet nouvelle-question pèse environ 60 tokens, le skill livré claude-api environ 360, et le corps du fichier ne se charge qu'au déclenchement : une procédure de trois cents lignes dans CLAUDE.md pèse à chaque session, la même dans un skill ne pèse que sa description.
La documentation fixe un plafond de 1 536 caractères par skill sur le total description plus when_to_use : c'est le seul texte qui décide de la découverte automatique, alors que l'invocation par /nom n'en dépend pas. disable-model-invocation: true produit volontairement le même effet, comme le montre /revue plus haut : la procédure reste disponible et n'est jamais choisie par l'agent.
/skill-doctor rend en session un rapport sur les skills chargés et sur ce qu'ils coûtent. L'onglet Stats de /plugin donne le coût en contexte de chaque skill installé et sa fréquence d'usage. Aucune des deux commandes ne fonctionne en mode -p, elles se lisent dans la session interactive.
SKILL.md obligatoire ; un fichier dans .claude/commands/ fait la même chose sans fichiers annexes.description décide seule du déclenchement automatique et doit contenir les mots de la demande ; disable-model-invocation: true réserve la procédure à l'appel explicite./nom-du-plugin:skill./code-review qui ne modifie rien et /simplify qui applique ses corrections, en anglais.TP associé : TP 6 : Skills et Automatisation
➡️ Module suivant : Git, CI/CD et Hooks Déterministes