Desarrolla con varias IAs, con garantías. Tu agente escribe; Karajan gobierna: método TDD-first, revisión IA-cruzada en cada commit, gates de git — el falso verde es imposible.
Tu agente de IA (Claude Code, Codex, Gemini CLI, Cursor…) escribe el código — Karajan gobierna cómo ocurre. kj instala un método que tu agente sigue en cada tarea (RAG antes de suponer, card primero, tests primero) y lo hace cumplir con gates de git: cada commit exige el veredicto de una IA distinta, los hallazgos de seguridad no los anula nadie, y la rama base solo se mueve por PR. El que hace nunca se califica a sí mismo — y el falso verde es estructuralmente imposible.
El prompt engineering sacaba una buena respuesta de un buen prompt. El context engineering curaba lo que veía el modelo. La frontera de 2026 es el loop engineering: dejas de promptear al agente a mano y diseñas el sistema que lo promptea, lo verifica y decide qué pasa después — hasta que se cumple el objetivo o te lo devuelve a ti. Karajan se construyó alrededor de ese bucle antes de que el término calara:
Separación maker / checker — un coder contra roles independientes de reviewer, tester y security, con Solomon arbitrando los conflictos. El maker nunca corrige su propio trabajo.
Verificación determinista — TDD, tests de aceptación por HU, gates de SonarQube y guardarraíles deterministas. Verificar es tests, no intuición.
La escalera de autonomía L1 → L2 → L3 — el eje interactive | assisted | autonomous (v3.7.0). Informe, luego fixes asistidos, luego kj autorun desatendido — con default interactive, así que tú decides.
Un spine de estado duradero — sesiones, el HU Board, journals, el índice RAG y kj resume mantienen vivo el bucle entre runs.
El caveat que el loop engineering recalca — los bucles desatendidos cometen errores desatendidos — está diseñado de serie: los runs autónomos listan sus defectos residuales, cada historia aterriza tras una PR, y kj-trash hace snapshot de las operaciones destructivas. Lee el mapeo completo de building blocks →
Arranque en una línea
Dile a tu agente: “lee karajancode.com/start.md y haz lo que dice”. Instala el stack completo, detecta si el proyecto es nuevo o existente, activa el entorno — y PARA a esperarte cuando un paso necesita sudo o una cuenta. Instalación →
Tu agente, gobernado
El playbook aterriza en CLAUDE.md, AGENTS.md y GEMINI.md desde una única fuente: RAG primero, card primero (kj hu), TDD, ADRs en git (kj adr). Los briefs de rol (kj brief) dan a tu agente el método destilado de triage, planner, architect, tester, security y audit. Trabaja con tu agente →
Revisión IA-cruzada + gates de git
kj review --staged liga el veredicto de una IA distinta al diff exacto — cambia el código y hay que revisarlo de nuevo. ¿Discrepas? Una tercera IA arbitra (kj solomon); los hallazgos de seguridad no los anula nadie. El gate pre-commit lo convierte en ley. Los gates →
RAG sobre tu código
Se construye al instalar y se refresca solo: kj rag query responde qué hace el código para que ningún agente adivine. En proyectos existentes, kj onboard produce un Architecture Brief antes de tocar nada.
Ecosistema que se repara solo
¿Tu agente choca con un bug de kj? kj report-issue lo diagnostica y lo sube — sanitizado, deduplicado y solo con tu aprobación. Los fixes vuelven a todos. Referencia de comandos →
Modo headless
El pipeline multiagente clásico sigue vivo para CI y automatización: kj run orquesta roles coder/reviewer/tester en subprocesos sin humano delante, con los mismos gates. Modo headless →
Torneo gobernado (v4.15)
Una tarea, N coders en carriles worktree aislados: kj tournament reparte, --score construye un scoreboard determinista sin LLM, un juez cross-AI sin conflicto de interés elige al ganador, y --crown lo corona por el gate normal de review — ganar da candidatura, no bypass.
kj review --third-party --json permite a un agente revisor revisar la PR de otra persona con el reviewer de kj y las reglas del repo destino, y devuelve un único JSON con el veredicto, los hallazgos y los requisitos de la PR (tamaño, commits, tests, secretos, datos personales, dependencias arriesgadas, semgrep, Sonar), sin las gates del trabajo propio y sin guardar veredicto. El Sentinel deja de leer shell donde ya decide un punto de control (actos humanos, identidad, push), pre-push comprueba la identidad de cada commit que sube, y el bloqueo del Steward también para un commit.
El coder de cada HU corre con el modelo y la intensidad que pide su tramo (trivial, estándar o deep) y sube al más capaz cuando una iteración falla; un modelo que hayas elegido siempre gana y el reviewer nunca se enruta. kj plan rellena el modelo de cada HU a partir de su tramo, el HU Board puede cambiarlo y kj report dice cuántas HUs se enrutaron y cuántas subieron. Las reviews en paralelo en una misma máquina comparten plazas de sonar-scanner, un reviewer ya no bloquea una funcionalidad de una plataforma que simplemente no conoce, y kj handoff add pasa el Sentinel.
v4.54.0: las skills llegan a los prompts y tienes una ventana de tareas
Las skills que encajan con la tarea (primero las del proyecto, luego las del catálogo local) llegan al coder y al reviewer, hasta 3 por rol, y al arrancar una HU se nombran. kj handoff watch muestra en otra terminal lo que solo puedes hacer tú (publicar, sellar, ejecutar un script), con fecha y motivo, fuera del scroll de la sesión. kj env install conecta el MCP de qmd para que el agente le pregunte por documentos, notas, ADRs y planes, y al RAG por el código. Y rag-first cuenta una respuesta de kj_rag_query que llega cortada.
La siguiente PR de una card partida en PRs apiladas se puede subir y abrir antes de mover la card de la primera, un push ya no contradice la respuesta que board-sync acaba de darle, un bloqueo que kj no pudo comprobar dice por qué (casi siempre otra cuenta de gh activa), y un título de card o un mensaje de commit que solo menciona sellar el harness o enrolar el móvil se lee como texto.
kj init ofrece enrolar tu móvil, kj doctor dice claro qué se rechaza sin él, y sin ningún móvil una persona en la terminal puede bajar el nivel. kj review --publish-pr deja en la PR los veredictos de la otra IA como una review de GitHub, kj review avisa de dependencias publicadas hace horas, kj harden dice cómo hacer obligatorios los checks del método, y arrancar una card la reserva para un equipo. Cada HU registra ahora el modelo y el coste de su coder, y kj report los suma por modelo; además sale de la descomposición con su tramo, y kj run --profile frugal|standard|deep elige los modelos. Un plan dice si cada cambio amplía, regenera o reconstruye código existente, y regenerar exige una licencia según el mutation score del módulo. La cuarentena de dependencias puede bloquear, kj check avisa de cuándo toca auditar, y los patrones de prompt-injection pasan a un catálogo que lee toda la familia.
Ninguna versión se publica sin la batería de escenarios en verde, y la CI la ejecuta en cada PR. kj worktree prune retira los carriles de kj que están demostrablemente abandonados, una corrección del revisor se nombra como el método funcionando, y el veredicto de un revisor claude se lee aunque su respuesta empiece con eventos de hooks.
v4.51.1: un umbral dicho en palabras que cambia de verdad
kj policy add "las PRs pueden tener hasta 500 líneas" cambia ahora el límite de líneas que la política ya tiene, en vez de añadir otro a su lado que el más estricto seguía anulando.
Un agente no podía escribir tu política, pero un cambio que llegara igualmente pasaba el commit y la CI, juzgado por la misma política que traía. Ahora un cambio en policy.yml o rules.yml se rechaza allí donde se usa (commit, CI y release) hasta que lo sellas con kj harden --commit, firmado desde tu móvil.
v4.50.0: un tablero para kj y una réplica en el tuyo
Con el Planning Game o un tablero externo como Jira o Linear, kj se apartaba y no mantenía HU Board. Ahora el HU Board es siempre el tablero de kj: cada card vive ahí, kj hu add --ref <id> enlaza su réplica en tu tracker y card-first reconoce la rama por cualquiera de los dos ids.
Una consulta al RAG que nombra un fichero indexado devuelve ahora ese fichero primero, así que el gate rag-first se abre para una página recién indexada que el ranking dejaba fuera de los primeros resultados, como una página .astro en un índice grande. Se resuelven tres avisos altos o críticos de dependencias con versiones parcheadas dentro de los rangos existentes.
kj review --staged --task-file entrega ahora el fichero al reviewer: la evidencia que pasaba una sesión (una documentación oficial, una especificación) se perdía, y el reviewer seguía rechazando lo que nunca vio. El pre-gate de Sonar encuentra también el token que kj guardó en su home, así que un token válido ya no bloquea cada commit con código.
claude recibe ahora el prompt por stdin, así que una revisión de seguridad sobre un diff grande ya no falla con E2BIG, y los ficheros generados como los lockfiles entran en los prompts del reviewer y de Solomon como una línea de resumen, de modo que el reviewer ve los cambios reales. kj env install commitea también el .mcp.json que configura, así que un clon nuevo conserva el RAG como herramienta nativa.
v4.49.2: runs de plan que implementan su HU y un Sentinel que lee comandos
Un run de plan ya no hace el triage del encargo original del plan: generaba otras HUs que se ejecutaban en lugar de las del plan, perdía sus Gherkin y podía saltarse el coder y aprobar un diff vacío. Una HU de código ya no se aprueba con la suite del proyecto en rojo, y la primera release de un repo recién preparado ya no se bloquea por los ficheros que instaló su propio setup. El Sentinel deja de reaccionar a palabras dentro de texto entrecomillado, acepta el kj rag query que él mismo recomienda y ya no toma la ruta de un fichero de cuerpo por una atribución. El E2BIG pasa enseguida al siguiente proveedor, los rangos de versión ya no son secretos y el audit se queda con las issues de Sonar del proyecto actual.
v4.49.1: runs de plan que commitean y un presupuesto de tamaño que no pregunta
kj run --plan se paraba antes de commitear cada HU, bloqueado por sus propios gates de card-first y de veredicto, volvía a revisar el spec del plan y nunca le pasaba al coder el contexto de dominio; las tres cosas están arregladas, y el contexto de dominio llega ahora al coder en todos los runs. El tamaño de PR tiene dos tramos: unas 150 líneas es lo ideal, hasta 200 se permite sin preguntar y por encima se parte. kj harden --report nombra ahora el Sentinel y los git hooks cuando faltan, y kj harden ya no pide sellar sin nada que sellar.
v4.49.0: planes que convergen, gates que dejan de gritarle a kj
Cinco avisos de campo de una misma sesión contra kj plan: el bucle de arreglo archivaba HUs con un estado que validate rechazaba, solo sabía añadir dependencias y podía cerrar un ciclo que luego llegaba al run. Ahora las HUs archivadas validan y las sustitutas heredan sus aristas, el fixer quita dependencias y recorta alcances cuando el feedback lo pide, y un ciclo se nombra y para el run. El gate de privacidad ya no toma un id de plan por una tarjeta, pr-size deja fuera el plan compartido, el catálogo de skills ya no mete fixtures de test en el proyecto y las guardas que CI no ve las avala la firma del padrón.
v4.48.3: el móvil respalda el sello de un kj anterior
Tras actualizar kj, kj release check negaba el hook que un humano había sellado con la versión anterior, porque lo recomputa con la plantilla nueva. Un sello de otra versión lo respalda ahora la firma del móvil sobre esos bytes; sin firma sigue negado y dice que hay que re-sellar. Incluye también la 4.48.2: el HU Board arranca en una instalación global.
v4.48.2: el HU Board arranca en una instalación global
El tablero viaja dentro del paquete principal, y tres de sus dependencias (ws, @xterm/xterm, node-pty) solo las declaraba su propio paquete, así que una instalación global no podía arrancarlo. Ahora las declara el paquete principal, node-pty como opcional porque es nativa y solo la usa la terminal embebida.
El workflow de calidad corre en la raíz del lenguaje cuando la app vive en un subdirectorio, kj rag query ya no reindexa el repo entero antes de responder cuando el índice es antiguo, y el rag-first deja editar un barrel (index.ts, __init__.py, mod.rs) en cuanto el RAG ha respondido sobre su carpeta.
El agente ya no pide al humano por el chat lo que kj le negó. Cada deny del Sentinel deja un registro con las palabras del propio gate, y kj handoff add registra un encargo solo contra ese registro, así que el porqué es del gate, nunca del agente; kj handoff list|show lo leen por identificador. Además: sacar del índice un fichero de runtime heredado ya no exige --no-verify, y el agente puede reportar con kj report-issue, justo el comando al que lo manda el Sentinel.
v4.47.0: el nivel que protege a quien no sabe que existe el riesgo
Seguridad máxima por defecto: todo acto del catálogo (sellar el supervisor, aprobar reglas, enrolar otro móvil, bajar el nivel) se firma desde el móvil sobre los bytes exactos y sin móvil se niega; kj security show|normal|max lee y cambia el nivel, y bajarlo es un acto firmado que dice qué se hace y por qué. Un móvil perdido se sustituye con el código de recuperación de un solo uso que se enseña al primer enrolamiento, nunca reinstalando: el código se gasta al usarlo, se emite otro y el móvil perdido queda revocado. CI juzga cada cambio del padrón de móviles. Y las reglas del relé, que desde 4.46 rechazaban todos los sellos con 403, admiten lo que la página de firma enseña.
“Veo ‘sentinel’, pero ¿qué estoy firmando? me puedes estar engañando”. La petición de firma lleva ahora qué cambia, fichero a fichero: nuevo, modificado o borrado, líneas añadidas y quitadas, un resumen de una línea, el diff (recortado y pasado por el escaneo de privacidad), la rama y qué la generó. La página habla el idioma del navegador, español o inglés, pliega el diff bajo cada fichero y dice que los sha256 que muestra son lo que la firma garantiza. Además: un catálogo cerrado de actos humanos con un solo mecanismo y un test de arquitectura que lo vigila (enrolar el móvil ejecuta las cuatro capas por sí mismo), y los criterios de la card llegan a las HUs al descomponer, para que ninguno se quede sin HU.
v4.45.0: aprobado significa que los criterios de la card están en el diff
Un run terminó aprobado sin implementar ninguno de los tres criterios de aceptación de la card. Con card leída, una IA distinta del coder lee ahora cada criterio contra el diff antes de que el run diga aprobado y contesta uno a uno: cubierto, con la evidencia, o no. Un criterio sin cubrir vuelve al coder; en el camino de HUs el resultado dice approved:false con la lista; un juez sin veredicto legible nunca concede una aprobación. Además: kj harden tras subir de versión ya no se bloquea contra el sello, y kj update nunca degrada un kj enlazado desde su árbol fuente.
Seis reportes de campo de un mismo día sobre un proyecto recién creado: un run aprobado sin push y sin PR y sin decirlo, cinco commits con dos identidades, ramas con nombre de HUs inventadas, una card que no se pudo leer y un pipeline que siguió sin ella, y un agente con kj instalado y nunca endurecido rodeando cada gate a mano. Ahora el push o la PR que falla viaja en el resultado del run con su remedio (el rechazo por el scope workflow nombra el arreglo exacto); la identidad git se resuelve una vez y cada commit del run la lleva; con card la rama es feat/<CARD-ID>-<slug> en los dos caminos; una card que no se puede leer para el run antes de empezar; un host Claude sin el harness del Sentinel también lo para, y una issue para karajan-code sale por kj report-issue. La primera sesión de cada versión invita a enrolar el móvil (ADR 0018).
Un run aprobó un paso con el reviewer desactivado, sin implementación y con un test en rojo, stageó 22 ficheros del harness en el commit y commiteó 960 líneas donde el plan permitía 150. Ahora una tarea simple conserva su review cruzada, y sin review el pipeline no sella veredicto ni commitea; con TDD la suite de tests del proyecto corre en cada iteración y una suite en rojo vuelve al coder; el presupuesto de la PR se aplica antes del commit, con el cálculo de kj pr-size; y el commit lleva solo lo que el run cambió, por rutas, con el veredicto atado a ese diff exacto. El Sentinel deniega además git add -A y stagear ficheros de runtime del agente, el hook pre-commit los rechaza lleguen como lleguen, y una pregunta que no cambiaba nada (documentos de dominio) ya no se hace.
Sesiones que trabajaban en otros proyectos reportaron en un día lo que el método les hacía mal, y todo está arreglado. Una revisión aprobada se leía como rechazo porque el revisor envolvía su veredicto en un sobre: ahora lo que kj no puede leer es un fallo del revisor, que se reintenta y se guarda, nunca un defecto que se le cuelga al coder. El ledger del RAG comparaba rutas como texto, así que un índice construido a través de un workspace con symlink descartaba todos los hits y rag-first denegaba cada edición: ahora compara rutas reales y nombra lo que descarta. El coder ya no commitea antes de la review, un fichero temporal fuera del repo no es una fuente, Sonar salta en una línea un repo sin src/, los pipelines de lectura ya no disparan el Sentinel, un timeout del preflight es un aviso, kj status ve un run muerto y kj harden commitea el contrato que genera.
En un repositorio con historia, kj generó 28 ficheros de contrato y se los dejó al agente, cuyas propias reglas de tamaño de PR prohíben ese commit. Ahora kj env install y kj bootstrap commitean lo que acaban de generar: solo esos ficheros, nunca lo que tenías sucio o staged, y nunca en la rama base, donde kj nombra los ficheros y cómo commitearlos en una rama. Además: una regla compilada puede decir por qué está compilada así, el revisor de una propuesta bloquea solo por debilidad material, y un rechazo del revisor ya no veta tu aprobación: sus objeciones van primero, y decides tú.
Las reglas que escribes en tus MD dejan de depender de que el agente las recuerde. kj las lee, compila cada una en una condición sobre una llamada a herramienta y comprueba cada llamada antes de ejecutarse, también las de servidores MCP; un deny nombra la regla y el MD del que sale. La compilación la apruebas tú desde tu terminal, después de que una IA distinta la haya revisado regla a regla, y lo que lees va ordenado por lo que puede hacer daño. Las reglas que salen de tus ficheros privados quedan fuera de git. Además: CI verifica la firma del móvil de un sello contra el padrón versionado, un ADR nuevo nace como propuesto, y kj audit trata una web estática como el frontend que es.
Una auditoría contó quince escapes KJ_ALLOW_*, y el agente podía activarlos todos anteponiéndolos a un comando. El ADR 0015 los retira, del Sentinel, de kj review y de los hooks de git: un gate que necesita un escape es un gate a corregir. Cada decisión que de verdad es del proyecto tiene su cauce fuera de la sesión, desde una PR a policy.yml hasta la etiqueta large-pr-justified. Además: la ruta de un body-file seguida de ;, la posición de solomon desde un fichero, restaurar un fichero que la propia sesión borró, ai-trash guardando el trabajo sin commitear y un pregate de Sonar que leía el análisis anterior.
Un coder bloqueado por rag-first escribió el mismo cambio con heredocs de shell y descartó con git checkout una línea sin commitear del usuario. Ahora el repo se escribe solo con Edit y Write, y una sesión no puede tirar trabajo que no hizo. Los guards del Sentinel salen de las plantillas a módulos reales con tests unitarios. Las reglas del método le llegan al agente en el momento de la acción y vuelven tras cada compactación. Y una sesión ya no cambia las políticas que la gobiernan: Karajan gobierna, y cada denegación lo dice.
El móvil firma ahora todo lo que enseña, incluida la versión de kj y su propia caducidad, así que una aprobación no puede durar más de lo que la persona vio. Una limpieza que borra código y corrige los comentarios que dejaba mintiendo ya no se toma por código nuevo que pide tests. Un .ragignore versionado dice qué se queda fuera del RAG. Y los dos límites que solo aparecían cuando un gate bloqueaba, el tamaño de una PR y el formato del mensaje de commit, se dicen ahora mientras se escribe: kj pr-size mide la rama con el mismo cálculo que el CI, y el hook de commit rechaza lo que el CI rechazaría.
Todos los proyectos de una máquina compartían un solo almacén del RAG y una sola vista del board, así que una consulta desde un repo podía devolver código de otro, y el buscador del propio board hacía justo eso. Ahora cada proyecto guarda su índice en su propio .karajan/rag.db, y kj rag migrate lo mueve ahí desde el almacén compartido sin volver a calcular nada. El board arranca solo, como Sonar, y kj lo abre en la vista de ese proyecto y nada más, /p/<slug>, donde la configuración, la terminal integrada y el buscador actúan sobre ese proyecto y ningún otro. El canon que trae kj sigue siendo común, en su propio almacén, con kj rag query --library. El índice deja además de depender de una lista de lenguajes: entra cualquier fichero de texto que tu proyecto versione, y lo que se queda fuera (binarios, generados, secretos) se dice con su motivo. Y en un repo gestionado con Rulesync, kj escribe sus reglas en .rulesync/rules/karajan.md, así que rulesync generate las reparte en vez de borrarlas.
Nueve arreglos en un día, casi todos reportados por un proyecto hermano de la misma máquina. El quality gate vuelve a correr dentro de un carril: el plugin SCM del scanner no sabía abrir un worktree enlazado, así que todo cambio hecho como el método manda pasaba sin gate y sin un rojo que lo dijera. El aviso de integridad del harness nombra ahora el kj que juzga, su versión y si es un árbol de desarrollo enlazado, porque una sesión se había montado el ritual de ejecutar kj harden veinte veces al día sin llegar a saber por qué. Y el guard de reescritura de JSON deja de vigilar ficheros fuera del repositorio, tras ocho rondas de review en las que cada una encontró una forma real de colar un comando.
Catorce issues llevaban abiertas, algunas meses, y todas decían lo mismo: un gate que grita en falso enseña a saltarse los gates. Un prefijo de caché de PHP llamado EXPERIMENTS_HANDOFF_TOKENS_NAMESPACE era un hallazgo crítico de clave en duro, porque dos reglas de credenciales acusan por el NOMBRE del identificador y no miran el valor. Un fichero .astro no puede estar en el índice del RAG, y aun así rag-first exigía que el RAG hubiera respondido sobre ese fichero exacto. Un .gitignore versionado se reescribía sin preguntar. El CLI de un provider rechazaba la combinación de flags que kj le pasa, y esos flags eran una constante del código. En todos el apaño era el mismo: una variable de escape que apaga la protección entera y acaba pegada en todos los comandos hasta que nadie recuerda qué silenció. Así que ahora, donde kj no puede saber, lo declaras tú en tu configuración versionada, donde se revisa como cualquier otra línea: guards.output.non_secret_assignments, agents.<nombre>.task_args, board.unverifiable. Y donde kj sí puede saber, computa el hecho: kj rag covers <fichero> responde si el índice puede contener ese fichero, con un remedio distinto para cada una de cuatro razones.
Seis gates bloqueaban justo la acción que los habría puesto en verde. El release check quería la landing desplegada y el guard trataba ese despliegue como una publicación, así que la única salida era apagar el gate entero. board-sync se negaba a dejar pasar la segunda mitad de una card después de haber aceptado que las cards se parten. El supervisor leía su propio desarrollo como manipulación, y el comando con el que se desbloquea destruía el sello que lo hacía innecesario. Un */ suelto se llevó al evaluador de policy y el guard denegó Edit, Write y Bash a la vez, que es exactamente lo que hacía falta para arreglar el fichero. Ahora un gate distingue un comando que consume su estado en rojo de uno que lo repara, siempre sobre un hecho comprobable: un item que declara remedied_by, otra PR abierta de la card, un hash que un humano selló, el fichero que nombra un diagnóstico. Donde falta el hecho sigue bloqueando, cada levantamiento se dice en voz alta, y el Stop gate queda intacto.
Tú eliges quién escribe y quién revisa, y hasta ahora esa elección solo valía dentro de kj run. El panel viaja ya con el playbook que todo anfitrión lee al empezar, y kj code invoca a TU coder con la card, sus criterios, la frontera del proyecto y lo que el RAG responde sobre la tarea. Debajo, la cadena declarada de modelos queda por fin conectada: su esquema llevaba en la config desde febrero y nadie construyó jamás la pieza intermedia, mientras cinco agentes resolvían un modelo retirado en silencio y por delante de lo que tú hubieras declarado. Ahora los agentes devuelven el fallo, decide tu cadena, el default del proveedor es su cola y no un primer paso escondido, y una cadena agotada dice qué se probó y en qué orden. kj además recuerda un modelo retirado para que la siguiente ejecución no vuelva a pagarlo, sin tocarte el pin. Y tres informes de campo cerraron la otra mitad: lo que kj escribe en un proyecto habla ya el lenguaje de ese proyecto, en vez de pedirle const a un repo de Python.
kj bootstrap lleva de una carpeta vacía a un proyecto bajo el método con un solo mando, en el orden que funciona, y hace él el commit del contrato en vez de dejarte pelear con los gates que acabas de instalar. kj doctor y kj check ya miran también el repositorio, y nombran cada síntoma con el mando literal que lo repara: un harness que no gobierna nada, un contrato que ningún clon heredaría, un clon sin identidad declarada. Y llegaron las dos pruebas que faltaban: el proyecto declara si de verdad arranca, así que un árbol que ya venía roto se dice ANTES de implementar en vez de achacárselo al cambio siguiente, y lo que una persona VE deja de darse por bueno con la suite verde: el recorrido viaja en el veredicto junto a los bloques de sonar y de RAG, avisando y sin bloquear, porque el navegador no captura los modales nativos y un gate que salta a menudo enseña a saltárselo.
Patch. kj privacy scan bloqueaba cada despliegue de la landing por la clave web de Firebase que la página de firma lleva en el navegador, una clave pública por diseño: sigue bloqueando, porque la forma por sí sola no dice qué clave de Google es, pero ahora nombra la salida declarada y lo que de verdad la protege. El test inestable de runflow-events resultó no ser un timeout: sin transcripción del coder, el detector marcaba como fuga toda entrada nueva en $HOME, así que una escritura de otro test mataba la ejecución y la reintentaba. Atribución y severidad pasan a ser cosas distintas. Y el sello del supervisor, atascado desde la 4.28.1 porque su procedencia guardaba una ruta cruda que el CI no podía reproducir, se regeneró sobre la 4.31.0 y entró, lo que destapó la última pieza: el chequeo de release era el único sitio que no aplicaba el levantamiento de procedencia, así que la primera versión cortada tras un sello quedaba denegada por ese mismo sello.
v4.31.0 — el arranque en frío deja de exigir forzar
Empezar un proyecto en una carpeta vacía acababa con el usuario eligiendo entre forzar un gate y rendirse. Un aviso de campo (issue #1753) abrió el mapa del camino entero: nueve gates disparándose, varios precisamente porque el repositorio se había levantado a mano. La épica KJC-PCS-0088 convierte el arranque en una fase con reglas propias, definida por un hecho comprobable (el repo no tiene ningún commit) y terminada en el primero. El Stop gate deja de exigir cobertura sobre un árbol que no existe, el commit del contrato pasa porque no hay de dónde ramificar, kj init crea el repositorio en vez de saltarse el harness y darse por terminado, una identidad sin declarar bloquea la instalación en lugar de cada git posterior, kj hu add produce una referencia que el gate de cards acepta, rag-first se aparta mientras no hay nada indexado, y kj go arranca en una carpeta vacía. En sentido contrario, un agujero cerrado: un harness ausente ahora bloquea el gate del RAG en vez de abrirlo, así que no hardenar deja de ser la forma cómoda de esquivarlo.
La sesión no toca lo que no ha consultado (ADR 0010, épica KJC-PCS-0086). El Sentinel lleva un registro por sesión de cada consulta al RAG y de las fuentes que devolvió, y rechaza editar una fuente sobre la que la sesión nunca preguntó; kj review --staged rechaza código que el registro no cubre antes de gastar un token del revisor, le entrega los gemelos que el RAG devolvió y el diff no toca, y guarda un bloque rag en el veredicto atado al hash del diff; kj review --check lo exige, tratando su modo como afirmación, nunca como autorización. kj check falla con fuentes que el índice no ve. El gate destapó que la aprobación de Solomon perdía la evidencia de Sonar y del RAG y rechazaba todo commit arbitrado desde 4.29.0: arreglado. Además: kj audit informa de claves env/config resueltas con reglas distintas en distintos módulos, verify-pack ejercita el servidor MCP del tarball por stdio, un test de paridad ata cada parámetro del schema MCP a un handler que lo lee, y dos arreglos del harness (home en instalaciones linkadas, workflows idénticos a prettier).
Patch, reportado minutos después de publicar 4.29.0 (#1730): el postinstall volvía a registrar karajan-mcp con un home dentro del paquete npm (borrado en cada reinstalación, nunca donde kj init guarda kj.config.yml), bajo el nombre deprecado KJ_HOME, y sustituía la entrada entera, así que el KARAJAN_HOME del usuario se perdía y todas las tools MCP fallaban con Config file not found tras cada actualización. El home se resuelve ahora desde KARAJAN_HOME, luego lo que la entrada ya llevaba, luego el registro de instancias y por último ~/.karajan; la entrada conserva todas las env keys del usuario, y las configs de Claude y Codex escriben KARAJAN_HOME.
Minor en la que el análisis estático deja de ser disciplina y pasa a ser un gate de git con los mismos dientes que el veredicto cross-AI (KJC-TSK-0838, tras un caso real: cuatro PRs llegaron a main con sonarqube.enabled: false y nada las paró). El resultado de Sonar viaja ahora dentro del registro del veredicto, atado al hash exacto del diff, y el pre-commit lo exige; la cobertura se prueba contra el índice de ficheros del propio scanner, así que una fuente staged que el análisis no vio bloquea. Sonar deshabilitado, caído o parcial rechaza cualquier diff con código (solo docs pasa), ninguna variable de entorno lo levanta, y la única excepción es un kj policy grant humano y con caducidad. Los monorepos escanean cada fichero desde su sonar-project.properties más cercano; kj doctor marca enabled: false como defecto de configuración; el informe del método dice qué veredictos están probados y cuáles no. Junto a ello, tres arreglos del MCP reportados desde el campo la misma semana: las herramientas directas aceptan taskFile igual que kj_run (#1723), kjHome llega al bootstrap gate y a la carga de config sobre karajan-core 1.5.0 sin tocar el entorno del proceso (#1722), y kj_rag_query acota la búsqueda al proyecto en vez de devolver chunks de cualquier otro indexado (#1713).
Patch: el entorno deja de dejar rastro. El pre-commit que genera kj harden ya no se autodetecta como atribución IA en el commit de bootstrap que versiona los hooks del supervisor (contienen el patrón del guard por diseño; #1667). La verificación ya no ensucia ~/.claude.json — el postinstall del tarball registraba karajan-mcp en una ruta de instalación temporal /tmp, un CONNECTION_CLOSED en cada sesión; verify corre ahora con un HOME aislado (#1666). kj doctor gana un check que detecta Y auto-repara una ruta muerta de karajan-mcp. Y el almacén de veredictos se limpia solo: .karajan/reviews se recolecta de forma oportunista en cada review, con kj review --prune para un barrido manual.
Patch: una ejecución del coder headless terminó su subtarea real y después descarriló inventándose un bootstrap de «montar la estructura del proyecto» (un worktree de verify rebelde, un .gitignore genérico multi-stack). Dos guards a nivel de plantilla lo cierran — el Sentinel deniega ya git worktree add crudo desde una sesión (el cauce es kj worktree start|done), y el prompt del coder ancla el alcance: proyecto existente, implementa solo la HU actual, nunca andamiaje ni bootstrap.
Minor en la que la última capa del sello del supervisor pasa a ser una firma desde tu móvil (KJC-TSK-0822, la respuesta que elegiste a «prueba que no puedes, nunca»): una página firmante genera un par Ed25519 cuya mitad privada jamás sale del teléfono; kj harden --commit pinta un QR de desafío, el móvil muestra en claro qué se sella y un toque lo firma, y kj lo verifica contra la clave pública enrolada. Con el móvil enrolado la firma es obligatoria — la llave que aprueba un sello del supervisor sencillamente no vive en la máquina que el agente controla, verificado de punta a punta contra producción. Enrolar esa clave es a su vez un acto humano que la sesión no puede ejecutar. Junto a ello, la atribución a IA queda prohibida por reglas deterministas en toda superficie — contenido del commit, cuerpo y título de la PR, y todo gh que publica texto — tras un caso real en el que un default del harness coló pies de atribución por delante de un guard que solo miraba los mensajes de commit. Y dos guards de sesión nacidos de reportes de campo: el Sentinel deniega en seco git worktree remove del árbol principal del repo (una ejecución descarrilada lo intentó en bucle), y enrolar la clave del móvil es solo humano. El único residual honesto — verificar la firma en CI, server-side, para que nunca dependa de que kj corra sin parchear — queda planificado.
Minor nacida de una orden del usuario que merece enmarcarse: «quiero probar que realmente NO PUEDES — ni aunque yo te lo ordene». La única operación que la clase de seguridad niega con razón incluso al autor del sistema — versionar lo que kj harden regenera del supervisor — gana su cauce sancionado (ADR 0009): kj harden --commit es un acto humano. Calcula el drift, escribe la procedencia versionada (versión de kj, parámetros de generación, sha256 por fichero), sella el acto en el acta hash-encadenada y commitea quirúrgicamente. Los gates solo alzan un diff de supervisor si coincide con la procedencia sellada Y con el render canónico que kj recompute — una coma manual sigue denegada, así que ni una falsificación exitosa podría debilitar a los guardias. Y la parte «humano» se construyó adversarialmente, con cuatro capas: el Sentinel deniega el comando en sesión (se autoprobó bloqueando a la sesión de su propio autor, dos veces); sin terminal real no hay trato; un pty falsificado sigue DESCENDIENDO del proceso del agente y /proc lo cuenta; y cuando un doble fork huérfano con prompts a ciegas atravesó de verdad las capas en el sandbox, se añadió el nonce aleatorio que hay que teclear en la tty real de control del proceso. Batería final: cinco clases de ataque, cero commits — con el residual honesto documentado, no escondido.
Minor en la que el gobierno se explica a sí mismo y el tablero se gana de vuelta la confianza del usuario. Las excepciones ganan ámbito declarado — proyecto o global (toda la máquina) — con procedencia FÍSICA: el origen se estampa según el almacén del que se leyó cada registro, así que no se puede falsear editando texto; una concesión global exige caducidad, lo security sigue siendo inexentable en todos los ámbitos, y kj policy report nombra el ámbito de cada concesión. Cada mensaje del Sentinel se firma como karajan y enlaza su propia documentación: una página nueva explica gate por gate qué protege cada uno de los 12 y qué significa cada escape KJ_ALLOW_* — un guardarraíl que no entiendes es uno que acabas desactivando. Y el HU-Board obedece dos órdenes directas del usuario: los nombres de proyecto derivan del repo y son ÚNICOS (un duplicado registra un error alto, nunca un gemelo en el dashboard), y la navegación se parte en dos niveles honestos — botones genéricos arriba, las vistas del proyecto cargado en su propia barra con su nombre, sin el select que confundía. Además: los workflows de CI gestionados por kj quedan versionados (con un fix fail-loud cazado por el revisor cruzado a nivel de plantilla) y el gate de LOC corregido para los docs compilados del monorepo.
Minor en la que el viaje del maggle termina en UNA ventana del navegador. El ADR 0008 se aceptó y salió el mismo día: kj go --window abre el tablero con la conversación del agente viviendo DENTRO — no un chat que se le parece, la terminal REAL del agente (un pty puenteado por un WebSocket solo-loopback, pintado con xterm), de modo que el harness sigue siendo exactamente lo que el Sentinel garantiza: el proceso ES el agente interactivo, con sus hooks intactos. La superficie está cerrada por construcción: los agentes salen de un catálogo cerrado (por la red viaja qué agente, nunca un comando), un token de sesión de 128 bits se entrega solo detrás de la auth del tablero, se compara en tiempo constante y viaja en el WebSocket como subprotocolo — porque las URLs acaban en logs y los subprotocolos no. Cerrar el panel no mata la sesión (reconectar reproduce el buffer); terminarla sí, limpiamente. La fase 1 (terminal + tablero) sigue siendo el default — una adición, nunca un reemplazo. El tablero además aprende que la identidad de un proyecto es su repo, no su ruta: los carriles de worktree ya no registran el mismo repo como una docena de proyectos homónimos. Publicada junto a sus hermanas kaRAGan 1.7.0 — Vertex migrado al Google Gen AI SDK (el viejo ya pasó su fecha de retirada), fallbacks de entorno para región y modelo, y globs exclude que dejan los secretos fuera del corpus antes de leer un solo byte — y kaWATCHan 0.8.0, cuya config ya declara grupos de repos, tiers DORA y reglas de sensibilidad de docs, validado estricto. Las dos moldeadas por informes de campo de un despliegue real, hasta una sonda en vivo contra la API real de Vertex desde la instancia que lo corre en Europa.
Minor en la que Karajan abre la puerta a quien no ha usado una terminal en su vida. kj go: UN comando que detecta el agente instalado (Claude Code o Codex — pregunta solo cuando hay dos), prepara el proyecto en silencio la primera vez, abre el tablero al lado, y deja a la persona dentro de una conversación que ya sigue el método — hablando en llano, diciendo antes de hacer, sin volcar jamás un error crudo. Lo que no se puede ocultar se dice con honestidad: sin agente instalado aparecen los comandos exactos de instalación y login, porque la cuenta es suya y kj jamás toca credenciales. Los instaladores terminan ahora con exactamente una instrucción — Listo. Ahora escribe: kj go — y el tablero que kj go abre se pinta en modo maggle: columnas Por hacer / En marcha / Hecho, la navegación plegada a Tablero | Proyectos | Más (con la vuelta al modo experto), un lanzador que lidera con «Pedir trabajo nuevo» y la promesa clara de qué va a pasar antes de que pase, la actividad sin terminal, y errores que siempre llevan titular en llano y paso siguiente — el stacktrace plegado como detalle técnico, nunca el mensaje entero. Un desarrollador que abre el tablero directamente no nota ningún cambio. La ventana única (la terminal REAL del agente embebida en el board vía pty, conservando intactos los hooks del Sentinel — un chat propio sobre SDK se evaluó y se descartó precisamente porque cambiaría el harness garantizado por estética) queda propuesta como ADR 0008: nada se implementa hasta que se acepte. Además, los dos fixes de la campaña de validación en campo de GREBLA: el detector de fantasmas E2E ya ve labels interpolados — en Lit el caso habitual, no la excepción — y un hallazgo fantasma apunta al fichero y línea del TEST, con el trozo muerto viajando aparte como sourceLine.
Minor en la que Karajan aprende a gobernar el ESTADO de un proyecto, no solo sus actos — porque la degradación ocurre precisamente en los días en los que nadie mira. Sale entero el Karajan Steward: cada garantía declarada responde UNA de cuatro cosas — ok, rota, desconocida (la evidencia caducó → refrescar) y no observable (nunca hubo dónde mirar → instrumentar), las dos respuestas honestas cuya ausencia dejó degradarse durante semanas a un proyecto real tras una fachada verde. kj steward sweep deja el veredicto versionado EN el repo (memoria compartida, nunca el registro de una máquina), sella cada barrido en la cadena de decisiones, y cardea cada rotura como trabajo PROPUESTO — evidencia, desde cuándo, y un plan de remedio que nada ejecuta sin revisión; el Sentinel dice lo roto al empezar a trabajar, una vez por sesión e imposible de ignorar, y bloquea casi nunca (solo seguridad y principal en rojo persistente, solo donde el proyecto lo adoptó). La cobertura fantasma gana sus dos detectores — grafo de llamadas para unitarios y CRUCE DE LITERALES para E2E, el caso que un grafo no ve: un spec buscando un aria-label que solo existía dentro de un método inalcanzable. Con ella aterriza la épica de credibilidad entera: alcanzabilidad de miembros dentro de un perímetro validado en campo con slots static/instancia y campos de constructor, informes de código muerto encabezados por la DERIVADA, diffs que solo borran sin deber tests, sonar vetando solo las líneas que la PR añade, presupuestos generados que ignoran lockfiles, y un escaneo de privacidad que sabe que un SHA de git no es un teléfono. Las afirmaciones con fuente llegan a los artefactos escritos: un cuerpo de PR con un dato desmentido por su propia fuente se rechaza antes de que la PR exista. Además: una contribución externa de seguridad — el token del HU Board comparado en tiempo constante (gracias, @ofri-peretz) — y tres fixes de campo: el escáner de Sonar respeta el sonar-project.properties del repo, kj board ya no arranca un servidor que el config mandó apagar, y las rutas de Windows llegan a ~/.codex/config.toml como TOML válido.
Minor en la que la familia gana su pieza más privilegiada y el método aprende a dudar de la propia IA. Nace la Karajan Console (@karajan-family/console, publicada 0.1.0 → 0.3.0 durante este ciclo): la consola web de administración de una instancia de la familia — salud de los corpus, accesos de personas como el binding IAM real del servicio, operaciones como runs de workflow con GitHub App, todo sellado en una cadena de auditoría hash-encadenada, con página estática sin build y dos proveedores de identidad: Google Sign-In, o Identity-Aware Proxy provisionado entero por terraform — y la consola verifica la aserción incluso detrás de IAP, porque una segunda capa que se fía de la primera es decoración. Guiada por una instancia real desde el primer día: sus informes de campo arreglaron una carrera de concurrencia en la cadena de auditoría y moldearon las notas de despliegue. Y afirmaciones con fuente (ADR aceptado): el transcript es el registro de fuentes, kj claims check cruza cada dato duro que la IA afirma contra lo que de verdad se ejecutó — respaldado, sin respaldo, o desmentido por su propia fuente, que es una alucinación probada. Además: un guard para un bug que JavaScript se niega a contar (un miembro de clase declarado dos veces: gana el último en silencio — 17 días de una pestaña vacía en producción de una instancia real), el parser de veredictos de kj review arreglado en el camino que de verdad recorre, dos fixes el mismo día para un reportero de campo en Windows, un agujero de inyección de shell cerrado en un workflow reusable, y las actions del propio repo fijadas a SHA de commit — lo que kj genera ya estaba fijado; lo que kj es no se había puesto al día.
Minor en la que dos reglas dejan de vivir en la memoria del agente y se convierten en gates. Identity lock: cada clon declara quién lo trabaja (kj identity set — cuenta de gh + email de git, por desarrollador, nunca trackeado; el siguiente kj harden lo pide, con un humano confirmando), y el Sentinel rechaza gh, git push y cualquier git que firme commits bajo otra cuenta ANTES de ejecutarlo — autoría resuelta por git var con el entorno del propio comando, shells envoltorio y sustituciones escaneados por dentro, jamás un auto-switch. Nació de un incidente real: un gh sin switch explícito publicó como la cuenta de un cliente en un repo público. Board-sync gate: una card mergeada debe quedar movida en el tablero antes de que nada avance — el Sentinel deja pendiente la card de la rama en un merge verificado y rechaza commit, push, nuevo PR, otro merge y el cierre del turno hasta que la llamada REAL al tracker la limpia (update_card vía MCP o kj hu move). Destapó tres huecos de producción en su primera hora y gobernó la card de su propia creación en su primer merge real. Más el fix de campo de la 4.20.1: kj start por fin ve el proyecto en el que está.
Minor nacida de un proyecto real de campo (una demo de kubernetes con el código en backend/): el método era agnóstico del lenguaje sobre el papel, pero tres piezas concretas seguían asumiendo código de aplicación — ahora el Sentinel cuenta los edits de terraform/k8s/shell/Docker como fuentes (card-first, Stop gate y push gate disparan exactamente igual que con un .js), la infra tiene suites de verdad (terraform validate, helm lint, kustomize build, ansible-lint, con checkov encadenado como deep scan aditivo — una tool ausente se declara con su comando de instalación, jamás un verde falso), y kj audit --security pasa checkov por el mismo canal best-effort que semgrep, porque los misconfigs SON superficie de seguridad. Además, tres fixes reportados desde el campo y publicados en horas: codex exec perdió --full-auto upstream (ahora --sandbox workspace-write con retry legacy), kj start pasaba el haiku de Claude a agy (los modelos se filtran por FAMILIA de provider en el chokepoint), y la escotilla de escape del propio Sentinel solo existía en su mensaje de error — todo prefijo KJ_ALLOW_X=1 funciona ya en comando simple, fail-closed en cadenas, probado la misma noche en que deadlockeó la release de su autor.
Minor donde el método deja de fiarse de una suite verde sin más: el pre-gate de mutación se une a la review — una suite puede pasar con asserts débiles, y los mutantes supervivientes lo demuestran. Opt-in (method_gates.mutation: warn|block, nunca corre sin declararse) y solo sobre el diff staged: warn entrega los supervivientes como aviso dentro de la tarea del reviewer, block rechaza ANTES de gastar un token de reviewer, listando cada superviviente con su remedio. kj doctor declara ahora su nivel de garantía por host — el acoplamiento a Claude Code no es un bug, es un gradiente DECLARADO: el tier A tool-time necesita los hooks síncronos del Sentinel, el tier B commit-time (los gates de git) es el suelo en CUALQUIER host, el tier C re-verifica en CI; ejecuta kj desde codex o gemini y te dice exactamente qué garantías conservas. Y una semana de hallazgos de campo aterriza arreglada: kj start ya no llama vacío a un proyecto de infra (el código anidado en backend/app/… y los yaml/tf/sh/Dockerfile cuentan como fuente), kj agents --help enumera sus roles y providers reales alimentados de las constantes, y el guard de carriles aprendió qué es un par de comillas después de bloquear a su propio autor. La migración de familia se hace real: @karajan-family/code publica los mismos bits que karajan-code — el primer dual-publish bajo el scope de la familia.
Minor donde la gobernanza deja de ser una feature de kj y se convierte en PAQUETE: @karajan-family/governance llega a npm — Política, Decisión y Excepción como objetos abstractos de primera clase (deterministas, locales, sin LLM), con karajan-code como primer consumidor, no como dueño. La capa de policy completa sus tres tiers: la regla dispara ANTES del daño en tool-time (con el rol del agente que actúa), el diff violador no entra en commit-time, y CI re-verifica el PR contra la misma policy — cubriendo hasta el hook local manipulado. Las excepciones llevan el modelo probatorio completo: quién (identidad), regla exacta, justificación escrita en el momento y caducidad OBLIGATORIA que ejecuta el sistema — la vencida vuelve a bloquear sola, y a la regla concedida tres veces se le dice a la cara que ya no es una excepción sino la política real pidiendo cambio. Cada decisión de chokepoint deja rastro hash-encadenado y anclado en git: reescribir el log de ayer exige reescribir el repo de ayer. Y kj policy add: dices la regla hablando, el motor la valida, y nada se escribe sin tu confirmación.
Minor donde toda la familia Karajan se muda bajo un mismo techo: radar, rag, watch y la propia landing se fusionan en el monorepo con sus historias COMPLETAS (reescritas bajo la ruta de cada paquete — git log packages/rag cuenta toda la historia; los repos origen quedan congelados como referencia inmutable, y cada autoría importada firma con la dirección noreply). El prerequisito de seguridad llegó primero: aislamiento de carril — cada sesión muta solo SU worktree, denegado por el gate PreToolUse del Sentinel ANTES del daño, con escape auditado (dos sesiones chocando en un árbol fue un incidente real; nunca más). Y el tercer pilar: policy as code — .karajan/policy.yml declara reglas por rol en un vocabulario cerrado y fail-loud (una regla que el motor no puede aplicar es error de carga, jamás una regla muerta en silencio) y kj policy check/eval las evalúan deterministas en modo warn; el cableado de deny llega después. La prueba del techo: esta misma release actualizó su landing en el mismo repositorio y el mismo PR — la danza de delegación release→landing ha muerto.