session-orchestrator 3.23.0 → 4.0.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 (393) hide show
  1. package/.agents/skills/architecture/SKILL.md +18 -0
  2. package/.agents/skills/autopilot/SKILL.md +17 -0
  3. package/.agents/skills/bootstrap/SKILL.md +20 -0
  4. package/.agents/skills/brainstorm/SKILL.md +22 -0
  5. package/.agents/skills/claude-md-drift-check/SKILL.md +15 -0
  6. package/.agents/skills/convergence-monitoring/SKILL.md +22 -0
  7. package/.agents/skills/debug/SKILL.md +22 -0
  8. package/.agents/skills/discovery/SKILL.md +20 -0
  9. package/.agents/skills/dispatcher/SKILL.md +15 -0
  10. package/.agents/skills/docs-orchestrator/SKILL.md +18 -0
  11. package/.agents/skills/ecosystem-health/SKILL.md +20 -0
  12. package/.agents/skills/eli5/SKILL.md +20 -0
  13. package/.agents/skills/eval/SKILL.md +21 -0
  14. package/.agents/skills/evolve/SKILL.md +21 -0
  15. package/.agents/skills/frontmatter-guard/SKILL.md +15 -0
  16. package/.agents/skills/gitlab-ops/SKILL.md +20 -0
  17. package/.agents/skills/gitlab-portfolio/SKILL.md +15 -0
  18. package/.agents/skills/grill/SKILL.md +22 -0
  19. package/.agents/skills/hook-development/SKILL.md +15 -0
  20. package/.agents/skills/mcp-builder/SKILL.md +15 -0
  21. package/.agents/skills/memory-cleanup/SKILL.md +21 -0
  22. package/.agents/skills/mode-selector/SKILL.md +17 -0
  23. package/.agents/skills/npm-publish/SKILL.md +16 -0
  24. package/.agents/skills/peekaboo-driver/SKILL.md +18 -0
  25. package/.agents/skills/persona-panel/SKILL.md +17 -0
  26. package/.agents/skills/plan/SKILL.md +20 -0
  27. package/.agents/skills/playwright-driver/SKILL.md +20 -0
  28. package/.agents/skills/quality-gates/SKILL.md +20 -0
  29. package/.agents/skills/reconcile/SKILL.md +21 -0
  30. package/.agents/skills/remote-offload/SKILL.md +20 -0
  31. package/.agents/skills/repo-audit/SKILL.md +16 -0
  32. package/.agents/skills/session-end/SKILL.md +20 -0
  33. package/.agents/skills/session-plan/SKILL.md +20 -0
  34. package/.agents/skills/session-start/SKILL.md +20 -0
  35. package/.agents/skills/spinout/SKILL.md +16 -0
  36. package/.agents/skills/sunset-review/SKILL.md +16 -0
  37. package/.agents/skills/test-runner/SKILL.md +20 -0
  38. package/.agents/skills/tmux-layout/SKILL.md +21 -0
  39. package/.agents/skills/using-orchestrator/SKILL.md +17 -0
  40. package/.agents/skills/vault-mirror/SKILL.md +15 -0
  41. package/.agents/skills/vault-sync/SKILL.md +15 -0
  42. package/.agents/skills/wave-executor/SKILL.md +20 -0
  43. package/.agents/skills/write-executable-plan/SKILL.md +22 -0
  44. package/.claude-plugin/marketplace.json +1 -1
  45. package/.claude-plugin/plugin.json +1 -1
  46. package/.codex-plugin/plugin.json +1 -1
  47. package/.cursor/commands/autopilot.md +2 -2
  48. package/.cursor/commands/bootstrap.md +1 -1
  49. package/.cursor/commands/brainstorm.md +1 -1
  50. package/.cursor/commands/debug.md +1 -1
  51. package/.cursor/commands/discovery.md +1 -1
  52. package/.cursor/commands/dispatcher.md +2 -2
  53. package/.cursor/commands/eli5.md +2 -2
  54. package/.cursor/commands/eval.md +2 -2
  55. package/.cursor/commands/evolve.md +1 -1
  56. package/.cursor/commands/go.md +1 -1
  57. package/.cursor/commands/grill.md +2 -2
  58. package/.cursor/commands/memory-cleanup.md +2 -2
  59. package/.cursor/commands/persona-panel.md +1 -1
  60. package/.cursor/commands/plan.md +1 -1
  61. package/.cursor/commands/portfolio.md +1 -1
  62. package/.cursor/commands/reconcile.md +2 -2
  63. package/.cursor/commands/release.md +2 -2
  64. package/.cursor/commands/session.md +2 -2
  65. package/.cursor/commands/spinout.md +2 -2
  66. package/.cursor/commands/sunset-review.md +2 -2
  67. package/.cursor/commands/templates-ack.md +2 -2
  68. package/.cursor/commands/test.md +2 -2
  69. package/.cursor/skills/brainstorm/SKILL.md +1 -1
  70. package/.cursor/skills/eval/SKILL.md +1 -1
  71. package/.cursor/skills/quality-gates/SKILL.md +1 -1
  72. package/.cursor/skills/remote-offload/SKILL.md +13 -0
  73. package/.orchestrator/policy/blocked-commands.json +121 -0
  74. package/.orchestrator/policy/ecosystem.schema.json +66 -0
  75. package/.orchestrator/policy/quality-gates.example.json +16 -0
  76. package/.orchestrator/policy/quality-gates.schema.json +38 -0
  77. package/.orchestrator/policy/templates-policy.json +27 -0
  78. package/.orchestrator/policy/test-profiles.json +47 -0
  79. package/AGENTS.md +225 -0
  80. package/CHANGELOG.md +1401 -0
  81. package/NOTICE +11 -6
  82. package/README.md +127 -92
  83. package/agents/db-specialist.md +0 -1
  84. package/agents/eval-judge.md +1 -1
  85. package/agents/skill-applied-judge.md +1 -1
  86. package/assets/wave-lifecycle.svg +98 -0
  87. package/commands/release.md +6 -3
  88. package/commands/session.md +18 -3
  89. package/docs/README.md +4 -0
  90. package/{agents/AGENTS.md → docs/agent-authoring.md} +19 -26
  91. package/docs/baseline.md +67 -0
  92. package/docs/ci-setup.md +249 -48
  93. package/docs/codex-setup.md +66 -22
  94. package/docs/components.md +37 -16
  95. package/docs/cursor-setup.md +6 -2
  96. package/docs/events-schema.md +51 -10
  97. package/docs/instruction-delivery.md +62 -0
  98. package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
  99. package/docs/migration-v4.md +341 -0
  100. package/docs/pi-setup.md +6 -1
  101. package/docs/plugin-architecture-v3.md +1 -1
  102. package/docs/rule-authoring.md +85 -19
  103. package/docs/scope-collision-guard.md +8 -8
  104. package/docs/session-config-reference.md +120 -61
  105. package/docs/session-config-template.md +40 -33
  106. package/docs/telemetry/telemetry-claims.md +11 -10
  107. package/docs/telemetry.md +187 -4
  108. package/docs/vault-docs-architecture.md +50 -11
  109. package/hooks/_lib/atomic-json.mjs +111 -0
  110. package/hooks/_lib/hook-import-set.json +1487 -0
  111. package/hooks/_lib/subagent-paths.mjs +143 -0
  112. package/hooks/_lib/subagent-transcript.mjs +562 -0
  113. package/hooks/config-protection.mjs +2 -2
  114. package/hooks/cwd-change-restore.mjs +11 -31
  115. package/hooks/enforce-commands.mjs +69 -0
  116. package/hooks/enforce-scope.mjs +35 -6
  117. package/hooks/hooks-codex.json +1 -1
  118. package/hooks/hooks-cursor.json +10 -0
  119. package/hooks/hooks-pi.json +5 -0
  120. package/hooks/hooks.json +6 -1
  121. package/hooks/loop-guard.mjs +3 -3
  122. package/hooks/on-session-end.mjs +280 -14
  123. package/hooks/on-session-start.mjs +153 -4
  124. package/hooks/on-stop.mjs +371 -17
  125. package/hooks/operator-steer.mjs +2 -2
  126. package/hooks/post-bash-write-verify.mjs +189 -4
  127. package/hooks/post-edit-import-probe.mjs +344 -0
  128. package/hooks/post-subagent-discovery-validator.mjs +278 -392
  129. package/hooks/post-tool-batch-wave-signal.mjs +272 -44
  130. package/hooks/post-tool-failure-corrective-context.mjs +11 -34
  131. package/hooks/post-tooluse-frontend-slop.mjs +3 -3
  132. package/hooks/pre-bash-destructive-guard.mjs +39 -13
  133. package/hooks/pre-bash-memory-propose-audit.mjs +13 -7
  134. package/hooks/skill-invocation-telemetry.mjs +17 -5
  135. package/hooks/subagent-telemetry.mjs +24 -30
  136. package/monitors/monitors.json +3 -3
  137. package/package.json +9 -1
  138. package/pi/prompts/session.md +2 -2
  139. package/plugin.json +27 -0
  140. package/scripts/autopilot.mjs +26 -12
  141. package/scripts/backfill-abandoned-sessions.mjs +130 -15
  142. package/scripts/backfill-learnings-from-vault.mjs +9 -3
  143. package/scripts/dialectic-deriver.mjs +73 -8
  144. package/scripts/emit-event.mjs +10 -2
  145. package/scripts/export-hw-learnings.mjs +113 -1
  146. package/scripts/generate-agents-skills.mjs +378 -0
  147. package/scripts/generate-cursor-adapter.mjs +45 -8
  148. package/scripts/generate-hook-import-set.mjs +249 -0
  149. package/scripts/lib/agent-status.mjs +13 -2
  150. package/scripts/lib/auq/parse.mjs +5 -29
  151. package/scripts/lib/auto-dialectic.mjs +68 -0
  152. package/scripts/lib/auto-dream.mjs +38 -36
  153. package/scripts/lib/autonomy/suitability.mjs +6 -0
  154. package/scripts/lib/autopilot/loop.mjs +2 -2
  155. package/scripts/lib/autopilot/worktree-pipeline.mjs +82 -6
  156. package/scripts/lib/build-live-signals.mjs +25 -22
  157. package/scripts/lib/ci-status-banner.mjs +220 -75
  158. package/scripts/lib/codex/plugin-contract.mjs +82 -6
  159. package/scripts/lib/cold-start-detector.mjs +23 -14
  160. package/scripts/lib/config/auto-dream.mjs +2 -1
  161. package/scripts/lib/config/block-header.mjs +63 -0
  162. package/scripts/lib/config/block-preprocess.mjs +177 -0
  163. package/scripts/lib/config/broken-window.mjs +2 -1
  164. package/scripts/lib/config/cold-start.mjs +2 -1
  165. package/scripts/lib/config/config-protection.mjs +22 -2
  166. package/scripts/lib/config/context-coverage.mjs +2 -1
  167. package/scripts/lib/config/cross-repo.mjs +2 -1
  168. package/scripts/lib/config/custom-phases.mjs +2 -1
  169. package/scripts/lib/config/dialectic.mjs +2 -1
  170. package/scripts/lib/config/discovery-validator.mjs +9 -3
  171. package/scripts/lib/config/dispatcher-autonomy-capture.mjs +24 -1
  172. package/scripts/lib/config/dispatcher-autonomy.mjs +2 -1
  173. package/scripts/lib/config/docs-orchestrator.mjs +2 -1
  174. package/scripts/lib/config/docs-staleness.mjs +2 -1
  175. package/scripts/lib/config/drift-check.mjs +2 -1
  176. package/scripts/lib/config/eval.mjs +2 -1
  177. package/scripts/lib/config/events-rotation.mjs +2 -1
  178. package/scripts/lib/config/evolve.mjs +8 -2
  179. package/scripts/lib/config/frontend-slop-hook.mjs +7 -3
  180. package/scripts/lib/config/gitlab-portfolio.mjs +2 -1
  181. package/scripts/lib/config/handover-gate.mjs +2 -1
  182. package/scripts/lib/config/health-endpoints.mjs +388 -0
  183. package/scripts/lib/config/issue-budget.mjs +2 -1
  184. package/scripts/lib/config/loop-guard.mjs +2 -1
  185. package/scripts/lib/config/memory.mjs +2 -1
  186. package/scripts/lib/config/moc-staleness.mjs +2 -1
  187. package/scripts/lib/config/persona-gate-wave.mjs +2 -1
  188. package/scripts/lib/config/private-config-dir.mjs +67 -0
  189. package/scripts/lib/config/reconcile.mjs +2 -1
  190. package/scripts/lib/config/remote-hosts.mjs +234 -0
  191. package/scripts/lib/config/section-extractor.mjs +7 -1
  192. package/scripts/lib/config/skill-evolution.mjs +2 -1
  193. package/scripts/lib/config/slopcheck.mjs +2 -1
  194. package/scripts/lib/config/state-md-lock.mjs +2 -1
  195. package/scripts/lib/config/templates-first.mjs +2 -1
  196. package/scripts/lib/config/test.mjs +2 -1
  197. package/scripts/lib/config/vault-integration.mjs +7 -1
  198. package/scripts/lib/config/vault-mirror-quality.mjs +2 -1
  199. package/scripts/lib/config/vault-staleness.mjs +2 -1
  200. package/scripts/lib/config/vault-sync.mjs +2 -1
  201. package/scripts/lib/config/verification-auto-fix.mjs +2 -1
  202. package/scripts/lib/config/wave-reviewers.mjs +2 -1
  203. package/scripts/lib/config/worktree-orphans.mjs +2 -1
  204. package/scripts/lib/config.mjs +31 -3
  205. package/scripts/lib/convergence-monitor.mjs +82 -16
  206. package/scripts/lib/dispatcher/enumerate.mjs +2 -17
  207. package/scripts/lib/dispatcher/rank.mjs +124 -48
  208. package/scripts/lib/ecosystem-health.mjs +16 -2
  209. package/scripts/lib/eval/engine.mjs +9 -1
  210. package/scripts/lib/eval/session-resolve.mjs +23 -4
  211. package/scripts/lib/events-schema.mjs +48 -0
  212. package/scripts/lib/events.mjs +256 -7
  213. package/scripts/lib/evolve/autonomy-verdict.mjs +9 -4
  214. package/scripts/lib/evolve/autopilot-effectiveness.mjs +18 -1
  215. package/scripts/lib/frontmatter-guard.mjs +131 -13
  216. package/scripts/lib/gates/gate-full.mjs +26 -0
  217. package/scripts/lib/gates/gate-helpers.mjs +76 -0
  218. package/scripts/lib/gitlab-portfolio/cli.mjs +3 -15
  219. package/scripts/lib/hardware-pattern-detector.mjs +18 -1
  220. package/scripts/lib/harness-audit/categories/category1.mjs +17 -6
  221. package/scripts/lib/harness-audit/categories/category4.mjs +31 -11
  222. package/scripts/lib/host-identity.mjs +50 -11
  223. package/scripts/lib/instruction-budget-guard.mjs +171 -5
  224. package/scripts/lib/learnings/evolve-telemetry.mjs +178 -0
  225. package/scripts/lib/learnings/io.mjs +60 -6
  226. package/scripts/lib/memory-banner.mjs +20 -8
  227. package/scripts/lib/memory-proposals/store.mjs +30 -22
  228. package/scripts/lib/owner-config-banner.mjs +43 -6
  229. package/scripts/lib/owner-config-loader.mjs +21 -10
  230. package/scripts/lib/owner-interview.mjs +3 -3
  231. package/scripts/lib/owner-yaml.mjs +207 -14
  232. package/scripts/lib/peer-discovery.mjs +20 -2
  233. package/scripts/lib/platform.mjs +108 -15
  234. package/scripts/lib/plugin-update-banner.mjs +406 -0
  235. package/scripts/lib/project-hygiene.mjs +38 -2
  236. package/scripts/lib/qg-command-drift-banner.mjs +50 -12
  237. package/scripts/lib/quality-gate.mjs +133 -44
  238. package/scripts/lib/reconcile/emitter.mjs +68 -6
  239. package/scripts/lib/reconcile/engine.mjs +249 -9
  240. package/scripts/lib/reconcile/idempotency.mjs +37 -4
  241. package/scripts/lib/reconcile/writer.mjs +40 -18
  242. package/scripts/lib/scope-gate.mjs +36 -0
  243. package/scripts/lib/session-close-backfill.mjs +125 -18
  244. package/scripts/lib/session-discovery.mjs +57 -3
  245. package/scripts/lib/session-end/phase-skip.mjs +2 -2
  246. package/scripts/lib/session-id.mjs +12 -23
  247. package/scripts/lib/session-identity/own-session.mjs +187 -11
  248. package/scripts/lib/session-lock-shape.mjs +43 -0
  249. package/scripts/lib/session-lock.mjs +5 -10
  250. package/scripts/lib/session-registry.mjs +25 -9
  251. package/scripts/lib/session-schema/constants.mjs +36 -2
  252. package/scripts/lib/session-schema/validator.mjs +38 -4
  253. package/scripts/lib/session-start-probes.mjs +18 -1
  254. package/scripts/lib/session-transition.mjs +1 -1
  255. package/scripts/lib/sessions-canonical.mjs +446 -0
  256. package/scripts/lib/sessions-staleness-banner.mjs +18 -11
  257. package/scripts/lib/skill-health/join.mjs +17 -4
  258. package/scripts/lib/state-md.mjs +78 -0
  259. package/scripts/lib/sunset/walker.mjs +6 -0
  260. package/scripts/lib/telemetry/schema.mjs +255 -17
  261. package/scripts/lib/telemetry/sync.mjs +417 -24
  262. package/scripts/lib/tmux-layout/telemetry.mjs +14 -2
  263. package/scripts/lib/validate/check-agents-skills.mjs +327 -0
  264. package/scripts/lib/validate/check-agents.mjs +3 -3
  265. package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
  266. package/scripts/lib/validate/check-doc-cli-commands.mjs +9 -33
  267. package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +370 -0
  268. package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
  269. package/scripts/lib/validate/check-owner-leakage.mjs +281 -20
  270. package/scripts/lib/validate/check-skill-links.mjs +163 -0
  271. package/scripts/lib/validate/check-skill-script-paths.mjs +455 -0
  272. package/scripts/lib/validate/check-untracked-test-deps.mjs +10 -0
  273. package/scripts/lib/validate/check-unwired-features.mjs +0 -9
  274. package/scripts/lib/validate/check-validator-registration.mjs +254 -0
  275. package/scripts/lib/validate/check-vcs-repo-flag.mjs +6 -28
  276. package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
  277. package/scripts/lib/validate/markdown-fences.mjs +196 -0
  278. package/scripts/lib/vault-backfill/template.mjs +63 -6
  279. package/scripts/lib/vault-mirror/process.mjs +165 -42
  280. package/scripts/lib/vault-mirror/telemetry.mjs +2 -2
  281. package/scripts/lib/vault-status/board-lock.mjs +185 -0
  282. package/scripts/lib/vault-status/board-writer.mjs +174 -135
  283. package/scripts/lib/vault-status/narrative-mirror.mjs +129 -37
  284. package/scripts/lib/wave-executor/dispatch-common.mjs +164 -0
  285. package/scripts/lib/wave-executor/foreign-dispatch.mjs +7 -142
  286. package/scripts/lib/wave-executor/remote-dispatch.mjs +502 -0
  287. package/scripts/lib/wave-resource-gate.mjs +133 -7
  288. package/scripts/lib/wave-sizing.mjs +4 -1
  289. package/scripts/lib/wave-transcript-tail.mjs +142 -8
  290. package/scripts/materialize-wave-scope.mjs +32 -9
  291. package/scripts/memory-propose.mjs +146 -8
  292. package/scripts/migrate-cold-start-seed.mjs +4 -1
  293. package/scripts/parse-config.mjs +60 -3
  294. package/scripts/promote-vault-strict.mjs +4 -15
  295. package/scripts/release.mjs +337 -29
  296. package/scripts/repair-invalid-sessions.mjs +3 -3
  297. package/scripts/run-quality-gate.mjs +128 -11
  298. package/scripts/site-numbers.mjs +36 -4
  299. package/scripts/sweep-expired-learnings.mjs +90 -0
  300. package/scripts/sync-vault-schema.mjs +3 -1
  301. package/scripts/telemetry.mjs +2 -2
  302. package/scripts/validate-plugin.mjs +187 -0
  303. package/scripts/validate-wave-scope.mjs +28 -8
  304. package/scripts/vault-consolidate.mjs +3 -11
  305. package/scripts/vault-integration-watcher.mjs +2 -4
  306. package/scripts/vault-mirror.mjs +111 -26
  307. package/scripts/wave-scope-binding.mjs +215 -0
  308. package/skills/_shared/instruction-file-resolution.md +10 -0
  309. package/skills/_shared/parallel-aware-auq.md +31 -2
  310. package/skills/_shared/parallel-aware-preamble.md +18 -4
  311. package/skills/_shared/platform-tools.md +1 -1
  312. package/skills/_shared/state-ownership.md +1 -1
  313. package/skills/architecture/SKILL.md +7 -5
  314. package/skills/{domain-model/SKILL.md → architecture/references/domain-model.md} +9 -9
  315. package/skills/autopilot/SKILL.md +4 -18
  316. package/skills/claude-md-drift-check/SKILL.md +5 -1
  317. package/skills/claude-md-drift-check/checker.mjs +62 -2
  318. package/skills/convergence-monitoring/SIGNALS.md +55 -0
  319. package/skills/discovery/probes/vault-staleness.mjs +37 -13
  320. package/skills/discovery/probes-arch.md +20 -18
  321. package/skills/dispatcher/SKILL.md +3 -2
  322. package/skills/ecosystem-health/SKILL.md +4 -1
  323. package/skills/ecosystem-health/wizard.md +5 -0
  324. package/skills/evolve/SKILL.md +87 -11
  325. package/skills/frontmatter-guard/SKILL.md +11 -5
  326. package/skills/npm-publish/SKILL.md +1 -1
  327. package/skills/reconcile/SKILL.md +38 -2
  328. package/skills/remote-offload/SKILL.md +89 -0
  329. package/skills/session-end/SKILL.md +18 -905
  330. package/skills/session-end/phase-3-6-tail.md +19 -9
  331. package/skills/session-end/plan-verification.md +221 -155
  332. package/skills/session-end/references/phase-2-quality-gate.md +93 -0
  333. package/skills/session-end/references/phase-3-documentation-updates.md +229 -0
  334. package/skills/session-end/references/phase-4a-worktree-cleanup.md +120 -0
  335. package/skills/session-end/references/phase-4b-worktree-orphan-sweep.md +58 -0
  336. package/skills/session-end/references/phase-5-issue-cleanup.md +104 -0
  337. package/skills/session-end/references/session-summary-template.md +62 -0
  338. package/skills/session-plan/SKILL.md +49 -0
  339. package/skills/session-start/SKILL.md +41 -900
  340. package/skills/session-start/phase-8-5-express-path.md +1 -1
  341. package/skills/session-start/references/phase-1-1-dispatcher-autonomy-capture.md +55 -0
  342. package/skills/session-start/references/phase-1-2-session-lock.md +140 -0
  343. package/skills/session-start/references/phase-1-5-session-continuity.md +254 -0
  344. package/skills/session-start/references/phase-1-7-vault-status-board.md +53 -0
  345. package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +75 -0
  346. package/skills/session-start/references/phase-4-ssot-environment-check.md +155 -0
  347. package/skills/session-start/references/phase-6-5-forced-reads.md +75 -0
  348. package/skills/session-start/references/phase-6-6-project-intelligence.md +81 -0
  349. package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +103 -0
  350. package/skills/vault-sync/validator.mjs +21 -27
  351. package/skills/wave-executor/SKILL.md +16 -2
  352. package/skills/wave-executor/references/wave-loop-dispatch.md +612 -0
  353. package/skills/wave-executor/references/wave-loop-review.md +570 -0
  354. package/skills/wave-executor/references/wave-loop-scope-manifest.md +162 -0
  355. package/skills/wave-executor/wave-loop.md +14 -1271
  356. package/templates/_shared/journey-manifest.md +10 -6
  357. package/.cursor/commands/autopilot-multi.md +0 -14
  358. package/.cursor/commands/contract-version-bump.md +0 -14
  359. package/.cursor/commands/journey-audit.md +0 -14
  360. package/.cursor/skills/contract-version-bump/SKILL.md +0 -12
  361. package/.cursor/skills/daily/SKILL.md +0 -12
  362. package/.cursor/skills/domain-model/SKILL.md +0 -13
  363. package/.cursor/skills/journey-audit/SKILL.md +0 -13
  364. package/.cursor/skills/skill-creator/SKILL.md +0 -13
  365. package/.cursor/skills/ubiquitous-language/SKILL.md +0 -13
  366. package/commands/autopilot-multi.md +0 -74
  367. package/commands/contract-version-bump.md +0 -28
  368. package/commands/journey-audit.md +0 -43
  369. package/pi/prompts/autopilot-multi.md +0 -12
  370. package/pi/prompts/contract-version-bump.md +0 -12
  371. package/pi/prompts/journey-audit.md +0 -12
  372. package/scripts/autopilot-multi.mjs +0 -885
  373. package/scripts/backfill-learnings-expires.mjs +0 -196
  374. package/scripts/backfill-learnings.mjs +0 -203
  375. package/scripts/fleet-instruction-scan.mjs +0 -141
  376. package/scripts/lib/autopilot/dep-graph.mjs +0 -417
  377. package/scripts/lib/autopilot/multi-killswitch.mjs +0 -184
  378. package/scripts/lib/webhook-url.mjs +0 -105
  379. package/scripts/lifecycle-sim-v6.mjs +0 -347
  380. package/scripts/migrate-learnings-jsonl.mjs +0 -189
  381. package/scripts/migrate-subagents-jsonl.mjs +0 -196
  382. package/scripts/upload-social-preview.mjs +0 -316
  383. package/skills/_shared/model-selection.md +0 -64
  384. package/skills/contract-version-bump/SKILL.md +0 -219
  385. package/skills/daily/SKILL.md +0 -222
  386. package/skills/daily/generate.sh +0 -92
  387. package/skills/daily/templates/daily.md.tpl +0 -36
  388. package/skills/journey-audit/SKILL.md +0 -269
  389. package/skills/skill-creator/SKILL.md +0 -168
  390. package/skills/ubiquitous-language/SKILL.md +0 -97
  391. package/skills/vault-sync/package-lock.json +0 -40
  392. /package/skills/{domain-model → architecture/references}/ADR-FORMAT.md +0 -0
  393. /package/skills/{domain-model → architecture/references}/CONTEXT-FORMAT.md +0 -0
@@ -34,6 +34,8 @@ Do NOT proceed past Phase 0 if GATE_CLOSED. There is no bypass. Refer to `skills
34
34
 
35
35
  ## Phase 1: Config & Data Loading
36
36
 
37
+ **Telemetry start marker (#1200):** note the current wall-clock time before Step 1.1 runs (e.g. `date +%s%3N`, or the coordinator's own turn-start instant). Every `orchestrator.evolve.completed` emit in Phase 1 / Phase 3 below reports `duration_ms` (placeholder `DURATION_MS`) as the elapsed milliseconds since this marker — same in-memory-value convention as `CT`/`AC`/`ASK`/`DROP` in `skills/session-end/SKILL.md`'s `orchestrator.handover.gated` emits.
38
+
37
39
  ### 1.1 Read Session Config
38
40
 
39
41
  Read and parse Session Config per `skills/_shared/config-reading.md`. Store result as `$CONFIG`.
@@ -44,6 +46,13 @@ Extract `persistence` from `$CONFIG`. If `persistence` is `false`, abort with me
44
46
 
45
47
  > "Learnings require persistence to be enabled in Session Config. Add `persistence: true` to your Session Config block (CLAUDE.md for Claude Code, AGENTS.md for Codex CLI)."
46
48
 
49
+ **Telemetry on abort (#1200, #1206):** before stopping, emit the abort form of the run-completion event. Kept as a minimal `emit-event.mjs` call, not routed through `scripts/sweep-expired-learnings.mjs` — no store-write CLI has run yet at this gate (it fires before Step 1.4 even reads `learnings.jsonl`), so there is no mechanical pipeline call site to fold this emit into, unlike the Step 3.5(5)/(6) success path below:
50
+
51
+ ```bash
52
+ node scripts/emit-event.mjs --type orchestrator.evolve.completed --payload \
53
+ "$(node -e "process.stdout.write(JSON.stringify({aborted: 'persistence-disabled', reason: 'Learnings require persistence to be enabled in Session Config.'.slice(0,300), duration_ms: DURATION_MS}))")"
54
+ ```
55
+
47
56
  ### 1.3 Determine Mode
48
57
 
49
58
  Read mode from `$ARGUMENTS`:
@@ -91,7 +100,12 @@ Extract learnings from session history.
91
100
  - Read all entries from `.orchestrator/metrics/sessions.jsonl` (or `<state-dir>/metrics/sessions.jsonl` if the v2 path does not exist — see Phase 1.4 fallback)
92
101
  - Parse each JSONL line as JSON
93
102
  - Sort by `completed_at` descending (most recent first)
94
- - If no sessions found, abort: "No session data available. Complete at least one session before running evolve."
103
+ - If no sessions found, abort: "No session data available. Complete at least one session before running evolve." **Telemetry on abort (#1200, #1206):** before stopping, emit — same minimal `emit-event.mjs` call as Phase 1.2's abort, and for the same reason: this gate fires before the Step 3.5(5) `sweep-expired-learnings.mjs --prune` call exists to fold the emit into:
104
+
105
+ ```bash
106
+ node scripts/emit-event.mjs --type orchestrator.evolve.completed --payload \
107
+ "$(node -e "process.stdout.write(JSON.stringify({aborted: 'no-session-data', reason: 'No session data available. Complete at least one session before running evolve.'.slice(0,300), duration_ms: DURATION_MS}))")"
108
+ ```
95
109
 
96
110
  ### Step 3.1b: Read Extra Sources (#638)
97
111
 
@@ -167,7 +181,7 @@ For each of the 9 built-in analyzer learning types, apply these heuristics:
167
181
  - Read `.orchestrator/metrics/events.jsonl` (session + wave events) and the registry `sweep.log` at `~/.config/session-orchestrator/sessions/sweep.log`. Both are optional — missing files produce no candidates.
168
182
  - Invoke `scripts/lib/hardware-pattern-detector.mjs` → `detectHardwarePatterns({events, sweepLogEntries, thresholds})`. Thresholds come from Session Config `resource-thresholds` when present, falling back to `DEFAULT_THRESHOLDS`.
169
183
  - Five detection signals (aggregated per `(signal, host_class)` pair, ≥2 occurrences required):
170
- - **oom-kill** — `orchestrator.session.stopped` with `exit_code: 137` or OOM-marker in `error`
184
+ - **oom-kill** — `orchestrator.turn.stopped` (or its deprecated alias `orchestrator.session.stopped`, which `hooks/on-stop.mjs` still emits with `deprecated: true` until **2027-03-06**) with `exit_code: 137` or OOM-marker in `error`. Both names are accepted for the deprecation window because every OOM record already on disk carries only the legacy name; the detector's set lives in `OOM_TERMINAL_EVENTS` (`scripts/lib/hardware-pattern-detector.mjs`) and drops the alias on that date.
171
185
  - **heartbeat-gap** — registry sweep-log entries with `gap_minutes` above `resource-thresholds.zombie-threshold-min`
172
186
  - **concurrent-session-pressure** — session-start events with `peer_count ≥ concurrent-sessions-warn`
173
187
  - **disk-full** — events whose `error` matches `ENOSPC` / "no space left"
@@ -302,22 +316,34 @@ For confirmed learnings, use atomic rewrite strategy:
302
316
  Write the full next-generation entry set (existing entries **with** the step-2/3 confidence
303
317
  updates, **plus** the step-4 new learnings) as JSONL to a temp sidecar **via the Write tool**
304
318
  (not a shell `>` redirect — the destructive-command guard blocks it), then invoke the
305
- `--prune` subcommand of the sweep CLI:
319
+ `--prune` subcommand of the sweep CLI. **This call is also `/evolve`'s ONLY
320
+ `orchestrator.evolve.completed` success emit (#1206)** — export `N` (Step 3.5(4)'s
321
+ new-learnings count), `M` (Step 3.5(2)'s reinforced-existing count) and `DURATION_MS`
322
+ (elapsed ms since the Phase 1 marker) as real shell variables before running this line;
323
+ `${N:-0}`-style expansion means an un-exported variable degrades to a safe `0` rather than
324
+ an argument error:
306
325
 
307
326
  ```bash
308
327
  NEXT=".orchestrator/metrics/.learnings-next.jsonl" # written by the step above
309
- node scripts/sweep-expired-learnings.mjs --prune --apply --json --entries "$NEXT" && rm -f "$NEXT"
328
+ node scripts/sweep-expired-learnings.mjs --prune --apply --json --entries "$NEXT" \
329
+ --appended "${N:-0}" --boosted "${M:-0}" --duration-ms "${DURATION_MS:-0}" \
330
+ --repo-root "$(pwd)" && rm -f "$NEXT"
310
331
  ```
311
332
 
312
333
  `--file` / `--archive` default to the canonical store + archive paths — pass them only when
313
334
  operating on a non-default pair. The command prints ONE JSON line; capture it as `$PRUNE` and
314
- report its `{scanned, kept, archived, byReason}` in the final summary. Preview first with
315
- `--prune --dry-run --json` (same counts, zero writes) whenever the next generation was
316
- hand-assembled.
317
-
318
- > **This step is `/evolve`'s only store-write path.** Until #1017 the invocation lived here as
319
- > an inline `node --input-type=module -e` block, which is a mechanism hiding inside prose: no
320
- > `--help`, no exit-code contract, no test. Do not re-inline it, and do not hand-roll a
335
+ report its `{scanned, kept, archived, byReason}` in the final summary — `$PRUNE.archived` is
336
+ also the `pruned` counter the emit above just wrote, so there is nothing left to compute for
337
+ the telemetry after this line. Preview first with `--prune --dry-run --json` (same counts,
338
+ zero writes, **no telemetry emit** — dry-run never claims a completed run) whenever the next
339
+ generation was hand-assembled.
340
+
341
+ > **This step is `/evolve`'s only store-write path, and (since #1206) its only
342
+ > `orchestrator.evolve.completed` success emit.** Until #1017 the store write lived here as
343
+ > an inline `node --input-type=module -e` block, and until #1206 the telemetry emit was a
344
+ > SEPARATE `emit-event.mjs` call further down this file — both were a mechanism hiding inside
345
+ > prose: no `--help`, no exit-code contract, no test, and (for the emit) forgettable
346
+ > independently of the write it reported on. Do not re-inline either, and do not hand-roll a
321
347
  > `jq | ... > learnings.jsonl` pass — that bypasses every #721 safety net.
322
348
 
323
349
  **Exit codes are the no-op rule.** `0` = applied (or a clean no-op). `1` = input error: the
@@ -380,6 +406,13 @@ For confirmed learnings, use atomic rewrite strategy:
380
406
 
381
407
  Report: "Saved N new learnings, updated M existing. Total active: K."
382
408
 
409
+ **Telemetry (#1200, #1206):** already emitted by `scripts/sweep-expired-learnings.mjs --prune`
410
+ at Step 3.5(5) above — no separate action here. `appended`/`boosted`/`duration_ms` are whatever
411
+ `$N`/`$M`/`$DURATION_MS` carried into that call, and `pruned` is `$PRUNE.archived` (the sweep
412
+ CLI's own returned total). `promoted` is always `0` from THIS call site: promotion to `public`
413
+ scope is the separate `npm run share:hw-learnings -- --promote` CLI, never invoked by
414
+ `/evolve analyze` itself — see `docs/events-schema.md`.
415
+
383
416
  ### Step 3.6: C2 Auto-Repair Feeder (opt-in — #647)
384
417
 
385
418
  > **Default OFF (advisory-only).** With no `skill-evolution:` block in Session Config, this step surfaces repair candidates as ADVICE only — it applies nothing and opens no MR. This mirrors the opt-in precedent of `slopcheck` (#520) and `verification-auto-fix` (#521): the engine is dark unless explicitly enabled.
@@ -542,6 +575,8 @@ N active learnings (M high confidence, K expiring soon)
542
575
 
543
576
  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.
544
577
 
578
+ **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.
579
+
545
580
  ### Step 6.0: Argument Parsing
546
581
 
547
582
  Parse `$ARGUMENTS` for trailing flags after the `dialectic` keyword:
@@ -603,6 +638,29 @@ const result = await runDialecticDeriver({
603
638
  - If `--apply`: call `mergePeerCard(existingBody, managedUpdates)` 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.
604
639
  - Report: `Dialectic-derived: M deltas to USER.md, N deltas to AGENT.md. Dry-run | Applied. Tokens: in=<X> out=<Y>.`
605
640
 
641
+ **Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs`, not skill prose.**
642
+ The dry-run branch needs no action here: `runDialecticDeriver()` already emitted the success
643
+ form (`mode: 'dry-run'`) internally at Step 6.2, using `countManagedSections(diff)` on the SAME
644
+ diff this step presents — in dry-run the diff IS the final artefact, so the event and the
645
+ artefact are computed from the same value. The **apply** branch is the one case that pipeline
646
+ cannot record on its own: the merge above happens here, one layer up, so call
647
+ `recordDialecticRun()` (the sibling export beside `emitEvolveCompleted` in
648
+ `scripts/lib/learnings/evolve-telemetry.mjs`) immediately after the `writePeerCard()` calls,
649
+ using each target's `mergePeerCard()` `stats` for the deltas:
650
+
651
+ ```javascript
652
+ await recordDialecticRun({
653
+ repoRoot,
654
+ status: 'ok',
655
+ mode: 'apply',
656
+ userDeltas: userMergeStats.replaced + userMergeStats.appended,
657
+ agentDeltas: agentMergeStats.replaced + agentMergeStats.appended,
658
+ tokensIn: result.usage?.input_tokens,
659
+ tokensOut: result.usage?.output_tokens,
660
+ durationMs: DURATION_MS,
661
+ });
662
+ ```
663
+
606
664
  ### Step 6.5: Error Handling
607
665
  - `status: 'unknown-model'` → fail with clear error (already thrown by validateModel)
608
666
  - `status: 'budget-exceeded'` → emit `{status:'budget-exceeded', used:N, budget:M}`, do NOT truncate
@@ -610,6 +668,24 @@ const result = await runDialecticDeriver({
610
668
  - `status: 'empty-input'` → exit clean with message "dialectic: skipped (no input)"
611
669
  - subagent crash → log ⚠, exit cleanly (do NOT write to `.orchestrator/dialectic-pending.md`)
612
670
 
671
+ **Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs` for THREE of the five
672
+ outcomes.** `budget-exceeded`, `would-empty-card`, and `empty-input` are `runDialecticDeriver()`
673
+ RETURN values, so the module records them itself, mechanically, at the exact return point —
674
+ nothing to do here for those three. The remaining two are THROWN, not returned, and can only be
675
+ caught one layer up:
676
+
677
+ - `unknown-model` — `validateModel()` throws synchronously before `runDialecticDeriver()` can
678
+ record anything about the call.
679
+ - `subagent-crash` — a `dispatchAgent`/`Agent()` failure propagates out of
680
+ `runDialecticDeriver()` uncaught (it has no status of its own for this case).
681
+
682
+ Catch both here and call the SAME `recordDialecticRun()` used in Step 6.4's apply branch,
683
+ passing the literal slug as `status` (the abort form: `{aborted: status, duration_ms}`):
684
+
685
+ ```javascript
686
+ await recordDialecticRun({ repoRoot, status: 'unknown-model' /* or 'subagent-crash' */, durationMs: DURATION_MS });
687
+ ```
688
+
613
689
  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).
614
690
 
615
691
  ---
@@ -94,13 +94,19 @@ The output is stable across calls for the same schema version. Regenerate only w
94
94
 
95
95
  ## Schema Source Path
96
96
 
97
- The canonical schema source is:
97
+ The canonical schema source is `packages/zod-schemas/src/vault-frontmatter.ts` inside a **projects-baseline** checkout. That checkout is **optional and private** — see [`docs/baseline.md`](../../docs/baseline.md) — so the path is RESOLVED, never hardcoded. `resolveSchemaSourcePath()` resolves it in two tiers and returns `null` when nothing resolves. When the EXPLICIT tier is set it is used **alone** — probing past a wrong explicit value would silently read a different baseline than the one named:
98
98
 
99
- ```
100
- ~/Projects/projects-baseline/packages/zod-schemas/src/vault-frontmatter.ts
101
- ```
99
+ | Tier | Candidate | Set by |
100
+ |---|---|---|
101
+ | **explicit** (exclusive) | `<baseline-path>/packages/zod-schemas/src/vault-frontmatter.ts` | `SO_BASELINE_PATH` env, else `owner.yaml` `paths.baseline-path` (host-local, never committed) — via `resolveHostPath('baseline-path', …)` |
102
+ | convention 1 | `<repoRoot>/../projects-baseline/packages/…` | sibling-checkout convention, the same one `scripts/sync-vault-schema.mjs` uses |
103
+ | convention 2 | `~/Projects/projects-baseline/packages/…` | legacy default this module shipped with |
104
+
105
+ Before this was resolved, convention 2 was the ONLY path and it was hardcoded: on a host whose checkout lives anywhere else, `readVaultSchema()` returned `null` and `generateFrontmatterSnippet()` then died with `Cannot destructure property 'typeEnum' of 'schema' as it is undefined`.
106
+
107
+ `readVaultSchema()` reads the resolved file on every call unless the in-memory mtime cache is current. It returns `null` (no throw) when no candidate resolves or the file is unreadable.
102
108
 
103
- `readVaultSchema()` reads this file on every call unless the in-memory mtime cache is current. The function returns `null` (no throw) when the file is absent or unreadable.
109
+ **Degraded mode.** With `null`, `generateFrontmatterSnippet()` does not throw: it falls back to an in-module enum/field set mirroring `skills/vault-sync/validator.mjs` (this repo's own in-tree copy of the schema, and what `vault-sync` actually validates against) and writes ONE stderr WARN per process. `computeSchemaHash()` returns `null` in that state — never the SHA-256 of the empty string, which would look like a real measurement and compare equal across every baseline-less host.
104
110
 
105
111
  The parsed output includes:
106
112
 
@@ -39,7 +39,7 @@ The script gates mechanics. These three are yours, and it will not make them for
39
39
 
40
40
  **2. What a leak means when one is found.** A hit from the leakage gate is not a pattern to silence. Decide which of two it is: a real leak (fix `package.json` `files`, re-pack, re-check) or genuine over-matching (fix `LEAKAGE_PATTERNS` in `scripts/release.mjs` **with a test**). There is no third option, and neither is "publish anyway and clean it up in the next version" — an npm publish is not revocable, and unpublishing burns the version number permanently. Operator handling detail: `docs/distribution/npm-publish-checklist.md` § 3.
41
41
 
42
- **3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror, CI not green on the exact commit, a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry propagation, a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `commands/release.md` § Abort criteria is the operative list.
42
+ **3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror, CI not green on the exact commit **on either platform** (`--check` carries both `ci-green-on-head` for GitLab and `ci-green-on-head-github` for the mirror, whose macOS matrix leg has no GitLab equivalent), a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry propagation, a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `commands/release.md` § Abort criteria is the operative list.
43
43
 
44
44
  ## Failure-mode table
45
45
 
@@ -156,9 +156,9 @@ himself.
156
156
  ### 2.3 Invoke `runReconcile`
157
157
 
158
158
  ```javascript
159
- import { runReconcile } from '$PLUGIN_ROOT/scripts/lib/reconcile/engine.mjs';
159
+ import { runReconcileFromSkill } from '$PLUGIN_ROOT/scripts/lib/reconcile/engine.mjs';
160
160
 
161
- const { proposals, rejected, summary, error } = await runReconcile({
161
+ const { proposals, rejected, summary, error } = await runReconcileFromSkill({
162
162
  repoRoot, // absolute path from git rev-parse --show-toplevel
163
163
  ruleExpiryDays: RULE_EXPIRY_DAYS, // empty → undefined → engine per-type TTL
164
164
  minRuleDays: MIN_RULE_DAYS, // default 7 — floors a near-dead expires-at
@@ -166,6 +166,9 @@ const { proposals, rejected, summary, error } = await runReconcile({
166
166
  maxProposalsPerRun: MAX_PROPOSALS_PER_RUN, // default 10 — volume brake (issue #900 D)
167
167
  now: new Date(),
168
168
  dryRun: DRY_RUN, // true → engine touches no disk (no idempotency sidecar write)
169
+ // trigger is pinned to 'skill' IN CODE by runReconcileFromSkill (#1201 Part A) —
170
+ // this prose block no longer sets it.
171
+ targets, // from resolveEffectiveTargets above; recorded when non-empty, omitted otherwise
169
172
  });
170
173
 
171
174
  // The engine does NOT apply a confidence floor — it proposes every eligible
@@ -353,6 +356,39 @@ If `written === 0` and `approved.length === 0`:
353
356
 
354
357
  ---
355
358
 
359
+ ## Consolidating and Dropping Generated Rules (merge contract)
360
+
361
+ `.claude/rules/` grows one file per approved learning, so it accumulates. This
362
+ repo consolidated 43 generated files (112,443 B, 46.2 % frontmatter+provenance
363
+ overhead) into 8 thematic files plus 10 drops on 2026-09-06. Both operations
364
+ are safe ONLY under the contract below — the full authoring spec is
365
+ [`docs/rule-authoring.md`](../../docs/rule-authoring.md) § "Consolidated rules:
366
+ N provenance pairs in ONE file". The three facts that decide whether a
367
+ consolidation survives the next `/reconcile`:
368
+
369
+ - **A target file may carry N provenance bullet PAIRS.** Frontmatter
370
+ `learning-key:` is a scalar, so at most one marker fits there; the other N−1
371
+ live in the body as `` - learning-key: `…` `` + `` - learning-id: `…` ``
372
+ bullets, which `engine.mjs` reads via `BODY_LEARNING_KEY_RE` /
373
+ `BODY_LEARNING_ID_RE`. One pair per absorbed learning — a missing pair
374
+ regenerates that learning as a standalone file on the next run.
375
+ - **A merged file's `expires-at` is the EARLIEST of its parts**, never the
376
+ latest: it must not outlive its shortest-lived content.
377
+ - **A dropped learning must be STAMPED before deletion, or it regenerates.**
378
+ `rm .claude/rules/<slug>.md` alone leaves `isProcessed()` false and no
379
+ on-disk marker, so the engine re-proposes it. Stamp it terminal first with
380
+ `markCandidateProcessed({ learningKey, outcome: 'rejected', fallbackSlug,
381
+ repoRoot })` from `scripts/lib/reconcile/idempotency.mjs` — the ONLY
382
+ sanctioned writer of `.orchestrator/runtime/reconcile-candidates.jsonl`
383
+ (never append to that file by hand; the read-side shape guard drops foreign
384
+ records and `mergeCandidates` rewrites the store in full).
385
+
386
+ **Verify a consolidation with a dry run**, not by eye: `alreadyMaterialized`
387
+ must equal absorbed + dropped. If it equals only the absorbed count, the drops
388
+ were not stamped and the next run will resurrect them. Do the whole operation
389
+ while `reconcile.enabled: false` in Session Config, so nothing regenerates
390
+ underneath you mid-edit.
391
+
356
392
  ## Critical Rules
357
393
 
358
394
  - **NEVER** call `writeApprovedRules` before the operator has confirmed via AUQ — this is the
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: remote-offload
3
+ user-invocable: false
4
+ tags: [reference, remote, offload, wave-executor, resource-gate]
5
+ model: haiku
6
+ model-preference: sonnet
7
+ model-preference-codex: gpt-5.4-mini
8
+ model-preference-cursor: claude-sonnet-4-6
9
+ description: Use when local resource pressure would shrink or coordinator-direct a wave, a wave plan carries heavy build/test/audit roles (test, ui, perf), or the operator says offload, remote host, or auslagern — reference for routing that wave role to a declared SSH-reachable host instead of reducing agent count
10
+ ---
11
+
12
+ # Remote Offload — routing a wave role to a declared host instead of shrinking it
13
+
14
+ Repo-side half of #1160: `remote-hosts:` declares hosts, `wave-resource-gate.mjs` places work on them, `remote-dispatch.mjs` runs it. The host-side `offload` CLI (a separate baseline repo owns its SSOT) is invoked as a subprocess; this skill covers what the repo itself knows about it.
15
+
16
+ ## Quick reference
17
+
18
+ | Task | Command |
19
+ |---|---|
20
+ | Host readiness | `offload doctor -H <alias> --brief` |
21
+ | Gate (typecheck/lint/test) | `offload gate <repo> -H <alias>` |
22
+ | Run a command | `offload run <repo> -H <alias> -- <cmd...>` |
23
+ | Read-only analysis | `offload claude <repo> -H <alias> --model <name> < prompt.txt` |
24
+ | Implementation + patch | `offload claude <repo> -H <alias> --write --patch <path> < prompt.txt` |
25
+ | Remove finished jobs | `offload clean -H <alias> --older-than <hours>` |
26
+
27
+ Exit codes (`offload --help`, measured 2026-09-02): `0` ok · `1` usage/config · `2` host unreachable/not ready · `3` remote command failed · `4` sync failed · `5` timeout · `6` empty diff on a `--write` run · `7` account quota exhausted (429) · `8` write lock held. Same map as `OFFLOAD_EXIT_REASONS` in `scripts/lib/wave-executor/remote-dispatch.mjs`.
28
+
29
+ ## 1. Decision rule — offload vs reduce
30
+
31
+ The gate decides, not the coordinator. `applyOffloadDecision()` in `scripts/lib/wave-resource-gate.mjs` only fires when the resource verdict is already `reduce` or `coordinator-direct`, and only AFTER the HR-004 heavy-repo cap — a capped wave that offloads still respects the cap. It never probes the network; the coordinator supplies a readiness WITNESS:
32
+
33
+ - `opts.remoteReady` — `{ [alias]: boolean }`, built from the SessionStart banner line `Offload <alias>: ready=yes …`, or
34
+ - `opts.probeFn` — an async `(alias) => boolean` fallback, consulted only for aliases `remoteReady` doesn't answer for (backed by `remoteDoctor()`, i.e. `offload doctor -H <alias> --brief` parsed by `parseDoctorLine()`).
35
+
36
+ With neither supplied, no host counts as ready and the wave stays local — the gate fails toward local, never toward an unverified host. A role in `NEVER_FOREIGN_ROLES` (`scripts/lib/wave-executor/dispatch-common.mjs`: `impl-core`, `security-review`, `migration`, `release`, `secrets`) is never offloaded regardless of readiness.
37
+
38
+ ## 2. What is declared where
39
+
40
+ `remote-hosts:` in Session Config (`docs/session-config-reference.md` § Remote Hosts) declares the hosts, in preference order — the gate takes the FIRST host whose `roles-allowed` accepts the wave role and is witnessed ready:
41
+
42
+ ```yaml
43
+ remote-hosts:
44
+ - alias: <ssh-alias> # required, SAFE slug; reaches argv as `-H <alias>`
45
+ roles-allowed: [test, ui, perf] # subset of test|ui|perf (default: all three)
46
+ repo-path: ~/path/on/host # optional; SAFE path; default null
47
+ claude-path: ~/.local/bin/claude # optional; SAFE path; default null
48
+ ```
49
+
50
+ Two enums meet here and must not be conflated: `roles-allowed` holds `agent-mapping` roles (`test`/`ui`/`perf`), not wave roles (`Impl-Core`/`Quality`/…). The translation table is `OFFLOADABLE_WAVE_ROLES` in `wave-resource-gate.mjs` (`quality`→`test`, `test`→`test`, `ui`→`ui`, `perf`→`perf`; a wave role absent from that map stays local by default).
51
+
52
+ An `agent-mapping` entry of the form `<role>: ssh:<alias>` routes that wave role to Claude running ON the declared host instead of shrinking the wave; the alias must already exist under `remote-hosts`, or the config parse throws.
53
+
54
+ ## 3. Three channels of work
55
+
56
+ | Channel | Command | Verdict rule |
57
+ |---|---|---|
58
+ | Gate / arbitrary command | `offload gate` / `offload run` | Exit code decides — use the table above, never the prose in the run's own output |
59
+ | Implementation, patch back | `offload claude --write --patch <file>` via `dispatchRemote()` | Empty patch (exit `6`) is a FAILURE regardless of what the run reports; the coordinator READS the patch, then applies it with its own `git apply` — the remote job never touches the repo the coordinator commits from |
60
+ | Read-only analysis | `offload claude` (no `--write`) | No patch is produced; treat the transcript as advisory input, same skepticism as any reviewer output (`receiving-review.md`) |
61
+
62
+ `dispatchRemote()` (`scripts/lib/wave-executor/remote-dispatch.mjs`) is the wave-executor caller for the second and third channels; it emits `orchestrator.remote_dispatch.completed` once per call (`docs/events-schema.md`) — the only ledger record a remote dispatch produces, since a Bash-spawned `offload` child fires no `SubagentStop` hook. Payload: `host`, `role`, `run_id`, `ok`, `exit_code`, `duration_ms`, `patch_files`, `patch_bytes`, `reason` (present on every refusal and every failure class — absence means success). Deliberately excluded from the payload: prompt text, patch body, `patch_path`.
63
+
64
+ ## 4. Rules
65
+
66
+ - **Supervised, not blind.** Read the gate log or the patch before treating it as a result — completed and correct are not the same claim.
67
+ - **Prompt travels on stdin, never argv** (`offload --help`: "prompts travel by file (mode 600), never argv"; argv is visible to every process on the host).
68
+ - **The patch is READ, then applied by the coordinator** — never inside the offloaded job.
69
+ - **`never_foreign` roles are never offloaded** — checked first in `dispatchRemote()`, before any spawn or side effect.
70
+ - **One `--job` per concurrent run.** A job holds ONE set of run artefacts; two parallel runs sharing a job collided until per-run ids were introduced.
71
+ - **Rate-limit (exit `7`) carries the reset time in the message** — do not retry blind.
72
+ - **Secrets never in output** (SEC-008) — `offload` does not print credentials, and the module deliberately excludes prompt text and patch body from telemetry.
73
+ - **Never "clean up" another checkout on the host.** `offload clean` only removes the offload tool's OWN finished job worktrees, never a host's other active checkouts.
74
+
75
+ ## 5. Host readiness checklist
76
+
77
+ - SSH alias configured with key auth (no password/interactive prompt on connect).
78
+ - `tmux` available on the host (for an interactive `offload session`).
79
+ - Claude authenticated ON the host — never copy OAuth credentials between machines (refresh-token rotation invalidates the source copy); log in fresh with `/login` there instead.
80
+ - Repo cloned on the host with headless git credentials configured (no interactive auth prompt on push/pull).
81
+ - Node version matching this repo's `.nvmrc`.
82
+ - Toolchain parity with the local checkout (same package manager, same lockfile).
83
+
84
+ ## 6. Pitfalls measured in this repo
85
+
86
+ - **The pre-push quality gate used to fire on the sync push.** `.husky/pre-push` (#C10) detects a SCRATCH push — an unconfigured remote URL, e.g. the offload tool's own SSH sync target — and skips the gate for it; publish remotes (`origin`, `github`) stay gated regardless. The offload tool has since been fixed upstream to push with `--no-verify` itself, so this repo-side detection is defense-in-depth, not the primary fix.
87
+ - **The host installer must follow this repo's committed lockfile.** `package-lock.json` is tracked here (npm-canonical — `.claude/rules/development.md` § Package Management); install with `npm ci`, never a different package manager's install command, or the host checkout's `node_modules` layout diverges from CI's.
88
+ - **A linked worktree makes `.git` a file, not a directory.** 13 tracked files used to be flagged as "not in repository" in an unmodified worktree at the same layout, because the file form of `.git` was read as an untracked candidate rather than the repository marker — wave 3 fixed `scripts/lib/validate/check-untracked-test-deps.mjs` to treat a `.git` FILE as the repository marker in a linked worktree; the remote gate then ran 15,829/0.
89
+ - **Keychain-route auth shares the host account's usage window with that account's other interactive sessions**, not a dedicated quota — a token-slot profile (`--via slot`) avoids the sharing where a fixed quota matters.