@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,284 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Verify version-bearing sites resolve dynamically, not as static literals.
4
+
5
+ Why this enforcement exists. Companion to ``dynamism_grep.py``. The
6
+ dynamism rule mandates that every version-bearing site in the project
7
+ derive its value from a single source of truth (package metadata via
8
+ ``importlib.metadata``, the shields.io dynamic badge endpoints that
9
+ resolve against the npm registry and GitHub Releases, or the site
10
+ build's version-injection mechanism) rather than carry the version
11
+ as a hard-coded literal. Static literals drift the moment a release
12
+ ships: badge URLs lie about the current version, docs pages display
13
+ the version that was true at last edit, and the runtime ``__version__``
14
+ attribute returns a value that disagrees with the installed package.
15
+ This standalone validator walks three classes of site (README badges,
16
+ docs site config, runtime ``__version__``) and reports every static
17
+ resolution so the operator can convert it to a dynamic form.
18
+
19
+ Scope. Standalone corpus-level validator. Walks the project root from a
20
+ single ``main(root)`` entry point and exits 0 (PASS) or 2 (FAIL) with a
21
+ structured JSON report listing every static-version site. Invoked via
22
+ ``python -m apothem.conformity.gate --all .`` or
23
+ ``python -m apothem.conformity.gate --check static-version-grep <root>``.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import json
29
+ import re
30
+ import sys
31
+ from dataclasses import asdict, dataclass, field
32
+ from pathlib import Path
33
+ from typing import Final
34
+
35
+ GREP_NAME: Final[str] = "static-version-grep"
36
+ RULE_ANCHOR: Final[str] = "rules/dynamism.md §static-version-resolution"
37
+ EXIT_PASS: Final[int] = 0
38
+ EXIT_FAIL: Final[int] = 2
39
+
40
+ # README sites inspected for badge URLs. Shields.io dynamic badge paths
41
+ # include the project / package coordinate after a `/github/v/release/`,
42
+ # `/github/v/tag/`, `/npm/v/`, `/npm/dm/`, `/pypi/v/`, or `/pypi/dm/` segment;
43
+ # static badges instead embed a literal version number in the URL or use the
44
+ # `/badge/` static generator with a hard-coded value.
45
+ README_CANDIDATES: Final[tuple[str, ...]] = ("README.md", "README.rst", "README")
46
+
47
+ # Site config candidates. Each is inspected for a `version:` key bearing a
48
+ # string-literal value rather than a templated / dynamic reference.
49
+ SITE_CONFIG_CANDIDATES: Final[tuple[str, ...]] = (
50
+ "site/next.config.mjs",
51
+ "site/package.json",
52
+ )
53
+
54
+ # Runtime version-bearing module. The canonical pattern is
55
+ # ``__version__ = importlib.metadata.version(__package__)`` (or an
56
+ # equivalent ``metadata.version("apothem")`` form). A literal string
57
+ # assignment is the failure mode this validator catches.
58
+ RUNTIME_VERSION_MODULE: Final[str] = "src/apothem/__init__.py"
59
+
60
+ # A semver-shaped literal version embedded in a badge URL or a config
61
+ # value. Captures forms like `v1.2.3`, `1.2.3`, `1.2.3-alpha.1`,
62
+ # `2.0.0+build.7`. Word boundaries prevent partial matches inside
63
+ # longer identifiers.
64
+ LITERAL_VERSION_RE: Final[re.Pattern[str]] = re.compile(
65
+ r"\bv?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?\b"
66
+ )
67
+
68
+ # Shields.io dynamic badge markers — any of these path fragments in a
69
+ # badge URL indicates the badge resolves dynamically against an upstream
70
+ # registry rather than carrying a literal version.
71
+ SHIELDS_DYNAMIC_MARKERS: Final[tuple[str, ...]] = (
72
+ "img.shields.io/github/v/release/",
73
+ "img.shields.io/github/v/tag/",
74
+ "img.shields.io/npm/v/",
75
+ "img.shields.io/npm/dm/",
76
+ "img.shields.io/pypi/v/",
77
+ "img.shields.io/pypi/dm/",
78
+ "img.shields.io/crates/v/",
79
+ "img.shields.io/gem/v/",
80
+ )
81
+
82
+ # Markdown badge / image syntax. Captures the URL inside the
83
+ # `![alt](url)` form so each URL can be classified independently.
84
+ MARKDOWN_IMAGE_RE: Final[re.Pattern[str]] = re.compile(r"!\[[^\]]*\]\(([^)]+)\)")
85
+
86
+ # Git-ref query parameters (`?branch=`, `?tag=`, `?ref=`) on a badge URL carry a
87
+ # git ref that may itself be a version tag — e.g. a build-status badge pinned to
88
+ # `?branch=v1.2.3`. That ref is not the badge's *displayed* version, so a semver
89
+ # token appearing only inside one of these parameters must not be read as a
90
+ # static-version literal. The parameter values are stripped before the
91
+ # literal-version scan; a version embedded in the URL *path* (the static
92
+ # `/badge/<label>-<version>-<color>` generator) is untouched and still flagged.
93
+ REF_PARAM_RE: Final[re.Pattern[str]] = re.compile(r"[?&](?:branch|tag|ref)=[^&]*")
94
+
95
+ # A literal ``version:`` key in a YAML/Python config carrying a quoted
96
+ # string value (site-generator config style). Templated references — e.g.
97
+ # ``version: !ENV [VERSION]`` or ``version = metadata.version(...)`` —
98
+ # do not match.
99
+ YAML_LITERAL_VERSION_RE: Final[re.Pattern[str]] = re.compile(
100
+ r"""^\s*version\s*[:=]\s*["']([^"']+)["']""",
101
+ re.MULTILINE,
102
+ )
103
+
104
+ # A literal ``__version__ = "x.y.z"`` assignment. Captures the assigned
105
+ # string when it is a literal; the dynamic form
106
+ # ``__version__ = importlib.metadata.version(...)`` is not matched.
107
+ LITERAL_DUNDER_VERSION_RE: Final[re.Pattern[str]] = re.compile(
108
+ r"""^\s*__version__\s*=\s*["']([^"']+)["']""",
109
+ re.MULTILINE,
110
+ )
111
+
112
+ # Dynamic ``__version__`` resolution markers. Presence of any of these
113
+ # fragments indicates the runtime version derives from package metadata
114
+ # rather than a literal.
115
+ DYNAMIC_VERSION_MARKERS: Final[tuple[str, ...]] = (
116
+ "importlib.metadata.version",
117
+ "importlib_metadata.version",
118
+ "metadata.version(",
119
+ "version(__package__",
120
+ 'version("apothem"',
121
+ "version('apothem'",
122
+ )
123
+
124
+
125
+ @dataclass(frozen=True)
126
+ class Finding:
127
+ """One static-version site discovered in the project."""
128
+
129
+ site_class: str
130
+ path: str
131
+ detail: str
132
+ rule: str = RULE_ANCHOR
133
+
134
+
135
+ @dataclass(frozen=True)
136
+ class GrepResult:
137
+ grep: str
138
+ path: str | None
139
+ passed: bool
140
+ findings: list[Finding] = field(default_factory=list)
141
+
142
+ def to_json(self) -> str:
143
+ payload = {
144
+ "grep": self.grep,
145
+ "path": self.path,
146
+ "passed": self.passed,
147
+ "findings": [asdict(f) for f in self.findings],
148
+ }
149
+ return json.dumps(payload, indent=2)
150
+
151
+
152
+ def _strip_ref_params(url: str) -> str:
153
+ """Remove git-ref query-parameter values from a badge URL.
154
+
155
+ ``?branch=v1.2.3`` / ``?tag=v1.2.3`` / ``?ref=v1.2.3`` carry a git ref, not
156
+ a displayed version; their values are dropped so the literal-version scan
157
+ does not misread a dynamic build-status badge pinned to a release branch.
158
+ A version embedded in the URL path is untouched.
159
+ """
160
+ return REF_PARAM_RE.sub("", url)
161
+
162
+
163
+ def _check_readme(root: Path, findings: list[Finding]) -> None:
164
+ """Flag badge URLs in README that carry literal versions."""
165
+ for candidate in README_CANDIDATES:
166
+ readme = root / candidate
167
+ if not readme.is_file():
168
+ continue
169
+ try:
170
+ text = readme.read_text(encoding="utf-8")
171
+ except (OSError, UnicodeDecodeError):
172
+ continue
173
+ for match in MARKDOWN_IMAGE_RE.finditer(text):
174
+ url = match.group(1).strip()
175
+ if "shields.io" not in url and "badge" not in url.lower():
176
+ continue
177
+ is_dynamic = any(marker in url for marker in SHIELDS_DYNAMIC_MARKERS)
178
+ if is_dynamic:
179
+ continue
180
+ if LITERAL_VERSION_RE.search(_strip_ref_params(url)):
181
+ findings.append(
182
+ Finding(
183
+ site_class="readme-badge",
184
+ path=str(readme.relative_to(root)),
185
+ detail=(
186
+ f"badge URL carries a literal version: {url!r}; "
187
+ "convert to a shields.io dynamic endpoint "
188
+ "(e.g., img.shields.io/npm/v/%40ahmed-g-gad%2Fapothem "
189
+ "or img.shields.io/github/v/release/ahmed-g-gad/apothem)"
190
+ ),
191
+ )
192
+ )
193
+
194
+
195
+ def _check_site_config(root: Path, findings: list[Finding]) -> None:
196
+ """Flag site config files declaring a literal ``version:``."""
197
+ for candidate in SITE_CONFIG_CANDIDATES:
198
+ config = root / candidate
199
+ if not config.is_file():
200
+ continue
201
+ try:
202
+ text = config.read_text(encoding="utf-8")
203
+ except (OSError, UnicodeDecodeError):
204
+ continue
205
+ if any(marker in text for marker in DYNAMIC_VERSION_MARKERS):
206
+ # The config imports a dynamic version-resolution helper; a
207
+ # nearby literal `version:` key is almost certainly a fallback
208
+ # default rather than the canonical source, so do not flag.
209
+ continue
210
+ for match in YAML_LITERAL_VERSION_RE.finditer(text):
211
+ literal = match.group(1)
212
+ if not LITERAL_VERSION_RE.search(literal):
213
+ continue
214
+ findings.append(
215
+ Finding(
216
+ site_class="site-config",
217
+ path=str(config.relative_to(root)),
218
+ detail=(
219
+ f"site config declares a literal version: {literal!r}; "
220
+ 'derive from importlib.metadata.version("apothem") '
221
+ "or an equivalent dynamic source"
222
+ ),
223
+ )
224
+ )
225
+
226
+
227
+ def _check_runtime_version(root: Path, findings: list[Finding]) -> None:
228
+ """Flag a literal ``__version__`` assignment in the runtime module."""
229
+ module = root / RUNTIME_VERSION_MODULE
230
+ if not module.is_file():
231
+ return
232
+ try:
233
+ text = module.read_text(encoding="utf-8")
234
+ except (OSError, UnicodeDecodeError):
235
+ return
236
+ if any(marker in text for marker in DYNAMIC_VERSION_MARKERS):
237
+ return
238
+ match = LITERAL_DUNDER_VERSION_RE.search(text)
239
+ if match is None:
240
+ return
241
+ findings.append(
242
+ Finding(
243
+ site_class="runtime-version",
244
+ path=str(module.relative_to(root)),
245
+ detail=(
246
+ f"__version__ is a literal string {match.group(1)!r}; "
247
+ "derive from importlib.metadata.version(__package__) so "
248
+ "the runtime value tracks the installed package metadata"
249
+ ),
250
+ )
251
+ )
252
+
253
+
254
+ def check(root: Path) -> GrepResult:
255
+ """Walk the three version-bearing site classes; return a structured result.
256
+
257
+ Pre-conditions: ``root`` is the project root (the directory holding
258
+ ``pyproject.toml`` or its closest ancestor).
259
+ Post-conditions: ``result.passed`` is True iff every inspected site
260
+ resolves dynamically (README badges hit shields.io dynamic endpoints,
261
+ docs config derives version from package metadata, runtime
262
+ ``__version__`` calls ``importlib.metadata.version`` or equivalent).
263
+ """
264
+ findings: list[Finding] = []
265
+ _check_readme(root, findings)
266
+ _check_site_config(root, findings)
267
+ _check_runtime_version(root, findings)
268
+ return GrepResult(
269
+ grep=GREP_NAME,
270
+ path=str(root),
271
+ passed=not findings,
272
+ findings=findings,
273
+ )
274
+
275
+
276
+ def main(root: Path) -> int:
277
+ result = check(root)
278
+ print(result.to_json())
279
+ return EXIT_PASS if result.passed else EXIT_FAIL
280
+
281
+
282
+ if __name__ == "__main__":
283
+ target = Path(sys.argv[1]) if len(sys.argv) >= 2 else Path.cwd()
284
+ sys.exit(main(target))
@@ -0,0 +1,185 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Flag filler phrases, throat-clearing openers, and content-free qualifiers.
4
+
5
+ Why this enforcement exists. The clean-room generation rule §5 (Prose and
6
+ Documentation) and the token-efficiency rewrite rule require every sentence
7
+ to advance the artifact's purpose. Filler ("In this section, we will…"),
8
+ throat-clearing ("Before diving in…"), restatement openers, and
9
+ content-free qualifiers ("very", "quite", "rather", "fairly") consume
10
+ tokens without carrying semantic load. The mechanical matcher surfaces
11
+ each occurrence so the operator can either delete the phrase, replace it
12
+ with substantive content, or — for qualifiers — substitute a measured
13
+ form ("twice as fast" rather than "very fast").
14
+
15
+ Scope. Hits inside fenced code blocks (between triple-backtick fences),
16
+ inline-code spans (single-backtick delimited), quoted blocks (lines
17
+ starting `>`), and HTML comment regions are excluded. These typically carry
18
+ external material, sample inputs, preserved conversation, or — for inline
19
+ code — a forbidden phrase cited meta-linguistically (a doc that names the
20
+ filler vocabulary it forbids) rather than the artifact's own prescriptive
21
+ prose.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import re
27
+ import sys
28
+ from dataclasses import dataclass
29
+ from pathlib import Path
30
+ from typing import Final
31
+
32
+ from apothem.conformity._grep_base import GrepResult, run_grep
33
+
34
+ # Multi-word filler phrases and throat-clearing openers. Matched
35
+ # case-insensitively against the line text. These patterns are
36
+ # multi-word, so word-boundary anchors at the ends suffice.
37
+ FILLER_PHRASES: Final[tuple[str, ...]] = (
38
+ r"In this section, we will",
39
+ r"It is important to note",
40
+ r"As mentioned earlier",
41
+ r"Before diving in",
42
+ r"Without further ado",
43
+ r"Let's begin by",
44
+ r"Before we discuss",
45
+ r"To begin with",
46
+ r"First and foremost",
47
+ r"kind of",
48
+ )
49
+
50
+ # Single-word content-free qualifiers that flag unconditionally. Separated
51
+ # from the multi-word phrases so each carries word-boundary anchors and
52
+ # matches only when standing alone (not as a substring of a larger word).
53
+ # "rather" is intentionally NOT here: it needs a context exclusion (see
54
+ # RATHER_QUALIFIER_RE) because the comparative "rather than" carries
55
+ # semantic load and is not a content-free qualifier.
56
+ QUALIFIER_WORDS: Final[tuple[str, ...]] = (
57
+ "very",
58
+ "quite",
59
+ "somewhat",
60
+ "fairly",
61
+ )
62
+
63
+ FILLER_RE: Final[re.Pattern[str]] = re.compile(
64
+ r"(?i)(?:" + "|".join(FILLER_PHRASES) + r")"
65
+ )
66
+
67
+ QUALIFIER_RE: Final[re.Pattern[str]] = re.compile(
68
+ r"(?i)\b(?:" + "|".join(QUALIFIER_WORDS) + r")\b"
69
+ )
70
+
71
+ # "rather" is a content-free qualifier as a bare intensifier ("rather slow",
72
+ # "rather large") but carries semantic load in the comparative construction
73
+ # "rather than" ("X rather than Y" expresses a deliberate contrast — the kind
74
+ # of measured form §5 endorses, not filler). The negative lookahead excludes
75
+ # the comparative form so legitimate comparative prose is not flagged; the
76
+ # bare-intensifier form still matches.
77
+ RATHER_QUALIFIER_RE: Final[re.Pattern[str]] = re.compile(r"(?i)\brather\b(?!\s+than\b)")
78
+
79
+ # Every qualifier regex contributes findings. The order is fixed so the
80
+ # matcher's output is deterministic across runs.
81
+ QUALIFIER_RES: Final[tuple[re.Pattern[str], ...]] = (
82
+ QUALIFIER_RE,
83
+ RATHER_QUALIFIER_RE,
84
+ )
85
+
86
+ CODE_FENCE_RE: Final[re.Pattern[str]] = re.compile(r"^```")
87
+ # Inline-code span: a single-backtick-delimited run on one line. A filler
88
+ # phrase or qualifier quoted inside backticks is a meta-linguistic citation
89
+ # (a doc naming the vocabulary it forbids), not prose that uses it, so these
90
+ # spans are blanked before the scan. The column-preserving blank mirrors the
91
+ # inline-code exclusion in binding_reciprocity_grep.
92
+ INLINE_CODE_RE: Final[re.Pattern[str]] = re.compile(r"`[^`]*`")
93
+ QUOTE_LINE_RE: Final[re.Pattern[str]] = re.compile(r"^\s*>")
94
+ HTML_COMMENT_OPEN_RE: Final[re.Pattern[str]] = re.compile(r"<!--")
95
+ HTML_COMMENT_CLOSE_RE: Final[re.Pattern[str]] = re.compile(r"--!?>")
96
+
97
+ GREP_NAME: Final[str] = "token-efficiency-grep"
98
+ RULE_ANCHOR: Final[str] = "clean-room-generation §5 + token-efficiency-rewrite"
99
+ EXIT_PASS: Final[int] = 0
100
+ EXIT_FAIL: Final[int] = 2
101
+ STDIN_FLAG: Final[str] = "--stdin"
102
+
103
+
104
+ @dataclass(frozen=True)
105
+ class Finding:
106
+ """One filler or qualifier occurrence outside an excluded region."""
107
+
108
+ line: int
109
+ match: str
110
+ context: str
111
+ rule: str = RULE_ANCHOR
112
+
113
+
114
+ def check(content: str, path: Path | None = None) -> GrepResult:
115
+ """Scan content; return a structured result.
116
+
117
+ Pre-conditions: `content` is the artifact body about to be emitted.
118
+ Post-conditions: `result.passed` is True iff zero filler phrases and
119
+ zero content-free qualifiers were found outside fenced code blocks,
120
+ inline-code spans, quoted lines, or HTML comment regions.
121
+ """
122
+ findings: list[Finding] = []
123
+ inside_fence = False
124
+ inside_html_comment = False
125
+ for line_index, line in enumerate(content.splitlines(), start=1):
126
+ if CODE_FENCE_RE.match(line):
127
+ inside_fence = not inside_fence
128
+ continue
129
+ if inside_fence:
130
+ continue
131
+ # Track HTML comment span. A single-line comment opens and closes
132
+ # on the same line; a multi-line comment spans several lines.
133
+ working = line
134
+ if inside_html_comment:
135
+ close = HTML_COMMENT_CLOSE_RE.search(working)
136
+ if close is None:
137
+ continue
138
+ inside_html_comment = False
139
+ working = working[close.end() :]
140
+ # Strip inline comments and detect a trailing open.
141
+ while True:
142
+ open_match = HTML_COMMENT_OPEN_RE.search(working)
143
+ if open_match is None:
144
+ break
145
+ close_match = HTML_COMMENT_CLOSE_RE.search(working, open_match.end())
146
+ if close_match is None:
147
+ working = working[: open_match.start()]
148
+ inside_html_comment = True
149
+ break
150
+ working = working[: open_match.start()] + working[close_match.end() :]
151
+ # Blank inline-code spans (same-length spaces preserve columns) so a
152
+ # filler phrase or qualifier cited inside backticks — a doc that
153
+ # forbids the `kind of` phrasing — is read as a citation, not prose.
154
+ working = INLINE_CODE_RE.sub(lambda m: " " * len(m.group(0)), working)
155
+ if QUOTE_LINE_RE.match(working):
156
+ continue
157
+ if not working.strip():
158
+ continue
159
+ for match in FILLER_RE.finditer(working):
160
+ findings.append(
161
+ Finding(
162
+ line=line_index,
163
+ match=match.group(),
164
+ context=line.strip(),
165
+ )
166
+ )
167
+ for qualifier_re in QUALIFIER_RES:
168
+ for match in qualifier_re.finditer(working):
169
+ findings.append(
170
+ Finding(
171
+ line=line_index,
172
+ match=match.group(),
173
+ context=line.strip(),
174
+ )
175
+ )
176
+ return GrepResult(
177
+ grep=GREP_NAME,
178
+ path=str(path) if path is not None else None,
179
+ passed=not findings,
180
+ findings=findings,
181
+ )
182
+
183
+
184
+ if __name__ == "__main__":
185
+ sys.exit(run_grep(check, sys.argv))
@@ -0,0 +1,115 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Flag GitHub Actions workflows that pin actions to mutable refs.
4
+
5
+ Why this enforcement exists. The production-ready discipline M15 + the
6
+ supply-chain posture preservation clause require third-party action
7
+ references to be pinned to a 40-character commit SHA rather than a
8
+ floating tag. A `uses: actions/checkout@v4` reference can silently
9
+ re-point to a malicious release; a `uses: actions/checkout@<40-char-sha>`
10
+ reference cannot. The pre-emission gate's mechanical bar 15 (M15 supply-chain) catches the
11
+ mutable-ref shapes (`@main`, `@master`, `@latest`, `@v1`, `@v1.x.y`,
12
+ `@<branch>`) and surfaces each occurrence so the operator pins to a
13
+ SHA in the same change-set.
14
+
15
+ Detection strategy. The grep parses every line beginning with
16
+ `uses: <owner>/<action>@<ref>` (whitespace-tolerant) and inspects the
17
+ `<ref>`. A 40-character lowercase-hex SHA is the only conformant form;
18
+ anything else is flagged with the parsed action name and the offending
19
+ ref so the operator can rewrite to the SHA pin.
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
+ # `uses: <owner>/<action>(/<sub>)*@<ref>` shape per the GitHub Actions
33
+ # workflow YAML specification. The optional sub-path matches actions like
34
+ # `actions/cache/save@v3`. The capture groups isolate the action name and
35
+ # the ref so the finding can name both. A trailing `# ...` comment is
36
+ # tolerated so inline exemption markers (see `EXEMPTION_RE`) sit on the
37
+ # same line as the declaration without causing the regex to miss-match.
38
+ USES_LINE_RE: Final[re.Pattern[str]] = re.compile(
39
+ r"^\s*-?\s*uses:\s*([\w./-]+)@([\w./+-]+)\s*(?:#.*)?$"
40
+ )
41
+
42
+ # Canonical SHA shape — exactly forty lowercase hex characters. No upper-
43
+ # case, no shorter prefixes (those are abbreviations, not pins).
44
+ COMMIT_SHA_RE: Final[re.Pattern[str]] = re.compile(r"^[0-9a-f]{40}$")
45
+
46
+ # Inline exemption marker. A `uses:` line carrying a trailing comment of
47
+ # the form `# action-pinning-exempt: <reason>` is exempt from the SHA-pin
48
+ # requirement. The reason is required (audit-trail discipline) — bare
49
+ # `# action-pinning-exempt` without a reason is not honored. Canonical
50
+ # use case: SLSA reusable-workflow references where the Sigstore policy
51
+ # forbids SHA-pinning and the `@<tag>` form is the trust anchor rather
52
+ # than a mutable ref.
53
+ EXEMPTION_RE: Final[re.Pattern[str]] = re.compile(r"#\s*action-pinning-exempt:\s*\S")
54
+
55
+ # Local-action references (path within the same repository) start with
56
+ # `./` and are out of scope — they're not third-party supply-chain risks.
57
+ LOCAL_ACTION_PREFIX: Final[str] = "./"
58
+
59
+ GREP_NAME: Final[str] = "unpinned-action-grep"
60
+ RULE_ANCHOR: Final[str] = "M15 production-ready §Supply-chain"
61
+ EXIT_PASS: Final[int] = 0
62
+ EXIT_FAIL: Final[int] = 2
63
+ STDIN_FLAG: Final[str] = "--stdin"
64
+
65
+
66
+ @dataclass(frozen=True)
67
+ class Finding:
68
+ """One unpinned-action occurrence."""
69
+
70
+ line: int
71
+ action: str
72
+ ref: str
73
+ rule: str = RULE_ANCHOR
74
+
75
+
76
+ def check(content: str, path: Path | None = None) -> GrepResult:
77
+ """Scan content; return a structured result.
78
+
79
+ Pre-conditions: `content` is the YAML body of a workflow file about
80
+ to be emitted. The grep accepts content from any source — the
81
+ operator points it at a single workflow file or pipes a multi-file
82
+ bundle via stdin.
83
+ Post-conditions: `result.passed` is True iff every `uses: <action>@<ref>`
84
+ declaration's ref is a 40-character commit SHA, or the action is a
85
+ local in-repo reference exempt from supply-chain pinning.
86
+ """
87
+ findings: list[Finding] = []
88
+ for line_index, line in enumerate(content.splitlines(), start=1):
89
+ match = USES_LINE_RE.match(line)
90
+ if match is None:
91
+ continue
92
+ action, ref = match.group(1), match.group(2)
93
+ if action.startswith(LOCAL_ACTION_PREFIX):
94
+ continue
95
+ if COMMIT_SHA_RE.match(ref) is not None:
96
+ continue
97
+ if EXEMPTION_RE.search(line) is not None:
98
+ continue
99
+ findings.append(
100
+ Finding(
101
+ line=line_index,
102
+ action=action,
103
+ ref=ref,
104
+ )
105
+ )
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,74 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Block emission of artifacts containing unresolved authority placeholders.
4
+
5
+ Why this enforcement exists. Required-category inquiries (identity, scope
6
+ direction, security, public-surface naming) emit a `<USER-CONFIRM:id=...>`
7
+ placeholder that the operator must resolve before the artifact ships. An
8
+ unfilled placeholder reaching emission means a required-data inquiry was
9
+ never closed; the artifact would silently bind to fabricated authority data
10
+ the moment it lands. The pre-emission gate's mechanical bar 5 (M5 authority) catches the
11
+ literal placeholder shape so the operator never has to remember.
12
+
13
+ Invocation. Two surfaces: as a callable for the orchestrator (`check(content,
14
+ path)`), or as a CLI tool (`python user-confirm-grep.py <file>` / `--stdin`).
15
+ Exit code 0 indicates clean; non-zero indicates a finding. Stdout carries a
16
+ JSON report regardless of outcome — the orchestrator reads it; humans read
17
+ it for triage.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import re
23
+ import sys
24
+ from dataclasses import dataclass
25
+ from pathlib import Path
26
+ from typing import Final
27
+
28
+ from apothem.conformity._grep_base import GrepResult, run_grep
29
+
30
+ # The canonical placeholder shape declared in the authority-inquiry rule §10.
31
+ # `<USER-CONFIRM:id=foo>`, `<USER-CONFIRM:kind=bar>`, and bare `<USER-CONFIRM>`
32
+ # all flag — the colon-id form is the documented contract; the bare form is
33
+ # rare but equally non-conformant.
34
+ PLACEHOLDER_RE: Final[re.Pattern[str]] = re.compile(r"<USER-CONFIRM(?::[^>]*)?>")
35
+
36
+ GREP_NAME: Final[str] = "user-confirm-grep"
37
+ RULE_ANCHOR: Final[str] = "M5 authority-inquiry §10"
38
+ EXIT_PASS: Final[int] = 0
39
+ EXIT_FAIL: Final[int] = 2
40
+ STDIN_FLAG: Final[str] = "--stdin"
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class Finding:
45
+ """One placeholder occurrence in the artifact body."""
46
+
47
+ line: int
48
+ match: str
49
+ rule: str = RULE_ANCHOR
50
+
51
+
52
+ def check(content: str, path: Path | None = None) -> GrepResult:
53
+ """Scan content; return a structured result.
54
+
55
+ Pre-conditions: `content` is the artifact body about to be emitted.
56
+ Post-conditions: `result.passed` is True iff zero placeholders were found.
57
+ Failure mode: malformed UTF-8 raises `UnicodeDecodeError` at the read site,
58
+ not here — this function operates on already-decoded text.
59
+ """
60
+ findings: list[Finding] = []
61
+ for match in PLACEHOLDER_RE.finditer(content):
62
+ # Convert byte offset to a 1-indexed line number for human triage.
63
+ line = content.count("\n", 0, match.start()) + 1
64
+ findings.append(Finding(line=line, match=match.group()))
65
+ return GrepResult(
66
+ grep=GREP_NAME,
67
+ path=str(path) if path is not None else None,
68
+ passed=not findings,
69
+ findings=findings,
70
+ )
71
+
72
+
73
+ if __name__ == "__main__":
74
+ sys.exit(run_grep(check, sys.argv))