Qué es
ODD-H conserva el núcleo de Organic Driven Development: explorar antes de tocar, crear un documento solo cuando hace falta y citar la spec textual. Lo que cambia es dónde vive el cumplimiento. En ODD, las reglas están en el prompt y compiten por la atención del modelo con todo lo demás. En ODD-H, las que importan para la corrección pasan al harness; en el prompt quedan solo las de criterio.
En la práctica, eso significa tres cosas:
- "Tildé el AC-3" deja de ser una afirmación. Es una línea en
.odd/ledger.jsonlcon el exit code, la duración y el hash del árbol en el que se tomó. - El trabajo chico no paga nada. Sin feature activa, ningún gate actúa. El plugin es no-op en repos sin
.odd/. - El trabajo grande siempre se puede retomar. Un documento por feature, commiteado en git, con un Próximo paso que se inyecta al abrir la sesión.
El diseño completo está en docs/ODD.md. Esta página describe lo que el plugin hace hoy. Los primeros pilotos contra SDD están en SDD contra ODD-H.
Cómo funciona
Tres capas, y ninguna confía en lo que otra declara: los hooks leen el ledger y el estado, no lo que el modelo dice que hizo.
Protocolo
Lo inyecta SessionStart
Diez reglas de criterio: clasificar el pedido, explorar en proporción, citar la spec, escribir ACs tipados.
CLI odd
Lo corre el agente por Bash
Ejecuta los checks, registra la evidencia, congela y enmienda criterios, cierra la feature.
Hooks
Los corre Claude Code
Deniegan escrituras indebidas y bloquean el fin de turno cuando la feature quedó en un estado que no se puede retomar.
Cuándo se crea un documento
La pregunta es una sola: ¿un agente nuevo, solo con el pedido y el git diff, podría terminarlo? Si no, va documento. Cualquiera de estos disparadores lo fuerza:
- Va a requerir más de una sesión.
- Depende de algo externo: una respuesta, un deploy, una API ajena, un review humano.
- La spec supera unas 40 líneas o trae strings exactos que tienen que sobrevivir a la compactación.
- Toca un path de riesgo (fase 4, todavía no lo detecta el harness).
- Lo pedís vos.
Tamaño, cantidad de archivos o cantidad de pasos no disparan nada. Sin disparador, el agente trabaja inline: sin documento y sin gates.
Ciclo de vida de una feature
El estado vive en la línea Estado: del documento. odd close solo cierra si todos los criterios tienen evidencia fresca; si falla, el agente vuelve a implementar.
Evidencia
El modelo no escribe evidencia, la pide. odd check AC-1 lee el comando de la línea del AC, lo ejecuta en la raíz del repo y agrega una entrada al ledger:
{"ts": "2026-10-28T14:02:11.204+00:00", "feature": "export-csv", "ac": "AC-1",
"kind": "test", "cmd": "pytest tests/test_export.py::test_csv_respects_filters",
"exit": 0, "secs": 1.84, "tree": "9c1e0a7f3b…"}
Frescura
La evidencia vale solo para el árbol en el que se tomó. El hash del árbol cubre todo el working tree, incluidos los archivos sin trackear, menos odd/tasks/ y .odd/: tildar una tarea en el documento no vence nada, pero tocar una línea de código sí. Se calcula con un índice temporal, así que no toca tu staging.
Cada AC está en uno de cuatro estados, según su última entrada en el ledger:
Pasó sobre el árbol actual.
Se tomó sobre otro árbol. Hay que volver a correrla.
La última corrida falló sobre el árbol actual.
Nunca se corrió, o el comando del AC cambió desde entonces.
Esto mata el patrón "corrí los tests, después toqué una cosa más y cerré". Cambiar la configuración también vence la evidencia, porque entra en el hash.
Tipos de criterio
| Tipo | Qué prueba | Cómo se registra |
|---|---|---|
test | Un test puntual: pytest path::test, swift test --filter | odd check, exit 0 sobre el árbol actual |
cmd | Un comando cualquiera: build, lint, un curl local | odd check, exit 0 sobre el árbol actual |
manual | Algo que solo una persona puede ver: una animación, el feel de una interacción | odd confirm, desde una terminal |
judge | Lo que no se reduce a un comando: fidelidad a la spec, legibilidad | Veredicto de odd-verifier. Llega en la fase 4; hoy odd lock lo rechaza |
La regla: si un AC puede ser test o cmd, no puede ser otra cosa.
Por qué el agente no puede confirmar un manual
odd confirm pregunta por /dev/tty, no por stdin. Un agente que lo corre por Bash no tiene terminal y falla; además, el guard de escritura le deniega la llamada y le dice que te pida a vos que lo corras. Dentro de Claude Code, ni con ! hay TTY: se corre en una terminal aparte.
TDD
Con "tdd": true en la configuración, odd close exige que cada AC test tenga una corrida en rojo anterior a la primera en verde. Es la prueba de que el test se vio fallar.
Gates
Cuatro hooks. Todos son no-op en repos sin .odd/, y los de feature no hacen nada si no hay una abierta.
| Evento | Qué hace |
|---|---|
SessionStart | Inyecta el protocolo y el estado: feature activa, su estado, el modo y el Próximo paso textual. |
UserPromptSubmit | Cada pedido nuevo rearma el tope de bloqueos del Stop. |
PreToolUse | Sobre Edit, Write, NotebookEdit y Bash: protege .odd/, aplica el modo read y reserva odd mode y odd confirm para vos. |
Stop | No deja terminar el turno en cuatro casos concretos. |
Qué bloquea el Stop
No puede bloquear todo fin de turno: una feature multi-sesión termina turnos sin estar cerrada, y a veces el agente para a preguntarte algo. Bloquea solo cuando:
## Criterioscambió sinodd amend. El contrato no se ablanda en silencio.- Todas las tareas están tildadas y la feature sigue abierta. Es la señal de que el agente cree que terminó: tiene que pasar por
odd close. odd closefalló en este turno. No se puede intentar cerrar, fallar y despedirse igual.- El código cambió y el documento no. Si el árbol cambió desde el último Stop pero
## Tareasy## Próximo pasosiguen iguales, la feature no se podría retomar.
Bloquea como máximo tres veces por pedido. A la cuarta deja pasar, pero anota lo pendiente en una sección ## Sin resolver del documento. Un gate que puede trabar la sesión para siempre se termina desactivando; uno que escapa a la vista, no.
Qué protege el guard de escritura
.odd/lo escribe solo el CLI.EdityWritesobre esa carpeta se deniegan, y también cualquier comando de Bash que la mencione, salvo una invocación simple deoddo ungit add,status,diffologcon flags seguros.- Modo read. Con
/odd-readactivo,Edit,WriteyNotebookEditse deniegan hasta que corras/odd-build. Sirve para reviews, auditorías o exploración. - Acciones humanas. El agente no puede cambiar el modo ni correr
odd confirm.
Si el guard mismo falla, deniega: no deja pasar escrituras sin revisar. El Stop hace lo contrario y deja pasar, para no trabar la sesión.
Es un freno, no un sandbox. El modelo de amenaza es la pereza del modelo, no un adversario. Un intérprete con el path armado en runtime lo esquiva.
Instalación
Requisitos: Claude Code, git y Python 3.9 o posterior. El plugin usa solo la stdlib.
1. Agregar el marketplace e instalar
El repo deadcode-labs/odd-h es a la vez el plugin y su marketplace. Desde el proyecto donde lo quieras usar:
claude plugin marketplace add deadcode-labs/odd-h
claude plugin install odd-h@odd-h --scope project
Para probarlo sin instalar, en una sola sesión:
claude --plugin-dir <ruta a odd-h>
2. Activarlo en el repo
Instalado, el plugin no hace nada hasta que el repo tenga .odd/. Lo crea odd init, que podés correr directo desde el plugin:
<ruta a odd-h>/bin/odd init
Crea .odd/config.json y odd/tasks/, y agrega al .gitignore el estado efímero: state.json, ledger.jsonl y el índice del hash. Commiteá .odd/config.json y los documentos de odd/tasks/.
Dentro de una sesión de Claude Code, odd ya está en el PATH de Bash. Afuera, para odd confirm, usá la ruta a bin/odd del plugin o un alias.
Desactivarlo en un proyecto
claude plugin disable odd-h@odd-h --scope local
Primera feature
Un export CSV en una API FastAPI. El pedido trae unas 50 líneas con los nombres exactos de las columnas: eso dispara documento por spec larga. Vos pedís; el agente sigue el protocolo.
-
Crear el documento
El agente explora, corre
odd new export-csvy completaodd/tasks/export-csv.md: la spec citada textual, el alcance y los criterios tipados.## Criterios - [ ] AC-1 · test · `pytest tests/test_export.py::test_csv_respects_filters` · El CSV respeta los filtros activos - [ ] AC-2 · cmd · `ruff check app/export` · Sin errores de lint en el módulo - [ ] AC-3 · manual · La descarga arranca sin bloquear la UI -
Congelar los criterios
odd lockguarda el hash de## Criteriosy pasa la feature alocked. Desde acá, cambiar un AC exige editar su línea y correrodd amend AC-n "motivo"en el mismo turno, que deja la entrada en Decisiones. -
Implementar con evidencia
Con TDD, escribe el test y corre
odd check AC-1: exit 1, y el rojo queda en el ledger. Implementa, lo vuelve a correr y da exit 0. Lo mismo conodd check AC-2. -
Mantener el documento al día
Si termina un turno habiendo tocado código sin actualizar Tareas ni Próximo paso, el Stop lo bloquea: "El código cambió y el documento no." Actualiza y sigue.
-
Confirmar lo manual
odd closefalla porque AC-3 esmanualy nadie lo confirmó. El agente te pide probar la descarga. Vos lo probás y, en tu terminal:odd confirm AC-3 AC-3 · La descarga arranca sin bloquear la UI ¿Lo verificaste vos? [s/N] s -
Cerrar
odd closetilda los ACs con evidencia fresca y escribe la tabla de Evidencia en el documento. En ningún momento el agente escribió "verificado" en prosa: cada tilde salió del ledger.
En cualquier momento, odd status muestra el modo, el estado de cada AC y cuánto falta para cerrar.
Documento de feature
Uno por feature, en odd/tasks/<feature>.md, commiteado. Es la única fuente de verdad: no hay espejo en memoria externa. ## Criterios tiene formato estricto; el resto es prosa libre.
# export-csv
Estado: tracking
Disparador: spec-larga
## Objetivo
Una oración: qué cambia para el usuario.
## Spec
> Cita textual del pedido. Sin resumir, sin reordenar.
## Alcance
- Incluye: ...
- No incluye: ...
## Criterios
- [ ] AC-1 · test · `pytest tests/test_x.py::test_y` · Qué prueba
## Tareas
- [ ] T1 · Endpoint de export (AC-1)
## Decisiones
## Evidencia
(la completa `odd close`)
## Próximo paso
Una línea. Lo primero que hace quien retome.
Formato de un criterio
- [ ] AC-<n> · <tipo> · `<comando>` · <descripción>
testycmdllevan comando entre backticks;manualno.- Cualquier línea de
## Criteriosque no sea un AC es un error. Los comentarios HTML se ignoran. - El tilde no forma parte del contrato: lo pone
odd close, no el modelo.
Decisiones de diseño
- Criterios separados de Tareas. Los ACs son el contrato y se congelan; las tareas son el plan y se reordenan sin amend.
- Próximo paso obligatorio. Se inyecta al abrir la sesión, así el agente retoma sabiendo dónde estaba.
- Sin diario de progreso. El progreso es el estado de las tareas más el ledger. Un diario se desactualiza y nadie lo lee.
Referencia del CLI
La única vía para producir evidencia. Todo comando busca la raíz git desde el directorio actual y falla si no hay .odd/, salvo init.
| Comando | Qué hace |
|---|---|
odd init | Crea .odd/config.json y odd/tasks/, y completa el .gitignore. |
odd new <feature> | Crea el documento desde el template y lo activa. Nombre en minúsculas, dígitos y guiones. Una feature activa a la vez. |
odd lock | Valida y congela ## Criterios, y pasa a locked. |
odd check AC-n | Corre el comando de un AC test o cmd y registra el resultado. Devuelve su exit code; un timeout se registra como 124. |
odd amend AC-n "motivo" | Acepta el cambio de un solo AC ya editado (nuevo, modificado o eliminado), lo anota en Decisiones y recongela. |
odd confirm AC-n | Registra un AC manual. Solo una persona, desde una terminal. |
odd close | Si toda la evidencia está fresca, tilda los ACs, escribe la tabla de Evidencia y cierra. Si no, falla y lista qué falta. |
odd status | Modo, estado de cada AC, tareas hechas y si la feature está lista para cerrar. |
odd mode read|build | Cambia el modo. Lo usan /odd-read y /odd-build; el agente no puede correrlo. |
Comandos de Claude Code
/odd-read: activa el modo read. El agente puede leer, responder y proponer, pero no editar./odd-build: vuelve al modo build.
Configuración
.odd/config.json, versionado con el repo:
{
"tdd": false,
"hash_exclude": [],
"check_timeout": 600
}
| Clave | Qué controla |
|---|---|
tdd | Si es true, cada AC test tiene que verse en rojo antes de su primer verde para poder cerrar. |
hash_exclude | Paths relativos concretos que no entran en el hash del árbol, como "assets". Útil en repos con directorios pesados. No acepta comodines, . ni ... |
check_timeout | Segundos que puede tardar un odd check antes de cortarse. |
Los archivos que generen tus checks (snapshots, caches) conviene que estén en .gitignore: el hash respeta el .gitignore y se toma antes de correr el comando.
Qué está hecho
El diseño se adopta en cinco fases, cada una usable por sí sola. El plugin va por la tercera.
| Fase | Incluye | Estado |
|---|---|---|
| 1. Protocolo | Protocolo inyectado al iniciar y template del documento | hecha |
| 2. CLI y ledger | init, new, lock, check, amend, confirm, close, status | hecha |
| 3. Gates básicos | Guard de escritura, modo read, Stop gate | hecha |
| 4. Riesgo y subagentes | risk.yml, odd-verifier y ACs judge, odd-explorer, guard de delegación | pendiente |
| 5. Calibración | metrics.jsonl, odd doctor, defaults por stack | pendiente |
Hasta la fase 4, el protocolo no menciona subagentes y los paths de riesgo no se detectan solos: ese disparador queda a criterio del agente.
Límites
- Los ACs se congelan, los tests no. Después de
odd lock, el agente puede debilitar el test al que apunta un AC y el gate pasa en verde. El rojo obligatorio de TDD lo mitiga; la revisión de esos cambios por el verifier llega en la fase 4. - Clasificar sigue siendo juicio. Un trabajo que necesitaba documento se puede hacer inline.
- El hash del árbol cuesta. Se calcula en cada Stop; en repos grandes, excluí directorios pesados con
hash_exclude. - Los tests lentos hacen lento a
odd check. Escribí ACs por caso, no por suite, y dejá UI y animaciones comomanual. - El escape del Stop es visible, no imposible. A los tres bloqueos se puede terminar el turno, pero queda escrito en
## Sin resolver.
Un límite de fondo: ODD-H no mejora las decisiones de diseño. Garantiza que lo que se declaró se cumplió y que el trabajo se puede retomar.