@tyroneross/build-loop 0.30.3

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 (389) hide show
  1. package/.agents/plugins/marketplace.json +10 -0
  2. package/.claude-plugin/marketplace.json +38 -0
  3. package/.claude-plugin/plugin.json +30 -0
  4. package/.codex-plugin/plugin.json +41 -0
  5. package/.cursor/rules/build-loop-surface.mdc +22 -0
  6. package/AGENTS.md +498 -0
  7. package/LICENSE +202 -0
  8. package/README.md +403 -0
  9. package/agents/alignment-checker.md +124 -0
  10. package/agents/api-assessor.md +136 -0
  11. package/agents/architecture-scout.md +185 -0
  12. package/agents/assessment-orchestrator.md +163 -0
  13. package/agents/build-orchestrator.md +198 -0
  14. package/agents/database-assessor.md +133 -0
  15. package/agents/design-contract-specialist.md +239 -0
  16. package/agents/fact-checker.md +69 -0
  17. package/agents/fix-critique.md +161 -0
  18. package/agents/frontend-assessor.md +136 -0
  19. package/agents/implementer.md +185 -0
  20. package/agents/independent-auditor.md +143 -0
  21. package/agents/mock-scanner.md +78 -0
  22. package/agents/optimize-runner.md +112 -0
  23. package/agents/overfitting-reviewer.md +96 -0
  24. package/agents/performance-assessor.md +159 -0
  25. package/agents/plan-critic.md +85 -0
  26. package/agents/promotion-reviewer.md +121 -0
  27. package/agents/recurring-pattern-detector.md +248 -0
  28. package/agents/retrospective-synthesizer.md +109 -0
  29. package/agents/root-cause-investigator.md +285 -0
  30. package/agents/scope-auditor.md +121 -0
  31. package/agents/security-reviewer.md +151 -0
  32. package/agents/self-improvement-architect.md +125 -0
  33. package/agents/synthesis-critic.md +99 -0
  34. package/agents/transcript-pattern-miner.md +165 -0
  35. package/agents/ui-validator.md +193 -0
  36. package/codex-skills/build-loop/SKILL.md +20 -0
  37. package/codex-skills/debug-loop/SKILL.md +18 -0
  38. package/codex-skills/handoff/SKILL.md +22 -0
  39. package/codex-skills/knowledge/SKILL.md +21 -0
  40. package/codex-skills/optimize/SKILL.md +18 -0
  41. package/codex-skills/research/SKILL.md +18 -0
  42. package/commands/agent-rally-point.md +301 -0
  43. package/commands/assess.md +41 -0
  44. package/commands/debug.md +20 -0
  45. package/commands/debugger-detail.md +34 -0
  46. package/commands/debugger-scan.md +15 -0
  47. package/commands/debugger-status.md +20 -0
  48. package/commands/debugger.md +32 -0
  49. package/commands/handoff.md +113 -0
  50. package/commands/knowledge-review.md +16 -0
  51. package/commands/optimize.md +31 -0
  52. package/commands/plan-verify.md +39 -0
  53. package/commands/promote-experiment.md +129 -0
  54. package/commands/research.md +22 -0
  55. package/commands/run.md +12 -0
  56. package/commands/self-review.md +51 -0
  57. package/commands/start-prd.md +57 -0
  58. package/commands/test.md +34 -0
  59. package/dist/src/assessment-orchestrator.d.ts +78 -0
  60. package/dist/src/assessment-orchestrator.d.ts.map +1 -0
  61. package/dist/src/assessment-orchestrator.js +304 -0
  62. package/dist/src/assessment-orchestrator.js.map +1 -0
  63. package/dist/src/audit-miner.d.ts +21 -0
  64. package/dist/src/audit-miner.d.ts.map +1 -0
  65. package/dist/src/audit-miner.js +421 -0
  66. package/dist/src/audit-miner.js.map +1 -0
  67. package/dist/src/batch-operations.d.ts +30 -0
  68. package/dist/src/batch-operations.d.ts.map +1 -0
  69. package/dist/src/batch-operations.js +339 -0
  70. package/dist/src/batch-operations.js.map +1 -0
  71. package/dist/src/config.d.ts +83 -0
  72. package/dist/src/config.d.ts.map +1 -0
  73. package/dist/src/config.js +176 -0
  74. package/dist/src/config.js.map +1 -0
  75. package/dist/src/context-engine.d.ts +45 -0
  76. package/dist/src/context-engine.d.ts.map +1 -0
  77. package/dist/src/context-engine.js +135 -0
  78. package/dist/src/context-engine.js.map +1 -0
  79. package/dist/src/debug-wrapper.d.ts +58 -0
  80. package/dist/src/debug-wrapper.d.ts.map +1 -0
  81. package/dist/src/debug-wrapper.js +285 -0
  82. package/dist/src/debug-wrapper.js.map +1 -0
  83. package/dist/src/index.d.ts +31 -0
  84. package/dist/src/index.d.ts.map +1 -0
  85. package/dist/src/index.js +149 -0
  86. package/dist/src/index.js.map +1 -0
  87. package/dist/src/interactive-verifier.d.ts +26 -0
  88. package/dist/src/interactive-verifier.d.ts.map +1 -0
  89. package/dist/src/interactive-verifier.js +435 -0
  90. package/dist/src/interactive-verifier.js.map +1 -0
  91. package/dist/src/lessons.d.ts +59 -0
  92. package/dist/src/lessons.d.ts.map +1 -0
  93. package/dist/src/lessons.js +172 -0
  94. package/dist/src/lessons.js.map +1 -0
  95. package/dist/src/log-reader.d.ts +39 -0
  96. package/dist/src/log-reader.d.ts.map +1 -0
  97. package/dist/src/log-reader.js +291 -0
  98. package/dist/src/log-reader.js.map +1 -0
  99. package/dist/src/logger.d.ts +59 -0
  100. package/dist/src/logger.d.ts.map +1 -0
  101. package/dist/src/logger.js +328 -0
  102. package/dist/src/logger.js.map +1 -0
  103. package/dist/src/parallel-retrieval.d.ts +52 -0
  104. package/dist/src/parallel-retrieval.d.ts.map +1 -0
  105. package/dist/src/parallel-retrieval.js +309 -0
  106. package/dist/src/parallel-retrieval.js.map +1 -0
  107. package/dist/src/pattern-extractor.d.ts +30 -0
  108. package/dist/src/pattern-extractor.d.ts.map +1 -0
  109. package/dist/src/pattern-extractor.js +386 -0
  110. package/dist/src/pattern-extractor.js.map +1 -0
  111. package/dist/src/result-aggregator.d.ts +44 -0
  112. package/dist/src/result-aggregator.d.ts.map +1 -0
  113. package/dist/src/result-aggregator.js +315 -0
  114. package/dist/src/result-aggregator.js.map +1 -0
  115. package/dist/src/retrieval.d.ts +139 -0
  116. package/dist/src/retrieval.d.ts.map +1 -0
  117. package/dist/src/retrieval.js +724 -0
  118. package/dist/src/retrieval.js.map +1 -0
  119. package/dist/src/setup/auto-setup.d.ts +15 -0
  120. package/dist/src/setup/auto-setup.d.ts.map +1 -0
  121. package/dist/src/setup/auto-setup.js +157 -0
  122. package/dist/src/setup/auto-setup.js.map +1 -0
  123. package/dist/src/setup/configure-hooks.d.ts +8 -0
  124. package/dist/src/setup/configure-hooks.d.ts.map +1 -0
  125. package/dist/src/setup/configure-hooks.js +16 -0
  126. package/dist/src/setup/configure-hooks.js.map +1 -0
  127. package/dist/src/setup/create-slash-commands.d.ts +8 -0
  128. package/dist/src/setup/create-slash-commands.d.ts.map +1 -0
  129. package/dist/src/setup/create-slash-commands.js +101 -0
  130. package/dist/src/setup/create-slash-commands.js.map +1 -0
  131. package/dist/src/setup/index.d.ts +8 -0
  132. package/dist/src/setup/index.d.ts.map +1 -0
  133. package/dist/src/setup/index.js +17 -0
  134. package/dist/src/setup/index.js.map +1 -0
  135. package/dist/src/setup/inject-claude-md.d.ts +10 -0
  136. package/dist/src/setup/inject-claude-md.d.ts.map +1 -0
  137. package/dist/src/setup/inject-claude-md.js +150 -0
  138. package/dist/src/setup/inject-claude-md.js.map +1 -0
  139. package/dist/src/setup/uninstall.d.ts +22 -0
  140. package/dist/src/setup/uninstall.d.ts.map +1 -0
  141. package/dist/src/setup/uninstall.js +235 -0
  142. package/dist/src/setup/uninstall.js.map +1 -0
  143. package/dist/src/storage.d.ts +192 -0
  144. package/dist/src/storage.d.ts.map +1 -0
  145. package/dist/src/storage.js +1037 -0
  146. package/dist/src/storage.js.map +1 -0
  147. package/dist/src/string-similarity.d.ts +8 -0
  148. package/dist/src/string-similarity.d.ts.map +1 -0
  149. package/dist/src/string-similarity.js +57 -0
  150. package/dist/src/string-similarity.js.map +1 -0
  151. package/dist/src/traces/adapters/browser.d.ts +69 -0
  152. package/dist/src/traces/adapters/browser.d.ts.map +1 -0
  153. package/dist/src/traces/adapters/browser.js +280 -0
  154. package/dist/src/traces/adapters/browser.js.map +1 -0
  155. package/dist/src/traces/adapters/index.d.ts +23 -0
  156. package/dist/src/traces/adapters/index.d.ts.map +1 -0
  157. package/dist/src/traces/adapters/index.js +67 -0
  158. package/dist/src/traces/adapters/index.js.map +1 -0
  159. package/dist/src/traces/adapters/langchain.d.ts +42 -0
  160. package/dist/src/traces/adapters/langchain.d.ts.map +1 -0
  161. package/dist/src/traces/adapters/langchain.js +151 -0
  162. package/dist/src/traces/adapters/langchain.js.map +1 -0
  163. package/dist/src/traces/adapters/opentelemetry.d.ts +46 -0
  164. package/dist/src/traces/adapters/opentelemetry.d.ts.map +1 -0
  165. package/dist/src/traces/adapters/opentelemetry.js +164 -0
  166. package/dist/src/traces/adapters/opentelemetry.js.map +1 -0
  167. package/dist/src/traces/adapters/sentry.d.ts +58 -0
  168. package/dist/src/traces/adapters/sentry.d.ts.map +1 -0
  169. package/dist/src/traces/adapters/sentry.js +212 -0
  170. package/dist/src/traces/adapters/sentry.js.map +1 -0
  171. package/dist/src/traces/index.d.ts +10 -0
  172. package/dist/src/traces/index.d.ts.map +1 -0
  173. package/dist/src/traces/index.js +45 -0
  174. package/dist/src/traces/index.js.map +1 -0
  175. package/dist/src/traces/storage.d.ts +78 -0
  176. package/dist/src/traces/storage.d.ts.map +1 -0
  177. package/dist/src/traces/storage.js +399 -0
  178. package/dist/src/traces/storage.js.map +1 -0
  179. package/dist/src/traces/summarizer.d.ts +83 -0
  180. package/dist/src/traces/summarizer.d.ts.map +1 -0
  181. package/dist/src/traces/summarizer.js +247 -0
  182. package/dist/src/traces/summarizer.js.map +1 -0
  183. package/dist/src/traces/types.d.ts +365 -0
  184. package/dist/src/traces/types.d.ts.map +1 -0
  185. package/dist/src/traces/types.js +14 -0
  186. package/dist/src/traces/types.js.map +1 -0
  187. package/dist/src/types.d.ts +495 -0
  188. package/dist/src/types.d.ts.map +1 -0
  189. package/dist/src/types.js +27 -0
  190. package/dist/src/types.js.map +1 -0
  191. package/docs/agent-surface-policy.md +45 -0
  192. package/docs/memory-setup.md +226 -0
  193. package/hooks/_arch_scan_bg.py +88 -0
  194. package/hooks/_plugin_drift_check_bg.py +85 -0
  195. package/hooks/_session_start_lib.sh +42 -0
  196. package/hooks/git/pre-push +141 -0
  197. package/hooks/hooks.json +126 -0
  198. package/hooks/post-commit +30 -0
  199. package/hooks/pre-commit +29 -0
  200. package/hooks/pre-edit-apppulse.sh +6 -0
  201. package/hooks/pre-edit-architecture.sh +106 -0
  202. package/hooks/pre-edit-rally-point.sh +92 -0
  203. package/hooks/session-start-apppulse.sh +6 -0
  204. package/hooks/session-start-architecture.sh +10 -0
  205. package/hooks/session-start-git-hooks.sh +12 -0
  206. package/hooks/session-start-plugin-drift.sh +27 -0
  207. package/hooks/session-start-rally-point.sh +44 -0
  208. package/hooks/session-start-retrieval.sh +24 -0
  209. package/hooks/session-start-worktree-gc.sh +105 -0
  210. package/hooks/test_apppulse_hooks.sh +6 -0
  211. package/hooks/test_rally_point_hooks.sh +388 -0
  212. package/hooks/test_sec008_hooks.sh +66 -0
  213. package/package.json +111 -0
  214. package/scripts/README.md +301 -0
  215. package/scripts/_db_url.py +61 -0
  216. package/scripts/_paths.py +445 -0
  217. package/scripts/blm.py +162 -0
  218. package/scripts/blm_api.py +263 -0
  219. package/scripts/check_cache_sync.py +490 -0
  220. package/scripts/embed_backend.py +475 -0
  221. package/scripts/install_memory.py +556 -0
  222. package/scripts/lessons_index/__init__.py +77 -0
  223. package/scripts/lessons_index/__main__.py +135 -0
  224. package/scripts/lessons_index/ingest.py +288 -0
  225. package/scripts/lessons_index/query.py +285 -0
  226. package/scripts/lessons_index/schema.py +114 -0
  227. package/scripts/memory_context/__init__.py +610 -0
  228. package/scripts/memory_graph/__init__.py +393 -0
  229. package/scripts/project_resolver.py +172 -0
  230. package/scripts/prune_codex_plugin_cache.py +23 -0
  231. package/scripts/prune_plugin_cache.py +359 -0
  232. package/scripts/semantic_index/__init__.py +482 -0
  233. package/scripts/semantic_index/_bench_hybrid.py +175 -0
  234. package/scripts/semantic_index/backfill.py +263 -0
  235. package/scripts/semantic_index/hybrid.py +174 -0
  236. package/scripts/semantic_index/test_backfill.py +292 -0
  237. package/scripts/semantic_index/test_hybrid.py +541 -0
  238. package/scripts/sync_navgator_lessons.py +666 -0
  239. package/scripts/sync_plugin_cache.py +388 -0
  240. package/skills/agent-rally-point/SKILL.md +165 -0
  241. package/skills/agent-rally-watcher/SKILL.md +83 -0
  242. package/skills/api-registry-bridge/SKILL.md +59 -0
  243. package/skills/architecture/dead/SKILL.md +56 -0
  244. package/skills/architecture/impact/SKILL.md +88 -0
  245. package/skills/architecture/review/SKILL.md +227 -0
  246. package/skills/architecture/rules/SKILL.md +72 -0
  247. package/skills/architecture/scan/SKILL.md +79 -0
  248. package/skills/architecture/trace/SKILL.md +65 -0
  249. package/skills/attribution-standard/SKILL.md +122 -0
  250. package/skills/authentication/SKILL.md +81 -0
  251. package/skills/authentication/references/better-auth-magic-link.md +135 -0
  252. package/skills/authentication/references/better-auth-setup.md +224 -0
  253. package/skills/authentication/references/google-calendar-sync.md +278 -0
  254. package/skills/authentication/references/google-cloud-console.md +159 -0
  255. package/skills/authentication/references/google-geocoding-directions.md +126 -0
  256. package/skills/authentication/references/google-lessons-example-web-app.md +177 -0
  257. package/skills/authentication/references/google-maps.md +162 -0
  258. package/skills/authentication/references/google-oauth-setup.md +343 -0
  259. package/skills/authentication/references/google-places.md +173 -0
  260. package/skills/authentication/references/lessons-example-web-app-better-auth.md +126 -0
  261. package/skills/authentication/references/resend-email.md +227 -0
  262. package/skills/authentication/references/resend-otp-magic-link.md +153 -0
  263. package/skills/authentication/references/supabase-auth.md +172 -0
  264. package/skills/auto-decision-capture/SKILL.md +419 -0
  265. package/skills/build-loop/SKILL.md +516 -0
  266. package/skills/build-loop/detect-plugins.mjs +82 -0
  267. package/skills/build-loop/eval-guide.md +65 -0
  268. package/skills/build-loop/fallbacks.md +549 -0
  269. package/skills/build-loop/phases/fact-check.md +42 -0
  270. package/skills/build-loop/phases/ui-validation.md +267 -0
  271. package/skills/build-loop/references/apple-native-planning.md +439 -0
  272. package/skills/build-loop/references/capability-routing.md +181 -0
  273. package/skills/build-loop/references/codex-subagents.md +98 -0
  274. package/skills/build-loop/references/coordination.md +161 -0
  275. package/skills/build-loop/references/correction-aware-capture.md +177 -0
  276. package/skills/build-loop/references/independent-auditor.md +72 -0
  277. package/skills/build-loop/references/intent-capability-pack.md +170 -0
  278. package/skills/build-loop/references/intent-exploration-prompts.md +96 -0
  279. package/skills/build-loop/references/leadership.md +72 -0
  280. package/skills/build-loop/references/memory.md +284 -0
  281. package/skills/build-loop/references/modular-systems-pack.md +96 -0
  282. package/skills/build-loop/references/output-style.md +129 -0
  283. package/skills/build-loop/references/pay-it-forward-arch.md +98 -0
  284. package/skills/build-loop/references/phase-1-assess.md +218 -0
  285. package/skills/build-loop/references/phase-2-plan.md +77 -0
  286. package/skills/build-loop/references/phase-3-execute.md +47 -0
  287. package/skills/build-loop/references/phase-4-review.md +310 -0
  288. package/skills/build-loop/references/phase-5-iterate.md +71 -0
  289. package/skills/build-loop/references/phase-6-learn.md +56 -0
  290. package/skills/build-loop/references/recent-design-structures.md +274 -0
  291. package/skills/build-loop/references/refactor-history/ASSESSMENT.md +85 -0
  292. package/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +149 -0
  293. package/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +32 -0
  294. package/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +48 -0
  295. package/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +60 -0
  296. package/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +51 -0
  297. package/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +71 -0
  298. package/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +52 -0
  299. package/skills/build-loop/references/refactor-history/trace-comparison.md +202 -0
  300. package/skills/build-loop/references/self-recursive-dev.md +77 -0
  301. package/skills/build-loop/references/self-review.md +232 -0
  302. package/skills/build-loop/references/ui-io-contract.md +116 -0
  303. package/skills/build-loop/scanners/audit-design-rules.mjs +476 -0
  304. package/skills/build-loop/scanners/require-visual-evidence.mjs +239 -0
  305. package/skills/build-loop/templates/backlog-item.md +35 -0
  306. package/skills/build-loop/templates/codex-worker-prompt.md +89 -0
  307. package/skills/build-loop/templates/ui-subagent-prompt.md +179 -0
  308. package/skills/build-loop/templates/ux-fix-plan.md +40 -0
  309. package/skills/building-with-deepagents/SKILL.md +195 -0
  310. package/skills/building-with-deepagents/references/anti-patterns.md +141 -0
  311. package/skills/building-with-deepagents/references/api-quick-reference.md +184 -0
  312. package/skills/capabilities/SKILL.md +91 -0
  313. package/skills/debug-loop/SKILL.md +278 -0
  314. package/skills/debug-loop/references/convergence-rules.md +145 -0
  315. package/skills/debug-loop/references/swiftui-macos-clunky-ui-debugger.html +823 -0
  316. package/skills/debugging/assess/SKILL.md +111 -0
  317. package/skills/debugging/debug-loop/SKILL.md +231 -0
  318. package/skills/debugging/memory/SKILL.md +147 -0
  319. package/skills/debugging/store/SKILL.md +153 -0
  320. package/skills/debugging-memory/SKILL.md +440 -0
  321. package/skills/debugging-memory/examples/incident-example.json +67 -0
  322. package/skills/debugging-memory/references/incident-documentation.md +280 -0
  323. package/skills/debugging-memory/references/ios-notification-alarm-playbook.md +300 -0
  324. package/skills/debugging-memory/references/pattern-extraction.md +163 -0
  325. package/skills/debugging-memory/references/subagent-integration.md +312 -0
  326. package/skills/defenseclaw-bridge/SKILL.md +156 -0
  327. package/skills/defenseclaw-bridge/references/dc-config-mapping.md +162 -0
  328. package/skills/defenseclaw-bridge/references/output-format.md +108 -0
  329. package/skills/handoff/SKILL.md +94 -0
  330. package/skills/ibr-bridge/SKILL.md +68 -0
  331. package/skills/knowledge/SKILL.md +127 -0
  332. package/skills/knowledge/references/recall-integration.md +83 -0
  333. package/skills/knowledge/templates/madr-minimal.md +56 -0
  334. package/skills/knowledge-review/SKILL.md +112 -0
  335. package/skills/logging-tracer/SKILL.md +202 -0
  336. package/skills/logging-tracer/references/log-analysis.md +128 -0
  337. package/skills/logging-tracer/references/stack-templates.md +274 -0
  338. package/skills/logging-tracer-bridge/SKILL.md +70 -0
  339. package/skills/mcp-builder/SKILL.md +278 -0
  340. package/skills/mcp-builder/references/mcp-security.md +106 -0
  341. package/skills/model-tiering/SKILL.md +216 -0
  342. package/skills/native-ax-driver/SKILL.md +220 -0
  343. package/skills/native-ax-driver/scripts/layout_fill.py +222 -0
  344. package/skills/native-ax-driver/scripts/native_driver.py +495 -0
  345. package/skills/native-ax-driver/swift/bl-ax-driver/Package.swift +20 -0
  346. package/skills/native-ax-driver/swift/bl-ax-driver/Sources/main.swift +542 -0
  347. package/skills/optimize/SKILL.md +202 -0
  348. package/skills/optimize/profiles.md +61 -0
  349. package/skills/plan-verify/SKILL.md +115 -0
  350. package/skills/plan-verify/test-fixtures/example-app-v20-findings.json +27 -0
  351. package/skills/plan-verify/test-fixtures/example-app-v20.md +42 -0
  352. package/skills/plan-verify/test-fixtures/example-app-v22-findings.json +15 -0
  353. package/skills/plan-verify/test-fixtures/example-app-v22.md +1608 -0
  354. package/skills/plan-verify/test-fixtures/unrelated-good-plan-findings.json +15 -0
  355. package/skills/plan-verify/test-fixtures/unrelated-good-plan.md +55 -0
  356. package/skills/plugin-builder/SKILL.md +329 -0
  357. package/skills/plugin-builder/references/authoritative-sources.md +104 -0
  358. package/skills/plugin-builder/references/build-loop-phase-guidance.md +94 -0
  359. package/skills/plugin-builder/references/components-guide.md +221 -0
  360. package/skills/plugin-builder/references/distribution.md +317 -0
  361. package/skills/plugin-builder/references/dual-host-claude-codex.md +220 -0
  362. package/skills/plugin-builder/references/hooks-reference.md +210 -0
  363. package/skills/plugin-builder/references/manifest-schema.md +111 -0
  364. package/skills/plugin-builder/references/plugin-hygiene-lessons.md +307 -0
  365. package/skills/plugin-tests/SKILL.md +94 -0
  366. package/skills/prd-bridge/SKILL.md +135 -0
  367. package/skills/research/SKILL.md +80 -0
  368. package/skills/security-methodology/SKILL.md +105 -0
  369. package/skills/security-methodology/references/cross-source-matrix.md +77 -0
  370. package/skills/security-methodology/references/mitre-atlas-starter.md +83 -0
  371. package/skills/security-methodology/references/nist-600-1-mapping.md +119 -0
  372. package/skills/security-methodology/references/owasp-agentic-top-10.md +157 -0
  373. package/skills/security-methodology/references/owasp-llm-top-10.md +144 -0
  374. package/skills/security-methodology/references/owasp-web-top-10.md +65 -0
  375. package/skills/self-improve/SKILL.md +298 -0
  376. package/skills/spec-writing/SKILL.md +548 -0
  377. package/skills/spec-writing/scripts/check_checklist.py +478 -0
  378. package/skills/sync-skills/SKILL.md +132 -0
  379. package/skills/telemetry/SKILL.md +66 -0
  380. package/skills/ui-design/SKILL.md +75 -0
  381. package/skills/ui-design/references/design-patterns-multi.md +165 -0
  382. package/skills/ui-design/references/design-preferences-from-owned-apps.md +150 -0
  383. package/skills/ui-design/references/evidence-capture-policy.md +55 -0
  384. package/skills/ui-design/references/ui-guidance-sources.md +330 -0
  385. package/skills/ui-design/references/universal-design-principles.alt.md +182 -0
  386. package/skills/ui-design/references/universal-design-principles.md +419 -0
  387. package/templates/memory/MEMORY.md.template +55 -0
  388. package/templates/memory/constitution.md.template +64 -0
  389. package/templates/memory/manifest.json +47 -0
@@ -0,0 +1,388 @@
1
+ #!/usr/bin/env python3
2
+ # SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ """Sync a local plugin source repo into installed host caches.
5
+
6
+ Default behavior is intentionally conservative: materialize committed HEAD with
7
+ ``git archive`` and sync that clean snapshot into the target cache. This keeps
8
+ unrelated dirty worktree edits out of Codex and Claude runtime caches.
9
+
10
+ Use ``--dirty`` only for explicit temporary runtime testing. Use ``--file`` to
11
+ copy a targeted slice without deleting the rest of the cache.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import io
17
+ import json
18
+ import os
19
+ import re
20
+ import shutil
21
+ import stat
22
+ import subprocess
23
+ import sys
24
+ import tarfile
25
+ import tempfile
26
+ from pathlib import Path
27
+ from typing import Any
28
+
29
+ HERE = Path(__file__).resolve().parent
30
+ if str(HERE) not in sys.path:
31
+ sys.path.insert(0, str(HERE))
32
+
33
+ import check_cache_sync as cache_sync # type: ignore # noqa: E402
34
+
35
+
36
+ EXCLUDE_DIRS = {".git", "node_modules", "__pycache__", ".venv", ".build-loop"}
37
+ HOOK_NAMES = ("post-commit", "post-merge", "post-checkout", "post-rewrite")
38
+ HOOK_MARKER = "# --- BEGIN build-loop plugin-cache-sync ---"
39
+ HOOK_MARKER_END = "# --- END build-loop plugin-cache-sync ---"
40
+ HOOK_SEGMENT_RE = re.compile(
41
+ rf"{re.escape(HOOK_MARKER)}.*?{re.escape(HOOK_MARKER_END)}\n?",
42
+ re.DOTALL,
43
+ )
44
+
45
+
46
+ class SyncError(RuntimeError):
47
+ pass
48
+
49
+
50
+ def run_git(source: Path, args: list[str]) -> str:
51
+ proc = subprocess.run(
52
+ ["git", *args],
53
+ cwd=str(source),
54
+ stdout=subprocess.PIPE,
55
+ stderr=subprocess.PIPE,
56
+ text=True,
57
+ check=False,
58
+ )
59
+ if proc.returncode != 0:
60
+ raise SyncError(f"git {' '.join(args)} failed: {proc.stderr.strip()}")
61
+ return proc.stdout.strip()
62
+
63
+
64
+ def require_git_head(source: Path) -> None:
65
+ inside = run_git(source, ["rev-parse", "--is-inside-work-tree"])
66
+ if inside != "true":
67
+ raise SyncError(f"{source} is not inside a git worktree; use --dirty for non-git sources")
68
+ run_git(source, ["rev-parse", "--verify", "HEAD"])
69
+
70
+
71
+ def safe_extract_tar(tar_bytes: bytes, target: Path) -> None:
72
+ target_resolved = target.resolve()
73
+ with tarfile.open(fileobj=io.BytesIO(tar_bytes), mode="r:") as archive:
74
+ for member in archive.getmembers():
75
+ member_target = (target / member.name).resolve()
76
+ if target_resolved != member_target and target_resolved not in member_target.parents:
77
+ raise SyncError(f"unsafe archive member path: {member.name}")
78
+ archive.extractall(target)
79
+
80
+
81
+ def materialize_head(source: Path) -> tempfile.TemporaryDirectory[str]:
82
+ require_git_head(source)
83
+ proc = subprocess.run(
84
+ ["git", "archive", "--format=tar", "HEAD"],
85
+ cwd=str(source),
86
+ stdout=subprocess.PIPE,
87
+ stderr=subprocess.PIPE,
88
+ check=False,
89
+ )
90
+ if proc.returncode != 0:
91
+ raise SyncError(f"git archive HEAD failed: {proc.stderr.decode(errors='ignore').strip()}")
92
+ tmp = tempfile.TemporaryDirectory(prefix="build-loop-plugin-head-")
93
+ safe_extract_tar(proc.stdout, Path(tmp.name))
94
+ return tmp
95
+
96
+
97
+ def ignore_dirty_tree(_dir: str, names: list[str]) -> set[str]:
98
+ return {name for name in names if name in EXCLUDE_DIRS}
99
+
100
+
101
+ def copy_tree_to_temp(source: Path, target_parent: Path) -> Path:
102
+ target_parent.mkdir(parents=True, exist_ok=True)
103
+ tmp = Path(tempfile.mkdtemp(prefix=".build-loop-sync-", dir=str(target_parent)))
104
+ shutil.rmtree(tmp)
105
+ shutil.copytree(source, tmp, ignore=ignore_dirty_tree)
106
+ return tmp
107
+
108
+
109
+ def sync_full_tree(source: Path, cache: Path, dry_run: bool) -> int:
110
+ files = [p for p in source.rglob("*") if p.is_file() and not any(part in EXCLUDE_DIRS for part in p.parts)]
111
+ if dry_run:
112
+ return len(files)
113
+ if cache.resolve() == source.resolve() or cache.resolve() in source.resolve().parents:
114
+ raise SyncError(f"refusing to sync into source path: {cache}")
115
+ parent = cache.parent
116
+ tmp = copy_tree_to_temp(source, parent)
117
+ if cache.exists():
118
+ shutil.rmtree(cache)
119
+ os.replace(tmp, cache)
120
+ return len(files)
121
+
122
+
123
+ def sync_targeted_files(source: Path, cache: Path, files: list[str], dry_run: bool) -> tuple[int, list[str]]:
124
+ missing: list[str] = []
125
+ copied = 0
126
+ for raw in files:
127
+ rel = raw.strip().lstrip("/")
128
+ if not rel or rel.startswith("../") or "/../" in rel:
129
+ missing.append(raw)
130
+ continue
131
+ src = source / rel
132
+ if not src.is_file():
133
+ missing.append(rel)
134
+ continue
135
+ copied += 1
136
+ if dry_run:
137
+ continue
138
+ dst = cache / rel
139
+ dst.parent.mkdir(parents=True, exist_ok=True)
140
+ shutil.copy2(src, dst)
141
+ return copied, missing
142
+
143
+
144
+ def host_list(host: str) -> list[str]:
145
+ return ["claude", "codex"] if host == "all" else [host]
146
+
147
+
148
+ def load_host_manifest(source: Path, host: str, explicit: bool) -> dict[str, Any] | None:
149
+ manifest_dir = ".codex-plugin" if host == "codex" else ".claude-plugin"
150
+ if not (source / manifest_dir / "plugin.json").exists():
151
+ if explicit:
152
+ raise SyncError(f"missing {manifest_dir}/plugin.json under {source}")
153
+ return None
154
+ return cache_sync.load_manifest(source, host)
155
+
156
+
157
+ def resolve_cache(
158
+ *,
159
+ source: Path,
160
+ host: str,
161
+ manifest: dict[str, Any],
162
+ args: argparse.Namespace,
163
+ ) -> tuple[Path, list[Path]]:
164
+ if host == "claude" and args.claude_cache:
165
+ return Path(args.claude_cache).expanduser().resolve(), []
166
+ if host == "codex" and args.codex_cache:
167
+ return Path(args.codex_cache).expanduser().resolve(), []
168
+ if args.cache:
169
+ if args.host == "all":
170
+ raise SyncError("--cache can only be used with --host claude or --host codex")
171
+ return Path(args.cache).expanduser().resolve(), []
172
+ name = manifest.get("name")
173
+ version = manifest.get("version")
174
+ if not name or not version:
175
+ raise SyncError(f"{host} plugin.json missing name or version")
176
+ return cache_sync.default_cache(source, host, str(name), str(version), args.marketplace)
177
+
178
+
179
+ def refs_for_host(source: Path, host: str, manifest: dict[str, Any], files: list[str]) -> set[str]:
180
+ if files:
181
+ return {item.strip().lstrip("/") for item in files if item.strip()}
182
+ if host == "codex":
183
+ return cache_sync.find_codex_surfaces(source, manifest)
184
+ refs = cache_sync.find_references(source)
185
+ for extra in (".claude-plugin/plugin.json", "hooks/hooks.json"):
186
+ if (source / extra).exists():
187
+ refs.add(extra)
188
+ return refs
189
+
190
+
191
+ def verify_host(source: Path, host: str, manifest: dict[str, Any], cache: Path, files: list[str]) -> list[dict[str, Any]]:
192
+ return cache_sync.check_sync(source, cache, refs_for_host(source, host, manifest, files))
193
+
194
+
195
+ def sync_one_host(
196
+ *,
197
+ host: str,
198
+ explicit_host: bool,
199
+ source_for_sync: Path,
200
+ source_for_manifest: Path,
201
+ args: argparse.Namespace,
202
+ ) -> dict[str, Any]:
203
+ manifest = load_host_manifest(source_for_manifest, host, explicit_host)
204
+ if manifest is None:
205
+ return {"host": host, "action": "skipped", "reason": "missing_manifest"}
206
+ cache, stale_versions = resolve_cache(source=source_for_manifest, host=host, manifest=manifest, args=args)
207
+ if args.files:
208
+ copied, missing = sync_targeted_files(source_for_sync, cache, args.files, args.dry_run)
209
+ action = "dry_run" if args.dry_run else "targeted_sync"
210
+ else:
211
+ copied = sync_full_tree(source_for_sync, cache, args.dry_run)
212
+ missing = []
213
+ action = "dry_run" if args.dry_run else "full_sync"
214
+
215
+ diffs: list[dict[str, Any]] = []
216
+ if not args.no_verify and not args.dry_run:
217
+ diffs = verify_host(source_for_sync, host, manifest, cache, args.files)
218
+
219
+ return {
220
+ "host": host,
221
+ "action": action,
222
+ "plugin": manifest.get("name"),
223
+ "version": manifest.get("version"),
224
+ "cache": str(cache),
225
+ "files_copied": copied,
226
+ "missing_files": missing,
227
+ "stale_versions": [str(path) for path in stale_versions],
228
+ "verification_diffs": diffs,
229
+ "ok": not missing and not diffs,
230
+ }
231
+
232
+
233
+ def repo_toplevel(source: Path) -> Path:
234
+ try:
235
+ return Path(run_git(source, ["rev-parse", "--show-toplevel"])).resolve()
236
+ except SyncError as exc:
237
+ raise SyncError(f"cannot install hooks outside a git repo: {exc}") from exc
238
+
239
+
240
+ def hook_segment(script_path: Path, host: str) -> str:
241
+ return f'''{HOOK_MARKER}
242
+ BUILD_LOOP_PLUGIN_CACHE_SYNC_TOPLEVEL="$(git rev-parse --show-toplevel 2>/dev/null)"
243
+ if [ -n "$BUILD_LOOP_PLUGIN_CACHE_SYNC_TOPLEVEL" ] && [ "${{BUILD_LOOP_PLUGIN_CACHE_SYNC_DISABLE:-}}" != "1" ]; then
244
+ python3 {str(script_path)!r} --source "$BUILD_LOOP_PLUGIN_CACHE_SYNC_TOPLEVEL" --host {host} --quiet >/dev/null 2>&1 || true
245
+ fi
246
+ {HOOK_MARKER_END}
247
+ '''
248
+
249
+
250
+ def append_before_terminal_exit(script: str, segment: str) -> str:
251
+ lines = script.rstrip().splitlines()
252
+ for idx in range(len(lines) - 1, -1, -1):
253
+ if lines[idx].strip() == "exit 0":
254
+ before = "\n".join(lines[:idx]).rstrip()
255
+ after = "\n".join(lines[idx:]).rstrip()
256
+ return f"{before}\n\n{segment.rstrip()}\n{after}\n"
257
+ return f"{script.rstrip()}\n\n{segment.rstrip()}\n"
258
+
259
+
260
+ def install_hook(hooks_dir: Path, name: str, segment: str) -> str:
261
+ hook = hooks_dir / name
262
+ existing = hook.read_text(encoding="utf-8") if hook.exists() else "#!/bin/sh\n"
263
+ if not existing.startswith("#!"):
264
+ existing = "#!/bin/sh\n" + existing
265
+ cleaned = HOOK_SEGMENT_RE.sub("", existing)
266
+ hook.write_text(append_before_terminal_exit(cleaned, segment), encoding="utf-8")
267
+ mode = hook.stat().st_mode
268
+ hook.chmod(mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
269
+ return str(hook)
270
+
271
+
272
+ def install_git_hooks(source: Path, host: str) -> dict[str, Any]:
273
+ top = repo_toplevel(source)
274
+ hooks_dir = top / ".git" / "hooks"
275
+ if not hooks_dir.is_dir():
276
+ raise SyncError(f"hooks directory not found: {hooks_dir}")
277
+ segment = hook_segment(Path(__file__).resolve(), host)
278
+ installed = [install_hook(hooks_dir, name, segment) for name in HOOK_NAMES]
279
+ return {"action": "installed_hooks", "hooks": installed, "host": host, "source": str(top)}
280
+
281
+
282
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
283
+ parser = argparse.ArgumentParser(description=__doc__)
284
+ parser.add_argument("--host", choices=["claude", "codex", "all"], default="all")
285
+ parser.add_argument("--source", default=".", help="Plugin source repo root.")
286
+ parser.add_argument("--cache", default=None, help="Cache dir for a single explicit host.")
287
+ parser.add_argument("--claude-cache", default=None, help="Claude cache dir for --host all or --host claude.")
288
+ parser.add_argument("--codex-cache", default=None, help="Codex cache dir for --host all or --host codex.")
289
+ parser.add_argument("--marketplace", default=None, help="Marketplace name override.")
290
+ parser.add_argument("--dirty", action="store_true", help="Sync the dirty working tree instead of committed HEAD.")
291
+ parser.add_argument("--file", action="append", dest="files", default=[], help="Target one relative file. Repeatable.")
292
+ parser.add_argument("--dry-run", action="store_true")
293
+ parser.add_argument("--no-verify", action="store_true", help="Skip post-sync cache verification.")
294
+ parser.add_argument("--json", action="store_true")
295
+ parser.add_argument("--quiet", action="store_true")
296
+ parser.add_argument(
297
+ "--install-git-hooks",
298
+ action="store_true",
299
+ help="Install idempotent post-commit/merge/checkout/rewrite sync hooks and exit.",
300
+ )
301
+ return parser.parse_args(argv)
302
+
303
+
304
+ def print_human(results: list[dict[str, Any]], source_mode: str, materialized_source: Path) -> None:
305
+ for result in results:
306
+ host = result.get("host")
307
+ action = result.get("action")
308
+ if action == "skipped":
309
+ print(f"- {host}: skipped ({result.get('reason')})")
310
+ continue
311
+ ok = "OK" if result.get("ok", True) else "WARN"
312
+ print(f"- {host}: {ok} {action} {result.get('plugin')}@{result.get('version')}")
313
+ if result.get("cache"):
314
+ print(f" cache: {result['cache']}")
315
+ print(f" source_mode: {source_mode}")
316
+ print(f" verified_source: {materialized_source}")
317
+ print(f" files_copied: {result.get('files_copied', 0)}")
318
+ for path in result.get("missing_files") or []:
319
+ print(f" missing: {path}")
320
+ diffs = result.get("verification_diffs") or []
321
+ if diffs:
322
+ print(f" verification_diffs: {len(diffs)}")
323
+ for diff in diffs[:20]:
324
+ print(f" [{diff.get('status')}] {diff.get('path')}")
325
+
326
+
327
+ def main(argv: list[str] | None = None) -> int:
328
+ args = parse_args(argv)
329
+ source = Path(args.source).expanduser().resolve()
330
+ if not source.is_dir():
331
+ print(f"error: source is not a directory: {source}", file=sys.stderr)
332
+ return 2
333
+
334
+ try:
335
+ if args.install_git_hooks:
336
+ installed = install_git_hooks(source, args.host)
337
+ if args.json:
338
+ print(json.dumps(installed, indent=2, sort_keys=True))
339
+ elif not args.quiet:
340
+ print(f"installed plugin cache sync hooks for {args.host}:")
341
+ for hook in installed["hooks"]:
342
+ print(f" {hook}")
343
+ return 0
344
+
345
+ tmp: tempfile.TemporaryDirectory[str] | None = None
346
+ if args.dirty:
347
+ source_for_sync = source
348
+ source_mode = "dirty"
349
+ else:
350
+ tmp = materialize_head(source)
351
+ source_for_sync = Path(tmp.name)
352
+ source_mode = "head"
353
+
354
+ explicit_host = args.host != "all"
355
+ results = [
356
+ sync_one_host(
357
+ host=host,
358
+ explicit_host=explicit_host,
359
+ source_for_sync=source_for_sync,
360
+ source_for_manifest=source_for_sync,
361
+ args=args,
362
+ )
363
+ for host in host_list(args.host)
364
+ ]
365
+ payload = {
366
+ "ok": all(result.get("ok", True) for result in results),
367
+ "source": str(source),
368
+ "source_mode": source_mode,
369
+ "materialized_source": str(source_for_sync),
370
+ "results": results,
371
+ }
372
+ if args.json:
373
+ print(json.dumps(payload, indent=2, sort_keys=True))
374
+ elif not args.quiet:
375
+ print_human(results, source_mode, source_for_sync)
376
+ if tmp is not None:
377
+ tmp.cleanup()
378
+ return 0 if payload["ok"] else 1
379
+ except SyncError as exc:
380
+ if args.json:
381
+ print(json.dumps({"ok": False, "error": str(exc)}, indent=2, sort_keys=True))
382
+ else:
383
+ print(f"error: {exc}", file=sys.stderr)
384
+ return 2
385
+
386
+
387
+ if __name__ == "__main__":
388
+ raise SystemExit(main())
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: agent-rally-point
3
+ description: "Use when coordinating build-loop with peer coding agents, checking Rally Point presence/inbox state, posting handoffs or feedback, validating the embedded Rally Point boundary, or changing the future agent-rally-point spin-out surface."
4
+ user-invocable: false
5
+ ---
6
+
7
+ <!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
8
+
9
+ # Agent Rally Point
10
+
11
+ Build-loop ships a native embedded `agent-rally-point` capability while the
12
+ standalone repo matures. Treat it as a mini-plugin inside build-loop: keep the
13
+ substrate logic, docs, tests, and thin build-loop adapters grouped so spin-out
14
+ is mechanical later.
15
+
16
+ ## Native Surface
17
+
18
+ | Purpose | Path |
19
+ |---|---|
20
+ | Substrate package | `${CLAUDE_PLUGIN_ROOT}/scripts/rally_point/` |
21
+ | Host-neutral CLI | `${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py` |
22
+ | Slash command | `${CLAUDE_PLUGIN_ROOT}/commands/agent-rally-point.md` |
23
+ | Hook adapters | `${CLAUDE_PLUGIN_ROOT}/hooks/session-start-rally-point.sh`, `${CLAUDE_PLUGIN_ROOT}/hooks/pre-edit-rally-point.sh` |
24
+ | Build-loop adapters | `${CLAUDE_PLUGIN_ROOT}/scripts/coordination_status.py`, `${CLAUDE_PLUGIN_ROOT}/scripts/coordination_rally.py`, `${CLAUDE_PLUGIN_ROOT}/scripts/coordination_bootstrap.py` |
25
+ | Boundary manifest | `${CLAUDE_PLUGIN_ROOT}/scripts/rally_point/plugin_boundary.json` |
26
+
27
+ ## Required Orchestrator Contract
28
+
29
+ At the Phase 1 preamble, before the first Rally Point write, the orchestrator
30
+ must generate or resume the durable run identity:
31
+
32
+ ```python
33
+ from scripts.rally_point.build_loop_id import generate_or_resume
34
+
35
+ execution = generate_or_resume(
36
+ workdir=Path.cwd(),
37
+ tool="<tool-id>",
38
+ session_id="<session-id>",
39
+ )
40
+ ```
41
+
42
+ `session_id` is the ephemeral host session. `run_id` is caller-chosen legacy
43
+ provenance. `build_loop_id` is the durable human-visible run identity and is
44
+ surfaced on Rally Point records as top-level `build_loop_id` and
45
+ `build_loop_run_label`.
46
+
47
+ ## Operating Rules
48
+
49
+ - Resolve the channel through `scripts/rally_point/discovery_bridge.py` or
50
+ `scripts/agent_rally.py where`; do not hardcode legacy channel roots.
51
+ - Write cross-session events through `scripts/rally_point/post.py::post()`;
52
+ do not append directly to `changes.jsonl`.
53
+ - Keep `build_loop_id` separate from `producer_metadata`.
54
+ - Keep substrate files independent from build-loop memory/orchestration
55
+ internals. If a build-loop-specific integration is needed, put it in a thin
56
+ adapter named in `plugin_boundary.json`.
57
+ - Use stable tool ids: `claude_code`, `codex`, `cursor`, `gemini`, or another
58
+ lowercase id agreed by the adapter.
59
+
60
+ ## Commands
61
+
62
+ ```bash
63
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py status --workdir "$PWD" --session-id "$SESSION_ID" --json
64
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py heartbeat --workdir "$PWD" --session-id "$SESSION_ID" --task-ref "$TASK_REF" --progress "still working" --json
65
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py ack-inbox --workdir "$PWD" --session-id "$SESSION_ID" --tool "$TOOL_ID" --json
66
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py boundary --repo "${CLAUDE_PLUGIN_ROOT}" --check --json
67
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/rally_point/boundary.py --repo "${CLAUDE_PLUGIN_ROOT}" --check --json
68
+ ```
69
+
70
+ Use `/agent-rally-point status` for the same sensor from Claude Code.
71
+ Status/watch envelopes include `inbox_latest_messages`, a compact doorbell
72
+ preview for the newest unread direct/broadcast inbox records. Counts are
73
+ session-ack aware; read `inbox/<tool>.jsonl` or `inbox/all.jsonl` before acting
74
+ on a full message, then run `ack-inbox` after handling it. Ack cursors live
75
+ under `inbox/.acks/` and never rewrite the append-only inbox payloads.
76
+
77
+ ## Task Heartbeat — still on the claimed task
78
+
79
+ Presence is process liveness: it tells peers this session can still write to
80
+ the channel. Task heartbeat is work liveness: it tells peers whether the
81
+ session is still on the claimed task, what changed since the last check-in,
82
+ what evidence exists, and when the next check-in is due.
83
+
84
+ For long-running tasks, write a heartbeat at task start and then at least every
85
+ 10 minutes:
86
+
87
+ ```bash
88
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py heartbeat \
89
+ --workdir "$PWD" \
90
+ --session-id "$SESSION_ID" \
91
+ --tool "$TOOL_ID" \
92
+ --model "$MODEL" \
93
+ --run-id "$RUN_ID" \
94
+ --task-ref "$TASK_REF" \
95
+ --status running \
96
+ --progress "short update since last check-in" \
97
+ --evidence "files/tests/commit-or-handoff-ids" \
98
+ --json
99
+ ```
100
+
101
+ Then pass the same `--task-ref` to `status` or `watch`. Health can be
102
+ `current`, `stale_check_in`, `wrong_task`, `missing`, `drift_risk`, `blocked`,
103
+ or `needs_attention`. `blocked` and `needs_attention` make status report
104
+ `blocked`; stale, missing, wrong-task, and drift-risk states report `warn`.
105
+
106
+ ## Roster — who is running, where, doing what, with how many subagents
107
+
108
+ `roster` answers the cross-channel "who's live right now" question in one
109
+ command. It walks **every** `<apps_root>/*/sessions/*.json` (all repos at
110
+ once), keeps sessions whose `last_seen` is within the stale window, and
111
+ builds a parent/child tree from each record's `parent` link plus the
112
+ self-reported `spawned` fan-out.
113
+
114
+ ```bash
115
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py roster # live tree, all channels
116
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py roster --app ptyd # one channel
117
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py roster --json # structured (array of agent objects w/ children + spawned)
118
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py roster --stale-secs 300 --all # widen window, keep stale
119
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py roster --watch 5 # re-render every 5s
120
+ ```
121
+
122
+ Each row: `session_id · app · host:cwd · tool/model · task · last-seen(age) ·
123
+ subagents (Σtotal by-type + live nested count)`. Children that posted their
124
+ own presence nest under the parent; subagents that did not post presence are
125
+ reflected by the parent's `spawned` totals.
126
+
127
+ ### Convention — populate the roster on every presence write
128
+
129
+ So the roster is useful, agents **must** enrich their `presence` calls. These
130
+ fields are additive and backward-compatible (existing callers keep working):
131
+
132
+ ```bash
133
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally.py presence \
134
+ --session-id "$SESSION_ID" --tool claude_code --model opus \
135
+ --cwd "$PWD" \
136
+ --task "what this agent is actually doing right now" \
137
+ --parent "$SPAWNING_SESSION_ID" \
138
+ --spawned "coder:2,workflow:21,independent-auditor:1"
139
+ ```
140
+
141
+ - `--cwd` / `--pid` / `--host` — where it runs (default cwd / this pid / this host).
142
+ - `--task` — fuller free text (falls back to `--phase` for display).
143
+ - `--parent <session_id>` — links a subagent to its spawning agent; omit for top-level.
144
+ - `--spawned <type:count,…>` — the fan-out an agent self-reports.
145
+ - Every `presence` call rewrites `last_seen`; re-post periodically so the
146
+ agent stays in the live window (default 120s). Presence is not task
147
+ heartbeat; use `agent_rally.py heartbeat` for long-running task check-ins.
148
+
149
+ Top-level orchestrators should post `--spawned` reflecting their dispatched
150
+ subagents; each dispatched subagent that can post should set `--parent` to the
151
+ orchestrator's `session_id`.
152
+
153
+ ## Validation
154
+
155
+ ```bash
156
+ uv run pytest scripts/test_build_loop_id.py scripts/rally_point/test_boundary.py scripts/rally_point/test_orchestrator_contract.py scripts/test_agent_rally_roster.py scripts/test_agent_rally_status.py
157
+ python3 scripts/agent_rally.py boundary --repo "$PWD" --check --json
158
+ ```
159
+
160
+ ## Spin-Out Rule
161
+
162
+ When extracting to the standalone plugin, copy the namespaced substrate,
163
+ skill, command, hooks, tests, and docs named in `plugin_boundary.json`.
164
+ Build-loop should then keep only the thin adapters that call the standalone
165
+ package.
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: agent-rally-watcher
3
+ description: "Use when listening for Rally Point changes, wiring coordination watchers, debugging watch-loop behavior, or changing the future agent-rally-watcher spin-out surface."
4
+ user-invocable: false
5
+ ---
6
+
7
+ <!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
8
+
9
+ # Agent Rally Watcher
10
+
11
+ Build-loop ships a native embedded `agent-rally-watcher` capability while the
12
+ standalone watcher repo matures. Treat it as a mini-plugin inside build-loop:
13
+ watcher behavior lives in one namespace, and build-loop keeps compatibility
14
+ entrypoints thin.
15
+
16
+ ## Native Surface
17
+
18
+ | Purpose | Path |
19
+ |---|---|
20
+ | Watcher package | `${CLAUDE_PLUGIN_ROOT}/scripts/agent_rally_watcher/` |
21
+ | Compatibility CLI | `${CLAUDE_PLUGIN_ROOT}/scripts/coordination_watch.py` |
22
+ | Status dependency | `${CLAUDE_PLUGIN_ROOT}/scripts/coordination_status.py` |
23
+ | Manual command | `${CLAUDE_PLUGIN_ROOT}/commands/agent-rally-point.md` `watch` subcommand |
24
+ | Boundary manifest | `${CLAUDE_PLUGIN_ROOT}/scripts/rally_point/plugin_boundary.json` |
25
+
26
+ ## Operating Rules
27
+
28
+ - Keep watch-loop logic under `scripts/agent_rally_watcher/`.
29
+ - Keep `scripts/coordination_watch.py` as a compatibility wrapper.
30
+ - Watchers emit compact JSONL transition events; they do not make decisions,
31
+ mutate code, stage files, commit, or resolve verdicts.
32
+ - Prefer short interactive watchers for active work. Durable always-on
33
+ watchers belong in launchd/systemd packaging, not ad hoc shell backgrounding.
34
+ - Stop watchers started by the current run before final closeout.
35
+
36
+ ## Commands
37
+
38
+ ```bash
39
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/coordination_watch.py \
40
+ --workdir "$PWD" \
41
+ --session-id "$SESSION_ID" \
42
+ --tool "$TOOL_ID" \
43
+ --task-ref "$TASK_REF" \
44
+ --interval 5 \
45
+ --jsonl \
46
+ --baseline-current
47
+ ```
48
+
49
+ For one-shot validation:
50
+
51
+ ```bash
52
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/coordination_watch.py \
53
+ --workdir "$PWD" \
54
+ --session-id watcher-smoke \
55
+ --tool codex \
56
+ --iterations 1 \
57
+ --jsonl
58
+ ```
59
+
60
+ Watcher transition events include `inbox_latest_messages`, a compact
61
+ doorbell preview of the newest addressed/broadcast inbox records. It is
62
+ additive to the raw unread counts; read the inbox before acting on the full
63
+ message.
64
+
65
+ Watcher transition events also include `task_heartbeat`. Pass `--task-ref`
66
+ when a long-running task has an expected claim/run/pillar id; the watcher will
67
+ wake on current/stale/wrong-task/blocked heartbeat changes without requiring
68
+ the peer to send an inbox message.
69
+
70
+ ## Validation
71
+
72
+ ```bash
73
+ uv run pytest scripts/test_coordination_status.py scripts/rally_point/test_session_probe.py
74
+ python3 scripts/coordination_watch.py --workdir "$PWD" --session-id watcher-smoke --tool codex --iterations 1 --jsonl
75
+ python3 scripts/agent_rally.py boundary --repo "$PWD" --check --json
76
+ ```
77
+
78
+ ## Spin-Out Rule
79
+
80
+ When extracting to the standalone watcher plugin, copy
81
+ `scripts/agent_rally_watcher/`, this skill, watcher tests, and the
82
+ compatibility contract named in `plugin_boundary.json`. Build-loop should then
83
+ keep `coordination_watch.py` as a thin adapter to the standalone package.