---
spec: recurso-codex-imagenes
creado: 2026-08-28
actualizado: 2026-08-29
estado: cumplido
---

# SPEC — `codex-imagenes`, primera skill publicada de la Bóveda

> **Este es el SPEC real** con el que se construyó
> [iapatodos.com/boveda/recursos/codex-imagenes](https://iapatodos.com/boveda/recursos/codex-imagenes).
> Se publica tal cual salió del repo, con cuatro recortes: el nombre de la persona que
> verificó dos criterios pasa a «otra persona», se quitan los hashes de commit y el nombre
> de una rama de trabajo, y se generalizan dos referencias a archivos internos del repo y dos
> menciones a otro recurso de la Bóveda que no viene al caso.
> Los criterios, los supuestos y las 16 filas de bitácora están enteros — incluidos los
> errores propios, que es la parte que enseña.

## Objetivo real

Hoy pasa que **el método se cuenta y no se enseña**: la Bóveda promete «skills de Claude
Code» y no hay ninguna, así que quien llega tiene que creerse de palabra que aquí se
verifica en vez de aceptar. Quiero que pase que **cualquiera pueda abrir por dentro una
pieza real del método** — Claude escribe el brief, Codex pinta, y después se comprueba
que no mintió — y salir sabiendo que una imagen puede salir bonita y aun así no haber
sido generada.

El recurso vende el método, no la imagen. Por eso el corazón de la página no es «mira qué
bonito quedó el hero», es **la trampa y su comprobación**: Codex dibuja con código si el
brief se lo permite, y la única prueba es que aparezca carpeta nueva en
`~/.codex/generated_images/` y que el `md5` del archivo entregado coincida con el original.

## Esto NO es

- **No es una guía de «cómo instalar Claude Code ni Codex».** Eso es `03 Tu taller`. Esta
  página declara los dos requisitos y enlaza; no los enseña.
- **No es un recurso sin coste para el lector.** Codex es de OpenAI y hay que pagarlo. Se
  dice en la página con la misma honestidad que las 5 herramientas de la colección.
- **No abre el estante de skills.** Entra UNA. Publicar `jarvis-prompt` u otras es otro
  trabajo, aunque este invente el molde que reutilizarán.
- **No toca el perfil `constructor` de nadie.** La skill publicada usa `-s workspace-write`
  en la línea. No se entrega ningún `.toml`, no se pide tocar `~/.codex/`.
- **No incluye imágenes de ejemplo generadas para lucirse.** Si entra alguna captura es
  para mostrar la comprobación, no el resultado.
- **No toca el catálogo más allá de lo justo.** El campo `pagina` entra **solo en
  `RecursoSkill`** — decidido el 2026-08-28. Los otros tres tipos (`prompt`, `herramienta`,
  `archivo`) no lo ganan, y los 6 items publicados se quedan exactamente como están. El día
  que un prompt quiera detalle, se sube a `RecursoBase` y se paga entonces.

## Bloques

| # | Bloque | Termina en | ¿Visto bueno? |
|---|---|---|---|
| 1 | **El paquete.** `SKILL.md` de-personalizado (fuera nombres propios, rutas locales y `-p <perfil>`) + `LEEME.md` dentro, comprimidos en `public/boveda/codex-imagenes.zip` | El `.zip` descomprimido en una carpeta limpia y usado de punta a punta: se dice la frase de disparo y sale un archivo de imagen | ✅ construido |
| 2 | **El catálogo.** `pagina` opcional en `RecursoSkill`, la entrada en `RECURSOS`, la tarjeta enlaza al detalle, y el bucle del sitemap incluye las skills con página | `/boveda/recursos` con la tarjeta SKILL · CLAUDE CODE arriba, su botón de descarga y su enlace; `boveda:check` en verde | ✅ construido |
| 3 | **La página de entrada.** `/boveda/recursos/codex-imagenes` — primer recurso con detalle, molde derivado del de las piezas. Incluye la ilustración `codex-imagenes-ilustracion.webp` y OG propia por `scripts/og-codex-imagenes.html` (`npm run og -- codex-imagenes`) | La página abierta en el navegador, en oscuro y en claro, leída entera; y la tarjeta OG capturada | ✅ construido |
| 4 | **Publicación.** Commit único y push a `main` | El recurso en vivo en iapatodos.com y en `/sitemap.xml` | ✅ publicado |

## Criterios de éxito

| # | Criterio | Se comprueba con | Resultado |
|---|---|---|---|
| 1 | Alguien que no estuvo en esta conversación descarga el `.zip`, lo descomprime en `~/.claude/skills/`, abre Claude Code en una **carpeta vacía**, dice la frase de disparo y obtiene un archivo de imagen ahí — **sin tocar `~/.codex/` ni crear ningún perfil** | Corrida real en carpeta limpia: `ls` del archivo entregado + carpeta nueva de hoy en `~/.codex/generated_images/` + `md5sum` de los dos iguales | ✅ confirmado por otra persona, 2026-08-29 |
| 2 | La skill publicada no filtra contexto privado | Dos greps sobre la carpeta descomprimida, **0 coincidencias en ambos**: `grep -irE 'cotiza\|revisor central\|ecomerce\|h-img\|constructor'` (nombres propios) y `grep -rnE 'Users.Usuario\|D:\\\|IAPATODOS\|startup COTIZA'` (rutas de la máquina del autor; case-sensitive, para no cazar «iapatodos.com») | ✅ |
| 3 | El sitio compila, pasa sus puertas y la página nueva es indexable | Las cuatro puertas del repo (`boveda:check`, `npx eslint src`, `npx tsc --noEmit`, `npm run build`) más `/boveda/recursos/codex-imagenes` en `/sitemap.xml`. Ojo con eslint: el repo tiene **línea base de 1 error heredado**, así que el criterio es **no subir de 1**, no llegar a cero | ✅ `boveda:check` con 7 recursos · eslint en 1 (la base) · `tsc` limpio · `build` con la ruta prerenderizada estática · sitemap con la URL |
| 4 | El texto que este trabajo añade se lee en modo claro y en oscuro | Dos cosas, porque miden distinto: `node scripts/contraste-tema.mjs` (mide los **tokens** del tema, no rutas) y los textos nuevos medidos **en el DOM** con la fórmula WCAG contra su fondo real, comprobando antes en qué tema se está — medir creyendo estar en claro y estar en oscuro ya pasó una vez | ✅ tokens 0 bajo umbral · página en **claro**: 81 textos, 0 fallos · en **oscuro**: 81 textos, 2 fallos y los dos son del footer heredado (idénticos en `tu-taller`, en producción) · tarjeta: 9 textos, 0 fallos |
| 5 | Quien lee la página **sin instalar nada** sabe explicar con sus palabras por qué una imagen puede salir correcta y aun así no estar generada | **Otra persona** la lee en frío —no construyó esto— y lo cuenta de vuelta. Si tiene que releer para encontrarlo, el criterio NO se cumple | ✅ confirmado, 2026-08-29 |

## Requiere permiso humano

- [x] **Push a `main` de `Cercosprefabricados/ia.patodos`** — Vercel despliega solo, así que empujar *es* publicar en iapatodos.com.
- [ ] **Publicar el precio de Codex.** Es de un tercero y la regla 7 del ROADMAP pide verificarlo en la página del fabricante el día que se escribe, y ponerlo en rango.
- [x] **Gasto de tokens de OpenAI** en las corridas de prueba del criterio 1 (cada verificación genera una imagen de verdad).

## Supuestos

Deducido sin confirmar. Corregir aquí si algo está mal:

- **El `.zip` contiene una carpeta `codex-imagenes/` con `SKILL.md` y `LEEME.md` dentro**, para que descomprimir en `~/.claude/skills/` deje la skill instalada sin mover nada a mano.
- **El molde de la página se deriva del de `tu-taller`**, no se inventa uno nuevo. Es el molde de pieza sin PDF, que es exactamente lo que esto es.
- **El recurso entra con `estado: "publicada"`**. Con `pendiente` llevaría `noindex` y no entraría al sitemap, y entonces el bloque 4 no prueba nada.
- **El lector ya tiene Claude Code y Codex CLI instalados y autenticados.** La página lo declara como requisito; no lo resuelve.
- **Codex CLI exige suscripción de pago de OpenAI.** No lo verifiqué — hay que mirarlo antes de escribir la cifra (ver permiso humano).
- **La frase de disparo publicada es «genera una imagen» / «crea el hero»**, la misma que ya trae el `SKILL.md`.

## Bitácora

| Fecha | Cambio | Motivo |
|---|---|---|
| 2026-08-28 | creado | — |
| 2026-08-28 | El permiso de escritura pasa de `-p constructor` a `-s workspace-write` | Comprobado en esta sesión: un perfil inexistente **no da error** en Codex y el default es **read-only**. Quien instalara la skill sin crear el perfil vería a Codex generar la imagen y no poder guardarla, sin que nada dijera que faltaba una config. Los perfiles además viven en `~/.codex/<nombre>.config.toml`, no en `[profiles.*]` de `config.toml` |
| 2026-08-28 | `pagina` entra solo en `RecursoSkill`, no en `RecursoBase`; y el criterio 5 nombra a quien lo va a leer en frío | Decisión del founder. Un item no justifica tocar el tipo que comparten los 6 recursos ya publicados; el refactor a `RecursoBase` se paga el día que un prompt o un archivo pida detalle |
| 2026-08-28 | El grep del criterio 2 deja de buscar «iapatodos» | Error mío al escribirlo: iapatodos es la marca pública, no contexto privado. El `LEEME.md` del paquete **tiene** que decir de dónde salió y enlazar a la Bóveda; con el grep original ese enlace habría hecho fallar el criterio |
| 2026-08-28 | El grep del criterio 2 se parte en dos y deja de buscar `d:` suelto | Al correrlo dio un falso positivo: `d:` matchea dentro de «de verdad:». Un criterio que salta con texto legítimo se acaba ignorando, que es peor que no tenerlo. Ahora un grep busca nombres propios y otro busca rutas de Windows (`[A-Za-z]:\`) |
| 2026-08-28 | El `.zip` NO se empaqueta con `Compress-Archive` de PowerShell | Genera las entradas con separador backslash (`codex-imagenes\SKILL.md`). En macOS y Linux muchos `unzip` crean con eso un archivo llamado literalmente así en vez de una carpeta, y la skill no queda instalada — fallo silencioso, justo el que este recurso enseña a cazar. Se empaqueta con `tar.exe -a -c -f` (bsdtar de Windows), que escribe `codex-imagenes/` |
| 2026-08-28 | Criterio 1 queda **parcial**, no cumplido | Verificado lo que sí se puede desde aquí: la receta publicada (`-s workspace-write`, las dos clausulas obligatorias) genera y guarda de punta a punta — carpeta nueva en `generated_images` (53→54) y `md5 a539255a…` idéntico entre la copia del modelo y el archivo entregado. Lo que NO: que Claude Code dispare la skill instalada **desde el `.zip`**. Por definición no lo puedo cerrar yo — el criterio pide «alguien que no estuvo en esta conversación» |
| 2026-08-28 | La portada generada se queda como **ilustración de la página**, no como OG; y el bloque 3 gana una OG propia por HTML | Decisión del founder. Las OG del sitio se capturan de HTML con las woff2 de la marca (`scripts/build-og.mjs`); una imagen generativa como tarjeta al compartir dejaría a las otras dos como las raras. La ilustración va optimizada: 2,03 MB PNG → **73 KB webp**, 1280×853 |
| 2026-08-28 | El botón de la tarjeta dice «ANTES DE DESCARGAR», no «CÓMO SE USA» | Visto en el navegador: Press Start 2P no trae las mayúsculas acentuadas, así que el navegador caía a otra fuente solo para ese glifo y se leía «CóMO», con una o minúscula redonda en medio. Es la razón por la que ninguna etiqueta en pixel del sitio lleva tilde. El texto nuevo además dice mejor lo que hace: esta skill exige dos programas instalados y uno se paga |
| 2026-08-28 | El criterio 4 se reescribe: `contraste-tema.mjs` no acepta rutas | Lo escribí asumiendo que recorría páginas y no lo hace — mide los pares de tokens declarados en `CONTRATO.md`. Un criterio que nombra mal su herramienta no se puede ejecutar. Ahora son dos medidas: los tokens con ese script, y los textos nuevos medidos en el DOM contra su fondo real |
| 2026-08-28 | `scripts/build-og.mjs` arreglado: **estaba roto para las cuatro tarjetas** | Al construir la OG nueva no salía nada. Diagnóstico real, tras tres hipótesis falsas (el `stdio`, npm, el borrado del perfil): **Edge headless escribe el PNG DESPUÉS de que el proceso retorna**, y el script comprobaba inmediatamente. Parecía aleatorio y a mano siempre funcionaba porque entre el comando y el `ls` pasaban segundos. `--virtual-time-budget=10000` no impedía la escritura: la retrasaba más allá de esa comprobación. El arreglo es esperar a que el archivo aterrice. Añadido además un control de `mtime`: como los PNG están versionados, el script encontraba el archivo VIEJO y anunciaba «Imagen OG generada» sin haber generado nada — un «hecho» que no hizo nada, y encima invisible porque el PNG viejo se ve bien. Probado regenerando otra de las tarjetas desde cero: sale byte a byte idéntica a la versionada |
| 2026-08-28 | Fuera el `priority` del `next/image` del hero | Lo puse por copiar el molde de `tu-taller`, y las reglas del repo lo prohíben: deprecado en Next 16 |
| 2026-08-28 | El criterio 3 deja de pedir eslint «limpio» | El repo fija una **línea base de 1 error heredado** y la regla es no subir de 1. Un criterio que pide cero es un criterio que nunca se va a poder marcar, y esos se acaban ignorando. Se le añade `npm run build`, que sí estaba en las puertas del repo y no en el SPEC |
| 2026-08-28 | **Publicado.** Verificado en producción, no solo empujado | La página, el `.zip`, la OG y la ilustración responden 200 con su tipo correcto; el sitemap trae la URL; y el `.zip` **descargado de iapatodos.com** descomprime a `codex-imagenes/` con sus dos archivos y su md5 (`120e82a0…`) coincide con el del commit. **El permiso de «publicar el precio de Codex» NO se ejerció**: la página remite a la web de OpenAI en vez de escribir una cifra, así que no hay nada que envejezca |
| 2026-08-28 | Reparado el texto de dos filas del SPEC que un `perl -pi` mal escapado dejó como «en .com» | Se comió «iapatodos» en las filas del bloque 4 y del permiso de push, y llegó así al commit. Mismo `perl` que antes se había comido dos backslashes del criterio 2. Lección barata: para editar tablas con `|` y rutas con `\`, reescribir la línea entera sale más barato que escapar |
| 2026-08-29 | **Criterios 1 y 5 confirmados por otra persona.** SPEC cumplido — 5/5 criterios en verde | Reporte del founder en sesión: esa persona instaló el `.zip`, disparó la skill y funcionó; leyó la página sin haber construido nada y supo explicar la trampa. Los dos criterios exigían justo a alguien que no estuvo en la conversación que construyó esto — quedan cerrados por su verificación, no por la mía |
