Sin Costes Extra
Funciona con tus suscripciones existentes de IA. No necesita API keys ni servicios cloud adicionales. Combina con RTK y Squeezr (cards de abajo) para un 60-90% adicional de ahorro en tokens.
En lugar de ejecutar un agente de IA y revisar manualmente su output, kj orquesta roles especializados — cada uno ejecutado por el agente de IA que tú elijas. El coder escribe código, los guards comprueban patrones destructivos, SonarQube lo analiza, el reviewer lo revisa, y si hay problemas, el coder recibe otra oportunidad. Los roles definen qué hacer; los agentes definen quién lo hace.
Sin Costes Extra
Funciona con tus suscripciones existentes de IA. No necesita API keys ni servicios cloud adicionales. Combina con RTK y Squeezr (cards de abajo) para un 60-90% adicional de ahorro en tokens.
Integración RTK — compresión de salidas Bash
RTK (Rust Token Killer) comprime la salida de 13 comandos Bash (git, ls, find, grep, cat, head, tail, wc, diff, tree, du, file) que el agente coder usa constantemente. Si Karajan detecta rtk --version en el preflight, envuelve transparentemente cada comando soportado vía wrapWithRtk() y acumula bytes ahorrados por sesión con RtkSavingsTracker. Opcional, opt-in al instalarlo — no hace falta flag de config. Ver docs de instalación.
Compatible con Squeezr — compresión de respuestas MCP
Squeezr es un proxy MCP que comprime las respuestas que el server MCP de Karajan devuelve al host (Claude Code, Cursor, etc.). Es arquitectónicamente ortogonal a RTK: RTK comprime dentro del pipeline (salida de comandos Bash); Squeezr comprime encima (mensajes MCP por el cable). Karajan no integra Squeezr — Squeezr vive en el transporte MCP del host — pero ambos componen limpiamente. Instalas Squeezr en la config MCP de tu host y Karajan se beneficia sin cambios.
Links a Documentación en Errores
Errores de preflight, bootstrap y MCP incluyen un puntero See: <url> a la página de docs relevante. Anclas específicas para SonarQube, Docker, install de agentes, install de RTK y problemas de config; el resto cae al troubleshooting genérico.
Telemetria (Opt-Out)
Estadisticas de uso anonimas (version, SO, comando, duracion del pipeline, tasa de exito) para mejorar Karajan. Totalmente desactivable con telemetry: false en el config.
Auto-Deteccion de Stack
kj init escanea package.json, go.mod, Cargo.toml y mas para detectar tu framework y lenguaje. Auto-activa impeccable para proyectos frontend.
Dashboard kj status
Dashboard de terminal mostrando estados de HUs, stage actual, tiempos y progreso. El MCP devuelve JSON estructurado para acceso programatico.
kj undo
Revierte la ultima ejecucion del pipeline con soft reset o --hard. Deshaz cambios de forma segura cuando un run produce resultados inesperados.
Dashboard HU Board
Dashboard web para visualizar historias de usuario y sesiones de todos los proyectos. Tablero kanban, timeline de sesiones, puntuaciones de calidad. Listo para Docker, sincroniza automáticamente desde ficheros locales.
Certificacion de Historias de Usuario
Quality gate obligatorio que evalua historias de usuario en 6 dimensiones (contexto JTBD, especificidad de usuario, cambio de comportamiento, zona de control, restricciones temporales, experimento viable). Detecta 7 antipatrones, reescribe historias debiles, pausa para contexto FDE. Soporta grafos de dependencias.
Auditoría de Salud del Codebase
Análisis de solo lectura en 5 dimensiones: seguridad, calidad de código (SOLID/DRY/KISS/YAGNI), rendimiento, arquitectura y testing. Genera un informe de salud con puntuaciones A/B/C/D/F por dimensión y recomendaciones priorizadas sin modificar ningún fichero.
5 250+ Tests Automatizados
466 ficheros de test cubriendo cada rol (incl. rag-context-stage), guard, opción de config, herramienta MCP (27 total), el paquete completo del HU Board (modal de settings editable + badge de plan compartido + assignee por HU), el subsystem Project RAG con modo hybrid + rerank, el dashboard de retrieval, el flujo del HU cohort compartido en equipo y la nueva suite audit-history-display (12 tests). Suite completa en unos 60 s con Vitest. Los tests de subsistemas opt-in (brain, ci, sonar, hu-board, webperf) llevan la etiqueta [opt-in: <feature>] y se pueden saltar con KJ_SKIP_ALL_OPTIN=1. Coverage v8 (text + html + lcov) viaja como artefacto de CI desde v2.32 — ver KJC-TSK-0465.
Pipeline Zero-Config
Auto-detecta TDD según el framework de tests del proyecto. Gestiona automáticamente el ciclo de vida Docker de SonarQube y la generación de config. Omite sonar/TDD para tareas de infra y doc automáticamente. Las tareas simples ejecutan un flujo ligero (solo coder), las complejas el pipeline completo — automáticamente según el triage.
Modo Skills
8 slash commands (/kj-run, /kj-code, /kj-review, /kj-test, /kj-security, /kj-discover, /kj-architect, /kj-sonar) con guardrails integrados. Sin MCP — funciona directamente en Claude Code.
Host-as-Coder
Cuando el host MCP es el mismo agente que el coder (ej. Claude llamando kj_run con coder=claude), Karajan delega directamente — sin subproceso, sin overhead. Todos los guardrails siguen activos.
Resilient Run
Auto-diagnostica fallos y reanuda sesiones caídas — hasta 2 reintentos. Errores no recuperables (config, auth, agente no encontrado) fallan inmediatamente. Configurable via session.max_auto_resumes.
Comandos de Rol Standalone
Ejecuta cualquier rol pre-build de forma independiente: kj discover, kj triage, kj researcher, kj architect. Disponibles como comandos CLI y herramientas MCP.
SonarQube + SonarCloud opcional
SonarQube (Docker local, quality gates bloqueantes) corre por defecto y es el motor del stage de análisis estático. SonarCloud es opt-in y complementario — actívalo con el flag --enable-sonarcloud, enableSonarcloud: true (MCP) o sonarcloud.enabled: true en kj.config.yml. Requiere sonarcloud.token y sonarcloud.organization (o las env vars KJ_SONARCLOUD_TOKEN / KJ_SONARCLOUD_ORG). Cuando ambos están activos, los resultados de SonarCloud son informativos.
Auditoría de Diseño Impeccable
Quality gate automatizado de UI/UX. Audita ficheros frontend modificados buscando problemas de accesibilidad, rendimiento, theming, responsive y anti-patrones. Se ejecuta después de SonarQube y aplica correcciones automáticamente.
Guards Deterministas
Output guard bloquea operaciones destructivas y filtraciones de credenciales. Perf guard detecta anti-patrones de rendimiento en frontend. Intent classifier pre-clasifica tareas obvias sin coste LLM. Todo configurable con patrones custom.
Discovery Pre-Ejecución
kj_discover analiza tareas buscando gaps antes de empezar a codificar. 5 modos: detección de gaps, preguntas Mom Test, checklist Wendel de cambio de comportamiento, clasificación START/STOP/DIFFERENT y generación de Jobs-to-be-Done.
BecarIA Gateway
Integración CI/CD completa con GitHub PRs como fuente de verdad. Todos los agentes publican comentarios y reviews en PRs. Creación temprana de PR, dispatch events configurables y workflow templates embebidos.
Mediación Inteligente del Reviewer
El scope filter auto-difiere issues del reviewer fuera de scope en vez de bloquear el pipeline. Los issues diferidos se rastrean como deuda técnica y se inyectan en el prompt del coder.
Monitorización en Tiempo Real
Detector de stalls, heartbeats continuos, guardarraíles de silencio, límite de runtime. kj-tail para log colorizado en vivo. kj_status para estado parseado.
Solomon — Pipeline Boss
Evalúa cada rechazo del reviewer, clasifica issues como críticos vs. solo estilo, y puede anular bloqueos por estilo. 6 reglas incluyendo scope guard, reviewer overreach y control inteligente de iteraciones.
Preflight Handshake
kj_preflight requiere confirmación humana de la config de agentes antes de ejecutar. Config de 3 niveles: sesión > proyecto > global.
Standby por Rate-Limit
Detecta mensajes de rate-limit / cuota de los CLIs (Claude / Codex / Gemini) y errores HTTP 429/5xx. Parsea el cooldown cuando el mensaje usa un formato reconocido (timestamp ISO, Retry-After: <segundos>, retry in N minutes, o el formato Claude resets at YYYY-MM-DD HH:MM UTC) y espera exactamente ese tiempo con heartbeats cada 30s — aunque sean horas. Si no hay tiempo parseable, cae a 5 min default con backoff exponencial (cap 30 min) y hasta 5 reintentos antes de pedir intervención humana.
Pipeline Tracker
Vista de progreso acumulativo durante kj_run — ve qué stages están completadas, en ejecución o pendientes en tiempo real via MCP y CLI.
Sistema de Plugins
Extiende con agentes custom via .karajan/plugins/. Auto-descubiertos al iniciar.
TDD Obligatorio
Se exigen cambios en tests cuando se modifican ficheros fuente. El pipeline rechaza iteraciones sin tests.
Servidor MCP
24 herramientas via MCP — incluyendo kj_discover, kj_triage, kj_researcher, kj_architect para ejecucion standalone de roles, kj_preflight para configuracion confirmada por humano, kj_board para gestion del HU Board, kj_status para estado parseado en vivo, y kj_undo para revertir ejecuciones del pipeline. Notificaciones de progreso en tiempo real para todas las herramientas. Reinicio graceful tras actualizaciones npm.
5 Agentes IA
Claude, Codex, Gemini, Aider y OpenCode. Combinalos — usa Claude como coder y Codex como reviewer, o cualquier combinacion. Extensible via plugins.
Pipeline Multi-Agente
24 roles configurables a lo largo de las fases pre-loop, iteración y post-loop — triage, planner, coder, reviewer, sonar, solomon, audit y más. Catálogo completo en Roles del pipeline. Auditoría obligatoria post-aprobación que certifica el código generado como limpio antes de completar.
Solomon — Juez IA (v2.0)
Refinado de jefe del pipeline a juez IA. Consultado solo en dilemas genuinos: seguridad-vs-deadline, gates de calidad en conflicto, loops estancados, evaluación de riesgos. Los issues de seguridad bypasean Solomon deterministicamente y vuelven directo al coder.
Karajan Brain (v2.0)
Orquestador central con IA que enruta toda la comunicación entre roles, enriquece feedback con pistas de ficheros, verifica outputs vía git diff, ejecuta acciones directas (npm install, gitignore) y comprime outputs de roles para 40-70% de ahorro de tokens. Consulta a Solomon solo en dilemas genuinos.
Tests de Aceptación Ejecutables (v2.4)
Cada HU lleva acceptance_tests: un array de comandos shell que Brain ejecuta tras cada iteración del coder. Todos pasan → HU aprobada. Alguno falla → Brain lee el error exacto y envía un diagnóstico concreto al coder. Sin reviewer. Sin tester genérico. Pasa/falla concreto.
Budget: Con KJ vs Sin KJ (v2.6)
Al cerrar sesión, el budget proyecta el coste que habrías pagado sin las optimizaciones de Karajan (RTK + compresión Brain). Líneas claras con el delta (-88%, por ejemplo) mantienen las expectativas pegadas a números reales.
Diario de Sesión Rico (v2.6)
Cada run escribe .reviews/<session>/decisions.md, iterations.md, summary.md y tree.txt. Log iteración a iteración de coder/reviewer/sonar/Solomon, resumen ejecutivo con tabla de stages y desglose de presupuesto, vista agrupada por directorio de cada fichero tocado.
Validación de Config con Valibot (v2.6)
La configuración se valida al cargar contra un schema Valibot. Erratas en review_mode, max_iterations: 0, hu_board.port fuera de rango, max_budget_usd negativo o budget.warn_threshold_pct fuera de 0-100 fallan con mensajes claros. Flags CLI falsy (--no-rebase, --reviewer-retries 0) por fin se respetan. Co-autoría con Jorge del Casar.
Inyección de Dependencias de Infraestructura (v2.6)
Adaptadores FileSystemService y CommandRunner bajo src/infrastructure/. BaseAgent acepta un Environment opcional; createAgent(…, env) lo propaga. En tests se inyecta MockFileSystem + MockCommandRunner con buildMockEnvironment() y todos los agents (Claude, Codex, Gemini, Aider, OpenCode) se testean sin lanzar subprocesos reales.
Orquestador Modular (v2.6)
src/orchestrator.js pasa de monolito de 2 084 líneas a barrel público de 22 líneas sobre src/orchestrator/flow-runner.js. Nuevo contrato StageExecutor (canRun / execute / onFailure) + StageRegistry permite registrar stages sin tocar el core. Añadir un stage nuevo es ahora un drop-in: subclase bajo src/orchestrator/stages/, registrar y listo.
addyosmani/agent-skills (v2.7)
Skills de proceso de primera fuente desde addyosmani/agent-skills: TDD, code-review-and-quality, security-and-hardening, performance-optimization, git-workflow-and-versioning, CI/CD, debugging, spec-driven-development y más. Clonado automático en ~/.karajan/agent-skills/, refresco semanal con git pull. Consciente del rol: cada rol de Karajan (tester, reviewer, security, architect, coder…) recibe los workflows que le corresponden. Totalmente ortogonal a OpenSkills — los skills de proceso y los de stack se componen.
Reportes de Audit + Transparencia de Coste (v2.9)
--report-file <path> persiste el audit a .md (con cabecera reproducible: timestamp, branch, commit, flags de invocación) o .json. $KJ_AUDIT_REPORT_DIR para defaults en CI. Cada audit termina con una sección ## LLM Usage mostrando provider + model + duration + tokens (in/out/total) + coste estimado en USD. Visible en stdout, JSON y reportes persistidos. Bug de paridad CLI/MCP corregido — ambos paths ahora ejecutan el mismo flow AuditRole.
Audit Stack-Aware (v2.9)
detectProjectStack informa al auditor LLM qué tipo de proyecto está mirando: frontend-only, backend-only, fullstack, lenguaje, frameworks. Las heurísticas se filtran — sin más alertas de N+1 queries en Astro, sin más alertas de bundle-size en APIs Express. Nueva dimensión accessibility auto-activa para proyectos frontend / fullstack con checks WCAG 2.x (alt text, labels, ARIA, focus management, hints de contraste). Nueva sección WebPerf con 10 patrones de perf frontend cuando no hay medición CWV en vivo.
Tres Colectores Deterministas de Seguridad (v2.9)
Hallazgos de SonarQube como ground truth en el prompt (rule ID + precisión de línea). OSV-Scanner cubre CVEs en toda la DB de OSV.dev — más amplia que npm audit, sin cuenta, sin upload. Semgrep SAST detecta XSS, SQLi, taint flow, secrets hardcodeados, anti-patrones específicos del lenguaje — equivalente a snyk code pero gratis para OSS. Los tres son best-effort: binario faltante o host inalcanzable saltan la sección silently.
Audit en Dos Fases (v2.9)
kj audit ahora recolecta hallazgos deterministas (basalCost, Sonar, OSV-Scanner, Semgrep, WebPerf, detección de stack) en paralelo — cero tokens — y los imprime ANTES de preguntar Continue with LLM analysis? [y/N]. Nuevo flag --deterministic-only para corridas sin tokens, -y/--yes para auto-confirmar, --json evita el prompt para output pipeable. CI / paths sin TTY auto-confirman — cero cambio de comportamiento para pipelines.
Hardening del HU Board (v2.10)
El bind por defecto es ahora 127.0.0.1 (antes: todas las interfaces). Nuevo --bind 0.0.0.0 para el caso explícito de exposición en LAN, con token autogenerado en ~/.karajan/hu-board/token (mode 0600). El middleware de auth fuerza el token solo para peers no-loopback — el navegador en la misma máquina sigue funcionando sin ?token=. Headers helmet + express-rate-limit 300 req/min en /api. Tres carriers aceptados: Authorization: Bearer, ?token=, cookie kj_board_token.
Quality Gate de Webperf (v2.10)
PerfStage se engancha al bucle de iteración justo después de Impeccable cuando pipeline.perf.enabled es true. Envuelve Lighthouse para un veredicto Core Web Vitals por iteración. PASS continúa; FAIL empuja feedback de métricas bloqueantes (p.ej. LCP=5500 (poor>4000) más top-opportunities como recursos render-blocking) al coder para la siguiente iteración; scanner no disponible salta best-effort. CLI: --enable-perf. MCP: enablePerf. Sin retry-loop — max_iterations es el techo natural.
SKILL.md por Comando del CLI (v2.10)
docs/agents/SKILL.kj-{plan,run,audit,doctor,init,board,review,resume,clean}.md — un fetch por capacidad del CLI (~ 2-4 KB de tokens cada uno), todos bajo el mismo contrato: What it does · Inputs · Outputs · Constraints · Side effects · Common failure modes · Example · Related. Guardado por CI: cada link en llms.txt debe resolver a un fichero con las cuatro secciones requeridas, o el build falla.
Score Agent-Readiness (v2.10)
kj audit --agent-readiness puntúa cualquier repo de 0 a 100 sobre 7 checks sin LLM: presencia y validez de llms.txt, allowlist de bots IA en robots.txt, presupuesto de tokens por doc (≤ 32 KB), jerarquía de headings (markdown + HTML <h1>), docs/agents/README.md como entry point, cobertura de SKILL.md. Transformación pura — sin red, sin LLM, sin side effects. --json para CI. Karajan-sobre-Karajan: 100/100. Pásalo a tu propio repo, mira con qué luchan los agentes, arregla desde la lista de top-fixes.
hu-board: Limpieza efímera + Ayuda (v2.11)
Al arrancar el board, los proyectos cuyo id encaja con tmp_* / test_* / demo_* / kj-test-* Y llevan >24 h inactivos se borran en cascada (proyecto + stories + sesiones). Override por proyecto vía un toggle de 3 estados en cada card (🧪 forzar test / 📌 fijar / · heurística por defecto) y PATCH /api/projects/:id/is-test. El header gana también un botón ?: abre un modal explicando cada una de las cinco vistas (Board / Graph / Dashboard / Sessions / Pipeline), y cada tab tiene un atributo title nativo para el tooltip de hover de 1 segundo.
Endurecido por Dogfooding (v2.11)
Un paso de dogfooding de dos días por toda la superficie de Karajan — desde kj --version hasta un sub-pipeline multi-HU completo dirigido por plan — arregló tres bugs latentes que sólo aparecían en repos /tmp recién creados: el SonarStage ya no quema max_iterations haciendo loop con Missing git remote.origin.url, commitAll tolera la carrera locale-específica de “nada para hacer commit”, y el sub-pipeline de HUs ramifica desde master/HEAD cuando el main configurado no existe. runFlow sella session.status en la frontera, así que kj status no muestra runs zombi running. Niveles N0–N8 re-validados verdes.
Detector de fs-leak del coder, segunda capa (v2.14)
El fs-leak-detector original hacía diff de $HOME antes y después de que el coder corriera. Pillaba el incidente original (cd /home/manu/assistant && pnpm init creando 36 MB fuera de projectDir) solo porque ~/assistant era nuevo. Si el dir target preexistía, el diff lo dejaba pasar. v2.14 añade detectTranscriptCdLeaks() como segunda capa: escanea el transcript del coder buscando patrones cd <abs-out-of-project> && <write-cmd> y los flagea independientemente del estado en disco. Comandos write reconocidos: mkdir, touch, cp, mv, git init, {pnpm,npm,yarn} init/create, npx create-*, cat >, echo >, redirects de shell. Comandos pure-read (ls, which, grep) no disparan, y /tmp está exento por convención.
Solomon ya no aprueba blockers de seguridad (v2.14)
Rule 6 del Solomon rules engine (reviewer_style_block) clasificaba cualquier issue blocker con severity low/minor o keywords cosméticas (name, format, documentation, …) como “style” — incluso blockers de seguridad legítimos se colaban. v2.14 añade un anti-clasificador: severities critical/high/blocker/major, categorías security/correctness, y una regex de keywords de seguridad (SQL injection, XSS, CSRF, auth, password, secret, hash, traversal, …) descalifican el issue del “all style”. 6 tests de regresión cubren los falsos positivos del incidente original.
Self-fix loop del planner (v2.14)
El plan-reviewer era flag-only: detectaba missing HUs, missing dependencies y scope overlaps, y los dejaba para que el usuario los aplicara a mano. v2.14 cierra ese loop. Tras el primer review pass, el nuevo módulo plan-fixer.js pide al planner que PARCHEE el plan (additions / deps_to_add / deletions), aplica el patch in-process vía addHu / removeHu / mutaciones de blocked_by, y re-review. Loop hasta 2 iteraciones o hasta cero issues. Opt-out con --no-plan-fixer / --quick. Combinado con tres arreglos al prompt del planner (respeto al scope, deps transversales uno-a-muchos, marker reuse explícito), las cuatro patologías que el dogfooding de GRETA Plan 2 seguía sacando ahora quedan cerradas en origen.
Guardrails de equipo — config recomendada
Config copy-paste para un equipo que delega trabajo a IA: SSH multi-cuenta (una clave por identidad), git hooks globales (commit-msg que bloquea atribución a IA, pre-push que bloquea push directo a main, git-secrets para escaneo de credenciales), permisos por agente (Claude Code, Codex con *.rules, Gemini CLI), rulesets de branch protection en GitHub, plantillas de PR / Issue y routing por CODEOWNERS. Pega, adapta, despliega. → Leer la guía
HU Board compartido en equipo (v2.31)
Varias máquinas, un solo plan. kj plan share <planId> opta el plan al cohort .karajan-shared/: el loader fusiona las HUs compartidas con el plan local, el board escanea el cohort y las marca con badge shared, y un nuevo campo assignee por HU permite que cada runner reclame su parte sin pisarse con los demás. Filtros --only / --exclude, round-trip kj plan unshare, y el escape hatch sharedConflictPolicy (local-wins / shared-wins / error) cubren los edge cases de conflicto. Siete PRs (#859–#865) cierran el prerequisito de team-shared (KJC-PRP-0002).
AI Harness Scorecard hardening (v2.32)
El Plan A de KJC-PCS-0051 cierra cinco FAILs del scorecard externo en un mismo sprint. Prettier --check (PR #868) bloquea PRs cuyo formato se desvía. Coverage v8 (PR #870) emite text + html + lcov y sube coverage/ como artefacto de CI con thresholds por glob al ejecutar opt-in. Conventional Commits (PR #872) verifica los mensajes de cada commit del PR con wagoid/commitlint-github-action@v6, encima del hook pre-commit local. Nightly drift workflow (PR #873) re-corre todo el CI cada noche a las 04:17 UTC y abre/actualiza un issue de tracking si algo se rompe. eslint-plugin-security (PR #874) bloquea eval, new Function, dynamic require, pseudoRandomBytes y la desactivación del escape de mustache. Más dos bug fixes que viajan junto a la release.
AI Harness Scorecard métrica dorada (v2.33)
El Plan B de KJC-PCS-0051 convierte kj audit en un loop de medición de calidad con un único número dorado. Bootstrap Docker (PR #877, KJC-TSK-0470) auto-pulla addyosmani/ai-harness-scorecard y corre un scan one-shot en ~10 s. Integración en audit (PR #878, KJC-TSK-0471) inyecta el score determinista 0–100 y la nota A–F en el headline del informe. History DB (PR #879, KJC-TSK-0472) persiste cada run en una audit-history.db per-proyecto (SQLite + WAL, PRAGMA user_version=1). Diff + sparkline de tendencia (PR #880, KJC-TSK-0473) muestra el delta vs el baseline anterior más un sparkline Unicode con la tendencia de los últimos N runs. Un solo número dorado para “qué tan AI-friendly es este repo hoy vs la semana pasada”, cero tokens LLM gastados.
Últimas release notes, primero las antiguas. La versión actual se muestra en la navbar; el histórico completo vive en Historia de la arquitectura.
16 PRs absorben bugs blockers (Solomon ya no aprueba issues de seguridad clasificados erróneamente como ‘style’, la detección de fs-leak del coder añade una segunda capa que pilla cd <abs> && pnpm init incluso cuando el dir preexistía, la rotación de password admin de Sonar ya no falla silenciosamente), las cuatro patologías del planner detectadas en el dogfooding de GRETA Plan 2 (respeto al scope, deps transversales uno-a-muchos, campo reuse explícito, y un self-fix loop nuevo donde el plan-reviewer re-invoca al planner con feedback estructurado hasta cero issues), pulido del HU Board (TTL para prompts zombi de runners crashed, rate-limit menos agresivo con SSE exento), y la primera tanda de reorg de tests/ (issue #368): 93 archivos movidos de root a subcarpetas espejo. 4577/4577 tests verde, 0 regresiones en las 16 PRs.
Dos patologías más del planner detectadas en dogfooding de v2.14.0 contra GRETA Plan 2: el self-fix loop podía empeorar el plan (iter 1 reducía 15→10 issues, iter 2 borraba HUs que iter 1 había añadido y subía a 17), y el planner declaraba blocked_by sobre observers asíncronos (HUs marcadas dependiendo de guardarraíles o cron jobs que solo reaccionan a ellas, rompiendo AVISA-no-BLOQUEA de GRETA). Fixes: P5 hace snapshot de plan.hus+plan.review antes de cada iter y revierte si newCount > currentCount; P6 lista seis patrones async observer en el prompt + heurística ‘consume vs react’. Regenerar Plan 2 GRETA con esta release vuelve al baseline-iter-1 (9 findings en 58 HUs, 15%) en lugar del 17 de v2.14.0. 2 PRs (#684, #685). 4580/4580 tests verde. Upgrade seguro desde 2.14.0.
Más caza de bugs UX del dogfooding GRETA Plan 2 v2.14.1: el botón ▶ Run en cards del HU Board aparecía en TODAS las HUs pending ignorando blocked_by (podías lanzar una HU cuyas deps aún no existían), y los titles del board habían perdido el prefix [EPICA] así que era imposible orientarse de un vistazo sobre qué área del plan pertenecía cada card. Fixes: canRunHu ahora exige blockedBy.length === 0; el prompt del planner exige description: "[EPICA] one-sentence description" con fallback INFRA/SHARED. Más nuevo doc spec-conventions.md con las 6 convenciones SPEC que el planner v2.14.x entiende, para que el usuario no las descubra por dogfooding. 2 PRs (#687, #688). 4584/4584 tests verde.
Tres mejoras del preflight detectadas en el primer kj run real sobre un proyecto greenfield: (1) la auth de gh por keyring ya se reconoce (antes Karajan exigía GH_TOKEN en env aunque gh auth login --web hubiera funcionado), (2) nuevo sistema de checks degradables que desactiva features opcionales (auto_pr/auto_push) con WARN en lugar de abortar el run, y (3) nuevo preflight project-aware que detecta signals (Dockerfile/firebase.json/pyproject.toml/Cargo.toml/*.tf/.env.example), comprueba las tools correspondientes, valida permisos de escritura en projectDir/.kj/.karajan, compara .env vs .env.example, y verifica acceso gh push al remote real. Comando nuevo kj doctor --project. 2 PRs (#690, #691). 4608/4608 tests verde.
Tres epics, 30+ commits, ~4 000 LOC. Brain Recovery (KJC-PCS-0044): clasificador universal de errores con 7 clases ricas cableado en TODAS las invocaciones a agentes IA (no más fallos silenciosos), hibernación persistente en ~/.kj/standby/ con scheduler event-driven (cero polling), kj standby list + kj standby resume, reconciliación del board al arrancar, y un fallback chain que cambia de provider automáticamente cuando se agota la cuota con retryAfter > 12h — crítico para el nuevo cap de $200/mes del Agent SDK de Anthropic desde el 15 de junio. Model Routing + Undo (KJC-PCS-0043): cada HU recibe coder_model + reviewer_model con revisión cross-provider por defecto (claude↔codex), override por HU desde el modal del board, OpenCode + Aider como providers de primera clase, y un botón ⏪ Undo que restaura ficheros vía snapshots git. Self-Healing Plan (KJC-PCS-0042): pasada de integridad estructural que rompe ciclos y limpia refs huérfanas, convergence guard inteligente para el self-fix loop, nuevo comando kj plan fix [planId] [--prompt] para iterar sin regenerar, skip de Sonar en HUs SPIKE/DOC/RESEARCH, y la columna Failed del kanban da paso a un badge result=fail en Pending. 4 835/4 835 tests passing en 400 ficheros.
Release orientado a calidad. La cabecera es un filtro determinístico de falsos positivos de Sonar (KJC-TSK-0416). Antes de que los issues de Sonar lleguen al coder o al auditor, se filtran por dos mecanismos: (1) rules estáticas { rule, filePattern, reason } desde un catálogo built-in (cubriendo falsos positivos comunes como javascript:S2699 en tests/architecture/ donde los asserts usan expect(off, msg).toEqual([]) que Sonar no detecta), extensible por proyecto vía config.sonar.false_positives; (2) inline ignores con // karajan-sonar-ignore: <ruleId> en la línea del issue. Resultado: el coder deja de quemar tokens “arreglando” asserts que no están rotos. Brain Recovery ahora envuelve todas las llamadas IA del pipeline — semantic-detector era el último caller legacy, cableado vía adapter (TSK-0413 step D). Codemod .replace(/regex/g, …) → .replaceAll(/regex/g, …) en 41 sitios, más limpieza de BLOCKER false positives del propio audit. 4 846/4 846 tests passing en 401 ficheros.
kj audit gana dos nuevos collectors estructurales determinísticos y el filtro de FPs de v2.16 se generaliza a todos los collectors. Knip dead-exports collector (dimensión codeQuality): detecta exports/tipos sin uso (MINOR) y ficheros sin uso (MAJOR). Stack-aware — solo JS/TS, requiere package.json. Subprocess via --reporter json, timeout 120 s. Madge circular-import collector (dimensión architecture): detecta ciclos de import. Severidad por longitud de cadena (≥4 ficheros = MAJOR, más cortos = MINOR). Honra tsconfig.json para resolución de path-aliases, timeout 60 s. Filtro generalizado: cada collector — sonar, knip, madge, osv, semgrep — usa el mismo shape config.audit.false_positives con nuevo campo tool más el marker inline // karajan-audit-ignore: <tool>:<ruleId>; legacy config.sonar.false_positives y // karajan-sonar-ignore: siguen funcionando. Catálogo built-in trae 4 entradas por defecto: knip:unused-files en tests/fixtures/ + examples/, knip:unused-exports en barrel files (index.{js,ts,…}), madge:circular-import en node_modules/. BREAKING(engines): Node >=20.10 → >=20.19 (requisito de knip 6.x). 4 872/4 872 tests passing en 402 ficheros. Upgrade seguro desde 2.16.0 si estás en Node ≥ 20.19.
Corrige KJC-BUG-0055: un proyecto borrado del HU Board (🗑️) ya no resucita al ejecutar kj plan ni al reiniciar el board. Se cierran cuatro fugas independientes: (1) gate temporal en sync.js — el removeTombstone incondicional que introdujo KJC-BUG-0050 pasa a ser una comparación plan.updatedAt > tombstone.deleted_at, de modo que un proyecto tombstoneado revive solo si el plan es genuinamente posterior al borrado; los planes stale en disco se ignoran y se eliminan. (2) ephemeral-cleaner.js ahora escribe un tombstone y hace rm -rf de los directorios hu-stories/, sessions/ y ~/.kj/plans/ al limpiar proyectos ephemeral en el arranque — antes solo borraba la fila en BD, así que los directorios huérfanos resucitaban el proyecto en el siguiente scan. (3) GC de fullScan en el arranque barre los directorios huérfanos tombstoneados (el caso de wipe manual de BD). (4) DELETE /api/projects/:id respeta KJ_PLANS_DIR en lugar del path hardcodeado. Nuevo helper getTombstone() en db.js. También corrige un fallo silencioso de kj board start (#753): el guard de entry-point del demonio comparaba import.meta.url con un path file:// construido a mano y devolvía false erróneamente en Windows, instalaciones con symlinks / globales y rutas con espacios — el board salía con código 0 y el log vacío. server.js ahora confía en un flag KJ_BOARD_DAEMON del lanzador y añade handlers uncaughtException / unhandledRejection más un error accionable de better-sqlite3; board.js detecta una muerte temprana del demonio en vez de reportar un PID fantasma. 4 909/4 909 tests passing en 408 ficheros. Upgrade seguro desde 2.17.0.
Cablea de extremo a extremo la hibernación por cuota agotada. Un kj run / kj plan que topa con el límite de sesión o de uso de un proveedor antes abortaba la tarea con un UNKNOWN_FATAL opaco; ahora se suspende, persiste su estado y te dice cómo reanudarlo. (1) Clasificación del límite de sesión (#756) — "You've hit your session limit · resets 10:10pm" no casaba ningún patrón de rate-limit; ahora se reconocen session limit / weekly limit y parseCooldown entiende el reloj de 12 h resets 10:10pm, así que el Brain sabe cuándo se resetea la cuota. (2) La hibernación se persiste (#757) — withBrainRecovery solo escribía ~/.kj/standby/<id>.json si recibía un sessionState, que ningún caller pasaba; el nuevo buildStandbyState() lo construye con un subconjunto de env en allowlist (nunca el process.env completo). (3) El orquestador consume action:"hibernate" (#758) — ningún punto del código lo comprobaba, así que una hibernación sellaba la HU como failed; las stages de coder y refactorer ahora paran limpio ante una cuota agotada y la sesión se sella hibernated (reanudable), no failed. (4) Pista de reanudación (#759) — la última línea de un kj run / kj plan detenido es ahora el comando exacto, kj standby resume <id> para una hibernación. Además CI ahora ejecuta la suite de packages/hu-board (#755). 4 931/4 931 tests passing en 410 ficheros. Upgrade seguro desde 2.17.1.
Cierra la auditoría de resiliencia disparada por el lanzamiento público: 15 PRs en 5 fases endureciendo Karajan contra la clase de bugs de fallo silencioso — el problema no es que algo falle, el problema es fallar sin que el usuario sepa por qué. Fase 1 — hibernación de extremo a extremo (#756–#759): un límite de cuota se clasifica como una clase recuperable (incl. "You've hit your session limit · resets 10:10pm" de Claude Code); withBrainRecovery persiste un JSON de standby; el orquestador consume action:"hibernate" y sella la sesión hibernated (reanudable) en vez de failed; la última línea impresa es el comando exacto de reanudación. Fase 2 — no mentir (#761–#763): runCommand expone ENOENT así que una CLI de agente ausente da un error accionable (no vacío); silenceTimeoutMs se propaga a todos los roles así que un agente colgado se mata, no se espera para siempre; los seis writers de estado pasan por writeJsonAtomic (write-temp + rename) — las escrituras interrumpidas ya no truncan plans / sesiones / standby. Fase 3 — no perder ni bloquear (#764–#767): un plan JSON corrupto se mueve aside con un warn alto; los errores de parse de kj.config.yml lanzan Invalid YAML in <path> (antes brickeaba todo kj incluyendo kj doctor); injectLoadedPlan reconcilia HUs dejadas en coding / reviewing / running por un kj run muerto; la SQLite del board recibe busy_timeout, un gate de user_version y recuperación ante corrupción. Fase 4 — no degradar en silencio (#768–#769): TriageRole avisa con warn cuando la salida del LLM no es parseable (antes saltaba researcher / architect / security / tester en silencio); verifyCoderOutput distingue un fallo de git de “el coder no hizo nada” — ya no se queman iteraciones culpando al agente por un fallo de infraestructura. Fase 5 — red de seguridad (#770): una suite tests/resilience/ indexa cada modo de fallo silencioso y pinea cada uno con un test. Además CI ejecuta la suite de packages/hu-board en cada PR (#755). 4 959/4 959 tests passing en 416 ficheros. Upgrade seguro desde 2.17.1.
Seis follow-ups del feedback del usuario tras v2.18.0: kj-tail tras kj resume (#772, quedaba mudo porque resume.js se saltaba withCliRunLog); el standby espera in-process en lugar de salirse en cooldowns cortos (#773, kj se queda vivo en esperas ≤ 12 h y reintenta solo; Ctrl+C durante la espera imprime kj standby resume <id>); cerrado KJC-BUG-0040 — binarios SEA de linux (#774, era una race condition entre gh release create y softprops, no better-sqlite3 como decía la memoria — fix con poll de 60 s + make_latest:false); sesgo de stack — repos Python ya no reciben vitest (#775 + #776 + #777, detectProjectStack finalmente cableado al prompt del coder, plantillas de HU del auto-generator por lenguaje, y el synthesizer + auto-hu-batch toman el stack del filesystem). 4 971/4 971 tests passing en 416 ficheros. Upgrade seguro desde 2.18.0.
Cierra KJC-PCS-0047 — la épica de consolidación del directorio home. Tres PRs encadenadas (#781, #782, #783) unifican el estado HOME de Karajan bajo una única raíz ~/.karajan/. Antes, ~/.kj/ guardaba planes, hibernación standby, run-registry y worktrees, mientras ~/.karajan/ guardaba sesiones, hu-stories, config — sin ADR que justificase el split y cuatro implementaciones divergentes de getKjHome() habían derivado. PR #781 unifica el resolver detrás de KARAJAN_HOME (con KJ_HOME aceptado + warning de deprecación una vez por proceso); PR #782 trae un auto-migrator idempotente que corre una sola vez en la próxima invocación de kj — backup tarball en ~/.karajan/backup/kj-pre-migration-<ISO>.tar.gz ANTES de mover, marker file previene re-ejecuciones, cross-device safe (rename → cp + rm con EXDEV); PR #783 hace flip de cada default a ~/.karajan/ y añade una check legacy-kj-home a kj doctor. El HU Board lee AMBAS ubicaciones hasta que el migrator se dispara, así que los usuarios que arrancan el board antes nunca ven “missing plans”. Restaurar es un tar -xzf away. 4 984/4 984 tests passing en 418 ficheros. ⚠ Salió con un bug de packaging que rompía kj board start en instalaciones nuevas — usa v2.19.1 o superior.
APPLICATION BLOCKER fix para kj board start en cualquier npm install -g karajan-code nuevo desde que se lanzó la feature del HU Board. Dos causas combinadas (PR #791): (1) el array package.json::files del root NO incluía packages/, así que npm pack --dry-run producía tarballs con cero archivos del board; (2) aunque el usuario copiase packages/hu-board/ a mano, el servidor petaba con Cannot find package 'helmet' imported from .../server.js — las cinco dependencias del HU Board (helmet, chokidar, better-sqlite3, express, express-rate-limit) estaban declaradas en packages/hu-board/package.json pero ausentes del root dependencies, y npm install -g karajan-code solo resuelve deps del root. Fix: añadir packages/hu-board/{src,public,package.json} a files; añadir las cinco deps al root a las mismas versiones exactas para que npm dedupe colapse a una copia única alcanzable por traversal hacia arriba desde server.js; regenerar package-lock.json. Verificado end-to-end: npm pack envía 28 archivos del board; el servidor arranca limpio. También interno (sin cambio user-visible): 38 callers directos de os.homedir() rerouteados por el resolver unificado (#790 — KARAJAN_HOME redirige ahora todos los componentes) y 5 construcciones inline de ~/.karajan/hu-board-runs/ unificadas bajo un helper (#789). Reportado por @aitormf.
El 401 de SonarQube ahora dispara re-bootstrap automático del token en lugar de fallar el run (KJC-BUG-0057, PR #793). bootstrapSonarToken() vivía en src/sonar/token-bootstrap.js desde v2.10.2 — probe admin/admin, rota password si sigue por defecto, revoca el token karajan-cli y genera un GLOBAL_ANALYSIS_TOKEN fresco — pero SOLO se invocaba desde kj init. Cualquier otro código path que hablase con Sonar con un token ausente / stale / revocado / de otra instancia tiraba HTTP 401 con el hint “Regenerate with kj init”, forzando al usuario a hacer plumbing que Karajan tiene los credenciales para hacer solo. El feedback del usuario fue inequívoco: “Si karajan ve que no funciona sonar, que tiene el user/passw, que genere nuevo token, karajan debe tener capacidad de hacer esto y no tiene que hacerlo la IA, es algo programatico.” Fix: src/sonar/api.js::sonarFetchOnce ahora invoca el nuevo src/sonar/token-recovery.js::recoverSonarToken() en el primer 401. Recovery tiene latch per-process (N endpoints 401-ando disparan UN bootstrap, no N), reusa bootstrapSonarToken, muta config.sonarqube.token en memoria, mirra el token nuevo a ~/.karajan/sonar-credentials.json, y la request original reintenta una vez. El usuario nunca ve el 401 cuando recovery tiene éxito. Programático, cero LLM. Reportado por @aitormf.
El HU Board lee + escribe planes desde el home dir canónico (KJC-BUG-0059, PR #795). Reportado por @aitormf: la card superior del board mostraba Directorio del proyecto — no detectado aun cuando el run tenía projectDir válido y el coder estaba leyendo ficheros de él. Causa raíz: cinco call sites del board todavía hard-coded a ~/.kj/plans/ como root de planes — supervivientes de la consolidación de home v2.19.0 que arregló sync.js pero dejó packages/hu-board/ intacto. Tras el auto-migrator (o tras crear planes nuevos post-v2.19.0), los planes vivían bajo ~/.karajan/plans/<slug>/; el board seguía mirando bajo ~/.kj/plans/<slug>/ y no encontraba nada — GET /api/projects/:id/preflight no podía extraer projectDir (el literal que Aitor veía), GET /api/projects/:id/plans-outcome devolvía plans: [] para todo proyecto, DELETE /api/projects/:id barría la ruta incorrecta dejando residuo en disco, DELETE /api/plans/:planId fallaba silencioso, plan-mutations.plansRoot escribía run logs nuevos al root legacy partiendo el estado entre ambos, y cleanup-zombies nunca GC’aba zombies bajo ~/.karajan/plans/. Fix: tres exports nuevos en packages/hu-board/src/db.js — getHuBoardPlansDir() (canónico, o KJ_PLANS_DIR override), getHuBoardLegacyPlansDir() (legacy, null si override), getHuBoardPlansDirs() ordenado [canonical, legacy?] para read callers. Single-write callers (plan-mutations) usan el canónico; read / delete / GC iteran ambos para no romper a usuarios mid-migration con planes aún bajo ~/.kj/. 349 tests del hu-board siguen verdes.
Dos bugs cerrados en un solo release: kj resume continúa donde paró, y autoInit() ya no produce commits zombie en main del usuario.
KJC-BUG-0058 (PR #798, reportado por @aitormf) — una sesión que paró durante Sonar re-ejecutaba todo el pre-loop al hacer kj resume <id>: HU-reviewer, intent, discover, triage, domainCurator, researcher, architect, planner desde cero. Doblaba coste de tokens y rompía el value-prop del comando. Causa raíz: resumeFlow llamaba a runFlow sin rehydratar stage state, y la sesión nunca persistía outputs de stage en primer lugar. Fix: dos nuevos mutators en src/session/mutators.js — setStageResult(session, name, result) mirror writes a stage_results[name] + stages_completed[] (idempotente en el array), y setStageBundle(session, name, bundle) añade stage_bundles[name] para cross-stage context que el stageResult no carga (researcher → researchContext, architect → architectContext, planner → plannedTask). Dos closures dentro de runPreLoopStages (persistStage + resumeSkip) envuelven cada stage cacheable. init-context.js rehydrata ctx.stageResults desde la sesión cargada antes de invocar el pre-loop. Triage NO se skipea — emite roleOverrides que el Brain decisor necesita y es cheap re-ejecutarla. 10 ficheros de test / 57 tests de orchestrator siguen verdes.
KJC-BUG-0060 (PR #797, reportado durante el release de v2.19.3) — git checkout main reportaba [adelante 27] ante origin/main tras ejecutar kj sobre el propio repo karajan-code (kj-linked). Cada commit titulado initial commit, autor el user.email local de karajan-code (que diverge del global), tree idéntico a su parent = commits completamente vacíos. El reflog acumulaba 2 495 SHAs con el mismo patrón desde abril 2026. Ninguno había llegado nunca a origin/main (push / CI los habrían rechazado), runtime impact cero, pero ensuciaba historia local y en cada release parecía pérdida de sync. Causa raíz: src/orchestrator/config-init.js::autoInit() guardaba con !(await exists(projectDir/.git)), falla por dos vías: (a) dogfooding kj sobre karajan-code desde un subdir → exists() devuelve false → git init reinicializa el .git/ del padre (idempotente, inocuo) → git commit --allow-empty resuelve hacia arriba y aterriza commit vacío en main del padre; (b) race FS transitoria (EACCES/ENOENT) flippea exists() a falso negativo. Fix: cambio el FS probe estático por git rev-parse --is-inside-work-tree, que hace la misma upward-traversal que git haría para el commit — el guard no puede discrepar con la operación que custodia. Drop del git commit --allow-empty -m "initial commit" que seguía al git init: ningún stage downstream necesita root commit; los 2 495 zombies nunca rompieron nada, el seed era decorativo y era el síntoma user-visible.
Cluster HU Board polish + UX papercuts — 5 cards cerradas. Dos features net-new, dos PG housekeeping syncs de trabajo que ya había aterrizado en minors previos sin cerrar PG, y un docs refresh.
KJC-TSK-0397 (PR #801) — kj plan generate prepende ahora una HU [PREFLIGHT-000] a cada plan y blockea todas las HUs funcionales sobre ella vía blocked_by. La HU lleva acceptance tests shell stack-aware para que el sub-pipeline rechace gastar tokens en trabajo funcional hasta que el entorno sea reproducible: git status --porcelain clean siempre; proyectos Node reciben node --version + npm install + npm test / npm run lint condicionales; proyectos Python reciben python --version + pip install -r requirements.txt (o poetry install) + pytest --collect-only; proyectos Firebase añaden firebase projects:list; proyectos GCP añaden gcloud auth list. Añadir un stack es una rama en composePreflightTests. La inyección es idempotente — un plan que ya tiene una HU titulada PREFLIGHT-000 / “verificar entorno” se respeta, no se duplica. Opt-out por invocación con --no-preflight-hu. Nuevo módulo src/plan/preflight-hu.js (102 LOC) + 6 acceptance tests en tests/plan/preflight-hu.test.js.
KJC-TSK-0395 (PR #802) — kj init aprende un wizard de scope más flags --global / --local. En TTY interactivo sin flags, el wizard pregunta dónde guardar la config: ~/.karajan/kj.config.yml (global, aplica a todos los proyectos) o ./.karajan/kj.config.yml (local override, project-scoped). --global y --local se saltan el prompt; pasar ambos lanza Cannot pass both --global and --local. No-interactivo sin flags se queda en global por compatibilidad con scripts CI. Más importante: loadConfig (src/config/loader.js) ahora rechaza cargar un proyecto que tiene local config sin contrapartida global — el invariante override-only-on-top-of-base — con mensaje accionable apuntando a kj init --global para crear la base. Nueva función exportada resolveConfigScope({ flags, interactive }) para que la resolución sea unit-testable sin spinning up el resto de initCommand. 5 acceptance tests en tests/commands/init-scope.test.js.
KJC-TSK-0396 (PG sync, originalmente PRs #702 + #703) — botón ⏹ Stop del HU Board. Aborta cada kj run asociado a un plan: SIGTERM a todos los PIDs tracked primero, timeout de 5 segundos, escala a SIGKILL en cualquiera que no respondió. HUs en running revierten a pending (no a failed) para que el plan se relance limpio. Visible sólo cuando al menos una HU está en coding/reviewing. El frontend usa el mismo patrón delegate-on-document que el botón ▶ Run (data-plan-id + data-pids); el backend expone POST /api/runs/:planId/stop devolviendo { stopped, killed, errors, hu_reset_count }; un registry persistente de run-tracker bridge los runs lanzados desde terminal y desde el board para que ambos paths de Stop vean los PIDs del otro. Ya shipped en v2.10.x; el release de hoy cierra la card PG con los commits canónicos como evidencia.
KJC-TSK-0377 (PG sync, originalmente PR #683) — auto-cleanup ampliado. El boot sweep del HU Board para proyectos efímeros ya barría tmp_* / test_* / demo_* / kj-test-*; el sync de hoy confirma que el mismo sweep también maneja s_* (proyectos placeholder con session-id), plan-* (placeholder con plan-id), auto-tmp_* y auto-test_*. Proyectos con is_test = 2 (📌 keep) quedan exentos sin importar el prefijo; los proyectos home-style home_<path> con repo git real nunca se barren. Ya shipped en v2.12.x.
KJC-TSK-0385 (PR #800) — docs refresh. docs/task-templates/spec-conventions.md gana dos secciones: la Sección 8 documenta que headings numerados (## 1., ### 2.1, §5) en un task file activan el campo spec_section REQUIRED en cada step emitido — sin esto, usuarios veían findings ‘missing spec_section’ en planes por lo demás buenos sin entender la regla de activación. La Sección 9 documenta la shape acceptance_tests por step: 2-4 tests, mix de gherkin (comportamiento observable) y shell (comandos concretos que exit 0 en éxito), pre-implementación, nunca el placeholder npx vitest run. La tabla quick-reference del top y el checklist pre-generate fueron actualizados. Más docs/task-templates/plan-generate.md flippea sus dos paths obsoletos ~/.kj/plans/ a ~/.karajan/plans/ (post-consolidación home v2.19.0).
Rol Onboarder brownfield. Karajan ships un path dedicado para bootstrap un Architecture Brief desde cualquier codebase existente, y el planner puede consumir ese brief como context automático. Cierra KJC-TSK-0384 en tres PRs.
KJC-TSK-0384 (PRs #804 + #805 + #806) — Tres capas de trabajo.
Capa 1 (PR #804) — collectors deterministas. Nuevo módulo src/onboarder/collectors/index.js expone cinco extractores puros, fail-soft. collectTree walks el project root ignorando node_modules / .git / dist / build / coverage / .karajan / .next / __pycache__. collectGitHistory devuelve null en greenfield, o { commitCount, branches, hotFiles, headSha } en un repo real — hot files = top N por appearance count en los últimos 200 commits del --name-only output. collectConfigs chequea presencia de 18 patrones conocidos de config y lee package.json::scripts. collectAdrs escanea docs/adr/, docs/adrs/, docs/architecture/ buscando ADR-style filenames. collectAll es el Promise.all bundle. Cada slot independiente; ningún collector aborta a los otros. 0 LLM calls, output JSON-serialisable.
Capa 2 (PR #805) — comando kj onboard + OnboarderRole. Nuevo comando CLI corre collectAll → opcional OnboarderRole.run → escribe ~/.karajan/onboarding/<slug>.md. El rol es una subclase delgada de AgentRole: extractInput acepta { bundle } o un string projectDir; parseOutput desempaqueta un bloque markdown con fences si lo hay o hace trim del raw output; handleParseNull devuelve soft-success para que greenfield nunca errore. Las instrucciones del rol viven en templates/roles/onboarder.md. Flags: --no-synth (salta la llamada LLM completamente y escribe el bundle raw dentro de un fence JSON — útil para CI / contextos sensibles al coste de tokens), --output <path> (override del target default).
Capa 3 (PR #806) — kj plan generate --use-onboarding. Nuevo src/onboarder/cache.js::readCachedBrief(projectDir) lee el brief cacheado determinísticamente usando el mismo briefPath() slug rule que usa el writer. kj plan generate gana el flag --use-onboarding; cuando está set, el brief se prepende al context del planner bajo un heading ## Architecture Brief (from kj onboard). Silent en cache miss sin el flag; loud warn cuando el flag está set pero no hay cache, para que una invocación olvidada de kj onboard surface inmediatamente. El brief compone con cualquier --context explícito que el usuario pase.
kj onboard # produce ~/.karajan/onboarding/<slug>.md una vezkj plan generate task.md \ --use-onboarding # el siguiente plan lee el brief como contextQué viene después — La épica Project RAG (KJC-PCS-0049) arranca en v2.22.0: vector store (better-sqlite3 + sqlite-vec), embedder Ollama, indexer (chokidar watcher), retriever + ranking, comandos CLI (kj rag <query> / kj rag index), tool MCP (kj_rag_query) y panel búsqueda HU Board. El Onboarder es su prerequisito — el brief alimenta la primera pasada del indexer con la estructura del proyecto ya digerida. ~1200 LOC estimadas en 8 PRs.
MVP de Project RAG (KJC-PCS-0049, seis PRs). Karajan indexa sus planes + briefs de onboarding (y opcionalmente los sources del proyecto) en un vector store local y deja consultarlos semánticamente desde la CLI. End-to-end desde terminal en v2.22.0; el tool MCP + panel HU Board aterrizan en v2.23.0.
Los seis PRs mapean uno-a-uno sobre las capas arquitectónicas — los módulos son pequeños, single-responsibility, y la cadena es reemplazable pieza por pieza.
| Step | PR | Módulo | LOC | Qué hace |
|---|---|---|---|---|
| 1 | #808 | src/rag/vec-store.js | 197 | openVecStore / insertChunk / searchSimilar / deleteChunksBySource sobre better-sqlite3 + nueva dep sqlite-vec ^0.1.9. DB en ~/.karajan/rag.db (override KJ_RAG_DB). Apertura idempotente. |
| 2 | #809 | src/rag/embedder.js | 160 | OllamaEmbedder.embed/embedBatch contra el servidor Ollama local. Defaults localhost:11434 + nomic-embed-text (dim 768). OllamaEmbedderError ante dim mismatch — un drift silencioso de dimensión corrompería el vec store con el tiempo. Cero deps nuevas (fetch global). |
| 3 | #810 | src/rag/chunker.js | 191 | Tres chunkers puros: chunkMarkdown preserva headingPath (para que el retriever muestre ‘de # Plan › ## Auth’), chunkPlan emite un chunk por HU con hu_id + title, chunkSource splittea JS/TS por symbol top-level via regex. Splitter en ventana compartido para secciones grandes (limit 800, overlap 100). |
| 4 | #811 | src/rag/indexer.js | 194 | indexFile(path, { db, embedder }) dispatcha por extension + path → chunker → embed → insertChunk. Idempotente (llama deleteChunksBySource primero). Fallo del embedder en un chunk = warn + continúa, el loop nunca aborta. indexProject(projectDir, { withSources }) walks plans + brief de onboarding; sources gated tras --with-sources. |
| 5 | #812 | src/rag/retriever.js | 105 | query(db, embedder, text, { topK, scope, kindBoost }) over-fetchea topK * 2 (clampeado a 50) para dar margen al rerank, aplica kind boosts (plan +0.05, onboarding +0.03, code 0) que rompen ties sin reordenar a través de gaps grandes de distancia. |
| 6 | #813 | src/commands/rag.js + src/cli/register-meta.js | 160 | kj rag index [--with-sources] [--json] + kj rag query <text> [--scope plans|code|onboarding|all] [--top-k N] [--json]. Bail-out con hint claro Run kj rag index first si el store está vacío. Los hits se imprimen como bloques de tres líneas con el label de metadata más específico (hu_id > symbol > headingPath). |
Workflow end-to-end:
cd ~/tu-proyectokj onboard # Architecture Brief en ~/.karajan/onboarding/<slug>.mdkj plan generate task.md -y # Plans en ~/.karajan/plans/<slug>/plan-*.jsonkj rag index # Sembrar el vec storekj rag query "¿cómo manejé auth en el módulo X?"La cadena compone con el Onboarder de v2.21.0: el brief siembra al indexer con la estructura del proyecto (stack, hot files, ADRs), así que las queries semánticas encuentran el plan o HU correcto sin re-walkear el repo cada vez.
El binario SEA stubea RAG y HU Board de la misma forma. src/rag/* + src/commands/rag.js se unen a packages/hu-board/src/* en la lista de módulos que scripts/esbuild-sea.config.mjs reescribe a build time — ambos subsystems dependen de better-sqlite3 (native node-gyp, sin entry JS) y romperían la build SEA. Usuarios standalone reciben un error accionable apuntando a npm install -g karajan-code.
Viene en v2.23.0 — Tool MCP kj_rag_query para que otros agentes (Claude Desktop, el propio pipeline de Karajan) puedan hacer las mismas preguntas; panel de búsqueda HU Board con el retriever wireado a la misma UI que el kanban; chokidar watcher para re-indexing en vivo en lugar de on-demand; chunker AST-aware (tree-sitter o @babel/parser); scoring híbrido BM25 + cosine.
RAG expuesto a agentes y humanos por igual (KJC-PCS-0049 Steps 7+8+Camino A). Tras el MVP CLI de v2.22.0, el corpus deja de ser una feature solo-para-humanos. Tres PRs traen tres consumidores nuevos:
| Consumidor | PR | Módulo | Cómo |
|---|---|---|---|
| Agentes MCP (Claude Desktop, Cursor, Claude Code, los propios roles de Karajan) | #815 | src/mcp/handlers/rag-handler.js + src/mcp/tools.js | Nuevos tools kj_rag_query + kj_rag_index. Tool count 25 → 27. Misma shape que la CLI. Store vacío responde empty: true para que el agente tenga señal determinista de recovery. |
| Usuarios de navegador | #816 | packages/hu-board/src/routes/api.js + public/app.js | Nuevo endpoint POST /api/rag/query + panel entre la preflight card y el kanban — input + dropdown de scope (All / Plans / Onboarding / Code) + botón Search + pane de resultados. Los hits se renderizan como cards con borde, kind + label + score + source + texto truncado. |
| Roles del pipeline (coder, researcher, architect, planner, spec-reviewer) | #817 | templates/roles/*.md | Sección ‘Prior context (RAG, opt-in)’ personalizada por rol. Los agentes SABEN ahora que el tool existe, qué topK / scope usar, y que un store vacío significa proceder-sin-retrieval, no bloquear-y-preguntar. |
El contract unificador a través de los tres: retrieval opt-in. Cuando el corpus está vacío (proyecto greenfield, instalación recién hecha, kj rag index sin correr aún), cada consumidor degrada a sin-retrieval en lugar de bailar o molestar al humano.
Workflow end-to-end:
kj onboard # una vez por proyecto — Architecture Briefkj rag index # una vez por proyecto — siembra el corpuskj plan generate task.md --use-onboarding# A partir de aquí:# - Coder llama kj_rag_query antes de tocar APIs poco familiares.# - Planner pregunta por planes pasados que puedan exponer un marker de reuse.# - Researcher evita re-walkear el repo cuando el corpus ya tiene la señal.# - Architect alinea con patrones previos.# - Spec-reviewer surface findings de scope_overlap contra HUs aprobadas.# Los humanos tienen el mismo retriever en el panel de búsqueda del HU Board.Guía por rol (literal de los templates):
topK: 3, scope: 'all'. Casos de uso: ‘cómo el proyecto manejó una concern similar antes (auth, error model, retry policy, naming convention…)’. Cap fuerte: una query por concern, no por fichero.topK: 5, scope: 'plans'. Antes de re-walkear el repo. Cita evidence retrievada como bullets bajo affects; NO pegues chunks raw.topK: 3, scope: 'all'. Cuando una decisión de diseño toca un area que el proyecto ya formó.topK: 5, scope: 'plans'. Antes de emitir blocked_by / dependencies / reuse. Si un plan previo produjo la utility que el nuevo necesita, marca reuse: [<hu-id>] en lugar de re-implementar — cierra el loop con KJC-BUG-0044 (P3).topK: 3, scope: 'all'. Si chunks retrievadas describen HUs ya aprobadas que solapan, surface como kind: 'scope_overlap' referenciando el id de la HU previa.Viene en v2.24.0+ — Camino B (slash command /kj-rag-query para hosts en modo Skills sin MCP), Camino C (pre-loop stage automática que pre-fetcha retrieval y la prepende al prompt del coder/researcher/architect sin que el agente tenga que pedirla — transparente + automático), Camino D (heurística Brain decisor para cuando retrieval merece la pena en tokens). Más chokidar watcher para re-indexing en vivo, chunker AST-aware, scoring híbrido BM25 + cosine.
RAG Camino C — pre-loop auto-retrieval (KJC-PCS-0049). La cuarta capa de integración RAG tras v2.22.0 (CLI), v2.23.0 (MCP + Board + role instructions). Donde Camino A enseñó a los agentes que kj_rag_query existe para queries on-demand, Camino C hace que Karajan inyecte el context por ellos automáticamente — transparente, sin llamada MCP por parte del agente.
El movimiento arquitectónico: en lugar de hacer fan-out de un ‘prompt builder RAG-aware’ por cada rol (researcher, architect, planner, coder), Karajan muta el parámetro task una vez, en el pre-loop driver, entre triage y domainCurator. Como task ya fluye a través de runPlanningPhases hacia cada stage downstream vía parameter passing, una mutación alimenta seis consumidores con cero cambio de código por stage. El coste de tokens se paga una vez por kj run, no por rol.
Cinco guards antes de que el retrieval llegue a dispararse (src/orchestrator/stages/rag-context-stage.js):
| Guard | Devuelve skipped con reason | Comportamiento |
|---|---|---|
config.rag.preload.enabled ausente/false | disabled | No-op silente. Estado default — opt-in. |
task vacío/no-string | no-task | Silente — el intent classifier a veces nos pasa string vacío. |
| Vec store con cero chunks | empty | Info log apuntando a kj rag index; el template del propio rol (Camino A) ya le dice que no bloquee en esto. |
| Retriever devuelve cero hits | no-hits | Silente — la query puede simplemente no matchear nada en el corpus. |
| Embedder / network / vec store throws | error | Warn log + continúa. El pipeline nunca ve la excepción. |
La stage nunca throws — best-effort enrichment, opt-out por defecto, opt-back-out en fallo. El contract es: es seguro wirearlo en pre-loop incondicionalmente porque el peor caso es no-op + warn.
Cuando los cinco guards pasan, el parámetro task recibe un bloque markdown ready-to-prepend:
## Prior context from RAG (auto-retrieved, top N)
### [plan · AUTH-1] /path/to/plan.json
<chunk text, truncated 600 chars>
### [plan · ARCH-3] /path/to/plan-2.json
<chunk text…>La regla de resolución de label (hu_id > symbol > headingPath > 'block') matchea el renderer de la CLI en src/commands/rag.js y el panel del HU Board de v2.23.0 — agentes viendo el context vía auto-retrieval, humanos viéndolo vía CLI, y humanos viéndolo vía panel del Board leen todos la misma shape.
Toggle + tuning:
rag: preload: enabled: true # default: false (opt-in) topK: 5 # default: 5 scope: all # default: all — también: plans | code | onboarding embedder: dim: 768 # default: 768 (nomic-embed-text) model: nomic-embed-text url: http://localhost:11434Compatibilidad con Camino A (v2.23.0): complementarios, no redundantes. Los role templates de PR #817 siguen diciéndoles a los agentes que kj_rag_query existe para queries on-demand — distinto a la inyección automática del pre-loop. Con ambos activos, el flujo típico es: pre-loop da al agente prior context en el kickoff; el agente lo usa; si necesita retrieval más granular mid-task, invoca kj_rag_query directamente.
Workflow con v2.24.0:
cd ~/tu-proyectokj onboardkj rag indexyq -i '.rag.preload.enabled = true' ~/.karajan/kj.config.ymlkj run task.md# researcher/architect/planner/coder ven todos prior context en su# task prompt al inicio de la iteración. Pueden seguir llamando# kj_rag_query para preguntas follow-up.Viene en v2.26.0+ — chokidar watcher para re-indexing en vivo sin kj rag index on-demand, chunker AST-aware (tree-sitter o @babel/parser) reemplazando el regex de export-symbol, scoring híbrido BM25 + cosine para mejor precisión en queries keyword-heavy.
RAG Camino B + Camino D (KJC-PCS-0049). Cierra el plan de superficies de consumo arrancado en v2.22.0. El retriever ya se alcanza desde todos los contextos de host relevantes, y el pre-loop stage de v2.24.0 sólo paga su coste cuando triage indica que la recuperación merece la pena.
Camino B — slash command /kj-rag-query para hosts Skills. Nuevo templates/skills/kj-rag-query.md. kj init lo despliega a .claude/commands/ para que los hosts que cargan Karajan vía Skills — Claude Code sin MCP, Cursor sin MCP — alcancen el retriever RAG con un slash command en vez de necesitar la herramienta MCP kj_rag_query. Wrapper delgado sobre el CLI existente:
/kj-rag-query <texto> [--scope <all|plans|onboarding|code>] [--top-k <n>]El skill delega la validación de flags al CLI (fuente única de verdad), surface el store vacío como hint de una línea sin bloquear la conversación, y renderiza los hits como bloques [score] source — snippet en lugar de JSON crudo.
Camino D — heurística Brain decisor para retrieval pre-loop. Nuevo módulo src/orchestrator/stages/rag-preload-decisor.js. Función pura shouldPreloadRag({ triage, task, config }) → { pull, reason } cableada en pre-loop.js antes de runRagContextStage (v2.24.0). Añade una nueva clave de configuración:
rag: preload: enabled: true policy: auto # auto | always | never (default: auto) brownfield: false # señal explícita — siempre pulls cuando truealways — pull en cada run (back-compat con v2.24.0).never — nunca pulls (benchmarking, debugging).auto (default) — heurística. Pulls cuando cualquiera de:
triage.shouldDecompose === true (run multi-HU; el contexto previo beneficia a researcher/architect/planner)triage.level ∈ {complex, high, epic}task.length >= 200 chars (un brief largo suele indicar scope no-trivial)config.rag.preload.brownfield === trueSi no, el stage persiste ragPreload: { skipped: true, reason: 'auto:low-value' } y el pipeline no paga retrieval en tasks triviales. El motivo del decisor también se persiste junto al conteo de hits cuando retrieval sí dispara — resume y audit pueden ver exactamente por qué retrieval corrió (o no) en cualquier sesión pasada.
Por qué los dos a la vez: B y D son superficies independientes — uno extiende alcance, el otro refina coste. Se publican juntos para que el arco RAG v2.22.0 → v2.25.0 cierre en un solo release en vez de gotear en varios minors.
Viene en v2.27.0+ — chokidar watcher (re-indexing en vivo), chunker AST de fuentes, scoring híbrido BM25 + cosine, adapters OpenAI/Voyage para usuarios sin Docker local.
RAG Auto-Bootstrap (KJC-PCS-0049). Cierra la fricción detectada en el dogfooding de v2.25.0: el RAG estaba técnicamente completo pero invisible para nuevos usuarios — tenían que instalar Ollama manualmente para que kj rag index, kj rag query, la herramienta MCP o el auto-retrieval pre-loop hicieran algo. Desde v2.26.0, el embedder simplemente está ahí.
kj init provisiona Ollama en Docker. Tres pasos integrados:
src/rag/ollama-capability.js valida que el demonio Docker es alcanzable y hay >= 4 GB RAM libre. Devuelve { capable, reasons[] } agregado.ollamaUp() escribe ~/.karajan/docker-compose.ollama.yml y arranca el container kj-ollama, después waitForOllamaReady() polea /api/tags hasta healthy.docker exec kj-ollama ollama pull nomic-embed-text rellena el modelo embedder (~270 MB en primer arranque; cacheado luego en el volumen kj_ollama_data).Nunca rompe init: Windows sin Docker Desktop, Linux con menos de 4 GB libres, o --no-ollama explícito degradan a warning de una línea y continúan. Hosts con Ollama corriendo ya en :11434 se detectan vía el patrón discover-before-spawn (igual que SonarQube): la instancia existente se reutiliza, sin segundo container.
kj doctor surface el estado de Ollama:
rag.preload.enabled | Container | Doctor reporta |
|---|---|---|
false (default) | irrelevante | info: Disabled in config — silencio en greenfield |
true | reachable | info: Reachable at <host> |
true | unreachable | warn con fix hint kj ollama start |
Subcomando kj ollama para lifecycle sin docker compose:
kj ollama start # provisiona + arranca (idempotente)kj ollama stop # docker compose stopkj ollama status # host + container + reachablekj ollama pull <model> # docker exec ... ollama pull <m>Bug fix bundled — el mismo smoke test de v2.25.0 que descubrió el gap de bootstrap también cazó KJC-BUG-0061: kj onboard --no-synth silenciosamente ignorado (Commander mapea --no-synth a flags.synth=false, no flags.noSynth=true); el branch synth invocaba OnboarderRole.run() sin init(), rompiendo el comando directamente; y kj rag query --json en store vacío emitía [] en vez del shape { hits, empty, topK, scope } que el handler MCP devuelve, rompiendo el contrato que el skill /kj-rag-query de v2.25.0 prometía a los hosts Skills. Los tres arreglados en PR #824 y embarcados con v2.26.0.
Pasada de calidad del RAG (KJC-PCS-0049 continuación). Cinco PRs aterrizan la siguiente capa del track RAG: visibilidad, más providers, queries más finas, mejor ranking final.
Dashboard de retrieval en el HU Board (PR #843). Nueva página standalone en /rag.html, enlazada desde la nav principal. Muestra total de chunks, tamaño de DB, último indexado, embedder activo + dim, conteos por kind (code / plan / onboarding) y por proyecto (top 20). Backend GET /api/rag/stats lee la rag.db local read-only y la sección embedder del kj.config.yml. Estado vacío cuando la DB no está inicializada. Primera pieza del roadmap config-UI v2.30 — el board crecerá controles editables (toggles de roles, swap de embedder, alpha/mode/rerank) sobre la misma superficie.
Cohere + Mistral embedder adapters (PR #848). embed-multilingual-v3.0 (1024 dim, fuerte multilingüe) y mistral-embed (1024 dim, EU-hosted para usuarios sensibles a GDPR). KJ_COHERE_KEY / KJ_MISTRAL_KEY Karajan-scoped. El slot original “Anthropic via OAuth” se descarta — Anthropic no tiene endpoint de embeddings; Cohere + Mistral cubren ese hueco con servicios first-party.
Embedder local ONNX (PR #??). Sexto provider, totalmente local: sin Docker, sin API key, sin servicio externo. Cargado dinámicamente vía @huggingface/transformers (legacy @xenova/transformers respetado como fallback). Default Xenova/all-MiniLM-L6-v2 (384 dim, ~80 MB cacheados primera vez). Opción de mayor calidad Xenova/jina-embeddings-v2-base-en (768 dim) seleccionable vía KJ_ONNX_EMBED_MODEL. Ambos paquetes transformers son peer deps opcionales — no se instalan automáticamente (combined ~500 MB con WASM + ONNX runtime); el adapter lanza hint de instalación útil si faltan. Pieza clave para el zero-config init de v2.31: default sensato con cero infraestructura.
Filtro --where de metadata por chunk (PR #??). Nuevo flag CLI con gramática KEY=VALUE AND KEY=VALUE (AND case-insensitive, strings entre comillas para valores con espacios):
kj rag query 'login flow' --where 'symbol=loadConfig'kj rag query 'auth' --where 'hu_id=HU-003 AND kind=plan'kj rag query 'router' --where 'kind=code AND symbol=createRouter'kind casuística contra la columna; cualquier otra key va por SQLite json_extract(c.metadata, '$.<key>') = ?, así cualquier metadata que el chunker emita (symbol, hu_id, headingPath, file, …) es queryable sin cambios de schema. El filtro aplica uniformemente a ambos lados (semantic y BM25) del retriever híbrido.
Rerank cross-encoder (PR #??). Flag opt-in --rerank re-puntúa los topK supervivientes con un cross-encoder (query, passage). Default Xenova/ms-marco-MiniLM-L-6-v2 (estándar de facto de sentence-transformers, ~80 MB cacheados primera vez). Los cross-encoders son más lentos que los bi-encoders (encodean el par junto en lugar de cachear el passage), pero materialmente más precisos para el ranking final — Karajan lo corre solo sobre los supervivientes post-fusion + post-boost, así la latencia se mantiene acotada. Encaja después de los boosts kind+source, actuando como una palanca de calidad de grano más fino.
UI de config editable en el HU Board (KJC-PCS-0042). Cuatro PRs aterrizan el modal de settings end-to-end: los teaser de v2.29 (toggle de roles, swap de embedder, alpha/mode/rerank) se vuelven editables sin abrir nunca kj.config.yml.
Toggles de roles del pipeline (PR #854, KJC-TSK-0450). Modal con sección “Pipeline roles” donde activas/desactivas roles individuales (researcher, architect, refactorer, security, audit, rag-context). El backend persiste vía la whitelist EDITABLE_FIELDS de config-yaml.js con escritura atómica (tmp + rename) y backup .bak. La estructura YAML del usuario se preserva — sin reformateo, sin pérdida de comentarios.
Controles de RAG (PR #855, KJC-TSK-0451). Sliders + selects para rag.search.{mode,alpha,rerank}. mode ∈ {hybrid, semantic, bm25}. alpha 0-1 (peso semantic vs lexical en hybrid). rerank toggle. Live preview del payload antes de guardar.
Secciones agrupadas en el modal de config (PR #856, KJC-TSK-0452). Reorganización visual: Pipeline / RAG / Coder / Reviewer / Brain en bloques colapsables. Reduce scroll, mejora la legibilidad cuando el config crece.
Toggle de scope: global vs per-proyecto (PR #857, KJC-TSK-0453). Nuevo switch en cada sección eligiendo dónde escribir: 'global' → ~/.karajan/kj.config.yml, 'project' → <projectDir>/.karajan/kj.config.yml. Resolución projectDir vía process.env.KJ_PROJECT_DIR || process.cwd(). El config del proyecto sobrescribe el global cuando ambos existen.
Viene en v2.31.0+ — zero-config init (wizard reducido a una pregunta crítica, defaults inteligentes para todo lo demás) sobre la base de un ~/.karajan/kj.config.yml que ahora se puede editar desde el board sin abrir un editor.
HU Board compartido en equipo (KJC-PRP-0002). Siete PRs (#859–#865) cierran el cohort multi-máquina end-to-end. Un plan ya no vive solo en ~/.karajan/plans/<planId>/: opt-in con kj plan share <planId> lo copia al .karajan-shared/plans/<planId>/, donde toda máquina que corra Karajan sobre el mismo proyecto puede verlo y reclamar partes del mismo plan.
Merge en loader + scan del board (PR1 / PR2). loadPlan() fusiona las HUs compartidas con el plan del proyecto, deduplica por id. El scanner del HU Board lee también .karajan-shared/ junto al cohort local, marca is_shared = 1 en los chunks que vienen de allí, y la API lo expone como un badge shared — visible de un vistazo, sin desplegar menús.
Round-trip unshare + assignee (PR3 / PR6). kj plan unshare revierte el share atómicamente (se borra la copia compartida; la local se queda). El nuevo campo assignee por HU es parte de EDITABLE_HU_FIELDS, así dos runners pueden repartirse el cohort sin sobreescribirse.
Share selectivo + política de conflictos (PR4 / PR5). --only id1,id2 y --exclude id3,id4 filtran qué HUs salen del cohort local. Cuando la misma HU existe en local y en shared (ediciones concurrentes en máquinas distintas), sharedConflictPolicy decide: local-wins (default), shared-wins, o error (rechaza cargar y fuerza resolución manual).
Cache en el frontend (PR2). projectIsSharedCache memoiza el lookup por proyecto para que la UI del board no machaque la API en cada render de HU.
Esto cierra el prerequisito de team-shared HU Board (KJC-PRP-0002) — la última pieza antes de que la reescritura del Brain en v3.0 pueda apoyarse en un substrato multi-runner estable.
AI Harness Scorecard hardening (KJC-PCS-0051). El Plan A cierra cinco FAILs del scorecard externo en un mismo sprint, más dos bug fixes que viajan junto a la release.
Prettier --check en CI (PR #868, KJC-TSK-0464). Un nuevo job format bloquea PRs cuyo formato se desvía de .prettierrc.json. Scope intencionalmente acotado al inicio (.github/workflows/, raíz) según .prettierignore; futuras PRs amplían el alcance bajo el shrink-budget.
Coverage v8 + artefacto CI (PR #870, KJC-TSK-0465). vitest.config.js ahora emite text + html + lcov vía @vitest/coverage-v8. El nuevo job coverage corre npm run test:coverage y sube coverage/ como artefacto descargable (retención 14 días). Thresholds por glob enforced cuando el usuario opta in; el suelo de src/mcp/handlers/** rebajado a 70/60 (era 80/80) para anclar el estado actual — follow-up trackeado para volver a subir.
Conventional Commits en el head del PR (PR #872, KJC-TSK-0466). wagoid/commitlint-github-action@v6 valida cada mensaje de commit del PR contra .commitlintrc.json. Enforcement en CI sobre el hook pre-commit local existente — saltarse husky ya no esquiva la puerta.
Nightly drift workflow (PR #873, KJC-TSK-0467). Nuevo .github/workflows/nightly.yml re-corre todo el CI (lint + syntax + tests + format) cada noche a las 04:17 UTC contra main. Los fallos auto-abren o actualizan un issue de tracking etiquetado drift vía actions/github-script@v8, así una dep flaky o una regresión upstream aflora en menos de 24 h en vez de en el siguiente PR no relacionado.
Política eslint-plugin-security (PR #874, KJC-TSK-0468). eslint.config.js bloquea eval, new Function, implied evals tipo Function, require dinámico, pseudoRandomBytes y la desactivación del escape de mustache como errores duros; marca detect-non-literal-regexp como warn (14 warnings aceptados, listados para follow-up). Las reglas ruidosas del preset recomendado están intencionalmente NO habilitadas (detect-object-injection, detect-non-literal-fs-filename, detect-child-process) para evitar falsos positivos en código legítimo del orchestrator.
Bug fixes junto a la release. PR #869 (KJC-BUG-0065) reparó 42 tests rotos en main para que el sprint de hardening salga de una base limpia. PR #871 (KJC-BUG-0066) añadió el await que faltaba en openEditor del refine-loop del spec-reviewer, eliminando una race donde el diff de hash SHA leía el contenido v2 antes de que el usuario terminase de editar.
AI Harness Scorecard métrica dorada (KJC-PCS-0051, Plan B). El Plan B convierte kj audit en un loop de calidad medible. Cada run produce un número determinista y una nota A–F para responder a “qué tan AI-friendly es este repo hoy vs la semana pasada”, con cero tokens LLM gastados en la métrica.
Bootstrap Docker de ai-harness-scorecard (PR #877, KJC-TSK-0470). kj audit auto-pulla addyosmani/ai-harness-scorecard en el primer uso (~10 s warm) y corre un scan one-shot contra el cwd. El bootstrap sigue el mismo patrón default-on-con---no-* que Ollama en v2.26.0 — --no-harness permite opt-out en entornos air-gapped.
Integración en el report de audit (PR #878, KJC-TSK-0471). El score (0–100) y la nota (A–F) del harness se splice en el headline del audit report junto a los findings deterministas. Paridad CLI/MCP preservada; el payload JSON expone harness.score, harness.grade, harness.checks[] para tooling downstream.
DB de histórico per-proyecto (PR #879, KJC-TSK-0472). Cada run de audit se persiste en .karajan/audit-history.db (SQLite + WAL, PRAGMA user_version=1). El schema captura run_id, started_at, score, grade, checks_json, commit_sha. La DB es per-proyecto (gitignored por defecto) y sobrevive releases vía migraciones versionadas.
Diff vs baseline + sparkline de tendencia (PR #880, KJC-TSK-0473). El report de audit muestra ahora el delta vs el baseline anterior (Δ +7 vs run #12 de 2026-05-21) y un sparkline Unicode opcional (▁▂▃▄▅▆▇█) con la tendencia de los últimos N runs. Edge cases cubiertos: primer run (sin diff), baseline stale (>30 días), commit SHA faltante. 12 tests nuevos en tests/audit/audit-history-display.test.js cubren firstRun, diff, biggest delta, stale baseline y los edge cases del sparkline.
5 250+ tests pasando en 466 ficheros. Los cuatro PRs (#877–#880) cierran KJC-PCS-0051 entera — el Plan A (v2.32) arregló los FAILs señalados por el audit externo del scorecard; el Plan B (v2.33) hace del scorecard una señal de primera clase dentro del propio audit de Karajan.