@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,478 @@
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
+ """
5
+ check_checklist.py — deterministic spec-writing checklist verifier.
6
+
7
+ Reads a plan markdown file, locates the <!-- checklist --> HTML comment block,
8
+ and checks whether each required item is answered (not blank, not
9
+ the literal placeholder text, and not omitted entirely).
10
+
11
+ Exit codes:
12
+ 0 — all required items answered (Items 15 and 17 are conditional on UI files in scope)
13
+ 1 — one or more items missing or unanswered
14
+ 2 — verifier error (file not found, parse failure)
15
+
16
+ Usage:
17
+ python3 check_checklist.py --plan docs/plans/my-feature.md [--json] [--quiet]
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import argparse
22
+ import json
23
+ import re
24
+ import sys
25
+ from pathlib import Path
26
+
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # Constants
30
+ # ---------------------------------------------------------------------------
31
+
32
+ ITEMS: list[tuple[str, str]] = [
33
+ ("item_1_auth_guard", "Item 1 — Auth guard"),
34
+ ("item_2_external_apis", "Item 2 — External APIs"),
35
+ ("item_3_rate_limit", "Item 3 — Rate-limit criterion"),
36
+ ("item_4_discoverability", "Item 4 — Discoverability"),
37
+ ("item_5_server_client_boundary", "Item 5 — Server/client boundary"),
38
+ ("item_6_concurrency", "Item 6 — Concurrency"),
39
+ ("item_7_observability", "Item 7 — Observability"),
40
+ ("item_8_input_validation", "Item 8 — Input validation"),
41
+ ("item_9_stable_id_traceability", "Item 9 — Stable ID traceability"),
42
+ ("item_10_json_spec_object", "Item 10 — JSON spec object"),
43
+ ("item_11_blocking_and_novel_question_gate", "Item 11 — Blocking-and-novel question gate"),
44
+ ("item_12_low_reversibility_adrs", "Item 12 — Low-reversibility ADRs"),
45
+ ("item_13_analytical_lens", "Item 13 — Analytical lens"),
46
+ ("item_14_handoff_document", "Item 14 — Handoff document"),
47
+ ("item_15_synthesis_dimensions", "Item 15 — Synthesis dimensions"),
48
+ ("item_16_risk_reason", "Item 16 — Risk reason"),
49
+ ("item_17_ui_io_contract", "Item 17 — UI input/output contract"),
50
+ ]
51
+
52
+ # Values that count as "not answered" — case-insensitive, stripped
53
+ PLACEHOLDER_PATTERNS: list[re.Pattern] = [
54
+ re.compile(r"^<answer>$"),
55
+ re.compile(r"^\.\.\.$"),
56
+ re.compile(r"^$"),
57
+ re.compile(r"^tbd$", re.IGNORECASE),
58
+ re.compile(r"^todo$", re.IGNORECASE),
59
+ re.compile(r"^none$", re.IGNORECASE),
60
+ ]
61
+
62
+ CHECKLIST_RE = re.compile(
63
+ r"<!--\s*checklist\s*(.*?)\s*-->",
64
+ re.DOTALL | re.IGNORECASE,
65
+ )
66
+
67
+ ITEM_LINE_RE = re.compile(
68
+ r"^(Item\s*\d+\s*[—\-–]\s*[^:]+)\s*:\s*(.*)$",
69
+ re.IGNORECASE,
70
+ )
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Parsing
75
+ # ---------------------------------------------------------------------------
76
+
77
+ def extract_checklist_block(text: str) -> str | None:
78
+ """Return the inner text of the first <!-- checklist ... --> block, or None."""
79
+ m = CHECKLIST_RE.search(text)
80
+ return m.group(1).strip() if m else None
81
+
82
+
83
+ def parse_checklist_block(block: str) -> dict[str, str]:
84
+ """
85
+ Parse `Item N — Label: answer` lines from the checklist block.
86
+ Returns a dict mapping the item label prefix (lowercased, spaces→underscores)
87
+ to the answer string.
88
+ """
89
+ parsed: dict[str, str] = {}
90
+ for line in block.splitlines():
91
+ line = line.strip()
92
+ if not line:
93
+ continue
94
+ m = ITEM_LINE_RE.match(line)
95
+ if m:
96
+ key = _normalize_label(m.group(1))
97
+ parsed[key] = m.group(2).strip()
98
+ return parsed
99
+
100
+
101
+ def _normalize_label(label: str) -> str:
102
+ """'Item 1 — Auth guard' → 'item_1_auth_guard'"""
103
+ s = label.lower()
104
+ s = re.sub(r"[—\-–]+", " ", s)
105
+ s = re.sub(r"[^a-z0-9\s]", "", s)
106
+ s = re.sub(r"\s+", "_", s.strip())
107
+ return s
108
+
109
+
110
+ def is_answered(value: str) -> bool:
111
+ v = value.strip()
112
+ return not any(p.match(v) for p in PLACEHOLDER_PATTERNS)
113
+
114
+
115
+ # ---------------------------------------------------------------------------
116
+ # Structural validators for items 9-14
117
+ # ---------------------------------------------------------------------------
118
+
119
+ # ID patterns: U-NN, F-NN, D-NN, S-NN, T-NN, A-NN
120
+ _ID_RE = re.compile(r"\b[UFDSTA]-\d+\b")
121
+ _P0_LINE_RE = re.compile(r"\[P0\]", re.IGNORECASE)
122
+ _T_ID_RE = re.compile(r"\bT-\d+\b")
123
+ _A_ID_RE = re.compile(r"\bA-\d+\b")
124
+ _JSON_SPEC_SECTION_RE = re.compile(r"^##\s+Spec Object.*\(JSON\)", re.IGNORECASE | re.MULTILINE)
125
+ _OPEN_Q_SECTION_RE = re.compile(r"^##\s+Open Questions", re.IGNORECASE | re.MULTILINE)
126
+ _BLOCKING_TEST_RE = re.compile(r"blocking-test:\s*T-\d+", re.IGNORECASE)
127
+ _ADR_HEADING_RE = re.compile(r"^##\s+ADR-\d+", re.IGNORECASE | re.MULTILINE)
128
+ _LOW_REV_RE = re.compile(
129
+ r"low-reversib|db choice|auth provider|api contract|public schema",
130
+ re.IGNORECASE,
131
+ )
132
+ _LENS_LINE_RE = re.compile(r"analytical lens\s*:", re.IGNORECASE)
133
+
134
+ # Items 15 and 17 — UI-only checks.
135
+ _UI_FILE_RE = re.compile(
136
+ r"""
137
+ (
138
+ \b[\w/.\-]+\.(?:tsx|jsx|vue|svelte)\b
139
+ |(?:^|[\s`(/])components/[\w/.\-]+
140
+ |(?:^|[\s`(/])(?:app|pages)/(?!(?:api|_app|_document)\b)[\w/.\-]*(?:page|layout)\.(?:ts|tsx|js|jsx)\b
141
+ |(?:^|[\s`(/])Views/[\w/.\-]+\.swift\b
142
+ |\b[\w/.\-]*(?:View|Screen|Page)\.swift\b
143
+ )
144
+ """,
145
+ re.IGNORECASE | re.VERBOSE,
146
+ )
147
+ _SYNTHESIS_BLOCK_RE = re.compile(
148
+ r"synthesis_dimensions\s*:\s*\n((?:[ \t]+[\w_]+\s*:.*\n?)+)", re.IGNORECASE)
149
+ _REQUIRED_SYNTHESIS_KEYS = ("placement", "cta_tier", "copy_tone",
150
+ "visual_weight", "empty_state")
151
+ _UI_IO_SECTION_RE = re.compile(
152
+ r"^##\s+UI\s+Input/Output\s+Contract\b", re.IGNORECASE | re.MULTILINE)
153
+ _UI_IO_REQUIRED_TERMS = (
154
+ "surface", "input", "output", "taxonomy", "operation", "component",
155
+ "state", "modality", "validation", "traceability",
156
+ )
157
+
158
+
159
+ def check_item_15_synthesis_dimensions(plan_text: str) -> tuple[str, str | None]:
160
+ """OK if no UI in scope; else require synthesis_dimensions block w/ all keys."""
161
+ if not _UI_FILE_RE.search(plan_text):
162
+ return ("OK", None)
163
+ m = _SYNTHESIS_BLOCK_RE.search(plan_text)
164
+ if not m:
165
+ return ("FAIL", "UI files detected but no `synthesis_dimensions:` block. "
166
+ "Required keys: " + ", ".join(_REQUIRED_SYNTHESIS_KEYS) + ".")
167
+ body = m.group(1)
168
+ missing = [k for k in _REQUIRED_SYNTHESIS_KEYS
169
+ if not re.search(rf"^\s+{re.escape(k)}\s*:", body, re.MULTILINE)]
170
+ if missing:
171
+ return ("FAIL", "synthesis_dimensions missing key(s): " + ", ".join(missing))
172
+ return ("OK", None)
173
+
174
+
175
+ def check_item_17_ui_io_contract(plan_text: str) -> tuple[str, str | None]:
176
+ """OK if no UI in scope; else require a UI Input/Output Contract section."""
177
+ if not _UI_FILE_RE.search(plan_text):
178
+ return ("OK", None)
179
+
180
+ m = _UI_IO_SECTION_RE.search(plan_text)
181
+ if not m:
182
+ return ("FAIL", "UI files detected but no `## UI Input/Output Contract` section found.")
183
+
184
+ section_start = m.end()
185
+ next_heading = re.search(r"^##\s+", plan_text[section_start:], re.MULTILINE)
186
+ section = (
187
+ plan_text[section_start: section_start + next_heading.start()]
188
+ if next_heading else plan_text[section_start:]
189
+ )
190
+ lower = section.lower()
191
+ missing = [term for term in _UI_IO_REQUIRED_TERMS if term not in lower]
192
+ if missing:
193
+ return ("FAIL", "UI Input/Output Contract missing term(s): " + ", ".join(missing))
194
+ return ("OK", None)
195
+
196
+
197
+ def _structural_findings(text: str, plan_path: Path) -> list[dict]:
198
+ """
199
+ Run structural checks for higher-order checklist items against the full plan text.
200
+ Returns a list of finding dicts (same shape as checklist findings).
201
+ Each finding has item_id, label, status ('ok'|'warn'|'fail'), and message.
202
+ These supplement — they do not replace — the checklist block checks.
203
+ """
204
+ findings = []
205
+
206
+ # Item 9: P0 lines must have at least one T- reference
207
+ p0_lines = [ln for ln in text.splitlines() if _P0_LINE_RE.search(ln)]
208
+ if p0_lines:
209
+ p0_without_test = [ln for ln in p0_lines if not _T_ID_RE.search(ln)]
210
+ if p0_without_test:
211
+ findings.append({
212
+ "item_id": "item_9_stable_id_traceability",
213
+ "label": "Item 9 — Stable ID traceability",
214
+ "status": "warn",
215
+ "message": (
216
+ f"{len(p0_without_test)} [P0] line(s) found without a linked T-NN test ID. "
217
+ "Each P0 must trace to at least one acceptance test."
218
+ ),
219
+ })
220
+ else:
221
+ # Also verify at least one full trace chain appears (U-, F-, T-)
222
+ has_chain = (
223
+ bool(_ID_RE.search(text))
224
+ and bool(re.search(r"\bU-\d+\b", text))
225
+ and bool(re.search(r"\bF-\d+\b", text))
226
+ )
227
+ if not has_chain:
228
+ findings.append({
229
+ "item_id": "item_9_stable_id_traceability",
230
+ "label": "Item 9 — Stable ID traceability",
231
+ "status": "warn",
232
+ "message": (
233
+ "P0 lines have T- links but no full U-NN → F-NN → T-NN chain found. "
234
+ "Add stable IDs threading from user need through feature to test."
235
+ ),
236
+ })
237
+
238
+ # Item 10: ## Spec Object (JSON) section must exist
239
+ if not _JSON_SPEC_SECTION_RE.search(text):
240
+ findings.append({
241
+ "item_id": "item_10_json_spec_object",
242
+ "label": "Item 10 — JSON spec object",
243
+ "status": "warn",
244
+ "message": (
245
+ "No '## Spec Object (JSON)' section found. "
246
+ "Emit a structured JSON block before rendering markdown."
247
+ ),
248
+ })
249
+
250
+ # Item 11: Open Questions entries must carry blocking-test: annotation
251
+ oq_match = _OPEN_Q_SECTION_RE.search(text)
252
+ if oq_match:
253
+ # Extract the Open Questions section (up to the next ## heading)
254
+ oq_start = oq_match.end()
255
+ next_heading = re.search(r"^##\s+", text[oq_start:], re.MULTILINE)
256
+ oq_body = text[oq_start: oq_start + next_heading.start()] if next_heading else text[oq_start:]
257
+ # Count question lines (non-empty, non-heading lines)
258
+ q_lines = [ln.strip() for ln in oq_body.splitlines()
259
+ if ln.strip() and not ln.strip().startswith("#")]
260
+ missing_annotation = [ln for ln in q_lines if not _BLOCKING_TEST_RE.search(ln)]
261
+ if missing_annotation:
262
+ findings.append({
263
+ "item_id": "item_11_blocking_and_novel_question_gate",
264
+ "label": "Item 11 — Blocking-and-novel question gate",
265
+ "status": "warn",
266
+ "message": (
267
+ f"{len(missing_annotation)} Open Question line(s) lack a 'blocking-test: T-NN' "
268
+ "annotation. Convert non-blocking questions to [ASSUMED: ...] entries."
269
+ ),
270
+ })
271
+
272
+ # Item 12: Low-reversibility decision mentions must have ADR link
273
+ low_rev_lines = [ln for ln in text.splitlines() if _LOW_REV_RE.search(ln)]
274
+ adr_headings_exist = bool(_ADR_HEADING_RE.search(text))
275
+ if low_rev_lines and not adr_headings_exist:
276
+ findings.append({
277
+ "item_id": "item_12_low_reversibility_adrs",
278
+ "label": "Item 12 — Low-reversibility ADRs",
279
+ "status": "warn",
280
+ "message": (
281
+ f"{len(low_rev_lines)} low-reversibility decision mention(s) found but no "
282
+ "'## ADR-NN:' section detected. Each such decision needs an ADR record."
283
+ ),
284
+ })
285
+
286
+ # Item 13: Analytical lens line must appear in the plan body (outside the checklist block)
287
+ body_text = CHECKLIST_RE.sub("", text) # strip the <!-- checklist --> block
288
+ if not _LENS_LINE_RE.search(body_text):
289
+ findings.append({
290
+ "item_id": "item_13_analytical_lens",
291
+ "label": "Item 13 — Analytical lens",
292
+ "status": "warn",
293
+ "message": (
294
+ "No 'Analytical lens:' line found in the plan body. "
295
+ "Name the lens (JTBD, QFD, TRIZ, Pugh/AHP, DSM, etc.) in Locked Decisions."
296
+ ),
297
+ })
298
+
299
+ # Item 14: Sibling .handoff.md must exist
300
+ slug = plan_path.stem # e.g. "my-feature" from "my-feature.md"
301
+ handoff_path = plan_path.parent / f"{slug}.handoff.md"
302
+ if not handoff_path.exists():
303
+ findings.append({
304
+ "item_id": "item_14_handoff_document",
305
+ "label": "Item 14 — Handoff document",
306
+ "status": "warn",
307
+ "message": (
308
+ f"Sibling handoff file '{handoff_path.name}' not found. "
309
+ "Generate docs/plans/<slug>.handoff.md alongside the plan."
310
+ ),
311
+ })
312
+
313
+ # Item 15: Synthesis dimensions block required when UI is in scope
314
+ status_15, msg_15 = check_item_15_synthesis_dimensions(text)
315
+ if status_15 == "FAIL":
316
+ findings.append({
317
+ "item_id": "item_15_synthesis_dimensions",
318
+ "label": "Item 15 — Synthesis dimensions",
319
+ "status": "fail",
320
+ "message": msg_15,
321
+ })
322
+
323
+ # Item 17: UI Input/Output Contract required when UI is in scope
324
+ status_17, msg_17 = check_item_17_ui_io_contract(text)
325
+ if status_17 == "FAIL":
326
+ findings.append({
327
+ "item_id": "item_17_ui_io_contract",
328
+ "label": "Item 17 — UI input/output contract",
329
+ "status": "fail",
330
+ "message": msg_17,
331
+ })
332
+
333
+ return findings
334
+
335
+
336
+ # ---------------------------------------------------------------------------
337
+ # Main verification
338
+ # ---------------------------------------------------------------------------
339
+
340
+ def verify(plan_path: Path) -> dict:
341
+ """
342
+ Returns a result dict:
343
+ {
344
+ "plan": str,
345
+ "checklist_found": bool,
346
+ "findings": [{"item_id": str, "label": str, "answer": str|None, "status": "ok"|"missing"|"unanswered"}],
347
+ "structural_warnings": [{"item_id": str, "label": str, "status": "warn", "message": str}],
348
+ "missing_count": int,
349
+ "structural_warning_count": int,
350
+ "exit_code": int # 0=clean, 1=failures, 2=error
351
+ }
352
+ """
353
+ try:
354
+ text = plan_path.read_text(encoding="utf-8")
355
+ except OSError as exc:
356
+ return {
357
+ "plan": str(plan_path),
358
+ "checklist_found": False,
359
+ "findings": [],
360
+ "structural_warnings": [],
361
+ "missing_count": len(ITEMS),
362
+ "structural_warning_count": 0,
363
+ "exit_code": 2,
364
+ "error": str(exc),
365
+ }
366
+
367
+ block = extract_checklist_block(text)
368
+ if block is None:
369
+ findings = [
370
+ {
371
+ "item_id": item_id,
372
+ "label": label,
373
+ "answer": None,
374
+ "status": "missing",
375
+ "message": "No <!-- checklist --> block found in plan file.",
376
+ }
377
+ for item_id, label in ITEMS
378
+ ]
379
+ return {
380
+ "plan": str(plan_path),
381
+ "checklist_found": False,
382
+ "findings": findings,
383
+ "structural_warnings": [],
384
+ "missing_count": len(ITEMS),
385
+ "structural_warning_count": 0,
386
+ "exit_code": 1,
387
+ }
388
+
389
+ parsed = parse_checklist_block(block)
390
+ # Items 15 and 17 are conditional: only required when UI files are in scope.
391
+ ui_in_scope = bool(_UI_FILE_RE.search(text))
392
+
393
+ findings = []
394
+ missing = 0
395
+ for item_id, label in ITEMS:
396
+ normalized = _normalize_label(label)
397
+ # Item 15/17 optional when no UI in scope; Item 16 always optional (only required
398
+ # when author has identified a high-consequence boundary — absent is valid).
399
+ is_optional = (
400
+ (item_id == "item_15_synthesis_dimensions" and not ui_in_scope)
401
+ or item_id == "item_16_risk_reason"
402
+ or (item_id == "item_17_ui_io_contract" and not ui_in_scope)
403
+ )
404
+ if normalized not in parsed:
405
+ if is_optional:
406
+ findings.append({"item_id": item_id, "label": label, "answer": None,
407
+ "status": "ok", "message": "N/A: no UI in scope."})
408
+ continue
409
+ findings.append({"item_id": item_id, "label": label, "answer": None,
410
+ "status": "missing",
411
+ "message": f"Item not found. Expected '{label}:'"})
412
+ missing += 1
413
+ elif not is_answered(parsed[normalized]):
414
+ if is_optional:
415
+ findings.append({"item_id": item_id, "label": label,
416
+ "answer": parsed[normalized], "status": "ok",
417
+ "message": "N/A: no UI in scope."})
418
+ continue
419
+ findings.append({"item_id": item_id, "label": label,
420
+ "answer": parsed[normalized], "status": "unanswered",
421
+ "message": "Placeholder or empty. Provide answer or 'N/A: <reason>'."})
422
+ missing += 1
423
+ else:
424
+ findings.append({"item_id": item_id, "label": label,
425
+ "answer": parsed[normalized], "status": "ok"})
426
+
427
+ structural_warnings = _structural_findings(text, plan_path)
428
+ structural_fail_count = sum(1 for w in structural_warnings if w.get("status") == "fail")
429
+ return {
430
+ "plan": str(plan_path), "checklist_found": True, "findings": findings,
431
+ "structural_warnings": structural_warnings, "missing_count": missing,
432
+ "structural_warning_count": len(structural_warnings),
433
+ "structural_fail_count": structural_fail_count,
434
+ "exit_code": 0 if (missing == 0 and structural_fail_count == 0) else 1,
435
+ }
436
+
437
+
438
+ # ---------------------------------------------------------------------------
439
+ # CLI
440
+ # ---------------------------------------------------------------------------
441
+
442
+ def main() -> int:
443
+ parser = argparse.ArgumentParser(
444
+ description="Verify spec-writing checklist in a plan markdown file."
445
+ )
446
+ parser.add_argument("--plan", required=True, help="Path to the plan markdown file.")
447
+ parser.add_argument("--json", action="store_true", dest="as_json",
448
+ help="Emit JSON output.")
449
+ parser.add_argument("--quiet", action="store_true",
450
+ help="Suppress human-readable summary (use with --json).")
451
+ args = parser.parse_args()
452
+
453
+ plan_path = Path(args.plan)
454
+ result = verify(plan_path)
455
+
456
+ if args.as_json:
457
+ print(json.dumps(result, indent=2))
458
+
459
+ if not args.quiet:
460
+ status = "CLEAN" if result["exit_code"] == 0 else "INCOMPLETE"
461
+ warn_count = result.get("structural_warning_count", 0)
462
+ print(
463
+ f"check_checklist — {status} "
464
+ f"({result['missing_count']} items missing/unanswered, "
465
+ f"{warn_count} structural warnings)"
466
+ )
467
+ for f in result["findings"]:
468
+ if f["status"] != "ok":
469
+ print(f" [{f['status'].upper()}] {f['label']}: {f.get('message', '')}")
470
+ for w in result.get("structural_warnings", []):
471
+ tag = w.get("status", "warn").upper()
472
+ print(f" [{tag}] {w['label']}: {w.get('message', '')}")
473
+
474
+ return result["exit_code"]
475
+
476
+
477
+ if __name__ == "__main__":
478
+ sys.exit(main())
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: build-loop:sync-skills
3
+ description: Use when the user asks to "check skill drift", "sync skills", or "update architecture skills", or when Phase 1 Assess detects stale source_hash values. Walks skills/architecture/ and skills/debugging/, recomputes source_hash, reports drift. Read-only.
4
+ version: 0.1.0
5
+ user-invocable: false
6
+ ---
7
+
8
+ <!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
9
+
10
+ # Sync-Skills — Drift Detection for Native Copies
11
+
12
+ Build-loop's `skills/architecture/` and `skills/debugging/` skills are copied from canonical upstream repos (NavGator, claude-code-debugger). Each carries a `source:` path and `source_hash:` SHA-256 in its frontmatter. This skill recomputes the hash from the canonical source file and reports any drift.
13
+
14
+ **Read-only.** Never auto-updates a skill — surfaces a list of skills that need refresh and a one-line refresh command.
15
+
16
+ ## When to Activate
17
+
18
+ - User asks "check skill drift", "sync skills", "are native skills stale"
19
+ - After updating NavGator or claude-code-debugger locally and you want to know which build-loop skills inherit the change
20
+ - Periodic maintenance (run quarterly, or before any release that touches the architecture/debugging surfaces)
21
+
22
+ ## Workflow
23
+
24
+ Run the drift-check script:
25
+
26
+ ```bash
27
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/sync_skills.py
28
+ ```
29
+
30
+ Or inline (no script dependency):
31
+
32
+ ```bash
33
+ python3 - <<'PY'
34
+ import hashlib, os, pathlib, re, sys
35
+
36
+ ROOT = pathlib.Path(os.environ.get("CLAUDE_PLUGIN_ROOT") or pathlib.Path(__file__).resolve().parents[2])
37
+ HOME = pathlib.Path.home()
38
+
39
+ def read_frontmatter(path):
40
+ text = path.read_text()
41
+ m = re.match(r'^---\n(.*?)\n---\n', text, re.DOTALL)
42
+ if not m:
43
+ return {}
44
+ fm = {}
45
+ for line in m.group(1).splitlines():
46
+ if ':' in line:
47
+ k, v = line.split(':', 1)
48
+ fm[k.strip()] = v.strip().strip('"').strip("'")
49
+ return fm
50
+
51
+ def find_canonical(rel_path):
52
+ # Try common parent dirs
53
+ for parent in [HOME / "dev" / "git-folder", ROOT.parent, pathlib.Path.cwd()]:
54
+ candidate = parent / rel_path
55
+ if candidate.exists():
56
+ return candidate
57
+ return None
58
+
59
+ drift = []
60
+ checked = 0
61
+ for tree in ["skills/architecture", "skills/debugging"]:
62
+ for skill_md in (ROOT / tree).rglob("SKILL.md"):
63
+ fm = read_frontmatter(skill_md)
64
+ src = fm.get("source")
65
+ expected_hash = fm.get("source_hash")
66
+ if not src or not expected_hash:
67
+ continue
68
+ canonical = find_canonical(src)
69
+ rel = skill_md.relative_to(ROOT)
70
+ checked += 1
71
+ if not canonical:
72
+ drift.append((str(rel), "MISSING", "canonical source not found: " + src))
73
+ continue
74
+ actual = hashlib.sha256(canonical.read_bytes()).hexdigest()
75
+ if actual != expected_hash:
76
+ drift.append((str(rel), "DRIFT", f"expected {expected_hash[:12]} got {actual[:12]}"))
77
+
78
+ print(f"Checked: {checked} skills")
79
+ if not drift:
80
+ print("Status: clean — no drift")
81
+ sys.exit(0)
82
+
83
+ print(f"Status: {len(drift)} drift(s)")
84
+ for rel, kind, detail in drift:
85
+ print(f" [{kind}] {rel}")
86
+ print(f" {detail}")
87
+ print()
88
+ print("Refresh: rerun build-loop:sync-skills with --refresh after reviewing the canonical diff,")
89
+ print("or invoke the orchestrator to re-import the affected skill(s).")
90
+ sys.exit(1 if drift else 0)
91
+ PY
92
+ ```
93
+
94
+ ## Output
95
+
96
+ - **Clean**: `Checked: 10 skills. Status: clean — no drift.`
97
+ - **Drift detected**: list of `<skill path> | DRIFT | expected <hash-prefix> got <hash-prefix>` plus one-line refresh hint
98
+ - **Missing canonical**: list of `<skill path> | MISSING | canonical source not found: <path>` — means upstream repo moved or was deleted
99
+
100
+ ## What This Skill Does NOT Do
101
+
102
+ - Does not auto-update SKILL.md files (refresh is a deliberate, reviewed action)
103
+ - Does not modify the canonical source repos
104
+ - Does not re-import — the user (or build-orchestrator on user request) re-runs the import flow
105
+
106
+ ## How to Refresh a Drifted Skill
107
+
108
+ 1. Read the canonical source file at the path in `source:`
109
+ 2. Diff against the local SKILL.md (skipping the rewritten frontmatter and any build-loop-specific sibling-skill references)
110
+ 3. Decide: pull the upstream change, keep local fork, or escalate to user
111
+ 4. If pulling: re-author the local SKILL.md preserving the build-loop-specific framing (skill name, sibling references), recompute `source_hash`, update frontmatter
112
+ 5. Re-run `build-loop:sync-skills` to confirm drift cleared
113
+
114
+ ## Locations Walked
115
+
116
+ - `skills/architecture/scan/SKILL.md`
117
+ - `skills/architecture/impact/SKILL.md`
118
+ - `skills/architecture/trace/SKILL.md`
119
+ - `skills/architecture/rules/SKILL.md`
120
+ - `skills/architecture/dead/SKILL.md`
121
+ - `skills/architecture/review/SKILL.md`
122
+ - `skills/debugging/memory/SKILL.md`
123
+ - `skills/debugging/store/SKILL.md`
124
+ - `skills/debugging/assess/SKILL.md`
125
+ - `skills/debugging/debug-loop/SKILL.md`
126
+
127
+ ## Sibling Skills
128
+
129
+ - All skills under `build-loop:architecture-*` — drift-checked by this skill
130
+ - All skills under `build-loop:debugging-*` — drift-checked by this skill
131
+
132
+ *Native to build-loop. Not copied from any upstream — this is the drift-detector itself.*
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: telemetry
3
+ description: Use when adding observability/telemetry to an app, instrumenting traces/metrics/logs, wiring LLM/agent tracing, choosing a monitoring vendor, or auditing an app for missing telemetry. Triggers — "add telemetry", "add observability", "instrument this", "tracing", "OpenTelemetry/OTel", "LLM observability", "LangChain tracing", "Phoenix/Langfuse/LangSmith", "Crashlytics/Sentry/mobile telemetry", "why is this slow in prod", "no visibility into". OpenTelemetry-first, vendor-neutral.
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
+ # Telemetry — OpenTelemetry-first, vendor-neutral
10
+
11
+ **The rule:** default to **OpenTelemetry (OTel)**. Instrument with OTel SDKs + **GenAI semantic conventions**; export OTLP to whatever backend fits. Never lock telemetry to a single proprietary vendor, and **never roll your own tracing schema** — OTel conventions exist. This codifies the user's already-decided stack (`prefer-opentelemetry`); it is a default, not dogma — document an exception when a closed tool genuinely wins.
12
+
13
+ Canonical working exemplar in-tree: **`sample-observability-app/src/observability.py`** (OTLP/HTTP → Phoenix, env-gated `SAMPLE_OBSERVE=1`, fails silent). Copy this pattern; don't reinvent it.
14
+
15
+ ## Decision tree — pick the stack by app type
16
+
17
+ | App type | Instrument with | Dev backend | Prod backend | Error tracking |
18
+ |---|---|---|---|---|
19
+ | **LLM / agent** (LangChain, LangGraph, raw SDK) | `openinference-instrumentation-langchain` **or** `opentelemetry-instrumentation-langchain` (OpenLLMetry) + OTel SDK | **Arize Phoenix** (Apache-2.0, OTLP-native, local eval UI) | **Langfuse** (self-host, OTLP `/api/public/otel`, evals + replay) | Sentry |
20
+ | **Web / server** (Node, Python) | `@opentelemetry/sdk-node` (JS SDK 2.0, stable) / `opentelemetry-sdk` (Python) + auto-instrumentations | OTel Collector → any | Grafana/SigNoz/Honeycomb/Datadog via OTLP | **Sentry** (the record for deployed web apps) |
21
+ | **Mobile / iOS** (SwiftUI) | **Embrace Apple SDK** (Apache-2.0, built on `opentelemetry-swift`; adds crash/ANR/session/UI that bare OTel-Swift lacks) | — | any OTLP backend (Grafana/SigNoz/Honeycomb) | Embrace or Sentry-cocoa (MIT) |
22
+
23
+ **LLM tracing — three paths, in preference order:** (A) **OpenLLMetry** `opentelemetry-instrumentation-langchain` — `LangchainInstrumentor().instrument()`, vendor-neutral OTLP; (B) **OpenInference** `openinference-instrumentation-langchain` — same monkey-patch model, tight Phoenix integration; (C) **LangSmith** — opt-in only (proprietary backend; has OTLP export but canonical storage stays LangSmith). LangChain does **not** emit OTel natively as of 2026, so an instrumentation lib is required. LangSmith stays behind a flag — "no paid posture."
24
+
25
+ **Mobile — the Firebase tradeoff (stated plainly):** Firebase's iOS SDK is Apache-2.0, but **Crashlytics/Performance emit no OTLP** — data is trapped in the Firebase console (or BigQuery export). For OTel portability Firebase Performance is a dead end; Crashlytics is fine for triage only. Prefer Embrace (OTel-compatible) when portability/reliability matter. Note: CocoaPods support for firebase-ios-sdk ends Oct 2026 (SPM only).
26
+
27
+ ## Minimal wire-up (Python LLM app)
28
+
29
+ ```python
30
+ from opentelemetry.sdk.trace import TracerProvider
31
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
32
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
33
+ from opentelemetry.instrumentation.langchain import LangchainInstrumentor
34
+
35
+ provider = TracerProvider()
36
+ provider.add_span_processor(BatchSpanProcessor(
37
+ OTLPSpanExporter(endpoint="http://otel-collector:4317"))) # swap endpoint = swap backend
38
+ LangchainInstrumentor().instrument(tracer_provider=provider)
39
+ ```
40
+
41
+ Use GenAI semconv attributes (`gen_ai.system`, `gen_ai.request.model`, `gen_ai.usage.input_tokens`) so the data is backend-agnostic. Gate observability behind an env flag, default-off on cheap tiers (OTel + batch processor adds ~10–50 ms/call). Probe the backend at startup and **warn without blocking** if it's down (fail-silent, like the sample observability exemplar).
42
+
43
+ ## Status (2026, cite before relying — these move)
44
+
45
+ - OTel **GenAI client spans stable** (early 2026); agent/framework spans experimental-but-stable-in-practice. JS SDK 2.0 stable; Python SDK stable.
46
+ - Phoenix, Langfuse, OpenLLMetry, OpenInference all OTLP-compatible and OSS.
47
+ - Embrace Kotlin SDK donated to OTel (CNCF, Mar 2026, KMP — Android-first); Embrace **Apple** SDK stays in Embrace's repo (Apache-2.0) but is built on OTel primitives.
48
+
49
+ ## Instrumentation gaps in this user's repos (audit 2026-05-31)
50
+
51
+ Already instrumented (reference these): **sample-observability-app** (OTel+Phoenix+OpenInference, full), **sample-reader/sample-rag** (OTel full + Sentry), **sample-secrets-service** (OTel metrics).
52
+
53
+ **Gaps worth closing first** — LLM/agent apps with zero telemetry:
54
+ 1. **sample-research-app** — LangChain + LangGraph, nothing. Drop in the sample observability pattern (~10 lines) for instant span/token visibility.
55
+ 2. **sample-strategy-app** — has LangSmith dep but no OTel plumbing; unify with the OTel-first stack.
56
+ 3. **sample-agent-app** — LangGraph, no telemetry.
57
+
58
+ Partial (error-only, no traces): sample-product-app, sample-decision-app, sample-prompt-lab (Sentry only). **sample-voice-ios** — no telemetry; candidate for Embrace Apple SDK.
59
+
60
+ ## When build-loop fires this skill
61
+
62
+ Phase 1 Assess: if the build touches a server/LLM/mobile app with no telemetry, flag the gap. Phase 2 Plan: if the build adds a new service, LLM call path, or user-facing mobile flow, include an OTel instrumentation step (default-off env flag). Phase 4 Review: a new LLM call path shipped without span coverage is an observability gap to surface, not a blocker.
63
+
64
+ ## Sources
65
+
66
+ OTel GenAI semconv: opentelemetry.io/docs/specs/semconv/gen-ai/ · JS SDK 2.0: opentelemetry.io/blog/2025/otel-js-sdk-2-0/ · OpenLLMetry: github.com/traceloop/openllmetry · OpenInference: github.com/Arize-ai/openinference · Phoenix: arize.com/docs/phoenix · Langfuse OTel: langfuse.com/integrations/native/opentelemetry · Embrace Apple: github.com/embrace-io/embrace-apple-sdk · opentelemetry-swift: github.com/open-telemetry/opentelemetry-swift · Sentry OTLP: docs.sentry.io/concepts/otlp/ · Firebase: firebase.google.com/docs/crashlytics, /docs/perf-mon.