Le mode headless de Claude Code, c’est l’option -p. claude -p "votre prompt" lance Claude Code une fois sans l’interface interactive : il lit votre prompt (et tout ce que vous lui envoyez par un pipe), travaille avec les outils que vous autorisez, affiche le résultat et s’arrête. Le code de sortie 0 signifie un succès, tout autre code un échec. Cela en fait un outil en ligne de commande ordinaire, que vous pouvez placer dans des scripts shell, des tâches cron, des hooks git et des pipelines CI.
Ce guide couvre les options que vous utiliserez vraiment : formats de sortie, permissions des outils, limites de tours et de budget, --bare, poursuite de sessions et envoi de données par pipe, puis des patterns prêts à l’emploi pour les scripts, cron et la CI, et le moment de passer à l’Agent SDK. Chaque option citée ici a été vérifiée dans la référence officielle du CLI telle qu’elle était en octobre 2026.
Les bases
claude -p "What does the auth module do?"
-p et --print sont la même option. La plupart des options interactives s’y combinent, comme --model, --effort, --append-system-prompt et --mcp-config. Quelques options n’existent qu’en mode print, parmi lesquelles --max-turns, --max-budget-usd, --json-schema et --no-session-persistence.
Deux détails comptent pour les scripts :
- Si vous passez une option invalide, l’erreur part sur stderr avant le début de l’exécution.
- Si quelque chose échoue pendant l’exécution, par exemple une authentification manquante, l’échec est affiché comme résultat sur stdout. Vérifiez le code de sortie, pas seulement la sortie.
Envoyer des données en entrée, rediriger les résultats
Le mode headless lit stdin, donc les logs, les diffs et les fichiers arrivent comme avec n’importe quel outil Unix :
cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt
git diff main | claude -p "Review this diff for bugs. List each as file:line and one sentence."
L’entrée stdin par pipe est plafonnée à 10 Mo. Au-delà, Claude Code sort avec une erreur ; pour les grosses entrées, écrivez donc le contenu dans un fichier et nommez son chemin dans le prompt.
Vous pouvez aussi le brancher dans package.json, comme le fait la documentation officielle avec un linter de fautes de frappe :
{
"scripts": {
"lint:claude": "git diff main | claude -p \"you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next. return nothing else.\""
}
}
Choisir un format de sortie
--output-format accepte trois valeurs :
| Format | Ce que vous obtenez | À utiliser pour |
|---|---|---|
text (par défaut) | La réponse finale en texte brut | Humains, fichiers, scripts simples |
json | Un seul objet JSON à la fin | Scripts qui ont besoin de la réponse et des métadonnées |
stream-json | Un événement JSON par ligne, au fil de l’eau | Progression en direct, interfaces sur mesure, journalisation |
L’objet JSON contient la réponse dans result, plus session_id, des chiffres d’usage et total_cost_usd. Ce coût est une estimation côté client et peut différer de votre facture.
claude -p "Summarize this project" --output-format json | jq -r '.result'
Sortie structurée avec —json-schema
Quand un script a besoin de données plutôt que de prose, passez un JSON Schema. Le résultat validé arrive dans structured_output :
claude -p "Extract the main function names from auth.py" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}'
Si l’exécution se termine sans sortie structurée valide, par exemple parce que Claude a refusé, le champ est absent. Vérifiez sa présence avant de l’utiliser :
out=$(claude -p "Extract the main function names from auth.py" --output-format json --json-schema "$(cat schema.json)")
echo "$out" | jq -e '.structured_output' > /dev/null || { echo "no structured output" >&2; exit 1; }
Événements en streaming
stream-json exige --verbose. Ajoutez --include-partial-messages pour recevoir les tokens au fur et à mesure qu’ils sont générés. Ceci n’affiche que le texte en streaming :
claude -p "Write a poem" --output-format stream-json --verbose --include-partial-messages | \
jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
Le premier événement est normalement system/init, avec le modèle, les outils, les serveurs MCP et les plugins. La dernière ligne est un message result avec le texte final, le coût et les métadonnées de session. Les nouvelles tentatives apparaissent sous forme d’événements system/api_retry. Un contrôle utile en CI : quand vous passez --mcp-config, une entrée de serveur dont la validation échoue est ignorée sans faire échouer l’exécution, et elle apparaît dans mcp_server_errors sur l’événement init. Faites échouer le job si ce tableau n’est pas vide.
Contrôler ce que l’exécution a le droit de faire
Dans un script, personne n’est là pour répondre à une demande de permission ; décidez donc à l’avance ce que Claude peut faire.
--allowedTools pré-approuve des outils avec la syntaxe des règles de permission :
claude -p "Look at my staged changes and create an appropriate commit" \
--allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"
L’espace avant * compte : Bash(git diff *) correspond aux commandes qui commencent par git diff, alors que Bash(git diff*) correspondrait aussi à git diff-index.
--permission-mode fixe le comportement de base pour tout ce qui n’est pas listé. En octobre 2026 (Claude Code v2.1.302 et versions suivantes), une exécution -p démarre en mode Manual quand rien ne fixe de mode, et un appel qui demande une approbation est refusé. Valeurs utiles :
| Mode | Comportement dans une exécution headless |
|---|---|
dontAsk | Tout ce qui n’est pas pré-approuvé est refusé. Le choix prévisible pour les scripts |
acceptEdits | Les modifications de fichiers sont autorisées sans demander |
plan | Lecture et planification uniquement, aucune modification |
auto | Un classifieur examine chaque action ; un blocage refuse cette action et l’exécution continue |
bypassPermissions | Aucun contrôle. Uniquement dans un conteneur ou une VM jetable |
--tools restreint les outils intégrés qui existent tout court, et --disallowedTools ajoute des règles deny. --permission-prompts none indique à Claude que personne ne peut approuver les demandes, pour qu’il ne les retente pas sans fin ; les refus sont listés dans permission_denials sur le résultat final. Pourquoi contourner les permissions sur votre propre machine est risqué est expliqué dans Claude Code et —dangerously-skip-permissions.
Fixer des limites à chaque exécution sans surveillance
--max-turns 20s’arrête après ce nombre de tours agentiques et sort avec une erreur. Pas de limite par défaut.--max-budget-usd 5.00s’arrête quand la dépense estimée atteint ce montant. Il s’appuie sur l’estimation côté client et la dépense peut légèrement dépasser le plafond, donc gardez de la marge.timeout, côté shell ou étape de CI, reste utile. Si vous arrêtez une exécution avec SIGTERM, Claude Code sort avec le code 143, n’enregistre aucun résultat pour le tour inachevé et lance quand même les hooksSessionEnd.
Utiliser —bare pour des exécutions reproductibles
Sans --bare, claude -p charge les mêmes éléments qu’une session interactive : hooks, skills, plugins, serveurs MCP, mémoire automatique et CLAUDE.md, depuis le dossier de travail et depuis ~/.claude. La même commande se comporte donc différemment sur votre portable et sur un runner de CI.
claude --bare -p "Summarize README.md" --allowedTools "Read"
--bare saute toute cette découverte et démarre plus vite. Vous ne passez que ce dont l’exécution a besoin :
| À charger | Option |
|---|---|
| Instructions supplémentaires | --append-system-prompt, --append-system-prompt-file |
| Réglages | --settings <file-or-json> |
| Serveurs MCP | --mcp-config <file-or-json> |
| Agents personnalisés | --agents <file-or-json> |
| Un plugin | --plugin-dir <path> |
Le mode bare ne lit jamais les identifiants OAuth ni le trousseau du système. Avec l’API Anthropic, définissez ANTHROPIC_API_KEY ou fournissez un apiKeyHelper dans le JSON de --settings. La documentation officielle recommande --bare pour les appels scriptés et indique qu’il deviendra le comportement par défaut de -p dans une future version ; l’écrire explicitement dès maintenant garde vos scripts stables le jour où cela arrivera.
Une raison de plus d’y prêter attention : sans --bare, une exécution -p dans un dépôt fraîchement cloné lance les hooks de projet et les serveurs .mcp.json de ce dépôt sans boîte de dialogue de confiance. Ne lancez pas une exécution headless sans --bare sur du code que vous n’avez pas relu.
Poursuivre et reprendre des sessions
Les exécutions headless sont enregistrées comme les sessions interactives, vous pouvez donc enchaîner les étapes :
# First request
claude -p "Review this codebase for performance issues"
# Continue the most recent conversation
claude -p "Now focus on the database queries" --continue
claude -p "Generate a summary of all issues found" --continue
Quand plusieurs exécutions ont lieu en même temps, --continue peut choisir la mauvaise. Récupérez plutôt l’ID de session :
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"
--resume retrouve la session par son ID depuis n’importe quel dossier de la machine, et accepte aussi un nom ou le chemin du transcript .jsonl d’une session. --fork-session démarre une nouvelle branche à partir de la conversation reprise au lieu de la prolonger, et --no-session-persistence évite d’enregistrer les exécutions ponctuelles.
Patterns pour les scripts, cron et la CI
Une boucle sur des fichiers
La page officielle des bonnes pratiques propose un bon modèle pour un changement mécanique sur de nombreux fichiers :
for file in $(cat files.txt); do
claude --bare -p "Migrate $file to the new logger API and commit. Reply OK or FAIL." \
--allowedTools "Read,Edit,Bash(git add *),Bash(git commit *)" \
--permission-mode dontAsk \
--max-turns 20
done
Lancez-le d’abord sur trois fichiers, lisez les commits, corrigez le prompt, puis lancez le reste. Une exécution qui atteint la limite de tours sort avec une erreur, que votre boucle peut journaliser.
Un script de revue
gh pr diff "$1" | claude -p \
--append-system-prompt "You are a security engineer. Review for vulnerabilities." \
--output-format json
Enregistrez-le sous review.sh et lancez bash review.sh 123 ; le texte de la revue est dans result.
Une tâche cron de nuit
# crontab -e
0 2 * * * cd /srv/app && claude --bare -p "Run the test suite, fix failing tests, commit on the current branch. Do not push." --allowedTools "Read,Edit,Bash(npm test *),Bash(git add *),Bash(git commit *)" --permission-mode dontAsk --max-turns 30 --output-format json >> /var/log/claude-nightly.jsonl 2>> /var/log/claude-nightly.err
Cron tourne avec un environnement minimal : assurez-vous que claude est dans son PATH et que ANTHROPIC_API_KEY est défini pour cet utilisateur. Lancez-le sur une branche ou dans un worktree, pas sur main. Si vous ajoutez --worktree, notez que les exécutions -p --worktree ne sont pas nettoyées pour vous ; supprimez-les avec git worktree remove <path>. Pour la configuration complète de nuit avec budgets et relecture le matin, voir Lancer Claude Code la nuit, et pour les minuteurs de chaque système, Planifier des tâches Claude Code.
Pipelines CI
En CI, utilisez --bare, gardez la clé API dans le gestionnaire de secrets de la CI et traitez le code de sortie comme le résultat de l’étape. Pour GitHub en particulier, l’action officielle s’en charge pour vous, avec des commentaires de PR et des mentions @claude : voir Claude Code GitHub Actions. Si vous utilisez un abonnement plutôt qu’une clé API, claude setup-token affiche un token OAuth longue durée pour la CI et les scripts ; il n’est pas enregistré, stockez-le donc tout de suite comme secret. N’oubliez pas que --bare ignore OAuth : un token d’abonnement exige une exécution sans --bare.
Pièges
- Skills et commandes slash. Les skills utilisateur fonctionnent si vous mettez
/skill-namedans le prompt. Les commandes qui n’existent que dans l’interface du terminal, comme/login, ne fonctionnent pas. - Refus d’outils silencieux. Si Claude dit qu’il n’a pas pu faire quelque chose, regardez
permission_denialsdans le résultat JSON et ajoutez la règle manquante à--allowedTools. - Travail en arrière-plan. Une exécution
-ppeut rester ouverte pour attendre des commandes en arrière-plan ou des subagents lancés par Claude ; par défaut, elle cesse d’attendre après 10 minutes d’inactivité. - Remplacer le prompt système.
--system-promptremplace entièrement le prompt par défaut, y compris l’instantané du statut git. Préférez--append-system-prompt, sauf si vous voulez vraiment partir d’une page blanche.
Quand passer à l’Agent SDK
claude -p, c’est le moteur de l’Agent SDK derrière un CLI. Dès que votre script commence à analyser des flux, à gérer des approbations ou à piloter de nombreuses sessions, passez à l’Agent SDK pour Python ou TypeScript. Il vous donne des objets message natifs, des callbacks d’approbation des outils et des sorties structurées directement dans le code, sans passer par le shell. L’article Bonnes pratiques Claude Code couvre ce qu’il faut mettre en place avant de laisser tourner une exécution sans surveillance.
Avec AgentVera
Les exécutions headless se lancent et s’oublient ; parfois, vous voulez la même automatisation avec un terminal que vous pouvez regarder. Dans AgentVera, les tâches planifiées (sur toutes les offres) envoient un prompt à un agent selon un planning cron pendant que l’application est ouverte, et l’agent tourne dans un vrai volet que vous pouvez ouvrir et réorienter. Les automatisations (Pro et Team) lancent un agent quand la CI passe au rouge ou qu’une PR reçoit un commentaire, et ne poussent jamais sur la branche par défaut. Le centre CI/CD liste les exécutions GitHub Actions, GitLab et Jenkins et peut confier un log en échec à un agent. Night shift (Pro et Team) exécute le travail en file pendant la nuit dans un worktree sur une branche night/<date>-<slug>, committe sans pousser et laisse un rapport le matin. Téléchargez AgentVera si vous voulez voir ces exécutions au lieu de les enfouir dans un fichier de log.
En résumé
La recette de base du Claude Code headless est courte : claude --bare -p "clear task with a check", une liste --allowedTools explicite, --permission-mode dontAsk, --max-turns, --output-format json, et un code de sortie que votre script respecte. Commencez petit, lisez ce que produisent les premières exécutions, et seulement ensuite mettez-le sur un minuteur.