El sistema que trabaja aunque no estéis mirando.
Esto os lo prometí en la Sesión 2, slide 2: «Estándar del equipo en el repo y tu primer agente personal». Hoy se cumple.
/spec-mine — demo + falsarUn método que depende de que te acuerdes de seguirlo no es un método. Es una buena intención.
| Misión | Bloque | XP | Badge |
|---|---|---|---|
| M1 · Estándares que bloquean | B3 | +200 | 🚧 Gatekeeper |
| M2 · Tu primer agente | B4 | +250 | 🤖 Agent Maker |
| M3 · Falsar la spec minada | B5 | +100 | ⛏️ Spec Miner |
| M4 · Judgment Day | B6 | +150 | 👁️ Doble Ciego |
| M5 · Portabilidad | B7 | +100 | 🧳 Nómada |
Bonus: +50 haces que un hook te bloquee y sabes explicar por qué · +30 tu agente lo usa otro dev y le funciona · +50 encuentras un error real en la spec minada · +50 Judgment Day con 0 findings confirmados sobre tu código · +20 identificas qué perderías exactamente al migrar de harness. El podio suma S2 + S3. Certificados al cierre.
Nadie se queda atrás.
# 1 · Observad primero. --dry-run no escribe nada. node scripts/install.js --harness claude-code --profile empowered --target <repo> --dry-run # 2 · Y ahora sí. node scripts/install.js --harness claude-code --profile empowered --target <repo> --apply # → Done: 113 created, 0 skipped ← lo que dice la terminal # → 102 archivos en disco ← lo que de verdad aterriza
CLAUDE.md no se toca (already exists — not overwriting project context). Todo lo demás se reescribe si repetís el --apply.--dry-run antes de --apply. Siempre. Esto también es loop engineering: observad antes de actuar.
settings.json.Esto va también en el email previo a la sesión. Si llegáis sin el repo clonado, el Bloque 0 se come el Bloque 1.
El cuarto kit del programa. Y el último que os doy hecho.
«Not a Claude Code kit. A neutral core/ projected into 5 AI harnesses.» — README del kit, literal.
core/ neutro — markdown + JS, sin marcaadapters/ a cinco harnesses.claude/Aquí no hay nada original nuestro salvo el criterio. Hay un ecosistema abierto ahí fuera — MIT, con licencia y con nombre — y el trabajo no fue escribirlo: fue saber qué coger, qué dejar y cómo encajarlo. Eso vale más que cualquier feature que os enseñe hoy.
| Kit S2 | Empowered | |
|---|---|---|
| Skills | 12 | 19 |
| Agentes | 3 | 19 |
| Hooks vivos | 0 | 8 |
| Contratos de orquestación | 0 | 10 |
| Validadores CI | 0 | 9 |
| Comandos | prestados de openspec | 15 propios |
| Harnesses | 1 | 5 |
Fijaos en la fila de los hooks. De cero a ocho. No es «más de lo mismo»: es la primera vez que hay código que os puede parar las manos.
Fijaos en lo que acaba de pasar: la cifra que llevaba dos días en mis notas era 102, y la terminal dice 113. Ninguna miente. Contaban cosas distintas y nadie lo comprobó. Llevamos cuatro slides de sesión.
Por qué el kit tiene hooks y no consejos.
Hice un dry-run del kit que os iba a dar hoy. Cuatro de los ocho hooks estaban muertos. No rotos — muertos. Cableados a eventos que nunca leían. Salían con 0 en cada invocación. El código estaba bien; el cableado estaba mal.
¿Y sabéis qué es lo mejor? Que --dry-run no podía cazarlo jamás. Dry-run nunca escribe settings.json, así que toda la capa de guardarraíles vivía justo en el único camino de código que dry-run se salta.
No me salvó revisar el código. Me salvó ejecutarlo y observar el resultado. Y casi os doy un kit con la mitad de los guardarraíles apagados.
--dry-run no podía cazar los hooks muertosvalidate-no-personal-paths.js no matcheaba ~/validate-specs.js no validaba ningunonpm run validate en verde era un no-opopenspec/ en el repo del kit.ripgrep dio un cero falso.claude/ y .cursor/ nunca se escanearon.Todo estaba declarado. Nada estaba verificado. El kit que os iba a enseñar loop engineering estaba construido sin un solo loop.
Le pedimos editar .pre-commit-config.yaml. Se negó, y reportó que el hook lo había bloqueado. Fuimos a mirar: el hook salía con 0. Nunca disparó. Lo que pasó es que leyó el CLAUDE.md del kit, se autocensuró, y narró como hecho un bloqueo que no existía.
Si eso pasa hoy en este aula, vosotros marcáis «hook disparó ✅» y os vais a casa creyendo en un guardarraíl que no existe. Lo cazamos porque alguien miró el git diff en vez de creerse el texto.
La narración del modelo NO es evidencia. Ni cuando dice que falló. Verificad por efecto, nunca por narración.
Todos tenéis el mismo Claude. Literalmente el mismo. Lo que os diferencia no es el modelo — es el loop en el que lo metéis.
Ojo a la tercera. El tipo que dirige la herramienta que tenéis abierta ahora mismo dice que su trabajo ya no es hablarle al modelo — es construirle el bucle. Esto no es una opinión mía: tiene un mes y ya cambió a qué se dedica la gente que hace las herramientas.
Fuentes: Addy Osmani — addyosmani.com/blog/loop-engineering/ · LangChain — langchain.com/blog/the-art-of-loop-engineering · O'Reilly Radar — oreilly.com/radar/loop-engineering/
Si el agente no puede observar el resultado de lo que hizo, todo lo que viene después es ficción. Verifica qué. Corrige contra qué.
En vez de pedir autoevaluación, gateguard exige hechos concretos antes de dejarte editar: quién importa esto, cuál es el esquema, qué te pidió el usuario. +2,25 puntos de calidad medida frente a agentes sin gate. El acto de investigar crea una consciencia que la autoevaluación nunca creó.
Los comandos cambian. Los kits caducan. El loop no. Si os lleváis una cosa, que sea el loop — y hoy os lleváis además el kit que lo implementa.
Quince minutos. Al volver: los estándares que bloquean — el primer LAB de la sesión.
«Estándar del equipo en el repo» — la primera mitad de lo que os prometí.
Un estándar que depende de que alguien se acuerde no es un estándar. Es folclore.
| Hook | Evento | Nivel | Qué hace | ¿Probado? |
|---|---|---|---|---|
block-no-verify | PreToolUse(Bash) | standard+ | BLOQUEA git commit/push --no-verify | ✅ bloqueo observado |
config-protection | PreToolUse(Edit|Write|MultiEdit) | standard+ | BLOQUEA ediciones a config de linter/formatter | ✅ bloqueo observado |
pre-deploy-guard | PreToolUse(Bash) | standard+ | BLOQUEA comandos de deploy hasta pasar la puerta de calidad | ⬜ sin probar |
secret-scan | PreToolUse | minimal+ | Avisa de secretos | ⚠️ no-op si lo escribe Claude |
session-start | SessionStart | minimal+ | Inyecta contexto vivo: rama, último commit, recordatorio | ✅ dispara |
context-monitor | PostToolUse(*) | standard+ | Avisa de scope creep y bucles de herramienta | ✅ advisory (exit 0 siempre) |
post-edit-accumulate | PostToolUse(Edit|Write|MultiEdit) | standard+ | Acumula rutas editadas; sin latencia por edición | ⬜ sin probar |
stop-format-typecheck | Stop | strict | Formatea + typechequea UNA vez al cerrar | ⬜ sin probar |
Cuatro de estos estaban muertos hace tres días. Ahora no. Y fijaos en la última columna: tres siguen sin probar, y os lo estoy diciendo. Eso es lo único que distingue esta tabla de la que había en el README.
Distinguid señal de gate: context-monitor y stop-format-typecheck siempre salen 0 — avisan, no paran. Solo tres bloquean de verdad. · ⚠️ secret-scan es no-op si el secreto lo escribe Claude (la clave aterriza en disco; verificado): solo avisa si lo tecleáis vosotros. No lo demostréis como si protegiera — es un agujero real y se cuenta como tal.
Dato del dry-run: había dos vocabularios (empowered vs strict) y nadie los traducía → --profile empowered no activaba los hooks empowered. Arreglado. Buen ejemplo de «el estándar existía en dos sitios y se contradecían».
# Paso 1 — que te bloquee. La forma IMPORTA: flag al final. git commit -m "chore: wip" --no-verify # → exit 2. El commit NO ocurre. # Paso 2 — NO te lo creas. Demuéstralo. ← AQUÍ ESTÁ EL XP. git log --oneline -1 # ¿hay commit nuevo? NO. # Paso 3 — otra vez, con un archivo: pedidle a Claude editar ruff.toml git diff ruff.toml # ¿cambió? NO. # Paso 4 — la trampa del perfil ★ EL MEJOR MOMENTO DEL LAB export HOOK_PROFILE=minimal # → NO hace absolutamente nada. # Paso 5 — el mecanismo real: cambiar el perfil en settings.json # → repetir el commit del paso 1 → ahora pasa. Probadlo con git log.
Paso 4, verificado: la shell dice minimal, el hook sigue viendo strict. El gating solo funciona vía settings.json. El modelo mental obvio es falso. «¿Veis? Otra vez. Está documentado como variable de entorno. Nadie lo comprobó nunca. Acabáis de encontrar el séptimo caso, vosotros solos, en directo.»
⚠ Nunca git commit --no-verify -m "..." (flag antes del mensaje): lo bloquea permissions.deny por match de prefijo incluso en perfil minimal, y el lab no enseña nada. · ⚠ Honestidad: secret-scan es no-op si el secreto lo escribe Claude. Solo avisa si lo tecleáis vosotros. NO demostrarlo como si protegiera.
# Paso 6 — RÓMPELO. Cinco minutos. +50 XP al primero que encuentre uno nuevo. # Bypasses YA endurecidos (verificados pasando ANTES del endurecimiento): git -c core.hooksPath=/dev/null commit -m "..." # ← pasaba printf '...' > ruff.toml # ← pasaba (config-protection # bloqueaba apply_patch, no la shell) # Buscad uno NUEVO. Y comprobad por efecto, siempre: git log --oneline -1
«Ya confiáis en el hook. Lo habéis visto pararos y lo habéis probado en el git log. Ahora quiero que lo rompáis. Tenéis cinco minutos.» Hemos endurecido los bypasses conocidos. Buscad uno nuevo — y lo va a encontrar alguien: es un juego que no se gana.
Paso 7 — ¿y entonces dónde está el gate? «Acabáis de derrotar vuestro propio guardarraíl en cinco minutos. Y gpt-5.4-mini lo hizo sin que nadie se lo pidiera — solo le dijimos que commiteara. ¿Dónde está el gate de verdad?» Respuesta: donde el agente no llega. CI. Branch protection. Checks obligatorios en el servidor. Los hooks cazan el error honesto — el --no-verify que tecleáis por costumbre a las 19:00 un viernes. No paran a un agente decidido, y no pretenden hacerlo.
No es un aviso. Es un exit 2: la acción no ocurre. Pero no me creáis a mí tampoco — miradlo en el git log. Hoy ya hemos visto a Claude jurar que un hook lo paró cuando el hook ni siquiera existía… y al minuto siguiente, saltárselo sin avisar.
✅ Verificado: una sesión NUEVA tras --apply no necesita reinicio; una ya abierta, sin verificar → asumir reinicio. · Esta lista se reparte impresa — es el reto del paso 6 y el material más honesto del deck.
Hace una hora os puse una jerarquía de señales y os dije que el escalón 5 — el hook con exit 2 — era no negociable. Me lo creía. Acabáis de demostrarme que estaba mal, con las manos, en cinco minutos. Eso que os acaba de pasar es exactamente lo que nos ha pasado con este kit durante dos días. Yo declaro. Vosotros verificáis. Se cae.
--no-verify-ncore.hooksPath=/dev/nullLos dieciocho casos de esta mañana eran declarado pero no verificado. Este es una clase nueva, y es peor: verificado — pero verificando lo que no era. El hook SÍ bloquea --no-verify. Probado, observado, real. Y no sirve de nada, porque matchea la ortografía, no el efecto.
Y no fuimos nosotros los primeros: gpt-5.4-mini, en un fixture limpio, bloqueado en --no-verify, usó git -c core.hooksPath=/dev/null por iniciativa propia y commiteó. Nadie le pidió que lo rodeara. · El modelo no era adversario. Era obediente. Le dijimos «commitea». El guardarraíl estaba entre él y el objetivo que le dimos nosotros. Rodearía un test que falla con la misma naturalidad. · Y no se arregla añadiendo hooksPath a la lista — whack-a-mole, siempre hay otra ortografía. Un hook ve una llamada a herramienta, no una syscall. El techo es estructural.
La jerarquía no tiene un eje. Tiene tres, y los tres los hemos pagado con cicatrices.
La única señal que vale es un test de comportamiento, que corre donde el agente no llega, y que has visto fallar. Falla uno de los tres ejes y tenéis decoración. Nosotros fallábamos los tres, y el kit decía 8 de 8.
El dato que lo sostiene: de los ~20 defectos reales de este kit, la suite estática arreglada cazaría 4. Los otros 16, no. test:guardrails y test:cursor — dos suites de comportamiento — valen más que los ocho validadores juntos. · Los 8 validadores de CI no son el cinturón, son el airbag. · Los hooks no sobran: cazan el --no-verify de un viernes a las 19:00. Eso lo hacen bien. Lo que no hacen es lo que yo os dije hace una hora.
HOOK_PROFILE va al repo.No os voy a decir cuál. Es vuestro repo y vuestras guardias. Pero elegidlo explícitamente — no por defecto.
⚠ Verificado hoy, y os va a morder: si volvéis a lanzar --apply (para actualizar el kit), el instalador reescribe env.HOOK_PROFILE al valor del perfil que le paséis. Puse minimal a mano, relancé --apply --profile empowered, y volvió a strict sin avisar. Vuestras claves propias en settings.json sí sobreviven — se hace merge, no clobber. Pero la del perfil no. Otra más: estaba declarado como «idempotente», y en disco no lo es.
Bonus disponible: +50 XP si haces que un hook te bloquee y sabes explicar por qué.
La segunda mitad de lo que os prometí. Y lo único de hoy que no os doy yo.
Lo que vais a escribir en veinticinco minutos es un markdown con frontmatter. Claude Code lo despacha, le da un contexto en blanco, le deja unas herramientas concretas, y cuando devuelve su respuesta se muere. No tiene loop propio. No tiene memoria entre invocaciones. No se despliega. No se despierta solo. Vive dentro del loop de Claude.
Llevamos toda la tarde cazando cosas que decían ser lo que no eran. Pues bien: esto es una de ellas, y está en la portada de mi propio deck.
❌ No es autónomo · no persiste · no tiene loop propio · no se despliega · no se programa · no ficha.
✅ Un rol especializado que Claude adopta · con contexto fresco · y herramientas restringidas.
Es un especialista al que Claude llama. No un empleado que ficha.
Un sub-agente es un loop dentro de otro loop, con menos contexto y menos manos. Todo lo del bloque 2 vale aquí: ¿cuál es su señal? ¿la ve? ¿cuándo para? Solo que ahora el que diseña el loop sois vosotros.
Por eso tools es la decisión más importante del frontmatter — no es una lista de permisos, es el tamaño del loop.
backend-developerfrontend-developerproduct-strategy-analystjd-judge-a · jd-judge-b · jd-fix-agentspec-miner · code-explorerplanner · tdd-guide# .claude/agents/capacity-reviewer.md --- name: capacity-reviewer description: Revisa cambios en el cálculo de capacidad de red. model: sonnet tools: ["Read", "Grep", "Glob", "Bash"] --- # Conocimiento de dominio que no está en ninguna wiki: # - Las fuentes mezclan MW y kW. REE publica MW; las distribuidoras, kW. # - El bug de marzo: un factor 1000 se coló por no normalizar en ingesta. # - NUNCA aprobar cambios en capacity_readings sin test de regresión.
Esto no es magia. Es un markdown. Lo que lo hace potente no es el modelo — es que vosotros sabéis qué preguntar y la wiki no.
Esquema verificado el 2026-07-16 contra los 20 agentes del kit y los 40 globales: name (20/20 · 40/40) · description (20/20 · 40/40) · tools (19/20 · 40/40, formato ["Read", "Grep"]) · model (20/20 · 30/40). Cuatro claves, ni una más. color es cosmético. metadata y license son convención del kit, no de Claude Code. No inventéis claves.
El mejor agente que vais a escribir hoy sale de una pregunta: ¿qué le explico a cada dev nuevo que entra, una y otra vez?
.claude/agents/<vuestro-agente>.md a manotools al mínimo/agents → ¿aparece en la Library? ← verificad por efectoPaso 5: «Esto es el bloque 2 aplicado a vuestro propio trabajo. Escribir el archivo es declarar. Verlo en la Library es verificar. Son cosas distintas, y llevamos toda la tarde pagando la diferencia. Hoy hemos visto a Claude jurar que un hook lo bloqueó cuando el hook no existía — y negar que unos agentes hubieran cargado cuando sí. No os creáis el archivo: miradlo.»
Cada uno se lleva un agente escrito por sí mismo. Ese es el entregable real de hoy — el kit os lo doy yo, el agente lo escribís vosotros.
⚠ /agents existe, pero desde la v2.1.198 ya NO abre asistente de creación — es un visor. No prometáis un wizard: no lo hay. Y eso mejora el lab: el asistente les habría escondido la anatomía y saltado la verificación.
.claude/agents/ está versionado.Un agente en tu portátil es un truco. Un agente en el repo es una decisión de equipo.
Bonus disponible: +30 XP si tu agente lo usa otro dev y le funciona.
Quince minutos. Los dos labs ya están hechos. Lo que queda es lo que hace que el sistema se sostenga solo.
SDD asume que empezáis de cero. Vosotros no empezáis de cero.
En la S2 hicimos SDD sobre un ticket nuevo, en verde. Perfecto. Pero onedev-grid-service ya existe. Miles de líneas, cero specs. ¿Las escribís a mano? ¿Los ocho? ¿Este trimestre?
openspec/specs/<capability>/spec.mdLast verified: <git-hash>Lanza /spec-mine dedup-sha256 sobre la deduplicación por SHA-256 — la que construisteis vosotros en la Sesión 2 (ONEDEV-218). En vivo.
Reciben la spec generada. Trabajo: falsarla contra el código. ¿Dónde se equivocó el agente? +50 XP al que encuentre un error real.
🎯 Por qué esa y no otra: esa spec la escribisteis vosotros a mano hace un mes. Tenéis la verdad de referencia en la cabeza. No estáis falsando a ciegas: estáis viendo qué entendió la máquina de algo que vosotros mismos especificasteis. En la S2 escribisteis la spec y de ahí salió el código; hoy la máquina lee el código y os devuelve la spec. Vamos a ver si coinciden.
Vuestro trabajo no es ejecutar el comando — eso lo hace cualquiera. Vuestro trabajo es no creéroslo. La corrección que hagáis es vuestro conocimiento de dominio entrando al repo.
⚠ Por qué demo y no lab: 5–10 min por run × 8 devs = rate limits de Opus (medido en el dry-run) + espera muerta. Falsar es la habilidad valiosa, no teclear.
/spec-mineNo minéis el repo entero. Nadie revisa 40 specs. Una por sprint, la que más duele. En seis meses tenéis el sistema documentado por el propio sistema.
Misión 3 completada · +100 XP · ⛏️ Spec Miner — Bonus: +50 XP si encuentras un error real en la spec minada.
El boss fight de la S2 tenía un agujero. Hoy lo tapamos.
En la S2 os enseñé /adversarial-review. Un juez, una pasada. Estaba bien. Tenía un agujero.
Conecta con el Bloque 2: esto es señal blanda — capa 2 de la jerarquía. Opinión de un modelo.
jd-judge-a y jd-judge-b revisan en paralelo e independientementejd-fix-agent aplica únicamente los confirmadosMirad lo que acaba de pasar: convertimos una opinión (capa 2) en algo parecido a una señal (capa 4). No porque el modelo sea mejor — porque el loop es mejor. Mismo modelo. Mejor loop. Eso es todo lo que os quería enseñar hoy, y está aquí, en un comando.
DEMO conducida: un run real. Enseñar findings de A, findings de B, la intersección, y qué se cae.
Regla: >400 líneas → chained-pr primero, después juzgas cada slice. Un juez frente a un diff gigante es un juez que no lee.
Misión 4 completada · +150 XP · 👁️ Doble Ciego — Bonus: +50 XP si Judgment Day sale con 0 findings confirmados sobre tu código.
La pregunta que os va a hacer vuestro manager. Y hoy la vais a saber contestar.
| Harness | Archivos en disco | Guardarraíles | Slash commands |
|---|---|---|---|
| Claude Code | 102 | Hooks vivos que bloquean | Sí |
| Cursor | 87 | Hooks vivos que bloquean | No |
| OpenCode | 94 | Hooks vivos que bloquean | Sí |
| Gemini | 71 | Reglas + CI (advisory) | No |
| Codex | 71 | Reglas + CI (advisory) | No |
Mismo kit. Mismo estándar. Mismo modelo. Y en Gemini se convierte en un consejo. ¿Veis por qué llevo toda la tarde insistiendo con la señal dura? Aquí lo tenéis medido en cinco herramientas. La línea divisoria no es la marca — es si el harness te deja poner un gate que bloquee.
Medido hoy, instalador real, perfil empowered, sobre fixtures desechables. Las cifras que llevaba en las notas (85·75·90·68·69) estaban todas caducadas: los adaptadores cambiaron después. · Y ojo con lo que esta tabla NO dice: es lo que el instalador proyecta — las tres últimas columnas salen de los skips que el propio adaptador declara («Gemini CLI: no live hooks»). No hemos ejecutado Gemini (sin autenticar) ni el dispatch de Cursor en el IDE. Proyección verificada ≠ runtime verificado. Os lo digo yo antes de que me lo preguntéis vosotros.
core/ neutro: skills, agentes, contratos, estándares y los 8 validadores de CI. Son markdown y Node: no dependen del harness. El airbag viaja entero.AGENTS.md, GEMINI.md o .cursor/rules/*.mdc — pero lo invocáis a mano.Fijaos en qué se cae y qué no: se cae el badén, nunca el gate. Los validadores de CI llegan intactos a las cinco herramientas porque no corren en la máquina del agente. Es la slide 30c otra vez, ahora medida en cinco productos distintos.
Contexto persistente, verificado por lo que se escribe en disco: CLAUDE.md (Claude Code) · AGENTS.md + .cursor/rules/ (Cursor) · AGENTS.md + opencode.json (OpenCode) · GEMINI.md (Gemini) · AGENTS.md (Codex). Equipo mixto: el estándar es el mismo archivo para todos; lo que cambia es quién lo puede hacer cumplir. · ⚠ Esto es proyección verificada, no runtime: Gemini no se ha ejecutado (sin autenticar) y el dispatch de Cursor en el IDE está sin verificar. Lo demás sale de correr el instalador de verdad.
--dry-run contra el harness que elijas, sobre tu repo. Cuenta qué perderías. Cinco minutos de teclado y lo discutimos.
# Cambiad solo --harness. Nunca contra un repo de verdad sin --dry-run. node scripts/install.js --harness gemini --profile empowered --target <repo> --dry-run # Archivos en disco por harness (medidos hoy, no leídos del README): # claude-code 102 · opencode 94 · cursor 87 · gemini 71 · codex 71 # La pregunta no es cuántos archivos pierdes. Es CUÁL de ellos.
Misión 5 · +100 XP · 🧳 Nómada — Bonus: +20 XP si identificas exactamente qué perderías al migrar de harness. · Las cifras que traía este deck (85·75·90·68·69) eran de antes de tocar los adaptadores: caducadas las cinco. Estas son de hoy.
intención → /enrich-us → /new + /ff → /apply → hooks # señal inmediata → /judgment-day # juez independiente → /verify # contra la spec → validadores CI # el último gate → /archive + /commit → PARA
Ocho comandos. No os los aprendáis — los comandos cambian. Aprendeos las cuatro preguntas: ¿cuál es mi señal? ¿llega rápido? ¿es dura o blanda? ¿cuándo paro?
context-monitor.La autonomía no se gana con confianza. Se gana con gates.
El kit instalado en onedev-grid-service con perfil elegido por el equipo · una capability minada y falsada · ocho agentes escritos por vosotros. El lunes: decidid el HOOK_PROFILE del equipo y commiteadlo — es decisión vuestra. Este sprint: una capability con /spec-mine. Este trimestre: los agentes que funcionen, al repo.