# El código base es el harness

> Original en inglés. Traducción generada por IA, no por el autor. [Leer el original en inglés](https://www.ferueda.com/writing/the-codebase-is-the-harness).

> Componentes prácticos para un harness en el que agentes y personas puedan confiar.

Antes escribí sobre [qué entiendo por ingeniería de harnesses](/es/writing/reflexiones-sobre-la-ingenieria-de-harnesses): el harness del modelo alrededor del LLM y el harness del proyecto que realmente controlas. Este artículo es la continuación práctica. Entonces, ¿qué debería vivir en el código base para que el agente no te pregunte lo mismo cada vez o, peor aún, se lo invente?

¿Sin harness? Las mismas preguntas en cada sesión. Qué leer, qué demuestra que terminamos, cómo preparar el entorno, dónde van las pruebas, qué comandos son seguros. El agente olvida. El código base recuerda.

Mi postura es simple: **el código base es el harness.** No un prompt. No Cursor ni Codex. Es la capa propia del proyecto que convierte la intención, la preparación y las verificaciones en algo que el agente puede comprobar.

## El modelo predice. El código base hace cumplir las reglas.

- **El harness del modelo** es el producto: sesiones, herramientas, permisos, MCP. Lo configuras. No es tuyo.
- **El harness del proyecto** es lo que vive en el código base: documentación, comandos, pruebas, scripts, integración con CI y hábitos que convierten errores repetidos en controles de protección.

El modelo predice el siguiente token plausible. El código base define qué cuenta como terminado. El mismo prompt, otra ejecución, otra respuesta. Ambas pueden sonar correctas. Por eso necesitas verificaciones que el agente pueda ejecutar sin preguntarte.

> Los prompts son sugerencias. Los linters son ley.

## El harness mínimo que resulta útil

Puedes ampliarlo con el tiempo. Estas son las piezas que no omitiría.

**Un mapa, no un libro.** El `AGENTS.md` de la raíz debería responder: qué es este proyecto, cuáles son las reglas innegociables, dónde está la intención del producto, dónde está la arquitectura, qué verificación ejecuto para cada tipo de cambio y qué hago cuando falla. Referencias a archivos reales. No un volcado de instrucciones de 50 páginas.

**Intención del proyecto.** Un documento enfocado que explique qué es el producto, para quién es, qué prioriza, qué explícitamente _no_ prioriza y qué suposiciones son peligrosas. Sin esto, el agente básicamente deduce la dirección del producto a partir del código que tiene alrededor. Aceptable para el color de un botón. Inaceptable para decidir a quién pertenecen los datos, la facturación, la privacidad o qué se permite romper en la API.

**Un comando que signifique terminado.** `make verify`, `pnpm verify`, `npm run validate`, lo que encaje en tu stack. Documentado en el mapa. Lo bastante amplio para detectar regresiones entre componentes. La verificación local antes de entregar debería ser al menos tan exigente como CI para el trabajo habitual.

**Verificaciones acotadas para iterar.** ¿Solo cambiaste el paquete de API? Ejecuta su verificación. ¿Una migración de base de datos? Ejecuta la de base de datos. La verificación final define la entrega; las acotadas mantienen rápido el ciclo.

**Comprobar y preparar el entorno local.** Una comprobación de solo lectura que diga qué falta. Una preparación explícita que cree un estado local seguro. Nunca inventar secretos reales. Nunca sobrescribir valores locales no vacíos. La preparación debería ser un comando, no un hilo en Slack.

**Guía de niveles de pruebas.** Indícale al agente dónde corresponde la evidencia: pruebas unitarias junto al código, pruebas de persistencia cuando la base de datos sea el objeto de la prueba, smoke tests solo cuando necesites transporte real y E2E completo como último recurso. Por defecto, el nivel más barato que demuestre la intención.

**Inventario de scripts.** Los scripts son parte de la API pública, lo hayas querido o no. Documéntalos: dónde están, si leen o modifican, quién es responsable y qué objetivo de Make/npm los expone a los agentes. Mal nombre: `setup.sh`. Mejor: `prepare-local-env`, para que nadie destruya producción por accidente.

**CI llama a los comandos del código base.** GitHub Actions, o lo que uses, debería ser sencillo: checkout, instalación y ejecución del objetivo de verificación del repositorio. No dupliques la lógica de “¿tocaron la API?” en tres archivos de workflow. Déjala en el código base para que local y CI se mantengan sincronizados.

**Hooks baratos.** Formatear y ejecutar lint al hacer commit está bien. Los hooks son higiene, no la definición de terminado. No cuelgues toda la suite de pruebas ni las verificaciones de base de datos del pre-commit.

| Pieza                                  | Función                                                       |
| -------------------------------------- | ------------------------------------------------------------- |
| `AGENTS.md`                            | Dirigir al agente a la documentación y los comandos adecuados |
| Intención del proyecto                 | Límites del producto antes de escribir código                 |
| Verificación final                     | Una respuesta a “¿terminamos?”                                |
| Verificaciones acotadas                | Iteración rápida sin omitir la entrega                        |
| Comprobación / preparación del entorno | Preparación autónoma                                          |
| Niveles de pruebas                     | Evidencia adecuada al costo adecuado                          |
| Inventario de scripts                  | Sin comandos que modifiquen cosas por sorpresa                |
| CI                                     | La misma lógica del repositorio que en local                  |

No le cargues todo esto al agente en cada sesión. Haz que pueda encontrarlo: un mapa breve al principio y documentos enfocados que pueda abrir cuando la tarea los necesite. Debería poder encontrar la pieza correcta sin que pegues medio repositorio en el chat.

## Camino de adopción

Empieza pequeño. Añade el resto a medida que aparezcan los problemas. No necesitas todo desde el primer día.

**Mapea el código base.** Un archivo breve para agentes en la raíz, intención del proyecto, referencias de arquitectura y documentos específicos donde algún dominio necesite un tratamiento especial. Haz navegable el código base antes de escribir una enciclopedia.

**Define terminado.** Una verificación final. Ejecutable localmente. Documentada. Lo bastante determinista para que los fallos indiquen qué hacer. CI invoca la misma lógica o un equivalente claramente documentado.

**Añade verificaciones acotadas.** Que correspondan a cómo cambia realmente el código base: solo frontend, solo backend, un paquete, contratos, documentación. Iteración rápida; la verificación final sigue siendo responsable de la entrega.

**Haz que CI se pueda reproducir localmente.** Filtros por ruta en un manifiesto o script con pruebas. Los workflows llaman a comandos del repositorio. Sin selección de objetivos duplicada entre archivos YAML.

**Haz explícita la preparación.** Comprueba qué falta. Prepara lo que sea seguro. Documenta qué puede restablecer localmente la verificación y por qué.

**Documenta los niveles de pruebas y el inventario de scripts.** Para que el agente no elija por defecto la prueba más lenta o un script de shell cualquiera en cada ocasión.

**Convierte la revisión repetida en controles.** Si tú o un revisor dicen lo mismo dos veces, es una señal: documéntalo, pruébalo, crea una regla de lint o un script. No sigas explicándolo en cada PR.

## Plantillas que puedes tomar prestadas

Estructuras independientes del stack. Cambia Make por npm, Vitest por `go test` o por lo que uses.

**Mapa raíz (`AGENTS.md`):**

```markdown
# Project name

Short description. Read `docs/project-intent.md` before product decisions.

## Non-negotiables

- Invariant one
- Invariant two

## Where to read

- Intent: `docs/project-intent.md`
- Architecture: `docs/architecture.md`
- Testing: `docs/testing.md`

## Checks

- Area changed only: `make check-<area>`
- Normal handoff: `make verify`

## When checks fail

Run `make fix` if available, then re-run the scoped gate or `make verify`.
```

**Intención del proyecto (`docs/project-intent.md`):**

```markdown
# Project intent

## What this is

One paragraph. Present tense. Real behavior today.

## What this is not

Explicit non-goals.

## Optimizes for

## Does not optimize for

## Unsafe assumptions

Things the agent must not infer from nearby code.

## Hard invariants

Violations are bugs, not style preferences.
```

**Matriz de comandos (en la documentación del harness o de contribución):**

| Comando                  | Cuándo                                | ¿Modifica?            |
| ------------------------ | ------------------------------------- | --------------------- |
| `make check-local-env`   | Antes del trabajo pesado              | No                    |
| `make prepare-local-env` | Faltan archivos locales               | Sí (solo local)       |
| `make check-api`         | Cambiaron rutas de API                | No                    |
| `make verify`            | Entrega con cambios de comportamiento | Tal vez (documentado) |
| `make fix`               | Después de fallos de formato/lint     | Sí                    |

**Verificación final (Makefile o script del paquete):**

```makefile
.PHONY: verify
verify: check fix-if-needed db-check-if-needed
	@echo "verify: ok"
```

**Fila del inventario de scripts:**

| Ruta                    | Dominio | Público                  | Modo     | Notas                |
| ----------------------- | ------- | ------------------------ | -------- | -------------------- |
| `scripts/seed-local.sh` | dev     | `make prepare-local-env` | modifica | Solo local; nunca CI |

**Entorno local:**

```makefile
check-local-env:
	@test -f .env.local || (echo "run: make prepare-local-env"; exit 1)

prepare-local-env:
	@test -f .env.local || cp .env.example .env.local
```

**Workflow de CI mínimo:**

```yaml
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: make verify
```

Lo importante no es la sintaxis. Es que cada capa apunte a los mismos contratos.

## No es solo teoría

No escribo sobre esto solo en abstracto. Lo construyo en la mayoría de mis proyectos y de mi trabajo. Un repositorio que mantengo aparte es [harness](https://github.com/ferueda/harness): una CLI, workflows invocables, skills empaquetadas y el ejecutor que los une. El repositorio de tu producto sigue necesitando su propio mapa, verificaciones y preparación. Harness es lo que uso para revisar cambios, dirigir el trabajo de agentes y mantener explícitos los ciclos.

Si las plantillas anteriores te ayudan a diseñar, ese repositorio te permite ver ejemplos funcionando: integración de workflows, estructura de skills y documentación para colaboradores. Sigue evolucionando. Copia lo que te sirva. Más contexto: [/projects/harness](/es/projects/harness).

## Lo que el harness no hace

No sustituye el criterio. Las verificaciones detectan desviaciones y errores mecánicos. No eligen tu estrategia de producto.

Las verificaciones obsoletas engañan. Si `verify` no coincide con lo que ejecuta CI, o la guía de pruebas dice una cosa y el código hace otra, el agente aprende la lección equivocada.

Los agentes omiten pasos si se lo permites. Las verificaciones acotadas no ejecutan toda la suite. Las versiones incorrectas de las herramientas siguen arruinándote la tarde. Las comprobaciones de base de datos necesitan Docker activo. **El harness reduce las suposiciones. No sustituye tu buen criterio.**

> El chat no es memoria. El código base sí.

Esa es toda la apuesta. Pon la intención, la preparación y la evidencia donde el agente, y la siguiente persona, puedan ejecutarlas sin depender de ti. Construye el harness junto al producto. Cada vez que explicas lo mismo dos veces, probablemente al código base le falta un control.
