Módulo 7: Integraciones: Git, SDK, y Remote Control

SDK Python y TypeScript: acceso programático a Claude Code

SDK Python y TypeScript: acceso programático a Claude Code

Descripción

Hasta ahora has interactuado con Claude Code de una sola forma: escribes un prompt en la terminal, Claude responde, tú revisas, repites. Ese modelo interactivo es poderoso para desarrollo — pero tiene una limitación fundamental: requiere un humano en el loop.

¿Qué pasa cuando necesitas que Claude Code revise 200 archivos automáticamente? ¿O que genere documentación cada vez que alguien hace push? ¿O que valide código en un pipeline de CI/CD sin que nadie esté mirando? Para eso existe el SDK.

El SDK de Claude Code te da acceso programático a las mismas capacidades que usas interactivamente, pero desde código Python o TypeScript. En lugar de escribir un prompt en la terminal, llamas a una función en tu script. En lugar de leer la respuesta en la terminal, la recibes como un objeto estructurado que tu programa puede procesar.


Qué es el SDK de Claude Code

El SDK (Software Development Kit) es una librería que expone las capacidades de Claude Code a través de una API programática. No es la API de Anthropic directamente — es una capa que ejecuta Claude Code como un proceso y te da control sobre su input y output.

SDK vs API de Anthropic vs Claude Code interactivo

CaracterísticaClaude Code interactivoSDK de Claude CodeAPI de Anthropic
InterfazTerminal (prompt manual)Función en códigoHTTP requests
Humano requeridoSí (tú en la terminal)No (automatizable)No
Acceso a herramientasTodas (read, write, execute)Todas (read, write, execute)Solo LLM (sin herramientas)
Contexto del proyectoSí (lee tu codebase)Sí (lee tu codebase)No (solo el prompt)
CLAUDE.mdSí (se carga automáticamente)Sí (se carga automáticamente)No
Skills y hooksSíSíNo
Caso de usoDesarrollo interactivoAutomatización y scriptingApps y chatbots

La diferencia clave: el SDK ejecuta Claude Code completo — con acceso a archivos, terminal, Git, y todo lo que aprendiste en módulos anteriores. La API de Anthropic solo te da acceso al modelo de lenguaje sin herramientas.


Python SDK

Instalación

pip install claude-agent-sdk

Nota sobre nombres: El paquete del Agent SDK es claude-agent-sdk (pip) / claude_agent_sdk (import). Este es diferente del SDK principal de Anthropic (pip install anthropic), que se usa para llamadas directas a la API. Verifica siempre los nombres actualizados en la documentación oficial del Agent SDK, ya que Anthropic itera rápidamente.

Requisitos:

  • Python 3.8+
  • Claude Code instalado y autenticado (claude --version)
  • Node.js 18+ (el SDK ejecuta Claude Code como proceso Node)

Uso básico: la función query()

La forma más simple de usar el SDK es con query():

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, Message

async def main():
    messages: list[Message] = []

    async for message in query(
        prompt="Explain this project's architecture",
        options=ClaudeAgentOptions(max_turns=3)
    ):
        if message.type == "text":
            print(message.content)

asyncio.run(main())

query() es un async generator que produce mensajes. Cada mensaje puede ser de tipo text (respuesta de Claude), tool_use (Claude ejecuta una herramienta), o tool_result (resultado de la herramienta).

Ejemplo básico: revisar un archivo

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def review_file(filepath: str) -> str:
    result = []

    async for message in query(
        prompt=f"Review {filepath} for bugs, security issues, and code quality. Be concise.",
        options=ClaudeAgentOptions(max_turns=5)
    ):
        if message.type == "text":
            result.append(message.content)

    return "\n".join(result)

async def main():
    review = await review_file("src/auth/login.py")
    print(review)

asyncio.run(main())

Ejemplo intermedio: batch review de múltiples archivos

import asyncio
import glob
from claude_agent_sdk import query, ClaudeAgentOptions

async def review_file(filepath: str) -> dict:
    result = []

    async for message in query(
        prompt=f"""Review {filepath}. Return a brief summary with:
        1. Purpose of the file
        2. Any bugs or issues found
        3. Suggestions for improvement
        Be concise - max 10 lines.""",
        options=ClaudeAgentOptions(max_turns=3)
    ):
        if message.type == "text":
            result.append(message.content)

    return {
        "file": filepath,
        "review": "\n".join(result)
    }

async def review_directory(directory: str) -> list[dict]:
    python_files = glob.glob(f"{directory}/**/*.py", recursive=True)

    tasks = [review_file(f) for f in python_files[:10]]
    reviews = await asyncio.gather(*tasks)

    return reviews

async def main():
    reviews = await review_directory("src/")

    for review in reviews:
        print(f"\n{'='*60}")
        print(f"File: {review['file']}")
        print(f"{'='*60}")
        print(review["review"])

asyncio.run(main())

Este script revisa hasta 10 archivos Python en paralelo, cada uno en su propia instancia de Claude Code.

ClaudeAgentOptions: control de la ejecución

from claude_agent_sdk import ClaudeAgentOptions

options = ClaudeAgentOptions(
    max_turns=10,
    system_prompt="You are a senior code reviewer. Be thorough but concise.",
    allowed_tools=["Read", "Grep", "Glob"],
    model="sonnet",
    cwd="/path/to/project"
)
ParámetroTipoDescripción
max_turnsintMáximo de turnos de conversación
system_promptstrPrompt de sistema adicional
allowed_toolslist[str]Herramientas permitidas
modelstrModelo a usar (opus, sonnet)
cwdstrDirectorio de trabajo
permission_modestrModo de permisos

Filtrar tipos de mensajes

async for message in query(prompt="...", options=options):
    match message.type:
        case "text":
            print(f"Claude dice: {message.content}")
        case "tool_use":
            print(f"Claude usa: {message.tool} con {message.input}")
        case "tool_result":
            print(f"Resultado: {message.content[:100]}...")

TypeScript SDK

Instalación

npm install @anthropic-ai/claude-agent-sdk

Requisitos:

  • Node.js 18+
  • Claude Code instalado y autenticado

Uso básico: la función query()

import { query } from "@anthropic-ai/claude-agent-sdk";

async function main() {
  for await (const message of query({
    prompt: "Explain this project's architecture",
    options: { maxTurns: 3 },
  })) {
    if (message.type === "text") {
      console.log(message.content);
    }
  }
}

main();

Ejemplo básico: generar documentación

import { query } from "@anthropic-ai/claude-agent-sdk";
import { writeFile } from "fs/promises";

async function generateDocs(directory: string): Promise<string> {
  const result: string[] = [];

  for await (const message of query({
    prompt: `Analyze the code in ${directory} and generate API documentation 
    in markdown format. Include: function signatures, parameters, return types, 
    and brief descriptions.`,
    options: {
      maxTurns: 10,
      allowedTools: ["Read", "Grep", "Glob"],
    },
  })) {
    if (message.type === "text") {
      result.push(message.content);
    }
  }

  return result.join("\n");
}

async function main() {
  const docs = await generateDocs("src/routes");
  await writeFile("docs/API.md", docs);
  console.log("Documentation generated: docs/API.md");
}

main();

Ejemplo intermedio: test generator

import { query } from "@anthropic-ai/claude-agent-sdk";
import { readdir, writeFile } from "fs/promises";
import { join, basename } from "path";

async function generateTestForFile(filepath: string): Promise<void> {
  const result: string[] = [];

  for await (const message of query({
    prompt: `Read ${filepath} and generate comprehensive unit tests using pytest.
    Cover: normal cases, edge cases, error handling.
    Output ONLY the test code, nothing else.`,
    options: {
      maxTurns: 5,
      allowedTools: ["Read", "Grep"],
    },
  })) {
    if (message.type === "text") {
      result.push(message.content);
    }
  }

  const testFilename = `test_${basename(filepath)}`;
  const testPath = join("tests", testFilename);
  await writeFile(testPath, result.join("\n"));
  console.log(`Generated: ${testPath}`);
}

async function main() {
  const files = await readdir("src/services");
  const pyFiles = files.filter((f) => f.endsWith(".py") && !f.startsWith("__"));

  for (const file of pyFiles) {
    await generateTestForFile(join("src/services", file));
  }
}

main();

createSdkMcpServer: exponer Claude Code como MCP server

El SDK de TypeScript permite exponer Claude Code como un servidor MCP, para que otros agentes o aplicaciones puedan usarlo como herramienta:

import { createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";

const server = createSdkMcpServer({
  name: "claude-code-reviewer",
  description: "Code review powered by Claude Code",
});

server.start();

Esto crea un servidor MCP que otros clientes pueden consumir, delegando tareas a Claude Code programáticamente.


SDK vs Claude Code interactivo: cuándo usar cada uno

Usa Claude Code interactivo cuando:

  • Estás desarrollando activamente y necesitas iteración rápida
  • La tarea requiere tu criterio en cada paso
  • Estás explorando un codebase nuevo
  • Necesitas feedback visual inmediato

Usa el SDK cuando:

  • La tarea es repetitiva y predecible
  • Necesitas procesar múltiples archivos/repos
  • La tarea se ejecuta sin supervisión humana
  • Necesitas integrar Claude Code en otro sistema
  • La tarea es parte de un pipeline automatizado

Tabla de decisión

EscenarioInteractivoSDK
Implementar un feature nuevo✅❌
Revisar 50 archivos de código❌✅
Debugging en tiempo real✅❌
Code review en CI/CD❌✅
Generar docs para todo un proyecto❌✅
Explorar un codebase desconocido✅❌
Pre-commit hook de validación❌✅
Refactoring guiado✅❌

Casos de uso prácticos del SDK

1. Code review automatizado en CI/CD

import asyncio
import subprocess
from claude_agent_sdk import query, ClaudeAgentOptions

async def review_pr_diff() -> str:
    diff = subprocess.run(
        ["git", "diff", "main...HEAD"],
        capture_output=True, text=True
    ).stdout

    result = []
    prompt = f"""Review this git diff for a PR. Focus on:
    1. Bugs or logic errors
    2. Security vulnerabilities
    3. Performance issues
    4. Code style violations

    Diff:
    {diff}

    Format: bullet points, severity (HIGH/MEDIUM/LOW), file:line reference."""

    async for message in query(
        prompt=prompt,
        options=ClaudeAgentOptions(
            max_turns=3,
            allowed_tools=["Read", "Grep"]
        )
    ):
        if message.type == "text":
            result.append(message.content)

    return "\n".join(result)

async def main():
    review = await review_pr_diff()
    print(review)

    with open("pr_review.md", "w") as f:
        f.write(review)

asyncio.run(main())

2. Generador de documentación

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def generate_module_docs(module_path: str) -> str:
    result = []

    async for message in query(
        prompt=f"""Analyze all files in {module_path} and generate comprehensive
        documentation in markdown format. Include:
        - Module overview
        - All public functions/classes with signatures
        - Parameters and return types
        - Usage examples
        - Dependencies""",
        options=ClaudeAgentOptions(
            max_turns=10,
            allowed_tools=["Read", "Grep", "Glob"]
        )
    ):
        if message.type == "text":
            result.append(message.content)

    return "\n".join(result)

async def main():
    modules = ["src/auth", "src/routes", "src/services"]

    for module in modules:
        docs = await generate_module_docs(module)
        output = f"docs/{module.split('/')[-1]}.md"
        with open(output, "w") as f:
            f.write(docs)
        print(f"Generated: {output}")

asyncio.run(main())

3. Migrador de código batch

import asyncio
import glob
from claude_agent_sdk import query, ClaudeAgentOptions

async def migrate_file(filepath: str) -> dict:
    result = []

    async for message in query(
        prompt=f"""Migrate {filepath} from Python 3.8 syntax to Python 3.12:
        - Replace typing.Optional with X | None
        - Replace typing.Union with X | Y
        - Replace typing.List/Dict/Set with list/dict/set
        - Use match/case where appropriate
        Apply the changes directly to the file.""",
        options=ClaudeAgentOptions(
            max_turns=5,
            allowed_tools=["Read", "Write"]
        )
    ):
        if message.type == "text":
            result.append(message.content)

    return {"file": filepath, "status": "migrated", "details": "\n".join(result)}

async def main():
    files = glob.glob("src/**/*.py", recursive=True)
    print(f"Migrating {len(files)} files...")

    for f in files:
        result = await migrate_file(f)
        print(f"  ✅ {result['file']}")

    print("Migration complete.")

asyncio.run(main())

Comparaciones y decisiones

Python SDK vs TypeScript SDK

AspectoPython SDKTypeScript SDK
Instalaciónpip install claude-agent-sdknpm install @anthropic-ai/claude-agent-sdk (incluye Agent SDK)
APIquery() async generatorquery() async iterator
MCP serverNo disponiblecreateSdkMcpServer()
EcosystemScripts, data pipelines, MLWeb apps, Node scripts, MCP
Concurrenciaasyncio.gather()Promise.all()
Mejor paraCI/CD, batch processing, dataMCP integration, web services

SDK vs Headless CLI (-p)

AspectoSDKHeadless CLI
ComplejidadMayor (código Python/TS)Menor (un comando bash)
ControlFino (streaming, types)Básico (output text/json)
Error handlingTry/catch, tiposExit codes
IntegraciónEn cualquier programaEn scripts bash
Mejor paraLógica compleja, pipelinesScripts simples, one-liners

Regla general: si puedes resolverlo con un comando bash, usa headless CLI (-p). Si necesitas lógica, parsing, o integración con otro sistema, usa el SDK.


Patterns comunes

Pattern: retry con backoff

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def query_with_retry(prompt: str, max_retries: int = 3) -> str:
    for attempt in range(max_retries):
        try:
            result = []
            async for message in query(
                prompt=prompt,
                options=ClaudeAgentOptions(max_turns=5)
            ):
                if message.type == "text":
                    result.append(message.content)
            return "\n".join(result)
        except Exception as e:
            if attempt == max_retries - 1:
                raise
            wait = 2 ** attempt
            print(f"Attempt {attempt + 1} failed: {e}. Retrying in {wait}s...")
            await asyncio.sleep(wait)

Pattern: restricción de herramientas

review_options = ClaudeAgentOptions(
    max_turns=5,
    allowed_tools=["Read", "Grep", "Glob"]
)

modify_options = ClaudeAgentOptions(
    max_turns=10,
    allowed_tools=["Read", "Write", "Grep", "Glob"]
)

Usa allowed_tools para controlar qué puede hacer Claude Code en cada script. Para review: solo lectura. Para migraciones: lectura y escritura.

Pattern: procesamiento secuencial con resumen

async def process_and_summarize(files: list[str]) -> str:
    all_results = []

    for f in files:
        result = await review_file(f)
        all_results.append(result)

    summary_parts = []
    async for message in query(
        prompt=f"Summarize these code reviews into a single report:\n\n" +
               "\n---\n".join([r["review"] for r in all_results]),
        options=ClaudeAgentOptions(max_turns=3)
    ):
        if message.type == "text":
            summary_parts.append(message.content)

    return "\n".join(summary_parts)

Pitfalls y edge cases

Pitfall 1: demasiados turns en batch processing

Si configuras max_turns=50 para un batch de 100 archivos, cada archivo puede consumir muchos tokens. Empieza con max_turns=3-5 para tasks simples.

Pitfall 2: paralelismo excesivo

Ejecutar 100 query() en paralelo con asyncio.gather() puede saturar tu sistema. Limita la concurrencia:

import asyncio

semaphore = asyncio.Semaphore(5)

async def limited_review(filepath: str):
    async with semaphore:
        return await review_file(filepath)

tasks = [limited_review(f) for f in files]
results = await asyncio.gather(*tasks)

Pitfall 3: no validar el output

El SDK devuelve texto libre. Si necesitas datos estructurados, pide JSON explícitamente en el prompt y parsea el resultado:

import json

async for message in query(
    prompt="Analyze this file. Respond with JSON: {\"issues\": [...], \"score\": 0-10}",
    options=options
):
    if message.type == "text":
        try:
            data = json.loads(message.content)
        except json.JSONDecodeError:
            pass  # Fallback: tratar como texto

Pitfall 4: olvidar el cwd

Si tu script se ejecuta desde un directorio diferente al del proyecto, Claude Code no encontrará los archivos:

options = ClaudeAgentOptions(
    cwd="/absolute/path/to/your/project"
)

Pitfall 5: costos en batch processing

Cada query() inicia una sesión completa de Claude Code. Para 100 archivos, son 100 sesiones. Monitorea el uso para evitar costos inesperados.


Ejemplo completo integrado

Un script que combina review, documentación, y reporte:

import asyncio
import glob
import json
from datetime import datetime
from claude_agent_sdk import query, ClaudeAgentOptions

REVIEW_OPTIONS = ClaudeAgentOptions(
    max_turns=5,
    allowed_tools=["Read", "Grep", "Glob"]
)

async def review_file(filepath: str) -> dict:
    result = []
    async for message in query(
        prompt=f"""Review {filepath}. Respond with JSON only:
        {{
            "file": "{filepath}",
            "issues": [
                {{"severity": "HIGH|MEDIUM|LOW", "line": 0, "description": "..."}}
            ],
            "quality_score": 0-10,
            "summary": "one line summary"
        }}""",
        options=REVIEW_OPTIONS
    ):
        if message.type == "text":
            result.append(message.content)

    text = "\n".join(result)
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return {"file": filepath, "issues": [], "quality_score": -1, "summary": text[:200]}

async def main():
    files = glob.glob("src/**/*.py", recursive=True)
    semaphore = asyncio.Semaphore(3)

    async def limited(f):
        async with semaphore:
            return await review_file(f)

    print(f"Reviewing {len(files)} files...")
    reviews = await asyncio.gather(*[limited(f) for f in files])

    high_issues = [
        r for r in reviews
        if any(i.get("severity") == "HIGH" for i in r.get("issues", []))
    ]

    report = {
        "date": datetime.now().isoformat(),
        "total_files": len(files),
        "files_with_high_issues": len(high_issues),
        "average_quality": sum(
            r.get("quality_score", 0) for r in reviews
            if r.get("quality_score", -1) >= 0
        ) / max(len(reviews), 1),
        "reviews": reviews
    }

    with open("code_review_report.json", "w") as f:
        json.dump(report, f, indent=2)

    print(f"\nReport saved: code_review_report.json")
    print(f"Files reviewed: {report['total_files']}")
    print(f"High-severity issues: {report['files_with_high_issues']}")
    print(f"Average quality: {report['average_quality']:.1f}/10")

asyncio.run(main())

Ejercicios prácticos

Ejercicio 1: Básico — Tu primer script con SDK

Crea un script Python que use el SDK para analizar la estructura de tu proyecto y genere un resumen.

Requisitos:

  • Instala claude-agent-sdk
  • Usa query() con un prompt que pida el análisis
  • Imprime el resultado en consola
  • Limita a 3 turns
Solución
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def analyze_project():
    result = []

    async for message in query(
        prompt="Analyze this project's structure. List: main language, "
               "framework, directory structure, and entry points. Be concise.",
        options=ClaudeAgentOptions(max_turns=3)
    ):
        if message.type == "text":
            result.append(message.content)

    print("\n".join(result))

asyncio.run(analyze_project())

Ejecuta: python analyze.py desde la raíz de tu proyecto.

Ejercicio 2: Intermedio — Review de un directorio

Crea un script que revise todos los archivos de un directorio y genere un reporte markdown.

Requisitos:

  • Acepta el directorio como argumento
  • Revisa cada archivo (limita a 5 para no gastar muchos tokens)
  • Genera un archivo review-report.md con los resultados
  • Incluye un score de calidad por archivo
Solución
import asyncio
import glob
import sys
from claude_agent_sdk import query, ClaudeAgentOptions

async def review_file(filepath: str) -> dict:
    result = []
    async for message in query(
        prompt=f"Review {filepath}. Give: 1) quality score (1-10), "
               f"2) top 3 issues if any, 3) one-line summary.",
        options=ClaudeAgentOptions(
            max_turns=3,
            allowed_tools=["Read"]
        )
    ):
        if message.type == "text":
            result.append(message.content)
    return {"file": filepath, "review": "\n".join(result)}

async def main():
    directory = sys.argv[1] if len(sys.argv) > 1 else "src"
    files = glob.glob(f"{directory}/**/*.py", recursive=True)[:5]

    print(f"Reviewing {len(files)} files in {directory}...")
    reviews = []
    for f in files:
        review = await review_file(f)
        reviews.append(review)
        print(f"  Done: {f}")

    with open("review-report.md", "w") as out:
        out.write("# Code Review Report\n\n")
        for r in reviews:
            out.write(f"## {r['file']}\n\n")
            out.write(f"{r['review']}\n\n---\n\n")

    print(f"\nReport saved: review-report.md")

asyncio.run(main())

Ejercicio 3: Intermedio — Generador de tests con TypeScript

Crea un script TypeScript que genere tests para los archivos de un directorio.

Requisitos:

  • Lee archivos .ts de un directorio
  • Para cada archivo, genera tests con el SDK
  • Guarda los tests en un directorio tests/
  • Usa allowedTools: ["Read"] (solo lectura del código fuente)
Solución
import { query } from "@anthropic-ai/claude-agent-sdk";
import { readdir, writeFile, mkdir } from "fs/promises";
import { join, basename } from "path";

async function generateTest(filepath: string): Promise<string> {
  const result: string[] = [];

  for await (const message of query({
    prompt: `Read ${filepath} and generate unit tests using vitest. 
    Cover normal cases, edge cases, and error handling. 
    Output ONLY the test code.`,
    options: {
      maxTurns: 5,
      allowedTools: ["Read"],
    },
  })) {
    if (message.type === "text") {
      result.push(message.content);
    }
  }

  return result.join("\n");
}

async function main() {
  const dir = process.argv[2] || "src";
  const files = await readdir(dir);
  const tsFiles = files.filter(
    (f) => f.endsWith(".ts") && !f.endsWith(".test.ts")
  );

  await mkdir("tests", { recursive: true });

  for (const file of tsFiles.slice(0, 5)) {
    const filepath = join(dir, file);
    console.log(`Generating test for ${filepath}...`);

    const testCode = await generateTest(filepath);
    const testFile = join("tests", `${basename(file, ".ts")}.test.ts`);
    await writeFile(testFile, testCode);

    console.log(`  Created: ${testFile}`);
  }
}

main();

Ejercicio 4: Avanzado — CI/CD review bot

Crea un script que se pueda ejecutar en CI/CD para revisar los cambios de un PR y dejar un comentario.

Requisitos:

  • Lee el diff con git diff main...HEAD
  • Usa el SDK para revisar el diff
  • Genera un archivo pr-review.md con el resultado
  • El resultado debe ser formateado para pegar en un comentario de GitHub
Solución
import asyncio
import subprocess
from claude_agent_sdk import query, ClaudeAgentOptions

async def review_pr():
    diff = subprocess.run(
        ["git", "diff", "main...HEAD"],
        capture_output=True, text=True
    ).stdout

    if not diff.strip():
        print("No changes to review.")
        return

    result = []
    async for message in query(
        prompt=f"""You are a code reviewer. Review this PR diff and provide 
        feedback formatted for a GitHub PR comment.

        Use this format:
        ## Code Review Summary
        [1-2 sentence overview]
        
        ## Issues Found
        - 🔴 **Critical**: [description] (`file:line`)
        - 🟡 **Warning**: [description] (`file:line`)
        - 🔵 **Suggestion**: [description] (`file:line`)
        
        ## What's Good
        - [positive observations]
        
        Diff:
        {diff[:10000]}""",
        options=ClaudeAgentOptions(
            max_turns=3,
            allowed_tools=["Read", "Grep"]
        )
    ):
        if message.type == "text":
            result.append(message.content)

    review_text = "\n".join(result)
    with open("pr-review.md", "w") as f:
        f.write(review_text)

    print(review_text)

asyncio.run(review_pr())

Ejercicio 5: Challenge — Pipeline completo

Combina review + docs + tests en un solo script que procese un módulo completo.

Requisitos:

  • Acepta un path de módulo como argumento
  • Paso 1: Review de todos los archivos
  • Paso 2: Generar documentación del módulo
  • Paso 3: Identificar archivos sin tests y generar tests básicos
  • Output: directorio reports/ con review.md, docs.md, y tests generados
Guía

Estructura del script:

async def main():
    module = sys.argv[1]
    
    # Paso 1: Review
    reviews = await review_all_files(module)
    save_markdown("reports/review.md", reviews)
    
    # Paso 2: Documentation
    docs = await generate_docs(module)
    save_markdown("reports/docs.md", docs)
    
    # Paso 3: Generate missing tests
    untested = find_files_without_tests(module)
    for f in untested:
        test = await generate_test(f)
        save_file(f"tests/test_{basename(f)}", test)
    
    print("Pipeline complete. Check reports/ directory.")

Usa las funciones de los ejercicios anteriores como base. Limita la concurrencia con asyncio.Semaphore(3) para no saturar el sistema.


Resumen

Lo que aprendiste en esta cápsula:

  • El SDK de Claude Code da acceso programático a todas las capacidades de Claude Code
  • Python Agent SDK (claude-agent-sdk): instalación con pip, función query() como async generator
  • TypeScript SDK (@anthropic-ai/claude-agent-sdk): instalación con npm, query() como async iterator, createSdkMcpServer() para exponer Claude Code como MCP server
  • SDK vs interactivo: interactivo para desarrollo, SDK para automatización y batch processing
  • SDK vs headless CLI: headless para scripts simples, SDK para lógica compleja y error handling
  • Casos de uso prácticos: code review en CI/CD, generación de docs, migración batch, testing
  • Pitfalls: controlar turns, limitar concurrencia, validar output, especificar cwd, monitorear costos

Siguiente cápsula: 04 - Headless mode CLI — el flag -p para ejecutar Claude Code desde scripts bash sin interacción.


Recursos adicionales

Documentación oficial

Integraciones

Complementarios