Cada llamada a la API de Claude es independiente. Claude NO recuerda nada entre requests. No hay session_id, no hay memoria server-side, no hay base de datos automática.
Si quieres una conversación multi-turno, tú debes pasar el historial completo en el array messages de cada request. Esto explica por qué las conversaciones largas se vuelven caras y lentas: cada turno acumula más tokens.
stop_reason — cómo saber por qué Claude terminóCada respuesta de Claude incluye un campo stop_reason que indica POR QUÉ paró de generar. Es la única forma confiable de detectar el fin de un turno (NUNCA parsear el texto).
| Valor | Significado | Qué hacer |
|---|---|---|
"end_turn" | Claude terminó voluntariamente | Mostrar resultado al usuario |
"tool_use" | Claude quiere llamar una herramienta | Ejecutar la tool, devolver tool_result |
"max_tokens" | Se acabaron los tokens permitidos | Respuesta truncada — aumentar límite o dividir tarea |
"stop_sequence" | Se generó una secuencia que TÚ definiste | Procesar según tu lógica |
"refusal" | Claude se negó por razones de seguridad | Reformular el prompt |
stop_reason === "tool_use", ejecutar la tool y devolver el resultado en un nuevo mensaje user. 3) Si stop_reason === "end_turn", terminar y mostrar. 4) Repetir.max_iterations=5 como mecanismo principal de parada (solo como safety net). NO confiar en el contenido textual para saber si Claude terminó.El system prompt define el rol, las restricciones y el comportamiento de Claude. Tiene 3 características importantes:
system de la request, NO en el array messages. Es un parámetro separado."siempre verifica al cliente primero", Claude va a llamar a get_customer incluso cuando el usuario pregunta por el stock, donde no aplica. Sé específico sobre cuándo aplican las reglas.Claude no procesa texto, procesa tokens (fragmentos de palabras). Aproximadamente 1 token ≈ 4 caracteres en español. La ventana de contexto es el TOTAL de tokens que Claude puede ver en una sola request: system + messages + tools + tool_results.
tool_result (crece con cada tool call)max_tokens)Claude puede llamar funciones externas (tools) que TÚ defines. El modelo no las ejecuta — solo genera una solicitud estructurada para llamarlas. Tu código las ejecuta y devuelve el resultado.
Una tool se define con 3 cosas: name, description (lo más importante: así Claude decide cuándo usarla), e input_schema en JSON Schema.
"Retrieves customer information", Claude va a confundirse cuando haya 3 tools similares. Si pones una descripción detallada con casos de uso y comparaciones contra otras tools, la selección es 95%+ confiable.Cuando usas JSON Schema con tool_use, eliminas completamente los errores sintácticos (JSON malformado, tipos incorrectos, faltan llaves). Eso ya no es problema.
Pero hay otra capa: los errores semánticos. El JSON está bien escrito pero los valores son incorrectos. Para eso necesitas otro nivel de validación.
| Tipo de error | Ejemplo | Solución |
|---|---|---|
| Sintáctico | JSON inválido, tipo erróneo | tool_use con JSON Schema lo elimina 100% |
| Semántico | Total = 150, pero suma de items = 145 | Validación con Pydantic, retry con feedback |
| De fabricación | Inventó un campo que no estaba en el doc | Marcar campo como ["string", "null"] nullable |
conflict_detected cuando difieran. Así no escondes errores.El examen evalúa 5 áreas con pesos distintos. Estudia los dominios proporcional a su peso:
Un agente no es solo una respuesta de Claude. Es un loop iterativo donde Claude decide qué hacer, ejecuta, recibe feedback, y decide de nuevo. Este enfoque se llama model-driven: el modelo, no tu código, decide qué tool llamar a continuación.
max_iterations=5 como mecanismo PRINCIPAL de parada. 3) Reintentos infinitos dentro de un subagente. La señal correcta de fin SIEMPRE es stop_reason === "end_turn".
AgentDefinitionEn Claude Agent SDK, un agente se define con un objeto AgentDefinition que tiene 4 campos clave:
allowed_tools debe contener solo lo necesario. Estudios muestran que agentes con 18 tools tienen 65% de precisión de selección; con 4-5 tools, sube a 90%+. Distribuye tools entre agentes especializados, no metas todo en uno.Cuando una tarea es muy grande para un solo agente (investigación con búsqueda + análisis + síntesis), divides en coordinador + subagentes. Toda la comunicación pasa por el coordinador — los subagentes no se hablan entre sí.
Los prompts son probabilísticos. Aunque digas "nunca proceses reembolsos sobre $500", el modelo cumple ~95% de las veces. Para el 5% restante necesitas algo determinístico: hooks.
Un hook es código que se ejecuta en puntos específicos del ciclo del agente. Hay 2 tipos principales:
Hay dos formas de partir un trabajo grande:
Pasos predefinidos en secuencia:
Las subtareas se deciden en runtime:
Cuando un subagente falla, el coordinador necesita información suficiente para decidir: ¿reintentar? ¿cambiar el query? ¿escalar? ¿continuar sin esta sección? Un error genérico "Operation failed" no permite ninguna decisión inteligente.
| Categoría | Ejemplo | ¿Retry? | Acción |
|---|---|---|---|
| Transient | Timeout, 503, fallo red | Sí | Backoff exponencial |
| Validation | Input inválido, falta campo | No | Corregir input antes de retry |
| Business | Política violada, límite excedido | No | Explicar al usuario, ofrecer alternativa |
| Permission | Sin permisos de acceso | No | Escalar a humano |
--resume y fork_sessionCuando un agente trabaja durante varias horas o días, necesitas persistir el estado. Claude Agent SDK ofrece dos mecanismos:
--resume <session-name>fork_session--resume con datos viejos que pueden contradecir el estado actual del código.Model Context Protocol es un protocolo abierto (open standard) que permite a Claude conectarse a sistemas externos de forma estandarizada. En lugar de programar integraciones one-off, configuras servidores MCP y Claude las usa automáticamente.
MCP define 3 tipos de recursos. La diferencia es crítica para el examen:
list_issues es ineficiente. Mejor expone un Resource con el catálogo de issues — el agente lo lee una vez y tiene todo el "mapa" sin llamadas exploratorias.Los servidores MCP se declaran en un archivo JSON. Hay 2 niveles:
| Archivo | Alcance | VCS | Cuándo usarlo |
|---|---|---|---|
.mcp.json (raíz repo) | Proyecto, equipo | Sí, commit | Integraciones del equipo (GitHub, Jira) |
~/.claude.json | Personal, home | No | Experimentos personales |
.mcp.json.mcp.json se commitea en git (todo el equipo lo ve), pero los tokens NO. Usa ${GITHUB_TOKEN} — Claude resuelve la variable en runtime desde tu ambiente local.La description de una tool es el mecanismo principal por el que Claude decide cuándo usarla. Una mala description es la causa #1 de selección errónea de tools.
analyze_content y analyze_document con descripciones casi idénticas, Claude elegirá al azar. Renombra para eliminar solapamiento (ej. extract_web_results vs analyze_local_file) o haz las descripciones claramente distintas.El input_schema define la estructura de los parámetros. Hay 4 decisiones de diseño que cambian drásticamente el comportamiento de Claude:
| Decisión | Efecto en Claude |
|---|---|
| required solo lo SIEMPRE disponible | Required fuerza al modelo a inventar si no encuentra el dato |
nullable ["string", "null"] | El modelo devuelve null en vez de inventar |
| enum con "other" + detail | Permite categorizar sin perder casos atípicos |
| enum con "unclear" | Un "no sé" honesto > una categoría errónea |
tool_choice — controlar la selecciónA veces necesitas más control que solo "Claude decide". Para eso existe tool_choice:
| Valor | Comportamiento | Cuándo usarlo |
|---|---|---|
{"type": "auto"} | Claude decide: usar tool o responder con texto | Default, mayoría de casos |
{"type": "any"} | Claude DEBE llamar alguna tool (la que sea) | Garantizar salida estructurada |
{"type": "tool", "name": "X"} | Claude DEBE llamar la tool X específicamente | Forzar primer paso del pipeline |
{"type": "none"} | Claude solo responde con texto, sin tools | Modo conversación pura |
tool_choice: "any"extract_invoice, extract_receipt, extract_contract) y quieres garantizar que Claude SIEMPRE devuelva datos estructurados sin importar el tipo de documento. any es perfecto: Claude elige la apropiada pero TIENE que usar una.Cuando una tool MCP falla, devuelve un objeto con isError: true. Pero el contenido del error es CRÍTICO — un error genérico le impide al agente decidir cómo recuperarse.
Cuando una tool puede causar daño irreversible (eliminar un usuario, mover dinero), necesitas garantías arquitectónicas de que se ejecutó una preview antes. Un parámetro dry_run: boolean NO es suficiente — el modelo lo va a omitir el 5% de las veces.
Solución: dividir la acción en 2 tools acopladas por un token de uso único:
CLAUDE.md es donde le das instrucciones persistentes a Claude Code. Existe en 3 niveles, cada uno con un alcance distinto:
| Nivel | Ubicación | Alcance | VCS |
|---|---|---|---|
| Usuario | ~/.claude/CLAUDE.md | Solo tú, en todos tus proyectos | No (local) |
| Proyecto | .claude/CLAUDE.md o CLAUDE.md en raíz | Todo el equipo del proyecto | Sí (git) |
| Directorio | CLAUDE.md dentro de subdirs | Trabajo en ese directorio específico | Sí |
~/.claude/CLAUDE.md (nivel usuario, local) en lugar de .claude/CLAUDE.md (proyecto, versionado).@path — instrucciones modularesUn CLAUDE.md monolítico de 500 líneas es difícil de mantener. La sintaxis @path permite importar otros archivos, lo que hace tu configuración modular:
@ directo antes del path (sin espacio).claude/rules/ con paths — convenciones condicionalesCLAUDE.md aplica a TODA la conversación. Pero a veces quieres reglas que apliquen solo a ciertos archivos. Para eso existe .claude/rules/:
src/api/handler.ts, no se carga. Si trabajas en src/components/Button.test.tsx, sí. Ahorra contexto al no cargar reglas irrelevantes..claude/rules/ vs CLAUDE.md de directorio| Caso | Solución |
|---|---|
| Convenciones para archivos dispersos en muchos dirs (tests, migraciones) | .claude/rules/ con globs |
Convenciones vinculadas a un directorio específico (todo en src/api/) | CLAUDE.md de directorio |
Un skill es un comando reutilizable que se invoca con /nombre. Vive en .claude/skills/<nombre>/SKILL.md. La estructura básica:
| Campo | Para qué sirve |
|---|---|
allowed-tools | Restringe qué tools puede usar el skill (seguridad — no puede borrar archivos si no está en la lista) |
model | Fuerza un modelo específico (ej. sonnet para revisión, opus para tareas complejas) |
context: fork | Ejecuta el skill en un subagente aislado, no contamina la sesión principal con salida verbosa |
argument-hint | Pista que solicita al usuario cuando invoca sin argumentos |
Por default Claude Code ejecuta cambios inmediatamente. Para tareas grandes o ambiguas eso es peligroso. Plan Mode es un modo donde Claude SOLO explora y propone un plan, sin hacer cambios:
| Plan Mode | Ejecución directa | |
|---|---|---|
| Tools permitidas | Read, Grep, Glob (exploración) | + Write, Edit, Bash (modificación) |
| Output | Plan textual aprobable | Cambios reales en archivos |
| Reversible | Sí (no cambia nada) | Necesitas git para revertir |
Para integrar Claude Code en pipelines de CI (GitHub Actions, GitLab CI), necesitas el modo no-interactivo:
-p (o --print): procesa, imprime a stdout, termina. NO espera input.--output-format json: salida en JSON estructurado para parsing programático.--json-schema: valida la salida contra un schema. Garantiza estructura./compact, /memory, fork_session/compact/memoryfork_sessionEl few-shot prompting consiste en mostrarle a Claude 2-4 ejemplos de input/output dentro del prompt. Es más efectivo que descripciones textuales porque:
data.filter(x => x.active) ✓data.filter(x => x.active == true) ✗{amount: "~100g", precision: "approximate"}"Sé conservador" y "reporta con cuidado" son instrucciones que cada modelo interpreta distinto. Los criterios explícitos eliminan ambigüedad:
Cuando extraes datos estructurados, no basta con validar. Si falla, hay que retry inteligente que pase el contexto del error al modelo:
tool_use — única fuente de verdad para tu schema.A veces el modelo extrae datos que se contradicen entre sí (el total declarado no coincide con la suma de items). Si pides solo el "total", no detectas el problema. Self-correction es un patrón donde Claude extrae ambos valores y marca el conflicto:
Cuando una tarea tiene muchos pasos, mandar todo en un solo prompt diluye la atención del modelo. Prompt chaining divide en pasos secuenciales enfocados:
En conversaciones de muchos turnos surgen problemas específicos. Aquí los 5 patrones más importantes:
Para procesar volúmenes grandes (10,000 documentos) sin urgencia, la Batch API te da 50% de ahorro en costo:
| Característica | Valor |
|---|---|
| Ahorro vs API sincrónica | 50% del costo |
| Ventana de procesamiento | Hasta 24 horas (sin SLA de latencia) |
| Tool calling multi-turn | NO soportado (una request = una response) |
| Correlación | Campo custom_id por solicitud |
| Caso | API | Por qué |
|---|---|---|
| Verificación pre-merge de PR | Sync | Dev espera resultado, 24h inaceptable |
| Reporte nocturno de deuda técnica | Batch | Listo en la mañana, ahorro 50% |
| Revisión de código interactiva | Sync | Necesita respuesta inmediata |
| Procesar 10,000 facturas | Batch | Procesamiento masivo, ahorro significativo |
custom_id, divide los documentos largos en fragmentos, y reenvía solo los 5 fallidos. No reproceses todo.Cuando una conversación dura 30 turnos, la sumarización del historial pierde precisión: "$89.99" se vuelve "aproximadamente $90". Para casos de soporte donde los detalles importan, el patrón estándar es mantener un bloque estructurado de hechos clave que se incluye en CADA prompt:
Si lookup_order devuelve 40 campos pero solo necesitas 5 para la tarea actual, los 35 extra están desperdiciando ventana de contexto. Trimming con un hook PostToolUse soluciona esto:
Los modelos de lenguaje procesan el inicio y el final de un texto largo de forma confiable, pero pierden información del medio. Esto es bien documentado y aplica a Claude. Para reportes largos, organiza así:
Durante una investigación larga de una codebase, el agente puede ir guardando hallazgos en un archivo scratchpad. Cuando el contexto se degrada o empiezas una nueva sesión, el agente lee el scratchpad en lugar de re-investigar todo:
--resume con datos viejos.Cuando agregas información de múltiples fuentes (búsqueda web, análisis de docs, síntesis), se pierde la conexión "afirmación → fuente". Esto es problemático: si el reporte final dice "$3.2 mil millones", ¿de dónde viene? ¿De qué año? ¿Qué metodología?
Si dos fuentes dan valores diferentes para el mismo dato, NO selecciones arbitrariamente:
Algunos casos NUNCA deberían resolverse automáticamente. La pregunta es: ¿cómo detectarlos confiablemente? No todos los triggers son iguales.
| Situación | Acción |
|---|---|
| Cliente dice explícitamente "dame un gerente" | Escalada INMEDIATA, sin intentar resolver |
| La política no cubre la solicitud | Escalar (ej. comparación de precios con competencia) |
| Agente no logra progreso tras intentos razonables | Escalar para evitar loops |
| Operación financiera sobre umbral | Vía hook, NO prompt |
| Múltiples coincidencias al buscar cliente | Pedir IDs adicionales, NO adivinar |
Cuando escalas, el operador humano NO tiene acceso al historial de conversación — solo ve el resumen JSON que tú generas. Debe ser completo y autosuficiente:
Para sistemas de extracción de datos en producción, necesitas saber cuándo confiar en el resultado y cuándo enviarlo a revisión humana. El patrón es routing por confianza:
["Read", "Grep"].-p. Único correcto para CI/CD. Soporta --output-format json..claude/agents/<name>.md. Único tipo que puede usar skills (si los lista en frontmatter).stop_reason="max_tokens" = truncada.${VAR} para secretos (no plaintext)..claude/rules/ con glob patterns. Carga condicional según archivo editado.~/.claude/skills/. Solo tú, en todos tus proyectos. NO se comparten..claude/skills/ del repo. Compartidos vía git al clonar.