session-orchestrator 5.2.0 → 5.4.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 (427) hide show
  1. package/.agents/skills/architecture/SKILL.md +3 -1
  2. package/.agents/skills/autopilot/SKILL.md +5 -1
  3. package/.agents/skills/autopilot/agents/openai.yaml +5 -0
  4. package/.agents/skills/bootstrap/SKILL.md +5 -1
  5. package/.agents/skills/bootstrap/agents/openai.yaml +5 -0
  6. package/.agents/skills/brainstorm/SKILL.md +5 -1
  7. package/.agents/skills/brainstorm/agents/openai.yaml +5 -0
  8. package/.agents/skills/claude-md-drift-check/SKILL.md +4 -2
  9. package/.agents/skills/close/SKILL.md +5 -1
  10. package/.agents/skills/close/agents/openai.yaml +5 -0
  11. package/.agents/skills/convergence-monitoring/SKILL.md +4 -2
  12. package/.agents/skills/debug/SKILL.md +5 -1
  13. package/.agents/skills/debug/agents/openai.yaml +5 -0
  14. package/.agents/skills/discovery/SKILL.md +5 -1
  15. package/.agents/skills/discovery/agents/openai.yaml +5 -0
  16. package/.agents/skills/dispatcher/SKILL.md +5 -1
  17. package/.agents/skills/dispatcher/agents/openai.yaml +5 -0
  18. package/.agents/skills/docs-orchestrator/SKILL.md +3 -1
  19. package/.agents/skills/ecosystem-health/SKILL.md +3 -1
  20. package/.agents/skills/eli5/SKILL.md +5 -1
  21. package/.agents/skills/eli5/agents/openai.yaml +5 -0
  22. package/.agents/skills/eval/SKILL.md +6 -2
  23. package/.agents/skills/eval/agents/openai.yaml +5 -0
  24. package/.agents/skills/evolve/SKILL.md +6 -2
  25. package/.agents/skills/evolve/agents/openai.yaml +5 -0
  26. package/.agents/skills/frontmatter-guard/SKILL.md +3 -1
  27. package/.agents/skills/gitlab-ops/SKILL.md +3 -1
  28. package/.agents/skills/gitlab-portfolio/SKILL.md +3 -1
  29. package/.agents/skills/go/SKILL.md +5 -1
  30. package/.agents/skills/go/agents/openai.yaml +5 -0
  31. package/.agents/skills/grill/SKILL.md +5 -1
  32. package/.agents/skills/grill/agents/openai.yaml +5 -0
  33. package/.agents/skills/harness-audit/SKILL.md +5 -1
  34. package/.agents/skills/harness-audit/agents/openai.yaml +5 -0
  35. package/.agents/skills/hook-development/SKILL.md +3 -1
  36. package/.agents/skills/mcp-builder/SKILL.md +3 -1
  37. package/.agents/skills/memory-cleanup/SKILL.md +5 -1
  38. package/.agents/skills/memory-cleanup/agents/openai.yaml +5 -0
  39. package/.agents/skills/mode-selector/SKILL.md +3 -1
  40. package/.agents/skills/navigator/SKILL.md +22 -0
  41. package/.agents/skills/navigator/agents/openai.yaml +5 -0
  42. package/.agents/skills/npm-publish/SKILL.md +4 -2
  43. package/.agents/skills/peekaboo-driver/SKILL.md +3 -1
  44. package/.agents/skills/persona-panel/SKILL.md +5 -1
  45. package/.agents/skills/persona-panel/agents/openai.yaml +5 -0
  46. package/.agents/skills/plan/SKILL.md +5 -1
  47. package/.agents/skills/plan/agents/openai.yaml +5 -0
  48. package/.agents/skills/playwright-driver/SKILL.md +3 -1
  49. package/.agents/skills/portfolio/SKILL.md +5 -1
  50. package/.agents/skills/portfolio/agents/openai.yaml +5 -0
  51. package/.agents/skills/quality-gates/SKILL.md +3 -1
  52. package/.agents/skills/reconcile/SKILL.md +5 -1
  53. package/.agents/skills/reconcile/agents/openai.yaml +5 -0
  54. package/.agents/skills/release/SKILL.md +5 -1
  55. package/.agents/skills/release/agents/openai.yaml +5 -0
  56. package/.agents/skills/remote-offload/SKILL.md +3 -1
  57. package/.agents/skills/repo-audit/SKILL.md +5 -1
  58. package/.agents/skills/repo-audit/agents/openai.yaml +5 -0
  59. package/.agents/skills/session/SKILL.md +21 -0
  60. package/.agents/skills/session/agents/openai.yaml +5 -0
  61. package/.agents/skills/session-end/SKILL.md +3 -1
  62. package/.agents/skills/session-plan/SKILL.md +3 -1
  63. package/.agents/skills/session-start/SKILL.md +3 -1
  64. package/.agents/skills/spinout/SKILL.md +5 -1
  65. package/.agents/skills/spinout/agents/openai.yaml +5 -0
  66. package/.agents/skills/sunset-review/SKILL.md +5 -1
  67. package/.agents/skills/sunset-review/agents/openai.yaml +5 -0
  68. package/.agents/skills/templates-ack/SKILL.md +21 -0
  69. package/.agents/skills/templates-ack/agents/openai.yaml +5 -0
  70. package/.agents/skills/test/SKILL.md +5 -1
  71. package/.agents/skills/test/agents/openai.yaml +5 -0
  72. package/.agents/skills/test-audit/SKILL.md +21 -0
  73. package/.agents/skills/test-audit/agents/openai.yaml +5 -0
  74. package/.agents/skills/test-runner/SKILL.md +3 -1
  75. package/.agents/skills/tmux-layout/SKILL.md +3 -1
  76. package/.agents/skills/using-orchestrator/SKILL.md +3 -1
  77. package/.agents/skills/ux-grill/SKILL.md +5 -1
  78. package/.agents/skills/ux-grill/agents/openai.yaml +5 -0
  79. package/.agents/skills/vault-mirror/SKILL.md +3 -1
  80. package/.agents/skills/vault-sync/SKILL.md +3 -1
  81. package/.agents/skills/wave-executor/SKILL.md +3 -1
  82. package/.agents/skills/write-executable-plan/SKILL.md +3 -1
  83. package/.claude-plugin/marketplace.json +1 -1
  84. package/.claude-plugin/plugin.json +1 -1
  85. package/.codex-plugin/plugin.json +4 -4
  86. package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
  87. package/.codex-plugin/skills/convergence-monitoring/SKILL.md +1 -3
  88. package/.codex-plugin/skills/eval/SKILL.md +1 -1
  89. package/.codex-plugin/skills/evolve/SKILL.md +1 -1
  90. package/.codex-plugin/skills/navigator/SKILL.md +22 -0
  91. package/.codex-plugin/skills/{convergence-monitoring → navigator}/agents/openai.yaml +2 -2
  92. package/.codex-plugin/skills/npm-publish/SKILL.md +1 -3
  93. package/.codex-plugin/skills/session/SKILL.md +1 -1
  94. package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
  95. package/.codex-plugin/skills/{npm-publish → test-audit}/agents/openai.yaml +1 -1
  96. package/.cursor/commands/eval.md +1 -1
  97. package/.cursor/commands/navigator.md +15 -0
  98. package/.cursor/commands/session.md +1 -1
  99. package/.cursor/commands/test-audit.md +14 -0
  100. package/.cursor/rules/000-session-orchestrator.mdc +0 -2
  101. package/.cursor/rules/050-plan.mdc +1 -1
  102. package/.cursor/rules/060-evolve.mdc +27 -12
  103. package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
  104. package/.cursor/skills/convergence-monitoring/SKILL.md +1 -0
  105. package/.cursor/skills/eval/SKILL.md +1 -1
  106. package/.cursor/skills/navigator/SKILL.md +13 -0
  107. package/.cursor/skills/npm-publish/SKILL.md +1 -0
  108. package/.cursor/skills/test-audit/SKILL.md +12 -0
  109. package/.cursor-plugin/plugin.json +1 -1
  110. package/.orchestrator/policy/blocked-commands.json +12 -3
  111. package/AGENTS.md +9 -30
  112. package/CHANGELOG.md +206 -0
  113. package/README.md +13 -9
  114. package/SECURITY.md +12 -0
  115. package/agents/dialectic-deriver.md +13 -10
  116. package/agents/eval-judge.md +67 -45
  117. package/agents/skill-applied-judge.md +34 -19
  118. package/commands/session.md +7 -3
  119. package/docs/agent-authoring.md +2 -2
  120. package/docs/baseline.md +22 -7
  121. package/docs/ci-setup.md +57 -4
  122. package/docs/codex-setup.md +14 -2
  123. package/docs/components.md +12 -10
  124. package/docs/events-schema.md +65 -15
  125. package/docs/persona-panel.md +5 -4
  126. package/docs/rule-authoring.md +84 -17
  127. package/docs/scope-collision-guard.md +26 -4
  128. package/docs/session-config-reference.md +154 -12
  129. package/docs/session-config-template.md +41 -3
  130. package/docs/telemetry.md +2 -0
  131. package/hooks/_lib/hook-import-set.json +87 -6
  132. package/hooks/_lib/subagent-transcript.mjs +582 -31
  133. package/hooks/config-protection.mjs +11 -3
  134. package/hooks/cwd-change-restore.mjs +11 -3
  135. package/hooks/enforce-commands.mjs +70 -23
  136. package/hooks/enforce-scope.mjs +143 -33
  137. package/hooks/hooks-codex.json +1 -1
  138. package/hooks/hooks-cursor.json +5 -0
  139. package/hooks/hooks-pi.json +5 -0
  140. package/hooks/hooks.json +6 -1
  141. package/hooks/loop-guard.mjs +11 -3
  142. package/hooks/on-session-end.mjs +58 -23
  143. package/hooks/on-session-start.mjs +101 -11
  144. package/hooks/on-stop.mjs +170 -22
  145. package/hooks/operator-steer.mjs +11 -3
  146. package/hooks/post-bash-issue-budget-refund.mjs +18 -8
  147. package/hooks/post-bash-write-verify.mjs +3 -2
  148. package/hooks/post-edit-import-probe.mjs +17 -9
  149. package/hooks/post-edit-validate.mjs +13 -5
  150. package/hooks/post-subagent-discovery-validator.mjs +98 -13
  151. package/hooks/post-tool-batch-wave-signal.mjs +202 -38
  152. package/hooks/post-tool-failure-corrective-context.mjs +11 -5
  153. package/hooks/post-tooluse-frontend-slop.mjs +10 -4
  154. package/hooks/pre-auq-clarity.mjs +15 -2
  155. package/hooks/pre-bash-destructive-guard.mjs +80 -9
  156. package/hooks/pre-bash-issue-budget.mjs +16 -11
  157. package/hooks/pre-bash-memory-propose-audit.mjs +137 -56
  158. package/hooks/pre-bash-sessions-ledger-guard.mjs +419 -22
  159. package/hooks/pre-bash-staging-fence.mjs +335 -31
  160. package/hooks/pre-bash-templates-first.mjs +19 -14
  161. package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
  162. package/hooks/pre-task-scope-disjoint.mjs +792 -74
  163. package/hooks/subagent-telemetry.mjs +111 -38
  164. package/hooks/wave-scope-commit-guard.mjs +197 -100
  165. package/monitors/monitors.json +1 -1
  166. package/output-styles/wave-summary.md +1 -1
  167. package/package.json +3 -3
  168. package/pi/prompts/eval.md +1 -1
  169. package/pi/prompts/navigator.md +12 -0
  170. package/pi/prompts/session.md +1 -1
  171. package/pi/prompts/test-audit.md +12 -0
  172. package/rules/README.md +7 -2
  173. package/rules/_index.md +3 -3
  174. package/rules/always-on/bash-harness-pitfalls.md +7 -1
  175. package/rules/opt-in-domain/prompt-caching.md +6 -2
  176. package/rules/opt-in-stack/backend-data.md +10 -2
  177. package/rules/opt-in-stack/backend.md +10 -4
  178. package/rules/opt-in-stack/frontend.md +7 -2
  179. package/rules/opt-in-stack/security-web.md +10 -4
  180. package/rules/opt-in-stack/swift.md +6 -2
  181. package/scripts/apply-session-learnings.mjs +492 -0
  182. package/scripts/archive-closed-prds.mjs +2 -1
  183. package/scripts/autopilot.mjs +70 -53
  184. package/scripts/backfill-abandoned-sessions.mjs +118 -16
  185. package/scripts/baseline-archetypes.mjs +1 -1
  186. package/scripts/check-package-manager.mjs +62 -5
  187. package/scripts/check-sessions-integrity.mjs +300 -0
  188. package/scripts/cursor-install.mjs +1 -4
  189. package/scripts/dialectic-deriver.mjs +50 -13
  190. package/scripts/emit-session.mjs +371 -31
  191. package/scripts/eval-session.mjs +65 -3
  192. package/scripts/export-hw-learnings.mjs +22 -3
  193. package/scripts/fleet-checkin.mjs +147 -0
  194. package/scripts/generate-agents-skills.mjs +102 -29
  195. package/scripts/generate-cursor-adapter.mjs +61 -16
  196. package/scripts/lib/agent-frontmatter.mjs +3 -3
  197. package/scripts/lib/agent-status.mjs +2 -31
  198. package/scripts/lib/auq/clarity.mjs +10 -2
  199. package/scripts/lib/auq/parse.mjs +12 -31
  200. package/scripts/lib/auq/schema.mjs +56 -41
  201. package/scripts/lib/auto-dialectic.mjs +304 -15
  202. package/scripts/lib/auto-dream.mjs +7 -6
  203. package/scripts/lib/autopilot/flags.mjs +18 -2
  204. package/scripts/lib/autopilot/kill-switches.mjs +6 -3
  205. package/scripts/lib/autopilot/loop.mjs +19 -2
  206. package/scripts/lib/autopilot/stall-sampler.mjs +80 -23
  207. package/scripts/lib/baseline-archetypes.mjs +41 -22
  208. package/scripts/lib/ci-status-banner.mjs +376 -16
  209. package/scripts/lib/command-blocker.mjs +275 -28
  210. package/scripts/lib/config/dialectic.mjs +12 -3
  211. package/scripts/lib/config/gate.mjs +74 -0
  212. package/scripts/lib/config/host-paths.mjs +79 -0
  213. package/scripts/lib/config/persona-gate-wave.mjs +3 -3
  214. package/scripts/lib/config/reaper.mjs +163 -0
  215. package/scripts/lib/config-schema.mjs +13 -0
  216. package/scripts/lib/config.mjs +85 -10
  217. package/scripts/lib/convergence-monitor.mjs +74 -11
  218. package/scripts/lib/ecosystem-health.mjs +11 -0
  219. package/scripts/lib/eval/engine.mjs +421 -53
  220. package/scripts/lib/eval/judge.mjs +463 -40
  221. package/scripts/lib/eval/schema.mjs +10 -1
  222. package/scripts/lib/events-rotation.mjs +221 -25
  223. package/scripts/lib/events-schema.mjs +114 -0
  224. package/scripts/lib/events.mjs +545 -7
  225. package/scripts/lib/fleet-protocol.mjs +270 -0
  226. package/scripts/lib/frontmatter-guard.mjs +21 -10
  227. package/scripts/lib/gates/gate-baseline.mjs +40 -5
  228. package/scripts/lib/gates/gate-full.mjs +35 -5
  229. package/scripts/lib/gates/gate-helpers.mjs +336 -23
  230. package/scripts/lib/gates/gate-incremental.mjs +49 -23
  231. package/scripts/lib/gates/gate-per-file.mjs +42 -8
  232. package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +6 -1
  233. package/scripts/lib/instruction-budget-guard.mjs +208 -8
  234. package/scripts/lib/io.mjs +42 -8
  235. package/scripts/lib/issue-close-strip-labels.mjs +207 -49
  236. package/scripts/lib/js-mask.mjs +197 -0
  237. package/scripts/lib/learnings/evolve-telemetry.mjs +11 -7
  238. package/scripts/lib/learnings/expiry-sweep.mjs +34 -3
  239. package/scripts/lib/learnings/io.mjs +154 -26
  240. package/scripts/lib/learnings/schema.mjs +163 -15
  241. package/scripts/lib/learnings/sizing-subject.mjs +2 -2
  242. package/scripts/lib/maintenance-due-banner.mjs +53 -88
  243. package/scripts/lib/memory-proposals/schema.mjs +11 -5
  244. package/scripts/lib/named-baseline-resolver.mjs +53 -28
  245. package/scripts/lib/named-vault-resolver.mjs +104 -5
  246. package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
  247. package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
  248. package/scripts/lib/orphan-reaper/reaper-audit.mjs +291 -0
  249. package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
  250. package/scripts/lib/orphan-reaper/scan-throttle.mjs +92 -0
  251. package/scripts/lib/orphan-reaper/scan.mjs +506 -0
  252. package/scripts/lib/orphan-reaper.mjs +316 -0
  253. package/scripts/lib/owner-yaml.mjs +104 -6
  254. package/scripts/lib/peer-cards/merger.mjs +48 -10
  255. package/scripts/lib/peer-cards/reader.mjs +78 -2
  256. package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
  257. package/scripts/lib/process-group.mjs +950 -0
  258. package/scripts/lib/project-hygiene.mjs +21 -1
  259. package/scripts/lib/quality-gate.mjs +152 -33
  260. package/scripts/lib/reconcile/backlog.mjs +368 -0
  261. package/scripts/lib/reconcile/engine.mjs +55 -188
  262. package/scripts/lib/reconcile/rule-expiry-sweep.mjs +302 -60
  263. package/scripts/lib/reconcile/sanitize.mjs +69 -3
  264. package/scripts/lib/reconcile-nudge-banner.mjs +138 -45
  265. package/scripts/lib/resource-probe/parsers.mjs +31 -0
  266. package/scripts/lib/resource-probe.mjs +1 -1
  267. package/scripts/lib/rule-loader.mjs +141 -74
  268. package/scripts/lib/rules-sync.mjs +27 -12
  269. package/scripts/lib/scope-baseline.mjs +3 -4
  270. package/scripts/lib/scope-echo.mjs +39 -2
  271. package/scripts/lib/scope-gate.mjs +605 -1
  272. package/scripts/lib/session-close-backfill.mjs +33 -6
  273. package/scripts/lib/session-id.mjs +9 -20
  274. package/scripts/lib/session-invocation.mjs +20 -0
  275. package/scripts/lib/session-record-repair.mjs +183 -26
  276. package/scripts/lib/session-registry.mjs +27 -2
  277. package/scripts/lib/session-schema/constants.mjs +56 -2
  278. package/scripts/lib/session-schema/normalizer.mjs +56 -4
  279. package/scripts/lib/session-schema/validator.mjs +28 -1
  280. package/scripts/lib/session-schema.mjs +8 -3
  281. package/scripts/lib/session-start-probes.mjs +95 -10
  282. package/scripts/lib/session-token-rollup.mjs +245 -52
  283. package/scripts/lib/sessions-canonical.mjs +118 -4
  284. package/scripts/lib/sessions-integrity-banner.mjs +7 -1
  285. package/scripts/lib/sessions-staleness-banner.mjs +193 -51
  286. package/scripts/lib/sh-quote.mjs +29 -0
  287. package/scripts/lib/skill-evidence-window.mjs +891 -0
  288. package/scripts/lib/skill-evolution/candidate-intake.mjs +133 -12
  289. package/scripts/lib/skill-evolution/engine.mjs +18 -9
  290. package/scripts/lib/skill-judge.mjs +45 -3
  291. package/scripts/lib/subagents-schema.mjs +30 -3
  292. package/scripts/lib/tail-window.mjs +56 -0
  293. package/scripts/lib/telemetry/pricing.mjs +118 -71
  294. package/scripts/lib/telemetry/schema.mjs +30 -0
  295. package/scripts/lib/telemetry/sync.mjs +61 -6
  296. package/scripts/lib/telemetry-flush-health-banner.mjs +4 -22
  297. package/scripts/lib/test-runner/issue-reconcile.mjs +48 -16
  298. package/scripts/lib/tests-src-ratio.mjs +140 -23
  299. package/scripts/lib/tmux-layout/layouts.mjs +1 -11
  300. package/scripts/lib/tmux-layout/telemetry-stats.mjs +72 -13
  301. package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
  302. package/scripts/lib/user-invocable-skills.mjs +23 -3
  303. package/scripts/lib/ux-grill/reconcile.mjs +48 -22
  304. package/scripts/lib/validate/check-agents-skills.mjs +26 -15
  305. package/scripts/lib/validate/check-agents.mjs +1 -1
  306. package/scripts/lib/validate/check-cursor-adapter.mjs +1 -0
  307. package/scripts/lib/validate/check-entry-guard.mjs +13 -50
  308. package/scripts/lib/validate/check-hook-entry-guards.mjs +636 -0
  309. package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
  310. package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
  311. package/scripts/lib/validate/check-pi-prompts.mjs +1 -0
  312. package/scripts/lib/validate/check-rules.mjs +7 -5
  313. package/scripts/lib/validate/check-skill-links.mjs +9 -1
  314. package/scripts/lib/validate/check-skill-script-paths.mjs +239 -27
  315. package/scripts/lib/validate/check-test-git-config-target.mjs +24 -34
  316. package/scripts/lib/validate/check-test-value-bans.mjs +87 -14
  317. package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
  318. package/scripts/lib/validate/check-untracked-test-deps.mjs +7 -102
  319. package/scripts/lib/validate/check-unwired-features.mjs +130 -27
  320. package/scripts/lib/validate/check-validator-registration.mjs +34 -10
  321. package/scripts/lib/validate/confidential-names.mjs +10 -0
  322. package/scripts/lib/validate-vendored-rules.mjs +210 -84
  323. package/scripts/lib/vault-mirror/namespace.mjs +46 -8
  324. package/scripts/lib/vault-mirror/process.mjs +10 -3
  325. package/scripts/lib/vault-mirror/render-sessions.mjs +12 -2
  326. package/scripts/lib/vault-mirror/telemetry.mjs +8 -1
  327. package/scripts/lib/vault-status/board-writer.mjs +48 -11
  328. package/scripts/lib/vault-status/narrative-mirror.mjs +71 -16
  329. package/scripts/lib/vault-yaml.mjs +118 -0
  330. package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
  331. package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
  332. package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
  333. package/scripts/lib/wave-resource-gate.mjs +34 -8
  334. package/scripts/lib/worktree/lifecycle.mjs +153 -1
  335. package/scripts/memory-propose.mjs +18 -5
  336. package/scripts/release-session-lock.mjs +306 -0
  337. package/scripts/release.mjs +40 -8
  338. package/scripts/repair-invalid-sessions.mjs +37 -4
  339. package/scripts/resolve-session-invocation.mjs +59 -0
  340. package/scripts/run-migrate-v2-cross-repo.mjs +158 -30
  341. package/scripts/run-quality-gate.mjs +357 -197
  342. package/scripts/site-numbers.mjs +163 -5
  343. package/scripts/sweep-expired-learnings.mjs +56 -5
  344. package/scripts/sweep-expired-rules.mjs +16 -4
  345. package/scripts/validate-plugin.mjs +19 -0
  346. package/scripts/validate-wave-scope.mjs +32 -105
  347. package/scripts/vault-integration-watcher.mjs +2 -1
  348. package/scripts/vault-mirror.mjs +81 -47
  349. package/scripts/wave-scope-binding.mjs +2 -1
  350. package/skills/_shared/config-reading.md +3 -3
  351. package/skills/_shared/fleet-protocol.md +131 -0
  352. package/skills/_shared/platform-tools.md +23 -11
  353. package/skills/_shared/state-ownership.md +5 -0
  354. package/skills/autopilot/SKILL.md +47 -18
  355. package/skills/bootstrap/SKILL.md +1 -1
  356. package/skills/bootstrap/_shared-template.md +1 -1
  357. package/skills/bootstrap/fast-template.md +1 -1
  358. package/skills/bootstrap/private-contract.md +2 -1
  359. package/skills/bootstrap/public-fallback.md +6 -3
  360. package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
  361. package/skills/claude-md-drift-check/SKILL.md +10 -10
  362. package/skills/claude-md-drift-check/checker.mjs +26 -18
  363. package/skills/convergence-monitoring/README.md +8 -1
  364. package/skills/convergence-monitoring/SIGNALS.md +50 -6
  365. package/skills/convergence-monitoring/SKILL.md +15 -6
  366. package/skills/eval/SKILL.md +39 -24
  367. package/skills/eval/rubric-v1.md +1 -0
  368. package/skills/eval/rubric-v2.md +457 -0
  369. package/skills/evolve/SKILL.md +3 -3
  370. package/skills/evolve/references/evolve-analyze-mode.md +10 -6
  371. package/skills/evolve/references/evolve-dialectic-mode.md +42 -25
  372. package/skills/gitlab-ops/SKILL.md +3 -2
  373. package/skills/memory-cleanup/SKILL.md +1 -1
  374. package/skills/navigator/SKILL.md +193 -0
  375. package/skills/navigator/references/account-check.sh +87 -0
  376. package/skills/navigator/references/fleet-decisions.mjs +231 -0
  377. package/skills/navigator/references/slot-check.sh +114 -0
  378. package/skills/npm-publish/SKILL.md +1 -1
  379. package/skills/persona-panel/SKILL.md +2 -2
  380. package/skills/persona-panel/persona-format.md +2 -2
  381. package/skills/persona-panel/presets/designer-lens.md +1 -1
  382. package/skills/persona-panel/presets/engineer-lens.md +1 -1
  383. package/skills/persona-panel/presets/pm-lens.md +1 -1
  384. package/skills/plan/mode-retro.md +19 -4
  385. package/skills/quality-gates/SKILL.md +6 -4
  386. package/skills/reconcile/SKILL.md +11 -0
  387. package/skills/remote-offload/SKILL.md +4 -2
  388. package/skills/session-end/SKILL.md +13 -16
  389. package/skills/session-end/discovery-scan.md +1 -1
  390. package/skills/session-end/learning-patterns.md +22 -12
  391. package/skills/session-end/metrics-collection.md +5 -6
  392. package/skills/session-end/phase-3-6-tail.md +55 -9
  393. package/skills/session-end/references/phase-3-documentation-updates.md +2 -2
  394. package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
  395. package/skills/session-end/references/phase-5-issue-cleanup.md +9 -14
  396. package/skills/session-end/references/session-summary-template.md +1 -1
  397. package/skills/session-end/session-metrics-write.md +32 -60
  398. package/skills/session-plan/SKILL.md +17 -8
  399. package/skills/session-plan/references/session-plan-task-classification.md +2 -2
  400. package/skills/session-start/SKILL.md +6 -0
  401. package/skills/session-start/references/operations-contract.md +4 -0
  402. package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
  403. package/skills/session-start/references/phase-4-ssot-environment-check.md +4 -3
  404. package/skills/test-audit/SKILL.md +152 -0
  405. package/skills/test-audit/references/campaign.md +111 -0
  406. package/skills/test-audit/references/mutate.sh +50 -0
  407. package/skills/ux-grill/SKILL.md +1 -1
  408. package/skills/wave-executor/SKILL.md +9 -5
  409. package/skills/wave-executor/circuit-breaker.md +2 -0
  410. package/skills/wave-executor/references/wave-executor-state-init.md +8 -3
  411. package/skills/wave-executor/references/wave-loop-dispatch.md +5 -2
  412. package/skills/wave-executor/references/wave-loop-review.md +3 -5
  413. package/templates/personas/README.md +5 -5
  414. package/templates/personas/accounting-compliance.v1.md +1 -1
  415. package/templates/personas/accounting-tax-advisor.v1.md +1 -1
  416. package/templates/personas/buyer-p1-cto.v1.md +1 -1
  417. package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
  418. package/templates/personas/buyer-p3-build.v1.md +1 -1
  419. package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
  420. package/templates/personas/buyer-p5-solo.v1.md +1 -1
  421. package/templates/personas/buyer-p6-ld.v1.md +1 -1
  422. package/templates/personas/klima-ai-expert.v1.md +1 -1
  423. package/templates/personas/klima-physicist.v1.md +1 -1
  424. package/.cursor/commands/convergence-monitoring.md +0 -13
  425. package/.cursor/commands/npm-publish.md +0 -13
  426. package/pi/prompts/convergence-monitoring.md +0 -11
  427. package/pi/prompts/npm-publish.md +0 -11
@@ -8,7 +8,7 @@
8
8
 
9
9
  Single-pass LLM derivation of USER.md + AGENT.md (peer cards from #503) updates from current learnings + sessions + steering files. Dry-run-default per #506 EARS contract.
10
10
 
11
- **Telemetry start marker (#1200):** note the current wall-clock time at Phase 6 entry (`DURATION_MS` in the Step 6.4/6.5 emits below is the elapsed milliseconds since this marker) — same placeholder convention as `skills/session-end/SKILL.md`'s `orchestrator.handover.gated` emits.
11
+ **Telemetry start marker (#1200):** note the current wall-clock time at Phase 6 entry (`DURATION_MS` in the Step 6.4 apply emit below is the elapsed milliseconds since this marker) — same placeholder convention as `skills/session-end/SKILL.md`'s `orchestrator.handover.gated` emits.
12
12
 
13
13
  ### Step 6.0: Argument Parsing
14
14
 
@@ -19,14 +19,14 @@ Parse `$ARGUMENTS` for trailing flags after the `dialectic` keyword:
19
19
  | `--apply` | `false` | Write diff to USER.md/AGENT.md via merger.mjs; without it = dry-run |
20
20
  | `--dry-run` | `true` | Explicit dry-run (default); mutually exclusive with --apply |
21
21
  | `--model <name>` | from Session Config `dialectic.model` (default `haiku`) | Override LLM |
22
- | `--budget-tokens <N>` | from Session Config `dialectic.budget-tokens` (default 8000) | Token budget |
22
+ | `--budget-tokens <N>` | from Session Config `dialectic.budget-tokens` (default 32000) | Input-token ceiling (the pre-dispatch estimate aborts above it; not a spend) |
23
23
 
24
24
  Mutex check: `--apply` + `--dry-run` together = error "flags mutually exclusive".
25
25
 
26
26
  ### Step 6.1: Pre-checks
27
27
  - Bootstrap gate (Phase 0) — already executed
28
28
  - Persistence check (Phase 1.2) — already executed
29
- - Cadence check: if invoked via session-end Phase 3.6.7 auto-trigger, the trigger has already pre-checked cadence. For manual invocation, skip cadence — manual always runs.
29
+ - Cadence check: none. `/evolve dialectic` is invoked MANUALLY (by the operator, or by the session-start maintenance loop acting on the `maintenance-due` probe's `dialectic` signal) and always runs. The session-end Phase 3.6.7 auto-trigger that used to pre-check cadence was removed in #1288; `shouldDispatchAutoDialectic` (`scripts/lib/auto-dialectic.mjs`) survives only as the side-effect-free signal that probe reads, and this phase never calls it.
30
30
 
31
31
  ### Step 6.2: Data Load
32
32
  Read all 4 input sources via `runDialecticDeriver()` from `scripts/dialectic-deriver.mjs` (see W2 I1):
@@ -60,19 +60,39 @@ const result = await runDialecticDeriver({
60
60
  dispatchAgent,
61
61
  repoRoot: process.cwd(),
62
62
  model: argv.model ?? config.dialectic?.model ?? 'haiku',
63
- budget: { input: argv['budget-tokens'] ?? config.dialectic?.['budget-tokens'] ?? 8000, output: 4000 },
63
+ budget: { input: argv['budget-tokens'] ?? config.dialectic?.['budget-tokens'] ?? 32000, output: 4000 },
64
64
  dryRun: !argv.apply,
65
65
  allowEmptying: argv['allow-emptying'] ?? false,
66
66
  });
67
67
  ```
68
68
 
69
69
  ### Step 6.4: Diff Output & Apply Gate
70
- - If dry-run (default): present diff inline; write to `.orchestrator/dialectic-pending.md` via `writeDialecticPending({ repoRoot, diff })` from `scripts/lib/auto-dialectic.mjs` (path constant `DIALECTIC_PENDING_PATH`; atomic tmp+rename). `runDialecticDeriver()` does NOT write this file itself — the dry-run branch returns the diff and the caller persists it. The body parameter is named `diff`, not `body`: a non-string or empty value throws `TypeError`, as does a missing `repoRoot`. EXIT. Suggestion: "Re-run with `/evolve --dialectic --apply` to apply." <!-- path-check: example -->
70
+ - If dry-run (default): present diff inline; write to `.orchestrator/dialectic-pending.md` via `writeDialecticPending({ repoRoot, diff })` from `scripts/lib/auto-dialectic.mjs` (path constant `DIALECTIC_PENDING_PATH`; atomic tmp+rename). `runDialecticDeriver()` does NOT write this file itself — the dry-run branch returns the diff and the caller persists it. The body parameter is named `diff`, not `body`, and it is a Markdown **string**: `result.diff` is an OBJECT `{ user?, agent? }`, so serialize it first — passing the object throws `TypeError` (as does an empty string or a missing `repoRoot`). An empty `result.diff` (no target proposed) has nothing to review: write no sidecar. EXIT. Suggestion: "Re-run with `/evolve --dialectic --apply` to apply." <!-- path-check: example -->
71
+
72
+ ```javascript
73
+ const pendingBody = renderPendingBody(result.diff); // scripts/lib/auto-dialectic.mjs
74
+ if (pendingBody) {
75
+ await writeDialecticPending({ repoRoot, diff: pendingBody, usage: result.usage, model });
76
+ }
77
+ ```
78
+
79
+ `renderPendingBody({ user?, agent? })` is the serializer that used to live here as a snippet (#1386). It is now code so the dry-run write and the apply-time drift check below build the body the SAME way — two hand-copied serializers would report drift that is only formatting. It returns `''` when neither target is a string: nothing to review, write no sidecar.
80
+ - **Before `--apply` writes anything: show the operator what changed since he approved (#1386).** `--apply` re-derives from the model (`dispatchAgent` runs unconditionally in `scripts/dialectic-deriver.mjs`), so under variant (b) the apply still costs a SECOND model call and what would be applied is not necessarily what was read in `.orchestrator/dialectic-pending.md`. This step makes that drift VISIBLE; it does **not** make apply deterministic. Run it after the fresh derivation and BEFORE any `writePeerCard()` call: <!-- path-check: example -->
81
+
82
+ ```javascript
83
+ const fresh = renderPendingBody(result.diff);
84
+ const cmp = await comparePendingBody({ repoRoot, body: fresh }); // never throws
85
+ ```
86
+
87
+ - `cmp.sidecarAbsent === true` (no sidecar — the operator may never have run the dry-run) or `cmp.drifted === false`: apply SILENTLY. An `AskUserQuestion` that blocks nothing is a rule break (`.claude/rules/ask-via-tool.md` AUQ-001/AUQ-005).
88
+ - `cmp.drifted === true`: present BOTH bodies (`cmp.sidecarBody` = approved, `cmp.freshBody` = fresh) and ask via `AskUserQuestion` — two options, each description carrying reason + cost + consequence, and the drifted text in the option `preview` so the operator decides from the payload rather than from a file:
89
+ - **"Frischen Vorschlag anwenden (Recommended)"** — recommended because the fresh derivation saw the newest learnings and sessions, while the sidecar is a snapshot of an earlier run; cost: the peer cards get text the operator has not reviewed line by line; consequence: cards are written, `writeDialecticLastRun` + `consumeDialecticPending` run, the sidecar is archived.
90
+ - **"Verwerfen, Sidecar für eine weitere Prüfung behalten"** — when the delta is large enough to want a second read; cost: the second model call just spent is wasted and `--apply` must run again later; consequence: **nothing is written to the peer cards and the sidecar is NOT consumed** — skip both bookkeeping calls below so the `pending-sidecar` signal keeps the review due. EXIT.
71
91
  - If `--apply`: call **`mergeDerivedBody(existingBody, result.diff[target])`** from `scripts/lib/peer-cards/merger.mjs` for each card target, then `writePeerCard(repoRoot, 'user', mergedUserCard)` and `writePeerCard(repoRoot, 'agent', mergedAgentCard)` from `scripts/lib/peer-cards/writer.mjs`. Update the `updated:` frontmatter.
72
92
 
73
93
  **`writePeerCard` shape (#1303).** `writePeerCard(repoRoot, target, card)` takes `card = { frontmatter, body }`. `frontmatter.id` (kebab-case slug, 2..128 chars) is **required and never auto-filled**; `type: 'peer-card'`, `target`, `updated` (defaults to `new Date().toISOString()`) and `created` (defaults to `updated`) are filled by the writer. ISO timestamps may carry optional milliseconds (`scripts/lib/peer-cards/schema.mjs` `ISO_DATETIME_REGEX`). A missing `id` returns `{ ok: false, errors: [...] }` and leaves the target file untouched — it does **not** throw; branch on `result.ok`.
74
94
 
75
- **Why `mergeDerivedBody` and not `mergePeerCard` directly (#1310):** the deriver emits a FULL BODY STRING per target (`agents/dialectic-deriver.md` § Output format); `mergePeerCard` consumes a SECTION MAP keyed by sentinel name. `mergeDerivedBody` is the adapter between the two — it splits the proposed body at `## ` headings and maps each heading to a sentinel section. `mergePeerCard` stays available as the section-map primitive. Handling per heading class, all of it in `mergeDerivedBody`'s return value:
95
+ **Why `mergeDerivedBody` and not `mergePeerCard` directly (#1310):** the deriver emits, per target, the WHOLE `## ` SECTIONS it changes or adds — never the card's full body (`agents/dialectic-deriver.md` § Output format: "Omitted sections stay unchanged (nothing auto-deletes), so emit only the sections you change or newly ground"). `mergePeerCard` consumes a SECTION MAP keyed by sentinel name. `mergeDerivedBody` is the adapter between the two — it splits the proposed text at `## ` headings and maps each heading to a sentinel section, merging SECTION-WISE. Do not read this as a full-body replacement: a deriver that emitted the full body would overwrite every hand-written managed section with an LLM reproduction, and `detectEmptying` (`scripts/dialectic-deriver.mjs`) would not catch it — it refuses only a proposal with ZERO content lines. `mergePeerCard` stays available as the section-map primitive. Handling per heading class, all of it in `mergeDerivedBody`'s return value:
76
96
 
77
97
  | Heading in the proposed body | Section name | Merge effect | Surfaced as |
78
98
  |---|---|---|---|
@@ -81,10 +101,18 @@ const result = await runDialecticDeriver({
81
101
  | Existing managed section the proposal omits | — | KEPT (no auto-delete, per `mergePeerCard` semantics) | — |
82
102
  | Section name outside `[A-Za-z0-9_-]+` | — | `mergePeerCard` **throws** `invalid section name` | fix the name before merging |
83
103
  | Text before the first `## ` heading | — | NOT applied | `preamble` + a `{ type: 'unmapped-preamble' }` entry in `conflicts[]` |
104
+ | Falls inside an existing managed region that wraps MORE than one `## ` heading | — | NOT applied — the region stays byte-unchanged (no replace, which would delete its sibling headings' hand-written text; no append, which would duplicate the heading) | `{ type: 'multi-heading-region', region, headings, skipped }` in `conflicts[]` — `region` is the region's section name, `headings` the `## ` headings it wraps, `skipped` the proposed headings dropped. Operator action: split the region by hand into one managed region per heading, then re-run — or discard the proposal for those headings |
84
105
 
85
106
  Existing names are read back out of the card rather than re-derived because the live names are not a pure function of their headings — measured 2026-09-11 in `.orchestrator/peers/AGENT.md`: `## Guard and protocol-migration discipline` → `guard-and-protocol-migration`. Re-slugifying would APPEND a duplicate section instead of replacing one.
86
107
 
87
- **Present `conflicts[]` before writing.** A non-empty `conflicts[]` (`duplicate-section`, `orphan-begin`, `unmapped-preamble`) is operator-visible content that the merge did not place — report it beside the delta line rather than writing silently.
108
+ **Present `conflicts[]` before writing.** A non-empty `conflicts[]` (`duplicate-section`, `orphan-begin`, `unmapped-preamble`, `multi-heading-region`) is operator-visible content that the merge did not place — report it beside the delta line rather than writing silently.
109
+ - **Close the loop — after a successful `--apply` AND after the operator explicitly discards a reviewed proposal** (never after a dry-run, a failure, a skip, or the drift-check's "keep the sidecar for another review" branch above): record the run and consume the sidecar, both from `scripts/lib/auto-dialectic.mjs`. Without these two calls the maintenance-due probe keeps `dialectic` (measured against `.orchestrator/dialectic-last-run`) and `pending-sidecar` (`.orchestrator/dialectic-pending.md` younger than 14 days) due forever — nothing else writes the one or moves the other (#1380). Both return `{ ok, error? }` and never throw; log a failure and continue. Since #1388 `consumeDialecticPending` MOVES the sidecar to `.orchestrator/consumed/<timestamp>-dialectic-pending.md` (newest 10 retained) instead of deleting it, so the reviewed text survives the apply; `archivedTo` on the result names the file. <!-- path-check: example -->
110
+
111
+ ```javascript
112
+ const lastRun = await writeDialecticLastRun({ repoRoot, isoTimestamp: new Date().toISOString() });
113
+ const consumed = await consumeDialecticPending({ repoRoot }); // ENOENT → { ok: true, consumed: false }
114
+ if (!lastRun.ok || !consumed.ok) console.error(`⚠ dialectic bookkeeping: ${lastRun.error ?? consumed.error}`);
115
+ ```
88
116
  - Report: `Dialectic-derived: M deltas to USER.md, N deltas to AGENT.md. Dry-run | Applied. Tokens: in=<X> out=<Y>.`
89
117
 
90
118
  **Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs`, not skill prose.**
@@ -117,27 +145,16 @@ await recordDialecticRun({
117
145
  ### Step 6.5: Error Handling
118
146
  - `status: 'unknown-model'` → fail with clear error (already thrown by validateModel)
119
147
  - `status: 'budget-exceeded'` → emit `{status:'budget-exceeded', used:N, budget:M}`, do NOT truncate.
120
- Measured in a consumer repo (S119, 2026-09-10): 12 learnings + 127 sessions estimated at 11 158 input tokens against the 8000 default. Raise with `--budget-tokens 16000` or `dialectic.budget-tokens` in Session Config rather than trimming inputs.
148
+ The budget is an input CEILING, not a spend. The former 8000 default aborted real runs — a consumer repo estimated 11 158 input tokens (S119, 2026-09-10) and later 30 262, this repo ~12 268 for card bodies + steering alone — so the default is 32000 since #1380. If a repo still exceeds it, raise `--budget-tokens` or `dialectic.budget-tokens` in Session Config rather than trimming inputs.
121
149
  - `status: 'would-empty-card'` → warn + require `--allow-emptying` flag
122
150
  - `status: 'empty-input'` → exit clean with message "dialectic: skipped (no input)"
123
151
  - subagent crash → log ⚠, exit cleanly (do NOT write to `.orchestrator/dialectic-pending.md`) <!-- path-check: example -->
124
152
 
125
- **Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs` for THREE of the five
126
- outcomes.** `budget-exceeded`, `would-empty-card`, and `empty-input` are `runDialecticDeriver()`
127
- RETURN values, so the module records them itself, mechanically, at the exact return point —
128
- nothing to do here for those three. The remaining two are THROWN, not returned, and can only be
129
- caught one layer up:
130
-
131
- - `unknown-model` — `validateModel()` throws synchronously before `runDialecticDeriver()` can
132
- record anything about the call.
133
- - `subagent-crash` — a `dispatchAgent`/`Agent()` failure propagates out of
134
- `runDialecticDeriver()` uncaught (it has no status of its own for this case).
135
-
136
- Catch both here and call the SAME `recordDialecticRun()` used in Step 6.4's apply branch,
137
- passing the literal slug as `status` (the abort form: `{aborted: status, duration_ms}`):
138
-
139
- ```javascript
140
- await recordDialecticRun({ repoRoot, status: 'unknown-model' /* or 'subagent-crash' */, durationMs: DURATION_MS });
141
- ```
153
+ **Telemetry (#1200, #1206, #1221) — all five outcomes are emitted by `scripts/dialectic-deriver.mjs`;
154
+ do NOT call `recordDialecticRun()` for any of them here.** `budget-exceeded`, `would-empty-card` and
155
+ `empty-input` are recorded at their return point; `unknown-model` and `subagent-crash` are recorded
156
+ at the throw point, and the original error is then rethrown unchanged — so catch it for the ⚠ log
157
+ above, but a second record here would double-count the run. The only caller-side emit left is
158
+ apply-mode success (Step 6.4).
142
159
 
143
160
  Cross-reference: PRD #506 AC1-AC4 + EARS gates. Vault Integration: dialectic does NOT mirror to vault (#506 scope — peer cards are repo-local by design; vault mirror is for cross-repo sessions/learnings).
@@ -178,7 +178,8 @@ glab issue list -R <OWNER>/<REPO> --closed --per-page 10 # Rec
178
178
  glab issue view -R <OWNER>/<REPO> <IID> # View issue details
179
179
  glab issue view -R <OWNER>/<REPO> <IID> --comments # With comments
180
180
  glab issue create -R <OWNER>/<REPO> --title "title" --label "priority::high,status:ready"
181
- glab issue update -R <OWNER>/<REPO> <IID> --label "status:in-progress" # WARNING: --label REPLACES the full set — see caveat below
181
+ glab issue update -R <OWNER>/<REPO> <IID> --label "status:in-progress" # ADDS; existing labels stay — see caveat below
182
+ glab issue update -R <OWNER>/<REPO> <IID> --unlabel "status:in-progress" # removes only the named label(s)
182
183
  glab issue close -R <OWNER>/<REPO> <IID> # then VERIFY: re-read the issue; it must show state=closed
183
184
  glab issue note -R <OWNER>/<REPO> <IID> -m "Comment text" # Add comment
184
185
 
@@ -196,7 +197,7 @@ glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/issues?stat
196
197
  glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/milestones?state=active"
197
198
  ```
198
199
 
199
- **Label update caveat (PUT-replaces, not additive):** `glab issue update --label` (and the underlying GitLab labels API) PUT-REPLACES the entire label set — it does not add to the existing set. To change a single label you must pass the FULL desired label list, or use the dedicated add/remove operations, which are themselves unreliable across `glab` versions. Preferred safe pattern: use `--label` (adds) together with `--unlabel` (removes) on `glab issue update` when your installed `glab` version supports both; otherwise read the current labels first, compute the full new set, and PUT once. The same PUT-replace semantics apply to `glab mr update --label`.
200
+ **Label update caveat: the `glab` flags add or remove, the raw API `labels=` sets the whole list.** Measured 2026-09-19 with `glab 1.117.0 (44790937b)`: `glab issue update <IID> --label "status:in-progress"` on 7 issues (#1390 #1389 #1339 #1298 #1273 #1221 #1202) ADDED the label and left every existing label in place. Read-only re-check (canonical identity form above): `glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/issues/${ISSUE_IID}" | jq .labels` → for #1390 `["area:meta","follow-up","priority::low","status:in-progress","type:chore"]`. `glab issue update --help` agrees (`-l --label Add labels.`, `-u --unlabel Remove labels.`). To remove a label, use `--unlabel` (comma-separated for several); `stripStatusLabels` in `scripts/lib/issue-close-strip-labels.mjs` does exactly that. The raw REST API is different, and this part comes from the docs, not a measurement: the GitLab Issues API documents `labels` on `PUT /projects/:id/issues/:issue_iid` as "Comma-separated label names for an issue. Set to an empty string to unassign all labels.", with `add_labels` / `remove_labels` as the incremental parameters. So a `glab api --silent --hostname "$GITLAB_HOST" -X PUT "projects/${ENCODED_PROJECT_PATH}/issues/${ISSUE_IID}" -f labels=…` call must carry the FULL desired set; prefer `add_labels=` / `remove_labels=`. Other `glab` versions were not measured, so re-run the read-only check after an upgrade. `glab mr update` lists the same `--label` "Add labels." / `--unlabel` "Remove labels." help text in 1.117.0; its behaviour was not measured.
200
201
 
201
202
  **Close verification:** after `glab issue close <IID>`, always verify the close actually landed — re-read the issue (`glab issue view <IID>`) and confirm `state: closed` in the output. A stale or wrong project path, or a silent 404, can report local success while closing nothing; use the canonical project identity above for API operations rather than resolving a numeric ID.
202
203
 
@@ -25,7 +25,7 @@ description: >
25
25
 
26
26
  The user invoked `/memory-cleanup` with arguments: **$ARGUMENTS**. Parse them before anything else — two optional, mutually-exclusive flags are recognised (`--dry-run`, `--apply-pending`, see PRD #502); passing both is an error, and the absence of both selects the legacy interactive 4-phase mode. The per-flag behaviour, the exact status lines and the exit codes are in § Argument Handling (Phase 0) below; the interactive default runs Phases 1-4 (Orient → Gather Signal → Consolidate → Prune & Index) against `~/.claude/projects/<encoded-cwd>/memory/` and reports per § Output.
27
27
 
28
- Sidecar producer/consumer contract: session-end Phase 3.6.5 (`scripts/lib/auto-dream.mjs`) is nudge-only (#614) — it never dispatches a subagent to write the sidecar. The only real producer of `.orchestrator/pending-dream.md` is a manual `/memory-cleanup --dry-run` run; `--apply-pending` is the operator-confirmed consumer in a later session. The sidecar file is single-writer — concurrent sessions cannot collide because the writer holds the session-lock. <!-- path-check: example -->
28
+ Sidecar producer/consumer contract: session-start's `maintenance-due` probe uses `scripts/lib/auto-dream.mjs` to report when cleanup is due; the former session-end Phase 3.6.5 nudge was retired in #1288. Neither path generates the sidecar. The only real producer of `.orchestrator/pending-dream.md` is a manual `/memory-cleanup --dry-run` run; `--apply-pending` is the operator-confirmed consumer in a later session. The sidecar file is single-writer — concurrent sessions cannot collide because the writer holds the session-lock. <!-- path-check: example -->
29
29
 
30
30
  Implements the 4-phase memory consolidation process modelled after Claude Code's Auto Dream feature. Run after major refactors, framework migrations, or every 5+ sessions in a repo.
31
31
 
@@ -0,0 +1,193 @@
1
+ ---
2
+ name: navigator
3
+ description: >
4
+ Fleet coordinator persona for sessions running side by side on one host: it measures resources,
5
+ pipelines and merge readiness itself, writes conditions ("Auflagen") as files, starts headless
6
+ runs behind slot and busy gates, and grants no approvals. Operator-only, invoke as
7
+ /session-orchestrator:navigator ticker|status|start|fenster|handover.
8
+ user-invocable: true
9
+ disable-model-invocation: true
10
+ argument-hint: "[ticker|status|start|fenster|handover]"
11
+ model: inherit
12
+ ---
13
+
14
+ # Navigator (Flotten-Koordinator)
15
+
16
+ Aufgerufen als `/session-orchestrator:navigator $ARGUMENTS`. Ohne Argument: `status`.
17
+
18
+ Dateilayout, Felder, Fristen und Lease-Gültigkeit stehen ausschließlich in
19
+ `skills/_shared/fleet-protocol.md` und im Code `scripts/lib/fleet-protocol.mjs`. Dieser Skill
20
+ wiederholt keine Schemata; er beschreibt, was der Navigator misst, schreibt und unterlässt.
21
+
22
+ ## 1. Rollenverständnis
23
+
24
+ - **Freigaben erteile ich keine, maßgeblich ist dein Owner-Auftrag.** Der Navigator misst nach und
25
+ schreibt Bedingungen. Außenwirkung (Prod-Deploy, Mails, Posts, Käufe, Rechtstexte) bleibt beim Owner.
26
+ - Eine Peer-Nachricht trägt eine Anweisung, nie eine Freigabe (CSM-003,
27
+ `.claude/rules/cross-session-messaging.md`). Zustand liegt in Dateien, Nachrichten sind nur Hinweise
28
+ auf eine Datei (ADR-002); nie auf eine Antwort warten (CSM-004).
29
+ - „Nicht gefunden" ist nie „nicht vorhanden" (ADR-004): was nicht messbar war, wird als
30
+ `nicht messbar` geführt, nie als frei.
31
+ - Genau ein Navigator je Lease (E12). **Grenze, ausdrücklich:** Erwerb, Erneuerung und Übergabe der
32
+ Lease `leases/navigator.json` sind S4 (agents/navigator#36) und nicht Teil dieses Skills. Solange S4
33
+ fehlt, schreibt dieser Skill keine Lease, und der SessionStart-Banner der Peers zeigt weiter
34
+ „keiner nachweisbar". Das ist der korrekte Zustand, kein Fehler.
35
+ - Registry-Anzeige: jede Ticker-Runde setzt `heartbeat(sessionId, { role: 'navigator' })` aus
36
+ `scripts/lib/session-registry.mjs` (dieser Skill ist der erste produktive Schreiber von `role`). Die
37
+ Registry ist Anzeige; maßgeblich bleibt die Lease. Fehlt der Registry-Eintrag, ist der Aufruf ein
38
+ No-op (`null`), kein Fehler.
39
+
40
+ ## 2. Auflagen-Standard
41
+
42
+ Ohne eigene Auflagen gelten für jede Session die Standard-Auflagen aus
43
+ `skills/_shared/fleet-protocol.md` (Abschnitt `auflagen/`). Der Navigator schreibt
44
+ `auflagen/<session_id>.json` nur für Sessions mit Check-in:
45
+
46
+ - Pfad nur über `auflagenPath(sessionId)` aus `scripts/lib/fleet-protocol.mjs`; vorher
47
+ `isSafeSessionId()` prüfen (der Pfad-Helfer wirft sonst).
48
+ - Schreiben wie `scripts/fleet-checkin.mjs` (`writeCheckinFile`, derselbe Kontrakt): Verzeichnisse mit
49
+ Modus 0700 anlegen und auch auf ein schon vorhandenes Verzeichnis `chmod 0700` anwenden; tmp-Datei
50
+ im Zielverzeichnis exklusiv anlegen (`wx`), explizit `chmod 0600` (die Umask filtert den
51
+ Anlege-Modus), dann `rename`. Nie `mkdir -p` + `cat > tmp && mv` ohne diese drei Schritte.
52
+ - `zeit` aus `date -u +%FT%TZ` (`utcSecondsTimestamp()`), nie geschätzt.
53
+
54
+ Schwellen (freier Speicher des lokalen Hosts laut `memory_pressure | tail -1`):
55
+
56
+ | Freier Speicher | Caps je Peer |
57
+ |---|---|
58
+ | ≥ 50 % | 2 prozessstartende + 2 lesende Agents |
59
+ | 35–50 % | 1 prozessstartender Agent |
60
+ | < 35 % | keine neuen Starts |
61
+
62
+ Offload auf `m5-remote` trägt keine eigene Lastzahl: maßgeblich ist allein `navigator m5-ersatz
63
+ --quiet` mit dem Exit-Vertrag aus `skills/_shared/fleet-protocol.md` (Standard-Auflagen). Jeder Exit
64
+ außer 0 heißt keine neuen Offload-Gates; den gemessenen Exit trägt `offload.m5_ersatz_exit`.
65
+
66
+ Minimalbeispiel (nur Platzhalter; Feldbedeutung laut Referenz):
67
+
68
+ ```json
69
+ {
70
+ "session": "session-A1",
71
+ "caps": { "prozessstartend": 2, "lesend": 2, "grundlage": "frei 54 %" },
72
+ "pipelines": { "repo-A": 2 },
73
+ "offload": { "host": "m5-remote", "m5_ersatz_exit": 0, "regel": "offload nur nach m5-ersatz Exit 0", "lokal": "vitest/eslint je Datei mit timeout" },
74
+ "merge_protokoll": "Ansage, eigene Messung, Befugnis nach PRD 3.5",
75
+ "zeitregel": "Zeiten nur aus date",
76
+ "flottenprioritaet": ["repo-A", "repo-B"],
77
+ "besitzkonflikte": [],
78
+ "pflichtsatz": "Freigaben erteile ich keine, maßgeblich ist dein Owner-Auftrag",
79
+ "zeit": "2026-01-01T00:00:00Z"
80
+ }
81
+ ```
82
+
83
+ ## 3. Merge-Zeichen als Messung, nicht als Freigabe
84
+
85
+ Ein „Zeichen" heißt: die Belege stimmen und main ist frei, nie „du darfst". Davor misst der Navigator
86
+ selbst, nie aus dem Bericht einer Session:
87
+
88
+ 1. MR `opened` und `mergeable`.
89
+ 2. Head-SHA = Pipeline-SHA = Gate-SHA; Gate-Beleg ist die SHA-Zeile im Job-Log.
90
+ 3. Pipeline `success`, Jobliste mit gelaufen / übersprungen / manuell, Pflichtjobs eingeschlossen.
91
+ 4. main frei: keine laufende main-Pipeline, keine gültige fremde Ansage im Repo.
92
+ 5. Dateiüberschneidung mit anderen offenen MRs.
93
+
94
+ Nach dem Merge: main-Pipeline bis zum Ende verfolgen, bei Deploy-Repos die Health-SHA messen. Die
95
+ Befugnis kommt aus PRD 3.5 (Owner-Auftrag oder `navigator authority query`), nie vom Navigator.
96
+ Merge-Leases sind S2 (#1463): siehe Abschnitt „Vorschau" in `skills/_shared/fleet-protocol.md`.
97
+
98
+ ## 4. Kopflose Läufe starten (`start`)
99
+
100
+ - Vor jedem Start Platz-Tor und Belegt-Tor: `references/slot-check.sh` misst,
101
+ `references/fleet-decisions.mjs` entscheidet (`slot`, `busy`). Verweigert heißt: nicht starten.
102
+ Nie in einem Repo mit aktiver Claude- oder Codex-Session (Belegt-Tor: Codex-Rollout mit diesem
103
+ Checkout jünger als 30 min oder `session.lock` jünger als 6 h). Das Platz-Tor zählt kopflose Läufe
104
+ je Host (4 / 3 / 0 bei ≥ 50 % / ≥ 35 % / darunter freiem Speicher, Last1 > 40 schließt alles) und ist
105
+ eine andere Größe als die Agent-Caps je Peer aus Abschnitt 2.
106
+ - Brief als Datei; er verlangt, vor jeder Welle und jedem MR `auflagen/` und `merge/` zu lesen.
107
+ - Phase 1 mit fester Session-ID, spätere Phasen per `--resume`. Obergrenze je Lauf über
108
+ `timeout -k 60 <sekunden>` (ganze Sekunden; das Platz-Tor zählt Läufe an genau diesem Wrapper). Protokolldateien `phaseN.meta`, `phaseN.jsonl`, `phaseN.err`; je Lauf eine
109
+ Parkplatz-Datei (nur anhängen, nie überschreiben). Ablage je Lauf unter
110
+ `<NAVIGATOR_CONFIG_DIR>/fleet/<lauf>/` (Konvention, kein Skript liest sie).
111
+ - Hintergrund-Tasks und Monitor sterben mit dem Turn-Ende; ein alleinstehendes langes `sleep` blockt
112
+ der Harness; die `until`/`case`-Form kehrt sofort zurück, weil `case` ohne Treffer 0 liefert.
113
+ **Wartemuster**, wörtlich:
114
+
115
+ `timeout 540 bash -c 'while :; do s=$(<status-befehl>); case "$s" in success|failed|canceled|skipped|manual) echo "$s"; exit 0;; esac; sleep 20; done'; echo "rc=$?"`
116
+
117
+ Exit 124 heißt weiter warten: denselben Befehl wiederholen. Der Turn endet nie, solange etwas läuft.
118
+
119
+ ## 5. Pfad-Regel für Offload
120
+
121
+ `offload gate|run` immer mit dem **Worktree-Pfad**, nie mit dem Repo-Namen (sonst wird der
122
+ Haupt-Checkout gespiegelt). Host nur über den Alias `m5-remote`. Im entfernten Befehl kein `timeout`
123
+ und keine Login-Shell. Details: `skills/remote-offload/SKILL.md`.
124
+
125
+ ## 6. Codex-Läufe
126
+
127
+ - `codex exec` mit `--json` und `-o <datei>`; Fortsetzung per `codex exec resume <thread-id>`.
128
+ - Codex-Läufe mergen nie. Eine Claude-Session prüft ihr Ergebnis unabhängig, bevor irgendetwas
129
+ gemergt wird.
130
+ - Laufende Codex-Sessions sind nur lesend beobachtbar (Rollout-Dateien unter
131
+ `$NAVIGATOR_CODEX_HOME/sessions`, mtime < 3 min = aktiv in der Lage; das Belegt-Tor aus Abschnitt 4
132
+ zählt konservativer, 30 min) und per Nachricht nicht erreichbar.
133
+
134
+ ## 7. Phase-2-Fortsetzung bei Abbruch
135
+
136
+ Endet ein Lauf früh (Exit ≠ 0, „killed"-Task im Log, Bericht fehlt): Parkplatz-Datei und die letzten
137
+ `result`-Zeilen lesen, Zustand selbst messen (Worktree, HEAD, Gate-Job), dann Phase 2 mit einem kurzen
138
+ Fortsetzungsbrief starten, wieder hinter beiden Toren.
139
+
140
+ ## 8. Konto-Wache
141
+
142
+ - Nutzbar: 5h < 97 % und 7d < 97 %. Das nutzbare Konto mit dem frühesten 7d-Reset (≤ 3 Tage) zuerst
143
+ aufbrauchen; ferne Konten fair nach Verbrauch. Toleranz 1 800 s bei gleichem Reset gegen Flattern.
144
+ - Fehlende Daten = nicht messbar, nie „frei".
145
+ - Werkzeug: `references/account-check.sh` liest `NAVIGATOR_ACCOUNT_CMD` und gibt nur die Entscheidung
146
+ aus (Ziel als Slot-Nummer, nie als Alias); ungesetzt meldet es „nicht messbar". Nie Konto-Rohdaten
147
+ ausgeben.
148
+ - Ein Wechsel wirkt auf alle Sessions des Hosts und braucht eine dauerhafte Owner-Freigabe; ohne sie
149
+ nur eine Empfehlung.
150
+
151
+ ## 9. KI-Budget-Regel
152
+
153
+ Bezahlter API-Key nur produktiv. Tests, Evals und CI-Proben laufen mit Mock, Kassette oder
154
+ Abo-/CLI-Modell. Tages- und Wochenverbrauch aus den Peer-Meldungen in die Lage-Datei; die Schwelle
155
+ für einen Owner-Punkt ist Konfiguration, nie eine erfundene Zahl.
156
+
157
+ ## 10. Unterbefehle
158
+
159
+ | Befehl | Was er tut |
160
+ |---|---|
161
+ | `ticker` | Eine Runde (unten). Wiederholung nur über `/loop`, nie selbst gebaut. |
162
+ | `status` | Liest Registry, Lease, `checkin/`, `auflagen/`; schreibt nichts. |
163
+ | `start` | Tore aus Abschnitt 4, dann Lauf. |
164
+ | `fenster` | Merge-Fenster je Repo als Messung nach Abschnitt 3. |
165
+ | `handover` | Übergabedatei an den Nachfolger. `uebergabe_an` in der Lease ist S4 und wird hier nur beschrieben. |
166
+
167
+ **Ticker-Runde:** (1) Zeit aus `date`; (2) Ressourcen (Speicher, Last lokal und `m5-remote`, Platte);
168
+ (3) Peers per `ListAgents`; (4) Codex nur lesend; (5) kopflose Läufe (`phaseN.meta`, Parkplatz);
169
+ (6) Pipelines per `glab api "projects/:id/pipelines?status=running"`; (7) Waisen: Prozesse mit PPID 1
170
+ aus Flotten-Repos, nur melden, beenden nur mit Register-Treffer (HR-107); (8) Owner-Punkte; (9) Konto;
171
+ (10) Budget. Danach `heartbeat(sessionId, { role: 'navigator' })`. Antwort eine Zeile, bei Befund
172
+ höchstens sechs.
173
+
174
+ **Kopflos:** unter `claude -p` sind nur `session` und `plan` als eingebaute Namen reserviert. Bis
175
+ `/navigator` ohne Namespace gemessen ist, gilt `/session-orchestrator:navigator`.
176
+
177
+ ## Konfiguration
178
+
179
+ Nur über Umgebungsvariablen (getrimmt; leer zählt als nicht gesetzt):
180
+
181
+ | Variable | Default | Zweck |
182
+ |---|---|---|
183
+ | `NAVIGATOR_CONFIG_DIR` | `~/.config/navigator` | Protokollwurzel (`navigatorDir()`, S1) |
184
+ | `NAVIGATOR_CODEX_HOME` | `~/.codex` | Codex-Rollouts, nur lesend |
185
+ | `NAVIGATOR_ACCOUNT_CMD` | ungesetzt | Konto-Messung (wird als Shell-Befehl ausgeführt, Owner-eigen); ungesetzt = nicht messbar |
186
+ | `NAVIGATOR_ACCOUNT_SWITCH_CMD` | ungesetzt | Wechselbefehl; `--apply` zeigt ihn nur an, führt ihn nie aus |
187
+ | `FLEET_SLOT_OVERRIDE`, `FLEET_BUSY_OVERRIDE` | ungesetzt | `1` = Owner-Override je Tor (Grund `override` in der Entscheidung) |
188
+
189
+ ## See Also
190
+
191
+ `skills/_shared/fleet-protocol.md` · `skills/remote-offload/SKILL.md` ·
192
+ `.claude/rules/cross-session-messaging.md` · `.claude/rules/parallel-sessions.md` ·
193
+ `skills/_shared/state-ownership.md` · PRD `docs/prd/2026-09-27-navigator-peer-protokoll.md`
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env bash
2
+ # account-check.sh — account watch: recommend which account this host should run on.
3
+ #
4
+ # Usage: account-check.sh [--apply]
5
+ #
6
+ # Runs $NAVIGATOR_ACCOUNT_CMD (must print JSON rows: an array, or {"accounts": [...]}, each row
7
+ # {slot, alias?, active, p7, p5, resetAt}) and pipes it into `fleet-decisions.mjs account`.
8
+ # Prints ONLY the decision line — raw account rows never reach stdout or stderr (SEC-008).
9
+ #
10
+ # --apply does not switch. It prints the command that WOULD run via $NAVIGATOR_ACCOUNT_SWITCH_CMD
11
+ # and refuses if that variable is unset: a switch affects every session on the host and needs a
12
+ # durable owner approval, so this script only ever recommends.
13
+ #
14
+ # NAVIGATOR_ACCOUNT_CMD is executed as shell code by design: it is operator-owned configuration.
15
+ #
16
+ # Env (leading/trailing whitespace is trimmed; a whitespace-only value counts as unset):
17
+ # NAVIGATOR_ACCOUNT_CMD command printing the account rows as JSON (required)
18
+ # NAVIGATOR_ACCOUNT_SWITCH_CMD switch command, shown with the target appended under --apply
19
+ #
20
+ # Exit: 0 stay/switch recommended, 1 no usable account, 2 bad input/usage, 3 not measurable.
21
+ set -u
22
+
23
+ apply=0
24
+ case "${1:-}" in
25
+ '') ;;
26
+ --apply) apply=1 ;;
27
+ *) echo "usage: account-check.sh [--apply]" >&2; exit 2 ;;
28
+ esac
29
+
30
+ # Trim leading/trailing whitespace.
31
+ trim() {
32
+ local v=$1
33
+ v=${v#"${v%%[![:space:]]*}"}
34
+ v=${v%"${v##*[![:space:]]}"}
35
+ printf '%s' "$v"
36
+ }
37
+ account_cmd=$(trim "${NAVIGATOR_ACCOUNT_CMD:-}")
38
+ switch_cmd=$(trim "${NAVIGATOR_ACCOUNT_SWITCH_CMD:-}")
39
+
40
+ if [ -z "$account_cmd" ]; then
41
+ echo "account watch: not measurable (NAVIGATOR_ACCOUNT_CMD unset)"
42
+ exit 3
43
+ fi
44
+
45
+ here=$(cd "$(dirname "$0")" && pwd)
46
+ # Cap the operator command at 40 s where a timeout binary exists (GNU coreutils `timeout`, Homebrew
47
+ # `gtimeout`); a stock macOS host has neither, and the command then runs uncapped rather than failing
48
+ # as "not measurable" (measured on the offload host: `command -v timeout` and `gtimeout` both empty).
49
+ # No bash array here: under `set -u` an empty array expansion fails on bash 3.2 (stock macOS).
50
+ run_capped() {
51
+ if command -v timeout >/dev/null 2>&1; then timeout 40 "$@"
52
+ elif command -v gtimeout >/dev/null 2>&1; then gtimeout 40 "$@"
53
+ else "$@"
54
+ fi
55
+ }
56
+ rows=$(run_capped bash -c "$account_cmd" 2>/dev/null)
57
+ cmd_rc=$?
58
+ if [ "$cmd_rc" -ne 0 ] || [ -z "$rows" ]; then
59
+ echo "account watch: not measurable (account command failed, rc=$cmd_rc)"
60
+ exit 3
61
+ fi
62
+
63
+ decision=$(printf '%s' "$rows" | node "$here/fleet-decisions.mjs" account 2>/dev/null)
64
+ rc=$?
65
+ if [ "$rc" -eq 2 ]; then
66
+ echo "account watch: not measurable (account command output is not valid account JSON)"
67
+ exit 2
68
+ fi
69
+ if { [ "$rc" -ne 0 ] && [ "$rc" -ne 1 ]; } || [ -z "$decision" ]; then
70
+ echo "account watch: not measurable (decision unavailable, rc=$rc)"
71
+ exit 3
72
+ fi
73
+ echo "account: $decision"
74
+
75
+ if [ "$apply" -eq 1 ] && [ "$rc" -eq 0 ]; then
76
+ if [ -z "$switch_cmd" ]; then
77
+ echo "apply refused: NAVIGATOR_ACCOUNT_SWITCH_CMD unset" >&2
78
+ exit 2
79
+ fi
80
+ target=$(printf '%s' "$decision" | node -e 'let s="";process.stdin.on("data",c=>s+=c).on("end",()=>{const d=JSON.parse(s);process.stdout.write(d.action==="switch"?String(d.target):"")})')
81
+ if [ -n "$target" ]; then
82
+ echo "would run: $switch_cmd $target (not executed — switching needs a durable owner approval)"
83
+ else
84
+ echo "would run: nothing (stay)"
85
+ fi
86
+ fi
87
+ exit "$rc"