Harness engineering: el caso Codex y una implementación segura para principiantes
Harness engineering: caso Codex, límites entre IA y personas, acceso seguro a archivos y pruebas ejecutables.
Pides a un agente de IA que ordene un repositorio y termina cambiando una configuración que no tenía relación con la tarea. Le encargas que ejecute las pruebas y responde que todo ha salido bien, pero no deja ninguna evidencia de la ejecución. Son problemas habituales cuando un equipo empieza a delegar trabajo en Claude Code, Codex u otro agente de programación.
El prompt es solo una parte del problema. También hay que definir qué información puede ver el agente, qué herramientas puede usar, cuándo debe detenerse y qué prueba objetiva indica que el trabajo está terminado. El harness engineering diseña ese entorno. Un harness es el andamiaje que permite al agente trabajar sin tener que tomar por sí solo todas las decisiones.
Esta guía comienza con el caso práctico de Codex publicado por OpenAI. Después construye un harness pequeño que limita el acceso a archivos, rechaza sobrescrituras y cuenta con pruebas ejecutables. Al final se especifica con exactitud qué se verificó y qué quedó fuera de la comprobación.
Puntos clave
- Un harness no es un único script envoltorio. Combina conocimiento del repositorio, herramientas, permisos, pruebas, registros, recuperación y aprobación humana.
- En su caso de Codex, OpenAI hizo que la estructura del repositorio, el comportamiento de la aplicación y las reglas de calidad fueran visibles y comprobables para los agentes.
- La IA puede investigar, preparar borradores y repetir tareas. Las personas deben conservar las decisiones sobre borrado, producción, comunicación externa y gasto.
- Comprobar solo el prefijo textual de una ruta no crea una sandbox completa. También importan los enlaces simbólicos, la sobrescritura, los privilegios del proceso y el aislamiento del sistema operativo.
- Decir «probado» exige indicar el comando, el resultado y el alcance. El mensaje de éxito del modelo no es una evidencia.
Qué significa realmente harness engineering
Un prompt explica qué quieres conseguir en una ejecución. El harness define el entorno en el que se intentará cumplir esa instrucción.
| Capa | Pregunta que responde | Ejemplo mínimo |
|---|---|---|
| Contexto | ¿Qué puede aprender el agente? | AGENTS.md, un directorio concreto, una especificación versionada |
| Herramientas | ¿Qué puede hacer? | Leer, probar y crear un borrador |
| Permisos | ¿Dónde debe detenerse? | Aprobación humana antes de borrar o enviar |
| Verificación | ¿Qué significa «terminado»? | npm test finaliza con código 0 |
| Observabilidad | ¿Cómo se investiga un fallo? | Comando, diff y salida de error relevante |
| Recuperación | ¿Cómo se deshace una mala ejecución? | Commits pequeños, simulaciones y pasos de reversión |
El modelo es solo una pieza del ciclo:
Objetivo humano y reglas de aprobación
↓
Reglas del repositorio → agente de IA → herramientas permitidas
↑ ↓
Especificaciones pruebas, registros y diffs
└── corregir si falla; pedir criterio humano cuando haga falta ──┘
Cambiar de modelo no revela una decisión de diseño privada que solo existe en la memoria de una persona. En cambio, el mismo modelo resulta más fiable cuando puede encontrar el conocimiento necesario y ejecutar los criterios de aceptación.
Por qué el término ganó relevancia en 2026
Una de las fuentes principales del interés actual es el artículo de OpenAI Harness engineering: leveraging Codex in an agent-first world, publicado el 11 de febrero de 2026.
OpenAI describe un experimento que comenzó con un repositorio Git vacío. Durante unos cinco meses, tres ingenieros que dirigían Codex abrieron y fusionaron aproximadamente 1.500 pull requests. Según el artículo, el repositorio rondaba entonces el millón de líneas y la beta interna del producto tenía usuarios diarios y evaluadores alfa externos. Estas cifras pertenecen a ese proyecto concreto; no son una promesa de productividad para cualquier equipo.
La enseñanza útil no es el número de pull requests, sino el cambio de entorno. Las personas marcaron prioridades, transformaron los comentarios de usuarios en criterios de aceptación y validaron los resultados; Codex realizó la implementación. El caso publicado incluye estas decisiones:
- mantener planes, decisiones de diseño y reglas de calidad como artefactos versionados dentro del repositorio;
- usar un
AGENTS.mdbreve como mapa hacia fuentes más detalladas, no como un manual gigantesco; - permitir que el agente inspeccione directamente la interfaz, los logs, las métricas y las trazas;
- imponer direcciones de dependencias y otras invariantes mediante linters propios y pruebas estructurales;
- tratar cada fallo como señal de una herramienta, una regla o una abstracción que falta, en vez de pedir al modelo que «se esfuerce más»;
- ejecutar tareas periódicas de limpieza para detectar documentación obsoleta y desviaciones acumuladas.
OpenAI también aclara que el nivel de autonomía conseguido depende mucho de la estructura y las herramientas específicas de ese repositorio. No se debe esperar el mismo comportamiento en otro proyecto sin una inversión comparable.
Claude Code permite aplicar la misma idea general. La documentación oficial de hooks del Claude Agent SDK muestra cómo inspeccionar una solicitud de herramienta, denegarla, modificar su entrada o registrarla para auditoría. Cada producto ofrece controles distintos, pero el harness sigue siendo responsable de los límites y del ciclo de aprendizaje.
Qué debe hacer la IA y qué debe decidir una persona
No empieces con autonomía completa. Automatiza primero el trabajo reversible y exige aprobación cuando una acción afecte a clientes, dinero, datos sensibles o producción.
| Buen punto de partida | Delegar con condiciones | Mantener como decisión humana |
|---|---|---|
| Buscar archivos | Editar archivos existentes | Borrar datos de producción |
| Ejecutar pruebas | Añadir una dependencia | Enviar un correo a un cliente |
| Resumir un diff | Desplegar en staging | Cambiar facturación o contratos |
| Crear un borrador | Hacer push de una rama | Procesar datos personales sensibles |
Haz dos preguntas: ¿se puede deshacer la acción con poco coste? ¿Puede afectar a alguien fuera del equipo? Empieza con lectura y salidas temporales. Convierte una operación en automática solo después de poder observar tanto sus éxitos como sus fallos.
Construir un harness mínimo
El ejemplo solo ofrece al modelo dos capacidades:
- leer texto dentro de
sandbox; - crear un archivo de texto nuevo dentro de
sandbox.
No existe una herramienta para borrar, sobrescribir, ejecutar una shell ni acceder a la red. El ejemplo se comprobó con Node.js 22 y el SDK está fijado a la versión usada en esta verificación.
mkdir harness-demo
cd harness-demo
npm init -y
npm install @anthropic-ai/[email protected]
mkdir sandbox
echo "# meeting notes" > sandbox/note.md
Crea policy.json:
{
"workspace": "./sandbox",
"maxSteps": 6,
"maxToolResultChars": 4000
}
1. Aplicar el límite de archivos desde el código
Crea safe-files.mjs. Una comprobación como candidate.startsWith(root) no basta por sí sola: un directorio de nombre parecido también podría coincidir y un enlace simbólico dentro del área de trabajo podría apuntar fuera. La lectura siguiente comprueba el destino resuelto y las escrituras se limitan a archivos nuevos.
import { open, readFile, realpath } from "node:fs/promises";
import path from "node:path";
function assertInside(root, candidate) {
if (candidate !== root && !candidate.startsWith(root + path.sep)) {
throw new Error(`outside workspace: ${candidate}`);
}
}
export async function createFileGate(workspace) {
const root = await realpath(path.resolve(workspace));
async function readText(relativePath) {
const requested = path.resolve(root, relativePath);
assertInside(root, requested);
const actual = await realpath(requested);
assertInside(root, actual);
return readFile(actual, "utf8");
}
async function createText(relativePath, content) {
const requested = path.resolve(root, relativePath);
assertInside(root, requested);
const actualParent = await realpath(path.dirname(requested));
assertInside(root, actualParent);
let handle;
try {
handle = await open(requested, "wx", 0o600);
await handle.writeFile(content, "utf8");
} catch (error) {
if (error.code === "EEXIST") {
throw new Error(`refusing to overwrite: ${relativePath}`);
}
throw error;
} finally {
await handle?.close();
}
return "created";
}
return { readText, createText };
}
Este control pertenece a la aplicación, no es una frontera de seguridad completa. Si hace falta un aislamiento más fuerte, combina el código con un contenedor, una máquina virtual, permisos del sistema operativo o la sandbox del producto. Las comprobaciones de la aplicación no anulan privilegios elevados del proceso.
2. Exponer solo dos herramientas al modelo
Crea agent.mjs. El nombre del modelo se proporciona a propósito mediante ANTHROPIC_MODEL en lugar de fijarlo en el artículo, porque el acceso de la cuenta y la disponibilidad de modelos pueden cambiar.
import Anthropic from "@anthropic-ai/sdk";
import { readFile } from "node:fs/promises";
import { createFileGate } from "./safe-files.mjs";
const model = process.env.ANTHROPIC_MODEL;
if (!model) throw new Error("Set ANTHROPIC_MODEL to a model available to your account.");
const policy = JSON.parse(await readFile("./policy.json", "utf8"));
const gate = await createFileGate(policy.workspace);
const client = new Anthropic();
const tools = [
{
name: "read_file",
description: "Read a UTF-8 text file inside the workspace",
input_schema: {
type: "object",
properties: { path: { type: "string" } },
required: ["path"],
additionalProperties: false
}
},
{
name: "create_file",
description: "Create a new UTF-8 file; existing files cannot be overwritten",
input_schema: {
type: "object",
properties: {
path: { type: "string" },
content: { type: "string" }
},
required: ["path", "content"],
additionalProperties: false
}
}
];
async function runTool(name, input) {
if (name === "read_file") return gate.readText(input.path);
if (name === "create_file") return gate.createText(input.path, input.content);
throw new Error(`unknown tool: ${name}`);
}
const prompt = process.argv.slice(2).join(" ") ||
"Read note.md and create summary.md with a three-line summary.";
const messages = [{ role: "user", content: prompt }];
for (let step = 0; step < policy.maxSteps; step += 1) {
const response = await client.messages.create({
model,
max_tokens: 1200,
system: "Use only the supplied tools. Never claim a file was created unless the tool succeeded.",
tools,
messages
});
messages.push({ role: "assistant", content: response.content });
const calls = response.content.filter((block) => block.type === "tool_use");
if (calls.length === 0) {
console.log(response.content.find((block) => block.type === "text")?.text ?? "done");
process.exit(0);
}
const results = [];
for (const call of calls) {
try {
const value = await runTool(call.name, call.input);
results.push({
type: "tool_result",
tool_use_id: call.id,
content: String(value).slice(0, policy.maxToolResultChars)
});
} catch (error) {
results.push({
type: "tool_result",
tool_use_id: call.id,
is_error: true,
content: error.message
});
}
}
messages.push({ role: "user", content: results });
}
throw new Error(`step limit exceeded: ${policy.maxSteps}`);
3. Probar el límite antes de llamar a un modelo
La frontera crítica se puede probar en local sin gastar crédito de API. Crea safe-files.test.mjs:
import assert from "node:assert/strict";
import test from "node:test";
import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { createFileGate } from "./safe-files.mjs";
test("file gate blocks traversal, overwrite, and outside symlinks", async () => {
const base = await mkdtemp(path.join(tmpdir(), "harness-test-"));
const root = path.join(base, "sandbox");
const outside = path.join(base, "outside.txt");
try {
await mkdir(root);
await writeFile(path.join(root, "note.md"), "hello", "utf8");
await writeFile(outside, "secret", "utf8");
const gate = await createFileGate(root);
assert.equal(await gate.readText("note.md"), "hello");
await assert.rejects(() => gate.readText("../outside.txt"), /outside workspace/);
await assert.rejects(() => gate.createText("note.md", "replace"), /refusing to overwrite/);
try {
await symlink(outside, path.join(root, "outside-link.txt"), "file");
await assert.rejects(() => gate.readText("outside-link.txt"), /outside workspace/);
} catch (error) {
if (error.code !== "EPERM") throw error;
}
assert.equal(await gate.createText("summary.md", "safe"), "created");
} finally {
await rm(base, { recursive: true, force: true });
}
});
Ejecuta las comprobaciones sin conexión:
node --test safe-files.test.mjs
node --check agent.mjs
Solo después configura ANTHROPIC_API_KEY y ANTHROPIC_MODEL y ejecuta node agent.mjs. No guardes credenciales ni en el control de versiones ni en policy.json.
Tres casos de uso prácticos
1. Equipos de software: implementar y verificar una pull request
Entrega al agente una issue acotada, los directorios relevantes y los comandos de prueba. «Se escribió el código» no es la condición de aceptación. Exige una reproducción que falle antes del arreglo, una prueba que pase después y un diff comprensible. El despliegue en producción y las migraciones siguen sujetos a aprobación humana.
2. Operaciones editoriales: controlar un artículo antes de publicarlo
Separa la generación del texto de los controles de temas duplicados, profundidad, sintaxis del código, enlaces y visualización móvil. Si una comprobación falla, debe detener la publicación y devolver un mensaje de corrección concreto. Así, «parece terminado» se convierte en una serie de criterios observables.
3. Atención al cliente: clasificar una consulta y redactar una respuesta
El agente puede clasificar el mensaje y preparar un borrador razonado. Una persona aprueba los cambios en la ficha del cliente y el envío real. Proporciona solo los datos personales necesarios para la clasificación y evita conservar cuerpos completos de mensajes en logs de larga duración.
Cómo calcular un ROI sencillo
Mide el tiempo de revisión ahorrado y la reducción del retrabajo, no los tokens generados. Supongamos que un equipo dedica 20 minutos a revisar cada una de 15 tareas semanales: son cinco horas. Si construir el harness requiere seis horas y el mantenimiento posterior se reduce a una hora semanal, la inversión inicial se recupera en aproximadamente una semana y media.
Es una cuenta ilustrativa, no un resultado garantizado. Mide durante dos semanas antes y después de introducirlo:
- minutos de trabajo humano por tarea;
- porcentaje de tareas que requieren retrabajo;
- errores detectados antes de producción;
- número de escalados para aprobación humana.
Demasiadas solicitudes de aprobación pueden indicar que una operación ya demostrada y de bajo riesgo se puede delimitar mejor y automatizar. Si aumentan los errores o el retrabajo, hace falta otra comprobación o un contexto más claro, no ampliar la autonomía.
Pitfalls: errores frecuentes y cómo corregirlos
Confundir una comprobación de carpeta con una sandbox
Una ruta puede parecer interna mientras un enlace simbólico apunta fuera del área permitida. Resuelve los destinos, rechaza sobrescrituras y aplica permisos del sistema operativo como segunda frontera.
Escribir solo «no hagas nada peligroso» en el prompt
El texto orienta, pero no impone una barrera. No expongas una herramienta peligrosa o deniégala mediante un hook previo a su ejecución. La guía de permisos de Claude Code incluye una configuración concreta.
Aceptar el mensaje «las pruebas han pasado»
Registra el comando, el código de salida y el alcance de la verificación. Los cambios de interfaz también necesitan una interacción real o una captura de pantalla. El flujo de recibos de verificación explica cómo conservar esa evidencia.
Enviar todos los documentos en cada ejecución
Un contexto largo puede ocultar justo la restricción importante. Ofrece un punto de entrada breve con enlaces a fuentes concretas y versionadas. Registra su vigencia y estado de verificación para detectar documentación obsoleta.
Resumen
El harness engineering no consiste en escribir prompts cada vez más largos. Hace que el conocimiento relevante sea localizable, limita las herramientas, bloquea acciones sensibles, evalúa resultados mediante comandos y convierte los fallos en mejores reglas y pruebas.
Como primer paso, elige un único flujo de trabajo y escribe cuatro líneas: entrada, acciones permitidas, comando de aceptación y acciones que requieren aprobación humana. Los equipos que necesiten incorporar permisos, verificación y revisión a un repositorio real pueden adaptar estos límites a su proceso con la formación y consultoría de implantación de Claude Code.
Resultado de la verificación real
El 21 de julio de 2026 se extrajeron los bloques safe-files.mjs y safe-files.test.mjs de este artículo a un directorio temporal y se ejecutaron con Node.js. La prueba comprueba una lectura normal, la creación de un archivo nuevo, el rechazo de una ruta ../ que sale del área permitida y el rechazo de una sobrescritura. En sistemas donde el proceso puede crear enlaces simbólicos, también comprueba que se rechace un enlace dirigido al exterior. agent.mjs pasó una comprobación de sintaxis.
Una llamada real a la API de Anthropic no forma parte del alcance porque el acceso a modelos y el coste dependen de cada cuenta. La distinción es deliberada: «publicado», «sintaxis comprobada», «probado sin conexión» y «ejecutado contra una API externa de pago» son afirmaciones diferentes.
Artículos relacionados
Claude Agent SDK: integra Claude Code en apps con seguridad
Configuración actual, permisos, MCP, ejemplos ejecutables y errores comunes del Claude Agent SDK.
Claude Code o Codex, ¿al final cuál? La solución real para combinarlos sin accidentes
OpenAI Codex y Claude Code: ¿cuál hace mejor qué y a cuál le delegas qué?
Prompt engineering avanzado para Claude Code y Codex: briefs de tarea que sí se pueden revisar
Diseña prompts Claude Code/Codex con brief, criterios de aceptación, verificación y bucles seguros.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.