System prompt vs user prompt & Écrire un bon sous-agent
Distinguer le prompt système (le corps du sous-agent, préfixe fixe payé à chaque tour) du prompt utilisateur (le message de délégation), et écrire un bon sous-agent Claude Code : responsabilité unique, description-déclencheur, outils minimaux et contrat de sortie.
System prompt vs user prompt : le coût en tokens d’un agent défini
L’idée en une phrase
Dans un sous-agent, le corps Markdown devient son prompt système — le préfixe fixe présent dans sa fenêtre à chaque tour — tandis que le message de délégation est son prompt utilisateur, variable. Comprendre cette coupure, c’est un levier Reduce appliqué à la définition d’un agent : chaque ligne écrite dans le corps est une ligne payée en permanence.
Analogie : le prompt système, c’est l’en-tête pré-imprimé d’un bloc-notes. Il réapparaît, identique, en haut de chaque feuille — on ne le réécrit pas, mais il occupe toujours la même bande de papier. Ce qu’on note en dessous, la remarque du jour, change à chaque page. Un en-tête qui déborde sur la moitié de la feuille laisse d’autant moins de place pour écrire, page après page.
Points clés
- Le corps est le prompt système. Le frontmatter porte la configuration ; le corps Markdown, lui, devient le prompt système du sous-agent. Celui-ci ne reçoit que ce corps, plus l’environnement (répertoire de travail), la hiérarchie
CLAUDE.mdet legit status— pas le prompt système complet de Claude Code. Définir un sous-agent, c’est donc déjà réduire le prompt système par rapport à l’agent principal. - Système = fixe, utilisateur = variable. Le prompt système et les schémas des outils forment le préfixe fixe de la fenêtre : présent à chaque tour, de taille constante. Le prompt utilisateur (le message de délégation, puis le contenu lu et les sorties d’outils) croît avec la tâche.
- Le coût d’un agent « défini », c’est son préfixe fixe. Un corps verbeux et une longue liste d’outils gonflent la part de fenêtre occupée en permanence — celle qui n’accueille pas la vraie tâche. Le prompt système est souvent mis en cache : cela abaisse son coût de retraitement en euros, mais pas son occupation de la fenêtre ni son poids sur l’attention.
- Un drapeau ajoute au prompt système de tous les sous-agents. En mode headless,
--append-subagent-system-prompt(Claude Code v2.1.205+) colle un texte à la fin du prompt système de chaque sous-agent, imbriqués compris : un coût fixe multiplié par le nombre d’agents.
Exemple concret
Un sous-agent code-reviewer tourne sur ~12 tours pour relire un diff. À chaque tour, sa fenêtre se décompose en deux : un préfixe fixe — son corps (prompt système) plus CLAUDE.md, le git status et les schémas de ses outils — et une partie variable — le message de délégation, le git diff lu, ses propres raisonnements. Corps sobre de ~20 lignes → ~500 tokens de prompt système ; avec quatre schémas d’outils (~1 500 tokens), le préfixe fixe pèse ~2 000 tokens, présents à chaque tour. Gonflez le corps à ~120 lignes (persona, check-lists exhaustives, exemples) → ~3 000 tokens : le préfixe fixe passe à ~4 500 tokens, soit ~2 500 tokens de surcharge permanente, occupés à chaque tour avant même que l’agent n’ait lu une ligne du diff. Sur 12 tours, cette bande de fenêtre ne sert jamais la relecture — elle ne fait que diluer l’attention (lois d’échelle inverses, chapitre 2).
Deux prompts, deux régimes de coût
| Aspect | Prompt système (préfixe fixe) | Prompt utilisateur (partie variable) |
|---|---|---|
| Contenu | corps du sous-agent + CLAUDE.md + git status + schémas d’outils | message de délégation, puis contenu lu et sorties d’outils |
| Présence dans la fenêtre | à chaque tour, taille ~constante | à chaque tour, croît avec la tâche |
| Qui le fixe | la définition de l’agent (écrite une fois) | le déroulé de la tâche |
| Levier R&D | Reduce : corps sobre, outils minimaux | déléguer pour que le bruit reste ici, pas chez le parent |
Config — l’anatomie d’un sous-agent : préfixe fixe vs partie variable
---
name: code-reviewer
description: Relit un diff Git. Use proactively apres une modification. # metadonnee : PAS dans le prompt systeme
tools: Read, Grep, Glob, Bash # schemas injectes dans le PREFIXE FIXE
model: sonnet
---
# TOUT ce corps devient le PROMPT SYSTEME du sous-agent : c'est le prefixe
# fixe, present dans sa fenetre a CHAQUE tour. Chaque ligne ajoutee ici est
# une ligne occupee en permanence — d'ou la regle : rester sobre.
Tu es un relecteur de code en lecture seule. ...
Le message de délégation que l’agent principal rédige (le résumé de tâche) n’est pas dans ce fichier : il arrive au moment de l’appel, comme prompt utilisateur.
Commande — ajouter au prompt système de tous les sous-agents
# En mode headless : ce texte est colle a la fin du prompt systeme de CHAQUE
# sous-agent (y compris imbrique) -> un cout fixe multiplie par le nombre d'agents.
claude -p "corrige les tests" \
--append-subagent-system-prompt "Reponds en francais, format court."
Piège courant : croire qu’« un long prompt système ne coûte rien puisqu’il est mis en cache » est inexact. Le cache réduit le coût de retraitement (en euros, en latence), mais les tokens du prompt système occupent toujours la fenêtre à chaque tour et pèsent sur l’attention. Un corps verbeux reste une taxe permanente sur la concentration de l’agent, cache ou pas.
Écrire un bon sous-agent (dossier .claude/agents)
L’idée en une phrase
Un bon sous-agent obéit à la responsabilité unique : une seule mission, une description précise qui sert de déclencheur, un contrat de sortie strict, des outils minimaux et un modèle taillé à la tâche. C’est ce qui fait qu’un Delegate paie vraiment — le bruit reste isolé (chapitre 6) et seul un rapport compact revient au parent (Reduce sur le retour).
Analogie : un bon sous-agent, c’est un couteau d’office — une lame, une fonction, aiguisée. Un mauvais, c’est un couteau suisse à trente lames : on l’ouvre en cherchant la bonne, on se coupe avec une autre, et on ne sait jamais laquelle sortira. La netteté vient du fait de faire une chose, bien.
Points clés
- Responsabilité unique. Un agent = une mission. Un fourre-tout (« relit le code, écrit des tests, refactorise ») ne peut pas avoir de
descriptionprécise : Claude ne sait plus quand déléguer. - La
descriptionest le déclencheur. Claude s’en sert pour décider de déléguer. On l’écrit comme une règle — verbes d’action, cas d’usage concrets, « use proactively quand… ». Vague, elle ne se déclenche jamais, ou au mauvais moment. - Un contrat de sortie explicite. Imposer dans le corps un format de rapport court (« 15 lignes max », «
chemin:ligne, pas de contenu brut »). C’est le levier qui garde compact ce qui revient au parent — sans lui, la délégation renvoie un pavé qui re-pollue la fenêtre principale et annule le bénéfice. - Outils minimaux.
tools:en liste blanche (moindre privilège) oudisallowedTools:en liste noire. Moins d’outils = moins de schémas dans le préfixe fixe (thème précédent) et aucune écriture accidentelle. Un relecteur travaille en lecture seule. - Modèle taillé à la tâche.
haikupour trier et chercher,sonnet/opuspour raisonner (revue, refactor). Champ omis =inherit, soit le modèle du parent (chapitre 6). Les agents intégrésExploreetPlanillustrent la recette : lecture seule, modèle plafonné, périmètre net.
Exemple concret
Deux code-reviewer pour la même intention. Bâclé : description: Relit le code (vague → déléguée au petit bonheur), aucun tools (hérite de tout, Write et Edit compris — il peut modifier du code en « relisant »), corps de ~120 lignes de conseils génériques, aucun contrat de sortie → il renvoie un essai de ~2 500 tokens que l’agent principal doit re-digérer. Net : description: Relit un diff Git après une modification. Use proactively après une écriture de code. (déclencheur précis), tools: Read, Grep, Glob, Bash (lecture et git diff, aucune écriture), model: sonnet (la revue demande du raisonnement), corps de ~20 lignes imposant « rapport classé par sévérité, chemin:ligne, 15 lignes max » → il renvoie ~500 tokens actionnables. Même délégation ; l’un se déclenche au bon moment, ne peut rien casser, et rend un résumé dense — l’autre non.
Sous-agent bâclé vs bien écrit
| Critère | Sous-agent bâclé | Sous-agent bien écrit |
|---|---|---|
| Responsabilité | fourre-tout (« relit le code ») | une mission (« relit un diff Git ») |
description | vague → délégation aléatoire | règle de déclenchement (« use proactively après… ») |
| Outils | tous hérités (Write/Edit inclus) | Read, Grep, Glob, Bash — lecture seule |
| Contrat de sortie | aucun → pavé de ~2 500 tokens | rapport imposé → ~500 tokens |
| Modèle | inherit (gros modèle du parent) | sonnet, taillé à la revue |
Config — les cinq réglages d’un bon sous-agent
---
name: code-reviewer
description: >- # 2. DECLENCHEUR : precis, oriente cas d'usage
Relit un diff Git apres une modification. Use proactively des qu'on vient
d'ecrire ou de modifier du code.
tools: Read, Grep, Glob, Bash # 3. OUTILS minimaux : lecture + git, aucune ecriture
model: sonnet # 4. MODELE taille a la tache : la revue raisonne
---
# 1. RESPONSABILITE UNIQUE : une seule mission, tenue de bout en bout.
Tu es un relecteur de code en lecture seule. Tu observes, tu ne modifies rien.
# 5. CONTRAT DE SORTIE : impose le format ET la longueur du rapport.
# Rapport, 15 lignes max : un verdict, puis une remarque par ligne prefixee
# de sa severite et de `chemin:ligne`. Aucun code recopie.
Piège courant : croire qu’un sous-agent « générique et détaillé » est plus puissant est inexact. Un fourre-tout à la
descriptionvague se déclenche mal, hérite de tous les outils, et sans contrat de sortie renvoie un pavé qui re-pollue le parent — la délégation coûte alors plus qu’elle ne rapporte. La puissance vient de la concentration (chapitre 1) : une mission, un déclencheur net, des outils minimaux, un format de sortie imposé.
Fil rouge — Reduce ou Delegate ?
Ce chapitre affine le Delegate ouvert au chapitre 6, avec une double dose de Reduce. Côté définition de l’agent : le corps est son prompt système, un préfixe fixe présent à chaque tour — le garder sobre (~500 tokens plutôt que ~3 000) et les outils minimaux, c’est réduire ce que la fenêtre du sous-agent porte en permanence. Côté retour : une description-déclencheur précise et un contrat de sortie strict font que le travail bruyant (git diff, lecture des fichiers touchés, ~8 000–15 000 tokens) reste dans la fenêtre isolée — Delegate — et que seul un rapport de ~500 tokens revient au parent, au lieu d’un pavé de ~2 500 — Reduce sur le retour. Un sous-agent bien écrit est donc concentré aux deux bouts : préfixe fixe minimal, charge utile de retour minimale. L’agent principal, lui, garde sa fenêtre dense et son attention intacte (chapitre 2).
Travaux pratiques
À chaque leçon, un petit artefact à déposer dans ton .claude/ — commande, sous-agent, hook, mémo… — pour te bâtir, au fil du livre, une boîte à outils de context engineering réutilisable.
Un sous-agent maison — code-reviewer
Le chapitre 6 a ouvert le tiroir des sous-agents avec researcher (localiser une information). On y ajoute ici un deuxième spécialiste, écrit selon les cinq règles du chapitre : responsabilité unique (relire un diff), description-déclencheur précise, outils minimaux en lecture seule, modèle taillé à la revue (sonnet, qui raisonne), et surtout un contrat de sortie strict. Il incarne Delegate (le git diff et la lecture des fichiers touchés vivent dans sa fenêtre) doublé de Reduce (corps sobre = préfixe fixe minimal ; rapport imposé = retour compact). À déposer dans .claude/agents/code-reviewer.md.
---
name: code-reviewer
description: >-
Relecteur de code en lecture seule. Relit un diff Git (modifications non
committees ou dernier commit) et rend un rapport de revue court, classe par
severite. Use proactively juste apres une ecriture ou une modification de code.
tools: Read, Grep, Glob, Bash
model: sonnet
---
Tu es un relecteur de code experimente, en LECTURE SEULE. Tu ne modifies,
n'ecris et ne commites RIEN : tu observes et tu rapportes.
# Methode
- Recupere le perimetre avec Bash : `git diff` (travail en cours) ou
`git diff HEAD~1` (dernier commit). Ne relis QUE les lignes changees et leur
voisinage immediat.
- Ouvre avec Read uniquement les fichiers touches par le diff. Utilise Grep pour
verifier un appelant ou une dependance en cas de doute — rien de plus.
- Ne recopie pas de gros blocs de code dans ton rapport : cite `chemin:ligne`.
# Grille de revue (dans cet ordre)
1. Correction : bugs, cas limites non geres, erreurs de logique.
2. Securite : entrees non validees, secrets en clair, injections.
3. Lisibilite et nommage : intention claire, pas de complexite inutile.
4. Tests : le changement est-il couvert ?
# Rapport (obligatoire, 15 lignes maximum)
- Une ligne de verdict : `OK`, `A corriger` ou `Bloquant`.
- Puis une remarque par ligne, prefixee de sa severite et de son emplacement :
`[bloquant] chemin:ligne — le probleme, en une phrase`
`[majeur] chemin:ligne — ...`
`[mineur] chemin:ligne — ...`
- Aucun code recopie, aucune reformulation du diff, aucune digression.
Demande une relecture après une modification (« relis mes derniers changements ») : la description déclenche la délégation, le travail bruyant — git diff et lecture des fichiers touchés, ~8 000–15 000 tokens — reste dans la fenêtre du sous-agent, et l’agent principal ne reçoit qu’un rapport de ~500 tokens, classé par sévérité et directement actionnable. Préfixe fixe sobre (~2 000 tokens), retour compact (~500 tokens au lieu de ~2 500) : Reduce aux deux bouts, Delegate pour le bruit — attention préservée pour la vraie tâche.