Ao fazer ajustes em uma habilidade de um agente como o Codex, é difícil saber se ela realmente melhorou ou se apenas passou a se comportar de outra forma. Uma versão parece mais rápida, outra parece mais confiável e, de repente, surge uma regressão: a habilidade não é acionada, pula uma etapa obrigatória ou deixa arquivos extras no repositório.
Em essência, uma habilidade é um conjunto organizado de prompts e instruções para um LLM. A maneira mais confiável de aprimorar uma habilidade ao longo do tempo é avaliá-la como você avaliaria qualquer outro prompt de um aplicativo que usa LLMs.
As avaliações, chamadas em inglês de evals (abreviação de evaluations), verificam se o resultado de um modelo e as etapas que ele seguiu para produzi-lo correspondem ao que você pretendia. Em vez de perguntar “parece que melhorou?” ou de confiar na intuição, você pode fazer perguntas concretas como estas:
- O agente acionou a habilidade?
- Ele executou os comandos esperados?
- Os resultados seguem as convenções que importam para você?
Na prática, uma avaliação segue esta sequência: um prompt → uma execução registrada (rastreamento + artefatos) → um pequeno conjunto de verificações → uma pontuação que você pode comparar ao longo do tempo.
As avaliações de habilidades de agentes se parecem bastante com testes leves de ponta a ponta: você executa o agente, registra o que aconteceu e atribui uma nota ao resultado com base em algumas regras.
Este artigo mostra como fazer isso com o Codex. Primeiro, você define o que conta como sucesso. Depois, acrescenta verificações determinísticas e atribui notas com base em critérios definidos para identificar tanto melhorias quanto regressões.
1. Defina o que conta como sucesso antes de escrever a habilidade
Antes de escrever a habilidade, registre o que significa “sucesso” em termos que você consiga medir. Para isso, você pode dividir as verificações em algumas categorias:
- Objetivos de resultado: A tarefa foi concluída? O aplicativo funciona?
- Objetivos de processo: O Codex acionou a habilidade, usou as ferramentas e seguiu as etapas que você definiu?
- Objetivos de estilo: O resultado segue as convenções que você pediu?
- Objetivos de eficiência: O agente chegou ao resultado sem desperdiçar recursos, por exemplo, com comandos desnecessários ou uso excessivo de tokens?
Mantenha a lista curta e inclua apenas as verificações obrigatórias. Concentre-se nos comportamentos mais importantes, sem tentar transformar todas as suas preferências em regras logo de início.
Neste artigo, por exemplo, vamos avaliar uma habilidade que prepara um aplicativo de demonstração. Algumas verificações são bem concretas. O agente executou npm install? Criou o arquivo package.json? Vamos combiná-las com critérios de estilo estruturados para avaliar as convenções e o layout.
Essa combinação é intencional. Verificações rápidas e específicas permitem identificar regressões logo no início. Um único resultado de aprovação ou reprovação ao final não oferece esse nível de detalhe.
2. Crie a habilidade
Uma habilidade do Codex fica em um diretório com um arquivo SKILL.md. O arquivo começa com um cabeçalho YAML (name, description), seguido das instruções em Markdown que definem o comportamento da habilidade. O diretório também pode incluir recursos e scripts opcionais. O nome e a descrição têm mais peso do que parece. São os principais elementos que o Codex usa para decidir se deve acionar a habilidade e quando incluir o restante de SKILL.md no contexto do agente. Se o nome e a descrição forem vagos ou abrangerem situações demais, o acionamento será pouco confiável.
A maneira mais rápida de começar é usar o criador de habilidades integrado ao Codex (ele também é uma habilidade). Para que ele oriente você durante a criação, execute:
$skill-creator
O criador pergunta o que a habilidade faz, quando deve ser acionada e se usa apenas instruções ou também scripts. Por padrão, a recomendação é usar apenas instruções. Para saber mais sobre como criar uma habilidade, consulte a documentação.
Exemplo de habilidade
O exemplo deste artigo é simples de propósito: uma habilidade que prepara um pequeno aplicativo de demonstração em React de maneira previsível e reproduzível.
Essa habilidade vai:
- Gerar a estrutura inicial de um projeto com o modelo React + TypeScript do Vite
- Configurar o Tailwind CSS usando o plugin oficial para Vite
- Garantir uma estrutura de arquivos mínima e consistente
- Definir claramente os “critérios de conclusão” para facilitar a avaliação do resultado
Você pode colar o rascunho abaixo em um destes arquivos:
.codex/skills/setup-demo-app/SKILL.md(no escopo do repositório) ou~/.codex/skills/setup-demo-app/SKILL.md(no escopo do usuário).
---
name: setup-demo-app
description: Scaffold a Vite + React + Tailwind demo app with a small, consistent project structure.
---
## Quando usar esta habilidade
Use esta habilidade quando precisar de um novo aplicativo de demonstração para fazer experimentos rápidos de interface ou reproduzir um problema.
## O que criar
Crie um aplicativo React em TypeScript com o Vite e configure o Tailwind. Inclua apenas o essencial.
Estrutura do projeto após a configuração:
- src/
- main.tsx (ponto de entrada)
- App.tsx (componente raiz da interface)
- components/
- Header.tsx
- Card.tsx
- index.css (importação do Tailwind)
- index.html
- package.json
Requisitos de estilo:
- Escreva os componentes em TypeScript
- Use apenas componentes funcionais
- Aplique os estilos com classes do Tailwind, sem módulos CSS
- Não adicione outras bibliotecas de interface
## Etapas
1. Gere a estrutura inicial com o Vite usando o modelo React com TypeScript:
npm create vite@latest demo-app -- --template react-ts
2. Instale as dependências:
cd demo-app
npm install
3. Instale e configure o Tailwind usando o plugin para Vite.
- npm install tailwindcss @tailwindcss/vite
- Adicione o plugin do Tailwind a vite.config.ts
- Em src/index.css, substitua o conteúdo por:
@import "tailwindcss";
4. Implemente a interface mínima:
- Header: exiba o título do aplicativo e um subtítulo curto
- Card: crie um contêiner reutilizável para cartões
- App: renderize o componente Header e 2 instâncias de Card com texto de exemplo
## Critérios de conclusão
- O comando npm run dev inicia o servidor de desenvolvimento com sucesso
- O arquivo package.json existe
- Os arquivos src/components/Header.tsx e src/components/Card.tsx existem
A habilidade do exemplo faz escolhas específicas de propósito. Sem restrições claras, não há nada concreto a avaliar.
3. Acione a habilidade manualmente para descobrir o que ela pressupõe
Como o acionamento depende muito do nome e da descrição em SKILL.md, comece verificando se a habilidade setup-demo-app é acionada quando você espera.
Nos primeiros testes, ative a habilidade explicitamente pelo comando de barra /skills ou faça referência a ela com o prefixo $. Faça isso em um repositório real ou em um diretório de testes e observe em que ponto surgem problemas. É nessa etapa que você identifica os casos em que a habilidade não é acionada, é acionada quando não deveria ou executa etapas diferentes das previstas.
A velocidade e o acabamento podem esperar. Agora, o objetivo é identificar suposições implícitas na habilidade, como estas:
-
Sobre o acionamento: prompts como “prepare uma demonstração rápida em React” deveriam acionar
setup-demo-app, mas não acionam. Já prompts mais genéricos, como “adicione estilos com Tailwind”, podem acionar a habilidade sem querer. -
Sobre o ambiente: a habilidade pressupõe que está em um diretório vazio ou que
npmestá disponível e é o gerenciador de pacotes preferido. -
Sobre a execução: o agente pula
npm installporque presume que as dependências já estão instaladas ou configura o Tailwind antes de criar o projeto Vite.
Quando quiser tornar essas execuções reproduzíveis, passe a usar codex exec. Ele foi desenvolvido para automação e integração contínua (CI): envia o progresso para stderr à medida que a execução avança e grava apenas o resultado final em stdout. Isso facilita automatizar as execuções com scripts, registrá-las e inspecioná-las.
Por padrão, codex exec é executado em um sandbox restrito. Se a tarefa precisar gravar arquivos, use --full-auto. Como regra geral, principalmente em automações, conceda apenas as permissões necessárias para concluir a tarefa.
Veja um exemplo de execução manual:
codex exec --full-auto \
'Use a habilidade $setup-demo-app para criar o projeto neste diretório.'
Nessa primeira rodada manual, descobrir casos extremos é mais importante do que confirmar que tudo está correto. Cada ajuste manual, como acrescentar um npm install que faltava, corrigir a configuração do Tailwind ou tornar a descrição de acionamento mais precisa, pode dar origem a uma avaliação. Assim, você pode garantir que a habilidade preserve o comportamento esperado antes de avaliá-la em escala.
4. Use um conjunto pequeno e focado de prompts para detectar regressões cedo
Você não precisa de um grande conjunto de referência para tirar proveito das avaliações. Para uma única habilidade, um conjunto de 10 a 20 prompts é suficiente para identificar regressões e confirmar melhorias logo no início.
Comece com um arquivo CSV pequeno e amplie-o à medida que encontrar falhas reais durante o desenvolvimento ou o uso. Cada linha deve representar uma situação em que importa saber se a habilidade setup-demo-app é acionada ou permanece inativa, além do resultado esperado quando ela entra em ação.
Por exemplo, uma primeira versão de evals/setup-demo-app.prompts.csv poderia ser assim:
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 caso testa um aspecto diferente:
-
Acionamento explícito (
test-01)
O prompt menciona a habilidade pelo nome. Ele verifica se o Codex consegue acionarsetup-demo-appquando solicitado e se alterações no nome, na descrição ou nas instruções da habilidade preservam essa forma de uso. -
Acionamento implícito (
test-02)
O prompt descreve exatamente a situação para a qual a habilidade foi criada: preparar uma demonstração mínima com React + Tailwind, sem mencionar a habilidade pelo nome. Ele testa se o nome e a descrição emSKILL.mdsão específicos o suficiente para que o Codex selecione a habilidade por conta própria. -
Acionamento pelo contexto (
test-03)
O prompt acrescenta um detalhe do domínio (a API Responses), mas a preparação necessária continua a mesma. Ele verifica se a habilidade é acionada em prompts realistas, mesmo com alguma informação adicional, e se o aplicativo resultante segue a estrutura e as convenções esperadas. -
Controle negativo (
test-04)
O prompt não deve acionarsetup-demo-app. É um pedido comum e parecido (“adicione Tailwind a um aplicativo existente”) que pode corresponder por engano à descrição da habilidade (“demonstração com React + Tailwind”). Incluir pelo menos um caso comshould_trigger=falseajuda a detectar falsos positivos, em que o Codex seleciona a habilidade e gera um novo projeto quando o usuário queria apenas alterar um projeto existente.
Essa combinação é intencional. Algumas avaliações devem confirmar que a habilidade funciona corretamente quando acionada de forma explícita. Outras devem verificar se ela é ativada com prompts de uso real em que o usuário nem sequer menciona a habilidade.
Sempre que descobrir uma falha, como um prompt que não aciona a habilidade ou um resultado que foge do esperado, acrescente uma linha ao arquivo. Com o tempo, esse pequeno CSV passa a documentar os cenários em que a habilidade setup-demo-app precisa continuar funcionando corretamente.
Com o tempo, esse pequeno conjunto de dados se torna um registro atualizado do que a habilidade precisa continuar fazendo corretamente.
5. Comece com avaliadores determinísticos simples
O ponto central da avaliação é usar codex exec --json para que o harness de avaliação possa pontuar o que realmente aconteceu, indo além da aparência do resultado final.
Quando você ativa --json, stdout passa a transmitir eventos estruturados em JSONL. Isso facilita escrever verificações determinísticas diretamente ligadas ao comportamento que você quer avaliar. Por exemplo:
- O agente executou
npm install? - Criou o arquivo
package.json? - Executou os comandos esperados na ordem prevista?
Essas verificações são simples de propósito. Elas produzem resultados rápidos e fáceis de explicar antes mesmo de você acrescentar uma etapa de avaliação com um modelo.
Um script mínimo de execução em Node.js
Para começar, bastam três passos:
- Para cada prompt, execute
codex exec --json --full-auto "<prompt>" - Salve o registro da execução em disco no formato JSONL
- Analise o registro e aplique verificações determinísticas aos 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
"--sandbox",
"workspace-write", // Allow changes inside the example repository
prompt,
],
{ encoding: "utf8" }
);
if (res.error) throw res.error;
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.completed" &&
e.item?.type === "command_execution" &&
e.item.status === "completed" &&
e.item.exit_code === 0 &&
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";
const { exitCode, stderr } = runCodex(prompt, tracePath);
if (exitCode !== 0) {
throw new Error(`Codex exited with status ${exitCode}: ${stderr}`);
}
const events = parseJsonl(readFileSync(tracePath, "utf8"));
console.log({
ranNpmInstall: checkRanNpmInstall(events),
hasPackageJson: checkPackageJsonExists(path.join(projectDir, "demo-app")),
});A vantagem é que tudo é determinístico e fácil de depurar.
Se uma verificação falhar, abra o arquivo JSONL para ver exatamente o que aconteceu. Cada execução de comando aparece como um evento item.*, na ordem em que ocorreu. Isso facilita explicar e corrigir regressões, justamente o que você precisa nessa etapa.
6. Faça verificações qualitativas com o Codex e critérios de avaliação
As verificações determinísticas respondem à pergunta “o agente fez o básico?”, mas não à pergunta “ele fez do jeito que você queria?”
Em habilidades como setup-demo-app, muitos requisitos são qualitativos: a estrutura dos componentes, as convenções de estilo ou a forma como o Tailwind foi configurado. É difícil avaliar esses aspectos apenas verificando se determinados arquivos existem ou contando comandos.
Uma solução prática é acrescentar ao fluxo de avaliação uma segunda etapa com a ajuda de um modelo:
- Execute a habilidade de preparação do projeto (ela grava código em disco)
- Faça uma verificação de estilo somente leitura no repositório resultante
- Exija uma resposta estruturada que o harness possa pontuar de forma consistente
O Codex oferece suporte direto a isso com --output-schema, que restringe o formato da resposta final ao JSON Schema que você definir.
Um schema simples para os critérios de avaliação
Comece definindo um pequeno schema que represente as verificações importantes para você. Por exemplo, crie 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
}
Esse schema fornece campos estáveis (overall_pass, score e os resultados de cada verificação) que você pode combinar, comparar entre execuções e acompanhar ao longo do tempo.
O prompt de verificação de estilo
Em seguida, execute codex exec uma segunda vez para que o Codex apenas inspecione o repositório e produza uma resposta JSON de acordo com os critérios de avaliação:
codex exec \
"Avalie o repositório demo-app com base nestes requisitos:
- Existe um projeto com Vite + React + TypeScript
- O Tailwind está configurado com @tailwindcss/vite e o CSS importa tailwindcss
- O diretório src/components contém Header.tsx e Card.tsx
- Os componentes são funcionais e usam classes utilitárias do Tailwind para aplicar estilos, sem módulos CSS
Retorne o resultado da avaliação em JSON com os seguintes identificadores de verificação: vite, tailwind, structure, style." \
--output-schema ./evals/style-rubric.schema.json \
-o ./evals/artifacts/test-01.style.json
É aqui que --output-schema faz diferença. Em vez de texto livre, difícil de analisar ou comparar, você recebe um objeto JSON com formato previsível, ao qual o harness de avaliação pode atribuir notas em várias execuções.
Se depois você levar esse conjunto de avaliações para a CI, a GitHub Action do Codex permite passar --output-schema por meio de codex-args. Assim, você pode exigir o mesmo formato de saída nos fluxos de trabalho automatizados.
7. Amplie as avaliações à medida que a habilidade evolui
Depois de implementar o ciclo básico de avaliação, você pode ampliar os testes nos aspectos que mais importam para a habilidade. Comece com poucas verificações e acrescente outras mais detalhadas apenas quando elas aumentarem sua confiança no resultado.
Alguns exemplos:
-
Contagem de comandos e repetições desnecessárias: Conte os itens
command_executionno registro JSONL para detectar regressões em que o agente entra em um ciclo ou volta a executar os mesmos comandos. Os eventosturn.completedtambém informam o uso de tokens. -
Orçamento de tokens: Acompanhe
usage.input_tokenseusage.output_tokenspara identificar aumentos involuntários no tamanho dos prompts e comparar a eficiência entre versões. -
Verificações de build: Execute
npm run builddepois que a habilidade terminar. Isso testa o resultado de ponta a ponta com mais rigor e detecta importações que falham ou ferramentas mal configuradas. -
Testes básicos de funcionamento: Execute
npm run deve faça uma requisição ao servidor de desenvolvimento comcurlou, se você já tiver um teste simples em Playwright, execute-o. Use esses testes de forma seletiva. Eles aumentam a confiança no resultado, mas levam tempo. -
Limpeza do repositório: Verifique se a execução não gera arquivos indesejados e se a saída de
git status --porcelainestá vazia ou contém apenas alterações explicitamente permitidas. -
Regressões no sandbox e nas permissões: Verifique se a habilidade continua funcionando sem exigir permissões além das previstas. Usar o mínimo de privilégios por padrão é especialmente importante quando você automatiza as execuções.
Siga o mesmo princípio em todos os casos: comece com verificações rápidas que ajudem a explicar o comportamento e só depois acrescente verificações mais lentas e custosas, quando elas reduzirem o risco.
8. Principais conclusões
O pequeno exemplo de setup-demo-app mostra como passar da impressão de que “parece melhor” para a comprovação: execute o agente, registre o que aconteceu e avalie o resultado com algumas verificações. Com esse ciclo em funcionamento, fica mais fácil confirmar o efeito de cada ajuste e identificar cada regressão. Em resumo:
- Meça o que importa. Boas avaliações permitem identificar regressões e explicar falhas.
- Comece com critérios de conclusão verificáveis. Use
$skill-creatorpara criar a primeira versão da habilidade. Depois, refine as instruções até que fique claro o que conta como sucesso. - Avalie o comportamento observado. Registre os eventos em JSONL com
codex exec --jsone escreva verificações determinísticas para os eventoscommand_execution. - Use o Codex quando as regras forem insuficientes. Acrescente uma etapa estruturada com critérios definidos e use
--output-schemapara avaliar o estilo e as convenções de forma confiável. - Use falhas reais para ampliar a cobertura. Cada correção manual indica um comportamento que merece um teste. Transforme-a em um teste para que a habilidade continue produzindo o resultado esperado.