@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,445 @@
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
+ """Global path/schema resolver for the build-loop memory framework.
5
+
6
+ This module is the active path contract for durable build-loop memory.
7
+ Every writer/reader script should import helpers from here instead of
8
+ embedding store paths directly.
9
+
10
+ Environment variable contract:
11
+ - ``$BUILD_LOOP_MEMORY_STORE_ROOT``: override the build-loop-memory root.
12
+ - ``$BUILD_LOOP_MEMORY_ROOT``: compatibility override for the same root.
13
+ - ``$AGENT_MEMORY_ROOT`` : compatibility override for the same root.
14
+ Defaults to ``~/dev/git-folder/build-loop-memory``.
15
+ - ``$AGENT_MEMORY_SCHEMA`` : override the default Postgres schema.
16
+ Defaults to ``personal_memory``.
17
+ - ``$AGENT_MEMORY_DUAL_WRITE``: when set to ``"1"``, writers must produce
18
+ BOTH the legacy artifact (``<repo>/.episodic/decisions/``,
19
+ ``build_loop_memory.semantic_facts``) AND the
20
+ new artifact (``<root>/projects/<project>/decisions/``,
21
+ ``personal_memory.semantic_facts``).
22
+
23
+ Cutover lock:
24
+ - ``/tmp/agent-memory-cutover.lock`` (exists) → ``write_decision.py``
25
+ prints ``cutover in progress, skipping`` and exits 0 with no writes.
26
+
27
+ These functions are pure and side-effect-free except for environment
28
+ inspection. They never mkdir or touch files; callers handle creation.
29
+ """
30
+ from __future__ import annotations
31
+
32
+ import os
33
+ import re
34
+ import subprocess
35
+ from pathlib import Path
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # Legacy fallback constants. These are for migration/archive tooling only.
39
+ # Active build-loop readers and writers should use the canonical helpers
40
+ # below (`project_decisions_dir`, `project_lessons_dir`, top-level lanes).
41
+ # ---------------------------------------------------------------------------
42
+ LEGACY_SCHEMA = "build_loop_memory"
43
+ LEGACY_DECISIONS_REL = ".episodic/decisions"
44
+
45
+ DEFAULT_MEMORY_STORE_ROOT = "~/dev/git-folder/build-loop-memory"
46
+ DEFAULT_AGENT_MEMORY_ROOT = DEFAULT_MEMORY_STORE_ROOT
47
+ DEFAULT_SCHEMA = "personal_memory"
48
+
49
+ CUTOVER_LOCK_PATH = "/tmp/agent-memory-cutover.lock"
50
+
51
+ # Historical name retained as a compatibility alias. The active root is now
52
+ # the sibling `build-loop-memory` repository, not `~/.build-loop/memory`.
53
+ DEFAULT_BUILD_LOOP_MEMORY_ROOT = DEFAULT_MEMORY_STORE_ROOT
54
+
55
+ # Sub-component patterns: paths under a project that count as a distinct
56
+ # slug. Today: just `workers/`. Extend by adding entries; order matters
57
+ # (longest match wins).
58
+ SUBCOMPONENT_PATTERNS: tuple[str, ...] = ("workers",)
59
+
60
+
61
+ def memory_store_root() -> Path:
62
+ """Return the canonical build-loop-memory root.
63
+
64
+ Reads, in order, ``$BUILD_LOOP_MEMORY_STORE_ROOT``,
65
+ ``$BUILD_LOOP_MEMORY_ROOT``, and ``$AGENT_MEMORY_ROOT`` (expanded for
66
+ ``~``). Falls back to ``~/dev/git-folder/build-loop-memory``. Path is
67
+ not required to exist; callers that need the directory should create it.
68
+ """
69
+ raw = (
70
+ os.environ.get("BUILD_LOOP_MEMORY_STORE_ROOT")
71
+ or os.environ.get("BUILD_LOOP_MEMORY_ROOT")
72
+ or os.environ.get("AGENT_MEMORY_ROOT")
73
+ or DEFAULT_MEMORY_STORE_ROOT
74
+ )
75
+ return Path(os.path.expanduser(raw))
76
+
77
+
78
+ def agent_memory_root() -> Path:
79
+ """Compatibility alias for ``memory_store_root()``."""
80
+ return memory_store_root()
81
+
82
+
83
+ def decisions_root() -> Path:
84
+ """Return the legacy pre-cutover decisions root.
85
+
86
+ This helper exists for migration/archive tooling that still needs to
87
+ inventory ``<memory_store_root()>/decisions``. Active writers should use
88
+ ``project_decisions_dir(project)``.
89
+ """
90
+ return memory_store_root() / "decisions"
91
+
92
+
93
+ # Project tag whitelist: alphanumerics, underscore, dash, dot. No path
94
+ # separators, no leading dot+dot, no leading slash. Length 1..127. The
95
+ # leading underscore allowance covers the canonical ``_unscoped`` tag.
96
+ _SAFE_PROJECT_TAG_RE = re.compile(r"^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$")
97
+
98
+
99
+ def _safe_project_tag(tag: str) -> str:
100
+ """Return ``tag`` if it is safe to use as a directory name.
101
+
102
+ Rejects path-traversal sequences (``..``, ``/``, ``\\``) and
103
+ suspicious characters that could escape the decisions tree on
104
+ case-insensitive or symlink-following filesystems.
105
+ """
106
+ if not tag or not _SAFE_PROJECT_TAG_RE.match(tag) or tag in {".", ".."}:
107
+ raise ValueError(f"unsafe project tag: {tag!r}")
108
+ return tag
109
+
110
+
111
+ def _safe_project_relpath(project: str) -> Path:
112
+ """Return a validated relative path for a project tag.
113
+
114
+ Empty strings collapse to ``_unscoped``. Slash-separated subcomponent
115
+ slugs are supported, with every segment validated independently.
116
+ """
117
+ if not project:
118
+ project = "_unscoped"
119
+ parts = project.split("/")
120
+ for part in parts:
121
+ _safe_project_tag(part)
122
+ return Path(*parts)
123
+
124
+
125
+ def _safe_child(root: Path, relpath: Path, label: str) -> Path:
126
+ """Return ``root / relpath`` after checking it resolves below root."""
127
+ candidate = (root / relpath).resolve()
128
+ root_resolved = root.resolve()
129
+ # Path.is_relative_to was added in 3.9; fall back to startswith on str.
130
+ rel = str(candidate)
131
+ root_str = str(root_resolved)
132
+ if not (rel == root_str or rel.startswith(root_str + os.sep)):
133
+ raise ValueError(f"{label} resolves outside {root}")
134
+ return root / relpath
135
+
136
+
137
+ def project_root(project: str) -> Path:
138
+ """Return ``<memory_store_root()>/projects/<project>`` (validated)."""
139
+ return _safe_child(memory_store_root() / "projects", _safe_project_relpath(project), "project")
140
+
141
+
142
+ def project_decisions_dir(project: str) -> Path:
143
+ """Return ``<project_root(project)>/decisions``."""
144
+ return project_root(project) / "decisions"
145
+
146
+
147
+ def project_lessons_dir(project: str) -> Path:
148
+ """Return ``<project_root(project)>/lessons``."""
149
+ return project_root(project) / "lessons"
150
+
151
+
152
+ def project_raw_dir(project: str) -> Path:
153
+ """Return ``<project_root(project)>/raw`` for verbatim source material."""
154
+ return project_root(project) / "raw"
155
+
156
+
157
+ def project_raw_documents_dir(project: str) -> Path:
158
+ """Return ``<project_raw_dir(project)>/documents``."""
159
+ return project_raw_dir(project) / "documents"
160
+
161
+
162
+ def project_raw_files_dir(project: str) -> Path:
163
+ """Return ``<project_raw_dir(project)>/files``."""
164
+ return project_raw_dir(project) / "files"
165
+
166
+
167
+ def project_raw_artifacts_dir(project: str) -> Path:
168
+ """Return ``<project_raw_dir(project)>/artifacts``."""
169
+ return project_raw_dir(project) / "artifacts"
170
+
171
+
172
+ def project_debugging_dir(project: str) -> Path:
173
+ """Return ``<project_root(project)>/debugging``."""
174
+ return project_root(project) / "debugging"
175
+
176
+
177
+ def project_design_dir(project: str) -> Path:
178
+ """Return ``<project_root(project)>/design``."""
179
+ return project_root(project) / "design"
180
+
181
+
182
+ def project_product_dir(project: str) -> Path:
183
+ """Return ``<project_root(project)>/product``."""
184
+ return project_root(project) / "product"
185
+
186
+
187
+ def project_architecture_dir(project: str) -> Path:
188
+ """Return ``<project_root(project)>/architecture``."""
189
+ return project_root(project) / "architecture"
190
+
191
+
192
+ def top_level_lessons_dir() -> Path:
193
+ """Return ``<memory_store_root()>/lessons``."""
194
+ return memory_store_root() / "lessons"
195
+
196
+
197
+ def top_level_debugging_dir() -> Path:
198
+ """Return ``<memory_store_root()>/debugging``."""
199
+ return memory_store_root() / "debugging"
200
+
201
+
202
+ def top_level_design_dir() -> Path:
203
+ """Return ``<memory_store_root()>/design``."""
204
+ return memory_store_root() / "design"
205
+
206
+
207
+ def top_level_product_dir() -> Path:
208
+ """Return ``<memory_store_root()>/product``."""
209
+ return memory_store_root() / "product"
210
+
211
+
212
+ def top_level_architecture_dir() -> Path:
213
+ """Return ``<memory_store_root()>/architecture``."""
214
+ return memory_store_root() / "architecture"
215
+
216
+
217
+ def memory_indexes_dir() -> Path:
218
+ """Return ``<memory_store_root()>/indexes``."""
219
+ return memory_store_root() / "indexes"
220
+
221
+
222
+ def decisions_dir_for_project(project: str) -> Path:
223
+ """Compatibility alias for ``project_decisions_dir(project)``."""
224
+ return project_decisions_dir(project)
225
+
226
+
227
+ def legacy_decisions_dir(workdir: Path) -> Path:
228
+ """Return ``<workdir>/.episodic/decisions`` (the per-repo legacy path)."""
229
+ return Path(workdir) / ".episodic" / "decisions"
230
+
231
+
232
+ def default_schema() -> str:
233
+ """Return the default Postgres schema for the new system.
234
+
235
+ Reads ``$AGENT_MEMORY_SCHEMA``, falls back to ``personal_memory``.
236
+ """
237
+ return os.environ.get("AGENT_MEMORY_SCHEMA") or DEFAULT_SCHEMA
238
+
239
+
240
+ def legacy_schema() -> str:
241
+ """Return the legacy Postgres schema name (``build_loop_memory``).
242
+
243
+ Used during the dual-write transitional window. There is no env-var
244
+ override for the legacy schema — Phase D removes it entirely.
245
+ """
246
+ return LEGACY_SCHEMA
247
+
248
+
249
+ def dual_write_enabled() -> bool:
250
+ """Return True iff ``$AGENT_MEMORY_DUAL_WRITE`` is set to ``"1"``."""
251
+ return os.environ.get("AGENT_MEMORY_DUAL_WRITE") == "1"
252
+
253
+
254
+ def cutover_lock_active() -> bool:
255
+ """Return True iff the cutover lock file exists.
256
+
257
+ Writers must check this at the *very top* of their entry point and
258
+ exit cleanly when active.
259
+ """
260
+ return Path(CUTOVER_LOCK_PATH).exists()
261
+
262
+
263
+ # ---------------------------------------------------------------------------
264
+ # Build-loop memory paths (global + per-project segmentation).
265
+ #
266
+ # Per the memory-consolidation PR series (2026-05-13):
267
+ # - ~/.build-loop/memory/ global root (existing)
268
+ # - ~/.build-loop/memory/projects/<slug>/ project-scoped lessons (NEW)
269
+ # - ~/.build-loop/memory/projects/_archive/<slug>/ retired projects
270
+ #
271
+ # PR 1 (read-path tolerance, 2026-05-13) added the projects/<slug>/ tier
272
+ # while still reading the legacy per-repo location. PR 2 cut writes over.
273
+ # PR 3 (2026-05-13) removed the legacy read shim — the consolidated tree
274
+ # is now the only path read. Slug derivation reuses _safe_project_tag so
275
+ # the same normalization applies to filesystem dirs AND the Postgres
276
+ # semantic_facts.project column (no split-brain by construction).
277
+ # ---------------------------------------------------------------------------
278
+
279
+
280
+ def build_loop_memory_root() -> Path:
281
+ """Compatibility alias for ``memory_store_root()``."""
282
+ return memory_store_root()
283
+
284
+
285
+ def project_memory_root() -> Path:
286
+ """Return ``<memory_store_root()>/projects``."""
287
+ return memory_store_root() / "projects"
288
+
289
+
290
+ def project_memory_dir_for_project(project: str) -> Path:
291
+ """Compatibility alias for ``project_root(project)``."""
292
+ return project_root(project)
293
+
294
+
295
+ def archive_memory_dir(project: str) -> Path:
296
+ """Return ``project_memory_root() / _archive / <project>`` (validated).
297
+
298
+ Same safety contract as ``project_memory_dir_for_project`` — used for
299
+ retired projects whose memory should remain queryable.
300
+ """
301
+ if not project:
302
+ raise ValueError("archive_memory_dir requires a non-empty project tag")
303
+ parts = project.split("/")
304
+ for p in parts:
305
+ _safe_project_tag(p)
306
+ candidate_rel = Path("_archive", *parts)
307
+ candidate = (project_memory_root() / candidate_rel).resolve()
308
+ root_resolved = project_memory_root().resolve()
309
+ rel = str(candidate)
310
+ root_str = str(root_resolved)
311
+ if not (rel == root_str or rel.startswith(root_str + os.sep)):
312
+ raise ValueError(
313
+ f"archive project tag {project!r} resolves outside project_memory_root()"
314
+ )
315
+ return project_memory_root() / candidate_rel
316
+
317
+
318
+ def _canonical_repo_root(cwd_path: Path) -> Path | None:
319
+ """Return the canonical (worktree-independent) repo root for ``cwd_path``.
320
+
321
+ Runs ``git rev-parse --git-common-dir`` scoped to ``cwd_path``. A worktree's
322
+ git-common-dir points at the *canonical* repo's ``.git`` (shared by the main
323
+ checkout + every ``git worktree``), so the parent of the resolved common-dir
324
+ is identical from anywhere in the repo family. Returns ``None`` when the
325
+ invocation fails, output is empty, or resolution raises. Never raises.
326
+
327
+ DRY note: ``rally_point/channel_paths.py`` carries a sibling copy used for the
328
+ channel slug. ``_paths`` is the lower-level module (``channel_paths`` imports
329
+ FROM it), so the two cannot share without a circular import; consolidating is
330
+ tracked as a follow-up. Behaviour is identical.
331
+ """
332
+ try:
333
+ out = subprocess.run(
334
+ ["git", "rev-parse", "--git-common-dir"],
335
+ cwd=str(cwd_path),
336
+ check=True,
337
+ capture_output=True,
338
+ text=True,
339
+ ).stdout.strip()
340
+ except (subprocess.CalledProcessError, OSError):
341
+ return None
342
+ if not out:
343
+ return None
344
+ common = Path(out)
345
+ if not common.is_absolute():
346
+ common = cwd_path / common
347
+ try:
348
+ return common.resolve().parent
349
+ except (OSError, RuntimeError):
350
+ return None
351
+
352
+
353
+ def derive_slug_from_cwd(cwd: Path | str | None = None) -> str:
354
+ """Derive the project slug from a working directory.
355
+
356
+ Algorithm (deterministic; alignment with Postgres semantic_facts.project
357
+ is guaranteed by routing every slug through ``_safe_project_tag``):
358
+
359
+ 1. Resolve symlinks via ``Path.resolve()`` so a session running in
360
+ ``~/.claude/plugins/build-loop`` resolves to ``~/dev/git-folder/build-loop``.
361
+ 2. Walk up looking for a ``.git`` entry (file OR dir — worktrees use
362
+ a file). The deepest enclosing ``.git`` defines the repo root.
363
+ 3. Slug base = ``basename(repo_root)`` lowercased; non-safe chars
364
+ collapsed to ``-``; runs of ``-`` collapsed; leading/trailing
365
+ ``-`` stripped; capped at 64 chars.
366
+ 4. If ``cwd`` is N levels below repo_root AND the first level matches
367
+ a ``SUBCOMPONENT_PATTERNS`` entry, append ``/<subcomponent>`` to
368
+ the slug. Today only ``workers`` is recognized.
369
+ 5. If no ``.git`` is found in the ancestry, return ``_unscoped``.
370
+ 6. Final slug is run through ``_safe_project_tag`` (each segment
371
+ independently for sub-component slugs).
372
+
373
+ Returns the slug string. Never raises (returns ``_unscoped`` on
374
+ ambiguity); callers that need to know whether resolution succeeded
375
+ can check for the ``_unscoped`` sentinel.
376
+ """
377
+ if cwd is None:
378
+ cwd = Path.cwd()
379
+ try:
380
+ cwd_resolved = Path(os.path.expanduser(str(cwd))).resolve()
381
+ except (OSError, RuntimeError):
382
+ return "_unscoped"
383
+
384
+ # Walk up looking for .git
385
+ repo_root: Path | None = None
386
+ cursor = cwd_resolved
387
+ seen: set[str] = set()
388
+ while True:
389
+ key = str(cursor)
390
+ if key in seen:
391
+ break # symlink cycle guard
392
+ seen.add(key)
393
+ if (cursor / ".git").exists():
394
+ repo_root = cursor
395
+ break
396
+ parent = cursor.parent
397
+ if parent == cursor:
398
+ break
399
+ cursor = parent
400
+
401
+ if repo_root is None:
402
+ return "_unscoped"
403
+
404
+ # Slug base from the CANONICAL repo root so every `git worktree` of one repo
405
+ # shares a single memory project (else each worktree — e.g. an
406
+ # `isolation: "worktree"` build-orchestrator dispatch — gets its own split
407
+ # project). A worktree's `.git` is a FILE pointing at the main repo's gitdir;
408
+ # the main checkout's `.git` is a DIR. Only shell out to git for the worktree
409
+ # case so the common main-checkout path stays subprocess-free. Mirrors the
410
+ # channel slug's D1 fix in `rally_point/channel_paths.py`.
411
+ base_root = repo_root
412
+ if (repo_root / ".git").is_file():
413
+ canonical = _canonical_repo_root(cwd_resolved)
414
+ if canonical is not None:
415
+ base_root = canonical
416
+
417
+ base = base_root.name.lower()
418
+ base = re.sub(r"[^a-z0-9._-]", "-", base)
419
+ base = re.sub(r"-{2,}", "-", base).strip("-")
420
+ base = base[:64] or "_unscoped"
421
+
422
+ # Sub-component detection: is cwd under <repo_root>/<sub>/...?
423
+ try:
424
+ rel = cwd_resolved.relative_to(repo_root)
425
+ except ValueError:
426
+ rel = Path()
427
+ if rel.parts:
428
+ first = rel.parts[0].lower()
429
+ if first in SUBCOMPONENT_PATTERNS:
430
+ sub_safe = re.sub(r"[^a-z0-9._-]", "-", first).strip("-")[:64]
431
+ if sub_safe:
432
+ slug = f"{base}/{sub_safe}"
433
+ # Validate each segment
434
+ for seg in slug.split("/"):
435
+ try:
436
+ _safe_project_tag(seg)
437
+ except ValueError:
438
+ return "_unscoped"
439
+ return slug
440
+
441
+ try:
442
+ _safe_project_tag(base)
443
+ except ValueError:
444
+ return "_unscoped"
445
+ return base
package/scripts/blm.py ADDED
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env python3
2
+ # capability:
3
+ # purpose: Host-neutral CLI for build-loop-memory hot context and evidence reads.
4
+ # application: memory
5
+ # status: experimental
6
+ # SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
7
+ # SPDX-License-Identifier: Apache-2.0
8
+ """Host-neutral build-loop-memory CLI.
9
+
10
+ Primary surfaces:
11
+ blm context --workdir "$PWD" --query "<goal>" --mode fast --json
12
+ blm context --workdir "$PWD" --query "<goal>" --mode expand --json
13
+ blm open --id <memory-id-or-artifact-id>
14
+ blm status --workdir "$PWD" --json
15
+ blm serve --host 127.0.0.1 --port 8777
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import argparse
20
+ import json
21
+ import os
22
+ import sys
23
+ from pathlib import Path
24
+ from typing import Any
25
+
26
+ HERE = Path(__file__).resolve().parent
27
+ if str(HERE) not in sys.path:
28
+ sys.path.insert(0, str(HERE))
29
+
30
+ from memory_context import ( # type: ignore # noqa: E402
31
+ build_context,
32
+ describe_access,
33
+ open_artifact,
34
+ render_current_markdown,
35
+ )
36
+
37
+ DEFAULT_API_HOST = "127.0.0.1"
38
+ DEFAULT_API_PORT = 8777
39
+
40
+
41
+ def _emit_json(data: dict[str, Any]) -> None:
42
+ print(json.dumps(data, indent=2, sort_keys=True, default=str))
43
+
44
+
45
+ def _cmd_context(args: argparse.Namespace) -> int:
46
+ envelope = build_context(
47
+ workdir=Path(args.workdir).resolve(),
48
+ query=args.query,
49
+ mode=args.mode,
50
+ project=args.project,
51
+ write=not args.no_write,
52
+ limit=args.limit,
53
+ )
54
+ if args.json:
55
+ _emit_json(envelope)
56
+ return 0
57
+ current = envelope["current"]
58
+ print(render_current_markdown(current), end="")
59
+ if args.mode == "expand":
60
+ lessons = (envelope.get("expansion") or {}).get("lessons") or []
61
+ if lessons:
62
+ print("\n## Expanded Lessons\n")
63
+ for item in lessons:
64
+ print(f"- {item.get('name')} - {item.get('description')}")
65
+ return 0
66
+
67
+
68
+ def _cmd_open(args: argparse.Namespace) -> int:
69
+ result = open_artifact(
70
+ args.id,
71
+ workdir=Path(args.workdir).resolve(),
72
+ project=args.project,
73
+ max_chars=args.max_chars,
74
+ )
75
+ if args.json:
76
+ _emit_json(result)
77
+ return 0
78
+ if not result.get("exists"):
79
+ print(result.get("reason") or "not found", file=sys.stderr)
80
+ return 1
81
+ print(result.get("text", ""), end="")
82
+ return 0
83
+
84
+
85
+ def _cmd_status(args: argparse.Namespace) -> int:
86
+ result = describe_access(
87
+ workdir=Path(args.workdir).resolve(),
88
+ project=args.project,
89
+ host=args.host,
90
+ port=args.port,
91
+ )
92
+ if args.json:
93
+ _emit_json(result)
94
+ return 0
95
+ print(f"Project: {result['project']}")
96
+ print(f"Memory root: {result['memory_root']}")
97
+ print(f"Current JSON: {result['current_paths']['json']}")
98
+ print(f"Current exists: {result['current_exists']['json']}")
99
+ print(f"Fast CLI: {result['cli']['fast']}")
100
+ print(f"Expand CLI: {result['cli']['expand']}")
101
+ print(f"API: {result['api']['base_url']}")
102
+ return 0
103
+
104
+
105
+ def _cmd_serve(args: argparse.Namespace) -> int:
106
+ from blm_api import serve # type: ignore # noqa: PLC0415
107
+
108
+ try:
109
+ serve(host=args.host, port=args.port, allow_nonlocal=args.allow_nonlocal)
110
+ except ValueError as exc:
111
+ print(str(exc), file=sys.stderr)
112
+ return 1
113
+ return 0
114
+
115
+
116
+ def build_parser() -> argparse.ArgumentParser:
117
+ parser = argparse.ArgumentParser(description=__doc__)
118
+ sub = parser.add_subparsers(dest="command", required=True)
119
+
120
+ context = sub.add_parser("context", help="Return fast or expanded project memory context.")
121
+ context.add_argument("--workdir", default=os.getcwd())
122
+ context.add_argument("--query", default="")
123
+ context.add_argument("--project", default=None)
124
+ context.add_argument("--mode", choices=("fast", "expand"), default="fast")
125
+ context.add_argument("--limit", type=int, default=5)
126
+ context.add_argument("--json", action="store_true", help="Print JSON envelope.")
127
+ context.add_argument("--no-write", action="store_true", help="Do not persist CURRENT files.")
128
+ context.set_defaults(func=_cmd_context)
129
+
130
+ open_cmd = sub.add_parser("open", help="Read a memory evidence item by id or safe memory-store path.")
131
+ open_cmd.add_argument("--id", required=True)
132
+ open_cmd.add_argument("--workdir", default=os.getcwd())
133
+ open_cmd.add_argument("--project", default=None)
134
+ open_cmd.add_argument("--max-chars", type=int, default=8000)
135
+ open_cmd.add_argument("--json", action="store_true", help="Print JSON envelope.")
136
+ open_cmd.set_defaults(func=_cmd_open)
137
+
138
+ status = sub.add_parser("status", help="Show fast-access paths, commands, and API endpoints.")
139
+ status.add_argument("--workdir", default=os.getcwd())
140
+ status.add_argument("--project", default=None)
141
+ status.add_argument("--host", default=DEFAULT_API_HOST)
142
+ status.add_argument("--port", type=int, default=DEFAULT_API_PORT)
143
+ status.add_argument("--json", action="store_true", help="Print JSON envelope.")
144
+ status.set_defaults(func=_cmd_status)
145
+
146
+ serve_cmd = sub.add_parser("serve", help="Serve the optional local build-loop-memory HTTP API.")
147
+ serve_cmd.add_argument("--host", default=os.environ.get("BLM_API_HOST", DEFAULT_API_HOST))
148
+ serve_cmd.add_argument("--port", type=int, default=int(os.environ.get("BLM_API_PORT", str(DEFAULT_API_PORT))))
149
+ serve_cmd.add_argument("--allow-nonlocal", action="store_true")
150
+ serve_cmd.set_defaults(func=_cmd_serve)
151
+
152
+ return parser
153
+
154
+
155
+ def main(argv: list[str] | None = None) -> int:
156
+ parser = build_parser()
157
+ args = parser.parse_args(argv)
158
+ return int(args.func(args))
159
+
160
+
161
+ if __name__ == "__main__":
162
+ raise SystemExit(main())