Prompt système de Claude Code : leçons d’ingénierie pour les concepteurs d’agents
Le mois dernier, j’ai vu un agent de programmation interne supprimer le mauvais fichier généré, « corriger » l’échec du test qu’il avait provoqué, puis annoncer avec assurance que tout avait réussi. Le problème fondamental ne venait pas de la qualité du modèle. Il venait d’une limite mal définie : l’agent avait l’autorisation de modifier trop de choses, des règles vagues concernant les artefacts générés, et aucune confirmation obligatoire avant les actions destructrices.
C’est pourquoi les récentes discussions publiques autour des prompts système de Claude et de Claude Code sont utiles, même s’il ne faut pas considérer les prompts divulgués ou collectés comme parole d’évangile. Les extractions de prompts sont souvent non officielles, incomplètes, obsolètes ou issues d’un état du produit qui n’existe plus. Claude Code lui-même évolue rapidement, et la gamme actuelle de Claude — Opus 4.8, Sonnet 4.6, Haiku 4.5 et Fable 5 avec un contexte de 1M — offre aux concepteurs d’agents des compromis très différents de ceux des générations précédentes.
Mais la leçon intéressante n’est pas « copiez ce prompt ». La leçon utile concerne l’architecture : les agents de programmation matures intègrent les limites opérationnelles, la priorité des instructions, les règles de confirmation, la discipline d’accès aux fichiers et le comportement en cas d’échec dans le système qui entoure le modèle.
Cet article porte sur ces leçons.
Les leçons du prompt système de Claude Code, sans le copier
L’expression « prompt système de Claude Code » est devenue un raccourci pour « comment un agent de programmation sérieux indique-t-il au modèle la manière de se comporter ? ». C’est la mauvaise question si elle conduit à faire de l’archéologie des prompts, mais la bonne si elle conduit à mieux concevoir les agents.
En pratique, le prompt système n’est qu’une couche parmi d’autres. Un agent prêt pour la production dispose généralement d’au moins cinq mécanismes de contrôle qui coopèrent :
| Couche | Ce qu’elle contrôle | Exemple |
|---|---|---|
| Instructions système | Contrat comportemental stable | « Privilégiez les modifications minimales ; ne créez pas de commit sauf si on vous le demande. » |
| Politique du développeur | Règles propres au produit | « Utilisez apply_patch ; n’exécutez jamais de commandes destructrices sans approbation. » |
| Schéma des outils | Ce que le modèle peut réellement faire | read_file, edit_file, run_shell, update_plan |
| Autorisations d’exécution | Ce à quoi le processus est autorisé à accéder | Bac à sable, répertoire de travail, politique réseau |
| Instructions de l’utilisateur | Objectif propre à la tâche | « Corrigez le test d’authentification qui échoue. » |
L’erreur que je constate dans de nombreux agents maison consiste à fusionner tout cela dans un seul gros prompt. Cela fonctionne pour les démonstrations. Cela échoue sous pression.
Une meilleure approche consiste à utiliser le prompt pour expliquer l’intention, et l’environnement d’exécution pour imposer les limites des capacités.
Par exemple, ne vous contentez pas d’une instruction dans le prompt :
Do not delete files unless the user asks.
Faites de la suppression un outil distinct qui exige une confirmation :
{
"name": "delete_file",
"description": "Delete a file from the workspace.",
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" },
"reason": { "type": "string" },
"user_confirmed": { "type": "boolean" }
},
"required": ["path", "reason", "user_confirmed"]
}
}
Puis imposez cette règle en dehors du modèle :
def delete_file(path: str, reason: str, user_confirmed: bool):
if not user_confirmed:
raise PermissionError("delete_file requires explicit user confirmation")
if not path.startswith(WORKSPACE_ROOT):
raise PermissionError("cannot delete files outside workspace")
os.remove(path)
Le prompt indique à l’agent comment réfléchir. Les limites des outils déterminent ce qui peut se produire.
La hiérarchie des instructions est une interface d’ingénierie
Les modèles Claude suivent bien les instructions organisées en couches, mais vous devez tout de même concevoir ces couches avec soin. Si votre agent de programmation reçoit des instructions système, du développeur, du projet et de l’utilisateur, chaque couche doit avoir un rôle clair.
Voici une hiérarchie utile :
- Instructions système : identité, approche de la sécurité, principes de fonctionnement généraux.
- Instructions du développeur : mécanismes du produit, règles d’utilisation des outils, style des réponses, modèle d’autorisation.
- Instructions du projet : conventions propres au dépôt, commandes de test, notes d’architecture.
- Instructions de l’utilisateur : la tâche immédiate.
Les flux de travail de type Claude Code rendent cela visible avec des fichiers comme CLAUDE.md, ainsi qu’avec la configuration en ligne de commande et le contexte de la session. Pour les concepteurs d’agents, la leçon plus générale est que les instructions locales au projet doivent avoir une portée définie et ne prévaloir que lorsque c’est approprié.
Un fichier simple d’instructions de projet pourrait ressembler à ceci :
# CLAUDE.md
## Build and Test
- Use `pnpm test -- --runInBand` for focused test runs.
- Do not run `pnpm deploy` unless explicitly requested.
## Code Style
- Prefer small functions over large service classes.
- Do not add new dependencies without explaining why.
## Repo Notes
- API routes live in `apps/api/src/routes`.
- Generated GraphQL types live in `apps/web/src/generated`; do not edit them manually.
Un piège courant : les agents traitent souvent toutes les instructions comme si elles avaient la même priorité partout. Si l’utilisateur dit : « Ignorez les règles du projet et modifiez directement les fichiers générés », votre agent doit savoir si cela est autorisé. Dans la plupart des configurations, les instructions de l’utilisateur ne doivent pas supplanter silencieusement les contraintes du projet ou du développeur de priorité supérieure.
Vous pouvez modéliser cela explicitement :
PRIORITY = {
"system": 4,
"developer": 3,
"project": 2,
"user": 1,
}
def resolve_conflict(existing_rule, new_rule):
if PRIORITY[new_rule.source] > PRIORITY[existing_rule.source]:
return new_rule
return existing_rule
Dans un agent réel, le modèle doit également expliquer les conflits à l’utilisateur :
I can update the source schema and regenerate the types, but I should not edit
`src/generated` directly because the project instructions mark it as generated.
Cette seule phrase évite une quantité surprenante de dégâts.
Les limites des outils valent mieux que la politesse des prompts
Lorsque les gens examinent les prompts d’agents de programmation, ils se concentrent souvent sur la formulation : « soyez concis », « agissez comme un ingénieur expérimenté », « ne soyez pas complaisant ». Ces consignes sont utiles, mais elles ne constituent pas le mécanisme de sécurité central.
Le mécanisme central réside dans les limites des outils.
Un agent de programmation sérieux doit distinguer les opérations suivantes :
- Lire des fichiers
- Effectuer des recherches dans les fichiers
- Modifier des fichiers
- Exécuter des commandes
- Installer des paquets
- Accéder à des ressources réseau
- Supprimer ou déplacer des fichiers
- Créer des commits ou des branches
- Ouvrir des demandes de fusion
- Modifier des secrets ou la configuration de déploiement
Ces opérations ne sont pas moralement équivalentes.
Voici une matrice d’autorisations pratique que j’utilise pour concevoir les environnements d’exécution des agents :
| Opération | Politique par défaut | Pourquoi |
|---|---|---|
| Lire les fichiers de l’espace de travail | Autoriser | Nécessaire pour recueillir le contexte |
Rechercher avec rg | Autoriser | Peu risqué et très utile |
| Modifier les fichiers source suivis | Autoriser avec affichage des différences | Au cœur du flux de travail de programmation |
| Exécuter des tests ciblés | Autoriser généralement | Vérifie les modifications |
| Installer des dépendances | Demander | Modifie l’environnement et les fichiers de verrouillage |
| Supprimer des fichiers | Demander | Peut facilement entraîner une perte irréversible |
| Accéder au réseau | Demander ou refuser | Peut entraîner une fuite de données ou introduire du non-déterminisme |
| Modifier des secrets | Refuser par défaut | Conséquences potentielles très étendues |
| Créer un commit des modifications | Demander | L’historique du dépôt appartient à l’utilisateur |
| Déployer | Refuser sauf demande explicite | Impact sur la production |
C’est aussi là que le choix du modèle compte. J’apprécie les modèles de la catégorie Sonnet pour la plupart des boucles d’exécution d’agents de programmation, car ils offrent un bon équilibre entre latence, coût et raisonnement. Opus 4.8 est le modèle vers lequel je me tournerais lorsque l’agent a besoin d’une synthèse architecturale plus approfondie ou d’un débogage complexe. Haiku 4.5 convient à la classification rapide et à l’exploration légère des dépôts. Le contexte de 1M de Fable 5 est intéressant pour comprendre de grandes bases de code, mais un contexte étendu ne dispense pas d’une bonne recherche d’informations, de lectures au périmètre défini et d’une utilisation rigoureuse des outils.
Un million de tokens de contexte peut tout de même contenir le mauvais fichier.
La confirmation de l’utilisateur doit être précise, pas cérémonielle
Une mauvaise expérience de confirmation ressemble à ceci :
May I proceed?
Poursuivre quoi ? Modifier un fichier ? Exécuter des migrations ? Supprimer un répertoire ?
Une bonne confirmation est concrète :
I need confirmation before running:
`rm -rf apps/web/.next`
Reason: remove a stale Next.js build cache that may be causing the local
runtime error. This deletes only generated build output and does not touch
source files.
Pour les agents de type Claude Code, c’est important, car le modèle peut déduire correctement l’étape suivante tout en ayant besoin d’une autorisation humaine. Si chaque demande sollicite une approbation vague, les utilisateurs se lassent et valident sans réfléchir. Si seules les opérations à haut risque exigent une confirmation précise, les utilisateurs restent attentifs.
Je recommande de représenter la confirmation sous forme d’état structuré, plutôt que de texte libre :
{
"action": "run_shell",
"command": "rm -rf apps/web/.next",
"risk": "destructive_generated_artifact",
"requires_confirmation": true,
"confirmation_prompt": "Delete generated Next.js cache at apps/web/.next?"
}
Votre exécuteur de commandes shell peut alors la faire respecter :
def run_shell(command, confirmed=False):
risk = classify_command(command)
if risk.requires_confirmation and not confirmed:
return {
"status": "needs_confirmation",
"message": risk.prompt
}
return subprocess.run(command, shell=True, cwd=WORKSPACE_ROOT)
En pratique, la classification des commandes ne sera jamais parfaite. Ce n’est pas un problème. Utilisez des valeurs par défaut prudentes. Si votre classificateur ne sait pas si une commande est destructive, demandez confirmation.
Commandes à traiter avec précaution
Celles-ci méritent une politique explicite :
rm -rf path
git reset --hard
git clean -fd
git push --force
npm install some-package
pip install -r requirements.txt
docker compose down -v
kubectl delete ...
terraform apply
Certaines sont inoffensives dans le bon contexte. D’autres sont catastrophiques dans le mauvais. L’agent doit comprendre que cette différence dépend du contexte et demander confirmation lorsque l’étendue des conséquences est incertaine.
L’accès aux fichiers relève de l’ingénierie du contexte
L’accès aux fichiers est l’aspect le plus sous-estimé de la conception des agents de programmation. Le prompt peut dire « examinez d’abord les fichiers pertinents », mais l’environnement d’exécution doit faciliter ce comportement.
Au minimum, fournissez au modèle des outils pour :
- Trouver rapidement des fichiers par leur nom
- Rechercher du texte
- Lire des plages limitées de fichiers
- Consulter les diffs git
- Appliquer des correctifs de manière atomique
Un ensemble minimal d’outils pourrait ressembler à ceci :
[
{
"name": "search_files",
"input_schema": {
"type": "object",
"properties": {
"query": { "type": "string" },
"glob": { "type": "string" }
},
"required": ["query"]
}
},
{
"name": "read_file",
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" },
"start_line": { "type": "integer" },
"limit": { "type": "integer" }
},
"required": ["path"]
}
},
{
"name": "apply_patch",
"input_schema": {
"type": "object",
"properties": {
"patch": { "type": "string" }
},
"required": ["patch"]
}
}
]
Il est important de limiter les lectures. Si l’agent lit chaque fichier d’un monorepo, il gaspille du contexte et ses performances sont souvent moins bonnes. S’il en lit trop peu, il devine. Le bon équilibre consiste à acquérir le contexte de manière itérative :
rg "createSession|verifySession|SessionStore" apps packages
sed -n '1,220p' apps/api/src/auth/session.ts
sed -n '1,180p' apps/api/src/routes/login.ts
git diff -- apps/api/src/auth/session.ts
Les utilisateurs de Claude Code reconnaîtront ce rythme : rechercher, examiner, modifier, vérifier. Les concepteurs d’agents devraient intégrer cette boucle au comportement par défaut.
Un piège courant : les outils de manipulation de fichiers doivent préserver les fins de ligne, les permissions et l’encodage attendu. J’ai vu des agents réécrire « avec succès » des scripts shell en supprimant les permissions d’exécution, ou normaliser des fichiers d’une manière qui génère des diffs encombrés de changements superflus. Votre couche d’édition doit être sans surprise et prudente.
Modes de défaillance : ce qui se passe réellement quand les agents déraillent
La plupart des agents de programmation n’échouent pas de manière spectaculaire. Leurs échecs paraissent plausibles.
Voici les modes de défaillance que je rencontre le plus souvent.
1. L’agent corrige le symptôme
Le test échoue parce qu’une API renvoie 401. L’agent modifie le test pour qu’il attende 401. Le build passe, mais le produit est cassé.
Mesures d’atténuation :
- Exigez que l’agent explique la chaîne causale.
- Demandez des tests ciblés avant des réécritures de grande ampleur.
- Privilégiez les corrections du code source plutôt que les mises à jour des snapshots, sauf si l’utilisateur a demandé un changement de comportement.
2. L’agent modifie trop de choses
L’utilisateur demande une petite correction de bug. L’agent reformate cinq fichiers, renomme des variables et modifie des API publiques.
Mesures d’atténuation :
Make the minimal change that fixes the issue. Do not perform opportunistic
refactors unless they are necessary for correctness.
Mais imposez aussi une revue des diffs. Affichez les fichiers modifiés et le nombre de lignes concernées avant de finaliser :
git diff --stat
git diff -- apps/api/src/auth/session.ts
3. L’agent se fie à un contexte obsolète
Les sessions longues accumulent des hypothèses dépassées. L’utilisateur modifie un fichier en dehors de la session, les tests échouent désormais différemment, et l’agent continue avec son ancien modèle mental.
Mesures d’atténuation :
- Relisez les fichiers avant de les modifier s’ils ont pu changer.
- Vérifiez
git diffavant d’appliquer des correctifs. - Considérez les sorties des outils comme plus à jour que la mémoire de la conversation.
4. L’agent masque l’échec d’un outil
Une commande shell échoue, mais l’agent poursuit comme si elle avait réussi.
Mesure d’atténuation : les résultats des outils doivent être structurés et difficiles à ignorer.
{
"tool": "run_shell",
"command": "pnpm test auth",
"exit_code": 1,
"stdout": "...",
"stderr": "Cannot find module '@repo/config'",
"status": "failed"
}
Donnez ensuite cette instruction à l’agent :
If a tool call fails, do not claim success. Diagnose the failure or clearly
report the blocker.
5. L’agent écrit des secrets dans le contexte
Si l’agent peut lire .env, des dumps de plantage ou la configuration de production, il peut accidentellement inclure des secrets dans des résumés, des journaux ou des prompts.
Mesures d’atténuation :
- Bloquez par défaut les fichiers connus pour contenir des secrets.
- Masquez les valeurs ressemblant à des jetons dans les sorties des outils.
- Exigez une approbation explicite de l’utilisateur pour les chemins contenant des secrets.
Exemple de politique d’accès aux chemins :
DENY_PATTERNS = [
".env",
".env.*",
"**/secrets/**",
"**/*.pem",
"**/*.key",
]
def can_read(path):
return not any(fnmatch(path, pattern) for pattern in DENY_PATTERNS)
Demander au modèle de ne pas divulguer de secrets est une bonne chose. L’empêcher de voir des secrets inutiles est encore mieux.
Concevoir une boucle d’agent avec l’API Claude
Si vous développez directement avec l’API Claude, la boucle utile la plus simple est la suivante :
- Envoyez les instructions système et développeur.
- Fournissez la tâche de l’utilisateur.
- Laissez Claude demander des appels d’outils.
- Exécutez les outils dans votre environnement d’exécution.
- Renvoyez les résultats des outils.
- Répétez jusqu’à ce que le modèle produise une réponse finale.
Une requête simplifiée ressemble à ceci :
{
"model": "claude-sonnet-4-6",
"max_tokens": 4096,
"system": "You are a coding agent. Make minimal, correct changes...",
"messages": [
{
"role": "user",
"content": "Fix the auth timeout bug and add a regression test."
}
],
"tools": [
{
"name": "read_file",
"description": "Read a bounded section of a workspace file.",
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" },
"start_line": { "type": "integer" },
"limit": { "type": "integer" }
},
"required": ["path"]
}
}
]
}
Une réponse demandant l’utilisation d’un outil ressemble, sur le plan conceptuel, à ceci :
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "I’ll inspect the auth timeout path first."
},
{
"type": "tool_use",
"name": "read_file",
"id": "toolu_123",
"input": {
"path": "apps/api/src/auth/session.ts",
"start_line": 1,
"limit": 220
}
}
]
}
Votre environnement d’exécution renvoie ensuite le résultat :
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_123",
"content": "export function createSession(...) { ... }"
}
]
}
La syntaxe exacte du SDK dépend de la version de votre client, mais le principe de conception reste le même : Claude propose des actions, votre environnement d’exécution les exécute ou les rejette, et le modèle reçoit le résultat au tour suivant.
C’est cette séparation qui permet de garder le système compréhensible.
Commandes et paramètres de Claude Code à étudier
Même si vous n’utilisez pas directement Claude Code, son flux de travail fournit des modèles de conception de produit utiles.
Initialisation typique d’un projet :
claude
/init
Cela crée ou met à jour les consignes du projet afin que les sessions futures comprennent les conventions propres au dépôt.
Une session pratique ressemble souvent à ceci :
claude "Find why the billing webhook test is flaky. Do not edit files yet."
claude "Patch the smallest fix and run the focused test."
claude "Show me the diff and summarize remaining risks."
J’aime cette approche parce qu’elle sépare l’investigation, la modification et la vérification. Les concepteurs d’agents peuvent reproduire cette séparation sous forme de modes :
{
"mode": "investigate",
"can_edit": false,
"can_run_tests": true,
"requires_confirmation_for": ["network", "delete", "install"]
}
Passez ensuite explicitement d’un mode à l’autre :
{
"mode": "implement",
"can_edit": true,
"can_run_tests": true,
"requires_confirmation_for": ["network", "delete", "install", "commit"]
}
L’important n’est pas la commande précise, mais le contrat d’interaction. Les utilisateurs doivent savoir quand l’agent se contente de lire, quand il modifie des fichiers et quand il s’apprête à effectuer une action ayant des effets de bord.
Pourquoi les copies de prompts sont fragiles
Le dépôt GitHub qui rassemblait des prompts système et des configurations de modèles est devenu populaire parce que les ingénieurs sont naturellement curieux de savoir quelles instructions reçoivent les outils réels. Je comprends cet attrait. Lire des prompts peut révéler la sensibilité des concepteurs en matière de produit : les risques qui les préoccupent, les flux de travail qu’ils optimisent et la manière dont ils s’adressent au modèle.
Mais les prompts copiés sont fragiles pour plusieurs raisons :
- Ils peuvent ne pas être officiels. Vous ne savez pas forcément comment ils ont été extraits ni s’ils sont complets.
- Ils peuvent être obsolètes. Les prompts des agents évoluent à mesure que les modèles, les outils et les politiques produit changent.
- Ils dépendent de comportements cachés de l’environnement d’exécution. Un prompt qui mentionne un outil est inutile sans l’implémentation de cet outil.
- Ils intègrent des compromis propres au produit. Les contraintes de Claude Code peuvent ne pas correspondre au modèle de menace de votre agent.
- Ils peuvent donner un faux sentiment de confiance. Un prompt soigné ne fait pas respecter les permissions.
Utilisez ces éléments comme source d’inspiration pour la conception, pas comme dépendances.
Un meilleur exercice consiste à se demander : quel problème cette instruction résout-elle ? Résolvez ensuite ce problème dans votre propre stack, avec le soutien du prompt et de l’environnement d’exécution.
Conseils pratiques
- Considérez la
Claude Code system promptconversation comme une discussion d’architecture, pas comme une occasion de faire du copier-coller. - Placez les comportements stables dans les instructions système et développeur, les conventions du dépôt dans les fichiers du projet et les objectifs de la tâche dans les messages utilisateur.
- Faites respecter les limites à haut risque dans les outils et les permissions de l’environnement d’exécution, pas seulement dans le texte.
- Exigez une confirmation précise pour les actions destructives, celles qui utilisent le réseau, celles qui modifient les dépendances ou celles qui affectent la production.
- Donnez à l’agent un accès limité aux fichiers, une recherche rapide, l’application atomique de correctifs et des rapports structurés sur les échecs des outils.
- Optimisez la boucle qui fonctionne en pratique : examiner, planifier, modifier le strict nécessaire, vérifier, résumer les risques.
- Partez du principe que les prompts copiés peuvent être obsolètes ou incomplets ; construisez un comportement d’agent durable autour de capacités explicites et d’une gestion claire des échecs.
Une seule clé API pour Claude Opus 5.5, Sonnet 5, Haiku 4.5 et Fable 5.1, ainsi que GPT-6 modèles. Paiement à l’usage, sans abonnement.
Obtenir votre clé API →