Mode Headless et CI/CD
Utilisez Claude Code en mode non-interactif dans vos pipelines. GitHub Actions, GitLab CI, pre-commit hooks et bonnes pratiques de sécurité.
Le mode headless : Claude Code sans interface
Le mode headless permet d'utiliser Claude Code comme un outil de ligne de commande classique : il reçoit une instruction, l'exécute, et retourne un résultat, sans interface interactive, sans demander de confirmation, sans attendre de saisie.
C'est la porte d'entrée vers l'intégration dans des pipelines CI/CD, des scripts d'automatisation et des outils DevOps.
Le flag --print (-p) : usage basique
Le flag --print (ou -p) lance Claude Code en mode non-interactif et affiche le résultat sur stdout :
# Usage basiqueclaude --print "Explique ce que fait cette fonction"# Avec un fichier en contexte (piping)cat src/utils/auth.ts | claude --print "Identifie les risques de sécurité dans ce code"# Piping vers d'autres commandesgit diff HEAD~1 | claude --print "Rédige un résumé de ces changements pour le CHANGELOG"# Raccourci -pclaude -p "Génère des tests unitaires pour le fichier src/lib/parser.ts"
Piping et scripts
Le mode --print s'intègre naturellement dans les pipes Unix :
#!/bin/bash# Script d'analyse de code avant commitCHANGED_FILES=$(git diff --name-only HEAD)for file in $CHANGED_FILES; doif [[ "$file" == *.ts ]] || [[ "$file" == *.tsx ]]; thenecho "Analyse de $file..."REVIEW=$(cat "$file" | claude --print \"Identifie les problèmes critiques dans ce code TypeScript.Réponds en JSON : {issues: array, severity: critical|high|medium|low}")echo "$REVIEW" | python3 -c "import sys, jsondata = json.load(sys.stdin)critical = [i for i in data.get('issues', []) if i.get('severity') == 'critical']if critical:print('BLOQUANT:', critical)exit(1)print('OK: pas de problème critique')"fidone
--output-format json : parsing automatisé
Pour intégrer la sortie de Claude dans des scripts, utilisez le format JSON :
# Format JSON structuréclaude --print --output-format json "Analyse ce code et retourne un objet JSON"# Stream JSON (pour les sorties longues)claude --print --output-format stream-json "Génère la documentation de cette API"
Le format json retourne un objet avec la structure suivante :
{"type": "result","subtype": "success","result": "Le contenu de la réponse de Claude...","session_id": "sess_abc123","total_cost_usd": 0.0023,"num_turns": 1}
Extraire uniquement la réponse avec jq :
RESULT=$(claude --print --output-format json "Résume en une phrase : $(cat README.md)" | jq -r '.result')echo "Résumé : $RESULT"
--max-turns : limiter les itérations
En mode headless, Claude peut effectuer plusieurs "tours" (lire des fichiers, écrire du code, vérifier...). --max-turns limite ce nombre pour éviter des boucles infinies :
# Limiter à 5 tours d'exécutionclaude --print --max-turns 5 "Corrige les erreurs TypeScript dans src/"# Pour des tâches simples, 1 tour suffitclaude --print --max-turns 1 "Génère un fichier README.md pour ce projet"
--dangerously-skip-permissions : mode automatique complet
Risque de sécurité élevé
Ce flag supprime toutes les demandes de confirmation de Claude Code. Il peut lire, écrire et exécuter n'importe quel fichier ou commande sans validation humaine. À utiliser uniquement dans des environnements isolés (conteneurs CI/CD, sandboxes) avec des permissions système réduites au minimum.
Ne jamais l'utiliser sur votre machine de développement personnelle pour des tâches non auditées.
# En CI/CD uniquement, dans un conteneur isoléclaude --print --dangerously-skip-permissions \"Génère les tests manquants pour src/services/ et exécute-les"
En production CI/CD, la combinaison recommandée est :
claude \--print \--dangerously-skip-permissions \--max-turns 10 \--output-format json \"Ta tâche ici"
Intégration GitHub Actions
Workflow complet : review automatique de PR
Ce workflow déclenche une review Claude Code sur chaque Pull Request :
name: Claude Code PR Reviewon:pull_request:types: [opened, synchronize]jobs:claude-review:runs-on: ubuntu-latestpermissions:contents: readpull-requests: writesteps:- name: Checkoutuses: actions/checkout@v4with:fetch-depth: 0- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: '20'- name: Install Claude Coderun: npm install -g @anthropic-ai/claude-code- name: Run Claude Code reviewid: reviewenv:ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}run: |DIFF=$(git diff origin/${{ github.base_ref }}...HEAD -- '*.ts' '*.tsx' '*.js' | head -c 10000)REVIEW=$(echo "$DIFF" | claude \--print \--max-turns 3 \--output-format json \"Tu es un expert en review de code. Analyse ce diff Git et fournis :1. Un résumé des changements2. Les problèmes potentiels (sécurité, performance)3. Des suggestions d'amélioration concrètesFormat: Markdown structuré et concis." | jq -r '.result')echo "$REVIEW" > /tmp/review.mdecho "review_done=true" >> $GITHUB_OUTPUT- name: Post review commentif: steps.review.outputs.review_done == 'true'uses: actions/github-script@v7with:script: |const fs = require('fs');const review = fs.readFileSync('/tmp/review.md', 'utf8');github.rest.issues.createComment({issue_number: context.issue.number,owner: context.repo.owner,repo: context.repo.repo,body: `## Review automatique : Claude Code\n\n${review}\n\n---\n*Généré automatiquement par Claude Code*`});
Workflow : génération de tests automatique
name: Générer les tests manquantson:workflow_dispatch:inputs:target_path:description: 'Chemin à analyser (ex: src/services/)'required: truedefault: 'src/'jobs:generate-tests:runs-on: ubuntu-latestpermissions:contents: writepull-requests: writesteps:- uses: actions/checkout@v4- uses: actions/setup-node@v4with:node-version: '20'- name: Install dependenciesrun: npm ci- name: Install Claude Coderun: npm install -g @anthropic-ai/claude-code- name: Generate missing testsenv:ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}run: |claude \--print \--dangerously-skip-permissions \--max-turns 15 \"Analyse les fichiers dans ${{ github.event.inputs.target_path }}.Pour chaque fichier sans test : crée le fichier de test Jest + TypeScriptcouvrant les cas nominaux et les cas d'erreur.Exécute ensuite npm test pour vérifier."- name: Create Pull Requestuses: peter-evans/create-pull-request@v5with:commit-message: "test: génération automatique des tests manquants"title: "Tests générés automatiquement par Claude Code"body: |Tests générés automatiquement pour les fichiers sans couverture.**Vérifier avant de merger :**- [ ] Les tests couvrent les cas nominaux- [ ] Les tests couvrent les cas d'erreur- [ ] La couverture est > 80%branch: "auto/generated-tests"
Workflow : audit de sécurité hebdomadaire
name: Audit de sécurité Claude Codeon:schedule:- cron: '0 6 * * 1' # Chaque lundi à 6hworkflow_dispatch:jobs:security-audit:runs-on: ubuntu-latestpermissions:contents: readissues: writesteps:- uses: actions/checkout@v4- uses: actions/setup-node@v4with:node-version: '20'- name: Install Claude Coderun: npm install -g @anthropic-ai/claude-code- name: Run security auditid: auditenv:ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}run: |AUDIT=$(claude \--print \--max-turns 8 \--output-format json \"Audit de sécurité complet :1. Recherche de secrets hardcodés2. Dépendances vulnérables (package.json)3. Patterns dangereux (eval, innerHTML)4. Configurations de sécurité (CORS, CSP)Retourne JSON avec : critical (array), warnings (array), score (/10)" \| jq -r '.result')echo "$AUDIT" > /tmp/audit.jsonCRITICAL_COUNT=$(echo "$AUDIT" | python3 -c "import sys, jsontry:data = json.loads(sys.stdin.read())print(len(data.get('critical', [])))except:print(0)")echo "critical_count=$CRITICAL_COUNT" >> $GITHUB_OUTPUT- name: Create issue if critical findingsif: steps.audit.outputs.critical_count > 0uses: actions/github-script@v7with:script: |const fs = require('fs');const audit = fs.readFileSync('/tmp/audit.json', 'utf8');github.rest.issues.create({owner: context.repo.owner,repo: context.repo.repo,title: '[SECURITE] Problèmes critiques détectés par Claude Code',body: `## Rapport d'audit de sécurité\n\n\`\`\`json\n${audit}\n\`\`\``,labels: ['security', 'critical']});
Variables secrets et configuration
Gestion des secrets dans GitHub Actions
Ne mettez jamais ANTHROPIC_API_KEY en clair dans vos workflows. Utilisez toujours les secrets GitHub :
- Aller dans Settings > Secrets and variables > Actions
- Cliquer "New repository secret"
- Nom :
ANTHROPIC_API_KEY, Valeur : votre clé API Anthropic
Dans le workflow, référencer via ${{ secrets.ANTHROPIC_API_KEY }}.
Intégration GitLab CI
Exemple basique d'intégration dans un pipeline GitLab :
# .gitlab-ci.ymlstages:- review- testclaude-review:stage: reviewimage: node:20-alpineonly:- merge_requestsscript:- npm install -g @anthropic-ai/claude-code- |DIFF=$(git diff origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD | head -c 8000)REVIEW=$(echo "$DIFF" | claude \--print \--max-turns 3 \"Review ce diff et identifie les problèmes potentiels.")echo "$REVIEW"variables:ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
Pre-commit hooks avec Claude Code
Intégrez Claude Code dans vos hooks git pre-commit :
#!/bin/bash# .git/hooks/pre-commit# Rendre exécutable : chmod +x .git/hooks/pre-commitset -eSTAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(ts|tsx|js|jsx)$' || true)if [ -z "$STAGED_FILES" ]; thenexit 0fiecho "Analyse Claude Code des fichiers staged..."for file in $STAGED_FILES; doISSUES=$(cat "$file" | claude \--print \--max-turns 1 \--output-format json \"Identifie les problèmes CRITIQUES (bugs évidents, failles de sécurité).Réponds avec un JSON {issues: string[], has_critical: boolean}" \| jq -r '.result' 2>/dev/null || echo '{"has_critical": false}')HAS_CRITICAL=$(echo "$ISSUES" | python3 -c "import sys, jsontry:d = json.loads(sys.stdin.read())print('true' if d.get('has_critical') else 'false')except:print('false')")if [ "$HAS_CRITICAL" = "true" ]; thenecho "BLOQUÉ : problème critique dans $file"exit 1fidoneecho "OK : pas de problème critique détecté"exit 0
Bonnes pratiques de sécurité en mode headless
Checklist sécurité obligatoire
Avant de déployer Claude Code en mode headless dans un pipeline de production :
- Utiliser des secrets chiffrés (GitHub Secrets, GitLab Variables, AWS Secrets Manager)
- Réduire les permissions du runner au minimum nécessaire
- Limiter
--max-turnspour éviter des boucles coûteuses - Logger les coûts en tokens pour détecter les abus
- Isoler dans des conteneurs sans accès réseau inutile
- Ne jamais committer de fichiers contenant
ANTHROPIC_API_KEY - Utiliser
--output-format jsonpour parser les résultats de manière sûre
Limiter les coûts en CI/CD
# Mauvais : envoie tout le codebaseclaude --print "Analyse tout le projet"# Bon : cible les fichiers modifiésgit diff --name-only HEAD~1 | xargs -I{} sh -c \'cat {} | claude --print --max-turns 1 "Analyse ce fichier"'# Bon : limite la taille du diffgit diff | head -c 5000 | claude --print --max-turns 2 "Review ce diff"
Prochaines étapes
Combinez le mode headless avec les providers enterprise (Bedrock, Vertex) pour des pipelines CI/CD conformes aux contraintes de données de votre organisation.