@ahmed-g-gad/apothem 0.1.1

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 (674) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/LICENSES/MIT.txt +18 -0
  4. package/LICENSES/PSF-2.0.txt +47 -0
  5. package/README.md +549 -0
  6. package/bin/README.md +37 -0
  7. package/bin/apothem.mjs +78 -0
  8. package/package.json +75 -0
  9. package/pyproject.toml +347 -0
  10. package/src/apothem/README.md +52 -0
  11. package/src/apothem/__init__.py +66 -0
  12. package/src/apothem/__main__.py +28 -0
  13. package/src/apothem/_vendor/.keep +0 -0
  14. package/src/apothem/_vendor/__init__.py +25 -0
  15. package/src/apothem/_vendor/attr/__init__.py +104 -0
  16. package/src/apothem/_vendor/attr/__init__.pyi +389 -0
  17. package/src/apothem/_vendor/attr/_cmp.py +160 -0
  18. package/src/apothem/_vendor/attr/_cmp.pyi +13 -0
  19. package/src/apothem/_vendor/attr/_compat.py +99 -0
  20. package/src/apothem/_vendor/attr/_config.py +31 -0
  21. package/src/apothem/_vendor/attr/_funcs.py +497 -0
  22. package/src/apothem/_vendor/attr/_make.py +3406 -0
  23. package/src/apothem/_vendor/attr/_next_gen.py +674 -0
  24. package/src/apothem/_vendor/attr/_typing_compat.pyi +15 -0
  25. package/src/apothem/_vendor/attr/_version_info.py +89 -0
  26. package/src/apothem/_vendor/attr/_version_info.pyi +9 -0
  27. package/src/apothem/_vendor/attr/converters.py +162 -0
  28. package/src/apothem/_vendor/attr/converters.pyi +19 -0
  29. package/src/apothem/_vendor/attr/exceptions.py +95 -0
  30. package/src/apothem/_vendor/attr/exceptions.pyi +17 -0
  31. package/src/apothem/_vendor/attr/filters.py +72 -0
  32. package/src/apothem/_vendor/attr/filters.pyi +6 -0
  33. package/src/apothem/_vendor/attr/py.typed +0 -0
  34. package/src/apothem/_vendor/attr/setters.py +79 -0
  35. package/src/apothem/_vendor/attr/setters.pyi +20 -0
  36. package/src/apothem/_vendor/attr/validators.py +750 -0
  37. package/src/apothem/_vendor/attr/validators.pyi +140 -0
  38. package/src/apothem/_vendor/attr.LICENSE +21 -0
  39. package/src/apothem/_vendor/attrs/__init__.py +72 -0
  40. package/src/apothem/_vendor/attrs/__init__.pyi +314 -0
  41. package/src/apothem/_vendor/attrs/converters.py +3 -0
  42. package/src/apothem/_vendor/attrs/exceptions.py +3 -0
  43. package/src/apothem/_vendor/attrs/filters.py +3 -0
  44. package/src/apothem/_vendor/attrs/py.typed +0 -0
  45. package/src/apothem/_vendor/attrs/setters.py +3 -0
  46. package/src/apothem/_vendor/attrs/validators.py +3 -0
  47. package/src/apothem/_vendor/attrs.LICENSE +21 -0
  48. package/src/apothem/_vendor/jsonschema/__init__.py +120 -0
  49. package/src/apothem/_vendor/jsonschema/__main__.py +6 -0
  50. package/src/apothem/_vendor/jsonschema/_format.py +546 -0
  51. package/src/apothem/_vendor/jsonschema/_keywords.py +449 -0
  52. package/src/apothem/_vendor/jsonschema/_legacy_keywords.py +449 -0
  53. package/src/apothem/_vendor/jsonschema/_types.py +204 -0
  54. package/src/apothem/_vendor/jsonschema/_typing.py +29 -0
  55. package/src/apothem/_vendor/jsonschema/_utils.py +355 -0
  56. package/src/apothem/_vendor/jsonschema/benchmarks/__init__.py +5 -0
  57. package/src/apothem/_vendor/jsonschema/benchmarks/const_vs_enum.py +30 -0
  58. package/src/apothem/_vendor/jsonschema/benchmarks/contains.py +28 -0
  59. package/src/apothem/_vendor/jsonschema/benchmarks/import_benchmark.py +31 -0
  60. package/src/apothem/_vendor/jsonschema/benchmarks/issue232/issue.json +2653 -0
  61. package/src/apothem/_vendor/jsonschema/benchmarks/issue232.py +25 -0
  62. package/src/apothem/_vendor/jsonschema/benchmarks/json_schema_test_suite.py +12 -0
  63. package/src/apothem/_vendor/jsonschema/benchmarks/nested_schemas.py +56 -0
  64. package/src/apothem/_vendor/jsonschema/benchmarks/subcomponents.py +42 -0
  65. package/src/apothem/_vendor/jsonschema/benchmarks/unused_registry.py +35 -0
  66. package/src/apothem/_vendor/jsonschema/benchmarks/useless_applicator_schemas.py +106 -0
  67. package/src/apothem/_vendor/jsonschema/benchmarks/useless_keywords.py +32 -0
  68. package/src/apothem/_vendor/jsonschema/benchmarks/validator_creation.py +14 -0
  69. package/src/apothem/_vendor/jsonschema/cli.py +292 -0
  70. package/src/apothem/_vendor/jsonschema/exceptions.py +490 -0
  71. package/src/apothem/_vendor/jsonschema/protocols.py +230 -0
  72. package/src/apothem/_vendor/jsonschema/validators.py +1410 -0
  73. package/src/apothem/_vendor/jsonschema.LICENSE +19 -0
  74. package/src/apothem/_vendor/jsonschema_specifications/__init__.py +12 -0
  75. package/src/apothem/_vendor/jsonschema_specifications/_core.py +38 -0
  76. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/metaschema.json +42 -0
  77. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/applicator +56 -0
  78. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/content +17 -0
  79. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/core +57 -0
  80. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/format +14 -0
  81. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data +37 -0
  82. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/validation +98 -0
  83. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/metaschema.json +58 -0
  84. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/applicator +48 -0
  85. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/content +17 -0
  86. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/core +51 -0
  87. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation +14 -0
  88. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion +14 -0
  89. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data +37 -0
  90. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated +15 -0
  91. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/validation +98 -0
  92. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft3/metaschema.json +172 -0
  93. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft4/metaschema.json +149 -0
  94. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft6/metaschema.json +153 -0
  95. package/src/apothem/_vendor/jsonschema_specifications/schemas/draft7/metaschema.json +166 -0
  96. package/src/apothem/_vendor/jsonschema_specifications.LICENSE +19 -0
  97. package/src/apothem/_vendor/referencing/__init__.py +7 -0
  98. package/src/apothem/_vendor/referencing/_attrs.py +31 -0
  99. package/src/apothem/_vendor/referencing/_attrs.pyi +21 -0
  100. package/src/apothem/_vendor/referencing/_core.py +739 -0
  101. package/src/apothem/_vendor/referencing/exceptions.py +165 -0
  102. package/src/apothem/_vendor/referencing/jsonschema.py +642 -0
  103. package/src/apothem/_vendor/referencing/py.typed +0 -0
  104. package/src/apothem/_vendor/referencing/retrieval.py +94 -0
  105. package/src/apothem/_vendor/referencing/typing.py +61 -0
  106. package/src/apothem/_vendor/referencing.LICENSE +19 -0
  107. package/src/apothem/_vendor/rpds/__init__.py +251 -0
  108. package/src/apothem/_vendor/typing_extensions.LICENSE +279 -0
  109. package/src/apothem/_vendor/typing_extensions.py +4317 -0
  110. package/src/apothem/_vendor/vendor.txt +22 -0
  111. package/src/apothem/_vendor/yaml/__init__.py +389 -0
  112. package/src/apothem/_vendor/yaml/composer.py +138 -0
  113. package/src/apothem/_vendor/yaml/constructor.py +748 -0
  114. package/src/apothem/_vendor/yaml/cyaml.py +100 -0
  115. package/src/apothem/_vendor/yaml/dumper.py +61 -0
  116. package/src/apothem/_vendor/yaml/emitter.py +1137 -0
  117. package/src/apothem/_vendor/yaml/error.py +74 -0
  118. package/src/apothem/_vendor/yaml/events.py +85 -0
  119. package/src/apothem/_vendor/yaml/loader.py +63 -0
  120. package/src/apothem/_vendor/yaml/nodes.py +48 -0
  121. package/src/apothem/_vendor/yaml/parser.py +588 -0
  122. package/src/apothem/_vendor/yaml/reader.py +185 -0
  123. package/src/apothem/_vendor/yaml/representer.py +388 -0
  124. package/src/apothem/_vendor/yaml/resolver.py +226 -0
  125. package/src/apothem/_vendor/yaml/scanner.py +1435 -0
  126. package/src/apothem/_vendor/yaml/serializer.py +110 -0
  127. package/src/apothem/_vendor/yaml/tokens.py +103 -0
  128. package/src/apothem/_vendor/yaml.LICENSE +20 -0
  129. package/src/apothem/agents/README.md +60 -0
  130. package/src/apothem/agents/codebase-explorer.md +91 -0
  131. package/src/apothem/agents/convention-auditor.md +93 -0
  132. package/src/apothem/agents/dependency-auditor.md +97 -0
  133. package/src/apothem/agents/fact-checker.md +84 -0
  134. package/src/apothem/agents/mcp-builder.md +86 -0
  135. package/src/apothem/agents/memory-auditor.md +93 -0
  136. package/src/apothem/agents/prompt-evaluator.md +87 -0
  137. package/src/apothem/agents/quality-gate.md +103 -0
  138. package/src/apothem/agents/refactor-surgeon.md +74 -0
  139. package/src/apothem/agents/research-scout.md +73 -0
  140. package/src/apothem/agents/security-scanner.md +83 -0
  141. package/src/apothem/agents/test-runner.md +84 -0
  142. package/src/apothem/audit/README.md +73 -0
  143. package/src/apothem/audit/_scan_lib.py +182 -0
  144. package/src/apothem/audit/analyze_graph.py +260 -0
  145. package/src/apothem/audit/build_capability_graph.py +607 -0
  146. package/src/apothem/audit/build_inventory.py +657 -0
  147. package/src/apothem/audit/build_plans_provenance.py +997 -0
  148. package/src/apothem/audit/check_links.py +389 -0
  149. package/src/apothem/audit/classify_artifacts.py +381 -0
  150. package/src/apothem/audit/deprecated-tokens.txt +10 -0
  151. package/src/apothem/audit/execute_plans_migration.py +491 -0
  152. package/src/apothem/audit/known-projects.txt +15 -0
  153. package/src/apothem/audit/render_capability_index.py +467 -0
  154. package/src/apothem/audit/render_inventory.py +405 -0
  155. package/src/apothem/audit/scan_ai_surfaces.py +1125 -0
  156. package/src/apothem/audit/scan_ai_surfaces_coarse.py +261 -0
  157. package/src/apothem/audit/scan_drift_features.py +143 -0
  158. package/src/apothem/audit/scan_frontmatter.py +293 -0
  159. package/src/apothem/audit/scan_header_coverage.py +1134 -0
  160. package/src/apothem/audit/scan_plan_leakage.py +540 -0
  161. package/src/apothem/audit/scan_plans_discipline.py +188 -0
  162. package/src/apothem/audit/scan_secrets_pii.py +245 -0
  163. package/src/apothem/audit/scan_stale_tokens.py +296 -0
  164. package/src/apothem/audit/synthesize_drift.py +205 -0
  165. package/src/apothem/benchmarks/README.md +33 -0
  166. package/src/apothem/benchmarks/__init__.py +3 -0
  167. package/src/apothem/benchmarks/bench_agents.py +63 -0
  168. package/src/apothem/benchmarks/bench_hooks.py +93 -0
  169. package/src/apothem/benchmarks/bench_install.py +58 -0
  170. package/src/apothem/benchmarks/bench_tests.py +93 -0
  171. package/src/apothem/benchmarks/bench_validate_ecosystem.py +84 -0
  172. package/src/apothem/cli/README.md +33 -0
  173. package/src/apothem/cli/__init__.py +229 -0
  174. package/src/apothem/cli/_cmd_completion.py +88 -0
  175. package/src/apothem/cli/_cmd_diff.py +181 -0
  176. package/src/apothem/cli/_cmd_doctor.py +143 -0
  177. package/src/apothem/cli/_cmd_harnesses.py +167 -0
  178. package/src/apothem/cli/_cmd_install.py +327 -0
  179. package/src/apothem/cli/_cmd_migrate_workspace.py +143 -0
  180. package/src/apothem/cli/_cmd_profile.py +341 -0
  181. package/src/apothem/cli/_cmd_status.py +180 -0
  182. package/src/apothem/cli/_cmd_uninstall.py +215 -0
  183. package/src/apothem/cli/_cmd_update.py +397 -0
  184. package/src/apothem/cli/_cmd_verify.py +194 -0
  185. package/src/apothem/cli/_common_flags.py +90 -0
  186. package/src/apothem/cli/_epilogs.py +296 -0
  187. package/src/apothem/cli/_helpers.py +857 -0
  188. package/src/apothem/cli/_json_formatter.py +21 -0
  189. package/src/apothem/cli/_materialize.py +376 -0
  190. package/src/apothem/cli/completions/apothem.bash +30 -0
  191. package/src/apothem/cli/completions/apothem.fish +19 -0
  192. package/src/apothem/cli/completions/apothem.ps1 +27 -0
  193. package/src/apothem/cli/completions/apothem.zsh +42 -0
  194. package/src/apothem/cli/reference_export.py +126 -0
  195. package/src/apothem/commands/README.md +125 -0
  196. package/src/apothem/commands/a11y-audit.md +203 -0
  197. package/src/apothem/commands/architecture-review.md +194 -0
  198. package/src/apothem/commands/audit.md +165 -0
  199. package/src/apothem/commands/code-audit.md +218 -0
  200. package/src/apothem/commands/code-review.md +193 -0
  201. package/src/apothem/commands/dependency-audit.md +209 -0
  202. package/src/apothem/commands/docs-review.md +199 -0
  203. package/src/apothem/commands/elevate.md +285 -0
  204. package/src/apothem/commands/eval.md +149 -0
  205. package/src/apothem/commands/fortress.md +172 -0
  206. package/src/apothem/commands/freshify.md +168 -0
  207. package/src/apothem/commands/github-deploy-fresh.md +178 -0
  208. package/src/apothem/commands/github-deploy-next.md +167 -0
  209. package/src/apothem/commands/perf-audit.md +198 -0
  210. package/src/apothem/commands/plan-amend.md +104 -0
  211. package/src/apothem/commands/plan-audit.md +127 -0
  212. package/src/apothem/commands/plan-design.md +257 -0
  213. package/src/apothem/commands/plan-execute.md +495 -0
  214. package/src/apothem/commands/plan-generate.md +351 -0
  215. package/src/apothem/commands/plan-review.md +555 -0
  216. package/src/apothem/commands/plan-spec.md +359 -0
  217. package/src/apothem/commands/plan-status.md +222 -0
  218. package/src/apothem/commands/plan.md +173 -0
  219. package/src/apothem/commands/projectify.md +142 -0
  220. package/src/apothem/commands/release-readiness.md +142 -0
  221. package/src/apothem/commands/research-analysis.md +241 -0
  222. package/src/apothem/commands/research-design.md +231 -0
  223. package/src/apothem/commands/research-disseminate.md +225 -0
  224. package/src/apothem/commands/research-experiment.md +232 -0
  225. package/src/apothem/commands/research-ideate.md +213 -0
  226. package/src/apothem/commands/research-paper.md +252 -0
  227. package/src/apothem/commands/research-proposal.md +220 -0
  228. package/src/apothem/commands/research-publish.md +255 -0
  229. package/src/apothem/commands/research-review.md +251 -0
  230. package/src/apothem/commands/research-sources.md +266 -0
  231. package/src/apothem/commands/research-spec.md +255 -0
  232. package/src/apothem/commands/research-synthesis.md +233 -0
  233. package/src/apothem/commands/research-theory.md +218 -0
  234. package/src/apothem/commands/research.md +181 -0
  235. package/src/apothem/commands/security-audit.md +196 -0
  236. package/src/apothem/commands/supply-chain-audit.md +192 -0
  237. package/src/apothem/commands/test-suite.md +146 -0
  238. package/src/apothem/commands/threat-model-audit.md +199 -0
  239. package/src/apothem/commands/ux-review.md +202 -0
  240. package/src/apothem/commands/workflow.md +162 -0
  241. package/src/apothem/conformity/README.md +173 -0
  242. package/src/apothem/conformity/__init__.py +1 -0
  243. package/src/apothem/conformity/_grep_base.py +93 -0
  244. package/src/apothem/conformity/agent_capability_grep.py +306 -0
  245. package/src/apothem/conformity/agents_md_coverage_grep.py +382 -0
  246. package/src/apothem/conformity/agnosticism_grep.py +311 -0
  247. package/src/apothem/conformity/always_on_budget_grep.py +318 -0
  248. package/src/apothem/conformity/bare_except_grep.py +115 -0
  249. package/src/apothem/conformity/binding_reciprocity_grep.py +151 -0
  250. package/src/apothem/conformity/brand_mark_grep.py +272 -0
  251. package/src/apothem/conformity/commented_out_code_grep.py +176 -0
  252. package/src/apothem/conformity/completion_claim_grep.py +169 -0
  253. package/src/apothem/conformity/conventional_commit_grep.py +319 -0
  254. package/src/apothem/conformity/copilot_instructions_presence_grep.py +324 -0
  255. package/src/apothem/conformity/cross_platform_matrix_grep.py +297 -0
  256. package/src/apothem/conformity/determinism_grep.py +306 -0
  257. package/src/apothem/conformity/diagram_staleness_grep.py +154 -0
  258. package/src/apothem/conformity/dynamism_grep.py +284 -0
  259. package/src/apothem/conformity/editorconfig_presence_grep.py +281 -0
  260. package/src/apothem/conformity/file_header_grep.py +502 -0
  261. package/src/apothem/conformity/freshness_token_grep.py +233 -0
  262. package/src/apothem/conformity/frontmatter_grep.py +274 -0
  263. package/src/apothem/conformity/frontmatter_value_grep.py +386 -0
  264. package/src/apothem/conformity/gate.py +1386 -0
  265. package/src/apothem/conformity/gitattributes_presence_grep.py +238 -0
  266. package/src/apothem/conformity/harden_runner_grep.py +320 -0
  267. package/src/apothem/conformity/hedging_grep.py +129 -0
  268. package/src/apothem/conformity/license_author_consistency_grep.py +204 -0
  269. package/src/apothem/conformity/link_check.py +327 -0
  270. package/src/apothem/conformity/magic_number_grep.py +182 -0
  271. package/src/apothem/conformity/multi_surface_coherence_grep.py +620 -0
  272. package/src/apothem/conformity/naming_grep.py +224 -0
  273. package/src/apothem/conformity/no_global_plans_grep.py +339 -0
  274. package/src/apothem/conformity/no_toplevel_docs_grep.py +120 -0
  275. package/src/apothem/conformity/oidc_trusted_publishing_grep.py +291 -0
  276. package/src/apothem/conformity/option_annotation_grep.py +352 -0
  277. package/src/apothem/conformity/orphan_output_grep.py +206 -0
  278. package/src/apothem/conformity/permissions_minimum_scope_grep.py +299 -0
  279. package/src/apothem/conformity/plain_language_grep.py +559 -0
  280. package/src/apothem/conformity/plan_next_step_consistency_grep.py +450 -0
  281. package/src/apothem/conformity/plan_suite_structure_grep.py +534 -0
  282. package/src/apothem/conformity/plans_discipline_language_grep.py +245 -0
  283. package/src/apothem/conformity/production_ready_pr_grep.py +200 -0
  284. package/src/apothem/conformity/recommend_next_step_grep.py +250 -0
  285. package/src/apothem/conformity/redundancy_grep.py +401 -0
  286. package/src/apothem/conformity/reference_token_grep.py +230 -0
  287. package/src/apothem/conformity/registry_capability_consistency_grep.py +368 -0
  288. package/src/apothem/conformity/secret_leak_grep.py +193 -0
  289. package/src/apothem/conformity/semver_stability_grep.py +358 -0
  290. package/src/apothem/conformity/smoke_install_grep.py +194 -0
  291. package/src/apothem/conformity/static_version_grep.py +284 -0
  292. package/src/apothem/conformity/token_efficiency_grep.py +185 -0
  293. package/src/apothem/conformity/unpinned_action_grep.py +115 -0
  294. package/src/apothem/conformity/user_confirm_grep.py +74 -0
  295. package/src/apothem/conformity/workflow_concurrency_grep.py +283 -0
  296. package/src/apothem/harnesses/README.md +63 -0
  297. package/src/apothem/harnesses/__init__.py +16 -0
  298. package/src/apothem/harnesses/_shared/README.md +36 -0
  299. package/src/apothem/harnesses/_shared/__init__.py +12 -0
  300. package/src/apothem/harnesses/_shared/install_driver.py +281 -0
  301. package/src/apothem/harnesses/_shared/install_driver_apply.py +612 -0
  302. package/src/apothem/harnesses/_shared/install_driver_backup.py +535 -0
  303. package/src/apothem/harnesses/_shared/install_driver_converters.py +310 -0
  304. package/src/apothem/harnesses/_shared/install_driver_lifecycle.py +495 -0
  305. package/src/apothem/harnesses/_shared/install_driver_materialize.py +675 -0
  306. package/src/apothem/harnesses/_shared/install_driver_merge.py +656 -0
  307. package/src/apothem/harnesses/_shared/install_driver_pathsafety.py +137 -0
  308. package/src/apothem/harnesses/_shared/install_driver_planvalidation.py +240 -0
  309. package/src/apothem/harnesses/_shared/install_driver_removal.py +366 -0
  310. package/src/apothem/harnesses/_shared/install_driver_treeops.py +248 -0
  311. package/src/apothem/harnesses/_shared/install_driver_types.py +330 -0
  312. package/src/apothem/harnesses/_shared/wrapper_factories.py +448 -0
  313. package/src/apothem/harnesses/antigravity/STANDARD-CONVENTION-PIN.md +91 -0
  314. package/src/apothem/harnesses/antigravity/__init__.py +70 -0
  315. package/src/apothem/harnesses/antigravity/capabilities.yml +40 -0
  316. package/src/apothem/harnesses/antigravity/install.py +63 -0
  317. package/src/apothem/harnesses/antigravity/templates/GEMINI.md +40 -0
  318. package/src/apothem/harnesses/antigravity/templates/plugin.json +5 -0
  319. package/src/apothem/harnesses/antigravity/uninstall.py +22 -0
  320. package/src/apothem/harnesses/antigravity/update.py +10 -0
  321. package/src/apothem/harnesses/antigravity/verify.py +11 -0
  322. package/src/apothem/harnesses/claude_code/STANDARD-CONVENTION-PIN.md +65 -0
  323. package/src/apothem/harnesses/claude_code/__init__.py +107 -0
  324. package/src/apothem/harnesses/claude_code/capabilities.yml +42 -0
  325. package/src/apothem/harnesses/claude_code/install.py +147 -0
  326. package/src/apothem/harnesses/claude_code/templates/settings.json +351 -0
  327. package/src/apothem/harnesses/claude_code/uninstall.py +23 -0
  328. package/src/apothem/harnesses/claude_code/update.py +10 -0
  329. package/src/apothem/harnesses/claude_code/verify.py +11 -0
  330. package/src/apothem/harnesses/codebuddy/STANDARD-CONVENTION-PIN.md +74 -0
  331. package/src/apothem/harnesses/codebuddy/__init__.py +49 -0
  332. package/src/apothem/harnesses/codebuddy/capabilities.yml +34 -0
  333. package/src/apothem/harnesses/codebuddy/install.py +40 -0
  334. package/src/apothem/harnesses/codebuddy/templates/apothem-rules.md +37 -0
  335. package/src/apothem/harnesses/codebuddy/uninstall.py +25 -0
  336. package/src/apothem/harnesses/codebuddy/update.py +10 -0
  337. package/src/apothem/harnesses/codebuddy/verify.py +11 -0
  338. package/src/apothem/harnesses/codex/STANDARD-CONVENTION-PIN.md +79 -0
  339. package/src/apothem/harnesses/codex/__init__.py +72 -0
  340. package/src/apothem/harnesses/codex/capabilities.yml +40 -0
  341. package/src/apothem/harnesses/codex/install.py +69 -0
  342. package/src/apothem/harnesses/codex/templates/AGENTS.md +40 -0
  343. package/src/apothem/harnesses/codex/templates/hooks.json +127 -0
  344. package/src/apothem/harnesses/codex/uninstall.py +23 -0
  345. package/src/apothem/harnesses/codex/update.py +10 -0
  346. package/src/apothem/harnesses/codex/verify.py +11 -0
  347. package/src/apothem/harnesses/cursor/STANDARD-CONVENTION-PIN.md +79 -0
  348. package/src/apothem/harnesses/cursor/__init__.py +48 -0
  349. package/src/apothem/harnesses/cursor/capabilities.yml +42 -0
  350. package/src/apothem/harnesses/cursor/install.py +38 -0
  351. package/src/apothem/harnesses/cursor/templates/apothem-rules.mdc +40 -0
  352. package/src/apothem/harnesses/cursor/uninstall.py +25 -0
  353. package/src/apothem/harnesses/cursor/update.py +10 -0
  354. package/src/apothem/harnesses/cursor/verify.py +11 -0
  355. package/src/apothem/harnesses/gemini_cli/STANDARD-CONVENTION-PIN.md +102 -0
  356. package/src/apothem/harnesses/gemini_cli/__init__.py +52 -0
  357. package/src/apothem/harnesses/gemini_cli/capabilities.yml +43 -0
  358. package/src/apothem/harnesses/gemini_cli/install.py +43 -0
  359. package/src/apothem/harnesses/gemini_cli/templates/GEMINI.md +38 -0
  360. package/src/apothem/harnesses/gemini_cli/uninstall.py +25 -0
  361. package/src/apothem/harnesses/gemini_cli/update.py +10 -0
  362. package/src/apothem/harnesses/gemini_cli/verify.py +11 -0
  363. package/src/apothem/harnesses/github_copilot/STANDARD-CONVENTION-PIN.md +84 -0
  364. package/src/apothem/harnesses/github_copilot/__init__.py +47 -0
  365. package/src/apothem/harnesses/github_copilot/capabilities.yml +42 -0
  366. package/src/apothem/harnesses/github_copilot/install.py +40 -0
  367. package/src/apothem/harnesses/github_copilot/templates/copilot-instructions.md +33 -0
  368. package/src/apothem/harnesses/github_copilot/uninstall.py +25 -0
  369. package/src/apothem/harnesses/github_copilot/update.py +10 -0
  370. package/src/apothem/harnesses/github_copilot/verify.py +11 -0
  371. package/src/apothem/harnesses/glm/STANDARD-CONVENTION-PIN.md +77 -0
  372. package/src/apothem/harnesses/glm/__init__.py +56 -0
  373. package/src/apothem/harnesses/glm/capabilities.yml +33 -0
  374. package/src/apothem/harnesses/glm/install.py +45 -0
  375. package/src/apothem/harnesses/glm/templates/glm.toml +58 -0
  376. package/src/apothem/harnesses/glm/uninstall.py +25 -0
  377. package/src/apothem/harnesses/glm/update.py +10 -0
  378. package/src/apothem/harnesses/glm/verify.py +11 -0
  379. package/src/apothem/harnesses/hermes/STANDARD-CONVENTION-PIN.md +57 -0
  380. package/src/apothem/harnesses/hermes/__init__.py +33 -0
  381. package/src/apothem/harnesses/hermes/capabilities.yml +36 -0
  382. package/src/apothem/harnesses/hermes/install.py +17 -0
  383. package/src/apothem/harnesses/hermes/materializer.py +35 -0
  384. package/src/apothem/harnesses/hermes/uninstall.py +33 -0
  385. package/src/apothem/harnesses/hermes/update.py +10 -0
  386. package/src/apothem/harnesses/hermes/verify.py +11 -0
  387. package/src/apothem/harnesses/kimi_code/STANDARD-CONVENTION-PIN.md +128 -0
  388. package/src/apothem/harnesses/kimi_code/__init__.py +59 -0
  389. package/src/apothem/harnesses/kimi_code/capabilities.yml +40 -0
  390. package/src/apothem/harnesses/kimi_code/install.py +42 -0
  391. package/src/apothem/harnesses/kimi_code/templates/AGENTS.md +43 -0
  392. package/src/apothem/harnesses/kimi_code/uninstall.py +27 -0
  393. package/src/apothem/harnesses/kimi_code/update.py +10 -0
  394. package/src/apothem/harnesses/kimi_code/verify.py +11 -0
  395. package/src/apothem/harnesses/kiro/STANDARD-CONVENTION-PIN.md +77 -0
  396. package/src/apothem/harnesses/kiro/__init__.py +49 -0
  397. package/src/apothem/harnesses/kiro/capabilities.yml +36 -0
  398. package/src/apothem/harnesses/kiro/install.py +39 -0
  399. package/src/apothem/harnesses/kiro/templates/apothem-rules.md +36 -0
  400. package/src/apothem/harnesses/kiro/uninstall.py +25 -0
  401. package/src/apothem/harnesses/kiro/update.py +10 -0
  402. package/src/apothem/harnesses/kiro/verify.py +11 -0
  403. package/src/apothem/harnesses/open_claw/STANDARD-CONVENTION-PIN.md +62 -0
  404. package/src/apothem/harnesses/open_claw/__init__.py +35 -0
  405. package/src/apothem/harnesses/open_claw/capabilities.yml +35 -0
  406. package/src/apothem/harnesses/open_claw/install.py +17 -0
  407. package/src/apothem/harnesses/open_claw/materializer.py +36 -0
  408. package/src/apothem/harnesses/open_claw/uninstall.py +32 -0
  409. package/src/apothem/harnesses/open_claw/update.py +10 -0
  410. package/src/apothem/harnesses/open_claw/verify.py +11 -0
  411. package/src/apothem/harnesses/opencode/STANDARD-CONVENTION-PIN.md +76 -0
  412. package/src/apothem/harnesses/opencode/__init__.py +35 -0
  413. package/src/apothem/harnesses/opencode/capabilities.yml +43 -0
  414. package/src/apothem/harnesses/opencode/install.py +17 -0
  415. package/src/apothem/harnesses/opencode/materializer.py +31 -0
  416. package/src/apothem/harnesses/opencode/uninstall.py +34 -0
  417. package/src/apothem/harnesses/opencode/update.py +10 -0
  418. package/src/apothem/harnesses/opencode/verify.py +11 -0
  419. package/src/apothem/harnesses/qwen_code/STANDARD-CONVENTION-PIN.md +87 -0
  420. package/src/apothem/harnesses/qwen_code/__init__.py +37 -0
  421. package/src/apothem/harnesses/qwen_code/capabilities.yml +43 -0
  422. package/src/apothem/harnesses/qwen_code/install.py +19 -0
  423. package/src/apothem/harnesses/qwen_code/materializer.py +174 -0
  424. package/src/apothem/harnesses/qwen_code/templates/QWEN.md +30 -0
  425. package/src/apothem/harnesses/qwen_code/uninstall.py +34 -0
  426. package/src/apothem/harnesses/qwen_code/update.py +10 -0
  427. package/src/apothem/harnesses/qwen_code/verify.py +11 -0
  428. package/src/apothem/harnesses/trae/STANDARD-CONVENTION-PIN.md +70 -0
  429. package/src/apothem/harnesses/trae/__init__.py +49 -0
  430. package/src/apothem/harnesses/trae/capabilities.yml +34 -0
  431. package/src/apothem/harnesses/trae/install.py +38 -0
  432. package/src/apothem/harnesses/trae/templates/apothem-rules.md +37 -0
  433. package/src/apothem/harnesses/trae/uninstall.py +25 -0
  434. package/src/apothem/harnesses/trae/update.py +10 -0
  435. package/src/apothem/harnesses/trae/verify.py +11 -0
  436. package/src/apothem/harnesses/windsurf/STANDARD-CONVENTION-PIN.md +91 -0
  437. package/src/apothem/harnesses/windsurf/__init__.py +52 -0
  438. package/src/apothem/harnesses/windsurf/capabilities.yml +40 -0
  439. package/src/apothem/harnesses/windsurf/install.py +41 -0
  440. package/src/apothem/harnesses/windsurf/templates/apothem-rules.md +37 -0
  441. package/src/apothem/harnesses/windsurf/uninstall.py +25 -0
  442. package/src/apothem/harnesses/windsurf/update.py +10 -0
  443. package/src/apothem/harnesses/windsurf/verify.py +11 -0
  444. package/src/apothem/harnesses/zed/STANDARD-CONVENTION-PIN.md +92 -0
  445. package/src/apothem/harnesses/zed/__init__.py +57 -0
  446. package/src/apothem/harnesses/zed/capabilities.yml +38 -0
  447. package/src/apothem/harnesses/zed/install.py +41 -0
  448. package/src/apothem/harnesses/zed/templates/apothem-rules.md +32 -0
  449. package/src/apothem/harnesses/zed/uninstall.py +28 -0
  450. package/src/apothem/harnesses/zed/update.py +10 -0
  451. package/src/apothem/harnesses/zed/verify.py +11 -0
  452. package/src/apothem/hooks/README.md +81 -0
  453. package/src/apothem/hooks/__init__.py +24 -0
  454. package/src/apothem/hooks/askuserquestion_validator.py +380 -0
  455. package/src/apothem/hooks/dispatch.py +296 -0
  456. package/src/apothem/hooks/emit_hook_context.py +444 -0
  457. package/src/apothem/hooks/hooks.json +318 -0
  458. package/src/apothem/hooks/lib/README.md +39 -0
  459. package/src/apothem/hooks/lib/__init__.py +18 -0
  460. package/src/apothem/hooks/lib/bootstrap.ps1 +129 -0
  461. package/src/apothem/hooks/lib/bootstrap.sh +103 -0
  462. package/src/apothem/hooks/lib/events.py +51 -0
  463. package/src/apothem/hooks/lib/find-pwsh.ps1 +78 -0
  464. package/src/apothem/hooks/lib/find-pwsh.sh +76 -0
  465. package/src/apothem/hooks/lib/find-python.ps1 +63 -0
  466. package/src/apothem/hooks/lib/find-python.sh +97 -0
  467. package/src/apothem/hooks/lib/log.py +43 -0
  468. package/src/apothem/hooks/lib/resolve_root.py +264 -0
  469. package/src/apothem/hooks/messages/postcompact.md +14 -0
  470. package/src/apothem/hooks/messages/posttooluse-proactive-compaction.md +46 -0
  471. package/src/apothem/hooks/messages/precompact.md +14 -0
  472. package/src/apothem/hooks/messages/pretooluse-askuserquestion-recommended.md +65 -0
  473. package/src/apothem/hooks/messages/pretooluse-bash-plan-guard.md +97 -0
  474. package/src/apothem/hooks/messages/pretooluse-bash.md +39 -0
  475. package/src/apothem/hooks/messages/pretooluse-conformity.md +70 -0
  476. package/src/apothem/hooks/messages/pretooluse-dependency-guard.md +21 -0
  477. package/src/apothem/hooks/messages/pretooluse-edit-header-guard.md +61 -0
  478. package/src/apothem/hooks/messages/pretooluse-edit.md +21 -0
  479. package/src/apothem/hooks/messages/pretooluse-eval-guard.md +39 -0
  480. package/src/apothem/hooks/messages/pretooluse-notebookedit.md +11 -0
  481. package/src/apothem/hooks/messages/pretooluse-write-header-guard.md +45 -0
  482. package/src/apothem/hooks/messages/pretooluse-write-plan-guard.md +72 -0
  483. package/src/apothem/hooks/messages/pretooluse-write.md +21 -0
  484. package/src/apothem/hooks/messages/sessionstart.md +15 -0
  485. package/src/apothem/hooks/messages/stop.md +27 -0
  486. package/src/apothem/hooks/proactive_compaction_tracker.py +327 -0
  487. package/src/apothem/hooks/session_start_bootstrap.py +472 -0
  488. package/src/apothem/lib/README.md +42 -0
  489. package/src/apothem/lib/__init__.py +13 -0
  490. package/src/apothem/lib/atomic_io.py +189 -0
  491. package/src/apothem/lib/auditor.py +687 -0
  492. package/src/apothem/lib/clean_slate.py +396 -0
  493. package/src/apothem/lib/contexts.py +352 -0
  494. package/src/apothem/lib/data_home.py +255 -0
  495. package/src/apothem/lib/frontmatter.py +101 -0
  496. package/src/apothem/lib/harness_materializer.py +213 -0
  497. package/src/apothem/lib/harness_protocol.py +59 -0
  498. package/src/apothem/lib/harness_registry.py +282 -0
  499. package/src/apothem/lib/harness_registry_data.py +843 -0
  500. package/src/apothem/lib/install_ledger.py +347 -0
  501. package/src/apothem/lib/learning.py +540 -0
  502. package/src/apothem/lib/memory.py +347 -0
  503. package/src/apothem/lib/parallel_sweep.py +234 -0
  504. package/src/apothem/lib/plan_tiers.py +200 -0
  505. package/src/apothem/lib/plugin_bootstrap.py +132 -0
  506. package/src/apothem/lib/plugin_tree.py +599 -0
  507. package/src/apothem/lib/profile.py +755 -0
  508. package/src/apothem/lib/profile_projection.py +198 -0
  509. package/src/apothem/lib/propagation-manifest.yaml +878 -0
  510. package/src/apothem/lib/propagation.py +220 -0
  511. package/src/apothem/lib/python_resolver.py +189 -0
  512. package/src/apothem/lib/reporter.py +62 -0
  513. package/src/apothem/lib/workspace_migration.py +323 -0
  514. package/src/apothem/output-styles/README.md +41 -0
  515. package/src/apothem/output-styles/concise-engineer.md +49 -0
  516. package/src/apothem/output-styles/default-architect.md +52 -0
  517. package/src/apothem/output-styles/default.md +113 -0
  518. package/src/apothem/output-styles/forensic-auditor.md +63 -0
  519. package/src/apothem/py.typed +0 -0
  520. package/src/apothem/rules/README.md +121 -0
  521. package/src/apothem/rules/agent-capability-discipline-matrix.md +89 -0
  522. package/src/apothem/rules/agent-capability-discipline.md +78 -0
  523. package/src/apothem/rules/agent-orchestration-patterns.md +144 -0
  524. package/src/apothem/rules/agent-orchestration.md +65 -0
  525. package/src/apothem/rules/agents-md-convention.md +86 -0
  526. package/src/apothem/rules/agile-sprints-elements.md +135 -0
  527. package/src/apothem/rules/agile-sprints.md +64 -0
  528. package/src/apothem/rules/agnostic-posture-checklist.md +47 -0
  529. package/src/apothem/rules/agnostic-posture.md +48 -0
  530. package/src/apothem/rules/authoritative-referencing-quotation.md +50 -0
  531. package/src/apothem/rules/authoritative-referencing.md +66 -0
  532. package/src/apothem/rules/authority-inquiry-categories.md +58 -0
  533. package/src/apothem/rules/authority-inquiry.md +54 -0
  534. package/src/apothem/rules/auto-memory-topic-files.md +86 -0
  535. package/src/apothem/rules/auto-memory.md +67 -0
  536. package/src/apothem/rules/bidirectional-binding.md +123 -0
  537. package/src/apothem/rules/canonical-layout-reporting-tiers.md +212 -0
  538. package/src/apothem/rules/canonical-layout.md +60 -0
  539. package/src/apothem/rules/clean-architecture-layers.md +186 -0
  540. package/src/apothem/rules/clean-room-generation-protocols.md +124 -0
  541. package/src/apothem/rules/clean-room-generation.md +59 -0
  542. package/src/apothem/rules/code-craft-conventions.md +101 -0
  543. package/src/apothem/rules/code-craft-markdown.md +138 -0
  544. package/src/apothem/rules/code-craft-python.md +154 -0
  545. package/src/apothem/rules/code-craft-shell.md +192 -0
  546. package/src/apothem/rules/cognitive-identity-techniques.md +180 -0
  547. package/src/apothem/rules/cognitive-identity.md +81 -0
  548. package/src/apothem/rules/context-management-budget.md +46 -0
  549. package/src/apothem/rules/context-management-protocol.md +161 -0
  550. package/src/apothem/rules/context-management-scratch.md +128 -0
  551. package/src/apothem/rules/context-management.md +85 -0
  552. package/src/apothem/rules/definitiveness-virtues.md +67 -0
  553. package/src/apothem/rules/definitiveness.md +58 -0
  554. package/src/apothem/rules/determinism.md +81 -0
  555. package/src/apothem/rules/disclosure-ledger-markers.md +58 -0
  556. package/src/apothem/rules/disclosure-ledger.md +52 -0
  557. package/src/apothem/rules/dynamism.md +38 -0
  558. package/src/apothem/rules/etc-extension.md +57 -0
  559. package/src/apothem/rules/expertise-posture-elements.md +68 -0
  560. package/src/apothem/rules/expertise-posture.md +54 -0
  561. package/src/apothem/rules/freshness-facade.md +64 -0
  562. package/src/apothem/rules/harness-adapter-shape-schemas.md +162 -0
  563. package/src/apothem/rules/harness-adapter-shape.md +42 -0
  564. package/src/apothem/rules/host-discovery-manifests.md +50 -0
  565. package/src/apothem/rules/host-discovery.md +56 -0
  566. package/src/apothem/rules/i18n-discipline-locale-cohorts.md +120 -0
  567. package/src/apothem/rules/i18n-discipline.md +70 -0
  568. package/src/apothem/rules/interactive-questions-canonical-shapes.md +590 -0
  569. package/src/apothem/rules/interactive-questions-detail.md +41 -0
  570. package/src/apothem/rules/interactive-questions-sweep-matchers.md +184 -0
  571. package/src/apothem/rules/interactive-questions.md +89 -0
  572. package/src/apothem/rules/large-file-generation.md +112 -0
  573. package/src/apothem/rules/large-file-reading.md +59 -0
  574. package/src/apothem/rules/living-docs.md +85 -0
  575. package/src/apothem/rules/multi-agent-workflow.md +57 -0
  576. package/src/apothem/rules/operational-mandates-expanded.md +78 -0
  577. package/src/apothem/rules/operational-mandates.md +88 -0
  578. package/src/apothem/rules/option-annotation-form.md +60 -0
  579. package/src/apothem/rules/option-annotation.md +45 -0
  580. package/src/apothem/rules/own-voice-reimplementation.md +86 -0
  581. package/src/apothem/rules/performance-discipline.md +91 -0
  582. package/src/apothem/rules/persistent-conventions-vigilance-checklist.md +54 -0
  583. package/src/apothem/rules/persistent-conventions-vigilance.md +61 -0
  584. package/src/apothem/rules/plain-language.md +56 -0
  585. package/src/apothem/rules/planning-techniques.md +130 -0
  586. package/src/apothem/rules/pre-emission-gate-bars.md +86 -0
  587. package/src/apothem/rules/pre-emission-gate.md +54 -0
  588. package/src/apothem/rules/production-ready-prs-surfaces.md +162 -0
  589. package/src/apothem/rules/production-ready-prs.md +83 -0
  590. package/src/apothem/rules/propagation.md +63 -0
  591. package/src/apothem/rules/recommend-next-step.md +106 -0
  592. package/src/apothem/rules/refactoring-discipline.md +76 -0
  593. package/src/apothem/rules/session-closure.md +44 -0
  594. package/src/apothem/rules/sota-elevation-exemplars.md +76 -0
  595. package/src/apothem/rules/sota-elevation.md +52 -0
  596. package/src/apothem/rules/source-accessibility.md +58 -0
  597. package/src/apothem/rules/surgical-manipulation.md +48 -0
  598. package/src/apothem/rules/systemic-participation-relations.md +108 -0
  599. package/src/apothem/rules/systemic-participation.md +70 -0
  600. package/src/apothem/rules/ten-dimension-check-dimensions.md +52 -0
  601. package/src/apothem/rules/ten-dimension-check.md +59 -0
  602. package/src/apothem/rules/token-budget-discipline.md +81 -0
  603. package/src/apothem/rules/token-efficiency-rewrite-protocol.md +79 -0
  604. package/src/apothem/rules/token-efficiency-rewrite.md +77 -0
  605. package/src/apothem/rules/tool-use-discipline.md +48 -0
  606. package/src/apothem/rules/visual-leverage.md +102 -0
  607. package/src/apothem/schemas/NOTICE.md +9 -0
  608. package/src/apothem/schemas/README.md +104 -0
  609. package/src/apothem/schemas/__init__.py +176 -0
  610. package/src/apothem/schemas/advisory-finding.schema.json +111 -0
  611. package/src/apothem/schemas/agent.schema.json +106 -0
  612. package/src/apothem/schemas/authorship-header.txt +1 -0
  613. package/src/apothem/schemas/cohort-manifest.yaml +248 -0
  614. package/src/apothem/schemas/cohort-metadata-vocabulary.yaml +168 -0
  615. package/src/apothem/schemas/cohort.schema.json +113 -0
  616. package/src/apothem/schemas/command.schema.json +68 -0
  617. package/src/apothem/schemas/compatibility-matrix.yaml +432 -0
  618. package/src/apothem/schemas/context-fragment.schema.json +64 -0
  619. package/src/apothem/schemas/freshness-token-denylist.txt +51 -0
  620. package/src/apothem/schemas/handoff-manifest.yaml +353 -0
  621. package/src/apothem/schemas/header-exceptions.txt +141 -0
  622. package/src/apothem/schemas/header-visibility.yaml +39 -0
  623. package/src/apothem/schemas/learning-signal.schema.json +46 -0
  624. package/src/apothem/schemas/memory-record.schema.json +61 -0
  625. package/src/apothem/schemas/output-style.schema.json +40 -0
  626. package/src/apothem/schemas/plan.schema.json +51 -0
  627. package/src/apothem/schemas/plugin.schema.json +83 -0
  628. package/src/apothem/schemas/profile.example.yaml +70 -0
  629. package/src/apothem/schemas/profile.minimal.yaml +6 -0
  630. package/src/apothem/schemas/profile.schema.json +396 -0
  631. package/src/apothem/schemas/reference-token-denylist.txt +25 -0
  632. package/src/apothem/schemas/skill.schema.json +75 -0
  633. package/src/apothem/skills/README.md +93 -0
  634. package/src/apothem/skills/dependency-upgrade/SKILL.md +105 -0
  635. package/src/apothem/skills/dev-toolkit/SKILL.md +120 -0
  636. package/src/apothem/skills/diagram-authoring/SKILL.md +113 -0
  637. package/src/apothem/skills/document-authoring/SKILL.md +118 -0
  638. package/src/apothem/skills/ecosystem-audit/SKILL.md +108 -0
  639. package/src/apothem/skills/ecosystem-audit/references/audit-fortress.md +85 -0
  640. package/src/apothem/skills/ecosystem-audit/references/procedure.md +162 -0
  641. package/src/apothem/skills/eval-harness/SKILL.md +88 -0
  642. package/src/apothem/skills/incident-runbook/SKILL.md +92 -0
  643. package/src/apothem/skills/multi-source-research/SKILL.md +90 -0
  644. package/src/apothem/skills/plan-suite/SKILL.md +118 -0
  645. package/src/apothem/skills/plan-suite/master_template.md +1324 -0
  646. package/src/apothem/skills/projectify/SKILL.md +117 -0
  647. package/src/apothem/skills/prompt-engineering/SKILL.md +122 -0
  648. package/src/apothem/skills/refactor-extract/SKILL.md +85 -0
  649. package/src/apothem/skills/research-suite/SKILL.md +170 -0
  650. package/src/apothem/skills/research-suite/references/directory-structure.md +47 -0
  651. package/src/apothem/skills/research-suite/references/lifecycle.md +67 -0
  652. package/src/apothem/skills/research-suite/references/principal-investigator-framework.md +37 -0
  653. package/src/apothem/skills/research-suite/references/rigor-mandates.md +30 -0
  654. package/src/apothem/skills/research-suite/research_template.md +476 -0
  655. package/src/apothem/skills/secret-rotation/SKILL.md +87 -0
  656. package/src/apothem/skills/source-synthesis/SKILL.md +92 -0
  657. package/src/apothem/skills/surgical-guard/SKILL.md +118 -0
  658. package/src/apothem/skills/test-authoring/SKILL.md +85 -0
  659. package/src/apothem/skills/vuln-triage/SKILL.md +91 -0
  660. package/src/apothem/skills/workflow/SKILL.md +139 -0
  661. package/src/apothem/statuslines/README.md +26 -0
  662. package/src/apothem/statuslines/__init__.py +20 -0
  663. package/src/apothem/statuslines/conformity.json +5 -0
  664. package/src/apothem/statuslines/render.py +334 -0
  665. package/src/apothem/statuslines/statusline.md +50 -0
  666. package/src/apothem/templates/README.md +43 -0
  667. package/src/apothem/templates/agents-md-template.md +80 -0
  668. package/src/apothem/templates/consideration-log.md +39 -0
  669. package/src/apothem/templates/expertise-gap-log.md +56 -0
  670. package/src/apothem/templates/master-index-template.md +93 -0
  671. package/src/apothem/templates/potency-map.md +53 -0
  672. package/src/apothem/templates/preservation-audit.md +60 -0
  673. package/src/apothem/templates/question-resolution-audit.md +52 -0
  674. package/src/apothem/templates/trace-matrix-template.md +77 -0
@@ -0,0 +1,245 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Verify the canonical Plans Discipline language reaches every required surface.
4
+
5
+ Why this validator exists. Spec section 3 declares Plans Discipline as
6
+ multi-surface enforcement (defense-in-depth). Four surfaces MUST carry
7
+ the directive:
8
+
9
+ * ``AGENTS.md`` — the canonical project instruction surface.
10
+ * ``CLAUDE.md`` — the Claude Code mirror.
11
+ * ``src/apothem/output-styles/default.md`` — the ecosystem-default tonal floor.
12
+ * ``.github/copilot-instructions.md`` — the Copilot-side mirror.
13
+
14
+ Each surface MUST contain either (a) the byte-exact fixture sentence
15
+ at ``tests/fixtures/plans-discipline.txt``, or (b) a semantic-paraphrase
16
+ that covers the canonical token set with sufficient density. The
17
+ two-mode admission honors the multi-surface-coherence comparator's
18
+ semantic-equivalence-token approach: byte-exact reproduction is
19
+ strongest, paraphrase with token coverage is acceptable.
20
+
21
+ Detection strategy. The validator walks the four surfaces from
22
+ ``--root`` (the repository root). Per surface, it first probes for
23
+ byte-exact fixture presence; on miss, it computes a token-coverage
24
+ score against the canonical token set. A coverage of ``COVERAGE_FLOOR``
25
+ (0.6) admits the surface; below the floor is a finding.
26
+
27
+ Exit semantics. Exits 0 when every surface passes; exits 2 on any
28
+ finding. The exit-2 convention matches the conformity-gate
29
+ orchestrator's EXIT_FAIL constant.
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import json
35
+ import sys
36
+ from dataclasses import asdict, dataclass, field
37
+ from pathlib import Path
38
+ from typing import Final
39
+
40
+ GREP_NAME: Final[str] = "plans-discipline-language-grep"
41
+ RULE_ANCHOR: Final[str] = "CLAUDE.md Plans Discipline (multi-surface language)"
42
+
43
+ EXIT_PASS: Final[int] = 0
44
+ EXIT_FAIL: Final[int] = 2
45
+
46
+ # Surfaces that MUST carry the Plans Discipline directive. Paths are
47
+ # relative to the repository root supplied at invocation.
48
+ REQUIRED_SURFACES: Final[tuple[str, ...]] = (
49
+ "AGENTS.md",
50
+ "CLAUDE.md",
51
+ "src/apothem/output-styles/default.md",
52
+ ".github/copilot-instructions.md",
53
+ )
54
+
55
+ # Path to the byte-exact fixture relative to the repository root.
56
+ FIXTURE_PATH: Final[str] = "tests/fixtures/plans-discipline.txt"
57
+
58
+ # Canonical token set the paraphrase tolerance scores against. Each entry is a
59
+ # tuple of accepted alternatives; the entry counts toward coverage when ANY of
60
+ # its alternatives appears (case-insensitive substring). The tokens capture the
61
+ # directive's load-bearing semantics: the canonical destination, the negative
62
+ # claim, the global ban, and the non-negotiability frame.
63
+ #
64
+ # The canonical-destination entry is the sole project-local plans location
65
+ # ``<project-root>/.apothem/plans/``; a legacy ``<project-root>/.plans/`` tree
66
+ # is no longer canonical — operators upgrade it via ``apothem migrate-workspace``.
67
+ CANONICAL_TOKENS: Final[tuple[tuple[str, ...], ...]] = (
68
+ ("<project-root>/.apothem/plans/",),
69
+ ("~/.codex/",),
70
+ ("~/.claude/",),
71
+ ("never",),
72
+ ("global",),
73
+ ("plans discipline",),
74
+ )
75
+ COVERAGE_FLOOR: Final[float] = 0.6
76
+
77
+
78
+ @dataclass(frozen=True)
79
+ class Finding:
80
+ """One surface that lacks the directive at admission strength."""
81
+
82
+ surface: str
83
+ detail: str
84
+ coverage: float
85
+ rule: str = RULE_ANCHOR
86
+
87
+
88
+ @dataclass(frozen=True)
89
+ class SurfaceVerdict:
90
+ """Per-surface admission record (informational; survives passing surfaces)."""
91
+
92
+ surface: str
93
+ mode: str
94
+ coverage: float
95
+ admitted: bool
96
+
97
+
98
+ @dataclass(frozen=True)
99
+ class GrepResult:
100
+ """Aggregated multi-surface sweep result."""
101
+
102
+ grep: str
103
+ root: str
104
+ fixture_present: bool
105
+ surfaces: list[SurfaceVerdict]
106
+ passed: bool
107
+ findings: list[Finding] = field(default_factory=list)
108
+
109
+ def to_json(self) -> str:
110
+ payload = {
111
+ "grep": self.grep,
112
+ "root": self.root,
113
+ "fixture_present": self.fixture_present,
114
+ "surfaces": [asdict(s) for s in self.surfaces],
115
+ "passed": self.passed,
116
+ "findings": [asdict(f) for f in self.findings],
117
+ }
118
+ return json.dumps(payload, indent=2)
119
+
120
+
121
+ def _read_fixture(root: Path) -> str | None:
122
+ """Return the fixture body, or None when the fixture file is absent."""
123
+ fixture_file = root / FIXTURE_PATH
124
+ if not fixture_file.exists():
125
+ return None
126
+ return fixture_file.read_text(encoding="utf-8").strip()
127
+
128
+
129
+ def _coverage(body: str, tokens: tuple[tuple[str, ...], ...]) -> float:
130
+ """Fraction of token entries present in body (case-insensitive substring).
131
+
132
+ Each entry is a tuple of accepted alternatives; an entry counts when ANY of
133
+ its alternatives appears. The canonical-destination entry admits the sole
134
+ project-local ``<project-root>/.apothem/plans/`` phrasing.
135
+ """
136
+ if not tokens:
137
+ return 1.0
138
+ lowered = body.lower()
139
+ matched = sum(
140
+ 1
141
+ for alternatives in tokens
142
+ if any(alt.lower() in lowered for alt in alternatives)
143
+ )
144
+ return matched / len(tokens)
145
+
146
+
147
+ def _verdict_for_surface(
148
+ surface_path: str,
149
+ body: str,
150
+ fixture_text: str | None,
151
+ ) -> tuple[SurfaceVerdict, Finding | None]:
152
+ """Score one surface; return its verdict and any finding."""
153
+ if fixture_text and fixture_text in body:
154
+ verdict = SurfaceVerdict(
155
+ surface=surface_path, mode="byte-exact", coverage=1.0, admitted=True
156
+ )
157
+ return verdict, None
158
+ coverage = _coverage(body, CANONICAL_TOKENS)
159
+ admitted = coverage >= COVERAGE_FLOOR
160
+ verdict = SurfaceVerdict(
161
+ surface=surface_path,
162
+ mode="paraphrase",
163
+ coverage=round(coverage, 3),
164
+ admitted=admitted,
165
+ )
166
+ if admitted:
167
+ return verdict, None
168
+ finding = Finding(
169
+ surface=surface_path,
170
+ detail=(
171
+ f"plans-discipline language insufficient: coverage "
172
+ f"{coverage:.2f} < floor {COVERAGE_FLOOR:.2f} and "
173
+ f"byte-exact fixture absent"
174
+ ),
175
+ coverage=round(coverage, 3),
176
+ )
177
+ return verdict, finding
178
+
179
+
180
+ def check(root: Path) -> GrepResult:
181
+ """Sweep the four required surfaces under root for the directive."""
182
+ fixture_text = _read_fixture(root)
183
+ fixture_present = fixture_text is not None
184
+ verdicts: list[SurfaceVerdict] = []
185
+ findings: list[Finding] = []
186
+ if not fixture_present:
187
+ findings.append(
188
+ Finding(
189
+ surface=FIXTURE_PATH,
190
+ detail=(
191
+ "byte-exact fixture absent at canonical path; "
192
+ "byte-exact admission disabled for every surface"
193
+ ),
194
+ coverage=0.0,
195
+ )
196
+ )
197
+ for surface_path in REQUIRED_SURFACES:
198
+ full_path = root / surface_path
199
+ if not full_path.exists():
200
+ verdicts.append(
201
+ SurfaceVerdict(
202
+ surface=surface_path,
203
+ mode="absent",
204
+ coverage=0.0,
205
+ admitted=False,
206
+ )
207
+ )
208
+ findings.append(
209
+ Finding(
210
+ surface=surface_path,
211
+ detail="surface file absent at canonical path",
212
+ coverage=0.0,
213
+ )
214
+ )
215
+ continue
216
+ body = full_path.read_text(encoding="utf-8")
217
+ verdict, finding = _verdict_for_surface(surface_path, body, fixture_text)
218
+ verdicts.append(verdict)
219
+ if finding is not None:
220
+ findings.append(finding)
221
+ return GrepResult(
222
+ grep=GREP_NAME,
223
+ root=str(root),
224
+ fixture_present=fixture_present,
225
+ surfaces=verdicts,
226
+ passed=not findings,
227
+ findings=findings,
228
+ )
229
+
230
+
231
+ def _read_input(argv: list[str]) -> Path:
232
+ if len(argv) >= 2:
233
+ return Path(argv[1])
234
+ return Path.cwd()
235
+
236
+
237
+ def _main(argv: list[str]) -> int:
238
+ root = _read_input(argv)
239
+ result = check(root)
240
+ print(result.to_json())
241
+ return EXIT_PASS if result.passed else EXIT_FAIL
242
+
243
+
244
+ if __name__ == "__main__":
245
+ sys.exit(_main(sys.argv))
@@ -0,0 +1,200 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Flag commits whose change-set lacks the production-ready four-class shape.
4
+
5
+ Why this enforcement exists. The production-ready discipline M15 requires
6
+ every change touching public surface to ship in the same change-set with
7
+ tests, documentation, and a CHANGELOG entry. A code change without its
8
+ companions persists as half-finished — the follow-up never lands; the
9
+ release notes lie. The pre-emission gate's mechanical bar 15 (M15 production-ready) catches
10
+ change-sets where public-surface code was modified but the companion
11
+ classes (tests / docs / CHANGELOG) are absent or trivially populated.
12
+
13
+ Detection strategy. The grep inspects the staged diff via `git diff
14
+ --cached --name-only` and classifies every touched file into one of
15
+ four classes (code, tests, docs, changelog). When code-class files are
16
+ touched, the grep verifies at least one tests-class and at least one
17
+ docs-class file is also touched, plus the changelog-class file is
18
+ present in the change-set. Per-file invocation is a soft pass — the
19
+ grep operates at change-set granularity rather than per-file, so the
20
+ orchestrator's per-Write dispatch returns clean and the CLI mode
21
+ performs the substantive check.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import re
28
+ import subprocess
29
+ import sys
30
+ from dataclasses import asdict, dataclass, field
31
+ from pathlib import Path
32
+ from typing import Final
33
+
34
+ # Per-class path patterns. Patterns are inclusive — a file matching
35
+ # multiple patterns counts toward every class it matches.
36
+ CODE_PATTERNS: Final[tuple[re.Pattern[str], ...]] = (
37
+ re.compile(r"^src/.+\.(?:py|ts|js|go|rs|rb|java|kt|swift)$"),
38
+ re.compile(r"^lib/.+\.(?:py|ts|js|go|rs)$"),
39
+ re.compile(r"^(?:rules|commands|agents|skills|hooks|tools)/.+\.(?:py|md)$"),
40
+ )
41
+ TEST_PATTERNS: Final[tuple[re.Pattern[str], ...]] = (
42
+ re.compile(r"^tests?/.+"),
43
+ re.compile(r".+/test_[A-Za-z0-9_]+\.py$"),
44
+ re.compile(r".+_test\.(?:py|go|rs)$"),
45
+ re.compile(r".+\.test\.(?:ts|js)$"),
46
+ )
47
+ DOCS_PATTERNS: Final[tuple[re.Pattern[str], ...]] = (
48
+ re.compile(r"^docs?/.+"),
49
+ re.compile(r"^README\.md$"),
50
+ re.compile(r"^CONTRIBUTING\.md$"),
51
+ )
52
+ CHANGELOG_PATTERNS: Final[tuple[re.Pattern[str], ...]] = (
53
+ re.compile(r"^CHANGELOG\.md$"),
54
+ re.compile(r"^CHANGES(?:\.md)?$"),
55
+ re.compile(r"^HISTORY\.md$"),
56
+ )
57
+
58
+ # Per-file invocation mode: when the grep is dispatched against a
59
+ # single file (orchestrator's PreToolUse path), return PASS without
60
+ # inspecting git. The substantive check fires at commit-time CLI use.
61
+ PER_FILE_PASS_MODE: Final[bool] = True
62
+
63
+ GREP_NAME: Final[str] = "production-ready-pr-grep"
64
+ RULE_ANCHOR: Final[str] = "M15 production-ready §Same-change-set"
65
+ EXIT_PASS: Final[int] = 0
66
+ EXIT_FAIL: Final[int] = 2
67
+ STDIN_FLAG: Final[str] = "--stdin"
68
+ STAGED_FLAG: Final[str] = "--staged"
69
+
70
+ # Subprocess timeout for the git invocation; the per-grep budget is
71
+ # `gate.PER_GREP_BUDGET_SECONDS` (~520ms) but the staged-diff check is a
72
+ # single git command that completes well under that ceiling on
73
+ # representative repositories.
74
+ GIT_TIMEOUT_SECONDS: Final[int] = 5
75
+
76
+
77
+ @dataclass(frozen=True)
78
+ class Finding:
79
+ issue: str
80
+ detail: str
81
+ rule: str = RULE_ANCHOR
82
+
83
+
84
+ @dataclass(frozen=True)
85
+ class GrepResult:
86
+ grep: str
87
+ path: str | None
88
+ passed: bool
89
+ findings: list[Finding] = field(default_factory=list)
90
+
91
+ def to_json(self) -> str:
92
+ payload = {
93
+ "grep": self.grep,
94
+ "path": self.path,
95
+ "passed": self.passed,
96
+ "findings": [asdict(f) for f in self.findings],
97
+ }
98
+ return json.dumps(payload, indent=2)
99
+
100
+
101
+ def _classify(path: str) -> set[str]:
102
+ """Return the set of class labels the path matches."""
103
+ classes: set[str] = set()
104
+ if any(p.match(path) for p in CODE_PATTERNS):
105
+ classes.add("code")
106
+ if any(p.match(path) for p in TEST_PATTERNS):
107
+ classes.add("tests")
108
+ if any(p.match(path) for p in DOCS_PATTERNS):
109
+ classes.add("docs")
110
+ if any(p.match(path) for p in CHANGELOG_PATTERNS):
111
+ classes.add("changelog")
112
+ return classes
113
+
114
+
115
+ def _staged_paths() -> list[str]:
116
+ """Return the staged-diff path list via git; empty on failure."""
117
+ try:
118
+ result = subprocess.run(
119
+ ["git", "diff", "--cached", "--name-only"], # noqa: S607 # PATH-resolved git is acceptable for a developer-tool grep; full-path resolution would require host-discovery and breaks portability across operator setups.
120
+ check=True,
121
+ capture_output=True,
122
+ text=True,
123
+ timeout=GIT_TIMEOUT_SECONDS,
124
+ )
125
+ except (
126
+ subprocess.CalledProcessError,
127
+ subprocess.TimeoutExpired,
128
+ FileNotFoundError,
129
+ ):
130
+ return []
131
+ return [line.strip() for line in result.stdout.splitlines() if line.strip()]
132
+
133
+
134
+ def _check_staged() -> GrepResult:
135
+ """Substantive check: inspect the staged diff against the four-class shape."""
136
+ paths = _staged_paths()
137
+ classes_present: set[str] = set()
138
+ for path in paths:
139
+ classes_present |= _classify(path)
140
+ findings: list[Finding] = []
141
+ if "code" in classes_present:
142
+ if "tests" not in classes_present:
143
+ findings.append(
144
+ Finding(
145
+ issue="missing tests-class file",
146
+ detail="code-class file modified; no tests/* file in the change-set",
147
+ )
148
+ )
149
+ if "docs" not in classes_present:
150
+ findings.append(
151
+ Finding(
152
+ issue="missing docs-class file",
153
+ detail="code-class file modified; no docs/* / README / CONTRIBUTING in the change-set",
154
+ )
155
+ )
156
+ if "changelog" not in classes_present:
157
+ findings.append(
158
+ Finding(
159
+ issue="missing CHANGELOG entry",
160
+ detail="code-class file modified; CHANGELOG.md is not part of the change-set",
161
+ )
162
+ )
163
+ return GrepResult(
164
+ grep=GREP_NAME,
165
+ path="<staged diff>",
166
+ passed=not findings,
167
+ findings=findings,
168
+ )
169
+
170
+
171
+ def check(content: str, path: Path | None = None) -> GrepResult:
172
+ """Per-file mode returns PASS; the substantive check fires via --staged."""
173
+ if PER_FILE_PASS_MODE:
174
+ return GrepResult(
175
+ grep=GREP_NAME,
176
+ path=str(path) if path is not None else None,
177
+ passed=True,
178
+ )
179
+ return _check_staged()
180
+
181
+
182
+ def _read_input(argv: list[str]) -> tuple[str, Path | None]:
183
+ if len(argv) >= 2 and argv[1] != STDIN_FLAG:
184
+ path = Path(argv[1])
185
+ return path.read_text(encoding="utf-8"), path
186
+ return sys.stdin.read(), None
187
+
188
+
189
+ def _main(argv: list[str]) -> int:
190
+ if len(argv) >= 2 and argv[1] == STAGED_FLAG:
191
+ result = _check_staged()
192
+ else:
193
+ content, path = _read_input(argv)
194
+ result = check(content, path)
195
+ print(result.to_json())
196
+ return EXIT_PASS if result.passed else EXIT_FAIL
197
+
198
+
199
+ if __name__ == "__main__":
200
+ sys.exit(_main(sys.argv))
@@ -0,0 +1,250 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Verify every command file carries a `## Recommended Next Step` block.
4
+
5
+ Why this enforcement exists. Per `rules/recommend-next-step.md`, every
6
+ `commands/*.md` artifact terminates its working trace with a
7
+ Recommended-Next-Step block so the operator's onward path is named at
8
+ the close of every command. The block lands in one of two canonical
9
+ forms: the singular `## Recommended Next Step` heading followed by
10
+ substantive prose, or the multi-action `## Next Steps` heading whose
11
+ option list carries exactly one `**Recommended**` marker.
12
+
13
+ Detection strategy. The validator walks two terminal-surface classes —
14
+ `src/apothem/commands/*.md` (excluding `README.md` — the command-class
15
+ index is not itself a command) and `src/apothem/skills/*/SKILL.md` — to
16
+ match the rule's declared command-and-skill scope. For each surface it
17
+ locates either of the two heading forms; absence is a finding. For the
18
+ singular form the validator verifies the heading is followed by at least
19
+ one non-empty prose line. For the multi-action form the validator counts
20
+ `**Recommended**` markers between the heading and the next sibling H2 (or
21
+ end of file); exactly one is admissible. Zero or two-plus markers is a
22
+ finding.
23
+
24
+ Exit semantics. Exits 0 when every command file passes; exits 2 on any
25
+ finding. The exit-2 convention matches the conformity-gate
26
+ orchestrator's EXIT_FAIL constant.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import json
32
+ import re
33
+ import sys
34
+ from dataclasses import asdict, dataclass, field
35
+ from pathlib import Path
36
+ from typing import Final
37
+
38
+ GREP_NAME: Final[str] = "recommend-next-step-grep"
39
+ RULE_ANCHOR: Final[str] = "rules/recommend-next-step.md"
40
+
41
+ EXIT_PASS: Final[int] = 0
42
+ EXIT_FAIL: Final[int] = 2
43
+
44
+ # Terminal-surface roots relative to the repository root supplied at invocation.
45
+ COMMANDS_DIR: Final[str] = "src/apothem/commands"
46
+ SKILLS_DIR: Final[str] = "src/apothem/skills"
47
+
48
+ # Filenames excluded from the sweep — folder-companion docs, not commands:
49
+ # the human-facing directory index and the agent-facing companion.
50
+ EXCLUDED_FILES: Final[frozenset[str]] = frozenset({"README.md", "AGENTS.md"})
51
+
52
+ # Heading patterns. The singular form is the dominant convention; the
53
+ # multi-action `## Next Steps` form is admissible when the command's
54
+ # close branches across several options.
55
+ SINGULAR_HEADING_RE: Final[re.Pattern[str]] = re.compile(
56
+ r"^##\s+Recommended\s+Next\s+Step\s*$"
57
+ )
58
+ MULTI_HEADING_RE: Final[re.Pattern[str]] = re.compile(r"^##\s+Next\s+Steps\s*$")
59
+
60
+ # Any H2 heading — used to scope the multi-action block's option list to
61
+ # the region between its own heading and the next sibling H2.
62
+ ANY_H2_RE: Final[re.Pattern[str]] = re.compile(r"^##\s+\S")
63
+
64
+ # Recommended marker. The convention is the literal `**Recommended**`
65
+ # bolded token, matching the canonical option-annotation discipline.
66
+ RECOMMENDED_MARKER_RE: Final[re.Pattern[str]] = re.compile(r"\*\*Recommended\*\*")
67
+
68
+
69
+ @dataclass(frozen=True)
70
+ class Finding:
71
+ """One command file that lacks a valid Recommended-Next-Step block."""
72
+
73
+ surface: str
74
+ detail: str
75
+ rule: str = RULE_ANCHOR
76
+
77
+
78
+ @dataclass(frozen=True)
79
+ class GrepResult:
80
+ """Aggregated sweep result across every command file."""
81
+
82
+ grep: str
83
+ root: str
84
+ files_inspected: int
85
+ passed: bool
86
+ findings: list[Finding] = field(default_factory=list)
87
+
88
+ def to_json(self) -> str:
89
+ payload = {
90
+ "grep": self.grep,
91
+ "root": self.root,
92
+ "files_inspected": self.files_inspected,
93
+ "passed": self.passed,
94
+ "findings": [asdict(f) for f in self.findings],
95
+ }
96
+ return json.dumps(payload, indent=2)
97
+
98
+
99
+ def _has_substantive_prose(lines: list[str], start_index: int) -> bool:
100
+ """Return True iff at least one non-empty prose line follows the heading.
101
+
102
+ The scan stops at the next H2 (sibling heading) or end of file.
103
+ Empty lines, whitespace-only lines, and HTML-comment lines do not
104
+ count as substantive content.
105
+ """
106
+ for line in lines[start_index + 1 :]:
107
+ if ANY_H2_RE.match(line):
108
+ return False
109
+ stripped = line.strip()
110
+ if not stripped:
111
+ continue
112
+ if stripped.startswith("<!--") or stripped.startswith("-->"):
113
+ continue
114
+ return True
115
+ return False
116
+
117
+
118
+ def _count_recommended_markers(lines: list[str], start_index: int) -> int:
119
+ """Count `**Recommended**` markers between heading and next H2."""
120
+ count = 0
121
+ for line in lines[start_index + 1 :]:
122
+ if ANY_H2_RE.match(line):
123
+ break
124
+ count += len(RECOMMENDED_MARKER_RE.findall(line))
125
+ return count
126
+
127
+
128
+ def _classify_command_file(path: Path) -> Finding | None:
129
+ """Return a finding when the command file lacks a valid block."""
130
+ try:
131
+ body = path.read_text(encoding="utf-8")
132
+ except (OSError, UnicodeDecodeError) as exc:
133
+ return Finding(
134
+ surface=str(path),
135
+ detail=f"could not read command file: {exc}",
136
+ )
137
+ lines = body.splitlines()
138
+ singular_index = next(
139
+ (i for i, line in enumerate(lines) if SINGULAR_HEADING_RE.match(line)),
140
+ None,
141
+ )
142
+ multi_index = next(
143
+ (i for i, line in enumerate(lines) if MULTI_HEADING_RE.match(line)),
144
+ None,
145
+ )
146
+ if singular_index is None and multi_index is None:
147
+ return Finding(
148
+ surface=str(path),
149
+ detail=(
150
+ "no `## Recommended Next Step` or `## Next Steps` heading "
151
+ "found; the command must close with the canonical block"
152
+ ),
153
+ )
154
+ if singular_index is not None:
155
+ if not _has_substantive_prose(lines, singular_index):
156
+ return Finding(
157
+ surface=str(path),
158
+ detail=(
159
+ "`## Recommended Next Step` heading present but block is "
160
+ "empty; the canonical form carries at least one prose line"
161
+ ),
162
+ )
163
+ return None
164
+ # Multi-action form: verify exactly one Recommended marker.
165
+ # singular_index is None here (else returned above) and not both were None,
166
+ # so multi_index is necessarily set; the guard narrows the type and is
167
+ # unreachable in practice.
168
+ if multi_index is None: # pragma: no cover
169
+ return None
170
+ marker_count = _count_recommended_markers(lines, multi_index)
171
+ if marker_count == 0:
172
+ return Finding(
173
+ surface=str(path),
174
+ detail=(
175
+ "`## Next Steps` block carries zero `**Recommended**` markers; "
176
+ "the multi-action form requires exactly one"
177
+ ),
178
+ )
179
+ if marker_count > 1:
180
+ return Finding(
181
+ surface=str(path),
182
+ detail=(
183
+ f"`## Next Steps` block carries {marker_count} `**Recommended**` "
184
+ f"markers; the multi-action form admits exactly one"
185
+ ),
186
+ )
187
+ return None
188
+
189
+
190
+ def check(root: Path) -> GrepResult:
191
+ """Sweep every command and skill surface under root for the block."""
192
+ findings: list[Finding] = []
193
+ files_inspected = 0
194
+
195
+ commands_dir = root / COMMANDS_DIR
196
+ if not commands_dir.is_dir():
197
+ findings.append(
198
+ Finding(
199
+ surface=COMMANDS_DIR,
200
+ detail=(f"commands directory absent at canonical path {commands_dir}"),
201
+ )
202
+ )
203
+ else:
204
+ for path in sorted(commands_dir.glob("*.md")):
205
+ if path.name in EXCLUDED_FILES:
206
+ continue
207
+ files_inspected += 1
208
+ finding = _classify_command_file(path)
209
+ if finding is not None:
210
+ findings.append(finding)
211
+
212
+ skills_dir = root / SKILLS_DIR
213
+ if not skills_dir.is_dir():
214
+ findings.append(
215
+ Finding(
216
+ surface=SKILLS_DIR,
217
+ detail=(f"skills directory absent at canonical path {skills_dir}"),
218
+ )
219
+ )
220
+ else:
221
+ for path in sorted(skills_dir.glob("*/SKILL.md")):
222
+ files_inspected += 1
223
+ finding = _classify_command_file(path)
224
+ if finding is not None:
225
+ findings.append(finding)
226
+
227
+ return GrepResult(
228
+ grep=GREP_NAME,
229
+ root=str(root),
230
+ files_inspected=files_inspected,
231
+ passed=not findings,
232
+ findings=findings,
233
+ )
234
+
235
+
236
+ def _read_input(argv: list[str]) -> Path:
237
+ if len(argv) >= 2:
238
+ return Path(argv[1])
239
+ return Path.cwd()
240
+
241
+
242
+ def _main(argv: list[str]) -> int:
243
+ root = _read_input(argv)
244
+ result = check(root)
245
+ print(result.to_json())
246
+ return EXIT_PASS if result.passed else EXIT_FAIL
247
+
248
+
249
+ if __name__ == "__main__":
250
+ sys.exit(_main(sys.argv))