Cuando iteras sobre una habilidad para un agente como Codex, es difícil saber si realmente la estás mejorando o solo estás cambiando su comportamiento. Una versión parece más rápida, otra parece más confiable, y entonces se cuela una regresión: la habilidad no se activa, omite un paso obligatorio o deja archivos adicionales.
En esencia, una habilidad es una colección organizada de prompts e instrucciones para un LLM. La forma más confiable de mejorar una habilidad con el tiempo es evaluarla como evaluarías cualquier otro prompt para aplicaciones con LLM.
Las evaluaciones (conocidas como “evals”, abreviatura de evaluations en inglés) comprueban si el resultado de un modelo y los pasos que siguió para producirlo coinciden con lo que buscabas. En lugar de preguntarte “¿esto parece mejor?” (o guiarte por impresiones), las evaluaciones te permiten hacer preguntas concretas como:
- ¿El agente invocó la habilidad?
- ¿Ejecutó los comandos esperados?
- ¿Produjo resultados que siguen las convenciones que te importan?
En concreto, una evaluación consiste en: un prompt → una ejecución registrada (traza + artefactos) → un pequeño conjunto de comprobaciones → una puntuación que puedes comparar a lo largo del tiempo.
En la práctica, las evaluaciones de habilidades de agentes se parecen mucho a pruebas ligeras de extremo a extremo: ejecutas el agente, registras lo que pasó y calificas el resultado según un pequeño conjunto de reglas.
Este artículo explica un método claro para hacerlo con Codex: primero defines qué significa tener éxito y luego agregas comprobaciones deterministas y una calificación basada en rúbricas para que las mejoras (y las regresiones) sean evidentes.
1. Define qué significa tener éxito antes de escribir la habilidad
Antes de escribir la habilidad, anota qué significa “tener éxito” en términos que puedas medir. Una forma útil de abordar esto es dividir las comprobaciones en algunas categorías:
- Objetivos de resultado: ¿se completó la tarea? ¿La aplicación funciona?
- Objetivos de proceso: ¿Codex invocó la habilidad, usó las herramientas y siguió los pasos que habías previsto?
- Objetivos de estilo: ¿el resultado sigue las convenciones que pediste?
- Objetivos de eficiencia: ¿llegó al resultado sin dar vueltas innecesarias (por ejemplo, ejecutar comandos innecesarios o usar tokens en exceso)?
Mantén esta lista breve y centrada en las comprobaciones que deben superarse obligatoriamente. El objetivo no es plasmar todas las preferencias desde el principio, sino registrar los comportamientos que más te importan.
Por ejemplo, en este artículo se evalúa una habilidad que configura una aplicación de demostración. Algunas comprobaciones son concretas. ¿Ejecutó npm install? ¿Creó package.json? La guía las combina con una rúbrica de estilo estructurada para evaluar las convenciones y la disposición de los elementos.
Esta combinación es intencional. Buscas señales rápidas y específicas que permitan detectar regresiones concretas de forma temprana, en lugar de un único veredicto final de éxito o fallo.
2. Crea la habilidad
Una habilidad de Codex es un directorio con un archivo SKILL.md que incluye metadatos iniciales en YAML (name, description), seguidos de instrucciones en Markdown que definen el comportamiento de la habilidad, además de recursos y scripts opcionales. El nombre y la descripción importan más de lo que parece. Son las señales principales que usa Codex para decidir si debe invocar la habilidad y cuándo incorporar el resto de SKILL.md al contexto del agente. Si son vagos o abarcan demasiado, la habilidad no se activará de manera confiable.
La forma más rápida de empezar es usar el creador de habilidades integrado de Codex (que también es una habilidad). Te guía por el proceso:
$skill-creator
El creador te pregunta qué hace la habilidad, cuándo debe activarse y si solo contiene instrucciones o también usa scripts (la recomendación predeterminada es usar solo instrucciones). Para obtener más información sobre cómo crear una habilidad, consulta la documentación.
Una habilidad de ejemplo
Este artículo usa un ejemplo deliberadamente mínimo: una habilidad que configura una pequeña aplicación de demostración en React de forma predecible y repetible.
Esta habilidad hará lo siguiente:
- Crear la estructura inicial de un proyecto con la plantilla de React + TypeScript de Vite
- Configurar Tailwind CSS mediante el método oficial que usa un complemento de Vite
- Exigir una estructura de archivos mínima y uniforme
- Establecer una “definición de terminado” clara para que sea sencillo evaluar si se logró el objetivo
A continuación encontrarás un borrador breve que puedes pegar en cualquiera de estas ubicaciones:
.codex/skills/setup-demo-app/SKILL.md(con alcance de repositorio), o~/.codex/skills/setup-demo-app/SKILL.md(con alcance de usuario).
---
name: setup-demo-app
description: Scaffold a Vite + React + Tailwind demo app with a small, consistent project structure.
---
## When to use this
Use when you need a fresh demo app for quick UI experiments or reproductions.
## What to build
Create a Vite React TypeScript app and configure Tailwind. Keep it minimal.
Project structure after setup:
- src/
- main.tsx (entry)
- App.tsx (root UI)
- components/
- Header.tsx
- Card.tsx
- index.css (Tailwind import)
- index.html
- package.json
Style requirements:
- TypeScript components
- Functional components only
- Tailwind classes for styling (no CSS modules)
- No extra UI libraries
## Steps
1. Scaffold with Vite using the React TS template:
npm create vite@latest demo-app -- --template react-ts
2. Install dependencies:
cd demo-app
npm install
3. Install and configure Tailwind using the Vite plugin.
- npm install tailwindcss @tailwindcss/vite
- Add the tailwind plugin to vite.config.ts
- In src/index.css, replace contents with:
@import "tailwindcss";
4. Implement the minimal UI:
- Header: app title and short subtitle
- Card: reusable card container
- App: render Header + 2 Cards with placeholder text
## Definition of done
- npm run dev starts successfully
- package.json exists
- src/components/Header.tsx and src/components/Card.tsx exist
Esta habilidad de ejemplo adopta criterios específicos de forma deliberada. Sin restricciones claras, no hay nada concreto que evaluar.
3. Activa la habilidad manualmente para descubrir supuestos ocultos
Como la invocación de una habilidad depende tanto del nombre y la descripción en SKILL.md, lo primero que debes comprobar es si la habilidad setup-demo-app se activa cuando esperas que lo haga.
Al principio, activa la habilidad explícitamente, ya sea con el comando slash /skills o haciendo referencia a ella con el prefijo $, en un repositorio real o en un directorio de prueba, y observa dónde falla. Así descubrirás los fallos: casos en los que la habilidad no se activa, se activa con demasiada facilidad o se ejecuta, pero se desvía de los pasos previstos.
En esta etapa, no buscas optimizar la velocidad ni pulir los detalles. Buscas supuestos ocultos de la habilidad, como:
-
Supuestos sobre la activación: prompts como “configura una demo rápida en React” que deberían invocar
setup-demo-app, pero no lo hacen, o prompts más genéricos (“agrega estilos con Tailwind”) que la activan sin querer. -
Supuestos sobre el entorno: la habilidad supone que se ejecuta en un directorio vacío o que
npmestá disponible y se prefiere a otros gestores de paquetes. -
Supuestos sobre la ejecución: el agente omite
npm installporque supone que las dependencias ya están instaladas, o configura Tailwind antes de que exista el proyecto de Vite.
Cuando estés listo para hacer que estas ejecuciones sean repetibles, pasa a usar codex exec. Está diseñado para la automatización y la CI: envía el progreso de forma continua a stderr y escribe solo el resultado final en stdout, lo que facilita automatizar las ejecuciones con scripts, registrarlas e inspeccionarlas.
De forma predeterminada, codex exec se ejecuta en un sandbox restringido. Si tu tarea necesita escribir archivos, ejecútalo con --full-auto. Como regla general, especialmente al automatizar, usa los permisos mínimos necesarios para completar el trabajo.
Una ejecución manual básica podría verse así:
codex exec --full-auto \
'Use the $setup-demo-app skill to create the project in this directory.'
Esta primera prueba práctica se centra menos en validar que todo sea correcto y más en descubrir casos límite. Cada corrección manual que hagas aquí, como agregar un npm install que faltaba, corregir la configuración de Tailwind o precisar la descripción de activación, puede convertirse en una futura evaluación. Así puedes afianzar el comportamiento previsto antes de evaluar a gran escala.
4. Usa un conjunto pequeño y específico de prompts para detectar regresiones de forma temprana
No necesitas una gran batería de pruebas para sacar provecho de las evaluaciones. Para una sola habilidad, un conjunto pequeño de 10–20 prompts basta para detectar regresiones y confirmar mejoras de forma temprana.
Empieza con un CSV pequeño y amplíalo a medida que encuentres fallos reales durante el desarrollo o el uso. Cada fila debe representar una situación en la que importe que la habilidad setup-demo-app se active o no se active , y qué se considera un resultado satisfactorio cuando lo hace.
Por ejemplo, una versión inicial de evals/setup-demo-app.prompts.csv podría verse así:
id,should_trigger,prompt
test-01,true,"Create a demo app named `devday-demo` using the $setup-demo-app skill"
test-02,true,"Set up a minimal React demo app with Tailwind for quick UI experiments"
test-03,true,"Create a small demo app to showcase the Responses API"
test-04,false,"Add Tailwind styling to my existing React app"
Cada uno de estos casos pone a prueba algo ligeramente distinto:
-
Invocación explícita (
test-01)
Este prompt menciona la habilidad por su nombre. Comprueba que Codex pueda invocarsetup-demo-appcuando se le pida y que los cambios en el nombre, la descripción o las instrucciones de la habilidad no impidan su uso directo. -
Invocación implícita (
test-02)
Este prompt describe exactamente el escenario para el que está pensada la habilidad (configurar una demo mínima de React + Tailwind), sin mencionarla por su nombre. Comprueba si el nombre y la descripción enSKILL.mdson lo suficientemente claros para que Codex seleccione la habilidad por su cuenta. -
Invocación contextual (
test-03)
Este prompt agrega contexto del ámbito de trabajo (la API Responses), pero sigue requiriendo la misma configuración de base. Comprueba que la habilidad se active ante prompts realistas con algo de ruido y que la aplicación resultante siga cumpliendo con la estructura y las convenciones esperadas. -
Control negativo (
test-04)
Este prompt no debería invocarsetup-demo-app. Es una solicitud relacionada y habitual (“agrega Tailwind a una aplicación existente”) que puede coincidir sin querer con la descripción de la habilidad (“demo de React + Tailwind”). Incluir al menos un casoshould_trigger=falseayuda a detectar falsos positivos, en los que Codex selecciona la habilidad con demasiada facilidad y crea la estructura inicial de un proyecto nuevo cuando el usuario quería un cambio incremental en uno existente.
Esta combinación es intencional. Algunas evaluaciones deben confirmar que la habilidad se comporte correctamente cuando se invoca explícitamente; otras deben comprobar que se active ante prompts reales en los que el usuario no la menciona en absoluto.
A medida que descubras fallos, prompts que no activan la habilidad o casos en los que el resultado se aleja de tus expectativas, agrégalos como nuevas filas. Con el tiempo, este pequeño CSV se convierte en un registro vivo de los escenarios que la habilidad setup-demo-app debe seguir resolviendo correctamente.
Con el tiempo, este pequeño conjunto de datos se convierte en un registro vivo de lo que la habilidad debe seguir haciendo bien.
5. Empieza con calificadores deterministas ligeros
Esta es la clave de la etapa de evaluación: usa codex exec --json para que tu arnés de ejecución de evaluaciones pueda calificar lo que realmente ocurrió, y no solo si el resultado final parece correcto.
Cuando activas --json, stdout se convierte en un flujo JSONL de eventos estructurados. Eso facilita escribir comprobaciones deterministas vinculadas directamente al comportamiento que te importa, por ejemplo:
- ¿Ejecutó
npm install? - ¿Creó
package.json? - ¿Ejecutó los comandos esperados en el orden previsto?
Estas comprobaciones son ligeras a propósito. Te dan señales rápidas y fáciles de explicar antes de que agregues cualquier calificación basada en modelos.
Un ejecutor mínimo en Node.js
Un enfoque “suficientemente bueno” sería el siguiente:
- Para cada prompt, ejecuta
codex exec --json --full-auto "<prompt>" - Guarda la traza JSONL en disco
- Procesa la traza y ejecuta comprobaciones deterministas sobre los eventos
// evals/run-setup-demo-app-evals.mjs
import { spawnSync } from "node:child_process";
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
import path from "node:path";
function runCodex(prompt, outJsonlPath) {
const res = spawnSync(
"codex",
[
"exec",
"--json", // REQUIRED: emit structured events
"--full-auto", // Allow file system changes
prompt,
],
{ encoding: "utf8" }
);
mkdirSync(path.dirname(outJsonlPath), { recursive: true });
// stdout is JSONL when --json is enabled
writeFileSync(outJsonlPath, res.stdout, "utf8");
return { exitCode: res.status ?? 1, stderr: res.stderr };
}
function parseJsonl(jsonlText) {
return jsonlText
.split("\n")
.filter(Boolean)
.map((line) => JSON.parse(line));
}
// deterministic check: did the agent run `npm install`?
function checkRanNpmInstall(events) {
return events.some(
(e) =>
(e.type === "item.started" || e.type === "item.completed") &&
e.item?.type === "command_execution" &&
typeof e.item?.command === "string" &&
e.item.command.includes("npm install")
);
}
// deterministic check: did `package.json` get created?
function checkPackageJsonExists(projectDir) {
return existsSync(path.join(projectDir, "package.json"));
}
// Example single-case run
const projectDir = process.cwd();
const tracePath = path.join(projectDir, "evals", "artifacts", "test-01.jsonl");
const prompt =
"Create a demo app named demo-app using the $setup-demo-app skill";
runCodex(prompt, tracePath);
const events = parseJsonl(readFileSync(tracePath, "utf8"));
console.log({
ranNpmInstall: checkRanNpmInstall(events),
hasPackageJson: checkPackageJsonExists(path.join(projectDir, "demo-app")),
});
La ventaja es que todo es determinista y se puede depurar.
Si una comprobación falla, puedes abrir el archivo JSONL y ver exactamente qué ocurrió. Cada ejecución de un comando aparece como un evento item.*, en orden. Esto facilita explicar y corregir las regresiones, que es justo lo que buscas en esta etapa.
6. Realiza comprobaciones cualitativas con Codex y calificaciones basadas en rúbricas
Las comprobaciones deterministas responden a “¿hizo lo básico?” , pero no a “¿lo hizo como querías?”
En habilidades como setup-demo-app, muchos requisitos son cualitativos: la estructura de los componentes, las convenciones de estilo o si Tailwind sigue la configuración prevista. Es difícil comprobar estos aspectos solo verificando la existencia de archivos o contando comandos.
Una solución pragmática es agregar un segundo paso, asistido por un modelo, a tu flujo de evaluación:
- Ejecuta la habilidad de configuración (esto escribe código en disco)
- Ejecuta una comprobación de estilo de solo lectura sobre el repositorio resultante
- Exige una respuesta estructurada que tu arnés de ejecución pueda calificar de forma consistente
Codex permite hacerlo directamente mediante --output-schema, que restringe la respuesta final a un esquema que defines con JSON Schema.
Un esquema pequeño para la rúbrica
Comienza por definir un esquema pequeño que incluya las comprobaciones que te interesan. Por ejemplo, crea evals/style-rubric.schema.json:
{
"type": "object",
"properties": {
"overall_pass": { "type": "boolean" },
"score": { "type": "integer", "minimum": 0, "maximum": 100 },
"checks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"pass": { "type": "boolean" },
"notes": { "type": "string" }
},
"required": ["id", "pass", "notes"],
"additionalProperties": false
}
}
},
"required": ["overall_pass", "score", "checks"],
"additionalProperties": false
}
Este esquema te da campos estables (overall_pass, score, resultados por comprobación) que puedes combinar, comparar y seguir a lo largo del tiempo.
El prompt para comprobar el estilo
A continuación, ejecuta codex exec por segunda vez para que solo inspeccione el repositorio y genere una respuesta JSON que se ajuste a la rúbrica:
codex exec \
"Evaluate the demo-app repository against these requirements:
- Vite + React + TypeScript project exists
- Tailwind is configured via @tailwindcss/vite and CSS imports tailwindcss
- src/components contains Header.tsx and Card.tsx
- Components are functional and styled with Tailwind utility classes (no CSS modules)
Return a rubric result as JSON with check ids: vite, tailwind, structure, style." \
--output-schema ./evals/style-rubric.schema.json \
-o ./evals/artifacts/test-01.style.json
Aquí es donde --output-schema resulta útil. En lugar de texto libre difícil de procesar o comparar, obtienes un objeto JSON predecible que tu arnés de ejecución de evaluaciones puede calificar en numerosas ejecuciones.
Si más adelante llevas este conjunto de evaluaciones a CI, la GitHub Action de Codex admite explícitamente pasar --output-schema a través de codex-args, por lo que puedes exigir el mismo resultado estructurado en los flujos de trabajo automatizados.
7. Ampliar tus evaluaciones a medida que madura la habilidad
Una vez que tengas el ciclo básico funcionando, puedes ampliar tus evaluaciones en los aspectos más importantes para tu habilidad. Empieza con algo pequeño y luego agrega comprobaciones más exhaustivas solo donde aporten mayor confianza en los resultados.
Estos son algunos ejemplos:
-
Cantidad de comandos y actividad improductiva: cuenta los elementos
command_executionde la traza JSONL para detectar regresiones en las que el agente empieza a entrar en bucles o a volver a ejecutar comandos. El uso de tokens también está disponible en los eventosturn.completed. -
Presupuesto de tokens: haz un seguimiento de
usage.input_tokensyusage.output_tokenspara detectar aumentos involuntarios del tamaño del prompt y comparar la eficiencia entre versiones. -
Comprobaciones de compilación: ejecuta
npm run buildcuando termine la habilidad. Esto proporciona una señal más sólida del funcionamiento de extremo a extremo y detecta importaciones que fallan o herramientas mal configuradas. -
Pruebas básicas en tiempo de ejecución: inicia
npm run devy envía una solicitud al servidor de desarrollo concurl, o ejecuta una comprobación ligera con Playwright si ya tienes una. Usa este recurso de forma selectiva. Aporta confianza, pero lleva tiempo. -
Limpieza del repositorio: asegúrate de que la ejecución no genere archivos no deseados y de que la salida de
git status --porcelainesté vacía (o coincida con una lista explícita de elementos permitidos). -
Regresiones de sandbox y permisos: verifica que la habilidad siga funcionando sin elevar los permisos más allá de lo previsto. Los valores predeterminados de privilegio mínimo cobran mayor importancia cuando automatizas.
El patrón es el mismo: comienza con comprobaciones rápidas que expliquen el comportamiento y luego agrega otras más lentas y costosas solo cuando reduzcan el riesgo.
8. Puntos clave
Este pequeño ejemplo de setup-demo-app muestra cómo pasar de “parece mejor” a “tener pruebas”: ejecuta el agente, registra lo que ocurrió y califícalo con un pequeño conjunto de comprobaciones. Una vez que existe ese ciclo, es más fácil verificar cada ajuste y cada regresión se vuelve evidente. Estos son los puntos clave:
- Mide lo que importa. Las buenas evaluaciones hacen evidentes las regresiones y permiten explicar las fallas.
- Parte de una definición verificable de lo que significa terminar. Usa
$skill-creatorpara empezar y luego precisa las instrucciones hasta que quede claro, sin ambigüedades, qué significa tener éxito. - Basa las evaluaciones en el comportamiento. Captura JSONL con
codex exec --jsony escribe comprobaciones deterministas sobre los eventoscommand_execution. - Usa Codex donde las reglas no alcancen. Agrega una etapa estructurada y basada en una rúbrica con
--output-schemapara calificar el estilo y las convenciones de forma confiable. - Deja que las fallas reales guíen la cobertura. Cada corrección manual es una señal. Conviértela en una prueba para que la habilidad siga haciendo lo correcto.