@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,318 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """always-on-budget-grep: token-budget conformity matcher for always-on rules.
4
+
5
+ Why this enforcement exists. Always-on rules load into every session's
6
+ context as standing directives; aggregate body length is a multiplier on
7
+ every turn's cost. The token-budget-discipline rule caps each always-on
8
+ body at MAX_SUBSTANTIVE_TOKENS substantive tokens, with a pre-emptive
9
+ warn-band at WARN_BAND_THRESHOLD nudging authors to plan a path-filtered
10
+ companion sub-rule before the hard ceiling triggers. Bodies above the
11
+ ceiling are decomposed into the demand-load companion-sub-rule pattern
12
+ ratified at rules/context-management.md and its companion
13
+ rules/context-management-scratch.md.
14
+
15
+ Substantive-token counter. The count is a whitespace-separated token
16
+ count over the rule body with three regions excluded:
17
+
18
+ 1. YAML frontmatter — content between the opening `---` and the second
19
+ `---` delimiters at file head. Frontmatter declares the rule's
20
+ classification, not its directive content.
21
+ 2. The trailing `## Bindings (§0.j five-direction)` section — bindings
22
+ are pointers to peer artifacts, not standing directives. They
23
+ consume context but do not raise body-content load.
24
+ 3. Companion-sub-rule pointer lines — any line containing the literal
25
+ string `(Companion Sub-Rule Anchor)`. The pointer line names a
26
+ demand-load surface; the surface itself loads on path-filter match
27
+ and counts against its own (path-filtered) sibling rule, not the
28
+ parent always-on body.
29
+
30
+ Verdict matrix.
31
+ pass — the rule is not always-on (alwaysApply false OR pathFilter
32
+ non-empty), or the substantive-token count is at or below the
33
+ MAX_SUBSTANTIVE_TOKENS ceiling. WARN_BAND_THRESHOLD-MAX
34
+ counts produce an advisory in the finding payload but still
35
+ pass the gate.
36
+ FAIL — the substantive-token count exceeds MAX_SUBSTANTIVE_TOKENS;
37
+ the rule must be decomposed into a path-filtered companion
38
+ sub-rule with the parent body retaining only load-bearing
39
+ anchors plus the `(Companion Sub-Rule Anchor)` pointer.
40
+
41
+ Invocation. The matcher accepts either a single rule path on argv, a
42
+ directory (recurses over `*.md`), or `--stdin` reading the
43
+ rule body. When invoked with no path, defaults to scanning `rules/`
44
+ relative to the current working directory.
45
+ """
46
+
47
+ from __future__ import annotations
48
+
49
+ import json
50
+ import sys
51
+ from dataclasses import asdict, dataclass, field
52
+ from pathlib import Path
53
+ from typing import Final
54
+
55
+ # ---------------------------------------------------------------------------
56
+ # Module identity
57
+ # ---------------------------------------------------------------------------
58
+
59
+ GREP_NAME: Final[str] = "always-on-budget-grep"
60
+ RULE_ANCHOR: Final[str] = "D1 token-budget-discipline §Always-on body budget"
61
+ EXIT_PASS: Final[int] = 0
62
+ EXIT_FAIL: Final[int] = 2
63
+ STDIN_FLAG: Final[str] = "--stdin"
64
+
65
+ # ---------------------------------------------------------------------------
66
+ # Budget constants
67
+ # ---------------------------------------------------------------------------
68
+
69
+ MAX_SUBSTANTIVE_TOKENS: Final[int] = 500
70
+ WARN_BAND_THRESHOLD: Final[int] = 450
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # Region-exclusion markers
74
+ # ---------------------------------------------------------------------------
75
+
76
+ FRONTMATTER_DELIM: Final[str] = "---"
77
+ BINDINGS_HEADING_PREFIX: Final[str] = "## Bindings"
78
+ COMPANION_POINTER: Final[str] = "(Companion Sub-Rule Anchor)"
79
+ RULE_GLOB: Final[str] = "*.md"
80
+ DEFAULT_SCAN_DIR: Final[str] = "rules"
81
+
82
+
83
+ @dataclass(frozen=True)
84
+ class Finding:
85
+ """One per-rule budget verdict."""
86
+
87
+ path: str
88
+ always_on: bool
89
+ substantive_tokens: int
90
+ over_budget: bool
91
+ warn_band: bool
92
+ rule: str = RULE_ANCHOR
93
+
94
+
95
+ @dataclass(frozen=True)
96
+ class GrepResult:
97
+ grep: str
98
+ passed: bool
99
+ findings: list[Finding] = field(default_factory=list)
100
+
101
+ def to_json(self) -> str:
102
+ payload = {
103
+ "grep": self.grep,
104
+ "passed": self.passed,
105
+ "max-substantive-tokens": MAX_SUBSTANTIVE_TOKENS,
106
+ "warn-band-threshold": WARN_BAND_THRESHOLD,
107
+ "findings": [asdict(f) for f in self.findings],
108
+ }
109
+ return json.dumps(payload, indent=2)
110
+
111
+
112
+ def parse_frontmatter(content: str) -> tuple[dict[str, str], str]:
113
+ """Split frontmatter from body.
114
+
115
+ Args:
116
+ content: full rule file content.
117
+
118
+ Returns:
119
+ Tuple of (frontmatter mapping, body text). Frontmatter values are
120
+ stripped of surrounding quotes; missing keys yield an empty
121
+ mapping. When no frontmatter is present, returns ({}, content).
122
+
123
+ The parser tolerates a leading authorship-header banner (HTML comment
124
+ block on Markdown rules) preceding the frontmatter — it locates the
125
+ first `---` delimiter line that opens a YAML block whose immediate
126
+ content lines look like `key: value` pairs.
127
+ """
128
+ lines = content.splitlines()
129
+ start_index = -1
130
+ for i, line in enumerate(lines):
131
+ if line.strip() == FRONTMATTER_DELIM:
132
+ start_index = i
133
+ break
134
+ if start_index == -1:
135
+ return {}, content
136
+ end_index = -1
137
+ for i in range(start_index + 1, len(lines)):
138
+ if lines[i].strip() == FRONTMATTER_DELIM:
139
+ end_index = i
140
+ break
141
+ if end_index == -1:
142
+ return {}, content
143
+ fm: dict[str, str] = {}
144
+ for raw in lines[start_index + 1 : end_index]:
145
+ if ":" not in raw:
146
+ continue
147
+ key, _, value = raw.partition(":")
148
+ fm[key.strip()] = value.strip().strip('"').strip("'")
149
+ body = "\n".join(lines[end_index + 1 :])
150
+ return fm, body
151
+
152
+
153
+ def is_always_on(frontmatter: dict[str, str]) -> bool:
154
+ """Classify a rule as always-on per its frontmatter.
155
+
156
+ A rule is always-on iff `alwaysApply` is the literal string `true`
157
+ AND `pathFilter` is empty (absent or whitespace-only). Path-filtered
158
+ rules demand-load on glob match and are exempt from the body budget.
159
+ """
160
+ apply_value = frontmatter.get("alwaysApply", "").lower()
161
+ path_filter = frontmatter.get("pathFilter", "").strip()
162
+ return apply_value == "true" and path_filter == ""
163
+
164
+
165
+ def strip_bindings_section(body: str) -> str:
166
+ """Remove the trailing `## Bindings (§0.j five-direction)` section.
167
+
168
+ Bindings are reciprocal pointers to peer artifacts, not standing
169
+ directives; they are excluded from the substantive token count per
170
+ the rule's exclusion list.
171
+ """
172
+ lines = body.splitlines()
173
+ cut = -1
174
+ for i, line in enumerate(lines):
175
+ if line.lstrip().startswith(BINDINGS_HEADING_PREFIX):
176
+ cut = i
177
+ break
178
+ if cut == -1:
179
+ return body
180
+ return "\n".join(lines[:cut])
181
+
182
+
183
+ def strip_companion_pointers(body: str) -> str:
184
+ """Remove every line containing the companion-sub-rule pointer.
185
+
186
+ The pointer line names a demand-load surface; the surface itself is
187
+ weighed against its own path-filtered sibling rule, not the parent
188
+ always-on body.
189
+ """
190
+ return "\n".join(
191
+ line for line in body.splitlines() if COMPANION_POINTER not in line
192
+ )
193
+
194
+
195
+ def count_substantive_tokens(body: str) -> int:
196
+ """Count whitespace-separated tokens in the post-exclusion body.
197
+
198
+ The count is reproducible and platform-stable; markdown markers are
199
+ counted as tokens because they consume context just as words do.
200
+ """
201
+ return len(body.split())
202
+
203
+
204
+ def measure(content: str) -> tuple[bool, int]:
205
+ """Measure the always-on classification and the substantive token count.
206
+
207
+ Returns:
208
+ Tuple of (always_on, substantive_token_count). When the rule is
209
+ not always-on, the count is still reported for transparency but
210
+ the verdict is always pass.
211
+ """
212
+ frontmatter, body = parse_frontmatter(content)
213
+ always_on = is_always_on(frontmatter)
214
+ body_no_bindings = strip_bindings_section(body)
215
+ body_no_pointers = strip_companion_pointers(body_no_bindings)
216
+ return always_on, count_substantive_tokens(body_no_pointers)
217
+
218
+
219
+ def check_file(path: Path) -> Finding:
220
+ """Apply the matcher to a single rule file."""
221
+ content = path.read_text(encoding="utf-8")
222
+ always_on, tokens = measure(content)
223
+ over = always_on and tokens > MAX_SUBSTANTIVE_TOKENS
224
+ warn = always_on and (not over) and tokens >= WARN_BAND_THRESHOLD
225
+ return Finding(
226
+ path=str(path),
227
+ always_on=always_on,
228
+ substantive_tokens=tokens,
229
+ over_budget=over,
230
+ warn_band=warn,
231
+ )
232
+
233
+
234
+ def check(content: str, path: Path | None = None) -> GrepResult:
235
+ """Per-Write dispatch entry consumed by `conformity/gate.py`.
236
+
237
+ Measures one rule body's substantive-token count. The orchestrator
238
+ invokes this on every Write/Edit; non-rule paths and non-always-on
239
+ rules pass without a finding.
240
+
241
+ Pre-conditions: `content` is the artifact about to be emitted; `path`
242
+ is the target file path or None.
243
+ Post-conditions: `result.passed` is True iff the artifact is not an
244
+ over-budget always-on rule body.
245
+ """
246
+ path_str = str(path) if path is not None else "<stdin>"
247
+ if path is not None and not path_str.endswith(".md"):
248
+ return GrepResult(grep=GREP_NAME, passed=True, findings=[])
249
+ always_on, tokens = measure(content)
250
+ over = always_on and tokens > MAX_SUBSTANTIVE_TOKENS
251
+ warn = always_on and (not over) and tokens >= WARN_BAND_THRESHOLD
252
+ finding = Finding(
253
+ path=path_str,
254
+ always_on=always_on,
255
+ substantive_tokens=tokens,
256
+ over_budget=over,
257
+ warn_band=warn,
258
+ )
259
+ if not over:
260
+ return GrepResult(grep=GREP_NAME, passed=True, findings=[])
261
+ return GrepResult(grep=GREP_NAME, passed=False, findings=[finding])
262
+
263
+
264
+ def discover_rule_files(target: Path) -> list[Path]:
265
+ """Resolve a target into the rule files to inspect."""
266
+ if target.is_file():
267
+ return [target]
268
+ if target.is_dir():
269
+ return sorted(target.rglob(RULE_GLOB))
270
+ raise FileNotFoundError(f"target does not exist: {target}")
271
+
272
+
273
+ def _read_stdin_finding() -> Finding:
274
+ content = sys.stdin.read()
275
+ always_on, tokens = measure(content)
276
+ over = always_on and tokens > MAX_SUBSTANTIVE_TOKENS
277
+ warn = always_on and (not over) and tokens >= WARN_BAND_THRESHOLD
278
+ return Finding(
279
+ path="<stdin>",
280
+ always_on=always_on,
281
+ substantive_tokens=tokens,
282
+ over_budget=over,
283
+ warn_band=warn,
284
+ )
285
+
286
+
287
+ def _resolve_target(argv: list[str]) -> Path:
288
+ if len(argv) >= 2:
289
+ return Path(argv[1])
290
+ return Path(DEFAULT_SCAN_DIR)
291
+
292
+
293
+ def _main(argv: list[str]) -> int:
294
+ if len(argv) >= 2 and argv[1] == STDIN_FLAG:
295
+ finding = _read_stdin_finding()
296
+ result = GrepResult(
297
+ grep=GREP_NAME,
298
+ passed=not finding.over_budget,
299
+ findings=[finding],
300
+ )
301
+ print(result.to_json())
302
+ return EXIT_PASS if result.passed else EXIT_FAIL
303
+
304
+ target = _resolve_target(argv)
305
+ paths = discover_rule_files(target)
306
+ findings = [check_file(p) for p in paths]
307
+ failed = [f for f in findings if f.over_budget]
308
+ result = GrepResult(
309
+ grep=GREP_NAME,
310
+ passed=not failed,
311
+ findings=findings,
312
+ )
313
+ print(result.to_json())
314
+ return EXIT_PASS if result.passed else EXIT_FAIL
315
+
316
+
317
+ if __name__ == "__main__":
318
+ sys.exit(_main(sys.argv))
@@ -0,0 +1,115 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Flag bare except clauses without typed exceptions or re-raise.
4
+
5
+ Why this enforcement exists. The code-craft rule M13.3 forbids bare
6
+ `except:` and broad `except Exception:` that swallow errors silently.
7
+ Caught exceptions are typed and either handled with rationale or
8
+ re-raised with context. The pre-emission gate's mechanical bar 13 (M13 code craft)
9
+ catches both bare-clause shapes and the broad-Exception form (without
10
+ re-raise) and surfaces each occurrence so the operator either narrows
11
+ the type or adds a `raise` so the failure propagates.
12
+
13
+ Detection strategy. The grep walks Python source for `except:` (no
14
+ type spec), `except Exception:` / `except BaseException:` (broad), and
15
+ the parenthesized-tuple form that contains a broad type
16
+ (`except (ValueError, Exception):`); within each clause's body it
17
+ inspects whether the body contains a `raise` statement. A clause that
18
+ catches broadly without re-raising is the canonical violation; bare
19
+ `except:` is always flagged.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import re
25
+ import sys
26
+ from dataclasses import dataclass
27
+ from pathlib import Path
28
+ from typing import Final
29
+
30
+ from apothem.conformity._grep_base import GrepResult, run_grep
31
+
32
+ # Bare or broad except shapes. Bare `except:` matches with no type
33
+ # specifier; broad forms catch the root exception types either directly
34
+ # (`except Exception:`) or inside a tuple (`except (ValueError, Exception):`).
35
+ # The match groups capture the form for the finding's report.
36
+ BARE_EXCEPT_RE: Final[re.Pattern[str]] = re.compile(
37
+ r"^(\s*)except\s*(?:"
38
+ r":" # bare `except:`
39
+ r"|(" # group 2: a broad spec including the trailing colon
40
+ r"(?:Exception|BaseException)(?:\s+as\s+\w+)?\s*:" # broad single type
41
+ r"|\([^)]*\b(?:Exception|BaseException)\b[^)]*\)(?:\s+as\s+\w+)?\s*:" # broad tuple
42
+ r"))"
43
+ )
44
+ RAISE_RE: Final[re.Pattern[str]] = re.compile(r"^\s+raise\b")
45
+ # A re-raise written inline after the `except ...:` colon — `except
46
+ # Exception: raise` or `except Exception: log(); raise`. Matched at the
47
+ # start of the inline body or immediately after a `;` statement separator,
48
+ # so an inline re-raise is recognized as faithfully as a subsequent-line one.
49
+ INLINE_RAISE_RE: Final[re.Pattern[str]] = re.compile(r"(?:^|;)\s*raise\b")
50
+ GREP_NAME: Final[str] = "bare-except-grep"
51
+ RULE_ANCHOR: Final[str] = "M13.3 error handling"
52
+ EXIT_PASS: Final[int] = 0
53
+ EXIT_FAIL: Final[int] = 2
54
+ STDIN_FLAG: Final[str] = "--stdin"
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class Finding:
59
+ line: int
60
+ form: str
61
+ detail: str
62
+ rule: str = RULE_ANCHOR
63
+
64
+
65
+ def _clause_has_raise(lines: list[str], clause_index: int, indent: int) -> bool:
66
+ """Walk the clause body until dedent; return True iff any line is a raise."""
67
+ body_indent_min = indent + 1
68
+ for line in lines[clause_index + 1 :]:
69
+ if not line.strip():
70
+ continue
71
+ leading = len(line) - len(line.lstrip())
72
+ if leading < body_indent_min:
73
+ return False
74
+ if RAISE_RE.match(line):
75
+ return True
76
+ return False
77
+
78
+
79
+ def check(content: str, path: Path | None = None) -> GrepResult:
80
+ """Scan content; return a structured result."""
81
+ findings: list[Finding] = []
82
+ lines = content.splitlines()
83
+ for index, line in enumerate(lines):
84
+ match = BARE_EXCEPT_RE.match(line)
85
+ if match is None:
86
+ continue
87
+ indent = len(match.group(1))
88
+ is_bare = match.group(2) is None
89
+ form = "bare except:" if is_bare else "broad except: " + match.group(2).strip()
90
+ # Bare except is always a finding. Broad except is a finding only
91
+ # when the clause body contains no `raise` — counting both a
92
+ # subsequent indented line and an inline re-raise on the `except`
93
+ # line itself (`except Exception: raise`), so a faithful inline
94
+ # re-raise is not flagged as a swallow.
95
+ inline_body = line[match.end() :]
96
+ has_raise = bool(INLINE_RAISE_RE.search(inline_body)) or _clause_has_raise(
97
+ lines, index, indent
98
+ )
99
+ if is_bare or not has_raise:
100
+ detail = (
101
+ "bare except swallows every exception class"
102
+ if is_bare
103
+ else "broad except without re-raise; narrow the type or add raise"
104
+ )
105
+ findings.append(Finding(line=index + 1, form=form, detail=detail))
106
+ return GrepResult(
107
+ grep=GREP_NAME,
108
+ path=str(path) if path is not None else None,
109
+ passed=not findings,
110
+ findings=findings,
111
+ )
112
+
113
+
114
+ if __name__ == "__main__":
115
+ sys.exit(run_grep(check, sys.argv))
@@ -0,0 +1,151 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Flag binding declarations using non-canonical arrow notation.
4
+
5
+ Why this enforcement exists. The bidirectional-binding rule M10 declares
6
+ five canonical arrows — `→` (Drives), `←` (Driven by), `↑` (Established by),
7
+ `↓` (rare downward; reserved), and `↔` (Cross-bound with) — that every
8
+ Bindings section uses verbatim. ASCII substitutes (`->`, `<-`, `<->`) and
9
+ emoji-arrow variants are notation drift; they break sibling-convergence and
10
+ the mechanical reciprocity walk that future cross-file matchers will perform.
11
+ This grep enforces the in-file shape of the Bindings section: heading is
12
+ present and well-named, every arrow is from the canonical set, no ASCII
13
+ arrows appear in the Bindings region.
14
+
15
+ Cross-file reciprocity check (full half-edge detection across the rule set)
16
+ is out of scope for this per-file grep — it requires a corpus walk that
17
+ the orchestrator at `gate.py` will assemble. The per-file
18
+ contribution here is the notation discipline within each Bindings section.
19
+
20
+ Code is excluded from the arrow scan: fenced code blocks and inline-code spans
21
+ inside a Bindings section legitimately quote ASCII arrows (a Python return
22
+ annotation, a shell pipe, a CLI usage snippet), which are quotations rather than
23
+ Bindings notation.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import re
29
+ import sys
30
+ from dataclasses import dataclass
31
+ from pathlib import Path
32
+ from typing import Final
33
+
34
+ from apothem.conformity._grep_base import GrepResult, run_grep
35
+
36
+ # The canonical Bindings section heading per the §0.j five-direction notation.
37
+ # Rule files use `## Bindings (§0.j five-direction)`; some siblings drop the
38
+ # parenthetical. Both are accepted as valid section markers; the grep starts
39
+ # scanning at the first match and stops at the next H1/H2 heading.
40
+ BINDINGS_HEADING_RE: Final[re.Pattern[str]] = re.compile(
41
+ r"^##\s+Bindings(?:\s+\(§0\.j\s+five-direction\))?\s*$"
42
+ )
43
+ NEXT_HEADING_RE: Final[re.Pattern[str]] = re.compile(r"^##?\s+\S")
44
+
45
+ # ASCII substitute arrows that are notation drift. The rule's spec lists
46
+ # them explicitly as forbidden alternatives.
47
+ FORBIDDEN_ARROWS: Final[tuple[str, ...]] = (
48
+ "->",
49
+ "<-",
50
+ "<->",
51
+ "<=",
52
+ "=>",
53
+ )
54
+ FORBIDDEN_ARROW_RE: Final[re.Pattern[str]] = re.compile(
55
+ "|".join(re.escape(a) for a in FORBIDDEN_ARROWS)
56
+ )
57
+
58
+ # The canonical arrow alphabet. Any character outside this set inside an arrow
59
+ # context is suspect, but we only flag the explicit ASCII substitutes since
60
+ # free-form prose may legitimately contain any Unicode character.
61
+ CANONICAL_ARROWS: Final[frozenset[str]] = frozenset({"→", "←", "↑", "↓", "↔"})
62
+
63
+ # Code spans inside the Bindings section legitimately quote ASCII arrows — a
64
+ # Python return annotation (`f() -> str`), a shell pipe, a CLI usage snippet —
65
+ # so fenced blocks and inline-code spans are excluded from the arrow scan.
66
+ _CODE_FENCE_RE: Final[re.Pattern[str]] = re.compile(r"^```")
67
+ _INLINE_CODE_RE: Final[re.Pattern[str]] = re.compile(r"`[^`]*`")
68
+
69
+ GREP_NAME: Final[str] = "binding-reciprocity-grep"
70
+ RULE_ANCHOR: Final[str] = "M10 bidirectional-binding §Notation"
71
+ EXIT_PASS: Final[int] = 0
72
+ EXIT_FAIL: Final[int] = 2
73
+ STDIN_FLAG: Final[str] = "--stdin"
74
+
75
+
76
+ @dataclass(frozen=True)
77
+ class Finding:
78
+ """One notation-drift occurrence inside the Bindings section."""
79
+
80
+ line: int
81
+ match: str
82
+ context: str
83
+ rule: str = RULE_ANCHOR
84
+
85
+
86
+ def _bindings_region(lines: list[str]) -> tuple[int, int] | None:
87
+ """Locate the Bindings section as a (start, end) line-range pair.
88
+
89
+ Returns a 1-indexed inclusive start line and exclusive end line, or
90
+ None if no Bindings section is present in the artifact.
91
+ """
92
+ start: int | None = None
93
+ for i, line in enumerate(lines):
94
+ if start is None:
95
+ if BINDINGS_HEADING_RE.match(line):
96
+ start = i + 1 # First content line after the heading.
97
+ continue
98
+ # Past the heading; the section ends at the next heading.
99
+ if NEXT_HEADING_RE.match(line):
100
+ return start, i
101
+ if start is not None:
102
+ return start, len(lines)
103
+ return None
104
+
105
+
106
+ def check(content: str, path: Path | None = None) -> GrepResult:
107
+ """Scan content; return a structured result.
108
+
109
+ Pre-conditions: `content` is the artifact body about to be emitted.
110
+ Post-conditions: `result.passed` is True when either the Bindings
111
+ section is absent (not every artifact has one) or the section uses
112
+ only canonical arrow notation.
113
+ """
114
+ lines = content.splitlines()
115
+ region = _bindings_region(lines)
116
+ if region is None:
117
+ return GrepResult(
118
+ grep=GREP_NAME,
119
+ path=str(path) if path is not None else None,
120
+ passed=True,
121
+ )
122
+ findings: list[Finding] = []
123
+ start, end = region
124
+ inside_fence = False
125
+ for offset, line in enumerate(lines[start - 1 : end], start=start):
126
+ if _CODE_FENCE_RE.match(line):
127
+ inside_fence = not inside_fence
128
+ continue
129
+ if inside_fence:
130
+ continue
131
+ # Blank inline-code spans (same-length spaces preserve columns) so a
132
+ # quoted ASCII arrow inside backticks is not read as notation drift.
133
+ scanned = _INLINE_CODE_RE.sub(lambda m: " " * len(m.group(0)), line)
134
+ for match in FORBIDDEN_ARROW_RE.finditer(scanned):
135
+ findings.append(
136
+ Finding(
137
+ line=offset,
138
+ match=match.group(),
139
+ context=line.strip(),
140
+ )
141
+ )
142
+ return GrepResult(
143
+ grep=GREP_NAME,
144
+ path=str(path) if path is not None else None,
145
+ passed=not findings,
146
+ findings=findings,
147
+ )
148
+
149
+
150
+ if __name__ == "__main__":
151
+ sys.exit(run_grep(check, sys.argv))