Un agent de code se règle avec une poignée de briques. Elles ne se ressemblent pas : certaines sont du
texte que le modèle lit et peut oublier, d'autres sont exécutées par l'outil et tiennent quoi qu'il arrive.
Chaque fiche dit pourquoi la brique existe, quand s'en servir, où elle vit, et montre un vrai fichier.
Lu par le modèle, ou exécuté par l'outil
suggéré Le modèle lit
Du texte qui entre dans sa fenêtre de contexte. Il le suit presque toujours, mais peut l'oublier ou s'en écarter.
barrière Un troisième cas : le bac à sable, où c'est le système d'exploitation qui contraint la commande elle-même, quoi qu'elle dise. Une brique « mixte » a les deux premiers : un sous-agent suit son texte, mais ne peut utiliser que les outils permis. Un plugin vaut ce qu'il contient. Page écrite pour Claude Code ; Codex lit le même AGENTS.md, et ses autres emplacements sont dans le README de Kwa.
Le trajet d'une commande
L'agent veut lancer git commit. Voici, dans l'ordre, ce qui peut l'arrêter. Chaque étape est une brique.
Un projet qui utilise toutes les briques. Rien n'est obligatoire : la plupart des projets commencent par AGENTS.md et une ou deux règles.
mon-projet/
├── AGENTS.md instructions, lues à chaque session
├── CLAUDE.md @AGENTS.md (un pointeur)
├── .mcp.json serveurs MCP du projet
└── .claude/
├── settings.json permissions et hooks (partagés)
├── settings.local.json vos réglages à vous (hors git)
├── rules/ règles par sujet
│ └── composants.md
├── skills/ procédures
│ └── release-notes/
│ ├── SKILL.md
│ └── modele.md annexe, lue au besoin
├── agents/ sous-agents
│ └── security-reviewer.md
├── hooks/ scripts des hooks
│ ├── no-commit-on-main.py
│ └── format.ts
└── kwa.policy.json avec Kwa : la politique du projet
~/.claude/ les mêmes dossiers, pour tous vos projets
├── CLAUDE.md ├── rules/ ├── skills/ ├── agents/ └── settings.json
La fenêtre de contexte, au fil d'une session
Ce que chaque brique fait entrer dans la fenêtre, et ce qui en sort à la compaction. Avancez pas à pas.
Démarrage
Lecture de src/Button.tsx
Appel de /release-notes
Relecture par un sous-agent
Après /compact
chargé au démarrage
règle
skill
le travail de la session
Portées : qui l'emporte
Une brique peut exister chez vous, dans le projet, dans un plugin ou être imposée par l'organisation. Quand elle existe deux fois, la règle n'est pas la même partout.
réglages personnels, du projet, locaux, gérés · plugin · en-tête d'une skill ou d'un agent
Tous s'additionnent et tournent en parallèle. Un hook identique dans deux fichiers de réglages ne tourne qu'une fois ; la copie d'un plugin ou d'une skill tourne en plus.
Activé ou non : local, puis projet, puis le vôtre ; l'organisation peut l'imposer.
Instructions (AGENTS.md)
Ce que l'agent doit savoir sur le projet, à chaque session.
suggéré
Pourquoi
Une session repart de zéro. Ce fichier transmet ce que l'agent ne peut pas deviner en lisant le code : les commandes de vérification, les pièges, les interdits.
Quand l'utiliser
Un fait valable partout et tout le temps : comment lancer les tests, le port du serveur, la convention de branche.
Quand ce n'est pas le bon outil
Une consigne qui ne concerne qu'une partie du code (une règle), une procédure longue (une skill), une interdiction qui doit tenir (un hook).
Qui le déclenche
Personne : il est chargé au démarrage de chaque session.
Où il vit
AGENTS.md à la racine ; CLAUDE.md pour Claude Code, qui peut n'être qu'un pointeur.
Ce qu'il coûte au contexte
Toujours dans la fenêtre : restez court.
Sous Codex
AGENTS.md du projet, et ~/.codex/AGENTS.md ; du dossier racine au dossier courant, le plus proche pèse le plus.
Vérifier que ça marche
/context dans une session : AGENTS.md (ou CLAUDE.md) dans la liste des fichiers de mémoire chargés.
# AGENTS.md
Application web (Next.js, pnpm). Répondre en français.
## Vérifier avant de dire « fait »-`npx tsc --noEmit` puis `pnpm test` : citer le résultat.
-`pnpm lint` signale à tort les fichiers générés : lancer `pnpm lint src`.
## Pièges- Le serveur de développement écoute sur le port 4000, fixé dans `.env.example`.
- Après un changement de schéma : `pnpm db:migrate:create <nom>` puis `pnpm db:migrate`.
## Interdit- Pas de commit sur main : une branche par sujet, une PR par branche.
@AGENTS.md
@AGENTS.md un import : Claude Code lit AGENTS.md à la place, et Codex lit AGENTS.md directement. Un seul fichier à tenir.
pourquoi le garder Claude Code récent lit AGENTS.md même sans ce pointeur, mais un simple CLAUDE.local.md suffit à le lui faire ignorer. Le pointeur évite ce piège.
Une consigne rangée par sujet, chargée quand elle sert.
suggéré
Pourquoi
Quand AGENTS.md grossit, tout y est lu à chaque fois. Une règle isole un sujet ; avec paths, elle n'entre dans le contexte que quand l'agent touche un fichier concerné.
Quand l'utiliser
Une convention propre à un dossier ou à un type de fichier : les composants React, les migrations, l'API.
Quand ce n'est pas le bon outil
Un fait général (AGENTS.md) ou une étape à exécuter dans l'ordre (une skill).
Qui le déclenche
Personne : chargée au démarrage, ou quand l'agent lit, écrit ou modifie un fichier qui correspond à paths (après une compaction, elle revient au prochain fichier concerné).
Où il vit
.claude/rules/*.md dans le projet, ~/.claude/rules/ pour vous.
Ce qu'il coûte au contexte
Au démarrage sans paths ; seulement au besoin avec.
Sous Codex
pas d'équivalent : un AGENTS.md par sous-dossier joue ce rôle.
Vérifier que ça marche
/context, puis demander à l'agent de modifier un fichier .tsx : la règle apparaît dans le contexte après la lecture du fichier.
---paths:
- "src/**/*.tsx"---# Composants React- Tester avec Testing Library, jamais avec Enzyme.
- Un composant par fichier, nommé comme le fichier.
- Pas de style en ligne : les classes du design system.
--- … --- l'en-tête, en YAML : des paires « clé: valeur » que l'outil lit, le modèle ne les voit pas comme du texte.
paths les fichiers concernés. ** veut dire « dans tous les sous-dossiers », *.tsx « tout fichier qui finit par .tsx ». Sans paths, la règle est lue à chaque session, comme AGENTS.md : on la range à part seulement pour garder AGENTS.md court.
Une procédure que l'agent suit quand la situation correspond.
suggéré
Pourquoi
Une tâche qui revient se fait toujours de la même façon. La skill l'écrit une fois ; seule sa description reste dans le contexte, le corps n'est lu qu'à l'appel.
Quand l'utiliser
Une procédure à étapes, déclenchée par une demande : rédiger des notes de version, livrer une PR, déboguer.
Quand ce n'est pas le bon outil
Un fait à connaître en permanence (AGENTS.md) ou une contrainte qui doit tenir même si l'agent l'oublie (un hook).
Qui le déclenche
Le modèle, quand la description correspond à la demande ; ou vous, en tapant /release-notes.
Où il vit
.claude/skills/<nom>/SKILL.md, ses annexes à côté ; ~/.claude/skills/ pour vous ; ou un plugin.
Ce qu'il coûte au contexte
La description (1 536 caractères au plus) dès le démarrage. Une fois appelée, le corps reste dans la conversation jusqu'à la fin ; après une compaction, les skills appelées sont réattachées (5 000 jetons chacune, 25 000 au total), mais la liste des descriptions ne revient pas : l'agent ne pense plus tout seul aux skills qu'il n'a pas encore utilisées. Vous pouvez toujours la lancer avec /nom.
Sous Codex
.agents/skills/<nom>/SKILL.md ou ~/.agents/skills/, même format ; on l'appelle avec $nom.
Vérifier que ça marche
/skills, puis taper /release-notes : la skill dans la liste ; à l'appel, l'agent suit ses étapes.
Les pièges
Un champ mal orthographié dans l'en-tête est ignoré sans erreur.
Une skill personnelle (~/.claude/skills/) l'emporte sur une skill du projet qui porte le même nom.
disable-model-invocation: true la réserve à vous : utile pour ce qui a des effets (déployer, publier).
---name: release-notes
description: Rédiger les notes de version à partir des PR fusionnées. À utiliser quand l'utilisateur demande « les notes de version », « le changelog » ou « qu'est-ce qui part en prod ».
---# Notes de version
1. Lister les PR fusionnées depuis la dernière étiquette :
`gh pr list --state merged --search "merged:>=<date>"`.
2. Les classer : nouveautés, corrections, technique.
3. Une ligne par PR, au présent, sans jargon interne.
4. Suivre le gabarit de `modele.md` (dans ce dossier).
name le nom de la commande : /release-notes. Dans un plugin, il prend le préfixe du plugin (/kwa:tdd) ; sous Codex, on tape $ au lieu de /.
description la seule partie toujours chargée. Le modèle la compare à votre demande pour décider d'appeler la skill : dites quand l'utiliser, avec les mots que l'on emploie vraiment.
modele.md une annexe : lue seulement si la skill en a besoin, donc gratuite le reste du temps.
## Version <x.y.z> (<date>)### Nouveautés- …
### Corrections- …
Un second collaborateur, avec sa propre fenêtre de contexte.
mixte
Pourquoi
Lire trente fichiers remplit la fenêtre de l'agent principal. Un sous-agent le fait à part et ne rend qu'un résumé. Il peut aussi avoir moins d'outils : un relecteur qui ne peut pas écrire relit mieux.
Quand l'utiliser
Un travail de lecture volumineux, une relecture indépendante, plusieurs tâches en parallèle.
Quand ce n'est pas le bon outil
Une petite tâche : le brief et le résumé coûtent plus que de la faire dans la session.
Qui le déclenche
Le modèle, ou une skill qui le lance ; vous, en le nommant : tapez @ et choisissez-le, ou écrivez @agent-security-reviewer relis mon diff.
Où il vit
.claude/agents/<nom>.md ; ~/.claude/agents/ pour vous ; ou un plugin.
Ce qu'il coûte au contexte
Sa propre fenêtre, où il relit les fichiers d'instructions ; seul son résumé revient. La description de chaque sous-agent reste dans la fenêtre principale.
Sous Codex
un fichier TOML dans .codex/agents/ ou ~/.codex/agents/ (name, description, developer_instructions).
Vérifier que ça marche
écrire @agent-security-reviewer relis mon diff : l'agent lance le sous-agent, qui travaille à part puis rend son résumé.
---name: security-reviewer
description: Relit un diff sous l'angle de la sécurité (entrées non validées, secrets, droits). À utiliser avant une PR qui touche l'authentification, les paiements ou les données personnelles.
tools: Read, Grep, Glob
model: sonnet
---
Tu relis un changement sans le modifier. Pour chaque constat : le fichier et la
ligne, ce qui peut arriver, comment le reproduire, la gravité. Si rien ne pose
problème, dis-le en une phrase : n'invente pas de constat.
tools les seuls outils qu'il aura : ici lire et chercher, pas écrire. C'est l'outil qui l'applique : la partie imposée d'un sous-agent. Le reste du fichier est du texte qu'il suit.
model le modèle qui le fait tourner : sonnet, opus, haiku, ou inherit pour celui de la session. Absent, Claude Code choisit selon ses réglages, en général celui de la session.
le texte sous l'en-tête ses consignes. Il ne voit rien de votre conversation : seulement la tâche que l'agent principal lui donne. Sans Bash, il ne lance pas git diff : le diff lui est fourni dans la demande (le relecteur de Kwa a Bash, en lecture seule, gardé par un hook).
Un script que l'outil exécute à un moment précis, sans demander au modèle.
imposé
Pourquoi
Une instruction peut être oubliée. Un hook ne dépend pas du modèle : Claude Code l'exécute, toujours, avant ou après un outil, au démarrage, à la fin d'une réponse. Mais il juge un texte : une commande formulée autrement peut lui échapper. C'est un filet contre l'erreur ; une vraie barrière, c'est le bac à sable ou la protection de branche.
Quand l'utiliser
Refuser une action (commit sur main, lecture d'un secret), formater après une écriture, réinjecter du contexte au démarrage.
Quand ce n'est pas le bon outil
Une décision qui demande du jugement : un hook lit du texte, il ne comprend pas l'intention.
Qui le déclenche
Claude Code, à l'événement choisi (PreToolUse, PostToolUse, SessionStart, Stop…).
Où il vit
Déclaré dans .claude/settings.json ; le script où vous voulez, souvent .claude/hooks/. Python, TypeScript, bash : n'importe quel langage qui lit l'entrée standard.
Ce qu'il coûte au contexte
Aucun, sauf ce qu'il renvoie à l'agent.
Sous Codex
.codex/hooks.json, ~/.codex/hooks.json ou des tables [hooks] dans config.toml. Des événements de même nom (PreToolUse, PostToolUse, Stop, SessionStart…), mais une douzaine au lieu d'une trentaine. Les hooks du projet ne se chargent que si le projet est approuvé, et chaque hook doit être validé dans /hooks, puis revalidé s'il change.
Vérifier que ça marche
/hooks, puis demander un commit sur main : le hook dans la liste ; le commit est refusé avec la raison du script.
Les pièges
Sortie du script
Avant l'outil (PreToolUse)
Après (PostToolUse)
Fin de réponse (Stop)
0 sans rien
pas d'avis
rien
l'agent s'arrête
0 et un JSON
la décision du JSON (deny, ask, allow)
un retour pour l'agent
peut demander de continuer
2
refus, la sortie d'erreur part à l'agent
trop tard : l'outil a déjà tourné
l'agent repart travailler
1 ou autre
erreur sans effet : l'action continue
Tous les hooks d'un même événement tournent en parallèle, sans ordre : deux formateurs sur le même fichier se marchent dessus.
Un hook Stop qui refuse toujours fait boucler l'agent : testez stop_hook_active ; Claude Code rend la main après 8 relances d'affilée.
Un hook peut être déclaré ailleurs : réglages personnels ou locaux, plugin, en-tête d'une skill ou d'un agent. /hooks les montre tous.
PreToolUse, PostToolUse l'événement : avant ou après un outil. Il en existe une trentaine (démarrage, fin de réponse…).
matcher le nom de l'outil visé : Bash (le terminal), Edit|Write (l'un ou l'autre).
type: command le hook est un programme à lancer ; command est sa ligne de commande.
$CLAUDE_PROJECT_DIR la racine du projet, remplie par Claude Code : le chemin marche quel que soit le dossier courant.
#!/usr/bin/env python3"""PreToolUse : refuser git commit sur main. Un filet contre l'erreur, pas une barrière."""
import json
import re
import subprocess
import sys
COMMIT = re.compile(r"\bgit(\s+-[cC]\s+\S+)*\s+commit\b") # git commit, git -C dir commit, git -c x=y commit
def refuse(reason):
print(json.dumps({"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": reason,
}}))
sys.exit(0)
try:
event = json.load(sys.stdin) # ce que l'agent s'apprête à faire
command = event.get("tool_input", {}).get("command", "")
parts = re.split(r"&&|\|\||;|\|", command) # cd app && git commit : chaque morceau compteif not any(COMMIT.search(p) for p in parts):
sys.exit(0) # sans sortie : la décision suit son cours normal
branch = subprocess.run(["git", "branch", "--show-current"], cwd=event.get("cwd"),
capture_output=True, text=True, check=True).stdout.strip()
except Exception as error: # un garde qui plante doit refuser, pas laisser passer
refuse(f"Garde en erreur ({error}) : vérifier le hook avant de committer.")
if branch == "main":
refuse("Pas de commit sur main : créer une branche de travail.")
json.load(sys.stdin) Claude Code envoie sur l'entrée standard ce que l'agent s'apprête à faire : l'outil, sa commande, le dossier.
re.split(…)cd app && git commit est une seule commande pour l'outil : on la découpe, sinon le commit passe.
sys.exit(0) sans rien afficher « pas d'avis » : l'action suit son cours normal (permissions, demande éventuelle).
permissionDecision: deny le refus. La raison est renvoyée à l'agent, qui la lit et change de cap : ici, il crée une branche.
except Exception un script qui plante sort en code 1, ce qui ne bloque rien : un garde doit attraper ses propres erreurs et refuser.
ou bien exit 2 l'autre façon de refuser : écrire la raison sur la sortie d'erreur et sortir avec le code 2. Le JSON permet en plus ask (demander) ou allow.
// PostToolUse : formater le fichier que l'agent vient d'écrire.
import { execFileSync } from "node:child_process";
import { readFileSync } from "node:fs";
const event = JSON.parse(readFileSync(0, "utf8"));
const file: string | undefined = event.tool_input?.file_path;
if (file && /\.(ts|tsx|css)$/.test(file)) {
execFileSync("npx", ["--no-install", "prettier", "--write", file], { stdio: "ignore" });
}
readFileSync(0) lit l'entrée standard, comme le script Python : n'importe quel langage fait l'affaire.
npx --no-install utilise le prettier du projet sans rien télécharger ; un hook n'apporte pas ses dépendances (ici Node.js, tsx, prettier).
le fichier change sous l'agent après formatage, la prochaine modification de l'agent peut échouer sur un texte qui n'existe plus : il relit le fichier et recommence.
Des outils et des données branchés sur l'agent : une doc, un navigateur, une base.
suggéré
Pourquoi
L'agent ne voit que son dépôt. Un serveur MCP lui ajoute des outils, que le modèle découvre et décide d'appeler : chercher dans une doc à jour, piloter un navigateur, lire une base.
Quand l'utiliser
Un accès à un service ou à des données hors du dépôt.
Quand ce n'est pas le bon outil
Une procédure (une skill) ; un serveur que vous ne connaissez pas : il agit avec vos droits. En session interactive, Claude Code demande avant d'utiliser les serveurs d'un .mcp.json ; en claude -p et dans le SDK, il les charge sans demander.
Qui le déclenche
Le modèle, qui appelle ses outils (mcp__context7__…).
Où il vit
.mcp.json à la racine du projet (partagé) ; claude mcp add l'ajoute pour ce projet et vous seul, --scope user pour tous vos projets.
Ce qu'il coûte au contexte
Les noms des outils ; leurs définitions à la demande.
Sous Codex
une table [mcp_servers.<nom>] dans ~/.codex/config.toml, ou codex mcp add.
Vérifier que ça marche
/mcp : le serveur connecté et ses outils.
Les pièges
Un même serveur déclaré à plusieurs endroits : la définition locale gagne, puis celle du projet, puis la vôtre, puis celle d'un plugin.
Un dépôt cloné peut apporter un .mcp.json : en claude -p ou en CI, il est chargé sans demander. disabledMcpjsonServers en exclut un.
approval_policy dans config.toml, et des règles de commandes prefix_rule(…) dans .codex/rules/*.rules.
Vérifier que ça marche
/permissions : vos règles, rangées par portée (projet, local, personnel).
Les pièges
Un deny de n'importe quel fichier de réglages l'emporte sur un allow d'un autre.
Une règle Bash lit la commande écrite : bash -c '…' ou un chemin complet passent à côté. Pour une vraie limite, le bac à sable.
{"permissions":{"allow":["Bash(pnpm test *)","Bash(git status)"],"ask":["Bash(git push *)"],"deny":["Read(.env)","Read(secrets/**)","Bash(rm -rf *)","mcp__playwright__browser_run_code_unsafe"]}}
Bash(pnpm test *) la commande pnpm test, seule ou suivie d'arguments (l'étoile).
Read(.env) un nom de fichier seul vaut à toute profondeur (comme dans un .gitignore) ; ./.env ne viserait que le dossier courant. .env.local demande sa propre ligne.
Bash(rm -rf *) un filet : rm -fr ou /bin/rm passent à côté. Une règle Bash lit le texte de la commande.
deny, ask, allow évaluées dans cet ordre : un refus l'emporte toujours, même sur une autorisation plus précise, et vaut aussi pour chaque morceau d'une commande composée.
Une limite posée par le système d'exploitation autour des commandes shell.
barrière
Pourquoi
Une permission ou un hook lisent le texte d'une commande ; une commande écrite autrement leur échappe. Le bac à sable, lui, contraint le processus lui-même : les fichiers qu'il peut écrire, les sites qu'il peut joindre, quoi que la commande dise.
Quand l'utiliser
Laisser l'agent lancer des commandes sans confirmation, sur un projet où une fuite ou une suppression coûterait cher.
Quand ce n'est pas le bon outil
Les outils de fichiers (Read, Edit), les serveurs MCP et les hooks : ils tournent hors du bac à sable et suivent les permissions. Et Windows natif : il faut WSL2.
Qui le déclenche
Le système d'exploitation, pendant chaque commande shell de l'agent, et pour les processus qu'elle lance.
Où il vit
/sandbox dans une session, ou sandbox.enabled dans settings.json. Désactivé par défaut.
Ce qu'il coûte au contexte
Aucun.
Sous Codex
sandbox_mode dans config.toml : read-only, workspace-write ou danger-full-access.
Vérifier que ça marche
/sandbox, puis demander à l'agent « curl https://example.com » : le bac à sable actif ; en mode Manuel (default, celui où l'outil vous demande avant d'agir), une demande d'autorisation pour example.com s'affiche ; en dontAsk ou avec strictAllowlist, un refus net.
allowUnsandboxedCommands: false sans cela, Claude peut demander à relancer une commande hors du bac à sable quand elle échoue.
network.allowedDomains les sites que le shell joint sans demander ; la liste part vide. Pour un autre site, le mode de permission de la session décide : une demande s'affiche en mode Manuel (default), acceptEdits ou plan ; le site est refusé en dontAsk, et en auto sauf si la commande l'a déclaré et que le classifieur l'a validé ; la connexion passe sans demande en bypassPermissions. Pour un refus net partout, network.strictAllowlist: true, à mettre dans vos réglages personnels (il est ignoré dans ceux du projet).
filesystem.allowWrite les dossiers où écrire, en plus du projet.
Un paquet de skills, d'agents, de hooks et de serveurs, installé une fois par machine.
selon le contenu
Pourquoi
Copier les mêmes fichiers dans dix dépôts, c'est dix copies qui divergent. Un plugin les regroupe, se met à jour d'un coup, et le projet ne garde que sa configuration.
Quand l'utiliser
Partager une méthode entre plusieurs projets ou plusieurs personnes.
Quand ce n'est pas le bon outil
Un réglage propre à un seul projet : il reste dans le dépôt. À savoir : ses skills prennent son préfixe (/mon-plugin:release-notes) ; ses hooks désignent leurs scripts par ${CLAUDE_PLUGIN_ROOT}, pas $CLAUDE_PROJECT_DIR ; un CLAUDE.md placé dans un plugin n'est pas lu. claude plugin validate vérifie le tout.
Qui le déclenche
Vous : /plugin install ; le projet peut le proposer à l'équipe dans settings.json.
Où il vit
un dépôt Git, la marketplace/plugin install sur votre machineactivé dans le projet par settings.json
Ce qu'il coûte au contexte
Celui de ce qu'il contient.
Sous Codex
des plugins Codex existent aussi (skills, serveurs MCP, hooks), installés depuis /plugins.
Vérifier que ça marche
/plugin : le plugin installé et activé ; ses skills dans /skills.
mon-plugin/
├── .claude-plugin/
│ └── plugin.json le manifeste : nom, version, où sont les hooks
├── skills/
│ └── release-notes/SKILL.md
├── agents/
│ └── security-reviewer.md
├── hooks/hooks.json les hooks, au format du bloc hooks de settings.json
└── .mcp.json facultatif : les serveurs MCP
{"name":"mon-plugin","version":"0.1.0","description":"Les skills, agents et garde-fous de l'équipe."}
name le préfixe de ses skills et de ses agents : /mon-plugin:release-notes.
pas de chemin de hookshooks/hooks.json est l'emplacement par défaut ; un champ hooks en ajoute un autre (Kwa s'en sert).
Ce qui change d'un projet à l'autre, lu par les gardes et les skills de Kwa.
imposé (par les gardes)
Pourquoi
Les gardes sont les mêmes partout ; les commandes interdites, les vérifications et les environnements, non. La politique les décrit, sans toucher aux scripts.
Quand l'utiliser
Interdire une commande propre au projet, déclarer les vérifications, choisir les modules.
Quand ce n'est pas le bon outil
Une règle valable pour tous les projets : elle va dans Kwa lui-même.
Qui le déclenche
Les gardes de Kwa, à chaque outil surveillé ; les skills, quand elles en ont besoin.
Où il vit
.claude/kwa.policy.json, créé par kwa init, puis propriété du projet.
Ce qu'il coûte au contexte
Aucun.
Sous Codex
la même politique : Kwa la traduit en hooks et en règles de commandes pour Codex.
Vérifier que ça marche
kwa doctor . dans le terminal : « cible conforme », ou la liste de ce qui manque.
{"kwa":1,"modules":["core","craft","issue-flow"],"bash":{"deny":[{"id":"deploy-prod","reason":"La production part par la PR, pas par ce script.","all":["npm run deploy:prod"]}]},"verify":{"commands":["pnpm typecheck","pnpm test"]}}
bash.deny une commande que les gardes de Kwa refusent, avec la raison donnée à l'agent. Le même refus vaut sous Codex.
verify.commands les vérifications que les skills de Kwa lancent avant de dire « fait ».