Claude Code Headless et Programmatique : SDK et Automatisation
By Learnia Team
Claude Code Headless et Programmatique : SDK et Automatisation
Le mode headless transforme Claude Code d'un outil interactif en un moteur d'automatisation programmable. Construisez des scripts, des pipelines et des applications qui exploitent les capacités de Claude sans intervention humaine.
Qu'est-ce que le Mode Headless ?
Le mode headless exécute Claude Code sans prompts interactifs :
Mode Interactif (Par Défaut)
$ claude
> Comment puis-je vous aider aujourd'hui ?
_
Mode Headless
$ claude --print -p "Analyse cette base de code" > report.md
$ echo $? # Code de sortie : 0
Aucune interaction nécessaire. L'entrée est fournie, la sortie est produite.
Learn AI — From Prompts to Agents
Options CLI du Mode Headless
| Option | Description |
|---|---|
--print / -p | Sortie vers stdout au lieu de l'interface interactive |
--prompt / -p | Spécifier le prompt (combiné avec --print) |
--output-format | Format de sortie : text, json, stream-json |
--dangerously-skip-permissions | Ignorer tous les prompts de permission |
--max-tokens | Limiter les tokens de sortie |
--model | Spécifier le modèle : sonnet, opus, haiku |
--no-color | Désactiver la sortie colorée |
--quiet / -q | Supprimer les sorties non essentielles |
Utilisation Basique du Mode Headless
Prompt Simple
claude --print -p "Explique cette fonction" < src/utils.ts
Sortie vers Fichier
claude --print -p "Génère la documentation API" > docs/api.md
Sortie JSON
claude --print --output-format json -p "Liste tous les commentaires TODO en tableau JSON"
Entrée par Pipe
cat error.log | claude --print -p "Analyse ce journal d'erreurs et suggère des correctifs"
Fichiers Multiples
claude --print -p "Compare ces implémentations" < <(cat file1.ts file2.ts)
Modèles d'Automatisation
Intégration dans les Scripts
#!/bin/bash
# analyze.sh
# Obtenir les fichiers modifiés
changed=$(git diff --name-only HEAD~1)
# Analyser chaque fichier
for file in $changed; do
echo "Analyse de $file..."
claude --print --quiet -p "Revois $file pour détecter les problèmes" > "reviews/${file}.md"
done
echo "Analyse terminée"
Gestion des Erreurs
#!/bin/bash
output=$(claude --print -p "Génère la migration" 2>&1)
exit_code=$?
if [ $exit_code -ne 0 ]; then
echo "Erreur : $output"
exit 1
fi
echo "$output" > migration.sql
Logique Conditionnelle
#!/bin/bash
# Demander à Claude de catégoriser
category=$(claude --print --output-format json \
-p "Catégorise ce ticket. Retourne du JSON : {\"category\": \"bug|feature|docs\"}" \
< issue.txt | jq -r '.category')
case $category in
bug)
echo "Routage vers le triage de bugs..."
;;
feature)
echo "Ajout au backlog de fonctionnalités..."
;;
docs)
echo "Attribution à l'équipe de documentation..."
;;
esac
Le SDK Anthropic
Pour une intégration plus poussée, utilisez le SDK officiel :
Installation
npm install @anthropic-ai/sdk
Utilisation Basique
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function main() {
const message = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [
{
role: "user",
content: "Explique le concept d'injection de dépendances"
}
]
});
console.log(message.content[0].text);
}
main();
Avec un Prompt Système
const message = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: "Tu es un ingénieur logiciel senior. Fournis des conseils détaillés et pratiques.",
messages: [
{ role: "user", content: "Comment structurer un projet de microservices ?" }
]
});
Réponses en Streaming
const stream = await client.messages.stream({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [
{ role: "user", content: "Rédige un guide complet sur les tests" }
]
});
for await (const chunk of stream) {
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
process.stdout.write(chunk.delta.text);
}
}
Conversations Multi-Tours
const conversation = [
{ role: "user", content: "Je construis une API REST en Node.js" },
{ role: "assistant", content: "Super ! Quel framework utilisez-vous ?" },
{ role: "user", content: "Express. Comment structurer mes routes ?" }
];
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: conversation
});
Utilisation d'Outils avec le SDK
Claude peut utiliser des outils programmatiquement :
Définir les Outils
const tools = [
{
name: "get_weather",
description: "Obtenir la météo actuelle pour un lieu",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "Nom de la ville"
}
},
required: ["location"]
}
},
{
name: "search_code",
description: "Rechercher des modèles dans la base de code",
input_schema: {
type: "object",
properties: {
query: { type: "string" },
file_pattern: { type: "string" }
},
required: ["query"]
}
}
];
Exécuter les Outils
async function runWithTools(prompt: string) {
let messages = [{ role: "user", content: prompt }];
while (true) {
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
tools,
messages
});
// Vérifier si Claude veut utiliser un outil
const toolUse = response.content.find(block => block.type === "tool_use");
if (!toolUse) {
// Plus d'outils, retourner la réponse finale
return response.content.find(block => block.type === "text")?.text;
}
// Exécuter l'outil
const result = await executeToolCall(toolUse.name, toolUse.input);
// Ajouter le résultat de l'outil à la conversation
messages.push({
role: "assistant",
content: response.content
});
messages.push({
role: "user",
content: [{
type: "tool_result",
tool_use_id: toolUse.id,
content: result
}]
});
}
}
async function executeToolCall(name: string, input: any): Promise<string> {
switch (name) {
case "get_weather":
return JSON.stringify({ temp: 72, condition: "ensoleillé" });
case "search_code":
return `5 correspondances trouvées pour "${input.query}"`;
default:
return "Outil non trouvé";
}
}
Traitement par Lots
Traitez efficacement plusieurs éléments :
Traitement Séquentiel
import { readdir, readFile, writeFile } from "fs/promises";
async function processFiles(directory: string) {
const files = await readdir(directory);
for (const file of files) {
if (!file.endsWith(".ts")) continue;
const content = await readFile(`${directory}/${file}`, "utf-8");
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
messages: [{
role: "user",
content: `Génère des commentaires JSDoc pour ce fichier :\n\n${content}`
}]
});
const documented = response.content[0].text;
await writeFile(`${directory}/${file}`, documented);
console.log(`Traité : ${file}`);
}
}
Traitement Parallèle (avec limitation de débit)
import pLimit from "p-limit";
const limit = pLimit(5); // Maximum 5 requêtes simultanées
async function processFilesParallel(files: string[]) {
const tasks = files.map(file =>
limit(async () => {
const content = await readFile(file, "utf-8");
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{
role: "user",
content: `Analyse : ${content}`
}]
});
return { file, analysis: response.content[0].text };
})
);
return Promise.all(tasks);
}
API Batch (pour les gros volumes)
// Pour les très gros lots, utilisez l'API Batch
const batch = await client.batches.create({
requests: files.map((file, i) => ({
custom_id: `file-${i}`,
params: {
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: `Analyse : ${file}` }]
}
}))
});
// Vérifier l'état de complétion
while (batch.status !== "completed") {
await new Promise(r => setTimeout(r, 60000));
batch = await client.batches.retrieve(batch.id);
}
// Obtenir les résultats
const results = await client.batches.results(batch.id);
Construction de Pipelines
Pipeline d'Analyse de Code
interface AnalysisResult {
file: string;
issues: Issue[];
complexity: number;
suggestions: string[];
}
async function analyzeCodebase(directory: string): Promise<AnalysisResult[]> {
const files = await glob(`${directory}/**/*.ts`);
const results: AnalysisResult[] = [];
for (const file of files) {
const content = await readFile(file, "utf-8");
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
messages: [{
role: "user",
content: `Analyse ce fichier TypeScript et retourne du JSON :
{
"issues": [{"type": "string", "line": number, "message": "string"}],
"complexity": number (1-10),
"suggestions": ["string"]
}
Fichier : ${file}
\`\`\`typescript
${content}
\`\`\``
}]
});
const analysis = JSON.parse(response.content[0].text);
results.push({ file, ...analysis });
}
return results;
}
// Utiliser le pipeline
const analysis = await analyzeCodebase("./src");
const highComplexity = analysis.filter(r => r.complexity > 7);
console.log(`Fichiers nécessitant un refactoring : ${highComplexity.length}`);
Pipeline de Documentation
async function generateDocs(sourceDir: string, outputDir: string) {
// Étape 1 : Analyser la structure
const structure = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
messages: [{
role: "user",
content: `Analyse ${sourceDir} et crée un plan de documentation`
}]
});
// Étape 2 : Générer le README
const readme = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 4096,
messages: [{
role: "user",
content: `Génère un README.md basé sur : ${structure.content[0].text}`
}]
});
await writeFile(`${outputDir}/README.md`, readme.content[0].text);
// Étape 3 : Générer la référence API
const apiFiles = await glob(`${sourceDir}/api/**/*.ts`);
for (const file of apiFiles) {
const content = await readFile(file, "utf-8");
const doc = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
messages: [{
role: "user",
content: `Génère la documentation API pour :\n${content}`
}]
});
const docPath = file.replace(sourceDir, outputDir).replace(".ts", ".md");
await writeFile(docPath, doc.content[0].text);
}
}
Gestion des Erreurs et Retentatives
Appels API Robustes
import { setTimeout } from "timers/promises";
async function callWithRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
// Ne pas réessayer les erreurs de validation
if (error.status === 400) throw error;
// Backoff exponentiel
const delay = baseDelay * Math.pow(2, attempt);
console.log(`Tentative ${attempt + 1} échouée, nouvelle tentative dans ${delay}ms`);
await setTimeout(delay);
}
}
throw lastError;
}
// Utilisation
const response = await callWithRetry(() =>
client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }]
})
);
Gestion de la Limitation de Débit
import Bottleneck from "bottleneck";
const limiter = new Bottleneck({
reservoir: 100, // 100 requêtes
reservoirRefreshAmount: 100,
reservoirRefreshInterval: 60 * 1000, // par minute
maxConcurrent: 5
});
async function rateLimitedCall(prompt: string) {
return limiter.schedule(() =>
client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }]
})
);
}
Modèles de Production
Gestion de Configuration
// config.ts
interface Config {
model: string;
maxTokens: number;
temperature: number;
systemPrompt: string;
}
const configs: Record<string, Config> = {
analysis: {
model: "claude-sonnet-4-20250514",
maxTokens: 2048,
temperature: 0,
systemPrompt: "Tu es un expert en analyse de code. Sois minutieux et précis."
},
creative: {
model: "claude-sonnet-4-20250514",
maxTokens: 4096,
temperature: 0.7,
systemPrompt: "Tu es un rédacteur technique créatif."
},
fast: {
model: "claude-3-5-haiku-20241022",
maxTokens: 512,
temperature: 0,
systemPrompt: "Sois concis."
}
};
async function query(prompt: string, configName: keyof typeof configs) {
const config = configs[configName];
return client.messages.create({
model: config.model,
max_tokens: config.maxTokens,
temperature: config.temperature,
system: config.systemPrompt,
messages: [{ role: "user", content: prompt }]
});
}
Journalisation et Monitoring
import { createLogger, transports, format } from "winston";
const logger = createLogger({
level: "info",
format: format.combine(
format.timestamp(),
format.json()
),
transports: [
new transports.File({ filename: "claude.log" })
]
});
async function trackedQuery(prompt: string, metadata: Record<string, any>) {
const startTime = Date.now();
try {
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }]
});
logger.info("Appel API réussi", {
...metadata,
duration: Date.now() - startTime,
inputTokens: response.usage.input_tokens,
outputTokens: response.usage.output_tokens
});
return response;
} catch (error) {
logger.error("Appel API échoué", {
...metadata,
duration: Date.now() - startTime,
error: error.message
});
throw error;
}
}
Mise en Cache
import { createHash } from "crypto";
import { Redis } from "ioredis";
const redis = new Redis();
function hashPrompt(prompt: string, model: string): string {
return createHash("sha256")
.update(`${model}:${prompt}`)
.digest("hex");
}
async function cachedQuery(prompt: string, ttl = 3600) {
const cacheKey = hashPrompt(prompt, "claude-sonnet-4-20250514");
// Vérifier le cache
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
// Faire l'appel API
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }]
});
// Mettre en cache le résultat
await redis.setex(cacheKey, ttl, JSON.stringify(response));
return response;
}
Cas d'Utilisation
Service de Revue de Code Automatisée
// review-service.ts
import express from "express";
import { Anthropic } from "@anthropic-ai/sdk";
const app = express();
const client = new Anthropic();
app.post("/review", async (req, res) => {
const { code, language, rules } = req.body;
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
system: `Tu es un réviseur de code. Revois le code ${language} en suivant ces règles : ${rules}`,
messages: [{
role: "user",
content: `Revois ce code :\n\`\`\`${language}\n${code}\n\`\`\``
}]
});
res.json({
review: response.content[0].text,
tokens: response.usage
});
});
app.listen(3000);
Générateur de Documentation
// doc-generator.ts
async function generateModuleDocs(modulePath: string) {
const files = await glob(`${modulePath}/**/*.ts`);
const docs: string[] = [];
for (const file of files) {
const content = await readFile(file, "utf-8");
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
messages: [{
role: "user",
content: `Génère la documentation markdown pour :\n${content}`
}]
});
docs.push(`## ${file}\n\n${response.content[0].text}`);
}
return docs.join("\n\n---\n\n");
}
Générateur de Tests
// test-generator.ts
async function generateTests(sourceFile: string, testFramework = "jest") {
const source = await readFile(sourceFile, "utf-8");
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 4096,
system: `Génère des tests ${testFramework} complets. Inclus les cas limites et les scénarios d'erreur.`,
messages: [{
role: "user",
content: `Génère des tests pour :\n\`\`\`typescript\n${source}\n\`\`\``
}]
});
const testFile = sourceFile.replace(".ts", ".test.ts");
await writeFile(testFile, response.content[0].text);
return testFile;
}
Intégration avec les Fonctionnalités de Claude Code
Utiliser les Skills Programmatiquement
// Charger les définitions de skills
const skills = await loadSkills(".claude/skills");
async function runSkill(skillName: string, input: any) {
const skill = skills[skillName];
return client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 4096,
system: skill.systemPrompt,
messages: [{
role: "user",
content: `Exécute le skill "${skillName}" avec :\n${JSON.stringify(input)}`
}]
});
}
Voir Agent Skills dans Claude Code : Étendez les Capacités de Claude.
MCP Programmatique
import { MCPClient } from "@modelcontextprotocol/sdk";
const mcp = new MCPClient();
await mcp.connect("github", "https://api.github.com/mcp/");
// Utiliser les outils MCP dans les appels SDK
const tools = await mcp.listTools();
Voir Model Context Protocol (MCP) pour Claude Code : Guide Complet.
Points Clés à Retenir
- →
--printpour le scripting : Option essentielle pour l'automatisation headless. - →
SDK pour les workflows complexes : Contrôle total avec le SDK Anthropic.
- →
Gérer les erreurs avec élégance : Implémentez des retentatives et la limitation de débit.
- →
Mettre en cache quand c'est possible : Réduisez les coûts et la latence.
- →
Monitorer en production : Journalisez l'utilisation, les erreurs et les performances.
Construisez des Systèmes IA en Production
Le mode headless de Claude Code est la base des systèmes IA en production. Apprenez à construire des workflows IA fiables et évolutifs.
Dans notre Module 6 — Agents Autonomes, vous apprendrez :
- →Architecture des systèmes IA en production
- →Modèles de fiabilité
- →Stratégies de mise à l'échelle
- →Monitoring et observabilité
Module 6 — AI Agents & ReAct
Create autonomous agents that reason and take actions.
Weekly AI Insights
Tools, techniques & news — curated for AI practitioners. Free, no spam.
Free, no spam. Unsubscribe anytime.
→Related Articles
FAQ
Qu'est-ce que le mode headless dans Claude Code ?+
Le mode headless exécute Claude Code sans interface terminal interactive, permettant le scripting, l'intégration CI/CD et les pipelines automatisés. Utilisez 'claude --print' ou le SDK pour un accès programmatique.
Comment utiliser Claude Code dans des scripts ?+
Utilisez 'claude -p "votre prompt" --print' pour un scripting simple. Pour une automatisation complexe, utilisez le SDK TypeScript/Python avec des réponses en streaming et le contrôle de l'exécution des outils.
Claude Code peut-il être utilisé dans des pipelines CI/CD ?+
Oui. Claude Code s'intègre avec GitHub Actions, GitLab CI, Jenkins via le mode headless. Usages courants : revue de code automatisée, descriptions de PR, génération de tests et documentation.
Quelle est la différence entre le SDK Claude Code et l'API ?+
Le SDK encapsule les capacités d'agent de Claude Code (accès fichiers, outils, mémoire). L'API directe donne un accès brut au modèle. Utilisez le SDK pour les tâches de codage ; l'API pour les intégrations personnalisées.