navori 0.11.3 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +42 -56
  2. package/dist/assets/core/core-assets/agents/architect.md +1 -1
  3. package/dist/assets/core/core-assets/agents/implementer.md +9 -5
  4. package/dist/assets/core/core-assets/agents/orchestrator.md +7 -5
  5. package/dist/assets/core/core-assets/agents/publisher.md +23 -42
  6. package/dist/assets/core/core-assets/agents/reviewer.md +25 -21
  7. package/dist/assets/core/core-assets/hooks/_partials/audit-log.sh +2 -2
  8. package/dist/assets/core/core-assets/hooks/_partials/audit-signal.sh +1 -1
  9. package/dist/assets/core/core-assets/hooks/_partials/bash-outcome.sh +28 -3
  10. package/dist/assets/core/core-assets/hooks/_partials/draft-body.sh +216 -0
  11. package/dist/assets/core/core-assets/hooks/_partials/hook-input.sh +7 -1
  12. package/dist/assets/core/core-assets/hooks/_partials/inert-skeleton.sh +352 -0
  13. package/dist/assets/core/core-assets/hooks/_partials/resolve-worktree.sh +5 -4
  14. package/dist/assets/core/core-assets/hooks/comment-draft-confirm.sh +14 -195
  15. package/dist/assets/core/core-assets/hooks/guard-destructive.sh +142 -325
  16. package/dist/assets/core/core-assets/hooks/managed-drift-watch.sh +10 -0
  17. package/dist/assets/core/core-assets/hooks/pr-publisher-confirm.sh +36 -0
  18. package/dist/assets/core/core-assets/hooks/quality-gate-pre-commit.sh +106 -36
  19. package/dist/assets/core/core-assets/hooks/session-start-context.sh +28 -2
  20. package/dist/assets/core/core-assets/hooks/subagent-no-background.sh +42 -9
  21. package/dist/assets/core/core-assets/hooks/worktree-reclaim.sh +11 -0
  22. package/dist/assets/core/core-assets/managed/cierre-sesion.md +2 -2
  23. package/dist/assets/core/core-assets/managed/intake-tickets.md +2 -2
  24. package/dist/assets/core/core-assets/managed/sdd.md +4 -2
  25. package/dist/assets/core/core-assets/skills/resolve-ticket.md +13 -2
  26. package/dist/assets/core/core-assets/skills/review-diff.md +1 -1
  27. package/dist/assets/core/core-assets/skills/scoped-gate.md +1 -5
  28. package/dist/assets/core/core-assets/skills/security-invariants.md +3 -3
  29. package/dist/assets/core/core-assets/skills/solution-design.md +3 -1
  30. package/dist/assets/core/core-assets/skills/spec-bootstrap.md +6 -4
  31. package/dist/assets/plugins/gh/plugin.json +2 -8
  32. package/dist/index.js +1595 -547
  33. package/package.json +4 -5
  34. package/dist/assets/core/core-assets/hooks/_partials/scan-scope.sh +0 -113
  35. package/dist/assets/plugins/gh/managed/gh-protocol.md +0 -12
  36. package/dist/assets/plugins/jscpd/managed/jscpd-protocol.md +0 -10
  37. package/dist/assets/plugins/jscpd/plugin.json +0 -57
  38. package/dist/assets/plugins/jscpd/scripts/check-jscpd.sh +0 -329
  39. package/dist/assets/plugins/jscpd/skills/jscpd-review.md +0 -26
  40. package/dist/assets/plugins/semgrep/plugin.json +0 -51
  41. package/dist/assets/plugins/semgrep/scripts/check-semgrep.sh +0 -345
  42. package/dist/assets/plugins/semgrep/skills/semgrep-review.md +0 -27
package/README.md CHANGED
@@ -18,6 +18,9 @@ También renderiza un harness Codex completo: `AGENTS.md`, skills en
18
18
 
19
19
  // Solo guía universal, con el menor número de archivos
20
20
  { "engines": ["agents-md"] }
21
+
22
+ // Solo Pi (opt-in; ver docs/pi.md)
23
+ { "engines": ["pi"] }
21
24
  ```
22
25
 
23
26
  `codex` ya incluye y administra `AGENTS.md`; no necesitas combinarlo con
@@ -41,7 +44,7 @@ npx navori init
41
44
  cd ~/tu-repo
42
45
  navori init --recommended
43
46
 
44
- # + proveedores externos (tgrep, semgrep, jscpd, acli) + pre-commit hook +
47
+ # + proveedores externos (tgrep, acli) + pre-commit hook +
45
48
  # scan-monorepo + project block estricto — requiere instalar los binarios de esos proveedores.
46
49
  # También avisa si falta algún binario y cómo instalarlo, sin instalarlo nunca.
47
50
  navori init --full
@@ -115,7 +118,8 @@ de caché de ambos directorios.
115
118
  | `remove <plugin>` | Desactiva un plugin y limpia sus bloques managed, sub-bloques y scripts |
116
119
  | `configure <section>` | Ajusta una sección del config sin re-correr el wizard |
117
120
  | `adopt <path>` | Toma un archivo de `.claude/` que escribiste a mano bajo gestión de navori: lo envuelve en un bloque managed sin reescribir su contenido (preview por default) |
118
- | `update` | Re-detecta el repo, refresca config y corre sync en un paso |
121
+ | `refresh` | Re-detecta el repo, refresca config y corre sync en un paso |
122
+ | `update` | Actualiza el propio navori desde npm y luego corre `refresh` con el binario nuevo (ver [Actualizar navori](#actualizar-navori)) |
119
123
  | `render` | Genera los archivos nativos de cada engine configurado (preview por default; `--apply` escribe). `--all` renderea todos los repos del registro global; `--prune` limpia los que ya no existen |
120
124
  | `registry <sub>` | Registro global de tus repos con navori, para `render --all` (`ls`, `scan <dir>`, `add`, `remove`, `prune`) |
121
125
  | `sync` | Refresca todos los engines configurados con conflict resolution + backups. Los bloques en conflicto se resuelven con `--interactive` (diff, keep-mine / accept-new) o en bloque con `--accept-new` / `--keep-mine`. Los archivos completos sin marcador se resuelven archivo por archivo en modo interactivo (diff, keep / accept); `--accept-new-files` acepta en bloque los resolvibles |
@@ -124,17 +128,17 @@ de caché de ambos directorios.
124
128
  | `doctor` | Audita el config + drift de cada managed block (CLAUDE.md **y AGENTS.md**), orden canónico, markers malformados, desincronización de monorepo y tools externas faltantes (`--strict` para CI). Informativo, sin afectar `--strict`: versiones instaladas con problema conocido (`externalTool.versionAdvisory`) y avisos de versiones nuevas de herramientas (`navori tools notice`) |
125
129
  | `status` | Snapshot rápido: config, plugins activos, conteo de drift y próximos pasos |
126
130
  | `audit` | Reporta cómo corrió el harness de verdad: atribución de tokens, huecos de adherencia y outcomes de revisión y receipt; disponibilidad de herramientas por ventanas; eficiencia y ciclo de vida por tarea aceptada. `--snapshot` guarda una foto nombrada del rango y `--compare` la contrasta con otra por cohorte, con causas y evidencia |
127
- | `receipt <sub>` | Recibo de los bytes revisados antes de publicar: `sign` (`--feature <id>`, `--gate-ran scoped\|full`, `--spec <dir> --milestone <Mn>`), `check`, `gate --spec <dir> --milestone <Mn>` (decide si el milestone necesita el gate acotado o el completo) y `review begin` / `review seal --nonce <n>` (sidecar de revisión con identidad de contenido). Flags comunes: `--target <ref>`, `--dir <path>`, `--json` |
131
+ | `gate <fast\|full>` | Corre `qualityGate.fast` o `qualityGate.full` con la salida completa en un log (`.navori/state/gate/`) y solo un veredicto compacto en stdout. Flag: `--cwd <path>` |
132
+ | `receipt <sub>` | Recibo de los bytes revisados antes de publicar: `sign` (`--feature <id>`, `--gate-ran scoped\|full`, `--spec <dir> --milestone <Mn>` o `--phase <name\|index>`), `check`, `gate --spec <dir> --milestone <Mn>` o `--phase <name\|index>` (decide si el milestone necesita el gate acotado o el completo) y `review begin` / `review seal --nonce <n>` (sidecar de revisión con identidad de contenido). Flags comunes: `--target <ref>`, `--dir <path>`, `--json` |
128
133
  | `spec <classify\|check> <feature>` | `classify` decide si una spec sale en 1 PR o en una PR por entrega (umbrales de `sdd.deliveries`); `check` valida su `tasks.md`: milestones, criterios, cobertura y entregas verticales. Flags: `--cwd`, `--json` |
129
134
  | `tools notice [--ack <pluginId@x.y.z,…>]` | Emite los avisos de versiones de herramientas externas pendientes para el hook de arranque; `--ack` los marca como entregados |
130
- | `handoff <check>` | Valida el handoff del implementer (`impl_<feature>.json`) antes de despachar al siguiente agente (`navori handoff check <feature> [--for scribe] [--dir <path>] [--cwd <checkout>] [--json]`) |
135
+ | `handoff <check\|log-review>` | `check` valida el handoff del implementer (`impl_<feature>.json`) antes de despachar al siguiente agente; `log-review <feature>` valida `review_<feature>.json` y agrega a `findings.jsonl` los hallazgos con score >= 50 (`navori handoff check <feature> [--for scribe] [--produced-by reviewer [--since <iso>]] [--dir <path>] [--cwd <checkout>] [--json]`) |
131
136
  | `plan <sub>` | Planificación por niveles (`harness.planTiers`): `classify [--files\|--diff]` mide complejidad y nivel de una tarea, `render`/`update` mantienen el workplan Markdown en sync con su JSON, `check` valida su esquema y reglas, `gate` es el hook `PreToolUse(Agent)` que niega el despacho sin workplan válido |
132
137
  | `master <sub>` | Flujo guiado del plan maestro por etapas (`init`, `ux`, `mode`, `template`, `check`, `advance`, `status`, `part`, `close`) y entregas de sus partes: `delivery-slice`, `delivery-check`, `delivery-baseline`, `delivery-queue`, `delivery-criterion`, `delivery-review`, `delivery-present`, `delivery-decision`, `delivery-publication`, `delivery-revoke`. Las que autorizan o aprueban llevan `--approved-by` |
133
138
  | `bench` | Corre `render` en dry-run N veces y reporta latencias (detecta regresiones locales) |
134
139
  | `workspace <sub>` | Gestiona workspaces cross-repo (`init`, `ls`, `show`, `link`, `add-repo`, `set-default`, `render`, `rename`, `delete`) |
135
140
  | `ticket <sub>` | Gestiona tickets-as-files en un workspace (`new`, `list`, `show`, `archive`, `delete`) |
136
141
  | `dominio <sub>` | Base de conocimiento durable del workspace (`init`, `list`, `show`, `reindex`, `doctor`, `inject`) |
137
- | `global <sub>` | Harness base por máquina en `~/.claude` (`init`, `render`, `doctor`, `uninstall`) — opt-in explícito y aditivo. `global collect install` / `uninstall` gestionan el receptor OTel que alimenta `audit --collect` (launchd, solo macOS) |
138
142
  | `codex <sub>` | Comandos específicos de Codex; hoy `trust` aprueba los hooks del proyecto en `~/.codex/config.toml` |
139
143
  | `backup <sub>` | Lista y restaura backups de `~/.navori/backups/` |
140
144
  | `migrations <sub>` | Lista y restaura migraciones de `~/.navori/migrations/` |
@@ -185,8 +189,6 @@ La resolución es **local → bundled**: si tienes un preset local con el mismo
185
189
  | `tgrep` | Descubrimiento textual de código vía CLI indexado | `tgrep` binary |
186
190
  | `acli` | Leer tickets de Jira desde la terminal | `acli` |
187
191
  | `gh` | GitHub Issues, PRs y workflow runs | `gh` |
188
- | `jscpd` | Detección de duplicación en el diff | `jscpd` (opt-in) |
189
- | `semgrep` | Security gate local | `semgrep` (opt-in) |
190
192
 
191
193
  > `codegraph` y `tgrep` se retiraron brevemente el 2026-09-15 y se reintrodujeron el
192
194
  > 2026-09-16 (#838) con una integración que los hace trabajar entre sí — acta en
@@ -319,7 +321,7 @@ un aviso que **nombra** los repos con bloques editados a mano (conflict, que el
319
321
  render no pisa) y un roll-up `ok · changed · conflict · failed`.
320
322
 
321
323
  El registro (`~/.navori/registry.json`) se puebla solo: cada `navori init` /
322
- `navori update` te da de alta. Para arrancar con lo que ya tenías instalado,
324
+ `navori refresh` te da de alta. Para arrancar con lo que ya tenías instalado,
323
325
  escanéalo una vez:
324
326
 
325
327
  ```bash
@@ -331,52 +333,6 @@ navori registry prune # quitar los que ya no existen
331
333
  Es ortogonal a los workspaces: el registro es "qué repos existen"; el workspace
332
334
  es el perfil de policy (branchBase/prTarget) que cada repo hereda.
333
335
 
334
- ## Harness global por máquina (opt-in)
335
-
336
- Todo lo de arriba es por repo. Cuando abres una sesión **fuera** de un repo con navori (un scratch,
337
- un repo ajeno, tu `~`), no hay harness: ni doctrina de orquestación, ni skills, ni agentes. La capa
338
- global cubre ese hueco. No la confundas con `render --all` de la sección anterior: aquélla empuja tu
339
- harness a los repos que **ya** tienen navori; ésta cubre las sesiones que no están en ninguno.
340
-
341
- Es **opt-in de huella cero**: si nunca corres `navori global init`, no existe `~/.navori/global.json`
342
- y navori no escribió un solo byte en tu máquina.
343
-
344
- ```bash
345
- navori global init # wizard: bloques del baseline + permisos personales.
346
- # Preview: sin --apply no escribe un solo byte
347
- navori global init --apply # escribe lo que el preview mostró
348
- navori global init --recommended --apply # headless (CI): sin preguntas, selección recomendada
349
- navori global doctor # audita: drift del hook, gate, plugin, permisos y versión
350
- navori global render --apply # re-renderiza tras un bump del CLI (preview sin --apply)
351
- navori global uninstall # la retira por completo
352
- ```
353
-
354
- El `init` pregunta dos cosas: **qué bloques** componen el baseline (los que declaran `globalSafe`)
355
- y **qué permisos personales** quieres en `~/.claude/settings.json` — ése es el único camino de UI
356
- para `permissions`. Re-inicializar **preserva** lo que ya habías elegido: no te resetea a los
357
- defaults. Sin TTY (CI, pipe) cae solo al camino de `--recommended`, y `--lang es|en` fija el idioma
358
- del baseline y de los prompts.
359
-
360
- Qué escribe el `init --apply`, y nada más:
361
-
362
- - `~/.navori/global.json` — el manifest: idioma, bloques del baseline y tus permisos globales.
363
- - `~/.claude/skills/navori/` — el plugin `navori@skills-dir` con los 8 agentes, las 11 skills y el
364
- hook del baseline. Claude Code lo carga sin marketplace ni paso de instalación; las skills globales
365
- se invocan `/navori:<nombre>` (tras un render, `/reload-plugins` o sesión nueva).
366
- - `~/.claude/settings.json` — **solo** la clave `permissions`, y solo si declaraste permisos globales
367
- en el manifest. Con la config por default ni siquiera lo crea.
368
-
369
- Respeta `CLAUDE_CONFIG_DIR`: si lo tienes seteado, el plugin va ahí en vez de a `~/.claude`.
370
-
371
- **El baseline se hace a un lado solo.** El hook corre en `SessionStart` y busca un `navori.config.json`
372
- hacia arriba desde el directorio de la sesión: si lo encuentra, no emite nada — manda el harness del
373
- repo, que es más específico. Por eso el baseline viaja dentro de un hook y no como bloque estático en
374
- `~/.claude/CLAUDE.md`: ese archivo se carga siempre y no podría cederle el paso a nadie.
375
-
376
- `navori global uninstall` retira **solo lo que navori escribió**: el plugin, el manifest y los permisos
377
- que quedaron registrados como suyos. Un permiso que ya tenías en tu `settings.json` nunca se vuelve de
378
- navori, así que el uninstall no se lo lleva.
379
-
380
336
  ## Managed blocks con versionado
381
337
 
382
338
  Cada bloque que `navori` inyecta en tu `CLAUDE.md` lleva metadata:
@@ -408,9 +364,9 @@ Cambiar una sola cosa sin re-init:
408
364
 
409
365
  ```bash
410
366
  navori configure plugins # multiselect de plugins activos
411
- navori configure quality-gate # nuevo comando de quality gate
367
+ navori configure quality-gate # comandos del quality gate
412
368
  navori configure language en # switch a inglés (fallback a es)
413
- navori configure engines # multiselect: claude / codex / agents-md / cursor / copilot
369
+ navori configure engines # multiselect: claude / codex / agents-md / cursor / copilot / pi
414
370
  navori configure branch-base main # punto de fork / rama protegida
415
371
  navori configure pr-target develop # rama destino del PR (gh pr create --base)
416
372
  navori configure workspace bonum # asociar a un workspace
@@ -424,6 +380,24 @@ retiradas caen en la misma con valores distintos no se infiere nada — se pregu
424
380
  `--scout=<modelo> --scout-effort=<nivel>`. `--dry-run` no escribe, y `--all` barre el registry
425
381
  completo (preview salvo `--apply`).
426
382
 
383
+ ### Claves de config para el gate y los hooks nativos
384
+
385
+ - `qualityGate.scoped` (string): carril acotado del reviewer — los checks baratos de `full` más los tests relacionados con el diff. Si falta, usa `fast`. Se interpola como `navori.scopedGate`.
386
+ - `qualityGate.nativeHooks` (boolean): declara que el pre-commit nativo del proyecto ya corre `fast`; el hook `quality-gate-pre-commit` omite solo su paso de gate.
387
+ - `plugins.<id>.nativeHook` (boolean): el hook git nativo corre el check de ese plugin, así que su hook no se registra (los scripts se siguen instalando).
388
+
389
+ ### Tope de `progress/current.md`
390
+
391
+ `progress/current.md` se carga en cada sesión, así que tiene un tope. El hook pre-commit bloquea los commits de agente que lo dejan sobre el tope duro o lo hacen crecer estando ya sobre él (los commits humanos no se bloquean). `navori doctor` lo mide en bytes con los mismos topes y avisa; el hook de inicio de sesión advierte, sin bloquear, al pasar el tope suave.
392
+
393
+ ## Migrando a 0.12
394
+
395
+ - Se retiró el comando `global` y el colector launchd (`audit --collect` sigue). `doctor --json` ya no emite `globalScope`.
396
+ - Se retiraron los plugins `jscpd` y `semgrep`: `navori add jscpd|semgrep` responde que están retirados.
397
+ - El piso de Pi sube a 1.1.0: Pi 0.87.x pierde `navori_subagent`. Node mínimo: >= 22.12.
398
+ - `navori update` ahora actualiza el CLI (consulta npm, confirma, instala y luego corre `navori refresh`). El comportamiento anterior es ahora `navori refresh`, sin alias: los scripts que usaban `navori update` para re-sincronizar el harness deben cambiar a `navori refresh`.
399
+ - Migra con `navori render --apply` (poda los assets retirados que navori gestionaba) y luego `navori doctor` (reporta los restos).
400
+
427
401
  ## Extender el harness en tu repo
428
402
 
429
403
  navori instala un baseline; lo que lo vuelve valioso en **tu** repo es el conocimiento que sólo
@@ -477,3 +451,15 @@ Contrato del `SKILL.md`: [`docs/recipes/skill-authoring.md`](https://github.com/
477
451
  ## Licencia
478
452
 
479
453
  MIT.
454
+
455
+ ## Actualizar navori
456
+
457
+ `navori update` consulta npm por la última versión de navori y muestra el comando de
458
+ instalación según cómo lo tengas: npm global, devDependency, dependency o `npx`. Pide
459
+ confirmación (salvo `--yes`), instala y corre `navori refresh` con el binario nuevo.
460
+
461
+ - `--cli-only`: se detiene tras actualizar el CLI, sin `refresh`.
462
+ - Sin red o ya en la última versión: corre `refresh` directo.
463
+ - Si la instalación falla: imprime el comando manual y sale con código 1.
464
+ - Sin TTY y sin `--yes`: imprime el comando y sale con código 1.
465
+ - Solo soporta npm.
@@ -29,7 +29,7 @@ For a **master-plan** task, write the requested `<etapa>/plans/plan<n>.md` and p
29
29
 
30
30
  Use URLs de documentación oficial for expiring facts and include the fecha de consulta. If a source is unavailable, label the claim `[SIN VERIFICAR]` and list the sources consulted or unavailable.
31
31
 
32
- Via `Agent` you may dispatch `scout`/`scribe`; plan-gate and Agent hooks fire inside you with `agent_id`, expected.
32
+ <!-- navori:if-not onPi -->Via `Agent` you may dispatch `scout`/`scribe`; plan-gate and Agent hooks fire inside you with `agent_id`, expected.<!-- /navori:if-not -->
33
33
 
34
34
  ## Protocol
35
35
 
@@ -5,7 +5,7 @@ tools: Read, Write, Edit, Glob, Grep, Bash
5
5
  model: {{models.implementer}}
6
6
  effort: {{effort.implementer}}
7
7
  maxTurns: 160
8
- maxWords: 2448
8
+ maxWords: 2473
9
9
  ---
10
10
 
11
11
  # Implementer Agent
@@ -27,7 +27,7 @@ You execute **a single** task from start to verification. You don't orchestrate,
27
27
  - [ ] Define interface in <path>
28
28
  - [ ] Implement logic in <path>
29
29
  - [ ] Cover with a test
30
- - [ ] Run `{{qualityGate.fast}}`
30
+ - [ ] Run `{{gateRun.fast}}`
31
31
  ```
32
32
 
33
33
  - `Expected files: <list>`
@@ -38,10 +38,12 @@ You execute **a single** task from start to verification. You don't orchestrate,
38
38
  4. **Quality gate** (mandatory before returning):
39
39
 
40
40
  ```bash
41
- {{qualityGate.fast}}
41
+ {{gateRun.fast}}
42
42
  ```
43
43
 
44
- If it fails: fix it and re-run. Don't return with red. You are the single owner of this gate run: never share it with another process, never poll `pgrep`/`ps` for it, and a timeout is never a success signal. If the gate can outlive the Bash timeout, follow `.claude/skills/verify-before-done/SKILL.md`'s subagent row: run its chained steps one by one in the foreground, never background them (<!-- navori:if-not onCodex -->no shell `&`, no `run_in_background`, no `Monitor`<!-- /navori:if-not --><!-- navori:if onCodex -->no shell `&`, no background execution<!-- /navori:if -->) — you won't be re-woken to read the result. If no chained step fits under any foreground timeout, stop and report `BLOCKED` instead of improvising a background wait. When you can't explain WHY it failed, apply `.claude/skills/debug-failure/SKILL.md` before touching anything — the size of the output is not the trigger, the missing root cause is, and a failure whose error stream you truncated away reads the same as one you understand. If your second fix attempt fails the same way, that same skill's hypothesis re-check governs instead of throwing a third patch.
44
+ If `navori gate <kind>` prints no first line `navori gate <kind>: exit <N> — log <path>`, it did not run: run the literal `{{qualityGate.fast}}`. Open the log only on a red.
45
+
46
+ If it fails: fix it and re-run. Don't return with red. You are the single owner of this gate run: never share it with another process, never poll `pgrep`/`ps` for it, and a timeout is never a success signal. If the gate can outlive the Bash timeout, follow `.claude/skills/verify-before-done/SKILL.md`'s subagent row: run its chained steps one by one in the foreground, never background them (<!-- navori:if-not onCodex -->no shell `&`, no `run_in_background`, no `Monitor`<!-- /navori:if-not --><!-- navori:if onCodex -->no shell `&`, no background execution<!-- /navori:if -->) — you won't be re-woken to read the result. If no chained step fits under any foreground timeout, stop and report `BLOCKED` instead of improvising a background wait. When you can't explain WHY it failed, apply `.claude/skills/debug-failure/SKILL.md` before touching anything. If your second fix attempt fails the same way, that same skill's hypothesis re-check governs instead of throwing a third patch.
45
47
  5. **UI**: for screen changes, the default evidence is the repo's tests plus a correct diff — **do NOT spin up a browser or dev server automatically**. Visual/browser validation is **optional and strictly on-request**: run it only when the user explicitly asks to check the UI in this prompt, and then drive the repo's browser-automation tool if one is set up (e.g. `playwright-cli`, whose installer ships its own skill).
46
48
  6. **No commits** without the `reviewer`'s approval. When you finish, <!-- navori:if-not scribeOwnsMarkdown -->write the report<!-- /navori:if-not --><!-- navori:if scribeOwnsMarkdown -->write your JSON evidence<!-- /navori:if --> and return the reference.
47
49
  <!-- navori:if planTiers -->
@@ -60,7 +62,7 @@ When the encargo opens with `workplan: <feature>`, read `.navori/state/handoffs/
60
62
  - **Zero new errors** introduced by your code in the quality gate tools (vs. baseline) — classify per `verify-before-done`'s Failure attribution, never by diff location alone; see the evidence table below. Returning with any tool red (because of your change) is automatic grounds for `CHANGES_REQUESTED`.
61
63
  - **Never mutate or discard the shared working tree**: no stashing, no checkout/reset that discards local changes, no working-tree clean — these hit the `ask` permission rule and can stall a background agent indefinitely. Same reasoning for scratch files: leave them, don't clean them with a recursive delete.
62
64
  - **JSDoc** mandatory on public exports and functions >15 lines or with dense conditional logic.
63
- - **SDD traceability** (only if the feature has `{{sdd.specsDir}}/<feature>/tasks.md`, see the SDD block in `CLAUDE.md`): each `R<n>` in your batch is covered by ≥1 test, and each test references its requirements with a `// Covers: R<n>` comment above the case. Without full traceability the `reviewer` rejects.
65
+ - **SDD traceability** (only if the feature has `{{sdd.specsDir}}/<feature>/tasks.md`, see `spec-bootstrap`): each `R<n>` in your batch is covered by ≥1 test, and each test references its requirements with a `// Covers: R<n>` comment above the case. Without full traceability the `reviewer` rejects.
64
66
  - **Guard/policy coverage** (only if your task introduces or modifies a guard, policy or permission check): your report carries the enumeration, not just the diff — every entry point that mutates the same resource (routes, bulk/admin variants, jobs, scripts) with its `file:line` evidence, each marked covered or excluded with the reason. Locate them with `locate-code`; an entry point you didn't list is one the `reviewer` has to rediscover.
65
67
  - If a tool fails weirdly (e.g. tsc breaks with no apparent diff), **don't improvise a workaround**: note `Status: BLOCKED` + the reason in `.navori/state/handoffs/impl_<feature>.md` and stop.
66
68
  - **While iterating, run only the tests of the area you touch** (filter by the runner's path). The full gate in step 4 runs at the end, not on each iteration — saves time and context. Never run the full `{{qualityGate.full}}` suite yourself: that's the `reviewer`'s Pass 2 job, and it commonly outlives Bash's timeout. If this repo has a diff-scoped fast check (`scoped-gate`), it's hygiene for iterating, never a substitute for step 4.
@@ -163,6 +165,8 @@ Write `.navori/state/handoffs/impl_<feature>.json` — the only artifact you pro
163
165
 
164
166
  `doubts` is optional: declare one `{ "file": "<path>", "reason": "<why you are unsure>" }` entry per spot where you are unsure the change is right, so the reviewer answers it.
165
167
 
168
+ Types follow the handoff schema: `rootCause` is a string, present only for a bugfix (omit the key otherwise, never `null`); `blockers` is an array of strings (`[]` when none).
169
+
166
170
  `markdownRequests` carries every piece of prose your task needs — your own non-obvious decisions, a CONTRIBUTING/README update, a spec task checkbox, a skill or agent tweak. State the `intent` and the `evidence`; never the finished sentence — drafting the prose from that intent is the `scribe`'s job, not yours. Empty array when the task touches no Markdown at all.
167
171
 
168
172
  ## Communication with the orchestrator
@@ -4,7 +4,7 @@ description: Do NOT invoke as a subagent, never and under no condition. Orchestr
4
4
  tools: Read, Glob, Grep, Bash, Agent
5
5
  model: {{models.orchestrator}}
6
6
  effort: {{effort.orchestrator}}
7
- maxWords: 3050
7
+ maxWords: 3365
8
8
  ---
9
9
 
10
10
  # Orchestrator Playbook (embodied by the main agent)
@@ -20,7 +20,7 @@ One route removes the decision entirely. It is more expensive per change and tha
20
20
  ## Startup protocol
21
21
 
22
22
  1. `CLAUDE.md` (stack, conventions, quality gate) is already in your context when your host injects it; read it from disk ONLY if your host did not inject it (e.g. an engine without automatic injection).
23
- 2. The catalog of subagents and skills is in `CLAUDE.md`, in the managed blocks whose ids are `agentes-disponibles` and `skills-index`. Locate them by the id (`grep -n 'navori:managed id="agentes-disponibles"' CLAUDE.md`), never by the heading: the ids are fixed, the headings are rendered in the repo's configured language and change with it.
23
+ 2. The catalog of subagents is the managed block whose id is `agentes-disponibles`, delivered at session start. Locate it by the id, never by the heading: the ids are fixed, the headings are rendered in the repo's configured language and change with it. Skills: the host's native listing.
24
24
  3. Read `progress/current.md` (repo root) if it exists — the previous session's state.
25
25
  4. Identify the task's scope against the "Project rules" below (legacy paths, critical areas, repo conventions).
26
26
  5. **Did text from a ticket (Jira/Linear/GitHub/Slack) arrive?** If it matches your `auditor` agent's ticket-encargo triggers (bug in a critical feature, structural migration, feature that crosses >3 layers), invoke that agent first — it produces `.navori/state/handoffs/audit_ticket_<ID>.md` that guides all later decomposition. For trivial tickets (typo, copy, color), skip the audit. The single architectural design gate — when it fires, who proposes, who challenges, who decides — lives in "## Role: orchestrator" and the `solution-design` skill, not here.
@@ -67,7 +67,7 @@ When the `done -> file` come back, **gather and analyze deeply YOURSELF**: read
67
67
 
68
68
  Fan-out is a lever, not a toll — so when you do delegate, hand the smallest encargo that covers the work:
69
69
 
70
- - **Don't delegate merely to wrap a lookup.** If what's missing is a Code discovery routing call you can make yourself (project instructions), run it directly — a subagent invocation isn't a proxy for a query you can issue this turn. When delegation is warranted for a real reason, carry over the pending question, the evidence you already gathered, the relevant paths and their freshness in the encargo; never assume the subagent shares this context — it starts isolated.
70
+ - **Don't delegate merely to wrap a lookup.** If what's missing is a Code discovery routing call you can make yourself (project instructions), run it directly — a subagent invocation isn't a proxy for a query you can issue this turn. When delegation is warranted for a real reason, carry over the pending question, the evidence you already gathered, the relevant paths and their freshness in the encargo; never assume the subagent shares this context — it starts isolated, with no skills listing: name any skill it should apply with its path `.claude/skills/<id>/SKILL.md`.
71
71
  - **Peel off the mechanical first.** Copies, renames, scaffolding, JSON/string edits → send them to a low-tier agent in their own encargo; never bundle them into the `implementer`'s, where they inflate its context and its run without raising quality.
72
72
  - **One encargo = one unit.** A pre-existing bug the `implementer` hits outside its scope → it reports and stops there (a trivial one-liner is the exception); **you** decide whether to open a separate unit. Scope doesn't self-expand mid-run.
73
73
  - **Tier by sub-task, not by round.** A single fix round can mix tiers. Map: **low** → mechanical work (copies, renames, scaffolding, string/JSON edits, a one-line fix); **mid** → a scoped bugfix with a clear cause or a bounded feature; **high** → judgment work (design, security regex, ambiguous root-cause, removal semantics, critical areas).
@@ -155,10 +155,12 @@ And never take a merged PR as proof on its own: **squash merge leaves no ancestr
155
155
  ## Quality gate
156
156
 
157
157
  ```bash
158
- {{qualityGate.fast}} # fast gate — pre-step to the reviewer
159
- {{qualityGate.full}} # full gate — before closing the session / creating the PR
158
+ {{gateRun.fast}} # fast gate — pre-step to the reviewer
159
+ {{gateRun.full}} # full gate — before closing the session / creating the PR
160
160
  ```
161
161
 
162
+ When the command is `navori gate <kind>`, its first stdout line is `navori gate <kind>: exit <N> — log <path>`; if it is missing, the gate did not run: run the literal `{{qualityGate.fast}}` or `{{qualityGate.full}}` command instead.
163
+
162
164
  If the repo has no test suite, the `implementer` still can't claim "done" without fresh evidence (a correct diff plus whatever checks exist) — but browser/visual validation stays **on-request only, never automatic**. The `verify-before-done` skill enforces the "fresh evidence rule" over any "done" claim.
163
165
 
164
166
  ## What you do NOT do
@@ -17,14 +17,14 @@ You own the **end of the cycle**: well-structured commits in the configured styl
17
17
  ## When to trigger
18
18
 
19
19
  - Working tree with changes ready to commit (post-implementer + review APPROVED).
20
- - Branch finished, ready for PR: commits on the branch, harness approved, and fresh `{{qualityGate.full}}` evidence over the shipping diff (see Gate below).
20
+ - Branch finished, ready for PR: commits on the branch, harness approved, and fresh full-gate evidence over the diff that ships (see Gate below).
21
21
  - Explicit user request: "create the PR", "commit this", "send the PR", "/pr".
22
22
 
23
23
  ## When NOT to trigger
24
24
 
25
25
  - Working tree with uncommitted changes when the user only asked to "open the PR" → first commit or ask for permission.
26
26
  - You are on `{{prTarget}}`, on the branch this one was forked from, or another protected branch → abort + ask for a branch.
27
- - Harness active and THIS feature's review — `.navori/state/handoffs/review_<feature>.md`, the single file the pre-flight below identifies by name — contains `CHANGES_REQUESTED` → no PR is created. Never scan the directory for it: a `CHANGES_REQUESTED` belonging to someone else's closed cycle must not abort your PR, exactly as another feature's `APPROVED` never unblocks it.
27
+ - Harness active and THIS feature's review (`.navori/state/handoffs/review_<feature>.md`, identified by name in the pre-flight) contains `CHANGES_REQUESTED` → no PR is created.
28
28
  - Quality gate red this turn.
29
29
 
30
30
  > **Two branches, one that decides:** `{{prTarget}}` is the target for `gh pr create --base` and every diff below. The fork point is a separate setting; in most repos both name the same branch. Where they differ, the target branch wins — the fork-point diff is never the PR's.
@@ -43,51 +43,32 @@ if [ "$behind" -ne 0 ]; then
43
43
  exit 1
44
44
  fi
45
45
  git log origin/{{prTarget}}..HEAD --oneline # must have ≥1 commit (or changes to commit)
46
- git diff origin/{{prTarget}} --stat # REAL scope so far (two-dot: see below)
46
+ git diff origin/{{prTarget}} --stat # real scope so far
47
47
  gh auth status # gh authenticated
48
48
  ```
49
49
 
50
- A nonzero `behind` count is a hard stop: do not construct a shipping diff,
51
- consume a receipt, commit, push, or create a PR. The reviewer would otherwise
52
- have signed target-only files as phantom deletions from this stale worktree.
50
+ A nonzero `behind` count is a hard stop: do not consume a receipt, commit, push, or create a PR. The reviewer would otherwise have signed target-only files as phantom deletions from this stale worktree.
53
51
 
54
- The later `receipt.txt` check is also a hard stop: it must report JSON
55
- `"status":"ok"` before this branch can publish.
52
+ **Which review counts.** Identify THIS feature's review by name: `.navori/state/handoffs/review_<feature>.md`, with `<feature>` the id from your brief. A broad glob (`review_*.md`) over all reviews is not valid: another feature's `APPROVED` never unblocks this PR and another cycle's `CHANGES_REQUESTED` never aborts it. Open that file: its verdict must be `APPROVED` and its scope/feature section must name the feature you are about to commit. Absent, ambiguous (more than one candidate), or mismatched → not approved: abort, tell the user the review is missing, and never assume a generic `APPROVED`.
56
53
 
57
- ### The shipping diff — the one set every count in this pre-flight comes from
58
-
59
- Coverage of the review and the receipt's fingerprints are two questions about the SAME set of files. Write it once, read it everywhere:
60
-
61
- ```bash
62
- shipping=$({ git -c core.quotepath=false diff --name-only "origin/{{prTarget}}"; \
63
- git -c core.quotepath=false ls-files --others --exclude-standard; } \
64
- | sort -u | grep -vE '^(\.navori/state/handoffs/|progress/)')
65
- printf '%s\n' "$shipping" # read it: this is what ships
66
- ```
67
-
68
- - **`$shipping` does not survive the call.** Each Bash call starts a fresh shell — no variable or function crosses over — so re-run the assignment in the same call as whatever reads it. That is a copy of four lines, not a second definition of the set.
69
- - **Two dots, plus the untracked files — NEVER `...HEAD`.** Three-dot lists only what is already *committed*, and your trigger is by construction an **uncommitted** tree: there is no clean-working-tree check in this pre-flight because the commit is yours to make, further down. Run against an uncommitted tree, a three-dot listing comes back EMPTY — the coverage check then finds nothing missing and the waiver's count reads zero, so both are granted on every diff. It fails silently, in the unsafe direction. Two-dot plus `ls-files --others` is the exact set the `reviewer` captured and signed.
70
- - **`progress/` is dropped**, the same grep the receipt applies, so the two sets line up 1:1 and a git-persisted session-state update never looks like an unreviewed file. Deletions DO stay in the set (the receipt records them as `deleted <path>`), so a removed file can't ship unreviewed.
71
- - **`quotepath=false` on both listings**, exactly as the reviewer signed them: git C-quotes a non-ASCII path by default, and a quoted path never matches the receipt's line — the file would read as uncovered, or slip by unverified.
72
-
73
- If the harness is active, identify THIS feature's review: `.navori/state/handoffs/review_<feature>.md`, with `<feature>` the id you received in your brief. A broad glob (`review_*.md`) over all reviews is not valid — it's not enough that some review with `APPROVED` exists in the directory, it has to be this feature's.
74
-
75
- Open that specific file and confirm its verdict is `APPROVED` and that its scope/feature section names the same feature you're about to commit. The verdict only counts if the review **covers the whole shipping diff**: the reviewer's content receipt (below) is the authoritative list of the files it actually reviewed, so every file in the shipping diff above must appear there. A touched file the review never saw → the `APPROVED` doesn't cover the full change → it does NOT count as approved. Abort, don't create the PR, and send it back to the reviewer to cover the missing files. It's not enough to mention the difference and carry on. The coverage check is mechanical — see the receipt block.
76
-
77
- <!-- This file-coverage rule lives here only; the commit+PR flow has no second home to this agent (single owner of the PR flow). -->
78
-
79
-
80
- An absent file, ambiguous (more than one candidate), or with a verdict/scope that doesn't match the current feature → does NOT count as approved: abort, tell the user the review is missing, and never assume a generic `APPROVED`.
81
-
82
- **Content receipt: the diff must still match what was approved.** Before committing, run the receipt command with the feature id from `review_<feature>.md`. It owns coverage and drift detection; do not reproduce its algorithm in shell.
54
+ **Content receipt: the diff must still match what was approved.** The `receipt.txt` check is also a hard stop. Run it with the feature id from `review_<feature>.md`. It owns the shipping set (working tree against `origin/{{prTarget}}`, untracked files included), the coverage check and the drift check: do not reproduce any of them in shell.
83
55
 
84
56
  ```bash
85
57
  navori receipt check --feature <feature> --target {{prTarget}} --dir .navori/state/handoffs --json
86
58
  ```
87
59
 
88
- Continue only when the JSON has `"status":"ok"`. A missing `navori`, absent receipt, non-zero command, malformed JSON, `ERROR`, `UNCOVERED`, or `DRIFT` blocks the commit and PR.
60
+ Continue only on `"status":"ok"`, and read the rest of the JSON by this table:
61
+
62
+ | JSON from `navori receipt check` | Action |
63
+ |---|---|
64
+ | `"status":"error"` (`error` names the cause: branch behind the target, no receipt, receipt of another feature, fetch failure), a non-zero exit with no JSON, or `navori` missing | Hard stop. Report the `error`; no commit, push or PR. |
65
+ | `"status":"findings"` with `uncovered[]` not empty | The review never saw those files, so its `APPROVED` does not cover this change. Abort and send it back to the `reviewer` for a full re-review of them; do not carry on. |
66
+ | `"status":"findings"` with `drift[]` not empty (`kind`: `changed`, `missing`, `reappeared`) | `drift[].blob` is the approved blob: `git diff <blob-sha> <file>` shows the change (`git cat-file -p <blob-sha>` prints the approved content). An explained post-review edit goes to the `reviewer` for a **delta re-sign**; unexplained drift goes to a full re-review. |
67
+ | `"status":"ok"`, `"fresh":true`, `"gateKind":"full"` | Gate evidence is trusted: do not re-run the gate (see Gate below). |
68
+ | `"status":"ok"` with `"fresh":false` (`stale[]` lists `format`, `gate` or `inputs`), or `"gateKind":null` | No trustworthy gate evidence: you run the gate yourself (see Gate below). |
69
+ | `"gateKind":"scoped"` | Commit-only mode below, whatever `fresh` says. |
89
70
 
90
- For every live-file `DRIFT`, the JSON provides the approved blob and the exact inspection command is `git diff <blob-sha> <file>` (`git cat-file -p <blob-sha>` prints its approved content). Route explained drift caused by a post-review edit to the reviewer for a **delta re-sign**; route unexplained drift or any uncovered file to a full re-review. If the real PR base differs from `{{prTarget}}`, pass that actual base as `--target` to both receipt commands.
71
+ If the real PR base differs from `{{prTarget}}`, pass that actual base as `--target`.
91
72
 
92
73
  <!-- The orchestrator block states the rule (every change goes through implementer -> reviewer); this is where the PR side of it is enforced. -->
93
74
 
@@ -96,18 +77,18 @@ For every live-file `DRIFT`, the JSON provides the approved blob and the exact i
96
77
  **The one exception: delegation was genuinely impossible, and it was DECLARED.** The operator forbade subagents for the session, or the `Agent` tool was unavailable. The orchestrator must have said so explicitly, naming the reason. Then, and only then:
97
78
 
98
79
  - you do NOT abort for the missing review;
99
- - you MUST run `{{qualityGate.full}}` green yourself in pre-flight (see Gate below) — there is no review evidence to trust;
80
+ - you MUST run the full gate green yourself in pre-flight (see Gate below) — there is no review evidence to trust;
100
81
  - the **PR body must state it**, in one line: what was done inline and why delegation was not possible. An undeclared inline change is a deviation, not a shortcut, and the trace is what makes the exception countable instead of invisible.
101
82
 
102
83
  **No count, no judgement about the diff's content.** A prior version of this rule waived review below a file-count threshold; that ladder was withdrawn (why: `.claude/agents/orchestrator.md`) and has not returned. Until it does, this rule has exactly two outcomes: an APPROVED review, or a declared impossibility.
103
84
 
104
85
  ### Gate: `{{qualityGate.full}}` green before the PR
105
86
 
106
- The PR gate is the FULL one, `{{qualityGate.full}}`, not `{{qualityGate.fast}}`. Which steps sit where is a per-project decision; don't assume the fast gate covers all full steps. Three paths:
87
+ The PR gate is the FULL one, not `{{qualityGate.fast}}`. Which steps sit where is a per-project decision; don't assume the fast gate covers all full steps. Three paths:
107
88
 
108
- - **Reviewed:** the reviewer ran `{{qualityGate.full}}` green in Pass 2 (see `review_<feature>.md`). Skip re-running **only** when `navori receipt check` reports `"fresh":true`. The `quality-gate-pre-commit` hook re-runs `fast` on `git commit` and blocks if it fails. Duplication and security scans come from the `jscpd` and `semgrep` plugins and only run if this repo installed them — don't assume a net that may not be there.
109
- - **`"fresh":false` on `full` receipts:** no trustworthy evidence — YOU run `{{qualityGate.full}}` green in pre-flight before `gh pr create`. Follow `.claude/skills/verify-before-done/SKILL.md`'s subagent row if it outlives the timeout.
110
- - **Declared inline (no reviewer):** no review evidence either — run `{{qualityGate.full}}` yourself.
89
+ - **Reviewed:** the reviewer ran the full gate green in Pass 2 (see `review_<feature>.md`). Skip re-running **only** when the receipt table says `"fresh":true`. The `quality-gate-pre-commit` hook re-runs `fast` on `git commit` and blocks if it fails. Any duplication or security scan beyond the quality gate is the repo's own tooling and only runs if the repo wired it in — don't assume a net that may not be there.
90
+ - **`"fresh":false`:** no trustworthy evidence — YOU run `{{gateRun.full}}` in pre-flight before `gh pr create`. Follow `.claude/skills/verify-before-done/SKILL.md`'s subagent row if it outlives the timeout. When the command is `navori gate <kind>`, its first stdout line is `navori gate <kind>: exit <N> — log <path>`; if that line is missing, the gate did not run: run the literal full gate.
91
+ - **Declared inline (no reviewer):** no review evidence either — run it yourself.
111
92
 
112
93
  Never open the PR with the gate red.
113
94
 
@@ -225,7 +206,7 @@ This is a separate contract from the PR body in the flow above: that one is the
225
206
  ## Test plan
226
207
  - [ ] <concrete manual check 1>
227
208
  - [ ] <concrete manual check 2>
228
- - [ ] `{{qualityGate.full}}` green
209
+ - [ ] Full quality gate green
229
210
 
230
211
  ## References
231
212
  - Closes #<N> (an issue of THIS repo; omit the line if there is none)
@@ -4,7 +4,7 @@ description: Strict reviewer — approves or rejects a diff against CLAUDE.md an
4
4
  tools: Read, Glob, Grep, Bash, Write
5
5
  model: {{models.reviewer}}
6
6
  effort: {{effort.reviewer}}
7
- maxWords: 2966
7
+ maxWords: 3046
8
8
  ---
9
9
 
10
10
  # Reviewer Agent
@@ -15,13 +15,11 @@ You are a strict reviewer. Your only function is to **approve or reject**. You d
15
15
 
16
16
  ### Setup (common to both passes)
17
17
 
18
- 1. Ground yourself in `CLAUDE.md` — already in your context when your host injects it; read it from disk ONLY if your host did not inject it. Then read `.navori/state/handoffs/impl_<feature>.md` (when `impl_<feature>` carries `doubts`, read them too: each is a `{file, reason}`), `.navori/state/handoffs/audit_ticket_<ID>.md` and `.navori/state/handoffs/solution_<scope>.md` (whichever exist). When there IS a solution artifact, the diff is judged against the approach it records — an implementation that quietly took a different path is a `SPEC_MISS`, even if the code is good. You do NOT re-open the design itself: whether that approach was the right one was settled in its own phase; your question is whether the code did what was agreed.
18
+ 1. Ground yourself in `CLAUDE.md` — already in your context when your host injects it; read it from disk ONLY if your host did not inject it. Then read `.navori/state/handoffs/impl_<feature>.md` (when `impl_<feature>` carries `doubts`, read them too: each is a `{file, reason}`), `.navori/state/handoffs/audit_ticket_<ID>.md` and `.navori/state/handoffs/solution_<scope>.md` (whichever exist). When there IS a solution artifact, the diff is judged against the approach it records — an implementation that quietly took a different path is a `SPEC_MISS`, even if the code is good. You do NOT re-open the design itself: whether that approach was the right one was settled in its own phase; your question is whether the code did what was agreed. Read it by `Chosen solution`, `Boundaries & contracts`, `NOT in scope` and any revision after challenge section — the whole file when those headings are absent.
19
19
  2. Identify modified files. Diff against `{{prTarget}}` (the PR's target
20
20
  branch), **not** against the fork point: it's the EXACT diff GitHub will show and
21
- the one publisher reviews. In most repos the branch you forked from and
22
- the branch the PR targets are the same, and the distinction costs you nothing;
23
- where they differ, the fork-point diff is NOT the PR's — so the target always
24
- wins, and you never have to work out which of the two a given name refers to.
21
+ the one publisher reviews. Where the fork branch and the PR target differ, the
22
+ fork-point diff is NOT the PR's: the target always wins.
25
23
 
26
24
  ```bash
27
25
  git status --short
@@ -48,10 +46,9 @@ You are a strict reviewer. Your only function is to **approve or reject**. You d
48
46
  receipt. A target-only file would otherwise look like a deletion in this
49
47
  worktree and the receipt would sign that phantom deletion.
50
48
 
51
- 3. **Re-review** (if there's already a `.navori/state/handoffs/review_<feature>.md` from a previous cycle): focus the *reading* on (a) that the issues listed there are resolved and (b) the files the `implementer` reports having touched in this cycle (`impl_<feature>.md`). Don't re-review from scratch the already-approved code that didn't change; the full quality gate is still run anyway — a change can break something outside the delta. If the previous verdict was already `APPROVED` and the diff only moved because of an edit made after it, that's the **delta re-sign** mode below, not this one.
49
+ 3. **Re-review** (a previous `review_<feature>.md` exists): From round 2 on read the prior `review_<feature>.md` (are its issues resolved?) and the delta in `impl_<feature>.md`; re-open `solution_<scope>.md` only on a prior `SPEC_MISS` or design finding, or when the delta touches files outside the prior diff. Don't re-review unchanged code — the Pass 2 table sets the gate, so a `CHANGES_REQUESTED` round stays scoped; the Coverage table stays required on the signing round. If the previous verdict was already `APPROVED` and the diff only moved because of a later edit, that's the **delta re-sign** mode below.
52
50
  4. Apply `.claude/skills/verify-before-done/SKILL.md` to every `[x]` that depends on evidence. The quality gate is run **this turn, in Pass 2** (not before: a `SPEC_MISS` in Pass 1 doesn't need it — don't spend the gate on a diff you're going to reject on spec). Don't assume from the implementer's cached report.
53
- 5. When judging scope or an impact claim needs evidence beyond the diff itself, apply Code discovery routing (project instructions) before gathering it: occurrences from a text search don't demonstrate structural impact — confirm relationships and blast radius through the enabled structural provider, or scoped reading when it's unavailable.
54
- 6. **Closing cycle** (only for spec deliveries): when the encargo reads `spec: <spec> E<n> M<n>` and this is a delivery's closing milestone, read the whole delivery diff (`git diff "origin/{{prTarget}}"`), the re-review narrowing (Setup 3) does not apply, run `navori spec check <spec> --json` (must be `"status":"ok"`), and run `{{qualityGate.full}}` over those bytes. The receipt is then the publisher's reusable verdict.
51
+ 5. **Closing cycle** (only for spec deliveries): when the encargo reads `spec: <spec> E<n> M<n>` and this is a delivery's closing milestone, read the whole delivery diff (`git diff "origin/{{prTarget}}"`), the re-review narrowing (Setup 3) does not apply, run `navori spec check <spec> --json` (must be `"status":"ok"`), and run the full gate (Pass 2) over those bytes. The receipt is then the publisher's reusable verdict.
55
52
 
56
53
  ### Pass 1 — Spec compliance
57
54
 
@@ -77,7 +74,7 @@ Does the diff do EXACTLY what was asked? You don't review style yet.
77
74
 
78
75
  Does the code match the repo's conventions? Here you do review style/naming/types.
79
76
 
80
- Apply `.claude/skills/review-diff/SKILL.md` — the full checklist by dimensions (types, hardcode, naming, dead code, quality gate, etc.), with severities. When the diff touches auth, permissions, object access, secrets or anything in `{{project.criticalAreas}}`, also apply `.claude/skills/security-invariants/SKILL.md`: it carries the business invariants a static scanner cannot infer from the code. Its CRITICAL/HIGH map to the ≥80 issues below; MEDIUM to the informational observations. On top of that checklist, always validate against `CLAUDE.md` and the orchestrator's "Project rules" — plus any additional rule the orchestrator wrote in the user-section of its prompt.
77
+ Apply `.claude/skills/review-diff/SKILL.md` in full in round 1 (later rounds: the Pre-pass plus sections tied to prior findings) — the checklist by dimension, with severities. When the diff touches auth, permissions, object access, secrets or anything in `{{project.criticalAreas}}`, also apply `.claude/skills/security-invariants/SKILL.md`: it carries the business invariants a static scanner cannot infer from the code. Its CRITICAL/HIGH map to the ≥80 issues below; MEDIUM to the informational observations. On top of that checklist, always validate against `CLAUDE.md` and the orchestrator's "Project rules" — plus any additional rule the orchestrator wrote in the user-section of its prompt.
81
78
 
82
79
  **Quality gate** (mandatory green, run this turn):
83
80
 
@@ -85,21 +82,28 @@ When the encargo opens with `spec: <spec> E<n> M<n>`, run first:
85
82
  ```bash
86
83
  navori receipt gate --feature <feature> --spec <spec> --milestone M<n> --json
87
84
  ```
88
- If the result contains `"gateKind":"scoped"`, run `{{qualityGate.fast}}` plus the milestone's `A<n>` commands instead. If `"gateKind":"full"`, the gate fails, or there is no spec line, run:
85
+ If the result contains `"gateKind":"scoped"`, run `{{navori.scopedGate}}` plus the milestone's `A<n>` commands instead. If `"gateKind":"full"`, the gate fails, or there is no spec line, apply the table below.
86
+
87
+ | Round outcome | Gate evidence |
88
+ |---|---|
89
+ | Ends in `CHANGES_REQUESTED` (any issue ≥80) | `{{navori.scopedGate}}` plus the assigned `A<n>` commands. Do NOT run the full gate. |
90
+ | About to sign `APPROVED` (including delta re-sign) | The full gate, over the bytes you sign: |
89
91
  ```bash
90
- {{qualityGate.full}}
92
+ {{gateRun.full}}
91
93
  ```
94
+ The full gate runs once, on the round that signs; a rejected round never spends it.
95
+
96
+ If `navori gate <kind>` prints no first line `navori gate <kind>: exit <N> — log <path>`, it did not run (an old navori prints help and exits 0): run the literal `{{qualityGate.fast}}` or `{{qualityGate.full}}` instead. Read only the verdict.
92
97
 
93
98
  <!-- navori:if onCodex -->
94
- Read it in full to verify (exit code + failure count), but leave only `exit 0` + the summary line in the report (e.g. `N passed`); when red, only the failing tail. Don't drag the full verbose log turn to turn. This evidence —green gate over the final diff, this cycle— is what the `publisher` reuses so it does **not** re-run the gate, so it must be fresh and over the diff that's going to be committed. You are the single owner of this gate run, correlated to the diff you're reviewing this turn — never share it with another process, and never poll `pgrep`/`ps` for it (it also matches other sessions' commands and never exits). A timeout is never a success signal.
99
+ Read the verdict to verify (exit code + failure count), but leave only `exit 0` + the summary line in the report (e.g. `N passed`); when red, only the failing tail. Don't drag the full verbose log turn to turn. This evidence —green gate over the final diff, this cycle— is what the `publisher` reuses so it does **not** re-run the gate, so it must be fresh and over the diff that's going to be committed. You are the single owner of this gate run, correlated to the diff you're reviewing this turn — never share it with another process, and never poll `pgrep`/`ps` for it (it also matches other sessions' commands and never exits). A timeout is never a success signal.
95
100
 
96
- Start `{{qualityGate.full}}` once with the available execution tool, in the foreground, without shell `&` or detached/background execution. Retain the exact returned continuation handle and, if it yields while running, continue polling that same handle as the same reviewer until the process reports its actual final exit status, exit code, and failure count. For `exec_command`, continue only its exact returned `session_id` via `write_stdin` with empty `chars`; for a yielded tool-native cell, use only its matching cell handle and native wait. A yield is neither a timeout nor success. Do not detach, share, transfer, restart or replay the gate. Without the process's actual final exit, exit code, and failure count, the review is incomplete: report `BLOCKED` and write no receipt. An actual timeout, cancellation, rejection, or lost handle also leaves it `BLOCKED` with no receipt. A nonzero final exit or gate failures follow the existing `QUALITY_MISS` path.
101
+ Start `{{gateRun.full}}` once with the available execution tool, in the foreground, without shell `&` or detached/background execution. Retain the exact returned continuation handle and, if it yields while running, continue polling that same handle as the same reviewer until the process reports its actual final exit status, exit code, and failure count. For `exec_command`, continue only its exact returned `session_id` via `write_stdin` with empty `chars`; for a yielded tool-native cell, use only its matching cell handle and native wait. A yield is neither a timeout nor success. Do not detach, share, transfer, restart or replay the gate. Without the process's actual final exit, exit code, and failure count, the review is incomplete: report `BLOCKED` and write no receipt. An actual timeout, cancellation, rejection, or lost handle also leaves it `BLOCKED` with no receipt. A nonzero final exit or gate failures follow the existing `QUALITY_MISS` path. The full gate runs only on the round about to sign `APPROVED`; a round ending in `CHANGES_REQUESTED` uses the scoped gate and the assigned `A<n>` commands, and runs no full gate.
97
102
  <!-- /navori:if -->
98
103
  <!-- navori:if-not onCodex -->
99
- Read it in full to verify (exit code + failure count), but leave only `exit 0` + the summary line in the report (e.g. `N passed`); when red, only the failing tail. Don't drag the full verbose log turn to turn. This evidence —green gate over the final diff, this cycle— is what the `publisher` reuses so it does **not** re-run the gate, so it must be fresh and over the diff that's going to be committed. You are the single owner of this gate run: the only handle that exists is this Bash call itself, correlated to the diff you're reviewing this turn — never share it with another process, and never poll `pgrep`/`ps` for it (it also matches other sessions' commands and never exits). A timeout is never a success signal. Run it in the foreground with the Bash tool's max `timeout`; if `{{qualityGate.full}}` can exceed it, follow `.claude/skills/verify-before-done/SKILL.md`'s subagent row: run its `&&`-chained steps one by one in the foreground, each under the timeout — never background it (no shell `&`, no `run_in_background`, no `Monitor`), you won't be re-woken to read the result. If no chained step fits under any foreground timeout, stop and report `BLOCKED` instead of improvising a background wait.
104
+ Read the verdict to verify (exit code + failure count), but leave only `exit 0` + the summary line in the report (e.g. `N passed`); when red, only the failing tail. Don't drag the full verbose log turn to turn. This evidence —green gate over the final diff, this cycle— is what the `publisher` reuses so it does **not** re-run the gate, so it must be fresh and over the diff that's going to be committed. You are the single owner of this gate run: the only handle that exists is this Bash call itself, correlated to the diff you're reviewing this turn — never share it with another process, and never poll `pgrep`/`ps` for it (it also matches other sessions' commands and never exits). A timeout is never a success signal. Run `{{gateRun.full}}` in the foreground with the Bash tool's max `timeout`; if the full gate can exceed it, follow `.claude/skills/verify-before-done/SKILL.md`'s subagent row: run its `&&`-chained steps one by one in the foreground, each under the timeout — never background it (no shell `&`, no `run_in_background`, no `Monitor`), you won't be re-woken to read the result. If no chained step fits under any foreground timeout, stop and report `BLOCKED` instead of improvising a background wait. The full gate runs only on the round about to sign `APPROVED`; a round ending in `CHANGES_REQUESTED` uses the scoped gate and the assigned `A<n>` commands, and runs no full gate.
100
105
  <!-- /navori:if-not -->
101
106
 
102
- Don't gate a screen change on browser validation by default. Only if the user explicitly requested a visual/browser check and it wasn't done do you mark it incomplete — otherwise the diff + the repo's tests are the gate.
103
107
 
104
108
  **Partial verdict:**
105
109
 
@@ -108,7 +112,7 @@ Don't gate a screen change on browser validation by default. Only if the user ex
108
112
 
109
113
  ### Content receipt (write ONLY on APPROVED)
110
114
 
111
- Your APPROVED verdict is bound to the exact bytes you reviewed. Only after `APPROVED`, run the command below with the feature id from the implementer handoff. When the encargo has `spec: <spec> E<n> M<n>`, include `--spec <spec> --milestone M<n> --gate-ran scoped|full` (what actually ran) and verify the `gateKind` in the sign JSON matches the one from `receipt gate`; if absent (old binary), run the full gate and sign without flags. It owns the publish-set calculation and receipt format; do not reproduce either in shell.
115
+ Your APPROVED verdict is bound to the exact bytes you reviewed. Only after `APPROVED`, run the command below with the feature id from the implementer handoff. When the encargo has `spec: <spec> E<n> M<n>`, include `--spec <spec> --milestone M<n> --gate-ran scoped|full` (what actually ran) and verify the `gateKind` in the sign JSON matches the one from `receipt gate`; `--gate-ran full` means the full gate ran over the signed bytes, since signing needs it; if absent (old binary), run the full gate and sign without flags. It owns the publish-set calculation and receipt format; do not reproduce either in shell.
112
116
 
113
117
  ```bash
114
118
  navori receipt sign --feature <feature> --target {{prTarget}} --dir .navori/state/handoffs --json
@@ -122,7 +126,7 @@ A second mode, distinct from the re-review of item 3: you already signed this di
122
126
 
123
127
  1. **The previous `APPROVED` stands.** What didn't change isn't re-opened; you're extending a verdict, not replacing it.
124
128
  2. **Measure the delta, never eyeball it.** Per drifted file, the receipt line gives the approved sha: `git diff <blob-sha> <file>` is the exact change since the signature (`git cat-file -p <blob-sha>` for the full approved content). "It looks small" is not evidence.
125
- 3. **Re-run `{{qualityGate.full}}` anyway**, over the live bytes. The previous green expired the moment the bytes changed, and that evidence is what the pilot reuses.
129
+ 3. **Re-run the full gate** (Pass 2), over the live bytes, since this round is about to re-sign. The previous green expired the moment the bytes changed, and that evidence is what the pilot reuses.
126
130
  4. **Rewrite the receipt** over the final bytes with `navori receipt sign --feature <feature> --target {{prTarget}} --dir .navori/state/handoffs --json`, and continue only on `"status":"ok"`. A delta re-sign that doesn't re-sign leaves the pilot blocked on the same drift. Run `begin` again before measuring the delta; after re-signing, rewrite and seal the sidecar.
127
131
  5. **Append** to the existing `.navori/state/handoffs/review_<feature>.md` — your own heading, observations continuing the original numbering — never overwrite it. The chain of what was approved when has to stay readable.
128
132
  6. **Limit (anti-rubber-stamp):** this mode only covers a delta that stays inside the change that was suggested. If it alters logic beyond that hunk, touches shared machinery, or lands in `{{project.criticalAreas}}`, it is NOT a delta re-sign — do the full review. Same if the drift has no known author (a rebase, another session, a stray checkout): with no explanation there's no delta to bound.
@@ -172,7 +176,7 @@ An unanswered doubt, or one concluded `issue`, follows the normal severity and s
172
176
  ### Quality gate (run this turn)
173
177
  | Check | Status | Evidence |
174
178
  |---|---|---|
175
- | `{{qualityGate.full}}` | [x] / [ ] | <output or exit code from this turn> |
179
+ | Gate (Pass 2 table: scoped on `CHANGES_REQUESTED`, full on `APPROVED`) | [x] / [ ] | <output or exit code from this turn> |
176
180
  | Failure attribution | [x] / [ ] | <state per failure (per `verify-before-done`) + the run over `origin/{{prTarget}}` that demonstrates it, this turn> |
177
181
 
178
182
  ### Conventions (CLAUDE.md + orchestrator's Project rules)
@@ -233,10 +237,10 @@ CHANGES_REQUESTED -> .navori/state/handoffs/review_<feature>.md
233
237
  - ❌ Never skip Pass 1 (spec compliance). If the code is pretty but doesn't do what was asked, it's `CHANGES_REQUESTED`.
234
238
  - ❌ Never include as a blocker (in "Issues ≥80") a finding with confidence <80.
235
239
  - ✅ Apply `.claude/skills/verify-before-done/SKILL.md` before marking APPROVED: each `[x]` must be backed by evidence run this turn (not from the implementer's cached report).
236
- - ❌ Never approve with `{{qualityGate.full}}` red.
240
+ - ❌ Never approve with the full gate red.
237
241
  - ❌ Never approve a failure legitimately classified *introduced (demonstrated)* per `verify-before-done`'s Failure attribution, and never classify one *pre-existing* by diff location alone.
238
242
  - ❌ Never approve new code with explicit or implicit `any` without a valid `// any justified: <reason>`.
239
- - ❌ Don't block or escalate a screen change to a human for lack of browser validation — the default gate is the diff + tests; require a visual check only when the user explicitly asked for one.
243
+
240
244
  - ✅ On APPROVED, write the content receipt (`.navori/state/handoffs/receipt.txt`) so the commit is bound to the reviewed bytes.
241
245
  - ❌ In SDD features (with `tasks.md`), never approve if some `R<n>` in the batch has no traceable test covering it.
242
246
  - ❌ You never edit the code. You only point out what fails and where.
@@ -58,7 +58,7 @@ navori_audit_record_metadata() {
58
58
  fi
59
59
  command -v navori >/dev/null 2>&1 || return 0
60
60
  case "${nv_engine:-}" in
61
- claude | codex) navori_audit_host=$nv_engine ;;
61
+ claude | codex | pi) navori_audit_host=$nv_engine ;;
62
62
  *) case "$navori_audit_script" in *".codex/hooks/"* | *".codex/scripts/"*) navori_audit_host=codex ;; *) navori_audit_host=claude ;; esac ;;
63
63
  esac
64
64
  # The writer assigns eventId/wireVersion before first persistence. Replay
@@ -99,7 +99,7 @@ navori_audit_log() {
99
99
  + (if (.tool_use_id|id) then {toolUseId:.tool_use_id} else {} end)
100
100
  + (if (["Bash","Edit","Read","Write","Agent","Task","NotebookEdit"]|index($tool)) != null then {tool:$tool} else {} end)
101
101
  + (if $reason == "" then {}
102
- elif (["oversize","no-verify","force-push-base","rm-root","rm-var","no-preserve-root","fork-bomb","block-device","managed-rewrite","binary-missing","plan-denied","subcommand-unavailable"]|index($reason)) != null then {reason:$reason}
102
+ elif (["oversize","no-verify","force-push-base","rm-root","rm-var","no-preserve-root","fork-bomb","block-device","managed-rewrite","binary-missing","plan-denied","subcommand-unavailable","native-hook"]|index($reason)) != null then {reason:$reason}
103
103
  else {reason:"unspecified"} end)
104
104
  + (($kind | if . == "" then (if $verdict == "block" then "hard" elif $verdict == "ask" then "ask" else "" end) else . end) as $k
105
105
  | if (["hard","ask","advisory"]|index($k)) != null then {kind:$k} else {} end)' 2>/dev/null) || return 0
@@ -25,7 +25,7 @@
25
25
  # the ORIGINAL signal with its default disposition — so the process still dies
26
26
  # from what it was sent instead of continuing as if nothing happened — and never
27
27
  # changes what the host does with the tool call. It is deliberately NOT a
28
- # process-tree kill: the gate's own child (`pnpm lint`, `semgrep`, `jscpd`)
28
+ # process-tree kill: the gate's own child (`pnpm lint`, a scanner)
29
29
  # already outlives the hook today, and killing someone else's build from an
30
30
  # observer is a decision of its own (#797, residue 3).
31
31
  #