Harnesses y agentes de código Avanzado¶
1. ¿Qué es un harness?¶
El modelo aporta la inteligencia; el harness (arnés) es todo el software que lo convierte en un agente útil:
flowchart TB
U[Usuario / CI] --> H
subgraph H[Harness]
L[Bucle del agente]
CTX[Gestión de contexto<br/>instrucciones, memoria, compactación]
TOOLS[Herramientas<br/>ficheros, terminal, búsqueda, web, MCP]
PERM[Permisos y sandbox]
EXT[Extensiones<br/>skills, hooks, subagentes, plugins]
L --- CTX
L --- TOOLS
L --- PERM
L --- EXT
end
H <--> M[Modelo LLM<br/>vía API]
TOOLS <--> ENV[Tu entorno<br/>repo, shell, clúster, servicios]
| Componente | Responsabilidad |
|---|---|
| Bucle | Enviar contexto al modelo, ejecutar las herramientas que pide, devolver resultados, repetir |
| Herramientas | Leer y editar ficheros, ejecutar comandos, buscar, navegar, conectarse a MCP |
| Contexto | Cargar instrucciones del proyecto, memoria, skills; compactar cuando se llena |
| Permisos | Qué puede hacer sin preguntar, qué requiere aprobación, qué está prohibido; sandbox |
| Extensiones | Puntos de personalización del comportamiento |
| Interfaz | Terminal, IDE, web, escritorio, modo headless para CI |
Mismo modelo, resultados distintos
La calidad de un agente depende tanto del harness como del modelo: qué herramientas tiene, cómo gestiona el contexto,
y cuánto conocimiento del proyecto recibe. Por eso invertir en CLAUDE.md, skills y hooks tiene tanto retorno.
2. Panorama de harnesses de código¶
| Herramienta | Tipo | Notas |
|---|---|---|
| Claude Code (Anthropic) | CLI, extensiones de IDE (VS Code, JetBrains), escritorio, web | Muy extensible: CLAUDE.md, skills, hooks, subagentes, plugins, MCP. También como librería: Claude Agent SDK |
| Codex (OpenAI) | CLI, IDE, nube | Usa AGENTS.md para instrucciones del proyecto |
| Gemini CLI (Google) | CLI de código abierto | GEMINI.md, extensiones, MCP |
| GitHub Copilot | IDE (modo agente) y agente en la nube que abre PRs | Integrado en GitHub |
| Cursor, Windsurf | IDEs basados en VS Code con agente | Reglas de proyecto propias |
| Cline, Roo, Aider, OpenCode, goose, Amp | Código abierto / CLI / extensiones | Varios soportan múltiples proveedores de modelos |
AGENTS.md (cedido a la Linux Foundation en 2025) es la convención abierta para instrucciones de proyecto que leen
muchos agentes; Claude Code usa CLAUDE.md, que puede importar otros ficheros.
3. Claude Code a fondo¶
Mapa de extensiones¶
| Mecanismo | Dónde vive | Qué aporta | Se carga |
|---|---|---|---|
| CLAUDE.md | ~/.claude/CLAUDE.md (personal), ./CLAUDE.md (proyecto, en Git), subcarpetas |
Instrucciones y convenciones permanentes | Siempre, al inicio |
| Memoria automática | Carpeta de memoria del proyecto | Hechos aprendidos entre sesiones (preferencias, decisiones) | Índice al inicio |
| Skills | .claude/skills/<nombre>/SKILL.md (o ~/.claude/skills/) |
Procedimientos y conocimiento especializado; invocables como /nombre (los antiguos comandos de .claude/commands/ se han fusionado con las skills) |
Metadatos al inicio; cuerpo bajo demanda |
| Subagentes | .claude/agents/<nombre>.md |
Agentes especializados con contexto, herramientas y modelo propios | Cuando se delega |
| Hooks | settings.json |
Comandos deterministas en eventos del ciclo de vida | En cada evento |
| Servidores MCP | .mcp.json (proyecto) o configuración de usuario |
Herramientas externas | Al inicio (con carga diferida de herramientas si son muchas) |
| Plugins | Marketplaces | Paquetes que agrupan skills, agentes, hooks y servidores MCP | Al instalarlos |
| Settings | ~/.claude/settings.json, .claude/settings.json, .claude/settings.local.json |
Permisos, variables de entorno, hooks, modelo | Siempre |
¿Qué uso para qué?
Siempre relevante y breve → CLAUDE.md. Procedimiento para ciertas tareas → skill. Tiene que ocurrir sí o sí (formatear, validar, bloquear) → hook: el modelo puede olvidar una instrucción; un hook no. Exploración que ensucia el contexto → subagente. Acceso a un sistema externo → MCP.
CLAUDE.md¶
# cac-gitops-platform
Repositorio GitOps (Flux v2 + Kustomize) que define la plataforma de todos los clústeres.
## Estructura
- `clusters/<cluster>/` punto de entrada que Flux sincroniza por clúster
- `infrastructure/` controladores, namespaces y políticas comunes
- Las apps se añaden en `clusters/<cluster>/apps/` referenciando overlays
## Reglas
- Nunca secretos en claro: usar SOPS (`.sops.yaml` en la raíz)
- Tras editar YAML: `kustomize build clusters/kind-dev | kubeconform -strict -summary -`
- Cambios de `infrastructure/` afectan a todos los clústeres: explícalo en la descripción del PR
## Por qué
- Flux por clúster (pull) y no Argo central: los sitios edge tienen conectividad intermitente (ver docs/adr/007)
Buenas prácticas: corto y específico; lo que no se deduce leyendo el código (comandos, convenciones, porqués, trampas); actualízalo cuando el agente se equivoque dos veces en lo mismo.
Hooks¶
Un hook es una acción determinista que el harness ejecuta automáticamente cuando ocurre un evento. La
configuración tiene tres niveles: el evento, un matcher que filtra (por ejemplo, qué herramienta: Edit|Write)
y los manejadores que se ejecutan.
| Grupo | Eventos principales |
|---|---|
| Sesión | SessionStart, SessionEnd |
| Turno | UserPromptSubmit (antes de procesar lo que escribes), Stop (cuando el agente termina) |
| Herramientas | PreToolUse (antes: puede bloquear), PostToolUse (después), PostToolUseFailure, PermissionRequest |
| Subagentes y contexto | SubagentStart, SubagentStop, PreCompact, PostCompact |
| Otros | Notification, FileChanged, ConfigChange, InstructionsLoaded… (consulta la documentación: la lista crece) |
| Tipo de manejador | Qué hace |
|---|---|
command |
Ejecuta un comando o script (el más habitual) |
http |
Envía el evento por POST a un endpoint |
mcp_tool |
Llama a una herramienta de un servidor MCP |
prompt |
Pide a un modelo que evalúe el evento |
agent |
Lanza un subagente para verificar algo |
El manejador recibe un JSON por la entrada estándar (con hook_event_name, tool_name, tool_input, cwd…). En
PreToolUse, salir con código 2 bloquea la herramienta y el texto de error llega al modelo como explicación; ese
bloqueo no se puede anular desde la salida JSON. Con código 0 sigue el flujo normal de permisos.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "kustomize build clusters/kind-dev > /dev/null" }]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "python .claude/hooks/block_plain_secrets.py" }]
}
]
}
}
# .claude/hooks/block_plain_secrets.py — impide escribir Secrets de Kubernetes sin cifrar
import json, sys
event = json.load(sys.stdin)
content = event.get("tool_input", {}).get("content", "") or event.get("tool_input", {}).get("new_string", "")
if "kind: Secret" in content and "sops:" not in content:
print("Secret sin cifrar: cifra el fichero con SOPS antes de guardarlo.", file=sys.stderr)
sys.exit(2) # bloquea la herramienta y explica el motivo al modelo
Subagentes¶
---
name: manifest-reviewer
description: Revisa manifiestos de Kubernetes, Kustomize y Flux en busca de errores, riesgos de seguridad
y desviaciones de las convenciones. Úsalo después de modificar YAML en clusters/ o infrastructure/.
tools: Read, Grep, Glob, Bash
model: sonnet
---
Eres un revisor de plataforma. Para cada cambio comprueba: que `kustomize build` funciona, límites de
recursos, `prune` y `dependsOn` correctos, ausencia de secretos en claro e impacto en todos los clústeres.
Devuelve una lista priorizada de hallazgos con fichero y línea. No edites ficheros.
El subagente trabaja en su propia ventana de contexto y devuelve solo el informe: el agente principal no se
llena con todo lo que ha leído. Se guardan en .claude/agents/ (proyecto) o ~/.claude/agents/ (personal). Solo name
y description son obligatorios; otros campos útiles:
| Campo | Para qué |
|---|---|
tools / disallowedTools |
Qué herramientas puede usar (si se omite, hereda todas) |
model |
haiku, sonnet, opus, fable, un ID concreto o inherit |
permissionMode |
Modo de permisos propio del subagente |
maxTurns / effort |
Límite de pasos y nivel de razonamiento |
skills / mcpServers / hooks |
Skills precargadas, servidores MCP y hooks propios |
isolation: worktree |
Trabajar en un worktree de Git aislado |
Permisos y modos¶
| Modo | Comportamiento |
|---|---|
| Por defecto | Pide aprobación para editar ficheros y ejecutar comandos no permitidos |
| Aceptar ediciones | Edita sin preguntar; los comandos siguen necesitando aprobación |
| Plan | Solo lee e investiga; propone un plan antes de tocar nada |
| Auto | Actúa con autonomía dentro de límites de seguridad y confirma lo arriesgado |
| No preguntar (dontAsk) | Solo usa lo que ya está permitido en la configuración; lo demás se deniega sin preguntar |
| Sin permisos (bypass) | Todo permitido: solo en entornos aislados y desechables |
{
"permissions": {
"allow": ["Bash(kustomize build:*)", "Bash(git status)", "Bash(git diff:*)"],
"deny": ["Bash(kubectl delete:*)", "Read(./.env)", "Read(./secrets/**)"]
}
}
Otros usos¶
- Headless / CI:
claude -p "revisa este PR y comenta los riesgos"en un pipeline; integración con GitHub Actions. - Claude Agent SDK: el mismo harness como librería (Python/TypeScript) para construir tus propios agentes con herramientas de ficheros, terminal y búsqueda, hooks, subagentes y permisos.
- Sesiones en la nube y en paralelo: varias tareas a la vez en worktrees o entornos remotos.
Cómo gestiona el contexto un harness¶
Lo que el modelo "ve" al empezar una sesión en Claude Code no es solo tu mensaje:
flowchart TB
SYS[Instrucciones del sistema<br/>del harness] --> CTX
TOOLS[Definiciones de herramientas<br/>incluidas las de MCP] --> CTX
MD[CLAUDE.md<br/>personal + proyecto + carpetas] --> CTX
MEM[Índice de memoria] --> CTX
SK[Nombre y descripción<br/>de cada skill] --> CTX
USR[Tu mensaje] --> CTX
CTX[(Ventana de contexto)]
A medida que trabaja, se añaden los ficheros que lee, las salidas de los comandos y sus propias respuestas. Cuando la ventana se acerca a su límite, el harness compacta: resume la conversación anterior y continúa con ese resumen.
Consecuencias prácticas:
- Un
CLAUDE.mdenorme se paga en todas las sesiones: mantenlo breve y mueve lo detallado a skills. - Pedir al agente que lea un fichero de 20 000 líneas llena el contexto: mejor que busque (
grep) o delegar en un subagente. - En tareas largas, pide que guarde el plan y el progreso en un fichero: sobrevive a las compactaciones.
- Empezar una sesión nueva para una tarea nueva evita arrastrar contexto irrelevante.
4. Buenas prácticas de desarrollo asistido por agentes¶
| Práctica | Por qué |
|---|---|
| Explorar → planificar → implementar → verificar | Pedir primero que lea y proponga un plan (modo plan) evita soluciones precipitadas |
| Dar la forma de verificarse | Tests, linters, kustomize build, capturas: un agente que puede comprobar su trabajo itera solo hasta que funciona |
| Especificación antes que código (spec-driven) | En tareas grandes, acordar requisitos y diseño en un documento que el agente sigue |
| Contexto del proyecto versionado | CLAUDE.md, skills y hooks en Git: todo el equipo (y el CI) se beneficia |
| Tareas acotadas y revisables | Diffs pequeños; PRs revisados por humanos como cualquier otro |
| Tú sigues siendo el responsable | El agente propone; la responsabilidad del código que se fusiona es de quien lo aprueba |
| Seguridad | Mínimo privilegio, sin credenciales de producción en la máquina del agente, sandbox para modos autónomos, cuidado con el contenido no confiable (issues, webs) que lee el agente |
| Medir | Lead time, tasa de defectos, retrabajo: si la calidad baja, ajustar el proceso, no solo el prompt |
Para un arquitecto, el cambio de rol
Con agentes, el cuello de botella pasa de escribir código a especificar bien, dar contexto y verificar. Las habilidades de arquitectura (límites claros, ADRs, fitness functions, tests como contrato) son justo las que hacen que los agentes funcionen bien en un código base.
Preguntas de repaso¶
¿Qué diferencia hay entre un modelo y un harness?
El modelo genera texto y decide acciones; el harness ejecuta el bucle, proporciona herramientas, gestiona el contexto y los permisos, y conecta con tu entorno. Claude Code es un harness; Claude Opus o Sonnet son modelos.
¿Por qué un hook y no una instrucción en CLAUDE.md para validar YAML?
Una instrucción es una petición que el modelo puede olvidar u omitir; el hook es determinista: se ejecuta siempre en el evento y puede bloquear la acción.
¿Qué pondrías en una skill y qué en CLAUDE.md?
En CLAUDE.md, lo breve y relevante en casi toda sesión (estructura, comandos, reglas). En una skill, procedimientos largos o específicos de ciertas tareas (desplegar, auditar seguridad, medir rendimiento), que solo se cargan cuando hacen falta.
¿Qué riesgo introduce darle a un agente acceso a issues públicos y a la terminal?
Prompt injection: un texto malicioso en el issue puede intentar que el agente ejecute comandos o filtre datos. Mitigación: permisos restrictivos, sandbox, sin secretos accesibles y aprobación humana para acciones sensibles.
Ejercicios¶
Ejercicio 1 · Básico — ¿Dónde va cada cosa?
Decide si va en CLAUDE.md, una skill, un hook, un subagente o un servidor MCP: (a) "usamos Conventional Commits";
(b) formatear con spotless cada vez que se edita un fichero Java; (c) procedimiento de 40 pasos para migrar un servicio
a Spring Boot 4; (d) consultar incidentes en PagerDuty; (e) revisar a fondo los cambios de seguridad de una PR.
Solución
(a) CLAUDE.md: breve y relevante siempre. (b) Hook PostToolUse sobre Edit|Write: debe ocurrir siempre.
(c) Skill: procedimiento largo que solo se carga cuando toca. (d) Servidor MCP: acceso a un sistema externo.
(e) Subagente revisor: tarea con mucho contexto que conviene aislar y que devuelve solo el informe.
Ejercicio 2 · Medio — Hook de protección
Escribe un hook PreToolUse que impida al agente ejecutar kubectl contra cualquier contexto cuyo nombre contenga prod.
Solución
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": "python .claude/hooks/no_prod_kubectl.py" }] }
]
}
}
# .claude/hooks/no_prod_kubectl.py
import json, subprocess, sys
event = json.load(sys.stdin)
command = event.get("tool_input", {}).get("command", "")
if "kubectl" in command:
ctx = subprocess.run(["kubectl", "config", "current-context"], capture_output=True, text=True).stdout
if "prod" in ctx or "--context" in command and "prod" in command:
print(f"Bloqueado: kubectl contra un contexto de producción ({ctx.strip()}).", file=sys.stderr)
sys.exit(2) # bloquea la herramienta y el motivo llega al modelo
Ejercicio 3 · Avanzado — Adoptar agentes en un equipo
Tu equipo de plataforma (8 personas) quiere empezar a usar agentes de código. Propón un plan de adopción de 3 meses con salvaguardas y métricas.
Solución
- Mes 1 — base:
CLAUDE.mden los repositorios principales (estructura, comandos, reglas), hooks de validación (kustomize build, linters), permisos restrictivos compartidos en.claude/settings.json, sin credenciales de producción en los portátiles. Uso en tareas acotadas: tests, refactors, documentación. - Mes 2 — ampliación: skills para los procedimientos repetitivos (alta de apps, alta de sitios), subagente revisor de manifiestos, servidor MCP de solo lectura de la flota. Revisión humana de todas las PRs como hasta ahora.
- Mes 3 — medición y ajuste: comparar con la línea base lead time, tasa de PRs rechazadas o revertidas, defectos en producción, tiempo de revisión; retrospectiva sobre qué tareas funcionan bien y cuáles no. Salvaguardas en todo momento: el agente propone y la persona que aprueba es responsable; tareas pequeñas; el CI es el árbitro.