@tyroneross/build-loop 0.36.0 → 0.43.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 (270) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +3 -3
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/.cursor/rules/build-loop-surface.mdc +12 -11
  6. package/.cursor/rules/skill-index.mdc +33 -0
  7. package/AGENTS.md +213 -34
  8. package/README.md +99 -31
  9. package/agents/advisor.md +4 -4
  10. package/agents/alignment-checker.md +2 -2
  11. package/agents/architecture-scout.md +4 -4
  12. package/agents/build-orchestrator.md +38 -36
  13. package/agents/database-assessor.md +11 -5
  14. package/agents/design-contract-specialist.md +8 -8
  15. package/agents/fact-checker.md +13 -3
  16. package/agents/fix-critique.md +2 -2
  17. package/agents/independent-auditor.md +60 -7
  18. package/agents/leak-scanner.md +82 -0
  19. package/agents/overfitting-reviewer.md +2 -2
  20. package/agents/plan-critic.md +1 -1
  21. package/agents/promotion-reviewer.md +5 -5
  22. package/agents/retrospective-synthesizer.md +138 -35
  23. package/agents/scope-auditor.md +82 -11
  24. package/agents/security-reviewer.md +56 -2
  25. package/agents/self-improvement-architect.md +17 -3
  26. package/agents/transcript-pattern-miner.md +5 -5
  27. package/agents/ui-validator.md +1 -1
  28. package/bin/build-loop-debugger.js +143 -0
  29. package/bin/build-loop-install.js +1 -4
  30. package/bin/build-loop-load-probe.js +345 -0
  31. package/codex-skills/build-loop/SKILL.md +28 -6
  32. package/commands/feedback.md +37 -0
  33. package/dist/src/interactive-verifier.d.ts +1 -14
  34. package/dist/src/interactive-verifier.d.ts.map +1 -1
  35. package/dist/src/interactive-verifier.js +6 -113
  36. package/dist/src/interactive-verifier.js.map +1 -1
  37. package/dist/src/quality.d.ts +5 -0
  38. package/dist/src/quality.d.ts.map +1 -0
  39. package/dist/src/quality.js +81 -0
  40. package/dist/src/quality.js.map +1 -0
  41. package/dist/src/storage.d.ts.map +1 -1
  42. package/dist/src/storage.js +37 -3
  43. package/dist/src/storage.js.map +1 -1
  44. package/docs/agent-surface-policy.md +35 -31
  45. package/docs/memory-setup.md +19 -0
  46. package/hooks/git/pre-push +65 -4
  47. package/hooks/hooks.json +95 -38
  48. package/hooks/pre-commit +20 -1
  49. package/hooks/pre-edit-rally-point.sh +10 -3
  50. package/hooks/session-start-codex-hook-trust.sh +30 -0
  51. package/hooks/session-start-git-hooks.sh +3 -1
  52. package/hooks/session-start-rally-point.sh +52 -4
  53. package/hooks/session-start-worktree-gc.sh +47 -94
  54. package/hooks/stop-transcript-sweep.sh +173 -0
  55. package/hooks/test_closeout.sh +14 -2
  56. package/package.json +8 -7
  57. package/scripts/README.md +1 -1
  58. package/scripts/_paths.py +65 -0
  59. package/scripts/groundwork_exchange.py +1012 -0
  60. package/scripts/install_memory.py +33 -1
  61. package/scripts/lessons_index/ingest.py +13 -2
  62. package/scripts/lessons_index/query.py +36 -13
  63. package/scripts/memory_context/__init__.py +108 -14
  64. package/scripts/memory_graph/__init__.py +5 -1
  65. package/scripts/project_resolver.py +42 -36
  66. package/scripts/sync_plugin_cache.py +37 -2
  67. package/skills/agent-rally-point/SKILL.md +46 -0
  68. package/skills/api-registry-bridge/SKILL.md +1 -1
  69. package/skills/architecture/dead/SKILL.md +1 -1
  70. package/skills/architecture/impact/SKILL.md +1 -1
  71. package/skills/architecture/review/SKILL.md +1 -1
  72. package/skills/architecture/rules/SKILL.md +3 -3
  73. package/skills/architecture/scan/SKILL.md +1 -1
  74. package/skills/architecture/trace/SKILL.md +1 -1
  75. package/skills/attribution-standard/SKILL.md +6 -6
  76. package/skills/auto-decision-capture/SKILL.md +31 -2
  77. package/skills/auto-finding-capture/SKILL.md +28 -1
  78. package/skills/build-loop/SKILL.md +131 -23
  79. package/skills/build-loop/fallbacks.md +16 -21
  80. package/skills/build-loop/phases/ui-validation.md +2 -2
  81. package/skills/build-loop/references/advisor-dispatch-ladder.md +1 -1
  82. package/skills/build-loop/references/apple-native-planning.md +1 -1
  83. package/skills/build-loop/references/autonomous-and-per-commit-modes.md +11 -5
  84. package/skills/build-loop/references/autonomy-dashboard.md +115 -0
  85. package/skills/build-loop/references/capability-routing.md +24 -2
  86. package/skills/build-loop/references/coordination.md +24 -6
  87. package/skills/build-loop/references/experiment-results-template.md +15 -3
  88. package/skills/build-loop/references/leadership.md +1 -1
  89. package/skills/build-loop/references/memory.md +14 -3
  90. package/skills/build-loop/references/modular-systems-pack.md +8 -0
  91. package/skills/build-loop/references/output-style.md +86 -0
  92. package/skills/build-loop/references/phase-1-assess.md +102 -2
  93. package/skills/build-loop/references/phase-2-plan.md +9 -1
  94. package/skills/build-loop/references/phase-3-execute.md +5 -2
  95. package/skills/build-loop/references/phase-4-review.md +85 -8
  96. package/skills/build-loop/references/phase-5-iterate.md +76 -8
  97. package/skills/build-loop/references/phase-6-learn.md +10 -17
  98. package/skills/build-loop/references/privileged-request-broker.md +254 -0
  99. package/skills/build-loop/references/resource-aware-execution.md +183 -0
  100. package/skills/build-loop/references/self-recursive-dev.md +2 -2
  101. package/skills/build-loop/references/status-output-format.md +207 -0
  102. package/skills/build-loop/references/verify-dispatch.md +56 -2
  103. package/skills/building-with-deepagents/SKILL.md +1 -1
  104. package/skills/claim-scope/SKILL.md +185 -0
  105. package/skills/color-engine/SKILL.md +103 -0
  106. package/skills/color-engine/_core.py +464 -0
  107. package/skills/color-engine/color_engine.py +175 -0
  108. package/skills/cost-rca/SKILL.md +61 -0
  109. package/skills/data-plane-worktrees/SKILL.md +139 -0
  110. package/skills/data-plane-worktrees/agents/openai.yaml +4 -0
  111. package/skills/database-practice/SKILL.md +200 -0
  112. package/skills/database-practice/references/diagnostic-queries.sql +126 -0
  113. package/skills/database-practice/references/vector-and-graph-tuning.md +208 -0
  114. package/skills/database-practice/scripts/db_table_map.py +1244 -0
  115. package/skills/database-practice/scripts/test_db_table_map.py +514 -0
  116. package/skills/debug-loop/SKILL.md +36 -6
  117. package/skills/debugging-memory/SKILL.md +32 -430
  118. package/skills/debugging-memory/references/pattern-extraction.md +4 -4
  119. package/skills/debugging-memory/references/search.md +32 -120
  120. package/skills/debugging-memory/references/store.md +32 -126
  121. package/skills/debugging-memory/references/subagent-integration.md +1 -1
  122. package/skills/decision-queue/SKILL.md +251 -0
  123. package/skills/decision-queue/assets/template.html +1242 -0
  124. package/skills/decision-queue/references/example-large-queue-batching.md +164 -0
  125. package/skills/decision-queue/scripts/regen_template_constants.py +160 -0
  126. package/skills/defenseclaw-bridge/SKILL.md +2 -2
  127. package/skills/defenseclaw-bridge/references/dc-config-mapping.md +2 -9
  128. package/skills/drain-proposals/SKILL.md +53 -0
  129. package/skills/focused-loop-builder/SKILL.md +31 -0
  130. package/skills/focused-loop-builder/references/spec-format.md +27 -0
  131. package/skills/handoff/SKILL.md +169 -8
  132. package/skills/ibr-bridge/SKILL.md +4 -1
  133. package/skills/knowledge/SKILL.md +26 -14
  134. package/skills/knowledge/references/review-mode.md +2 -3
  135. package/skills/knowledge/templates/madr-minimal.md +1 -1
  136. package/skills/mcp-builder/SKILL.md +1 -1
  137. package/skills/model-bakeoff/SKILL.md +48 -10
  138. package/skills/model-tiering/SKILL.md +92 -31
  139. package/skills/native-ax-driver/SKILL.md +38 -5
  140. package/skills/native-ax-driver/scripts/native_driver.py +278 -22
  141. package/skills/native-ax-driver/scripts/test_native_driver.py +227 -0
  142. package/skills/optimize/SKILL.md +1 -1
  143. package/skills/plugin-builder/SKILL.md +48 -1
  144. package/skills/plugin-builder/references/build-loop-phase-guidance.md +3 -4
  145. package/skills/plugin-builder/references/distribution.md +13 -2
  146. package/skills/plugin-builder/references/plugin-hygiene-lessons.md +2 -2
  147. package/skills/plugin-tests/SKILL.md +2 -2
  148. package/skills/recursive-retrospective/SKILL.md +1 -1
  149. package/skills/repo-closeout/SKILL.md +17 -0
  150. package/skills/repo-closeout/agents/openai.yaml +4 -0
  151. package/skills/repo-maintenance/SKILL.md +179 -0
  152. package/skills/repo-maintenance/agents/openai.yaml +4 -0
  153. package/skills/repo-maintenance/references/pre-public-hygiene.md +134 -0
  154. package/skills/repo-maintenance/references/repository-taxonomy.md +161 -0
  155. package/skills/repo-maintenance/references/safety-protocol.md +106 -0
  156. package/skills/repo-maintenance/references/stack-profiles.md +138 -0
  157. package/skills/repo-maintenance/scripts/audit_repo_maintenance.py +1198 -0
  158. package/skills/repo-maintenance/scripts/test_audit_repo_maintenance.py +506 -0
  159. package/skills/repository-intelligence/SKILL.md +189 -0
  160. package/skills/repository-intelligence/agents/openai.yaml +4 -0
  161. package/skills/repository-intelligence/references/assessment-rubric.md +88 -0
  162. package/skills/repository-intelligence/scripts/repository_inventory.py +347 -0
  163. package/skills/research/SKILL.md +12 -2
  164. package/skills/root-cause-analysis/SKILL.md +1 -1
  165. package/skills/runtime-parity-verification/SKILL.md +36 -1
  166. package/skills/security-methodology/SKILL.md +23 -10
  167. package/skills/security-methodology/references/agentic-handoff-templates.md +220 -0
  168. package/skills/security-methodology/references/cross-source-matrix.md +1 -1
  169. package/skills/security-methodology/references/owasp-agentic-top-10.md +1 -1
  170. package/skills/security-scan/SKILL.md +55 -15
  171. package/skills/self-improve/SKILL.md +70 -50
  172. package/skills/silent-assumptions/SKILL.md +341 -0
  173. package/skills/silent-assumptions/references/elicitation-detectors.md +342 -0
  174. package/skills/spec-writing/SKILL.md +128 -24
  175. package/skills/spec-writing/scripts/check_checklist.py +114 -15
  176. package/skills/ui-design/SKILL.md +6 -4
  177. package/skills/ui-design/references/color-engine.md +132 -0
  178. package/skills/ui-design/references/design-preferences-from-owned-apps.md +8 -8
  179. package/skills/ui-design/references/ui-guidance-sources.md +1 -1
  180. package/skills/ui-design/references/universal-design-principles.alt.md +2 -2
  181. package/plugin-artifacts/codex/.codex-plugin/plugin.json +0 -41
  182. package/plugin-artifacts/codex/AGENTS.md +0 -560
  183. package/plugin-artifacts/codex/BUILD-ARTIFACT.md +0 -5
  184. package/plugin-artifacts/codex/LICENSE +0 -202
  185. package/plugin-artifacts/codex/README.md +0 -313
  186. package/plugin-artifacts/codex/assets/build-loop-plugin-icon.png +0 -0
  187. package/plugin-artifacts/codex/docs/agent-surface-policy.md +0 -63
  188. package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +0 -62
  189. package/plugin-artifacts/codex/references/agent-role-taxonomy.md +0 -135
  190. package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +0 -161
  191. package/plugin-artifacts/codex/references/autonomy-config.md +0 -231
  192. package/plugin-artifacts/codex/references/backlog-system.md +0 -285
  193. package/plugin-artifacts/codex/references/capability-routing.md +0 -231
  194. package/plugin-artifacts/codex/references/codex-subagents.md +0 -106
  195. package/plugin-artifacts/codex/references/coordination-file-template.md +0 -181
  196. package/plugin-artifacts/codex/references/coordination-rules.md +0 -552
  197. package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +0 -112
  198. package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +0 -102
  199. package/plugin-artifacts/codex/references/implementer-envelope-schema.md +0 -302
  200. package/plugin-artifacts/codex/references/intent-capability-pack.md +0 -257
  201. package/plugin-artifacts/codex/references/intent-exploration-prompts.md +0 -96
  202. package/plugin-artifacts/codex/references/leadership.md +0 -72
  203. package/plugin-artifacts/codex/references/memory-systems.md +0 -261
  204. package/plugin-artifacts/codex/references/memory.md +0 -313
  205. package/plugin-artifacts/codex/references/model-tier-mapping.md +0 -296
  206. package/plugin-artifacts/codex/references/modular-systems-pack.md +0 -96
  207. package/plugin-artifacts/codex/references/phase-1-assess.md +0 -249
  208. package/plugin-artifacts/codex/references/phase-2-plan.md +0 -86
  209. package/plugin-artifacts/codex/references/phase-3-execute.md +0 -49
  210. package/plugin-artifacts/codex/references/phase-4-review.md +0 -341
  211. package/plugin-artifacts/codex/references/phase-5-iterate.md +0 -72
  212. package/plugin-artifacts/codex/references/phase-6-learn.md +0 -58
  213. package/plugin-artifacts/codex/references/recent-design-structures.md +0 -274
  214. package/plugin-artifacts/codex/references/research-trigger-policy.md +0 -140
  215. package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +0 -42
  216. package/plugin-artifacts/codex/references/self-review.md +0 -234
  217. package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +0 -90
  218. package/plugin-artifacts/codex/references/task-capture-policy.md +0 -68
  219. package/plugin-artifacts/codex/references/ui-io-contract.md +0 -116
  220. package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +0 -65
  221. package/plugin-artifacts/codex/references/verify-dispatch.md +0 -85
  222. package/plugin-artifacts/codex/skills/build-loop/SKILL.md +0 -381
  223. package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +0 -82
  224. package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +0 -65
  225. package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +0 -549
  226. package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +0 -42
  227. package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +0 -267
  228. package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +0 -62
  229. package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +0 -439
  230. package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +0 -161
  231. package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +0 -231
  232. package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +0 -106
  233. package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +0 -161
  234. package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +0 -177
  235. package/plugin-artifacts/codex/skills/build-loop/references/experiment-results-template.md +0 -101
  236. package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +0 -72
  237. package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +0 -257
  238. package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +0 -96
  239. package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +0 -72
  240. package/plugin-artifacts/codex/skills/build-loop/references/memory.md +0 -313
  241. package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +0 -96
  242. package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +0 -222
  243. package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +0 -98
  244. package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +0 -249
  245. package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +0 -86
  246. package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +0 -49
  247. package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +0 -341
  248. package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +0 -72
  249. package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +0 -58
  250. package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +0 -274
  251. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +0 -85
  252. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +0 -149
  253. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +0 -32
  254. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +0 -48
  255. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +0 -60
  256. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +0 -51
  257. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +0 -71
  258. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +0 -52
  259. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +0 -202
  260. package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +0 -77
  261. package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +0 -234
  262. package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +0 -116
  263. package/plugin-artifacts/codex/skills/build-loop/references/verify-dispatch.md +0 -85
  264. package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +0 -476
  265. package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +0 -239
  266. package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +0 -35
  267. package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +0 -100
  268. package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +0 -179
  269. package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +0 -40
  270. package/scripts/build_codex_plugin_artifact.py +0 -321
package/hooks/hooks.json CHANGED
@@ -7,57 +7,66 @@
7
7
  {
8
8
  "type": "command",
9
9
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-architecture.sh\" </dev/null >/dev/null 2>&1; exit 0",
10
- "timeout": 2000
10
+ "timeout": 2
11
11
  },
12
12
  {
13
13
  "type": "command",
14
14
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-retrieval.sh\" </dev/null >/dev/null 2>&1; exit 0",
15
- "timeout": 2000
15
+ "timeout": 2
16
16
  },
17
17
  {
18
18
  "type": "command",
19
- "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-rally-point.sh\" </dev/null 2>/dev/null; exit 0",
20
- "timeout": 2000
19
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-rally-point.sh\" 2>/dev/null; exit 0",
20
+ "timeout": 2
21
21
  },
22
22
  {
23
23
  "type": "command",
24
24
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-worktree-gc.sh\" </dev/null >/dev/null 2>&1; exit 0",
25
- "timeout": 2000
25
+ "timeout": 2
26
26
  },
27
27
  {
28
28
  "type": "command",
29
29
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-git-hooks.sh\" </dev/null >/dev/null 2>&1; exit 0",
30
- "timeout": 2000
30
+ "timeout": 2
31
31
  },
32
32
  {
33
33
  "type": "command",
34
34
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-plugin-drift.sh\" </dev/null >/dev/null 2>&1; exit 0",
35
- "timeout": 2000
35
+ "timeout": 2
36
36
  },
37
37
  {
38
38
  "type": "command",
39
39
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-plugin-heal.sh\" </dev/null >/dev/null 2>&1; exit 0",
40
- "timeout": 2000
40
+ "timeout": 2
41
41
  },
42
42
  {
43
43
  "type": "command",
44
44
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-memory.sh\" </dev/null >/dev/null 2>&1; exit 0",
45
- "timeout": 6000
45
+ "timeout": 6
46
46
  },
47
47
  {
48
48
  "type": "command",
49
49
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-closeout.sh\" </dev/null >/dev/null 2>&1; exit 0",
50
- "timeout": 3000
50
+ "timeout": 3
51
51
  },
52
52
  {
53
53
  "type": "command",
54
54
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/closeout.sh\" session-start </dev/null 2>/dev/null; exit 0",
55
- "timeout": 3000
55
+ "timeout": 3
56
56
  },
57
57
  {
58
58
  "type": "command",
59
59
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-extensions.sh\" </dev/null 2>/dev/null; exit 0",
60
- "timeout": 2000
60
+ "timeout": 2
61
+ }
62
+ ]
63
+ },
64
+ {
65
+ "hooks": [
66
+ {
67
+ "type": "command",
68
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-codex-hook-trust.sh\" </dev/null 2>/dev/null || printf '{}'",
69
+ "timeout": 5
61
70
  }
62
71
  ]
63
72
  }
@@ -69,7 +78,7 @@
69
78
  {
70
79
  "type": "command",
71
80
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/route-guard.sh\" prompt-submit 2>/dev/null || printf '{}'",
72
- "timeout": 3000
81
+ "timeout": 3
73
82
  }
74
83
  ]
75
84
  }
@@ -81,7 +90,7 @@
81
90
  {
82
91
  "type": "command",
83
92
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/route-guard.sh\" pre-skill 2>/dev/null || printf '{}'",
84
- "timeout": 3000
93
+ "timeout": 3
85
94
  }
86
95
  ]
87
96
  },
@@ -91,12 +100,12 @@
91
100
  {
92
101
  "type": "command",
93
102
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/pre-edit-architecture.sh\" >/dev/null 2>&1; exit 0",
94
- "timeout": 2000
103
+ "timeout": 2
95
104
  },
96
105
  {
97
106
  "type": "command",
98
107
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/pre-edit-rally-point.sh\"; exit 0",
99
- "timeout": 2000
108
+ "timeout": 2
100
109
  }
101
110
  ]
102
111
  },
@@ -106,12 +115,22 @@
106
115
  {
107
116
  "type": "command",
108
117
  "command": "root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; hook=\"$root/scripts/hooks/pre_bash_dispatch.sh\"; if [ -x \"$hook\" ]; then \"$hook\"; else printf '{}'; fi",
109
- "timeout": 9000
118
+ "timeout": 9
110
119
  },
111
120
  {
112
121
  "type": "command",
113
122
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/pre-edit-rally-point.sh\"; exit 0",
114
- "timeout": 2000
123
+ "timeout": 2
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ "matcher": "",
129
+ "hooks": [
130
+ {
131
+ "type": "command",
132
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" hook --phase start >/dev/null 2>&1 || true",
133
+ "timeout": 1
115
134
  }
116
135
  ]
117
136
  }
@@ -123,12 +142,22 @@
123
142
  {
124
143
  "type": "command",
125
144
  "command": "[ -f .build-loop/state.json ] || exit 0; python3 -c \"import json,sys; s=json.load(open('.build-loop/state.json')); p7=s.get('phases',{}).get('fact_check',{}).get('completed',False); active=s.get('active',False); sys.exit(0 if (not active or p7) else 1)\" 2>/dev/null && exit 0; echo \"$TOOL_INPUT\" | grep -qE '\\b(git\\s+push|npm\\s+publish|vercel\\s+deploy|gh\\s+release)\\b' && echo 'Build loop Phase 7 (fact-check) has not completed. Run fact-check before deploying.'; exit 0",
126
- "timeout": 3000
145
+ "timeout": 3
127
146
  },
128
147
  {
129
148
  "type": "command",
130
149
  "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/post-push-closeout.sh\" </dev/null >/dev/null 2>&1; exit 0",
131
- "timeout": 2000
150
+ "timeout": 2
151
+ }
152
+ ]
153
+ },
154
+ {
155
+ "matcher": "",
156
+ "hooks": [
157
+ {
158
+ "type": "command",
159
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" hook --phase end >/dev/null 2>&1 || true",
160
+ "timeout": 1
132
161
  }
133
162
  ]
134
163
  }
@@ -139,43 +168,71 @@
139
168
  "hooks": [
140
169
  {
141
170
  "type": "command",
142
- "command": "if [ -n \"$CLAUDE_TRANSCRIPT_PATH\" ]; then nohup python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/scan_transcript_for_decisions.py\" --workdir \"$CLAUDE_PROJECT_DIR\" --transcript \"$CLAUDE_TRANSCRIPT_PATH\" --log-file \"${XDG_STATE_HOME:-$HOME/.local/state}/build-loop/scan.log\" </dev/null >/dev/null 2>&1 & fi; printf '{}'",
143
- "timeout": 5000
171
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/state_finalize.py\" --workdir \"$CLAUDE_PROJECT_DIR\" --mark-incomplete-as-crashed </dev/null >/dev/null 2>&1; printf '{}'",
172
+ "timeout": 2
144
173
  },
145
174
  {
146
175
  "type": "command",
147
- "command": "if [ -n \"$CLAUDE_TRANSCRIPT_PATH\" ]; then root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; nohup env PYTHONPATH=\"$root/scripts\" python3 -m scan_corrections --workdir \"$CLAUDE_PROJECT_DIR\" --transcript \"$CLAUDE_TRANSCRIPT_PATH\" --source stop-hook </dev/null >/dev/null 2>&1 & fi; printf '{}'",
148
- "timeout": 5000
176
+ "command": "root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; hook=\"$root/scripts/hooks/stop_finalize.sh\"; if [ -x \"$hook\" ]; then \"$hook\"; else printf '{}'; fi",
177
+ "timeout": 30
149
178
  },
150
179
  {
151
180
  "type": "command",
152
- "command": "if [ -n \"$CLAUDE_TRANSCRIPT_PATH\" ]; then root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; nohup env PYTHONPATH=\"$root/scripts\" python3 -m scan_findings --workdir \"$CLAUDE_PROJECT_DIR\" --transcript \"$CLAUDE_TRANSCRIPT_PATH\" --log-file \"${XDG_STATE_HOME:-$HOME/.local/state}/build-loop/findings-scan.log\" </dev/null >/dev/null 2>&1 & fi; printf '{}'",
153
- "timeout": 5000
154
- },
181
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/closeout.sh\" stop 2>/dev/null; exit 0",
182
+ "timeout": 6
183
+ }
184
+ ]
185
+ },
186
+ {
187
+ "matcher": "",
188
+ "hooks": [
155
189
  {
156
190
  "type": "command",
157
- "command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/state_finalize.py\" --workdir \"$CLAUDE_PROJECT_DIR\" --mark-incomplete-as-crashed </dev/null >/dev/null 2>&1; printf '{}'",
158
- "timeout": 2000
159
- },
191
+ "command": "if [ -f \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/commit_state_check.py\" ]; then python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/commit_state_check.py\" --workdir \"${CLAUDE_PROJECT_DIR}\" --hook; else printf '{}'; fi",
192
+ "timeout": 5
193
+ }
194
+ ]
195
+ },
196
+ {
197
+ "matcher": "",
198
+ "hooks": [
160
199
  {
161
200
  "type": "command",
162
- "command": "root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; hook=\"$root/scripts/hooks/stop_finalize.sh\"; if [ -x \"$hook\" ]; then \"$hook\"; else printf '{}'; fi",
163
- "timeout": 30000
164
- },
201
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" ingest >/dev/null 2>&1 || true; printf '{}'",
202
+ "timeout": 5
203
+ }
204
+ ]
205
+ },
206
+ {
207
+ "hooks": [
165
208
  {
166
209
  "type": "command",
167
- "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/closeout.sh\" stop 2>/dev/null; exit 0",
168
- "timeout": 6000
210
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/stop-transcript-sweep.sh\" all 2>/dev/null || printf '{}'",
211
+ "timeout": 5
169
212
  }
170
213
  ]
171
- },
214
+ }
215
+ ],
216
+ "SessionEnd": [
172
217
  {
173
218
  "matcher": "",
174
219
  "hooks": [
175
220
  {
176
221
  "type": "command",
177
- "command": "if [ -f \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/commit_state_check.py\" ]; then python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/commit_state_check.py\" --workdir \"${CLAUDE_PROJECT_DIR}\" --hook; else printf '{}'; fi",
178
- "timeout": 5000
222
+ "command": "root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; s=\"$root/scripts/hooks/session_end_retro_sweep.py\"; tp=$(python3 -c 'import sys,json;print(json.load(sys.stdin).get(\"transcript_path\",\"\"))' 2>/dev/null); if [ -n \"$tp\" ] && [ -f \"$s\" ]; then nohup python3 \"$s\" \"$tp\" </dev/null >/dev/null 2>&1 & fi; exit 0",
223
+ "timeout": 5
224
+ }
225
+ ]
226
+ }
227
+ ],
228
+ "PostToolUseFailure": [
229
+ {
230
+ "matcher": "",
231
+ "hooks": [
232
+ {
233
+ "type": "command",
234
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" hook --phase error >/dev/null 2>&1 || true",
235
+ "timeout": 1
179
236
  }
180
237
  ]
181
238
  }
package/hooks/pre-commit CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/bin/sh
2
- # Public-repo hygiene pre-commit hook.
2
+ # Public-repo hygiene and independent-audit pre-commit hook.
3
3
  #
4
4
  # build-loop is open source. This hook blocks a commit that stages a
5
5
  # private app slug (see scripts/check_private_slugs.py for the editable
@@ -26,4 +26,23 @@ if [ -f "$RUNTIME_MEMORY_GUARD" ]; then
26
26
  fi
27
27
  # --- END private-slug-guard pre-commit ---
28
28
 
29
+ # --- BEGIN portability-guard pre-commit ---
30
+ # Blocks a commit that ships a maintainer-machine path to installed users.
31
+ # Runs from the repo (no secret config needed, unlike the slug guard), so
32
+ # there is no .git/hooks copy to desync. See scripts/check_portability.py.
33
+ PORTABILITY_GUARD="$RALLY_POINT_TOPLEVEL/scripts/check_portability.py"
34
+ if [ -f "$PORTABILITY_GUARD" ]; then
35
+ python3 "$PORTABILITY_GUARD" || exit 1
36
+ fi
37
+ # --- END portability-guard pre-commit ---
38
+
39
+ # --- BEGIN independent-audit pre-commit ---
40
+ # Covers manual, Codex, IDE, and other commit paths. The auditor blocks only
41
+ # deterministic integrity failures; its advisory packet remains visible.
42
+ INDEPENDENT_AUDIT="$RALLY_POINT_TOPLEVEL/scripts/audit_before_commit.py"
43
+ if [ -f "$INDEPENDENT_AUDIT" ]; then
44
+ python3 "$INDEPENDENT_AUDIT" || exit $?
45
+ fi
46
+ # --- END independent-audit pre-commit ---
47
+
29
48
  exit 0
@@ -34,8 +34,7 @@ PKG="$SCRIPT_DIR/../scripts/rally_point"
34
34
  # the payload is forwarded to Python via the environment.
35
35
  STDIN_JSON=""
36
36
  if [ ! -t 0 ]; then
37
- STDIN_JSON=$(cat 2>/dev/null || true)
38
- STDIN_JSON=$(printf '%s' "$STDIN_JSON" | head -c 65536)
37
+ STDIN_JSON=$(head -c 65536 2>/dev/null || true)
39
38
  fi
40
39
 
41
40
  # Extract file_path (Edit/Write) and command (Bash) from the event JSON.
@@ -44,6 +43,7 @@ fi
44
43
  # with NUL handling across portable awk/read.
45
44
  FILE_PATH=""
46
45
  TOOL_CMD=""
46
+ EVENT_SESSION_ID=""
47
47
  if [ -n "$STDIN_JSON" ]; then
48
48
  EXTRACTED=$(STDIN_JSON="$STDIN_JSON" python3 - <<'PYEOF' 2>/dev/null
49
49
  import json, os, sys
@@ -55,22 +55,27 @@ except (ValueError, TypeError):
55
55
  ti = (d.get("tool_input") or {}) if isinstance(d.get("tool_input"), dict) else {}
56
56
  fp = ti.get("file_path") or ti.get("path") or ti.get("filename") or ""
57
57
  cmd = ti.get("command") or ""
58
+ session_id = d.get("session_id") or ""
58
59
  # Emit fp as base64 (single line, no newlines), then cmd as base64. The
59
60
  # bash side decodes; this avoids embedded-newline parsing entirely.
60
61
  import base64
61
62
  b64 = lambda s: base64.b64encode(s.encode("utf-8", "replace")).decode("ascii") if s else ""
62
- sys.stdout.write(b64(fp) + "\n" + b64(cmd) + "\n")
63
+ sys.stdout.write(b64(fp) + "\n" + b64(cmd) + "\n" + b64(session_id) + "\n")
63
64
  PYEOF
64
65
  )
65
66
  if [ -n "$EXTRACTED" ]; then
66
67
  FILE_PATH_B64=$(printf '%s\n' "$EXTRACTED" | sed -n '1p')
67
68
  TOOL_CMD_B64=$(printf '%s\n' "$EXTRACTED" | sed -n '2p')
69
+ EVENT_SESSION_ID_B64=$(printf '%s\n' "$EXTRACTED" | sed -n '3p')
68
70
  if [ -n "$FILE_PATH_B64" ]; then
69
71
  FILE_PATH=$(printf '%s' "$FILE_PATH_B64" | base64 --decode 2>/dev/null || true)
70
72
  fi
71
73
  if [ -n "$TOOL_CMD_B64" ]; then
72
74
  TOOL_CMD=$(printf '%s' "$TOOL_CMD_B64" | base64 --decode 2>/dev/null || true)
73
75
  fi
76
+ if [ -n "$EVENT_SESSION_ID_B64" ]; then
77
+ EVENT_SESSION_ID=$(printf '%s' "$EVENT_SESSION_ID_B64" | base64 --decode 2>/dev/null || true)
78
+ fi
74
79
  fi
75
80
  fi
76
81
 
@@ -83,9 +88,11 @@ fi
83
88
  # without polluting the terminal by default.
84
89
  if [ "${BUILD_LOOP_RALLY_DEBUG:-0}" = "1" ]; then
85
90
  python3 "$PKG/hooks.py" pre-edit --workdir "$WORKDIR" --tool claude_code \
91
+ --session-id "$EVENT_SESSION_ID" \
86
92
  --file-path "$FILE_PATH" --command "$TOOL_CMD" || exit 0
87
93
  else
88
94
  python3 "$PKG/hooks.py" pre-edit --workdir "$WORKDIR" --tool claude_code \
95
+ --session-id "$EVENT_SESSION_ID" \
89
96
  --file-path "$FILE_PATH" --command "$TOOL_CMD" 2>/dev/null || exit 0
90
97
  fi
91
98
 
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env bash
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ # Report Codex hooks that are registered but never trusted, so they cannot
4
+ # silently never run. Advisory: emits context only when there IS a gap, and
5
+ # always exits 0.
6
+ #
7
+ # WHY: Codex records hook trust in ~/.codex/config.toml keyed by ORDINAL
8
+ # POSITION. Nothing compared it to .codex/hooks.json, so on 2026-08-23 a sweep
9
+ # found 28 of 46 registered hooks across 10 repos had never been trusted --
10
+ # including one that had shipped in git 9 days earlier.
11
+ set +e
12
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-$PWD}}"
13
+ WORKDIR="${CLAUDE_PROJECT_DIR:-$PWD}"
14
+ CHECK="${PLUGIN_ROOT}/scripts/codex_hook_trust_check.py"
15
+
16
+ [ -f "$CHECK" ] || { printf '{}'; exit 0; }
17
+ [ -f "${WORKDIR}/.codex/hooks.json" ] || { printf '{}'; exit 0; }
18
+ command -v python3 >/dev/null 2>&1 || { printf '{}'; exit 0; }
19
+
20
+ REPORT="$(python3 "$CHECK" --workdir "$WORKDIR" 2>/dev/null)"
21
+ [ -n "$REPORT" ] || { printf '{}'; exit 0; }
22
+
23
+ REPORT="$REPORT" python3 -c '
24
+ import json, os
25
+ print(json.dumps({"hookSpecificOutput": {
26
+ "hookEventName": "SessionStart",
27
+ "additionalContext": os.environ.get("REPORT", ""),
28
+ }}))
29
+ ' 2>/dev/null || printf '{}'
30
+ exit 0
@@ -5,7 +5,8 @@
5
5
  # in one hook body — the test gate added per the 2026-06-29 RCA so new sessions get
6
6
  # the prevent-before-merge control automatically) + the artifact-guard pre-commit segment
7
7
  # (regenerate-and-restage checked-in artifacts; block undeclared third-party
8
- # imports — chained so it coexists with the rally-point private-slug segment).
8
+ # imports — chained so it coexists with the Rally Point hygiene and independent
9
+ # commit-audit segment).
9
10
  # Skips silently when: not inside a git repo, Python unavailable, hook
10
11
  # source not found, or a foreign (non-build-loop) pre-push is already
11
12
  # installed (requires --force to overwrite; we never force on auto-install).
@@ -14,4 +15,5 @@ cd "${CLAUDE_PROJECT_DIR:-$PWD}" 2>/dev/null || exit 0
14
15
  git rev-parse --git-dir >/dev/null 2>&1 || exit 0
15
16
  python3 "${PLUGIN_ROOT}/scripts/install_git_hooks.py" --install >/dev/null 2>&1 || true
16
17
  python3 "${PLUGIN_ROOT}/scripts/artifact_guard.py" --install-hook >/dev/null 2>&1 || true
18
+ python3 "${PLUGIN_ROOT}/scripts/rally_point/install_git_hook.py" --repo "$PWD" >/dev/null 2>&1 || true
17
19
  exit 0
@@ -15,6 +15,36 @@ W="${CLAUDE_PROJECT_DIR:-$PWD}"
15
15
  PKG="$(dirname "$D")/scripts/rally_point"
16
16
  [ -d "$PKG" ] || exit 0
17
17
 
18
+ # Claude's hook event is the authoritative session identity. Do not depend on
19
+ # CLAUDE_SESSION_ID being exported: plugin hooks receive the same session_id on
20
+ # stdin at SessionStart, PreToolUse, and Stop. The shared Python resolver keeps
21
+ # explicit/event, environment, and process fallbacks identical for every path.
22
+ STDIN_JSON=""
23
+ if [ ! -t 0 ]; then
24
+ STDIN_JSON=$(head -c 65536 2>/dev/null || true)
25
+ fi
26
+ EVENT_SESSION_ID=""
27
+ if [ -n "$STDIN_JSON" ]; then
28
+ EVENT_SESSION_ID=$(STDIN_JSON="$STDIN_JSON" python3 - <<'PYEOF' 2>/dev/null
29
+ import json, os
30
+ try:
31
+ event = json.loads(os.environ.get("STDIN_JSON") or "{}")
32
+ except (TypeError, ValueError):
33
+ event = {}
34
+ value = event.get("session_id") if isinstance(event, dict) else ""
35
+ print(str(value or "").replace("\n", " ").replace("\t", " "), end="")
36
+ PYEOF
37
+ ) || EVENT_SESSION_ID=""
38
+ fi
39
+ RALLY_HOOK_SESSION_ID=""
40
+ if [ -f "$PKG/actor_identity.py" ]; then
41
+ RALLY_HOOK_SESSION_ID=$(RALLY_OBSERVER_PID="${PPID:-0}" \
42
+ python3 "$PKG/actor_identity.py" --tool claude_code \
43
+ --session-id "$EVENT_SESSION_ID" --field session-id 2>/dev/null || true)
44
+ fi
45
+ [ -n "$RALLY_HOOK_SESSION_ID" ] || \
46
+ RALLY_HOOK_SESSION_ID="${EVENT_SESSION_ID:-${BUILD_LOOP_RALLY_SESSION_ID:-${CLAUDE_SESSION_ID:-${RALLY_AGENT_ID:-${RALLY_SESSION_ID:-claude-${PPID}}}}}}"
47
+
18
48
  # Guard: if CLAUDE_PROJECT_DIR is unset and $PWD is not a git repo, the
19
49
  # launch cwd is not a rally room — defer the join to pre-edit (operative
20
50
  # repo resolution from the first Edit/Write/Bash). This is the no-op path.
@@ -27,15 +57,19 @@ fi
27
57
  # Step 1: checkpoint_read restore line (verbose: surface delta if any).
28
58
  # ``session-start-safe`` no-ops cleanly when the resolved workdir is not a
29
59
  # git repo (belt-and-braces — the shell guard above already filters).
30
- python3 "$PKG/hooks.py" session-start-safe --workdir "$W" --verbose 2>/dev/null || true
60
+ python3 "$PKG/hooks.py" session-start-safe --workdir "$W" --verbose \
61
+ --tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" 2>/dev/null || true
31
62
 
32
63
  # Step 2: probe announce + listen (fully detached watcher).
33
64
  if [ "${BUILD_LOOP_RALLY_POINT_SKIP_WATCH:-}" = "1" ]; then
34
65
  [ -f "$PKG/session_probe.py" ] && WORKDIR="$W" python3 "$PKG/session_probe.py" \
35
- --workdir "$W" --tool claude_code --mode hook >/dev/null 2>&1 || true
66
+ --workdir "$W" --tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" \
67
+ --mode hook >/dev/null 2>&1 || true
36
68
  else
37
69
  [ -f "$PKG/session_probe.py" ] && WORKDIR="$W" python3 "$PKG/session_probe.py" \
38
- --workdir "$W" --tool claude_code --mode hook --start-watch >/dev/null 2>&1 || true
70
+ --workdir "$W" --tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" \
71
+ --mode hook --start-watch \
72
+ --watch-parent-pid "${PPID}" >/dev/null 2>&1 || true
39
73
  fi
40
74
 
41
75
  # Step 3: opportunistic reaper sweep — physical cleanup of over-TTL presence/claims/lead.
@@ -43,7 +77,8 @@ fi
43
77
  [ -f "$PKG/reaper.py" ] && python3 "$PKG/reaper.py" --workdir "$W" --apply >/dev/null 2>&1 || true
44
78
 
45
79
  # Step 4: advance cursor past probe's own writes (silent; same script, no VERBOSE).
46
- python3 "$PKG/hooks.py" session-start-advance --workdir "$W" 2>/dev/null || true
80
+ python3 "$PKG/hooks.py" session-start-advance --workdir "$W" \
81
+ --tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" 2>/dev/null || true
47
82
 
48
83
  # Step 5: on-PATH-vs-pin rally version staleness guard (lane E-a). This is
49
84
  # the control that would have caught the rally version-mismatch incident:
@@ -63,4 +98,17 @@ if command -v rally >/dev/null 2>&1; then
63
98
  fi
64
99
  fi
65
100
 
101
+ # Step 6: peer-on-same-workdir commit-collision WARN (lane EC-03 rca). Advisory +
102
+ # fail-open: warns (never blocks) when a peer session is active on THIS workdir —
103
+ # the precondition for the concurrent-write race (two writers on one checkout race
104
+ # on HEAD/index; commits land on the wrong branch). On any error this silently
105
+ # no-ops and NEVER affects the hook's exit code.
106
+ [ -f "$PKG/peer_collision.py" ] && python3 "$PKG/peer_collision.py" --workdir "$W" 1>/dev/null || true
107
+
108
+ # Step 7: orphan/stale-session NOTICE (lane EC-04 coord — notify half). Advisory +
109
+ # fail-open + READ-ONLY: a dry-run count of over-TTL sessions surfaced as a WARN.
110
+ # It never reaps (Step 3 already does that capability-gated); it only tells the
111
+ # human cleanup is pending. Prints only to stderr; exit 0 preserved.
112
+ [ -f "$PKG/orphan_notice.py" ] && python3 "$PKG/orphan_notice.py" --workdir "$W" 1>/dev/null || true
113
+
66
114
  exit 0
@@ -1,105 +1,58 @@
1
1
  #!/usr/bin/env bash
2
2
  # SPDX-License-Identifier: Apache-2.0
3
- # Worktree GC: remove merged+clean stale worktrees/branches, AUTO-PRUNE orphans.
4
- # ACT mode (bundle-first removal of merged worktrees + branches) is ON by default
5
- # so cross-run residue self-heals (intent.md A5); set BUILDLOOP_GC_ACT=0 to opt out
6
- # (report-only). Locked, dirty, or unmerged worktrees are never removed either way.
7
- cd "${CLAUDE_PROJECT_DIR:-$PWD}" 2>/dev/null || exit 0
8
- git rev-parse --git-dir >/dev/null 2>&1 || exit 0
9
- R=".build-loop/worktree-gc-last.txt"
10
- mkdir -p "$(dirname "$R")"
11
- _bundle_done=0
3
+ # SessionStart worktree report. This hook never mutates Git.
4
+ #
5
+ # Destructive finalization requires a direct collapse_run/reaper invocation with
6
+ # explicit owner release. BUILDLOOP_GC_ACT is intentionally ignored: Stop is a
7
+ # turn boundary, and SessionStart cannot prove the prior terminal process exited.
12
8
 
13
- # Rally exclusion (defense-in-depth, optional). If `rally` is on PATH and
14
- # `rally sessions --json` returns a list of live sessions, collect their
15
- # `cwd` paths so we can skip any worktree owned by an active session in
16
- # addition to the path-prefix guard below. Rally owns its own worktree
17
- # lifecycle; build-loop's GC must never reap a rally-owned worktree (force-
18
- # removing it deletes the cwd of a live agent process and every subsequent
19
- # hook fails with posix_spawn ENOENT). The path-prefix exclusion is the
20
- # PRIMARY guard and works even when `rally` is not installed.
21
- _rally_cwds=""
22
- if command -v rally >/dev/null 2>&1; then
23
- _rally_cwds=$(rally sessions --json 2>/dev/null \
24
- | awk 'match($0, /"cwd"[[:space:]]*:[[:space:]]*"[^"]+"/){
25
- s=substr($0,RSTART,RLENGTH);
26
- sub(/^"cwd"[[:space:]]*:[[:space:]]*"/,"",s);
27
- sub(/"$/,"",s);
28
- print s
29
- }' 2>/dev/null || true)
30
- fi
9
+ set -u
31
10
 
32
- {
33
- printf '# Worktree GC report — %s\n\n## Stale candidates (REPORT-ONLY)\n' "$(date -u +%FT%TZ)"
11
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
12
+ cd "$PROJECT_DIR" 2>/dev/null || exit 0
13
+ git rev-parse --git-dir >/dev/null 2>&1 || exit 0
34
14
 
35
- # Collect candidates; in ACT mode, acted-on items are echoed inline (ACT:removed)
36
- # and split into their own report section by the awk pass below.
37
- git worktree list --porcelain 2>/dev/null \
38
- | awk '/^worktree /{p=$2} /^branch /{b=$2; sub("refs/heads/","",b); if(p && b){print p" "b}; p=""; b=""}' \
39
- | while read -r path branch; do
40
- [ "$branch" = main ] && continue
41
- # Rally-owned worktrees are NEVER touched by build-loop's GC.
42
- # Primary guard: path-prefix exclusion (works without rally on PATH).
43
- case "$path" in
44
- */.rally/worktrees/*)
45
- echo " SKIP:rally-owned $path branch=$branch"
46
- continue
47
- ;;
48
- esac
49
- # Defense-in-depth: live rally session cwd cross-check.
50
- if [ -n "$_rally_cwds" ]; then
51
- _skip=0
52
- while IFS= read -r _cwd; do
53
- [ -z "$_cwd" ] && continue
54
- if [ "$_cwd" = "$path" ]; then
55
- _skip=1
56
- break
57
- fi
58
- done <<EOF
59
- $_rally_cwds
60
- EOF
61
- if [ "$_skip" = "1" ]; then
62
- echo " SKIP:rally-live-session $path branch=$branch"
63
- continue
64
- fi
65
- fi
66
- git merge-base --is-ancestor "$branch" main 2>/dev/null || continue
67
- dirty=$(git -C "$path" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
68
- locked=unlocked
69
- [ -f "$path/.git" ] && grep -q locked "$path/.git" 2>/dev/null && locked=locked
70
- echo " $path branch=$branch merged=yes dirty=$dirty $locked"
15
+ REPORT=".build-loop/worktree-gc-last.txt"
16
+ REPORT_DIR=".build-loop/worktree-gc"
17
+ mkdir -p "$(dirname "$REPORT")" "$REPORT_DIR"
71
18
 
72
- if [ "${BUILDLOOP_GC_ACT:-1}" = "1" ] && [ "$dirty" = "0" ] && [ "$locked" = "unlocked" ]; then
73
- # Reversibility: one bundle per run, created before first removal.
74
- if [ "$_bundle_done" = "0" ]; then
75
- mkdir -p ".build-loop/bundles"
76
- git bundle create ".build-loop/bundles/gc-$(date -u +%Y%m%dT%H%M%SZ).bundle" --all >/dev/null 2>&1
77
- _bundle_done=1
78
- fi
79
- git worktree remove -f -f "$path" >/dev/null 2>&1
80
- git branch -D "$branch" >/dev/null 2>&1
81
- echo " ACT:removed $path branch=$branch"
82
- fi
83
- done
19
+ HOOK_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
20
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$HOOK_DIR/.." 2>/dev/null && pwd)}"
21
+ REAPER="$PLUGIN_ROOT/scripts/worktree_reaper/__main__.py"
22
+ _py=""
23
+ if [ -f "$HOOK_DIR/_resolve_python.sh" ]; then
24
+ # shellcheck source=hooks/_resolve_python.sh
25
+ . "$HOOK_DIR/_resolve_python.sh"
26
+ fi
84
27
 
85
- printf '\n## Auto-prune (Git-proven orphans only)\n'
86
- git worktree prune -v 2>/dev/null
87
- } > "$R" 2>&1
28
+ stamp="$(date -u +%Y%m%dT%H%M%SZ)"
29
+ tmp="${REPORT}.tmp.$$"
30
+ json_tmp="${REPORT_DIR}/${stamp}-$$.json"
31
+ err_tmp="${REPORT_DIR}/${stamp}-$$.stderr"
88
32
 
89
- # Rewrite report to split REPORT-ONLY from Auto-removed sections cleanly.
90
- if [ "${BUILDLOOP_GC_ACT:-1}" = "1" ] && grep -q 'ACT:removed' "$R" 2>/dev/null; then
91
- tmp=$(mktemp)
92
- awk '
93
- /^## Stale candidates/ { in_stale=1 }
94
- in_stale && / ACT:removed / {
95
- sub(" ACT:removed ", " ")
96
- if (!printed_hdr) { removed=removed "\n## Auto-removed (merged, bundled)\n"; printed_hdr=1 }
97
- removed=removed $0 "\n"
98
- next
99
- }
100
- { print }
101
- END { printf "%s", removed }
102
- ' "$R" > "$tmp" && mv "$tmp" "$R"
33
+ if [ -n "$_py" ] && [ -f "$REAPER" ]; then
34
+ "$_py" "$REAPER" --workdir "$PWD" --dry-run --json >"$json_tmp" 2>"$err_tmp"
35
+ rc=$?
36
+ else
37
+ rc=127
38
+ : >"$json_tmp"
39
+ printf '%s\n' "worktree reporter unavailable (python or reaper missing)" >"$err_tmp"
103
40
  fi
104
41
 
42
+ {
43
+ printf '# Worktree report — %s\n\n' "$(date -u +%FT%TZ)"
44
+ printf 'Mode: REPORT-ONLY (SessionStart never owns terminal release)\n'
45
+ if [ "${BUILDLOOP_GC_ACT:-0}" = "1" ]; then
46
+ printf 'Notice: BUILDLOOP_GC_ACT=1 ignored; use an explicit owner-released finalizer call.\n'
47
+ fi
48
+ printf 'Exit: %s\n\n' "$rc"
49
+ printf '## Summary\n\n'
50
+ cat "$err_tmp"
51
+ printf '\n## JSON\n\n```json\n'
52
+ cat "$json_tmp"
53
+ printf '\n```\n'
54
+ } >"$tmp" 2>/dev/null
55
+
56
+ mv "$tmp" "$REPORT" 2>/dev/null || true
57
+ rm -f "$err_tmp"
105
58
  exit 0