@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,1125 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Detailed AI-conventions surface presence and coherence map.
4
+
5
+ Why this tool exists. The ecosystem ships its AI-assistant directive
6
+ prose across multiple surfaces — ``AGENTS.md`` (canonical project voice),
7
+ ``CLAUDE.md`` (Claude Code mirror), ``.github/copilot-instructions.md``
8
+ (GitHub Copilot voice), and optional siblings
9
+ (``site/content/docs/architecture/agents.mdx``, ``.cursorrules``,
10
+ ``.windsurfrules``) per the operator's opt-in. Each surface MUST carry
11
+ the same shared discipline claims (Plans Discipline, ambiguity
12
+ resolution, authorship header, naming, anti-patterns, modal hierarchy)
13
+ and SHOULD carry the canonical nine-section structure (Project Context,
14
+ Coding Conventions, File Headers, Plans Discipline, structured-inquiry Equivalent Behavior, Forbidden Patterns, Output Format, Review
15
+ Checklist, Pointers). The coarse pre-scan at the prior audit step
16
+ records bare presence; this deeper scan walks every present surface,
17
+ parses level-two headings, tests for the nine canonical sections by a
18
+ heading-and-body heuristic, computes the pairwise shared-section
19
+ coherence map across present surfaces, and emits a per-surface
20
+ authoring / refinement plan that the downstream Copilot-instructions
21
+ author, optional-surface generator, and instruction-surface refit consume.
22
+
23
+ What the tool captures. For every candidate surface in scope:
24
+ ``path``, ``presence`` (``present`` / ``absent`` / ``partial``),
25
+ ``sha256``, ``line-count``, parsed level-two headings, and a section-
26
+ presence map naming each canonical section's status (``present`` /
27
+ ``absent`` / ``renamed-to:<heading-text>``). The coherence map carries
28
+ one entry per ordered pair of present surfaces; each entry records, for
29
+ every shared section (Plans Discipline, Structured Inquiry,
30
+ File Headers, Forbidden Patterns, Naming, Anti-Patterns, Modal
31
+ Hierarchy), one of four verdicts: ``coherent``, ``contradicts``,
32
+ ``partial``, ``n/a``. The authoring / refinement plan is an array of
33
+ per-surface action items naming the missing-section template to
34
+ install, the present-but-drifted section delta to apply, or the
35
+ contradiction reconciliation path (default: ``AGENTS.md`` is the
36
+ canonical project voice; the divergent surface mirrors).
37
+
38
+ What the tool reports. ``ai-surfaces.json`` (machine-readable) and
39
+ ``ai-surfaces.md`` (human-readable mirror) at ``.audit/``. The deeper
40
+ authoring passes consume the plan; the coherence-validator's fixture
41
+ template is informed by this map's structure.
42
+
43
+ Scope boundary. The tool ONLY reads the candidate surface files; it
44
+ NEVER writes to them. The semantic-equivalence test on shared sections
45
+ is heuristic (key-token overlap and claim-pattern matching); the
46
+ rigorous test lives at the multi-surface coherence validator and is
47
+ fixture-driven.
48
+ """
49
+
50
+ from __future__ import annotations
51
+
52
+ import argparse
53
+ import hashlib
54
+ import json
55
+ import re
56
+ import sys
57
+ from dataclasses import asdict, dataclass
58
+ from datetime import datetime, timezone
59
+ from pathlib import Path
60
+ from typing import Final
61
+
62
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
63
+
64
+ from _scan_lib import load_inventory, read_text_safely
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Candidate surface catalog. Each entry names the canonical relative
68
+ # path, the surface's role in the ecosystem, and whether the surface is
69
+ # mandatory or opt-in. The order is the canonical reading order for
70
+ # every output table.
71
+ # ---------------------------------------------------------------------------
72
+ SURFACE_AGENTS_ROOT: Final[str] = "AGENTS.md"
73
+ SURFACE_CLAUDE_ROOT: Final[str] = "CLAUDE.md"
74
+ SURFACE_CLAUDE_NESTED: Final[str] = ".claude/CLAUDE.md"
75
+ SURFACE_COPILOT: Final[str] = ".github/copilot-instructions.md"
76
+ SURFACE_AGENTS_DOC: Final[str] = "site/content/docs/architecture/agents.mdx"
77
+ SURFACE_CURSOR: Final[str] = ".cursorrules"
78
+ SURFACE_WINDSURF: Final[str] = ".windsurfrules"
79
+
80
+
81
+ @dataclass(frozen=True)
82
+ class SurfaceDescriptor:
83
+ """One candidate surface plus its mandatory / opt-in disposition."""
84
+
85
+ path: str
86
+ role: str
87
+ mandatory: bool
88
+
89
+
90
+ CANDIDATE_SURFACES: Final[tuple[SurfaceDescriptor, ...]] = (
91
+ SurfaceDescriptor(SURFACE_AGENTS_ROOT, "Canonical project instructions", True),
92
+ SurfaceDescriptor(SURFACE_CLAUDE_ROOT, "Claude Code mirror", True),
93
+ SurfaceDescriptor(SURFACE_CLAUDE_NESTED, "Claude (mirror layout)", False),
94
+ SurfaceDescriptor(SURFACE_COPILOT, "GitHub Copilot", True),
95
+ SurfaceDescriptor(SURFACE_AGENTS_DOC, "Multi-agent platforms", False),
96
+ SurfaceDescriptor(SURFACE_CURSOR, "Cursor", False),
97
+ SurfaceDescriptor(SURFACE_WINDSURF, "Windsurf", False),
98
+ )
99
+
100
+
101
+ # ---------------------------------------------------------------------------
102
+ # Canonical nine-section catalog. Each section carries:
103
+ # - ``slug`` — stable identifier used as the JSON key.
104
+ # - ``display`` — human-readable section title (matches the spec body).
105
+ # - ``heading_keywords`` — case-insensitive substrings any one of which,
106
+ # present in a level-two heading, qualifies the heading as the section.
107
+ # - ``body_signatures`` — substrings whose presence in the body of a
108
+ # heading signals the canonical content is there even when the
109
+ # heading text is renamed.
110
+ # - ``is_shared`` — whether the section participates in the cross-
111
+ # surface coherence contract.
112
+ # ---------------------------------------------------------------------------
113
+
114
+
115
+ @dataclass(frozen=True)
116
+ class CanonicalSection:
117
+ slug: str
118
+ display: str
119
+ heading_keywords: tuple[str, ...]
120
+ body_signatures: tuple[str, ...]
121
+ is_shared: bool
122
+
123
+
124
+ CANONICAL_SECTIONS: Final[tuple[CanonicalSection, ...]] = (
125
+ CanonicalSection(
126
+ slug="project-context",
127
+ display="Project Context",
128
+ heading_keywords=(
129
+ "project context",
130
+ "context",
131
+ "about this",
132
+ "what this is",
133
+ "overview",
134
+ "introduction",
135
+ ),
136
+ body_signatures=("repository", "ecosystem", "purpose", "scope"),
137
+ is_shared=False,
138
+ ),
139
+ CanonicalSection(
140
+ slug="coding-conventions",
141
+ display="Coding Conventions",
142
+ heading_keywords=(
143
+ "coding conventions",
144
+ "conventions",
145
+ "code style",
146
+ "style",
147
+ "naming",
148
+ ),
149
+ body_signatures=(
150
+ "kebab-case",
151
+ "snake_case",
152
+ "PascalCase",
153
+ "RFC 2119",
154
+ "MUST",
155
+ "modal",
156
+ ),
157
+ is_shared=False,
158
+ ),
159
+ CanonicalSection(
160
+ slug="file-headers",
161
+ display="File Headers",
162
+ heading_keywords=(
163
+ "file headers",
164
+ "file header",
165
+ "authorship header",
166
+ "authorship banner",
167
+ "header banner",
168
+ "banner",
169
+ ),
170
+ body_signatures=(
171
+ "Copyright (c)",
172
+ "All rights reserved",
173
+ "inject-header",
174
+ "authorship-header",
175
+ "five canonical lines",
176
+ ),
177
+ is_shared=True,
178
+ ),
179
+ CanonicalSection(
180
+ slug="plans-discipline",
181
+ display="Plans Discipline",
182
+ heading_keywords=(
183
+ "plans discipline",
184
+ "plans-discipline",
185
+ "planning artifacts",
186
+ ".plans/",
187
+ ),
188
+ body_signatures=(
189
+ "<project-root>/.plans/",
190
+ "project-root/.plans",
191
+ "~/.claude/.plans/",
192
+ "no-global-plans",
193
+ ".plans/ at the project root",
194
+ "ephemeral working memory",
195
+ ),
196
+ is_shared=True,
197
+ ),
198
+ CanonicalSection(
199
+ slug="Structured Inquiry",
200
+ display="Structured Inquiry Behavior",
201
+ heading_keywords=(
202
+ "structured inquiry",
203
+ "ask user",
204
+ "ambiguity",
205
+ "clarification",
206
+ "interactive question",
207
+ "structured inquiry",
208
+ "todo(clarify)",
209
+ ),
210
+ body_signatures=(
211
+ "structured inquiry",
212
+ "TODO(clarify)",
213
+ "never invent",
214
+ "no silent",
215
+ "structured-inquiry",
216
+ "interactive-questions",
217
+ ),
218
+ is_shared=True,
219
+ ),
220
+ CanonicalSection(
221
+ slug="forbidden-patterns",
222
+ display="Forbidden Patterns",
223
+ heading_keywords=(
224
+ "forbidden patterns",
225
+ "forbidden",
226
+ "anti-patterns",
227
+ "anti patterns",
228
+ "do not",
229
+ "never do",
230
+ "prohibitions",
231
+ ),
232
+ body_signatures=(
233
+ "no marketing",
234
+ "no hedging",
235
+ "console.log",
236
+ "absolute path",
237
+ "do not commit",
238
+ "never commit",
239
+ "MUST NOT",
240
+ ),
241
+ is_shared=True,
242
+ ),
243
+ CanonicalSection(
244
+ slug="output-format",
245
+ display="Output Format",
246
+ heading_keywords=(
247
+ "output format",
248
+ "output conventions",
249
+ "output discipline",
250
+ "response format",
251
+ "generation format",
252
+ ),
253
+ body_signatures=(
254
+ "definitiveness",
255
+ "uniform sectioning",
256
+ "summary discipline",
257
+ "citations",
258
+ "typed",
259
+ "documented public surface",
260
+ ),
261
+ is_shared=False,
262
+ ),
263
+ CanonicalSection(
264
+ slug="review-checklist",
265
+ display="Review Checklist",
266
+ heading_keywords=(
267
+ "review checklist",
268
+ "checklist",
269
+ "before approving",
270
+ "review before",
271
+ "pr review",
272
+ "merge checklist",
273
+ ),
274
+ body_signatures=(
275
+ "header present",
276
+ "naming compliant",
277
+ "no .plans/ writes",
278
+ "validators green",
279
+ "no contradictions",
280
+ ),
281
+ is_shared=False,
282
+ ),
283
+ CanonicalSection(
284
+ slug="pointers",
285
+ display="Pointers",
286
+ heading_keywords=(
287
+ "pointers",
288
+ "references",
289
+ "see also",
290
+ "links",
291
+ "further reading",
292
+ "registry",
293
+ "registries",
294
+ ),
295
+ body_signatures=(
296
+ "site/content/docs/reference/plans-discipline",
297
+ "site/content/docs/reference/authorship-header",
298
+ "site/content/docs/reference/ai-conventions",
299
+ "CONTRIBUTING.md",
300
+ ),
301
+ is_shared=False,
302
+ ),
303
+ )
304
+
305
+
306
+ # Naming and Modal Hierarchy are sub-claims of Coding Conventions per
307
+ # the canonical nine-section list, but the coherence contract enumerates
308
+ # them as discrete shared sections. Each carries its own keyword and
309
+ # body signature so the cross-surface diff can attribute a contradiction
310
+ # to the right axis.
311
+ EXTRA_SHARED_SECTIONS: Final[tuple[CanonicalSection, ...]] = (
312
+ CanonicalSection(
313
+ slug="naming",
314
+ display="Naming",
315
+ heading_keywords=(
316
+ "naming",
317
+ "file naming",
318
+ "directory naming",
319
+ "kebab-case",
320
+ ),
321
+ body_signatures=(
322
+ "kebab-case",
323
+ "snake_case",
324
+ "PascalCase",
325
+ "UPPER_SNAKE_CASE",
326
+ ),
327
+ is_shared=True,
328
+ ),
329
+ CanonicalSection(
330
+ slug="modal-hierarchy",
331
+ display="Modal Hierarchy",
332
+ heading_keywords=(
333
+ "modal hierarchy",
334
+ "modal",
335
+ "RFC 2119",
336
+ "RFC2119",
337
+ "MUST / SHOULD",
338
+ ),
339
+ body_signatures=(
340
+ "RFC 2119",
341
+ "MUST",
342
+ "MUST NOT",
343
+ "SHOULD",
344
+ "SHOULD NOT",
345
+ "MAY",
346
+ ),
347
+ is_shared=True,
348
+ ),
349
+ )
350
+
351
+ ALL_SECTIONS_FOR_PRESENCE: Final[tuple[CanonicalSection, ...]] = CANONICAL_SECTIONS
352
+
353
+ SHARED_SECTIONS_FOR_COHERENCE: Final[tuple[CanonicalSection, ...]] = (
354
+ *(s for s in CANONICAL_SECTIONS if s.is_shared),
355
+ *EXTRA_SHARED_SECTIONS,
356
+ )
357
+
358
+
359
+ # ---------------------------------------------------------------------------
360
+ # Coherence verdict taxonomy.
361
+ # ---------------------------------------------------------------------------
362
+ COHERENCE_COHERENT: Final[str] = "coherent"
363
+ COHERENCE_CONTRADICTS: Final[str] = "contradicts"
364
+ COHERENCE_PARTIAL: Final[str] = "partial"
365
+ COHERENCE_NOT_APPLICABLE: Final[str] = "n/a"
366
+
367
+
368
+ # Section-presence verdict prefixes.
369
+ PRESENCE_PRESENT: Final[str] = "present"
370
+ PRESENCE_ABSENT: Final[str] = "absent"
371
+ PRESENCE_RENAMED_PREFIX: Final[str] = "renamed-to:"
372
+
373
+ # Surface-presence (top-level) verdicts.
374
+ SURFACE_PRESENT: Final[str] = "present"
375
+ SURFACE_ABSENT: Final[str] = "absent"
376
+ SURFACE_PARTIAL: Final[str] = "partial"
377
+
378
+
379
+ # ---------------------------------------------------------------------------
380
+ # Heading parsing. We extract every level-two heading and the body block
381
+ # that follows up to the next level-two heading.
382
+ # ---------------------------------------------------------------------------
383
+ HEADING_RE: Final[re.Pattern[str]] = re.compile(
384
+ r"^(?P<hashes>#{1,6})\s+(?P<text>.+?)\s*$",
385
+ re.MULTILINE,
386
+ )
387
+
388
+
389
+ @dataclass(frozen=True)
390
+ class HeadingBlock:
391
+ level: int
392
+ text: str
393
+ line_start: int
394
+ line_end: int
395
+ body: str
396
+
397
+
398
+ def parse_headings(content: str) -> list[HeadingBlock]:
399
+ """Return every heading paired with its body block.
400
+
401
+ A heading's body extends from the line after the heading up to the
402
+ line before the next heading at the same or shallower depth. We use
403
+ a flat slice and the parser keeps every heading level so the
404
+ section-presence heuristic can pick the most specific match.
405
+ """
406
+ lines = content.splitlines()
407
+ matches: list[tuple[int, int, str]] = []
408
+ for index, line in enumerate(lines):
409
+ match = HEADING_RE.match(line)
410
+ if match is None:
411
+ continue
412
+ level = len(match.group("hashes"))
413
+ text = match.group("text").strip()
414
+ matches.append((index, level, text))
415
+ blocks: list[HeadingBlock] = []
416
+ for position, (line_index, level, text) in enumerate(matches):
417
+ start = line_index + 1
418
+ if position + 1 < len(matches):
419
+ next_line, _next_level, _ = matches[position + 1]
420
+ end = next_line
421
+ else:
422
+ end = len(lines)
423
+ body = "\n".join(lines[start:end])
424
+ blocks.append(
425
+ HeadingBlock(
426
+ level=level,
427
+ text=text,
428
+ line_start=line_index + 1,
429
+ line_end=end,
430
+ body=body,
431
+ )
432
+ )
433
+ return blocks
434
+
435
+
436
+ def heading_text_matches(text: str, keywords: tuple[str, ...]) -> bool:
437
+ """Case-insensitive substring test against any one keyword."""
438
+ lowered = text.lower()
439
+ return any(keyword.lower() in lowered for keyword in keywords)
440
+
441
+
442
+ def body_signature_count(body: str, signatures: tuple[str, ...]) -> int:
443
+ """Count the distinct signature substrings present in a body block.
444
+
445
+ Case-sensitive — banner text and modal verbs are case-meaningful.
446
+ """
447
+ return sum(1 for signature in signatures if signature in body)
448
+
449
+
450
+ def detect_section_presence(
451
+ section: CanonicalSection,
452
+ headings: list[HeadingBlock],
453
+ full_content: str,
454
+ ) -> str:
455
+ """Return ``present`` / ``absent`` / ``renamed-to:<text>``.
456
+
457
+ Order of preference:
458
+ 1. A heading whose text matches the section's keywords AND whose
459
+ body carries at least one signature → ``present``.
460
+ 2. A heading whose text matches the keywords but whose body lacks a
461
+ signature → still ``present`` (the heading is the canonical
462
+ claim; signature absence may indicate an under-fleshed section
463
+ but not a renamed section).
464
+ 3. No heading-text match, but a heading whose body carries at least
465
+ one signature → ``renamed-to:<heading-text>``. The first such
466
+ heading by document order wins.
467
+ 4. No heading-text match and no body-signature match anywhere →
468
+ ``absent``.
469
+ """
470
+ for heading in headings:
471
+ if heading_text_matches(heading.text, section.heading_keywords):
472
+ return PRESENCE_PRESENT
473
+ for heading in headings:
474
+ if body_signature_count(heading.body, section.body_signatures) > 0:
475
+ return f"{PRESENCE_RENAMED_PREFIX}{heading.text}"
476
+ if body_signature_count(full_content, section.body_signatures) > 0:
477
+ return f"{PRESENCE_RENAMED_PREFIX}<no-heading-found>"
478
+ return PRESENCE_ABSENT
479
+
480
+
481
+ # ---------------------------------------------------------------------------
482
+ # Per-surface scan.
483
+ # ---------------------------------------------------------------------------
484
+
485
+
486
+ @dataclass
487
+ class SurfaceScan:
488
+ descriptor: SurfaceDescriptor
489
+ presence: str
490
+ sha256: str | None
491
+ line_count: int
492
+ headings: list[HeadingBlock]
493
+ section_presence: dict[str, str]
494
+ raw_content: str
495
+
496
+
497
+ def scan_surface(descriptor: SurfaceDescriptor, root: Path) -> SurfaceScan:
498
+ target = root / descriptor.path
499
+ if not target.exists() or not target.is_file():
500
+ return SurfaceScan(
501
+ descriptor=descriptor,
502
+ presence=SURFACE_ABSENT,
503
+ sha256=None,
504
+ line_count=0,
505
+ headings=[],
506
+ section_presence={
507
+ s.slug: PRESENCE_ABSENT for s in ALL_SECTIONS_FOR_PRESENCE
508
+ },
509
+ raw_content="",
510
+ )
511
+ content = read_text_safely(target)
512
+ if not content:
513
+ return SurfaceScan(
514
+ descriptor=descriptor,
515
+ presence=SURFACE_PARTIAL,
516
+ sha256=None,
517
+ line_count=0,
518
+ headings=[],
519
+ section_presence={
520
+ s.slug: PRESENCE_ABSENT for s in ALL_SECTIONS_FOR_PRESENCE
521
+ },
522
+ raw_content="",
523
+ )
524
+ raw = target.read_bytes()
525
+ sha = hashlib.sha256(raw).hexdigest()
526
+ headings = parse_headings(content)
527
+ line_count = len(content.splitlines())
528
+ presence_map: dict[str, str] = {}
529
+ for section in ALL_SECTIONS_FOR_PRESENCE:
530
+ presence_map[section.slug] = detect_section_presence(section, headings, content)
531
+ return SurfaceScan(
532
+ descriptor=descriptor,
533
+ presence=SURFACE_PRESENT,
534
+ sha256=sha,
535
+ line_count=line_count,
536
+ headings=headings,
537
+ section_presence=presence_map,
538
+ raw_content=content,
539
+ )
540
+
541
+
542
+ # ---------------------------------------------------------------------------
543
+ # Coherence map. For every ordered pair of present surfaces and every
544
+ # shared section we record one verdict.
545
+ # ---------------------------------------------------------------------------
546
+
547
+
548
+ @dataclass(frozen=True)
549
+ class CoherenceVerdict:
550
+ section_slug: str
551
+ section_display: str
552
+ verdict: str
553
+ rationale: str
554
+
555
+
556
+ def section_present_in_scan(scan: SurfaceScan, slug: str) -> bool:
557
+ """True when the section is present (either canonical or renamed)."""
558
+ status = scan.section_presence.get(slug, PRESENCE_ABSENT)
559
+ return status != PRESENCE_ABSENT
560
+
561
+
562
+ def shared_claim_overlap(
563
+ section: CanonicalSection,
564
+ scan_a: SurfaceScan,
565
+ scan_b: SurfaceScan,
566
+ ) -> tuple[int, int, int]:
567
+ """Return ``(both, only_a, only_b)`` body-signature counts.
568
+
569
+ A shared signature appearing in both surfaces' bodies counts toward
570
+ ``both``; a signature appearing in only one counts toward the
571
+ asymmetric bucket. The triple drives the verdict heuristic.
572
+ """
573
+ both = 0
574
+ only_a = 0
575
+ only_b = 0
576
+ for signature in section.body_signatures:
577
+ in_a = signature in scan_a.raw_content
578
+ in_b = signature in scan_b.raw_content
579
+ if in_a and in_b:
580
+ both += 1
581
+ elif in_a:
582
+ only_a += 1
583
+ elif in_b:
584
+ only_b += 1
585
+ return both, only_a, only_b
586
+
587
+
588
+ def coherence_verdict_for(
589
+ section: CanonicalSection,
590
+ scan_a: SurfaceScan,
591
+ scan_b: SurfaceScan,
592
+ ) -> CoherenceVerdict:
593
+ if not section_present_in_scan(scan_a, section.slug) or not section_present_in_scan(
594
+ scan_b, section.slug
595
+ ):
596
+ return CoherenceVerdict(
597
+ section_slug=section.slug,
598
+ section_display=section.display,
599
+ verdict=COHERENCE_NOT_APPLICABLE,
600
+ rationale=(
601
+ "At least one surface lacks the section; coherence is undefined "
602
+ "until both surfaces author the section."
603
+ ),
604
+ )
605
+ both, only_a, only_b = shared_claim_overlap(section, scan_a, scan_b)
606
+ total_signatures = len(section.body_signatures)
607
+ if both == 0 and only_a == 0 and only_b == 0:
608
+ return CoherenceVerdict(
609
+ section_slug=section.slug,
610
+ section_display=section.display,
611
+ verdict=COHERENCE_PARTIAL,
612
+ rationale=(
613
+ "Both surfaces carry the section heading but neither body shows "
614
+ "the canonical claim signatures; the rigorous coherence test "
615
+ "lives at the multi-surface coherence validator."
616
+ ),
617
+ )
618
+ if both > 0 and only_a == 0 and only_b == 0:
619
+ return CoherenceVerdict(
620
+ section_slug=section.slug,
621
+ section_display=section.display,
622
+ verdict=COHERENCE_COHERENT,
623
+ rationale=(
624
+ f"Both surfaces share {both} of {total_signatures} canonical "
625
+ "claim signatures; no asymmetric claim was detected."
626
+ ),
627
+ )
628
+ if (only_a > 0 and only_b == 0) or (only_a == 0 and only_b > 0):
629
+ return CoherenceVerdict(
630
+ section_slug=section.slug,
631
+ section_display=section.display,
632
+ verdict=COHERENCE_PARTIAL,
633
+ rationale=(
634
+ f"Shared claims: {both}; asymmetric claims: {only_a + only_b}. "
635
+ "One surface carries claims absent from the other; reconcile "
636
+ "by mirroring the canonical project voice."
637
+ ),
638
+ )
639
+ # Both surfaces carry asymmetric claims — the heuristic flags this
640
+ # as a candidate contradiction; the validator's fixture confirms.
641
+ return CoherenceVerdict(
642
+ section_slug=section.slug,
643
+ section_display=section.display,
644
+ verdict=COHERENCE_CONTRADICTS,
645
+ rationale=(
646
+ f"Each surface carries asymmetric claims (only-A={only_a}, "
647
+ f"only-B={only_b}, shared={both}); the heuristic flags a candidate "
648
+ "contradiction for the validator's fixture-driven confirmation."
649
+ ),
650
+ )
651
+
652
+
653
+ def build_coherence_map(scans: list[SurfaceScan]) -> dict[str, list[dict[str, str]]]:
654
+ """Return the pairwise coherence map keyed by ``A__vs__B``."""
655
+ present_scans = [s for s in scans if s.presence == SURFACE_PRESENT]
656
+ coherence: dict[str, list[dict[str, str]]] = {}
657
+ for index_a, scan_a in enumerate(present_scans):
658
+ for scan_b in present_scans[index_a + 1 :]:
659
+ pair_key = f"{scan_a.descriptor.path}__vs__{scan_b.descriptor.path}"
660
+ verdicts: list[dict[str, str]] = []
661
+ for section in SHARED_SECTIONS_FOR_COHERENCE:
662
+ verdict = coherence_verdict_for(section, scan_a, scan_b)
663
+ verdicts.append(asdict(verdict))
664
+ coherence[pair_key] = verdicts
665
+ return coherence
666
+
667
+
668
+ # ---------------------------------------------------------------------------
669
+ # Authoring / refinement plan. One action item per surface; items name
670
+ # the missing-section template, the present-but-drifted delta, or the
671
+ # contradiction reconciliation path.
672
+ # ---------------------------------------------------------------------------
673
+
674
+
675
+ @dataclass(frozen=True)
676
+ class PlanAction:
677
+ surface: str
678
+ action: str
679
+ detail: str
680
+ target_phase_hint: str
681
+
682
+
683
+ def template_for_section(section: CanonicalSection) -> str:
684
+ """Return a one-line template summary for the named section."""
685
+ return (
686
+ f"Author '{section.display}' section per the canonical nine-section "
687
+ f"structure; body covers: {', '.join(section.body_signatures[:3])}."
688
+ )
689
+
690
+
691
+ def build_authoring_plan(
692
+ scans: list[SurfaceScan],
693
+ coherence_map: dict[str, list[dict[str, str]]],
694
+ ) -> list[PlanAction]:
695
+ actions: list[PlanAction] = []
696
+ for scan in scans:
697
+ if scan.presence == SURFACE_ABSENT:
698
+ if scan.descriptor.mandatory:
699
+ actions.append(
700
+ PlanAction(
701
+ surface=scan.descriptor.path,
702
+ action="author-from-template",
703
+ detail=(
704
+ "Mandatory surface absent; author the full nine-section "
705
+ "structure with the canonical authorship banner header. "
706
+ f"Audience: {scan.descriptor.role}."
707
+ ),
708
+ target_phase_hint=(
709
+ "Copilot-instructions author pass / instruction-surface refit pass"
710
+ if scan.descriptor.path == SURFACE_COPILOT
711
+ else "instruction-surface refit pass"
712
+ ),
713
+ )
714
+ )
715
+ else:
716
+ actions.append(
717
+ PlanAction(
718
+ surface=scan.descriptor.path,
719
+ action="defer-to-opt-in",
720
+ detail=(
721
+ "Optional surface absent; author only when the operator "
722
+ f"opts in via the multi-surface opt-in inquiry. Audience: "
723
+ f"{scan.descriptor.role}."
724
+ ),
725
+ target_phase_hint="Optional-surface opt-in inquiry / generator",
726
+ )
727
+ )
728
+ continue
729
+ # Present surface — emit one action per absent / renamed section.
730
+ for section in ALL_SECTIONS_FOR_PRESENCE:
731
+ status = scan.section_presence[section.slug]
732
+ if status == PRESENCE_ABSENT:
733
+ actions.append(
734
+ PlanAction(
735
+ surface=scan.descriptor.path,
736
+ action="install-missing-section",
737
+ detail=template_for_section(section),
738
+ target_phase_hint=(
739
+ "instruction-surface refit pass"
740
+ if scan.descriptor.path
741
+ in (
742
+ SURFACE_AGENTS_ROOT,
743
+ SURFACE_CLAUDE_ROOT,
744
+ SURFACE_CLAUDE_NESTED,
745
+ )
746
+ else "Copilot-instructions author pass"
747
+ if scan.descriptor.path == SURFACE_COPILOT
748
+ else "Optional-surface generator"
749
+ ),
750
+ )
751
+ )
752
+ elif status.startswith(PRESENCE_RENAMED_PREFIX):
753
+ renamed_to = status[len(PRESENCE_RENAMED_PREFIX) :]
754
+ actions.append(
755
+ PlanAction(
756
+ surface=scan.descriptor.path,
757
+ action="rename-or-mirror-section",
758
+ detail=(
759
+ f"Section '{section.display}' is present under heading "
760
+ f"'{renamed_to}'; either rename to the canonical heading "
761
+ "or add the canonical heading and migrate the body."
762
+ ),
763
+ target_phase_hint="instruction-surface refit pass",
764
+ )
765
+ )
766
+ # Contradiction reconciliation actions per coherence map entry.
767
+ for pair_key, verdicts in coherence_map.items():
768
+ for verdict in verdicts:
769
+ if verdict["verdict"] == COHERENCE_CONTRADICTS:
770
+ surface_a, surface_b = pair_key.split("__vs__")
771
+ # The default reconciliation mirrors the canonical project
772
+ # voice into the divergent surface. AGENTS.md is canonical.
773
+ if surface_a == SURFACE_AGENTS_ROOT:
774
+ canonical, divergent = surface_a, surface_b
775
+ elif surface_b == SURFACE_AGENTS_ROOT:
776
+ canonical, divergent = surface_b, surface_a
777
+ elif surface_a == SURFACE_CLAUDE_ROOT:
778
+ canonical, divergent = surface_a, surface_b
779
+ elif surface_b == SURFACE_CLAUDE_ROOT:
780
+ canonical, divergent = surface_b, surface_a
781
+ else:
782
+ canonical, divergent = surface_a, surface_b
783
+ actions.append(
784
+ PlanAction(
785
+ surface=divergent,
786
+ action="reconcile-contradiction",
787
+ detail=(
788
+ f"Section '{verdict['section_display']}' contradicts the "
789
+ f"corresponding section in '{canonical}'. Default "
790
+ f"reconciliation: rewrite '{divergent}' to mirror "
791
+ f"'{canonical}' semantics in surface-appropriate framing."
792
+ ),
793
+ target_phase_hint="Multi-surface coherence reconciliation",
794
+ )
795
+ )
796
+ return actions
797
+
798
+
799
+ # ---------------------------------------------------------------------------
800
+ # JSON envelope.
801
+ # ---------------------------------------------------------------------------
802
+
803
+
804
+ def serialise_scan(scan: SurfaceScan) -> dict:
805
+ return {
806
+ "path": scan.descriptor.path,
807
+ "role": scan.descriptor.role,
808
+ "mandatory": scan.descriptor.mandatory,
809
+ "presence": scan.presence,
810
+ "sha256": scan.sha256,
811
+ "line-count": scan.line_count,
812
+ "headings": [
813
+ {
814
+ "level": h.level,
815
+ "text": h.text,
816
+ "line-start": h.line_start,
817
+ "line-end": h.line_end,
818
+ }
819
+ for h in scan.headings
820
+ ],
821
+ "section-presence": scan.section_presence,
822
+ }
823
+
824
+
825
+ def emit_json(
826
+ out_path: Path,
827
+ scans: list[SurfaceScan],
828
+ coherence_map: dict[str, list[dict[str, str]]],
829
+ plan: list[PlanAction],
830
+ inventory_sha: str,
831
+ coarse_sha: str | None,
832
+ ) -> None:
833
+ payload = {
834
+ "generated": datetime.now(timezone.utc).isoformat(),
835
+ "scanner": "scan_ai_surfaces",
836
+ "inventory-source-sha256": inventory_sha,
837
+ "coarse-source-sha256": coarse_sha,
838
+ "candidate-surfaces": [
839
+ {
840
+ "path": d.path,
841
+ "role": d.role,
842
+ "mandatory": d.mandatory,
843
+ }
844
+ for d in CANDIDATE_SURFACES
845
+ ],
846
+ "canonical-sections": [
847
+ {"slug": s.slug, "display": s.display, "is-shared": s.is_shared}
848
+ for s in ALL_SECTIONS_FOR_PRESENCE
849
+ ],
850
+ "shared-sections-for-coherence": [
851
+ {"slug": s.slug, "display": s.display}
852
+ for s in SHARED_SECTIONS_FOR_COHERENCE
853
+ ],
854
+ "surfaces": [serialise_scan(s) for s in scans],
855
+ "coherence-map": coherence_map,
856
+ "authoring-plan": [asdict(p) for p in plan],
857
+ "summary": {
858
+ "candidate-count": len(scans),
859
+ "present-count": sum(1 for s in scans if s.presence == SURFACE_PRESENT),
860
+ "absent-count": sum(1 for s in scans if s.presence == SURFACE_ABSENT),
861
+ "mandatory-absent": [
862
+ s.descriptor.path
863
+ for s in scans
864
+ if s.presence == SURFACE_ABSENT and s.descriptor.mandatory
865
+ ],
866
+ "pair-count": len(coherence_map),
867
+ "plan-action-count": len(plan),
868
+ },
869
+ }
870
+ out_path.parent.mkdir(parents=True, exist_ok=True)
871
+ out_path.write_text(
872
+ json.dumps(payload, indent=2, sort_keys=False) + "\n",
873
+ encoding="utf-8",
874
+ )
875
+
876
+
877
+ # ---------------------------------------------------------------------------
878
+ # Markdown render.
879
+ # ---------------------------------------------------------------------------
880
+
881
+
882
+ def render_markdown(
883
+ scans: list[SurfaceScan],
884
+ coherence_map: dict[str, list[dict[str, str]]],
885
+ plan: list[PlanAction],
886
+ inventory_sha: str,
887
+ coarse_sha: str | None,
888
+ generated_at: str,
889
+ ) -> str:
890
+ parts: list[str] = []
891
+ parts.append("# AI-Conventions Surfaces — Presence and Coherence Map\n")
892
+ parts.append("")
893
+ parts.append(
894
+ "> Per-surface presence detection plus pairwise shared-section "
895
+ "coherence verdicts plus authoring / refinement plan. Heuristic at "
896
+ "this layer; the rigorous fixture-driven test lives at the "
897
+ "multi-surface coherence validator.\n"
898
+ )
899
+ parts.append("")
900
+ parts.append(f"- **Generated:** `{generated_at}`")
901
+ parts.append(f"- **Inventory SHA-256:** `{inventory_sha}`")
902
+ if coarse_sha is not None:
903
+ parts.append(f"- **Coarse-scan SHA-256:** `{coarse_sha}`")
904
+ parts.append("")
905
+ # Surface presence table.
906
+ parts.append("## Surface Presence")
907
+ parts.append("")
908
+ parts.append("| Path | Role | Mandatory | Presence | SHA-256 | Lines |")
909
+ parts.append("|------|------|-----------|----------|---------|-------|")
910
+ for scan in scans:
911
+ sha_display = scan.sha256[:12] + "…" if scan.sha256 else "—"
912
+ parts.append(
913
+ f"| `{scan.descriptor.path}` | {scan.descriptor.role} | "
914
+ f"{'**MUST**' if scan.descriptor.mandatory else 'opt-in'} | "
915
+ f"{scan.presence} | `{sha_display}` | {scan.line_count} |"
916
+ )
917
+ parts.append("")
918
+ # Per-surface section-presence map.
919
+ parts.append("## Section Presence")
920
+ parts.append("")
921
+ section_headers = " | ".join(s.display for s in ALL_SECTIONS_FOR_PRESENCE)
922
+ section_separators = " | ".join("---" for _ in ALL_SECTIONS_FOR_PRESENCE)
923
+ parts.append(f"| Surface | {section_headers} |")
924
+ parts.append(f"|---------|{section_separators}|")
925
+ for scan in scans:
926
+ if scan.presence == SURFACE_ABSENT:
927
+ cells = " | ".join("—" for _ in ALL_SECTIONS_FOR_PRESENCE)
928
+ parts.append(f"| `{scan.descriptor.path}` | {cells} |")
929
+ continue
930
+ cells = []
931
+ for section in ALL_SECTIONS_FOR_PRESENCE:
932
+ status = scan.section_presence[section.slug]
933
+ if status == PRESENCE_PRESENT:
934
+ cells.append("present")
935
+ elif status == PRESENCE_ABSENT:
936
+ cells.append("**absent**")
937
+ else:
938
+ renamed_to = status[len(PRESENCE_RENAMED_PREFIX) :]
939
+ cells.append(f"renamed-to `{renamed_to[:24]}`")
940
+ cells_joined = " | ".join(cells)
941
+ parts.append(f"| `{scan.descriptor.path}` | {cells_joined} |")
942
+ parts.append("")
943
+ # Per-surface heading inventory (level-2 only, for present surfaces).
944
+ parts.append("## Per-Surface Heading Inventory (level-2)")
945
+ parts.append("")
946
+ for scan in scans:
947
+ if scan.presence != SURFACE_PRESENT:
948
+ continue
949
+ parts.append(f"### `{scan.descriptor.path}`")
950
+ parts.append("")
951
+ level_two = [h for h in scan.headings if h.level == 2]
952
+ if not level_two:
953
+ parts.append(
954
+ "_No level-two headings detected; the surface is either flat "
955
+ "prose or uses a different heading depth._\n"
956
+ )
957
+ parts.append("")
958
+ continue
959
+ parts.append("| # | Heading | Lines |")
960
+ parts.append("|---|---------|-------|")
961
+ for index, heading in enumerate(level_two, start=1):
962
+ parts.append(
963
+ f"| {index} | {heading.text} | "
964
+ f"{heading.line_start}-{heading.line_end} |"
965
+ )
966
+ parts.append("")
967
+ # Coherence map.
968
+ parts.append("## Coherence Map")
969
+ parts.append("")
970
+ if not coherence_map:
971
+ parts.append(
972
+ "_No pairs of present surfaces; the coherence map is empty by "
973
+ "construction. The map's structure is preserved for the post-"
974
+ "authoring re-run when at least two surfaces are present._\n"
975
+ )
976
+ parts.append("")
977
+ else:
978
+ for pair_key, verdicts in coherence_map.items():
979
+ surface_a, surface_b = pair_key.split("__vs__")
980
+ parts.append(f"### `{surface_a}` ↔ `{surface_b}`")
981
+ parts.append("")
982
+ parts.append("| Section | Verdict | Rationale |")
983
+ parts.append("|---------|---------|-----------|")
984
+ for verdict in verdicts:
985
+ rationale = verdict["rationale"].replace("|", "\\|")
986
+ parts.append(
987
+ f"| {verdict['section_display']} | "
988
+ f"{verdict['verdict']} | {rationale} |"
989
+ )
990
+ parts.append("")
991
+ # Authoring / refinement plan.
992
+ parts.append("## Authoring / Refinement Plan")
993
+ parts.append("")
994
+ if not plan:
995
+ parts.append(
996
+ "_No authoring / refinement actions emitted; every surface in "
997
+ "scope is fully canonical._\n"
998
+ )
999
+ parts.append("")
1000
+ else:
1001
+ parts.append("| # | Surface | Action | Target Phase Hint | Detail |")
1002
+ parts.append("|---|---------|--------|-------------------|--------|")
1003
+ for index, action in enumerate(plan, start=1):
1004
+ detail = action.detail.replace("|", "\\|")
1005
+ parts.append(
1006
+ f"| {index} | `{action.surface}` | {action.action} | "
1007
+ f"{action.target_phase_hint} | {detail} |"
1008
+ )
1009
+ parts.append("")
1010
+ # Reconciliation summary.
1011
+ contradictions = [
1012
+ verdict
1013
+ for verdicts in coherence_map.values()
1014
+ for verdict in verdicts
1015
+ if verdict["verdict"] == COHERENCE_CONTRADICTS
1016
+ ]
1017
+ parts.append("## Reconciliation Summary")
1018
+ parts.append("")
1019
+ if not contradictions:
1020
+ parts.append(
1021
+ "_No candidate contradictions detected at this heuristic layer. "
1022
+ "The fixture-driven validator confirms the verdict at a later "
1023
+ "phase._\n"
1024
+ )
1025
+ parts.append("")
1026
+ else:
1027
+ parts.append(
1028
+ "Default reconciliation: `AGENTS.md` is the canonical project voice; "
1029
+ "any divergent surface is rewritten to mirror its semantics in "
1030
+ "surface-appropriate framing. Surface-specific overrides require "
1031
+ "an in-file `<!-- coherence-override: <claim-id> -->` marker "
1032
+ "pointing at an architectural decision record.\n"
1033
+ )
1034
+ parts.append("")
1035
+ parts.append("| Section | Surfaces | Default Reconciliation |")
1036
+ parts.append("|---------|----------|------------------------|")
1037
+ for verdict in contradictions:
1038
+ parts.append(
1039
+ f"| {verdict['section_display']} | (see plan) | "
1040
+ f"Rewrite divergent surface to mirror `AGENTS.md`. |"
1041
+ )
1042
+ parts.append("")
1043
+ return "\n".join(parts) + "\n"
1044
+
1045
+
1046
+ # ---------------------------------------------------------------------------
1047
+ # Entry point.
1048
+ # ---------------------------------------------------------------------------
1049
+
1050
+
1051
+ def main(argv: list[str] | None = None) -> int:
1052
+ parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
1053
+ parser.add_argument(
1054
+ "--inventory",
1055
+ type=Path,
1056
+ default=Path(".audit/inventory.json"),
1057
+ help="Inventory snapshot whose SHA-256 anchors the scan output.",
1058
+ )
1059
+ parser.add_argument(
1060
+ "--coarse",
1061
+ type=Path,
1062
+ default=Path(".audit/drift-ai-surfaces-coarse.json"),
1063
+ help="Optional coarse pre-scan output; its SHA-256 is recorded.",
1064
+ )
1065
+ parser.add_argument("--root", type=Path, default=Path())
1066
+ parser.add_argument(
1067
+ "--out-json",
1068
+ type=Path,
1069
+ default=Path(".audit/ai-surfaces.json"),
1070
+ )
1071
+ parser.add_argument(
1072
+ "--out-md",
1073
+ type=Path,
1074
+ default=Path(".audit/ai-surfaces.md"),
1075
+ )
1076
+ args = parser.parse_args(argv)
1077
+ if not args.inventory.exists():
1078
+ print(
1079
+ f"error: inventory not found at {args.inventory}",
1080
+ file=sys.stderr,
1081
+ )
1082
+ return 1
1083
+ _, inventory_sha = load_inventory(args.inventory)
1084
+ coarse_sha: str | None = None
1085
+ if args.coarse.exists():
1086
+ coarse_sha = hashlib.sha256(args.coarse.read_bytes()).hexdigest()
1087
+ scans = [scan_surface(d, args.root) for d in CANDIDATE_SURFACES]
1088
+ coherence_map = build_coherence_map(scans)
1089
+ plan = build_authoring_plan(scans, coherence_map)
1090
+ generated_at = datetime.now(timezone.utc).isoformat()
1091
+ emit_json(args.out_json, scans, coherence_map, plan, inventory_sha, coarse_sha)
1092
+ args.out_md.parent.mkdir(parents=True, exist_ok=True)
1093
+ args.out_md.write_text(
1094
+ render_markdown(
1095
+ scans,
1096
+ coherence_map,
1097
+ plan,
1098
+ inventory_sha,
1099
+ coarse_sha,
1100
+ generated_at,
1101
+ ),
1102
+ encoding="utf-8",
1103
+ )
1104
+ present_count = sum(1 for s in scans if s.presence == SURFACE_PRESENT)
1105
+ absent_count = sum(1 for s in scans if s.presence == SURFACE_ABSENT)
1106
+ mandatory_absent = [
1107
+ s.descriptor.path
1108
+ for s in scans
1109
+ if s.presence == SURFACE_ABSENT and s.descriptor.mandatory
1110
+ ]
1111
+ print(
1112
+ f"scan_ai_surfaces: candidates={len(scans)}, present={present_count}, "
1113
+ f"absent={absent_count}, mandatory-absent={len(mandatory_absent)}, "
1114
+ f"pairs={len(coherence_map)}, plan-actions={len(plan)}"
1115
+ )
1116
+ if mandatory_absent:
1117
+ print(
1118
+ f" mandatory-absent: {', '.join(mandatory_absent)}",
1119
+ file=sys.stderr,
1120
+ )
1121
+ return 0
1122
+
1123
+
1124
+ if __name__ == "__main__":
1125
+ raise SystemExit(main())