@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,224 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Validate filesystem paths against the canonical naming convention.
4
+
5
+ Why this enforcement exists. Spec section 4.1 ratifies kebab-case for
6
+ files and folders, with a closed set of canonical-uppercase exceptions
7
+ for ecosystem-wide singletons (CLAUDE.md, README.md, LICENSE, etc.) and
8
+ plan-suite singletons (MASTER-PLAN.md, PROGRESS.md, PHASE.md, SKILL.md,
9
+ VERSION). Numeric prefixes are admissible only inside ordered sequences
10
+ (phase folders `NN-topic/`, sub-phase folders `NNL-subtopic/`, migration
11
+ scripts where the host has ratified ordinal prefixes). The pre-emission
12
+ gate enforces the convention so namespace pollution cannot drift in
13
+ silently.
14
+
15
+ Detection strategy. Each input path is split into its file and parent
16
+ components; each component is matched against (a) the canonical-name
17
+ exception set, (b) the ordered-sequence prefix patterns, and (c) the
18
+ plain kebab-case shape. Components that match none of the three are
19
+ findings. Hidden directories (a leading dot) are exempt because dotfile
20
+ conventions are host-discovered, not ratified at user scope.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import json
26
+ import re
27
+ import sys
28
+ from dataclasses import asdict, dataclass, field
29
+ from pathlib import Path
30
+ from typing import Final
31
+
32
+ # Canonical-uppercase exception set per spec section 4.1. These names
33
+ # are recognized verbatim regardless of casing rules. The set is closed;
34
+ # new exceptions land via rule revision, never ad-hoc.
35
+ CANONICAL_NAMES: Final[frozenset[str]] = frozenset(
36
+ {
37
+ "CLAUDE.md",
38
+ "README.md",
39
+ "LICENSE",
40
+ "LICENSE.md",
41
+ "LICENSE.txt",
42
+ "CHANGELOG.md",
43
+ "SECURITY.md",
44
+ "SUPPORT.md",
45
+ "CODE_OF_CONDUCT.md",
46
+ "CONTRIBUTING.md",
47
+ "NOTICE",
48
+ "NOTICE.md",
49
+ "MASTER-PLAN.md",
50
+ "PROGRESS.md",
51
+ "PHASE.md",
52
+ "SKILL.md",
53
+ "REPORT.md",
54
+ "PLAN-NOTES.md",
55
+ "PREAMBLE.md",
56
+ "COMPLETION.md",
57
+ "VERSION",
58
+ "MEMORY.md",
59
+ "site/content/docs/architecture/agents.mdx",
60
+ "Makefile",
61
+ }
62
+ )
63
+
64
+ # kebab-case for the principal stem; an optional dotted suffix carries
65
+ # the host-natural extension list. The stem may carry digits but not
66
+ # uppercase letters, underscores, or spaces.
67
+ KEBAB_STEM_RE: Final[re.Pattern[str]] = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
68
+
69
+ # Phase-folder prefix `NN-topic` and sub-phase-folder prefix `NNL-topic`
70
+ # (digits + optional single uppercase letter) honor the ordering
71
+ # discipline at canonical-layout section 2.1. The suffix is kebab-case.
72
+ PHASE_PREFIX_RE: Final[re.Pattern[str]] = re.compile(
73
+ r"^[0-9]{2}[A-Z]?-[a-z0-9]+(?:-[a-z0-9]+)*$"
74
+ )
75
+
76
+ # Migration-script prefix `NNNN_name` honors the host-ratified ordinal
77
+ # scheme common to migration tooling.
78
+ MIGRATION_PREFIX_RE: Final[re.Pattern[str]] = re.compile(
79
+ r"^[0-9]{2,5}_[a-z0-9]+(?:_[a-z0-9]+)*$"
80
+ )
81
+
82
+ # ADR filenames follow `NNNN-kebab-topic.md` per the ADR convention.
83
+ ADR_NAME_RE: Final[re.Pattern[str]] = re.compile(
84
+ r"^[0-9]{4}-[a-z0-9]+(?:-[a-z0-9]+)*\.md$"
85
+ )
86
+
87
+ GREP_NAME: Final[str] = "naming-grep"
88
+ RULE_ANCHOR: Final[str] = "CLAUDE.md Coding Conventions (kebab-case naming)"
89
+ EXIT_PASS: Final[int] = 0
90
+ EXIT_FAIL: Final[int] = 2
91
+ STDIN_FLAG: Final[str] = "--stdin"
92
+
93
+
94
+ @dataclass(frozen=True)
95
+ class Finding:
96
+ component: str
97
+ detail: str
98
+ rule: str = RULE_ANCHOR
99
+
100
+
101
+ @dataclass(frozen=True)
102
+ class GrepResult:
103
+ grep: str
104
+ path: str | None
105
+ passed: bool
106
+ findings: list[Finding] = field(default_factory=list)
107
+
108
+ def to_json(self) -> str:
109
+ payload = {
110
+ "grep": self.grep,
111
+ "path": self.path,
112
+ "passed": self.passed,
113
+ "findings": [asdict(f) for f in self.findings],
114
+ }
115
+ return json.dumps(payload, indent=2)
116
+
117
+
118
+ def _stem_and_extensions(name: str) -> tuple[str, str]:
119
+ """Split a filename at the first dot; the suffix is the extension run."""
120
+ if "." not in name:
121
+ return name, ""
122
+ head, tail = name.split(".", 1)
123
+ return head, tail
124
+
125
+
126
+ def _is_canonical_name(name: str) -> bool:
127
+ return name in CANONICAL_NAMES
128
+
129
+
130
+ def _is_phase_prefix(name: str) -> bool:
131
+ return bool(PHASE_PREFIX_RE.match(name))
132
+
133
+
134
+ def _is_migration_prefix(stem: str) -> bool:
135
+ return bool(MIGRATION_PREFIX_RE.match(stem))
136
+
137
+
138
+ def _is_adr_name(name: str) -> bool:
139
+ return bool(ADR_NAME_RE.match(name))
140
+
141
+
142
+ def _component_passes(name: str) -> tuple[bool, str]:
143
+ """Return (passes, reason). reason explains the failure shape."""
144
+ if not name:
145
+ return True, ""
146
+ if name.startswith("."):
147
+ # Dotfiles and dot-dirs are host-discovered; do not enforce.
148
+ return True, ""
149
+ if _is_canonical_name(name):
150
+ return True, ""
151
+ # Phase-prefix shape (NN-topic / NNL-topic) is unambiguous; admit
152
+ # regardless of the directory-vs-file inference because a user-
153
+ # supplied path string carries no on-disk-stat hint.
154
+ if _is_phase_prefix(name):
155
+ return True, ""
156
+ if _is_adr_name(name):
157
+ return True, ""
158
+ stem, _ = _stem_and_extensions(name)
159
+ if _is_migration_prefix(stem):
160
+ return True, ""
161
+ if KEBAB_STEM_RE.match(stem):
162
+ return True, ""
163
+ return False, (
164
+ f"component {name!r} is neither kebab-case nor a canonical "
165
+ f"exception (spec section 4.1)"
166
+ )
167
+
168
+
169
+ def check(target: str, *, is_dir: bool | None = None) -> GrepResult:
170
+ """Validate every path component against the naming convention.
171
+
172
+ ``is_dir`` is retained for call-site signature compatibility; the
173
+ convention check is component-shape-only and does not branch on
174
+ whether the terminal component is a directory.
175
+ """
176
+ del is_dir # accepted for signature compatibility; not consulted
177
+ findings: list[Finding] = []
178
+ parts = Path(target).parts
179
+ for component in parts:
180
+ # Drop drive anchors like 'C:', 'C:\\', or '/' on POSIX. The
181
+ # Windows form `Path('D:\\foo').parts[0]` returns the literal
182
+ # 'D:\\' (drive letter + colon + separator), not bare 'D:'.
183
+ if (
184
+ component.endswith(":")
185
+ or component in ("/", "\\")
186
+ or (len(component) >= 2 and component[1] == ":")
187
+ ):
188
+ continue
189
+ passes, reason = _component_passes(component)
190
+ if not passes:
191
+ findings.append(Finding(component=component, detail=reason))
192
+ return GrepResult(
193
+ grep=GREP_NAME,
194
+ path=target,
195
+ passed=not findings,
196
+ findings=findings,
197
+ )
198
+
199
+
200
+ def _read_input(argv: list[str]) -> str:
201
+ if len(argv) >= 2 and argv[1] != STDIN_FLAG:
202
+ return argv[1]
203
+ return sys.stdin.read().strip()
204
+
205
+
206
+ def _main(argv: list[str]) -> int:
207
+ target = _read_input(argv)
208
+ # In the conformity gate's --all mode this validator is handed the
209
+ # absolute repository root. naming-grep validates the project's own
210
+ # artifact names, not the host filesystem ancestry above the repo
211
+ # root (`Users`, a home-directory name, etc.) — so an absolute
212
+ # directory input is reduced to its own basename. Relative inputs
213
+ # (the per-path invocation form) are validated component-by-component
214
+ # unchanged.
215
+ candidate = Path(target)
216
+ if candidate.is_absolute() and candidate.is_dir():
217
+ target = candidate.name
218
+ result = check(target)
219
+ print(result.to_json())
220
+ return EXIT_PASS if result.passed else EXIT_FAIL
221
+
222
+
223
+ if __name__ == "__main__":
224
+ sys.exit(_main(sys.argv))
@@ -0,0 +1,339 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Walk the git index for tracked plans paths; fail when found.
4
+
5
+ Why this validator exists. The Plans Discipline at spec section 3
6
+ forbids planning artifacts at any global location and at the
7
+ ecosystem root. Plans live at the sole canonical
8
+ ``<project-root>/.apothem/plans/`` tree and are gitignored — they
9
+ never enter a git history. A plans path (under ``.apothem/plans/`` or
10
+ a legacy ``.plans/``) appearing in ``git ls-files`` is direct evidence
11
+ that the discipline has lapsed: either the gitignore is missing the
12
+ pattern, the ``.gitignore`` has been bypassed via ``git add --force``,
13
+ or a nested project's plans directory has been tracked by mistake.
14
+
15
+ Why git-index, not filesystem. The recursion case at spec section 3
16
+ (the apothem source repository itself contains a plans tree while it is
17
+ being authored — and, for the Claude Code harness specifically, that
18
+ working tree lives under ``~/.claude/``) is resolved precisely because
19
+ the on-disk plans tree is gitignored. Walking the filesystem would flag
20
+ the in-flight suite as a violation; walking the git index returns clean
21
+ by construction. The validator's surface IS the git index — the
22
+ source-of-truth for "what ships with this repository."
23
+
24
+ Detection strategy. The validator runs ``git ls-files`` from the
25
+ root, filters the output for entries under any plans directory
26
+ (``.apothem/plans/`` or a legacy ``.plans/``, top-level or nested), and
27
+ excludes the documented anti-pattern references inside
28
+ ``site/content/docs/reference/plans-discipline.mdx`` (the file is allow-
29
+ listed wholesale because the validator inspects path entries, not
30
+ file contents — and the file's path itself does not match the plans
31
+ pattern).
32
+
33
+ Filesystem stray-suite sweep (additive). The git-index check above is
34
+ blind to a plans directory that exists on disk but is untracked — a
35
+ stray suite materialized at a non-canonical location (a nested sub-tree,
36
+ a sibling tree, or a legacy ``<root>/.plans`` that has not yet been
37
+ upgraded) escapes ``git ls-files`` entirely because it is gitignored or
38
+ simply not yet added. The suite-locality invariant fixes exactly one
39
+ canonical plans tree per project: ``<root>/.apothem/plans/``. Any other
40
+ on-disk plans directory under the root — including a legacy
41
+ ``<root>/.plans`` an operator upgrades via ``apothem migrate-workspace``
42
+ — is a stray suite and a Plans-Locality violation. The sweep walks the
43
+ filesystem (skipping the vendored / generated / VCS trees that carry
44
+ upstream conventions or machine state) and flags every plans directory
45
+ that is not the canonical ``<root>/.apothem/plans``. The two checks are
46
+ complementary: the git-index check catches a *tracked* plans path; the
47
+ filesystem sweep catches an *untracked stray* plans directory the index
48
+ check is blind to.
49
+
50
+ Exit semantics. Exits 0 when no findings; exits 2 on any finding.
51
+ The exit-2 convention matches the conformity-gate orchestrator's
52
+ EXIT_FAIL constant.
53
+ """
54
+
55
+ from __future__ import annotations
56
+
57
+ import json
58
+ import re
59
+ import subprocess
60
+ import sys
61
+ from dataclasses import asdict, dataclass, field
62
+ from pathlib import Path
63
+ from typing import Final
64
+
65
+ GREP_NAME: Final[str] = "no-global-plans-grep"
66
+ RULE_ANCHOR: Final[str] = "CLAUDE.md Plans Discipline (no global plans)"
67
+
68
+ EXIT_PASS: Final[int] = 0
69
+ EXIT_FAIL: Final[int] = 2
70
+
71
+ # Pattern for any path containing a plans-suite directory segment. The sole
72
+ # canonical project-local plans location is `.apothem/plans/` (the shared
73
+ # Apothem working directory's plans child); the legacy `.plans/` layout is no
74
+ # longer canonical — operators upgrade an existing `.plans` tree via
75
+ # `apothem migrate-workspace`. Both layouts are gitignored, so a tracked path
76
+ # under EITHER is the same discipline lapse and is flagged for leak detection.
77
+ #
78
+ # Matches `.plans/foo`, `subdir/.plans/bar`, `.apothem/plans/foo`,
79
+ # `subdir/.apothem/plans/bar`, but does NOT match `plans-discipline.md` (no
80
+ # trailing slash), `my.plans/x.md` (no leading boundary), or a non-`plans`
81
+ # child of `.apothem/` such as `.apothem/memory/` (operator data, not a plan).
82
+ _PLANS_PATH_RE: Final[re.Pattern[str]] = re.compile(
83
+ r"(?:^|/)(?:\.plans|\.apothem/plans)/"
84
+ )
85
+
86
+ # Directory names the filesystem stray-suite sweep does NOT descend into.
87
+ # Vendored / generated / VCS / cache trees carry upstream or machine state, not
88
+ # apothem-authored content; a `.plans/` directory inside any of them is not a
89
+ # stray apothem plan suite. Pruning them also keeps the walk fast.
90
+ _SWEEP_SKIP_DIRS: Final[frozenset[str]] = frozenset(
91
+ {
92
+ ".git",
93
+ "_vendor",
94
+ "node_modules",
95
+ "dist",
96
+ "site/dist",
97
+ ".mypy_cache",
98
+ ".pytest_cache",
99
+ ".ruff_cache",
100
+ ".hypothesis",
101
+ "__pycache__",
102
+ ".venv",
103
+ "venv",
104
+ }
105
+ )
106
+
107
+
108
+ @dataclass(frozen=True)
109
+ class Finding:
110
+ """One tracked-in-git path under a .plans/ directory."""
111
+
112
+ path: str
113
+ detail: str
114
+ rule: str = RULE_ANCHOR
115
+
116
+
117
+ @dataclass(frozen=True)
118
+ class GrepResult:
119
+ """Aggregated walk result for a single git-index + filesystem sweep."""
120
+
121
+ grep: str
122
+ root: str
123
+ tracked_count: int
124
+ passed: bool
125
+ stray_plans_count: int = 0
126
+ findings: list[Finding] = field(default_factory=list)
127
+
128
+ def to_json(self) -> str:
129
+ payload = {
130
+ "grep": self.grep,
131
+ "root": self.root,
132
+ "tracked_count": self.tracked_count,
133
+ "stray_plans_count": self.stray_plans_count,
134
+ "passed": self.passed,
135
+ "findings": [asdict(f) for f in self.findings],
136
+ }
137
+ return json.dumps(payload, indent=2)
138
+
139
+
140
+ def _git_ls_files(root: Path) -> list[str]:
141
+ """Return the git-tracked file list under root.
142
+
143
+ Raises ``RuntimeError`` when ``git`` is unavailable or root is not
144
+ a git repository — both are operator errors the caller surfaces.
145
+ """
146
+ try:
147
+ completed = subprocess.run( # noqa: S603 — trusted invocation: literal argv against git
148
+ ["git", "-C", str(root), "ls-files"], # noqa: S607 — PATH-resolved git is acceptable for a developer-tool validator; full-path resolution would require host-discovery and breaks portability across operator setups.
149
+ check=True,
150
+ capture_output=True,
151
+ text=True,
152
+ encoding="utf-8",
153
+ )
154
+ except FileNotFoundError as exc:
155
+ raise RuntimeError("git executable not found on PATH") from exc
156
+ except subprocess.CalledProcessError as exc:
157
+ stderr = (exc.stderr or "").strip()
158
+ raise RuntimeError(
159
+ f"git ls-files failed under {root!s}: {stderr or 'no stderr'}"
160
+ ) from exc
161
+ return [line for line in completed.stdout.splitlines() if line]
162
+
163
+
164
+ def _sweep_stray_plans_dirs(
165
+ root: Path, tracked_plans_dirs: frozenset[str]
166
+ ) -> list[Finding]:
167
+ """Walk the filesystem under root; flag *untracked* stray plans dirs.
168
+
169
+ A stray suite is any on-disk plans directory that is not the sole canonical
170
+ project-local location ``<root>/.apothem/plans`` (the shared Apothem working
171
+ directory's plans child). Any ``.plans`` directory (including a legacy
172
+ ``<root>/.plans`` — operators upgrade it via ``apothem migrate-workspace``),
173
+ or any ``.apothem/plans`` directory under a non-root ``.apothem`` (e.g. a
174
+ nested ``sub/.apothem/plans`` analogous to a global ``~/.apothem/plans``),
175
+ is a stray and a Plans-Locality violation.
176
+
177
+ The walk prunes the vendored / generated / VCS / cache trees in
178
+ ``_SWEEP_SKIP_DIRS`` so a plans directory inside one of those (upstream or
179
+ machine state, never an apothem plan suite) is not flagged. It descends into
180
+ ``.apothem`` directories (they hold operator memory/learning/contexts data
181
+ alongside plans) but never descends into a plans tree itself or into the
182
+ ``.apothem`` data children — only the ``plans`` child of an ``.apothem``
183
+ directory is plans-relevant. The check is **additive and non-overlapping**
184
+ with the git-index check: a plans directory whose contents are already
185
+ git-tracked is reported there, so the sweep skips it via
186
+ ``tracked_plans_dirs`` to avoid double-reporting. The sweep's unique value is
187
+ the *untracked* stray. Returns an empty list when the filesystem is
188
+ unreadable (the git-index check still carries the verdict).
189
+ """
190
+ findings: list[Finding] = []
191
+ try:
192
+ resolved_root = root.resolve()
193
+ except (OSError, RuntimeError):
194
+ return findings
195
+ canonical_new = (resolved_root / ".apothem" / "plans").resolve()
196
+ canonical = {canonical_new}
197
+
198
+ def _record_stray(entry: Path, rel: str) -> None:
199
+ """Append a stray finding for a plans directory unless it is canonical
200
+ or already covered by the git-index check."""
201
+ already_tracked = rel in tracked_plans_dirs
202
+ if entry.resolve() in canonical or already_tracked:
203
+ return
204
+ findings.append(
205
+ Finding(
206
+ path=f"{rel}/",
207
+ detail=(
208
+ "an untracked stray plans directory exists on disk outside "
209
+ "the sole canonical project-local <root>/.apothem/plans tree; "
210
+ "there is exactly one plans tree per project per the "
211
+ "suite-locality invariant — relocate the stray suite, or run "
212
+ "`apothem migrate-workspace` to upgrade a legacy <root>/.plans "
213
+ "tree"
214
+ ),
215
+ )
216
+ )
217
+
218
+ stack: list[Path] = [resolved_root]
219
+ while stack:
220
+ current = stack.pop()
221
+ try:
222
+ entries = list(current.iterdir())
223
+ except (OSError, PermissionError):
224
+ continue
225
+ for entry in entries:
226
+ try:
227
+ is_dir = entry.is_dir()
228
+ except OSError:
229
+ continue
230
+ if not is_dir:
231
+ continue
232
+ name = entry.name
233
+ if name in _SWEEP_SKIP_DIRS:
234
+ continue
235
+ rel = entry.relative_to(resolved_root).as_posix()
236
+ if name == ".plans":
237
+ _record_stray(entry, rel)
238
+ # Do not descend into a .plans/ tree (it is suite content, not a
239
+ # place a nested .plans/ should appear).
240
+ continue
241
+ if name == ".apothem":
242
+ # An ``.apothem`` directory holds operator data
243
+ # (memory/learning/contexts) plus the plans child. Inspect only
244
+ # the ``plans`` child for stray-suite detection; descend no
245
+ # further into the data children.
246
+ plans_child = entry / "plans"
247
+ try:
248
+ if plans_child.is_dir():
249
+ _record_stray(plans_child, f"{rel}/plans")
250
+ except OSError:
251
+ pass
252
+ continue
253
+ stack.append(entry)
254
+ return findings
255
+
256
+
257
+ def _tracked_plans_dirs(tracked: list[str]) -> frozenset[str]:
258
+ """Return the set of plans-segment directory paths the git index covers.
259
+
260
+ For each tracked path matching ``(.../)?(.plans|.apothem/plans)/...``,
261
+ extract the directory portion up to and including the plans segment (e.g.
262
+ ``subdir/.plans/x.md`` -> ``subdir/.plans``; ``.plans/a.md`` -> ``.plans``;
263
+ ``sub/.apothem/plans/x.md`` -> ``sub/.apothem/plans``;
264
+ ``.apothem/plans/a.md`` -> ``.apothem/plans``). The sweep uses this set to
265
+ skip already-tracked plans directories so they are not double-counted across
266
+ the git-index check and the filesystem sweep.
267
+ """
268
+ dirs: set[str] = set()
269
+ for path in tracked:
270
+ match = _PLANS_PATH_RE.search(path)
271
+ if not match:
272
+ continue
273
+ # The match spans the leading-boundary slash (when present) plus the
274
+ # plans segment and its trailing slash, e.g. "/.apothem/plans/" or
275
+ # "/.plans/". Trim the trailing slash to leave the directory path up to
276
+ # and including the plans segment.
277
+ end = match.end() - 1 # drop the trailing '/'
278
+ dir_path = path[:end]
279
+ # Strip a leading separator the boundary group may have consumed when the
280
+ # segment was not at the path start.
281
+ dirs.add(dir_path.lstrip("/") if match.start() != 0 else dir_path)
282
+ return frozenset(dirs)
283
+
284
+
285
+ def check(root: Path) -> GrepResult:
286
+ """Walk the git index + filesystem under root; flag stray .plans/ paths.
287
+
288
+ Two complementary checks: (1) the git-index check flags any *tracked*
289
+ ``.plans/`` or ``.apothem/plans/`` path (a planning artifact that has
290
+ entered git history); (2) the filesystem stray-suite sweep flags any
291
+ *untracked* on-disk plans directory that is not the sole canonical
292
+ ``<root>/.apothem/plans`` (a stray suite the index check is blind to).
293
+ Either check's finding fails the validator.
294
+ """
295
+ tracked = _git_ls_files(root)
296
+ findings: list[Finding] = []
297
+ for path in tracked:
298
+ if _PLANS_PATH_RE.search(path):
299
+ findings.append(
300
+ Finding(
301
+ path=path,
302
+ detail=(
303
+ "plans path is tracked in git; planning artifacts MUST "
304
+ "live in the gitignored project-local "
305
+ "<project-root>/.apothem/plans/ tree per spec section 3"
306
+ ),
307
+ )
308
+ )
309
+ stray = _sweep_stray_plans_dirs(root, _tracked_plans_dirs(tracked))
310
+ findings.extend(stray)
311
+ return GrepResult(
312
+ grep=GREP_NAME,
313
+ root=str(root),
314
+ tracked_count=len(tracked),
315
+ stray_plans_count=len(stray),
316
+ passed=not findings,
317
+ findings=findings,
318
+ )
319
+
320
+
321
+ def _read_input(argv: list[str]) -> Path:
322
+ if len(argv) >= 2:
323
+ return Path(argv[1])
324
+ return Path.cwd()
325
+
326
+
327
+ def _main(argv: list[str]) -> int:
328
+ root = _read_input(argv)
329
+ try:
330
+ result = check(root)
331
+ except RuntimeError as exc:
332
+ sys.stderr.write(f"{GREP_NAME}: {exc}\n")
333
+ return EXIT_FAIL
334
+ print(result.to_json())
335
+ return EXIT_PASS if result.passed else EXIT_FAIL
336
+
337
+
338
+ if __name__ == "__main__":
339
+ sys.exit(_main(sys.argv))
@@ -0,0 +1,120 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Fail when a top-level ``docs/`` directory exists at the repository root.
4
+
5
+ Why this validator exists. The documentation source of truth is the
6
+ Next.js + Fumadocs site under ``site/``; the rendered reference pages live
7
+ at ``site/content/docs/``. A bare ``docs/`` directory at the
8
+ repository root is a competing documentation source — a second place a
9
+ contributor (or a generator) might write or read docs from, splitting
10
+ the single-source-of-truth invariant. Once a root ``docs/`` exists,
11
+ links, build steps, and contributor habits accrete around it and the
12
+ two trees drift. The invariant is therefore structural and hard: there
13
+ is exactly one documentation tree (``site/``), and the repository root
14
+ never carries a ``docs/`` directory.
15
+
16
+ Scope of the violation. ONLY a directory named ``docs`` directly under
17
+ the repository root is forbidden. Nested ``docs/`` directories under
18
+ other trees (for example a vendored package's own ``docs/``), the
19
+ ``site/`` tree, and ``src/`` are all fine — the validator inspects the
20
+ single root-level entry, not the whole tree.
21
+
22
+ Non-advisory. Unlike the advisory matchers, this is a hard structural
23
+ invariant: ``check()`` returns ``passed=False`` and the CLI exits 2 the
24
+ moment a root ``docs/`` directory is present, so a ``--strict`` CI step
25
+ blocks the change.
26
+
27
+ Exit semantics. Exits 0 when no findings; exits 2 on any finding,
28
+ matching the conformity-gate orchestrator's EXIT_FAIL constant.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import json
34
+ import sys
35
+ from dataclasses import asdict, dataclass, field
36
+ from pathlib import Path
37
+ from typing import Final
38
+
39
+ GREP_NAME: Final[str] = "no-toplevel-docs-grep"
40
+ RULE_ANCHOR: Final[str] = "single-source-of-truth (docs live in site/, not root docs/)"
41
+
42
+ EXIT_PASS: Final[int] = 0
43
+ EXIT_FAIL: Final[int] = 2
44
+
45
+ # The forbidden directory name at the repository root.
46
+ _FORBIDDEN_DIR: Final[str] = "docs"
47
+ # The canonical documentation tree contributors must use instead.
48
+ _CANONICAL_DOCS_TREE: Final[str] = "site/content/docs/"
49
+
50
+
51
+ @dataclass(frozen=True)
52
+ class Finding:
53
+ """The single finding: a root-level ``docs/`` directory exists."""
54
+
55
+ path: str
56
+ detail: str
57
+ rule: str = RULE_ANCHOR
58
+
59
+
60
+ @dataclass(frozen=True)
61
+ class GrepResult:
62
+ """Aggregated result for a single root-level ``docs/`` probe."""
63
+
64
+ grep: str
65
+ root: str
66
+ passed: bool
67
+ advisory: bool = False
68
+ findings: list[Finding] = field(default_factory=list)
69
+
70
+ def to_json(self) -> str:
71
+ payload = {
72
+ "grep": self.grep,
73
+ "root": self.root,
74
+ "passed": self.passed,
75
+ "advisory": self.advisory,
76
+ "findings": [asdict(f) for f in self.findings],
77
+ }
78
+ return json.dumps(payload, indent=2)
79
+
80
+
81
+ def check(root: Path) -> GrepResult:
82
+ """Flag a ``docs/`` directory living directly under *root*."""
83
+ candidate = root / _FORBIDDEN_DIR
84
+ findings: list[Finding] = []
85
+ if candidate.is_dir():
86
+ findings.append(
87
+ Finding(
88
+ path=f"{_FORBIDDEN_DIR}/",
89
+ detail=(
90
+ "a top-level docs/ directory is forbidden: the "
91
+ "documentation source of truth is site/ "
92
+ f"(rendered pages at {_CANONICAL_DOCS_TREE}); "
93
+ "remove the root docs/ tree and author documentation "
94
+ "under site/ instead"
95
+ ),
96
+ )
97
+ )
98
+ return GrepResult(
99
+ grep=GREP_NAME,
100
+ root=str(root),
101
+ passed=not findings,
102
+ findings=findings,
103
+ )
104
+
105
+
106
+ def _read_input(argv: list[str]) -> Path:
107
+ if len(argv) >= 2:
108
+ return Path(argv[1])
109
+ return Path.cwd()
110
+
111
+
112
+ def _main(argv: list[str]) -> int:
113
+ root = _read_input(argv)
114
+ result = check(root)
115
+ print(result.to_json())
116
+ return EXIT_PASS if result.passed else EXIT_FAIL
117
+
118
+
119
+ if __name__ == "__main__":
120
+ sys.exit(_main(sys.argv))