boost-skill-cli 1.0.147__tar.gz → 1.0.148__tar.gz

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 (297) hide show
  1. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/_version.py +2 -2
  3. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/pkg.py +14 -5
  4. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/rules.py +19 -9
  5. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/store.py +47 -13
  6. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/workflows.py +11 -5
  7. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  8. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_skill_cli.egg-info/SOURCES.txt +1 -0
  9. boost_skill_cli-1.0.148/docs/roadmap/items/install-scope-user-or-project.md +27 -0
  10. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap.html +24 -1
  11. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_pkg.py +16 -0
  12. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_rules.py +18 -0
  13. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_store.py +48 -0
  14. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_workflows.py +10 -0
  15. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/.gitattributes +0 -0
  16. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/.gitignore +0 -0
  17. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/CLAUDE.md +0 -0
  18. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/CONTRIBUTING.md +0 -0
  19. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/LICENSE +0 -0
  20. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/MANIFEST.in +0 -0
  21. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/Makefile +0 -0
  22. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/README.md +0 -0
  23. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/SECURITY.md +0 -0
  24. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost +0 -0
  25. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/__init__.py +0 -0
  26. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/__main__.py +0 -0
  27. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/cli.py +0 -0
  28. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/cliparse.py +0 -0
  29. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/__init__.py +0 -0
  30. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/bmad.py +0 -0
  31. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/configuration.py +0 -0
  32. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/discovery.py +0 -0
  33. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/hooks.py +0 -0
  34. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/info.py +0 -0
  35. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/intelligence.py +0 -0
  36. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/quality.py +0 -0
  37. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/taps.py +0 -0
  38. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/commands/team.py +0 -0
  39. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/__init__.py +0 -0
  40. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/adapters.py +0 -0
  41. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/agents.py +0 -0
  42. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/ai.py +0 -0
  43. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/catalog.py +0 -0
  44. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/claude_settings.py +0 -0
  45. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/config.py +0 -0
  46. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/dense.py +0 -0
  47. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/embed.py +0 -0
  48. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/frontmatter.py +0 -0
  49. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/gitutil.py +0 -0
  50. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/imperative.py +0 -0
  51. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/injectscan.py +0 -0
  52. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/journal.py +0 -0
  53. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/lockfile.py +0 -0
  54. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/logs.py +0 -0
  55. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/mcp.py +0 -0
  56. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/nethttp.py +0 -0
  57. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/output.py +0 -0
  58. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/paths.py +0 -0
  59. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/policy.py +0 -0
  60. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/rag.py +0 -0
  61. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/registry.py +0 -0
  62. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/secretscan.py +0 -0
  63. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/serve.py +0 -0
  64. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/stackprobe.py +0 -0
  65. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/staleness.py +0 -0
  66. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/typosquat.py +0 -0
  67. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/updatediff.py +0 -0
  68. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/core/util.py +0 -0
  69. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/data/registries.json +0 -0
  70. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/errors.py +0 -0
  71. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_cli/spin.py +0 -0
  72. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  73. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  74. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_skill_cli.egg-info/requires.txt +0 -0
  75. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/boost_skill_cli.egg-info/top_level.txt +0 -0
  76. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/.claude/settings.local.json +0 -0
  77. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/DEBUGGING.md +0 -0
  78. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/adapters.html +0 -0
  79. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/demo.gif +0 -0
  80. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/demo.tape +0 -0
  81. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/design-roadmap.html +0 -0
  82. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/eval.html +0 -0
  83. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/index.html +0 -0
  84. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/mcp-hub.html +0 -0
  85. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/rag-architecture.md +0 -0
  86. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D01.md +0 -0
  87. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D02.md +0 -0
  88. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D03.md +0 -0
  89. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D04.md +0 -0
  90. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D05.md +0 -0
  91. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D06.md +0 -0
  92. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D07.md +0 -0
  93. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D08.md +0 -0
  94. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D09.md +0 -0
  95. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D10.md +0 -0
  96. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D11.md +0 -0
  97. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D12.md +0 -0
  98. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D13.md +0 -0
  99. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D14.md +0 -0
  100. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D15.md +0 -0
  101. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D16.md +0 -0
  102. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D17.md +0 -0
  103. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D18.md +0 -0
  104. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D19.md +0 -0
  105. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D20.md +0 -0
  106. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D21.md +0 -0
  107. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D22.md +0 -0
  108. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D23.md +0 -0
  109. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D24.md +0 -0
  110. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D25.md +0 -0
  111. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/BOOST-D26.md +0 -0
  112. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  113. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  114. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  115. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  116. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  117. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  118. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  119. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  120. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  121. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  122. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  123. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  124. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  125. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  126. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  127. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  128. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  129. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  130. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  131. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  132. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  133. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  134. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  135. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  136. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  137. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  138. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  139. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  140. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  141. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  142. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  143. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  144. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  145. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  146. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  147. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  148. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  149. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  150. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  151. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  152. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  153. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  154. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  155. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  156. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  157. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  158. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  159. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  160. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  161. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  162. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  163. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  164. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  165. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  166. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  167. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  168. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  169. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  170. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  171. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  172. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  173. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  174. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  175. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  176. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  177. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  178. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  179. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  180. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  181. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  182. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  183. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  184. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  185. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  186. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  187. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  188. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  189. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  190. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  191. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  192. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  193. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  194. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  195. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  196. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  197. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  198. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  199. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  200. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  201. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  202. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  203. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  204. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  205. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  206. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  207. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  208. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  209. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  210. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  211. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  212. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  213. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  214. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  215. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  216. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  217. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  218. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/docs/roadmap/items/workspace-scope-install.md +0 -0
  219. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/examples/README.md +0 -0
  220. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/examples/adapt-demo.sh +0 -0
  221. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/examples/boost-run-prototype.sh +0 -0
  222. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/index.html +0 -0
  223. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/pyproject.toml +0 -0
  224. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/scripts/build_registries.py +0 -0
  225. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/scripts/build_roadmap.py +0 -0
  226. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/scripts/ensure_eval_corpus.sh +0 -0
  227. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/scripts/eval_explain.py +0 -0
  228. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/scripts/eval_recommend.py +0 -0
  229. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/scripts/eval_retrieval.py +0 -0
  230. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/scripts/mutation_gate.py +0 -0
  231. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/setup.cfg +0 -0
  232. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/style/README.md +0 -0
  233. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/style/boost.css +0 -0
  234. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/style/boost.js +0 -0
  235. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/style/demo.html +0 -0
  236. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/conftest.py +0 -0
  237. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/eval/baseline.json +0 -0
  238. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/eval/explain.jsonl +0 -0
  239. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/eval/golden.jsonl +0 -0
  240. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/eval/recommend.jsonl +0 -0
  241. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/eval/taps.txt +0 -0
  242. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_adapt.py +0 -0
  243. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_bmad.py +0 -0
  244. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_configuration.py +0 -0
  245. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_discovery.py +0 -0
  246. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_hooks.py +0 -0
  247. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_info.py +0 -0
  248. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_intelligence.py +0 -0
  249. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_quality.py +0 -0
  250. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_taps.py +0 -0
  251. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_cli_team.py +0 -0
  252. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_everyday_loop.py +0 -0
  253. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/functional/test_property_parsers.py +0 -0
  254. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/make_fixture.py +0 -0
  255. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/smoke.sh +0 -0
  256. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_adapters.py +0 -0
  257. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_agents.py +0 -0
  258. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_ai.py +0 -0
  259. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_catalog.py +0 -0
  260. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_claude_settings.py +0 -0
  261. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_cliparse.py +0 -0
  262. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_config.py +0 -0
  263. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_dense.py +0 -0
  264. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_dense_fallback.py +0 -0
  265. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_docs_pages_linked.py +0 -0
  266. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_embed.py +0 -0
  267. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_errors_and_cli_table.py +0 -0
  268. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_frontmatter.py +0 -0
  269. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_gitutil.py +0 -0
  270. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_imperative.py +0 -0
  271. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_injectscan.py +0 -0
  272. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_journal.py +0 -0
  273. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_lockfile.py +0 -0
  274. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_logs.py +0 -0
  275. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_mcp.py +0 -0
  276. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_mutation_hardening.py +0 -0
  277. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_nethttp.py +0 -0
  278. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_output.py +0 -0
  279. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_paths.py +0 -0
  280. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_pkg_confusions.py +0 -0
  281. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_pkg_injection.py +0 -0
  282. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_pkg_secrets.py +0 -0
  283. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_policy.py +0 -0
  284. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_rag.py +0 -0
  285. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_registries_fresh.py +0 -0
  286. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_registry.py +0 -0
  287. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_roadmap_fresh.py +0 -0
  288. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_secretscan.py +0 -0
  289. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_serve.py +0 -0
  290. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_spin.py +0 -0
  291. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_stackprobe.py +0 -0
  292. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_staleness.py +0 -0
  293. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_token_parity.py +0 -0
  294. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_typosquat.py +0 -0
  295. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_updatediff.py +0 -0
  296. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_util.py +0 -0
  297. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.148}/tests/unit/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.147
3
+ Version: 1.0.148
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.0.147'
22
- __version_tuple__ = version_tuple = (1, 0, 147)
21
+ __version__ = version = '1.0.148'
22
+ __version_tuple__ = version_tuple = (1, 0, 148)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -118,7 +118,9 @@ def _warn_secrets(res: store.InstallResult) -> None:
118
118
  def _report_result(res: store.InstallResult) -> None:
119
119
  """The canonical three-line install report."""
120
120
  if res.kind in ("rule", "workflow"):
121
- out.ok("materialized %s" % (" · ".join(res.linked) or "(no enabled agents)"))
121
+ where = " (this repo)" if res.scope == "project" else ""
122
+ out.ok("materialized%s → %s"
123
+ % (where, " · ".join(res.linked) or "(no enabled agents)"))
122
124
  out.ok("lock updated (.skill-lock.json)")
123
125
  _warn_injection(res)
124
126
  _warn_secrets(res)
@@ -166,6 +168,9 @@ def cmd_install(argv: List[str]) -> int:
166
168
  help="reinstall even if already installed or pinned")
167
169
  ap.add_argument("--agent", action="append", metavar="A",
168
170
  help="link only into this agent (repeatable)")
171
+ ap.add_argument("--scope", choices=("user", "project"), default="user",
172
+ help="rules/workflows: install into your user config (default) "
173
+ "or the current repo (project)")
169
174
  ap.add_argument("--dry-run", action="store_true",
170
175
  help="show what would happen without changing anything")
171
176
  args = ap.parse_args(argv)
@@ -191,8 +196,10 @@ def cmd_install(argv: List[str]) -> int:
191
196
  seen = (lockfile.get_rule if k == "rule"
192
197
  else lockfile.get_workflow)(e["name"])
193
198
  verb = "reinstall" if seen else "install"
194
- out.info("would %s %s %s v%s from %s" % (verb, k, e["name"],
195
- e["version"], e["tap"]))
199
+ where = "into this repo" if args.scope == "project" else "user config"
200
+ out.info("would %s %s %s v%s from %s (%s)" % (verb, k, e["name"],
201
+ e["version"], e["tap"],
202
+ where))
196
203
  out.info(" materialize → %s" % (" · ".join(targets)
197
204
  or "(no enabled agents)"))
198
205
  continue
@@ -210,7 +217,7 @@ def cmd_install(argv: List[str]) -> int:
210
217
  if multi:
211
218
  out.heading("%s v%s (%s)" % (e["name"], e["version"], e["tap"]))
212
219
  try:
213
- res = store.install(e, force=args.force, only_agents=only)
220
+ res = store.install(e, force=args.force, only_agents=only, scope=args.scope)
214
221
  except BoostError as err:
215
222
  if not multi:
216
223
  raise
@@ -414,7 +421,9 @@ def _update_materialized(kind: str, installed: Dict[str, dict], results) -> int:
414
421
  if not changed:
415
422
  continue
416
423
  try:
417
- store.install(entry, force=True)
424
+ # keep the item where it was installed (user vs a specific repo).
425
+ store.install(entry, force=True,
426
+ scope=lk.get("scope", "user"), base=lk.get("base"))
418
427
  except BoostError as err:
419
428
  out.warn("%s: %s" % (name, err.message))
420
429
  continue
@@ -15,7 +15,7 @@ the filesystem writes and the lock record so uninstall can reverse them.
15
15
  from __future__ import annotations
16
16
 
17
17
  from pathlib import Path
18
- from typing import Tuple
18
+ from typing import Optional, Tuple
19
19
 
20
20
  # Name-scoped managed-block markers for CLAUDE.md. Stable + per-rule so install
21
21
  # is idempotent (a re-install replaces the block) and uninstall strips exactly
@@ -40,17 +40,27 @@ def markers(name: str) -> Tuple[str, str]:
40
40
  return BLOCK_START % name, BLOCK_END % name
41
41
 
42
42
 
43
- def rule_target(agent: str, skills_dir: Path, name: str) -> Tuple[str, Path]:
44
- """Where rule ``name`` materializes for ``agent``, given its skills dir.
43
+ def rule_target(agent: str, skills_dir: Path, name: str,
44
+ base: "Optional[Path]" = None) -> Tuple[str, Path]:
45
+ """Where rule ``name`` materializes for ``agent``.
45
46
 
46
- Returns ``(mode, path)``: ``MODE_CLAUDE`` writes/merges the CLAUDE.md at the
47
- agent root; ``MODE_FILE`` drops a file into the agent's ``rules/`` dir. The
48
- agent root is the parent of its configured skills dir (``~/.cursor/skills``
49
- -> ``~/.cursor``), so no extra config is needed.
47
+ Returns ``(mode, path)``: ``MODE_CLAUDE`` writes/merges a CLAUDE.md;
48
+ ``MODE_FILE`` drops a file into the agent's ``rules/`` dir.
49
+
50
+ ``base`` selects the scope:
51
+ * ``None`` (user scope) — the agent's user config: the parent of its
52
+ configured skills dir (``~/.cursor/skills`` -> ``~/.cursor``), and
53
+ ``~/.claude/CLAUDE.md`` for Claude.
54
+ * a directory (project scope) — that repo: ``<base>/.cursor/rules/…`` and,
55
+ since Claude reads per-repo memory from the root, ``<base>/CLAUDE.local.md``
56
+ (the personal, git-ignored file) for Claude.
50
57
  """
51
- root = Path(skills_dir).parent
58
+ dotdir = Path(skills_dir).parent.name # ".claude" / ".cursor" / …
52
59
  if agent in CLAUDE_MD_AGENTS:
53
- return MODE_CLAUDE, root / "CLAUDE.md"
60
+ if base is not None:
61
+ return MODE_CLAUDE, Path(base) / "CLAUDE.local.md"
62
+ return MODE_CLAUDE, Path(skills_dir).parent / "CLAUDE.md"
63
+ root = (Path(base) / dotdir) if base is not None else Path(skills_dir).parent
54
64
  ext = RULE_DIR_EXT.get(agent, DEFAULT_RULE_EXT)
55
65
  return MODE_FILE, root / "rules" / (name + ext)
56
66
 
@@ -26,6 +26,7 @@ class InstallResult:
26
26
  score: int = 0
27
27
  upgraded: bool = False
28
28
  kind: str = "skill"
29
+ scope: str = "user" # "user" or "project" — where a rule/workflow landed
29
30
  # For rules/workflows the installed content is a single file (or a merged
30
31
  # CLAUDE.md block), not a SKILL.md tree — carry the raw source so the caller
31
32
  # scans exactly what it installed instead of a non-existent SKILL.md.
@@ -117,14 +118,32 @@ def _copy_skill(src: Path, dest: Path) -> None:
117
118
  shutil.rmtree(backup, ignore_errors=True)
118
119
 
119
120
 
121
+ def _resolve_base(scope: str, base) -> Optional[Path]:
122
+ """Directory a project-scoped install materializes under (the repo), or None
123
+ for user scope. An explicit ``base`` (e.g. from a lock record on update/sync)
124
+ wins so a re-materialization lands where the original install did, not in
125
+ whatever the current working directory happens to be."""
126
+ if base:
127
+ return Path(base)
128
+ return Path.cwd() if scope == "project" else None
129
+
130
+
120
131
  def install(entry: dict, force: bool = False,
121
- only_agents: Optional[List[str]] = None) -> InstallResult:
122
- """Install a catalog entry. Raises BoostError on policy block or conflict."""
132
+ only_agents: Optional[List[str]] = None,
133
+ scope: str = "user", base=None) -> InstallResult:
134
+ """Install a catalog entry. Raises BoostError on policy block or conflict.
135
+
136
+ ``scope`` is ``"user"`` (default — the agent's user config dirs) or
137
+ ``"project"`` (the current repo). Skills ignore scope (they always live in
138
+ the canonical store); rules/workflows honor it.
139
+ """
123
140
  kind = entry.get("kind", "skill")
124
141
  if kind == "rule":
125
- return _install_rule(entry, force=force, only_agents=only_agents)
142
+ return _install_rule(entry, force=force, only_agents=only_agents,
143
+ scope=scope, base=base)
126
144
  if kind == "workflow":
127
- return _install_workflow(entry, force=force, only_agents=only_agents)
145
+ return _install_workflow(entry, force=force, only_agents=only_agents,
146
+ scope=scope, base=base)
128
147
  if kind != "skill":
129
148
  raise BoostError(
130
149
  "%s is a %s, which boost does not know how to install" % (entry["name"], kind),
@@ -172,14 +191,16 @@ def install(entry: dict, force: bool = False,
172
191
 
173
192
 
174
193
  def _install_rule(entry: dict, force: bool = False,
175
- only_agents: Optional[List[str]] = None) -> InstallResult:
194
+ only_agents: Optional[List[str]] = None,
195
+ scope: str = "user", base=None) -> InstallResult:
176
196
  """Materialize a rule into each enabled agent's native format.
177
197
 
178
198
  Cursor/Windsurf/Cline get a verbatim file drop in their ``rules/`` dir
179
199
  (frontmatter preserved — it is native rule metadata); Claude Code has no
180
200
  rules folder, so the rule merges into ``CLAUDE.md`` as an idempotent managed
181
- block. Every materialization is recorded so ``uninstall`` reverses exactly
182
- what was written.
201
+ block. With ``scope="project"`` these land under the repo (and Claude uses
202
+ ``CLAUDE.local.md``). Every materialization is recorded so ``uninstall``
203
+ reverses exactly what was written.
183
204
  """
184
205
  import hashlib
185
206
 
@@ -204,13 +225,14 @@ def _install_rule(entry: dict, force: bool = False,
204
225
  meta, body = frontmatter.parse(raw)
205
226
  claude_body = rules.render_claude_body(str(meta.get("name") or name), body)
206
227
 
228
+ resolved_base = _resolve_base(scope, base)
207
229
  paths.ensure_dirs()
208
230
  materializations: List[dict] = []
209
231
  linked: List[str] = []
210
232
  for agent, skills_dir in agents.enabled_agents().items():
211
233
  if only_agents and agent not in only_agents:
212
234
  continue
213
- mode, path = rules.rule_target(agent, skills_dir, name)
235
+ mode, path = rules.rule_target(agent, skills_dir, name, base=resolved_base)
214
236
  path.parent.mkdir(parents=True, exist_ok=True)
215
237
  if mode == rules.MODE_CLAUDE:
216
238
  current = path.read_text(encoding="utf-8") if path.exists() else ""
@@ -228,6 +250,8 @@ def _install_rule(entry: dict, force: bool = False,
228
250
  "source_file": entry.get("skill_md", ""),
229
251
  "commit": gitutil.head_commit(tap.path),
230
252
  "sha256": hashlib.sha256(raw.encode("utf-8")).hexdigest(),
253
+ "scope": scope,
254
+ "base": str(resolved_base) if resolved_base is not None else None,
231
255
  "installed_at": (existing or {}).get("installed_at", now),
232
256
  "updated_at": now,
233
257
  "materializations": materializations,
@@ -240,6 +264,7 @@ def _install_rule(entry: dict, force: bool = False,
240
264
  kind="rule", scan_text=raw)
241
265
  res.linked = linked
242
266
  res.upgraded = existing is not None
267
+ res.scope = scope
243
268
  return res
244
269
 
245
270
 
@@ -266,12 +291,14 @@ def _uninstall_rule(name: str, rule: dict) -> dict:
266
291
 
267
292
 
268
293
  def _install_workflow(entry: dict, force: bool = False,
269
- only_agents: Optional[List[str]] = None) -> InstallResult:
294
+ only_agents: Optional[List[str]] = None,
295
+ scope: str = "user", base=None) -> InstallResult:
270
296
  """Materialize a workflow (slash command / subagent) into each enabled agent.
271
297
 
272
298
  A verbatim Markdown drop into the agent's ``commands/`` or ``agents/`` dir —
273
- the slot derived from the source path — with no transformation. Every drop is
274
- recorded so ``uninstall`` removes exactly the files it wrote.
299
+ the slot derived from the source path — with no transformation. With
300
+ ``scope="project"`` the drop lands under the repo (``<repo>/.claude/…``).
301
+ Every drop is recorded so ``uninstall`` removes exactly the files it wrote.
275
302
  """
276
303
  import hashlib
277
304
 
@@ -296,13 +323,14 @@ def _install_workflow(entry: dict, force: bool = False,
296
323
  raw = src.read_text(encoding="utf-8", errors="replace")
297
324
  slot = workflows.detect_slot(source_rel)
298
325
 
326
+ resolved_base = _resolve_base(scope, base)
299
327
  paths.ensure_dirs()
300
328
  materializations: List[dict] = []
301
329
  linked: List[str] = []
302
330
  for agent, skills_dir in agents.enabled_agents().items():
303
331
  if only_agents and agent not in only_agents:
304
332
  continue
305
- path = workflows.workflow_target(skills_dir, slot, name)
333
+ path = workflows.workflow_target(skills_dir, slot, name, base=resolved_base)
306
334
  path.parent.mkdir(parents=True, exist_ok=True)
307
335
  util.atomic_write_text(path, raw)
308
336
  materializations.append({"agent": agent, "slot": slot, "path": str(path)})
@@ -317,6 +345,8 @@ def _install_workflow(entry: dict, force: bool = False,
317
345
  "source_file": source_rel,
318
346
  "commit": gitutil.head_commit(tap.path),
319
347
  "sha256": hashlib.sha256(raw.encode("utf-8")).hexdigest(),
348
+ "scope": scope,
349
+ "base": str(resolved_base) if resolved_base is not None else None,
320
350
  "installed_at": (existing or {}).get("installed_at", now),
321
351
  "updated_at": now,
322
352
  "materializations": materializations,
@@ -329,6 +359,7 @@ def _install_workflow(entry: dict, force: bool = False,
329
359
  kind="workflow", scan_text=raw)
330
360
  res.linked = linked
331
361
  res.upgraded = existing is not None
362
+ res.scope = scope
332
363
  return res
333
364
 
334
365
 
@@ -506,7 +537,10 @@ def sync_apply(plan: Dict[str, list]) -> List[str]:
506
537
  matches = [e for e in catalog.find(name)
507
538
  if e["tap"] == tap_name and e.get("kind", "skill") == kind]
508
539
  if matches:
509
- install(matches[0], force=True)
540
+ # preserve the original scope/base so a project rule repairs
541
+ # into its repo, not wherever sync happens to run.
542
+ install(matches[0], force=True,
543
+ scope=entry.get("scope", "user"), base=entry.get("base"))
510
544
  actions.append("re-materialized %s %s from %s"
511
545
  % (kind, name, tap_name))
512
546
  continue
@@ -14,6 +14,7 @@ the filesystem writes and the lock record so uninstall can reverse them.
14
14
  from __future__ import annotations
15
15
 
16
16
  from pathlib import Path
17
+ from typing import Optional
17
18
 
18
19
  SLOT_COMMANDS = "commands"
19
20
  SLOT_AGENTS = "agents"
@@ -36,11 +37,16 @@ def detect_slot(source_rel: str) -> str:
36
37
  return SLOT_AGENTS if parts & AGENT_DIRS else SLOT_COMMANDS
37
38
 
38
39
 
39
- def workflow_target(skills_dir: Path, slot: str, name: str) -> Path:
40
+ def workflow_target(skills_dir: Path, slot: str, name: str,
41
+ base: Optional[Path] = None) -> Path:
40
42
  """Where workflow ``name`` (in ``slot``) materializes for an agent.
41
43
 
42
- The agent root is the parent of its configured skills dir
43
- (``~/.claude/skills`` -> ``~/.claude``), so the file lands at
44
- ``<root>/<slot>/<name>.md`` with no extra config.
44
+ ``base`` selects the scope:
45
+ * ``None`` (user scope) the parent of the agent's configured skills dir
46
+ (``~/.claude/skills`` -> ``~/.claude/<slot>/<name>.md``).
47
+ * a directory (project scope) — that repo's per-agent dotdir
48
+ (``<base>/.claude/<slot>/<name>.md``).
45
49
  """
46
- return Path(skills_dir).parent / slot / (name + ".md")
50
+ root = (Path(base) / Path(skills_dir).parent.name) if base is not None \
51
+ else Path(skills_dir).parent
52
+ return root / slot / (name + ".md")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.147
3
+ Version: 1.0.148
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -141,6 +141,7 @@ docs/roadmap/items/github-pages-deploy-is-broken-every-push.md
141
141
  docs/roadmap/items/golden-set-statistical-power.md
142
142
  docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md
143
143
  docs/roadmap/items/html-validation-html-validate.md
144
+ docs/roadmap/items/install-scope-user-or-project.md
144
145
  docs/roadmap/items/integrity-verification-boost-verify.md
145
146
  docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md
146
147
  docs/roadmap/items/layering-guard-import-linter.md
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: install-scope-user-or-project
3
+ board: code
4
+ section: internals
5
+ status: shipped
6
+ category: Install engine · UX
7
+ complexity: M
8
+ impact: High
9
+ wow: 3
10
+ note: rules/workflows were user-global only
11
+ order: 27
12
+ owner: loop/install-scope
13
+ pr: 169
14
+ title: <code>boost install --scope user|project</code> for rules/workflows
15
+ ---
16
+ Rule and workflow install always materialized into user-global agent config
17
+ (<code>~/.claude/CLAUDE.md</code>, <code>~/.cursor/rules</code>, …), so a
18
+ rule meant for one repo leaked into every session. Add
19
+ <code>--scope project</code>: materialize into the current repo instead —
20
+ <code>&lt;repo&gt;/.cursor/rules/</code>, <code>&lt;repo&gt;/.claude/commands|agents/</code>,
21
+ and, since Claude reads per-repo memory from the root and has no rules
22
+ folder, <code>&lt;repo&gt;/CLAUDE.local.md</code> (the personal, git-ignored
23
+ file). The chosen scope + base dir are recorded in the lock so
24
+ <code>update</code>/<code>sync</code> re-materialize back into the same
25
+ repo rather than wherever they happen to run. Default stays
26
+ <code>--scope user</code> (unchanged behavior). Uninstall already reverses
27
+ by recorded path, so it works for either scope.
@@ -118,7 +118,7 @@
118
118
  <div class="stat"><b>16</b><span>Shipped</span></div>
119
119
  <div class="stat"><b>1</b><span>Next up</span></div>
120
120
  <div class="stat"><b>4</b><span>Planned</span></div>
121
- <div class="stat"><b>107</b><span>Loop finds</span></div>
121
+ <div class="stat"><b>108</b><span>Loop finds</span></div>
122
122
  <!-- /ROADMAP:stats -->
123
123
  </div>
124
124
  </section>
@@ -840,6 +840,29 @@ chunks instead cost ~70%.</p>
840
840
  <span class="m">close the last skill-only gaps for rules/workflows</span>
841
841
  </div>
842
842
  </article>
843
+
844
+ <article class="cap rcard">
845
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Install engine · UX</span></div>
846
+ <h3><code>boost install --scope user|project</code> for rules/workflows</h3>
847
+ <p>Rule and workflow install always materialized into user-global agent config
848
+ (<code>~/.claude/CLAUDE.md</code>, <code>~/.cursor/rules</code>, …), so a
849
+ rule meant for one repo leaked into every session. Add
850
+ <code>--scope project</code>: materialize into the current repo instead —
851
+ <code>&lt;repo&gt;/.cursor/rules/</code>, <code>&lt;repo&gt;/.claude/commands|agents/</code>,
852
+ and, since Claude reads per-repo memory from the root and has no rules
853
+ folder, <code>&lt;repo&gt;/CLAUDE.local.md</code> (the personal, git-ignored
854
+ file). The chosen scope + base dir are recorded in the lock so
855
+ <code>update</code>/<code>sync</code> re-materialize back into the same
856
+ repo rather than wherever they happen to run. Default stays
857
+ <code>--scope user</code> (unchanged behavior). Uninstall already reverses
858
+ by recorded path, so it works for either scope.</p>
859
+ <div class="meta">
860
+ <span class="m">Complexity <b>M</b></span>
861
+ <span class="m hi">Impact <b>High</b></span>
862
+ <span class="m">Wow <b class="wow">★★★</b></span>
863
+ <span class="m">rules/workflows were user-global only</span>
864
+ </div>
865
+ </article>
843
866
  <!-- /ROADMAP:cards -->
844
867
 
845
868
  </div>
@@ -68,6 +68,22 @@ class TestInstall:
68
68
  assert "suspicious pattern" in r.out
69
69
  assert "in rule content" in r.out # not "in SKILL.md"
70
70
 
71
+ def test_rule_scope_project_lands_in_repo_not_global(self, boost,
72
+ fixture_tap_src,
73
+ tmp_path, monkeypatch):
74
+ tap_dir = _copy_tap(fixture_tap_src, tmp_path / "sp-tap")
75
+ _add_and_commit(tap_dir, "rules/team.mdc",
76
+ "---\nname: team-rules\n---\n\nAlways TDD.\n", "add rule")
77
+ boost("tap", tap_dir)
78
+ repo = tmp_path / "proj"
79
+ repo.mkdir()
80
+ monkeypatch.chdir(repo) # project scope == cwd
81
+ r = boost("install", "team-rules", "--scope", "project")
82
+ assert "materialized (this repo)" in r.out
83
+ assert (repo / "CLAUDE.local.md").is_file() # Claude -> personal repo file
84
+ assert (repo / ".cursor" / "rules" / "team-rules.mdc").is_file()
85
+ assert not (paths.home() / ".claude" / "CLAUDE.md").exists() # not global
86
+
71
87
  def test_exact_report_lines(self, boost, tapped):
72
88
  r = boost("install", "brainstorming")
73
89
  assert "copied to ~/.agents/skills/brainstorming" in r.out
@@ -43,6 +43,24 @@ class TestRuleTarget:
43
43
  assert mode == rules.MODE_FILE
44
44
  assert path == Path("/h/.zed/rules/r.md")
45
45
 
46
+ # --- project scope (base=<repo>) ---
47
+ def test_project_claude_uses_claude_local_md_at_repo_root(self):
48
+ mode, path = rules.rule_target("claude-code", Path("/h/.claude/skills"),
49
+ "r", base=Path("/repo"))
50
+ assert mode == rules.MODE_CLAUDE
51
+ assert path == Path("/repo/CLAUDE.local.md") # personal, not ~/.claude
52
+
53
+ def test_project_cursor_uses_repo_dotcursor_rules(self):
54
+ mode, path = rules.rule_target("cursor", Path("/h/.cursor/skills"),
55
+ "r", base=Path("/repo"))
56
+ assert mode == rules.MODE_FILE
57
+ assert path == Path("/repo/.cursor/rules/r.mdc")
58
+
59
+ def test_project_windsurf_uses_repo_dotwindsurf(self):
60
+ _mode, path = rules.rule_target("windsurf", Path("/h/.windsurf/skills"),
61
+ "r", base=Path("/repo"))
62
+ assert path == Path("/repo/.windsurf/rules/r.md")
63
+
46
64
 
47
65
  class TestRenderClaudeBody:
48
66
  def test_title_header_then_body(self):
@@ -700,3 +700,51 @@ class TestSyncMaterializations:
700
700
  res = store.install(_workflow_entry(tap))
701
701
  assert res.scan_text is not None
702
702
  assert "Run the release." in res.scan_text
703
+
704
+
705
+ class TestInstallScope:
706
+ def test_resolve_base(self):
707
+ from pathlib import Path as P
708
+ assert store._resolve_base("user", None) is None
709
+ assert store._resolve_base("project", None) == P.cwd()
710
+ assert store._resolve_base("project", "/x") == P("/x")
711
+
712
+ def test_rule_project_scope_materializes_under_base(self, tap, tmp_path):
713
+ repo = tmp_path / "repo"
714
+ repo.mkdir()
715
+ res = store.install(_rule_entry(tap), scope="project", base=str(repo))
716
+ assert res.scope == "project"
717
+ # Claude -> personal repo file, not ~/.claude/CLAUDE.md
718
+ cm = repo / "CLAUDE.local.md"
719
+ assert cm.is_file()
720
+ assert "boost:rule:team-conventions start" in cm.read_text()
721
+ assert (repo / ".cursor" / "rules" / "team-conventions.mdc").is_file()
722
+ assert (repo / ".windsurf" / "rules" / "team-conventions.md").is_file()
723
+ assert not (paths.home() / ".claude" / "CLAUDE.md").exists() # not global
724
+ rec = lockfile.get_rule("team-conventions")
725
+ assert rec["scope"] == "project"
726
+ assert rec["base"] == str(repo)
727
+
728
+ def test_workflow_project_scope_under_base(self, tap, tmp_path):
729
+ repo = tmp_path / "repo2"
730
+ repo.mkdir()
731
+ store.install(_workflow_entry(tap), scope="project", base=str(repo))
732
+ assert (repo / ".claude" / "commands" / "ship-it.md").is_file()
733
+ assert not (paths.home() / ".claude" / "commands" / "ship-it.md").exists()
734
+ assert lockfile.get_workflow("ship-it")["base"] == str(repo)
735
+
736
+ def test_user_scope_is_default_and_global(self, tap):
737
+ res = store.install(_rule_entry(tap))
738
+ assert res.scope == "user"
739
+ assert (paths.home() / ".claude" / "CLAUDE.md").is_file()
740
+ rec = lockfile.get_rule("team-conventions")
741
+ assert rec["scope"] == "user" and rec["base"] is None
742
+
743
+ def test_project_uninstall_reverses_repo_files(self, tap, tmp_path):
744
+ repo = tmp_path / "repo3"
745
+ repo.mkdir()
746
+ store.install(_rule_entry(tap), scope="project", base=str(repo))
747
+ store.uninstall("team-conventions")
748
+ assert not (repo / ".cursor" / "rules" / "team-conventions.mdc").exists()
749
+ assert not (repo / "CLAUDE.local.md").exists() # held only our block
750
+ assert lockfile.get_rule("team-conventions") is None
@@ -47,3 +47,13 @@ class TestWorkflowTarget:
47
47
  def test_uses_configured_skills_dir_parent(self):
48
48
  p = workflows.workflow_target(Path("/opt/cursor/skills"), "commands", "x")
49
49
  assert p == Path("/opt/cursor/commands/x.md")
50
+
51
+ def test_project_scope_lands_under_repo_dotdir(self):
52
+ p = workflows.workflow_target(Path("/h/.claude/skills"), "commands",
53
+ "ship", base=Path("/repo"))
54
+ assert p == Path("/repo/.claude/commands/ship.md")
55
+
56
+ def test_project_scope_subagent_under_repo(self):
57
+ p = workflows.workflow_target(Path("/h/.claude/skills"), "agents",
58
+ "rev", base=Path("/repo"))
59
+ assert p == Path("/repo/.claude/agents/rev.md")