Capítulo 2: Instalación y Configuración
Capítulo 2: Instalación y Configuración
1. Requisitos del Sistema
Antes de instalar el SDK, verifica que tu sistema cumple con todos los requisitos. Una instalación incompleta es la causa más común de errores inesperados.
1.1 Tabla de compatibilidad por plataforma
| Sistema Operativo | Python SDK | TypeScript SDK | Claude Code CLI | Notas |
|---|---|---|---|---|
| macOS 12+ (Intel) | Sí | Sí | Sí | Totalmente soportado |
| macOS 12+ (Apple Silicon) | Sí | Sí | Sí | Nativo ARM, sin Rosetta |
| Ubuntu 20.04+ | Sí | Sí | Sí | Totalmente soportado |
| Debian 11+ | Sí | Sí | Sí | Totalmente soportado |
| Fedora 38+ | Sí | Sí | Sí | Totalmente soportado |
| WSL2 (Windows) | Sí | Sí | Sí | Recomendado para Windows |
| Windows nativo | Parcial | Parcial | Sí | Limitaciones en Bash tool |
| Alpine Linux | Parcial | Parcial | Sí | Requiere glibc compat |
| Docker Linux | Sí | Sí | Sí | Ver sección Docker |
1.2 Versiones de Python soportadas
| Versión Python | Soportada | Notas |
|---|---|---|
| Python 3.9 | No | Falta asyncio.timeout y typing moderno |
| Python 3.10 | Sí (mínimo) | match/case, asyncio.timeout disponibles |
| Python 3.11 | Sí | Mejor performance async, recomendado |
| Python 3.12 | Sí | Versión actual recomendada |
| Python 3.13 | Sí | Beta, funciona bien |
| PyPy | No probado | Pueden haber problemas con subprocess async |
# Verificar versión de Python
python --version
# o
python3 --version
# Verificar que es 3.10+
python -c "import sys; assert sys.version_info >= (3, 10), 'Se requiere Python 3.10+'; print('Python OK')"
1.3 Versiones de Node.js soportadas
| Versión Node.js | Soportada | Notas |
|---|---|---|
| Node.js 16 | No | Sin soporte de for await...of con streams modernos |
| Node.js 18 LTS | Sí (mínimo) | Stable async iterators |
| Node.js 20 LTS | Sí | Recomendado para producción |
| Node.js 22 LTS | Sí | Versión más nueva, funciona bien |
| Node.js 23+ | Sí | Experimental, puede tener cambios |
| Deno | No | No soportado actualmente |
| Bun | Parcial | Puede funcionar pero no es oficial |
# Verificar versión de Node.js
node --version
# Verificar que es 18+
node -e "const v = parseInt(process.version.slice(1)); if (v < 18) throw new Error('Node 18+ requerido'); console.log('Node.js OK: ' + process.version)"
1.4 Claude Code CLI: el prerequisito más importante
El SDK no es autónomo: necesita que Claude Code CLI esté instalado en el sistema. El SDK lanza Claude Code como subproceso y se comunica con él via stdin/stdout. Sin Claude Code CLI, el SDK no puede funcionar.
# Verificar que Claude Code está instalado
claude --version
# Si no está instalado, verás:
# zsh: command not found: claude
1.5 Espacio en disco y memoria
- Claude Code CLI: ~200MB en disco
- SDK Python: ~5MB adicionales
- SDK TypeScript + node_modules: ~50MB adicionales
- RAM durante ejecución: ~200-500MB por instancia de agente (Claude Code mantiene el contexto en memoria)
- Para proyectos grandes: El contexto puede consumir hasta 1-2GB de RAM si analizas repositorios muy grandes
2. Instalación de Claude Code CLI
Claude Code CLI es la dependencia fundamental. Sin ella, el SDK no puede funcionar.
2.1 macOS con Homebrew (recomendado)
# Instalar via Homebrew
brew install --cask claude-code
# Verificar instalación
claude --version
# Output esperado:
# Claude Code 1.x.x
2.2 Todas las plataformas via npm
# Instalación global con npm
npm install -g @anthropic-ai/claude-code
# Con pnpm
pnpm add -g @anthropic-ai/claude-code
# Con yarn
yarn global add @anthropic-ai/claude-code
# Con bun (experimental)
bun add -g @anthropic-ai/claude-code
# Verificar
claude --version
which claude # Debe mostrar la ruta del binario
2.3 macOS / Linux / WSL: script de instalación directa
# Script oficial de instalación
curl -fsSL https://claude.ai/install.sh | bash
# Si prefieres revisar el script antes de ejecutarlo:
curl -fsSL https://claude.ai/install.sh -o install_claude.sh
cat install_claude.sh # revisa el contenido
bash install_claude.sh
# Agregar al PATH si no se agregó automáticamente
echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.bashrc
# o para zsh:
echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.zshrc
source ~/.bashrc # o ~/.zshrc
2.4 Windows (PowerShell nativo)
En Windows nativo (sin WSL), la instalación via npm es la opción más confiable:
# Instalar Node.js desde https://nodejs.org si no lo tienes
# Instalar Claude Code
npm install -g @anthropic-ai/claude-code
# Verificar en PowerShell
claude --version
# Configurar la API Key en Windows
$env:ANTHROPIC_API_KEY = "sk-ant-xxxxxxxx"
# Para persistir la variable de entorno (permanente):
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-xxxxxxxx", "User")
Nota importante sobre Windows nativo: La herramienta Bash del agente tendrá limitaciones en Windows nativo. Para uso completo de herramientas de terminal, se recomienda WSL2.
2.5 Configurar la API Key en Claude Code
La primera vez que ejecutes Claude Code, te pedirá tu API Key de Anthropic:
# Primera ejecución - configuración interactiva
claude
# O configurar directamente via variable de entorno
export ANTHROPIC_API_KEY="sk-ant-xxxxxxxxxxxxxxxxxxxxxxxx"
claude --print "Di hola"
Para obtener tu API Key:
- Ve a
https://console.anthropic.com/ - Inicia sesión o crea cuenta
- Ve a “API Keys” en el menú lateral
- Haz clic en “Create Key”
- Copia la key (solo se muestra una vez)
2.6 Verificar que Claude Code funciona
# Test básico: Claude debe responder sin errores
claude --print "Responde solo con la palabra: OK"
# Output esperado:
# OK
# Si ves errores de autenticación:
# Error: ANTHROPIC_API_KEY not set
# → Configura la variable de entorno
# Si ves errores de red:
# Error: Connection refused
# → Verifica tu conexión a internet o proxy
2.7 Problemas comunes en la instalación del CLI
Error: npm: permission denied al instalar globalmente
# Opción 1: Usar sudo (no recomendado por seguridad)
sudo npm install -g @anthropic-ai/claude-code
# Opción 2: Cambiar el directorio de npm (recomendado)
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
npm install -g @anthropic-ai/claude-code
Error: claude: command not found después de instalar
# Verificar dónde se instaló
npm list -g --depth=0 | grep claude-code
npm bin -g # Muestra el directorio de binarios globales
# Agregar al PATH manualmente
export PATH="$(npm bin -g):$PATH"
# Para persistir, agregar al ~/.bashrc o ~/.zshrc
Error: GLIBC_2.xx not found en Linux
# Este error ocurre en distribuciones muy antiguas
# Solución 1: Actualizar el sistema
sudo apt update && sudo apt upgrade
# Solución 2: Usar la versión npm que incluye binarios precompilados
# (normalmente resuelto en versiones más nuevas de Claude Code)
3. Instalación del SDK Python
3.1 Instalación básica con pip
# Método más simple
pip install claude-code-sdk
# Verificar la versión instalada
pip show claude-code-sdk
# Output:
# Name: claude-code-sdk
# Version: 0.0.x
# Location: /usr/local/lib/python3.12/site-packages
# Verificar que se puede importar
python -c "from claude_code_sdk import query, ClaudeCodeOptions; print('Importación exitosa')"
3.2 Instalación con uv (recomendado para proyectos nuevos)
uv es un gestor de paquetes Python muy rápido escrito en Rust. Es la opción moderna y recomendada.
# Instalar uv si no lo tienes
curl -LsSf https://astral.sh/uv/install.sh | sh
# o en macOS:
brew install uv
# Crear un nuevo proyecto
uv init mi-agente
cd mi-agente
# Agregar claude-code-sdk al proyecto
uv add claude-code-sdk
# Agregar dependencias de desarrollo
uv add --dev pytest pytest-asyncio ruff mypy
# Ejecutar con uv (maneja automáticamente el entorno virtual)
uv run python src/agente.py
Con uv, el pyproject.toml se actualiza automáticamente:
[project]
name = "mi-agente"
version = "0.1.0"
dependencies = [
"claude-code-sdk>=0.0.9",
]
3.3 Instalación con Poetry
# Crear nuevo proyecto con Poetry
poetry new mi-agente
cd mi-agente
# Agregar la dependencia
poetry add claude-code-sdk
# Agregar dependencias de desarrollo
poetry add --group dev pytest pytest-asyncio
# Activar el entorno
poetry shell
# O ejecutar directamente
poetry run python src/agente.py
pyproject.toml con Poetry:
[tool.poetry]
name = "mi-agente"
version = "0.1.0"
description = "Agente con Claude Code SDK"
authors = ["Tu Nombre <[email protected]>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.10"
claude-code-sdk = ">=0.0.9"
python-dotenv = ">=1.0.0"
[tool.poetry.group.dev.dependencies]
pytest = ">=7.0"
pytest-asyncio = ">=0.23"
ruff = ">=0.3"
mypy = ">=1.8"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
3.4 Crear entorno virtual manualmente
Para quienes prefieren el control total con venv estándar:
# Crear entorno virtual en el directorio del proyecto
python -m venv .venv
# Activar en macOS/Linux
source .venv/bin/activate
# Activar en Windows PowerShell
.\.venv\Scripts\Activate.ps1
# Activar en Windows CMD
.\.venv\Scripts\activate.bat
# Verificar que estás en el entorno virtual
which python # debe mostrar .venv/bin/python
# Instalar dependencias
pip install claude-code-sdk python-dotenv
# Guardar dependencias con versiones exactas
pip freeze > requirements.txt
requirements.txt con versiones pinned:
# requirements.txt - versiones pinned para reproducibilidad
claude-code-sdk==0.0.9
anyio==4.3.0
httpx==0.27.0
pydantic==2.6.3
python-dotenv==1.0.1
# Dev dependencies (en requirements-dev.txt separado)
# pytest==8.1.1
# pytest-asyncio==0.23.5
# ruff==0.3.4
# mypy==1.9.0
3.5 Instalación en Docker (Python)
El siguiente Dockerfile crea una imagen con todo lo necesario para ejecutar un agente Python:
# Dockerfile.python
FROM python:3.12-slim
# Instalar Node.js (necesario para Claude Code CLI)
RUN apt-get update && apt-get install -y \
curl \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*
# Instalar Claude Code CLI
RUN npm install -g @anthropic-ai/claude-code
# Configurar directorio de trabajo
WORKDIR /app
# Instalar dependencias Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copiar código del agente
COPY src/ ./src/
COPY CLAUDE.md ./
# Variables de entorno (se proveerán en runtime, no en build)
ENV ANTHROPIC_API_KEY=""
ENV PYTHONUNBUFFERED=1
# Ejecutar el agente
CMD ["python", "src/agente.py"]
# Construir la imagen
docker build -f Dockerfile.python -t mi-agente-python .
# Ejecutar con la API key
docker run -e ANTHROPIC_API_KEY=sk-ant-xxx mi-agente-python
# Montar el proyecto para desarrollo
docker run \
-e ANTHROPIC_API_KEY=sk-ant-xxx \
-v $(pwd)/src:/app/src \
mi-agente-python
3.6 Verificar la instalación Python
Script completo de verificación:
#!/usr/bin/env python3
"""verificar_instalacion.py - Verifica que el SDK está correctamente instalado."""
import sys
import os
import asyncio
import subprocess
def verificar_python():
"""Verifica que la versión de Python es compatible."""
version = sys.version_info
if version < (3, 10):
print(f"ERROR: Python {version.major}.{version.minor} no soportado. Se requiere 3.10+")
return False
print(f"OK: Python {version.major}.{version.minor}.{version.micro}")
return True
def verificar_claude_cli():
"""Verifica que Claude Code CLI está instalado y accesible."""
try:
result = subprocess.run(
["claude", "--version"],
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0:
print(f"OK: Claude Code CLI instalado: {result.stdout.strip()}")
return True
else:
print(f"ERROR: Claude Code CLI retornó código {result.returncode}")
return False
except FileNotFoundError:
print("ERROR: Claude Code CLI no encontrado. Instala con: npm install -g @anthropic-ai/claude-code")
return False
except subprocess.TimeoutExpired:
print("ERROR: Claude Code CLI tardó demasiado en responder")
return False
def verificar_api_key():
"""Verifica que la API key está configurada."""
api_key = os.environ.get("ANTHROPIC_API_KEY", "")
if not api_key:
print("ERROR: ANTHROPIC_API_KEY no configurada")
return False
if not api_key.startswith("sk-ant-"):
print(f"ADVERTENCIA: La API key no tiene el formato esperado (sk-ant-...)")
print(f" Valor: {api_key[:10]}...")
else:
print(f"OK: ANTHROPIC_API_KEY configurada: {api_key[:15]}...")
return bool(api_key)
def verificar_sdk_import():
"""Verifica que el SDK se puede importar correctamente."""
try:
from claude_code_sdk import query, ClaudeCodeOptions
print("OK: claude_code_sdk importado correctamente")
return True
except ImportError as e:
print(f"ERROR: No se puede importar claude_code_sdk: {e}")
print(" Instala con: pip install claude-code-sdk")
return False
async def verificar_funcionamiento():
"""Hace una llamada real al SDK para verificar que funciona end-to-end."""
try:
from claude_code_sdk import query, ClaudeCodeOptions
print("Haciendo llamada de prueba al agente...")
resultado = None
async for message in query(
prompt="Responde únicamente con la frase: VERIFICACION_EXITOSA",
options=ClaudeCodeOptions(max_turns=3)
):
if hasattr(message, 'result') and message.result:
resultado = message.result
if resultado and "VERIFICACION_EXITOSA" in resultado:
print(f"OK: Agente respondió correctamente: '{resultado.strip()}'")
return True
else:
print(f"ADVERTENCIA: Agente respondió pero no con el texto esperado: '{resultado}'")
return True # El agente funcionó aunque no siguió el formato exacto
except Exception as e:
print(f"ERROR en verificación de funcionamiento: {type(e).__name__}: {e}")
return False
async def main():
print("=" * 50)
print("VERIFICACIÓN DE INSTALACIÓN - Claude Code SDK")
print("=" * 50)
print()
checks = [
("Python Version", verificar_python()),
("Claude Code CLI", verificar_claude_cli()),
("API Key", verificar_api_key()),
("SDK Import", verificar_sdk_import()),
]
todos_ok = all(resultado for _, resultado in checks)
if todos_ok:
print()
funcionamiento = await verificar_funcionamiento()
checks.append(("Funcionamiento", funcionamiento))
print()
print("=" * 50)
print("RESUMEN")
print("=" * 50)
for nombre, resultado in checks:
estado = "✓" if resultado else "✗"
print(f" {estado} {nombre}")
todos_ok = all(r for _, r in checks)
print()
if todos_ok:
print("La instalación está completa y funcionando correctamente.")
else:
print("Hay problemas en la instalación. Revisa los errores arriba.")
sys.exit(1)
if __name__ == "__main__":
asyncio.run(main())
4. Instalación del SDK TypeScript/Node.js
4.1 Instalación básica con npm
# Crear directorio del proyecto
mkdir mi-agente-ts && cd mi-agente-ts
npm init -y
# Instalar el SDK
npm install @anthropic-ai/claude-code-sdk
# Verificar instalación
node -e "const sdk = require('@anthropic-ai/claude-code-sdk'); console.log('SDK cargado:', Object.keys(sdk))"
# Verificar versión
node -e "console.log(require('@anthropic-ai/claude-code-sdk/package.json').version)"
4.2 Instalación con pnpm (recomendado para monorepos)
# Instalar pnpm si no lo tienes
npm install -g pnpm
# Crear proyecto
mkdir mi-agente-ts && cd mi-agente-ts
pnpm init
# Instalar SDK
pnpm add @anthropic-ai/claude-code-sdk
# Instalar dependencias de desarrollo
pnpm add -D typescript @types/node tsx vitest
# Verificar
pnpm list @anthropic-ai/claude-code-sdk
4.3 Instalación con Bun
# Instalar Bun si no lo tienes
curl -fsSL https://bun.sh/install | bash
# Crear proyecto
mkdir mi-agente-bun && cd mi-agente-bun
bun init
# Instalar SDK
bun add @anthropic-ai/claude-code-sdk
# Ejecutar directamente con Bun
bun run src/agente.ts
Nota sobre Bun: El SDK no está oficialmente soportado con Bun como runtime. Puede funcionar para casos simples pero puede tener problemas con el manejo de subprocesos.
4.4 ESM vs CommonJS
El SDK usa ES Modules (ESM) de forma nativa. Para TypeScript moderno:
Para proyectos ESM (recomendado):
// package.json
{
"type": "module",
"dependencies": {
"@anthropic-ai/claude-code-sdk": "^0.2.0"
}
}
// ✓ Importación ESM
import { query, ClaudeCodeOptions } from "@anthropic-ai/claude-code-sdk";
Para proyectos CommonJS (compatibilidad legacy):
// package.json
{
"type": "commonjs"
}
// El SDK tiene exports para CJS también
const { query } = require("@anthropic-ai/claude-code-sdk");
// Para TypeScript con CJS:
import { query } from "@anthropic-ai/claude-code-sdk";
// (funciona con moduleResolution: "bundler" o "node16")
4.5 Tipos TypeScript disponibles
El SDK exporta los siguientes tipos principales:
import {
// Función principal
query,
// Opciones de configuración
ClaudeCodeOptions,
// Tipos de mensajes del stream
AssistantMessage,
ResultMessage,
SystemMessage,
// Tipos de contenido en mensajes
TextBlock,
ToolUseBlock,
ToolResultBlock,
// Tipos de error
CLINotFoundError,
CLIConnectionError,
ProcessError,
// Tipos de permisos
PermissionMode,
// Tipo para hooks
HookDefinition,
} from "@anthropic-ai/claude-code-sdk";
// Ejemplo de uso con tipos estrictos
const opciones: ClaudeCodeOptions = {
cwd: "/mi/proyecto",
maxTurns: 20,
permissionMode: "acceptEdits" as PermissionMode,
};
4.6 Verificar la instalación TypeScript
// verificar-instalacion.ts
import { query, ClaudeCodeOptions } from "@anthropic-ai/claude-code-sdk";
import { execSync } from "child_process";
function verificarCLI(): boolean {
try {
const version = execSync("claude --version", { encoding: "utf-8" }).trim();
console.log(`OK: Claude Code CLI: ${version}`);
return true;
} catch {
console.error("ERROR: Claude Code CLI no encontrado");
console.error(" Instala con: npm install -g @anthropic-ai/claude-code");
return false;
}
}
function verificarApiKey(): boolean {
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
console.error("ERROR: ANTHROPIC_API_KEY no configurada");
return false;
}
console.log(`OK: ANTHROPIC_API_KEY: ${apiKey.slice(0, 15)}...`);
return true;
}
async function verificarFuncionamiento(): Promise<boolean> {
console.log("Haciendo llamada de prueba...");
try {
for await (const message of query({
prompt: "Responde únicamente con: VERIFICACION_EXITOSA",
options: { maxTurns: 3 } as ClaudeCodeOptions,
})) {
if (message.type === "result") {
if (message.result?.includes("VERIFICACION_EXITOSA")) {
console.log(`OK: Respuesta correcta: '${message.result.trim()}'`);
} else {
console.log(`OK: Agente respondió (sin formato exacto): '${message.result?.slice(0, 50)}'`);
}
return true;
}
}
return false;
} catch (error) {
console.error(`ERROR: ${error instanceof Error ? error.message : String(error)}`);
return false;
}
}
async function main() {
console.log("=".repeat(50));
console.log("VERIFICACIÓN - Claude Code SDK (TypeScript)");
console.log("=".repeat(50));
console.log();
const checks: Array<[string, boolean]> = [
["Node.js Version", parseInt(process.version.slice(1)) >= 18],
["Claude Code CLI", verificarCLI()],
["API Key", verificarApiKey()],
];
console.log(`OK: Node.js ${process.version}`);
const todosOk = checks.every(([, r]) => r);
if (todosOk) {
console.log();
const funciona = await verificarFuncionamiento();
checks.push(["Funcionamiento", funciona]);
}
console.log();
console.log("=".repeat(50));
for (const [nombre, resultado] of checks) {
console.log(` ${resultado ? "✓" : "✗"} ${nombre}`);
}
if (!checks.every(([, r]) => r)) {
process.exit(1);
}
}
main().catch(console.error);
5. Configuración de API Key y Secrets
5.1 Métodos de configuración
flowchart TD
A["¿Cómo configurar ANTHROPIC_API_KEY?"] --> B{"¿Entorno de producción?"}
B -->|Sí| C["Usar secrets manager<br/>(AWS Secrets, Vault, etc.)"]
B -->|No| D{"¿Desarrollo local?"}
D -->|Sí| E["Archivo .env con dotenv"]
D -->|No| F{"¿CI/CD?"}
F -->|Sí| G["Variables de entorno del CI<br/>(GitHub Actions, etc.)"]
F -->|No| H["Variable de entorno del shell"]
C --> I["NUNCA hardcodear en código"]
E --> I
G --> I
H --> I
5.2 Configuración con archivo .env
Python con python-dotenv:
# Instalar
pip install python-dotenv
# src/agente.py - al inicio del archivo
import os
from dotenv import load_dotenv
# Cargar el .env ANTES de importar el SDK
load_dotenv()
# Ahora el SDK puede acceder a ANTHROPIC_API_KEY
from claude_code_sdk import query, ClaudeCodeOptions
# Verificar que la key está disponible
api_key = os.getenv("ANTHROPIC_API_KEY")
if not api_key:
raise ValueError("ANTHROPIC_API_KEY no configurada. Copia .env.example a .env y agrega tu key.")
TypeScript con dotenv:
// src/agente.ts - al inicio del archivo
import "dotenv/config"; // Carga .env automáticamente
// Alternativa más explícita:
import { config } from "dotenv";
config(); // Carga .env
// Ahora el SDK puede acceder a ANTHROPIC_API_KEY
import { query, ClaudeCodeOptions } from "@anthropic-ai/claude-code-sdk";
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
throw new Error("ANTHROPIC_API_KEY no configurada");
}
Archivo .env:
# .env - NUNCA committear este archivo al repositorio
ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Opcionales
CLAUDE_MODEL=claude-sonnet-4-5
MAX_TURNS=20
LOG_LEVEL=info
Archivo .env.example (sí committear):
# .env.example - plantilla para configurar el entorno
# Copia este archivo a .env y completa los valores
# REQUERIDO: Tu API Key de Anthropic
# Obtén una en: https://console.anthropic.com/
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxx
# OPCIONAL: Modelo a usar (default: claude-sonnet-4-5)
# Opciones: claude-opus-4-5, claude-sonnet-4-5, claude-haiku-3-5
CLAUDE_MODEL=claude-sonnet-4-5
# OPCIONAL: Máximo de turnos del agente (default: 20)
MAX_TURNS=20
5.3 Configuración en CI/CD (GitHub Actions)
# .github/workflows/agente.yml
name: Ejecutar Agente de Análisis
on:
push:
branches: [main]
pull_request:
jobs:
analisis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js (para Claude Code CLI)
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Instalar Claude Code CLI
run: npm install -g @anthropic-ai/claude-code
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Instalar dependencias Python
run: pip install claude-code-sdk python-dotenv
- name: Ejecutar agente de análisis
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # Configurado en GitHub Secrets
run: python src/agente.py .
5.4 Anti-patrón: hardcodear la API key
# MAL: NUNCA hagas esto
from claude_code_sdk import query, ClaudeCodeOptions
# La API key está expuesta en el código fuente
options = ClaudeCodeOptions(
# ERROR: Si subes esto a GitHub, tu key queda expuesta públicamente
api_key="sk-ant-api03-xxxxxxx" # NUNCA hagas esto
)
# BIEN: Siempre usa variables de entorno
import os
from dotenv import load_dotenv
load_dotenv()
# El SDK lee ANTHROPIC_API_KEY del entorno automáticamente
options = ClaudeCodeOptions(cwd="/mi/proyecto")
6. Configuración Avanzada con ClaudeCodeOptions
ClaudeCodeOptions es la clase principal de configuración del SDK. Aquí están todas las opciones disponibles con explicación detallada.
6.1 Tabla completa de opciones
| Opción | Tipo | Default | Descripción |
|---|---|---|---|
cwd | str | Path | Process cwd | Directorio de trabajo del agente |
max_turns (Python) / maxTurns (TS) | int | Ilimitado | Máximo de iteraciones del loop |
permission_mode (Python) / permissionMode (TS) | str | "default" | Control de permisos de herramientas |
system_prompt (Python) / systemPrompt (TS) | str | None | Prompt de sistema adicional |
model | str | "claude-sonnet-4-5" | Modelo de Claude a usar |
cli_path (Python) / cliPath (TS) | str | "claude" | Ruta al binario de Claude Code |
api_key (Python) / apiKey (TS) | str | Env var | API key (mejor usar env var) |
mcp_servers (Python) / mcpServers (TS) | list[dict] | [] | Servidores MCP a conectar |
6.2 permission_mode: explicación detallada
El modo de permisos controla qué acciones puede tomar el agente sin pedir confirmación:
from claude_code_sdk import query, ClaudeCodeOptions
# MODO "default": Claude pide permiso antes de acciones potencialmente peligrosas
# Úsalo cuando: el agente puede interactuar con un humano
options_interactivo = ClaudeCodeOptions(
permission_mode="default"
# El agente pausará y pedirá confirmación antes de:
# - Ejecutar comandos bash que modifican el sistema
# - Escribir en archivos fuera del cwd
# - Acciones destructivas
)
# MODO "acceptEdits": acepta automáticamente cambios en archivos
# Úsalo cuando: quieres que el agente modifique código automáticamente
# pero no ejecute comandos arbitrarios
options_edicion = ClaudeCodeOptions(
permission_mode="acceptEdits"
# El agente puede: Read, Write, Edit sin confirmación
# El agente NO puede: Bash (o pedirá permiso)
)
# MODO "bypassPermissions": acepta todo sin preguntar
# Úsalo cuando: automatización de confianza total, scripts internos
# ADVERTENCIA: permite ejecución de comandos bash, borrar archivos, etc.
options_automatico = ClaudeCodeOptions(
permission_mode="bypassPermissions"
# El agente puede hacer TODO sin preguntar
# Usa con extremo cuidado y solo con prompts confiables
)
// Lo mismo en TypeScript
const opcionesDefault: ClaudeCodeOptions = {
permissionMode: "default",
};
const opcionesEdicion: ClaudeCodeOptions = {
permissionMode: "acceptEdits",
};
const opcionesAutomatico: ClaudeCodeOptions = {
permissionMode: "bypassPermissions",
};
6.3 Configuración del modelo
from claude_code_sdk import query, ClaudeCodeOptions
# Modelos disponibles y sus casos de uso:
# claude-opus-4-5 → Tareas complejas, razonamiento profundo, más caro
# claude-sonnet-4-5 → Balance costo/capacidad, uso general (DEFAULT)
# claude-haiku-3-5 → Tareas simples, muy económico, más rápido
# Para análisis de código complejo:
opciones_opus = ClaudeCodeOptions(
model="claude-opus-4-5",
max_turns=30
)
# Para automatización de volumen alto:
opciones_haiku = ClaudeCodeOptions(
model="claude-haiku-3-5",
max_turns=10
)
# Para uso general (recomendado):
opciones_sonnet = ClaudeCodeOptions(
model="claude-sonnet-4-5",
max_turns=20
)
6.4 system_prompt: dar instrucciones permanentes al agente
from claude_code_sdk import query, ClaudeCodeOptions
# El system_prompt se agrega ANTES de cada conversación
# Es ideal para definir el rol, restricciones y convenciones
options = ClaudeCodeOptions(
cwd="/mi/proyecto",
system_prompt="""Eres un experto en Python senior trabajando en este proyecto.
RESTRICCIONES:
- Solo trabaja en archivos dentro de src/ y tests/
- NUNCA modifiques pyproject.toml, .env, o archivos de configuración
- NUNCA ejecutes comandos con sudo
- NUNCA instales paquetes nuevos sin pedirme confirmación
CONVENCIONES DEL PROYECTO:
- Usamos Black para formateo (88 caracteres por línea)
- Docstrings en formato Google
- Type hints obligatorios en todas las funciones públicas
- Principios SOLID: funciones de máximo 30 líneas
ANTES DE HACER CAMBIOS:
1. Lee el archivo completo para entender el contexto
2. Busca tests existentes relacionados
3. Verifica que el cambio no rompe la interfaz pública"""
)
async for message in query(
prompt="Refactoriza src/auth/login.py para mejorar el manejo de errores",
options=options
):
# ...
pass
6.5 Configuración de proxies y entornos corporativos
import os
from claude_code_sdk import query, ClaudeCodeOptions
# Si estás detrás de un proxy corporativo:
os.environ["HTTPS_PROXY"] = "https://proxy.empresa.com:8080"
os.environ["HTTP_PROXY"] = "http://proxy.empresa.com:8080"
os.environ["NO_PROXY"] = "localhost,127.0.0.1"
# El SDK heredará estas variables de entorno al spawnar Claude Code
# Para certificados SSL corporativos:
os.environ["NODE_EXTRA_CA_CERTS"] = "/path/to/corporate-ca.crt"
# Claude Code respeta las variables de entorno estándar de proxy
options = ClaudeCodeOptions(cwd="/mi/proyecto")
6.6 Configuración completa: ejemplo real de producción
"""
configuracion_produccion.py
Configuraciones listas para usar en diferentes contextos de producción.
"""
import os
from pathlib import Path
from claude_code_sdk import ClaudeCodeOptions
MODELO_DEFAULT = os.getenv("CLAUDE_MODEL", "claude-sonnet-4-5")
MAX_TURNS_DEFAULT = int(os.getenv("MAX_TURNS", "20"))
def config_code_review(repo_path: str) -> ClaudeCodeOptions:
"""Para revisiones de código automatizadas en CI/CD."""
return ClaudeCodeOptions(
cwd=repo_path,
max_turns=15,
permission_mode="bypassPermissions", # Solo lectura en práctica
model=MODELO_DEFAULT,
system_prompt="""Eres un revisor de código experto.
IMPORTANTE: Este agente SOLO debe LEER archivos, NO escribir ni modificar nada.
Analiza el código y genera un reporte sin hacer ningún cambio.""",
)
def config_refactor_automatico(repo_path: str) -> ClaudeCodeOptions:
"""Para refactoring automático con verificación de tests."""
return ClaudeCodeOptions(
cwd=repo_path,
max_turns=MAX_TURNS_DEFAULT,
permission_mode="acceptEdits",
model="claude-opus-4-5", # Más capaz para refactoring complejo
system_prompt="""Eres un experto en refactoring de código.
Antes de cualquier cambio: lee el archivo completo y sus tests.
Después de cada cambio: verifica que los tests aún pasan.
Si un cambio puede romper la API pública, documéntalo en un comentario.""",
)
def config_generacion_documentacion(repo_path: str) -> ClaudeCodeOptions:
"""Para generar documentación automáticamente."""
return ClaudeCodeOptions(
cwd=repo_path,
max_turns=30,
permission_mode="acceptEdits",
model=MODELO_DEFAULT,
system_prompt="""Genera documentación técnica clara y precisa.
Usa Markdown con formato excelente.
Incluye ejemplos de código para cada función pública.
NO expliques el código en voz pasiva; usa voz activa y lenguaje directo.""",
)
// configuracion-produccion.ts
import { ClaudeCodeOptions } from "@anthropic-ai/claude-code-sdk";
const MODELO_DEFAULT = process.env.CLAUDE_MODEL || "claude-sonnet-4-5";
const MAX_TURNS_DEFAULT = parseInt(process.env.MAX_TURNS || "20");
export const configCodeReview = (repoPath: string): ClaudeCodeOptions => ({
cwd: repoPath,
maxTurns: 15,
permissionMode: "bypassPermissions",
model: MODELO_DEFAULT,
systemPrompt: `Eres un revisor de código experto.
IMPORTANTE: Solo LEE archivos, NO escribas ni modifiques nada.
Genera un reporte de code review sin hacer cambios.`,
});
export const configRefactor = (repoPath: string): ClaudeCodeOptions => ({
cwd: repoPath,
maxTurns: MAX_TURNS_DEFAULT,
permissionMode: "acceptEdits",
model: "claude-opus-4-5",
systemPrompt: `Eres un experto en refactoring.
Lee el archivo completo antes de cualquier cambio.
Verifica la consistencia con el resto del codebase.`,
});
7. Estructura de Proyecto Recomendada
7.1 Estructura Python completa
mi-agente-python/
│
├── .env # API keys (NO en git)
├── .env.example # Plantilla (SÍ en git)
├── .gitignore
├── pyproject.toml # Configuración del proyecto
├── CLAUDE.md # Instrucciones para el agente
│
├── src/
│ └── mi_agente/
│ ├── __init__.py
│ ├── agente.py # Función principal del agente
│ ├── config.py # ClaudeCodeOptions reutilizables
│ ├── cli.py # Interfaz de línea de comandos
│ │
│ ├── hooks/ # Hooks pre/post herramienta
│ │ ├── __init__.py
│ │ ├── auditoria.py # Logging de todas las acciones
│ │ └── seguridad.py # Rechazar acciones peligrosas
│ │
│ └── utils/
│ ├── __init__.py
│ └── reportes.py # Formatear y guardar reportes
│
└── tests/
├── __init__.py
├── conftest.py # Fixtures de pytest
├── test_agente.py # Tests del agente
└── test_hooks.py # Tests de hooks
src/mi_agente/__init__.py:
"""Mi Agente - Automatización con Claude Code SDK."""
from .agente import ejecutar_agente
from .config import config_lectura, config_escritura
__all__ = ["ejecutar_agente", "config_lectura", "config_escritura"]
__version__ = "0.1.0"
src/mi_agente/agente.py:
"""Función principal del agente."""
import asyncio
from claude_code_sdk import query, ClaudeCodeOptions
from .config import config_lectura
async def ejecutar_agente(
prompt: str,
proyecto_path: str,
opciones: ClaudeCodeOptions | None = None
) -> str:
"""
Ejecuta el agente con el prompt dado y retorna el resultado.
Args:
prompt: Instrucción para el agente
proyecto_path: Ruta al proyecto donde trabaja el agente
opciones: ClaudeCodeOptions personalizado (opcional)
Returns:
str: Resultado final del agente
"""
if opciones is None:
opciones = config_lectura(proyecto_path)
resultado_final = ""
async for message in query(prompt=prompt, options=opciones):
if hasattr(message, 'result') and message.result:
resultado_final = message.result
return resultado_final
7.2 Estructura TypeScript completa
mi-agente-ts/
│
├── .env
├── .env.example
├── .gitignore
├── package.json
├── tsconfig.json
├── CLAUDE.md
│
├── src/
│ ├── index.ts # Entry point / CLI
│ ├── agente.ts # Función principal
│ ├── config.ts # ClaudeCodeOptions reutilizables
│ │
│ ├── hooks/
│ │ ├── auditoria.ts # Logging de acciones
│ │ └── seguridad.ts # Bloquear acciones peligrosas
│ │
│ └── utils/
│ └── reportes.ts # Formatear resultados
│
└── tests/
├── agente.test.ts
└── hooks.test.ts
7.3 .gitignore adecuado
# Secrets y configuración local
.env
.env.local
.env.*.local
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
.venv/
venv/
ENV/
.eggs/
*.egg-info/
dist/
build/
# Node.js
node_modules/
dist/
.next/
.nuxt/
# Claude Code
.claude/
.claude-checkpoints/
# Logs del agente
logs/
*.log
agent-output/
# IDEs
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
8. Primer Agente Verificable
8.1 Python: agente hello world completo
#!/usr/bin/env python3
"""
hello_agent.py
El agente más simple posible: analiza el directorio actual y genera un resumen.
"""
import asyncio
import os
from pathlib import Path
from dotenv import load_dotenv
# PASO 1: Cargar variables de entorno
load_dotenv()
# PASO 2: Verificar prerequisitos
if not os.getenv("ANTHROPIC_API_KEY"):
print("ERROR: Configura ANTHROPIC_API_KEY en tu .env o variable de entorno")
exit(1)
from claude_code_sdk import query, ClaudeCodeOptions
async def main():
# PASO 3: Configurar el agente
directorio = Path.cwd()
options = ClaudeCodeOptions(
cwd=str(directorio),
max_turns=5, # Límite corto para el hello world
permission_mode="bypassPermissions", # Solo lectura
)
print(f"Analizando directorio: {directorio}")
print("-" * 40)
# PASO 4: Ejecutar el agente
mensajes_recibidos = 0
costo = 0.0
async for message in query(
prompt="Mira qué hay en el directorio actual (usa ls o Glob) y dame un resumen de 3 líneas de qué proyecto es este.",
options=options
):
mensajes_recibidos += 1
# Ver el "pensamiento" del agente en tiempo real
if hasattr(message, 'content'):
for block in message.content:
if hasattr(block, 'text') and block.text.strip():
print(f"Claude: {block.text.strip()[:200]}")
# El resultado final
if hasattr(message, 'result'):
print()
print("=" * 40)
print("RESULTADO FINAL:")
print(message.result)
costo = getattr(message, 'cost_usd', 0) or 0
turnos = getattr(message, 'num_turns', 0)
print()
print(f"Turnos: {turnos} | Costo: ${costo:.6f} USD")
print(f"Mensajes totales recibidos: {mensajes_recibidos}")
if __name__ == "__main__":
asyncio.run(main())
Output esperado al ejecutar:
Analizando directorio: /home/dev/mi-proyecto
----------------------------------------
Claude: Voy a explorar el directorio actual para entender qué proyecto es este.
Claude: He visto los archivos. Es un proyecto TypeScript con Express...
========================================
RESULTADO FINAL:
Este es un proyecto de API REST en TypeScript usando Express.js con PostgreSQL.
Tiene estructura de Clean Architecture con controllers, use cases y repositories.
Incluye tests con Jest y tiene configuración de Docker para desarrollo.
Turnos: 3 | Costo: $0.000234 USD
Mensajes totales recibidos: 7
8.2 TypeScript: agente hello world completo
// hello-agent.ts
import "dotenv/config";
import { query, ClaudeCodeOptions } from "@anthropic-ai/claude-code-sdk";
import { resolve } from "path";
// Verificar prerequisitos
if (!process.env.ANTHROPIC_API_KEY) {
console.error("ERROR: Configura ANTHROPIC_API_KEY en tu .env");
process.exit(1);
}
async function main() {
const directorio = resolve(process.cwd());
const options: ClaudeCodeOptions = {
cwd: directorio,
maxTurns: 5,
permissionMode: "bypassPermissions",
};
console.log(`Analizando directorio: ${directorio}`);
console.log("-".repeat(40));
let costo = 0;
let turnos = 0;
for await (const message of query({
prompt: "Mira qué hay en el directorio actual y dame un resumen de 3 líneas de qué proyecto es.",
options,
})) {
// Ver el pensamiento del agente
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "text" && block.text.trim()) {
console.log(`Claude: ${block.text.slice(0, 200)}`);
}
}
}
// Resultado final
if (message.type === "result") {
console.log();
console.log("=".repeat(40));
console.log("RESULTADO FINAL:");
console.log(message.result);
costo = message.cost_usd || 0;
turnos = message.num_turns;
console.log();
console.log(`Turnos: ${turnos} | Costo: $${costo.toFixed(6)} USD`);
}
}
}
main().catch(console.error);
9. Configuración de IDE
9.1 Visual Studio Code
Extensiones recomendadas para desarrollo con el SDK:
// .vscode/extensions.json
{
"recommendations": [
"ms-python.python", // Python Language Server
"ms-python.mypy-type-checker", // Type checking
"charliermarsh.ruff", // Linting y formateo Python
"dbaeumer.vscode-eslint", // ESLint para TypeScript
"esbenp.prettier-vscode", // Formateo TypeScript
"ms-vscode.vscode-typescript-next", // TypeScript moderno
"bradlc.vscode-tailwindcss", // Si usas Tailwind
"usernamehw.errorlens" // Errores inline en el código
]
}
Configuración de debugging para el agente Python:
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Agente Python",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/src/agente.py",
"console": "integratedTerminal",
"envFile": "${workspaceFolder}/.env",
"args": ["${workspaceFolder}"], // Directorio a analizar
"justMyCode": false // Para ver el código del SDK también
},
{
"name": "Debug Agente TypeScript",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/src/agente.ts",
"runtimeExecutable": "tsx",
"envFile": "${workspaceFolder}/.env",
"console": "integratedTerminal"
}
]
}
Configuración de settings para el proyecto:
// .vscode/settings.json
{
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"editor.formatOnSave": true,
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit"
}
}
9.2 Punto de breakpoint útiles para debugging
# Para debuggear el stream de mensajes del agente:
import asyncio
from claude_code_sdk import query, ClaudeCodeOptions
async def debug_agente():
async for message in query(prompt="Lista los archivos"):
# PON UN BREAKPOINT EN ESTA LÍNEA para inspeccionar cada mensaje
tipo = type(message).__name__
print(f"Tipo de mensaje: {tipo}")
print(f"Atributos: {vars(message)}")
# El debugger se detendrá aquí para cada mensaje del stream
asyncio.run(debug_agente())
10. Troubleshooting de Instalación
10.1 Tabla de errores comunes y soluciones
| Error | Causa | Solución |
|---|---|---|
CLINotFoundError | Claude Code CLI no instalado | npm install -g @anthropic-ai/claude-code |
ANTHROPIC_API_KEY not set | Variable de entorno no configurada | Exportar la variable o crear .env |
Invalid API key | Key incorrecta o expirada | Generar nueva key en console.anthropic.com |
Connection refused | Sin conexión a internet o proxy | Verificar red, configurar proxy |
ModuleNotFoundError: claude_code_sdk | SDK Python no instalado | pip install claude-code-sdk |
Cannot find module '@anthropic-ai/claude-code-sdk' | SDK TS no instalado | npm install @anthropic-ai/claude-code-sdk |
Permission denied executing claude | Permisos del binario | chmod +x $(which claude) |
TimeoutError | Tarea muy larga | Aumentar timeout o dividir en subtareas |
ProcessError: non-zero exit | Error interno del agente | Ver mensaje de error, puede ser problema de API key |
Python 3.9 not supported | Versión antigua | Actualizar a Python 3.10+ |
10.2 Error: CLINotFoundError
import asyncio
from claude_code_sdk import query, ClaudeCodeOptions
from claude_code_sdk.errors import CLINotFoundError # Importar el error específico
async def main():
try:
async for message in query(prompt="Hola"):
pass
except CLINotFoundError as e:
print(f"Claude Code CLI no encontrado: {e}")
print()
print("Soluciones:")
print(" 1. npm install -g @anthropic-ai/claude-code")
print(" 2. brew install --cask claude-code (macOS)")
print(" 3. Verifica que 'claude' está en el PATH: which claude")
print()
print("Si está instalado pero no se encuentra:")
print(" export PATH=$(npm bin -g):$PATH")
Para un cli_path personalizado:
import shutil
from claude_code_sdk import ClaudeCodeOptions
# Si tienes Claude Code en una ruta no estándar
ruta_claude = shutil.which("claude") or "/ruta/alternativa/claude"
options = ClaudeCodeOptions(
cli_path=ruta_claude
)
10.3 Error: API Key inválida
# Verificar que la variable está configurada
echo $ANTHROPIC_API_KEY
# Verificar el formato correcto (debe empezar con sk-ant-)
echo $ANTHROPIC_API_KEY | grep -q "^sk-ant-" && echo "Formato OK" || echo "Formato incorrecto"
# Probar la API key directamente con curl
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model": "claude-haiku-3-5", "max_tokens": 10, "messages": [{"role": "user", "content": "Hi"}]}'
# Si la key es válida, verás una respuesta JSON con el mensaje
# Si es inválida, verás: {"type":"error","error":{"type":"authentication_error",...}}
10.4 Error: Connection / Timeout
import asyncio
import os
from claude_code_sdk import query, ClaudeCodeOptions
async def query_con_retry(prompt: str, max_intentos: int = 3) -> str:
"""Wrapper con retry automático para errores de conexión."""
from claude_code_sdk.errors import CLIConnectionError
for intento in range(1, max_intentos + 1):
try:
resultado = ""
async for message in query(prompt=prompt):
if hasattr(message, 'result'):
resultado = message.result or ""
return resultado
except CLIConnectionError as e:
if intento == max_intentos:
raise
print(f"Error de conexión (intento {intento}/{max_intentos}): {e}")
print(f"Reintentando en {intento * 2} segundos...")
await asyncio.sleep(intento * 2)
return ""
10.5 Error: ProcessError
import asyncio
from claude_code_sdk import query
from claude_code_sdk.errors import ProcessError
async def main():
try:
async for message in query(prompt="Hola"):
pass
except ProcessError as e:
print(f"Error del proceso Claude: {e}")
print(f"Código de salida: {e.returncode}")
print(f"Stderr: {e.stderr}")
# Causas comunes:
if "ANTHROPIC_API_KEY" in str(e):
print("→ Configura tu API key")
elif "rate limit" in str(e).lower():
print("→ Excediste el rate limit. Espera unos segundos.")
elif "context length" in str(e).lower():
print("→ El contexto es muy grande. Reduce el scope del agente.")
10.6 Diagnóstico completo del entorno
#!/bin/bash
# diagnostico.sh - Script de diagnóstico completo
echo "=== DIAGNÓSTICO CLAUDE CODE SDK ==="
echo
echo "1. Sistema operativo:"
uname -a
echo
echo "2. Python:"
python --version 2>/dev/null || python3 --version 2>/dev/null || echo " Python no encontrado"
echo
echo "3. Node.js:"
node --version 2>/dev/null || echo " Node.js no encontrado"
echo
echo "4. npm:"
npm --version 2>/dev/null || echo " npm no encontrado"
echo
echo "5. Claude Code CLI:"
claude --version 2>/dev/null || echo " Claude Code CLI no encontrado (ejecuta: npm install -g @anthropic-ai/claude-code)"
which claude 2>/dev/null || echo " claude no está en PATH"
echo
echo "6. ANTHROPIC_API_KEY:"
if [ -n "$ANTHROPIC_API_KEY" ]; then
echo " Configurada: ${ANTHROPIC_API_KEY:0:15}..."
else
echo " NO configurada"
fi
echo
echo "7. claude-code-sdk Python:"
pip show claude-code-sdk 2>/dev/null | grep "Version" || echo " No instalado (ejecuta: pip install claude-code-sdk)"
echo
echo "8. @anthropic-ai/claude-code-sdk:"
npm list @anthropic-ai/claude-code-sdk 2>/dev/null | grep "claude-code-sdk" || echo " No instalado en este directorio"
echo
echo "=== FIN DIAGNÓSTICO ==="
# Ejecutar el script de diagnóstico
chmod +x diagnostico.sh
./diagnostico.sh
11. Uso con Docker y Contenedores
11.1 Dockerfile Python de producción
# Dockerfile.python-produccion
# Imagen optimizada para producción
# Etapa 1: Builder
FROM python:3.12-slim AS builder
WORKDIR /app
# Instalar dependencias de build
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
# Etapa 2: Runtime
FROM python:3.12-slim AS runtime
# Instalar Node.js y npm (necesario para Claude Code CLI)
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# Instalar Claude Code CLI
RUN npm install -g @anthropic-ai/claude-code
# Copiar paquetes Python instalados desde builder
COPY --from=builder /root/.local /root/.local
WORKDIR /app
# Copiar código de la aplicación
COPY src/ ./src/
COPY CLAUDE.md ./
# Usuario no-root por seguridad
RUN useradd -m -u 1000 agente && chown -R agente:agente /app
USER agente
# Variables de entorno
ENV PATH=/root/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# La API key se provee en runtime, no en build
ENV ANTHROPIC_API_KEY=""
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import claude_code_sdk; print('OK')" || exit 1
CMD ["python", "src/agente.py"]
11.2 Dockerfile Node.js de producción
# Dockerfile.nodejs-produccion
FROM node:20-slim AS builder
WORKDIR /app
# Instalar dependencias
COPY package*.json tsconfig.json ./
RUN npm ci
# Compilar TypeScript
COPY src/ ./src/
RUN npm run build
FROM node:20-slim AS runtime
WORKDIR /app
# Instalar Claude Code CLI globalmente
RUN npm install -g @anthropic-ai/claude-code
# Copiar solo los archivos necesarios para producción
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
COPY CLAUDE.md ./
# Usuario no-root
RUN useradd -m -u 1000 agente && chown -R agente:agente /app
USER agente
ENV NODE_ENV=production
ENV ANTHROPIC_API_KEY=""
HEALTHCHECK --interval=30s --timeout=10s \
CMD node -e "require('@anthropic-ai/claude-code-sdk'); process.exit(0)" || exit 1
CMD ["node", "dist/index.js"]
11.3 docker-compose.yml para desarrollo
# docker-compose.yml
version: "3.9"
services:
agente-python:
build:
context: .
dockerfile: Dockerfile.python-produccion
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- CLAUDE_MODEL=${CLAUDE_MODEL:-claude-sonnet-4-5}
- MAX_TURNS=${MAX_TURNS:-20}
volumes:
# Montar el proyecto a analizar (solo lectura)
- ${PROJECT_PATH:-./proyecto}:/proyecto:ro
# Montar código del agente para desarrollo (lectura-escritura)
- ./src:/app/src
# Guardar outputs del agente
- ./output:/app/output
working_dir: /app
restart: unless-stopped
agente-typescript:
build:
context: .
dockerfile: Dockerfile.nodejs-produccion
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- NODE_ENV=production
volumes:
- ${PROJECT_PATH:-./proyecto}:/proyecto:ro
- ./output:/app/output
restart: unless-stopped
# Uso del docker-compose
export ANTHROPIC_API_KEY=sk-ant-xxxxxx
export PROJECT_PATH=/ruta/a/mi/proyecto
# Iniciar los servicios
docker-compose up -d
# Ver logs del agente
docker-compose logs -f agente-python
# Detener
docker-compose down
11.4 Consideraciones de seguridad en Docker
Cuando ejecutas el SDK en Docker, el agente tiene acceso al filesystem del contenedor. Para limitar el alcance:
# docker-compose.yml con restricciones de seguridad
services:
agente-seguro:
build: .
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
volumes:
# SOLO montar el directorio específico que el agente necesita
- ${PROJECT_PATH}:/proyecto:ro # Solo lectura
# Limitar recursos
deploy:
resources:
limits:
cpus: "2"
memory: 2G
# Security options
security_opt:
- no-new-privileges:true
read_only: false # El agente puede necesitar escribir en /tmp
tmpfs:
- /tmp # Solo escritura en memoria temporal
Anterior: Capítulo 1: Introducción al Claude Code SDK Siguiente: Capítulo 3: Query Básico y Tipos de Mensajes