@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,78 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ # Purpose: Locate a real PowerShell >= 7 on PATH for any PowerShell-side
4
+ # surface that needs to spawn a pwsh subprocess, rejecting Microsoft Store
5
+ # launcher shims (zero-byte stubs at AppData\Local\Microsoft\WindowsApps
6
+ # that fail at exec time with "Executable not found").
7
+ # Contract: dot-source then call Find-RealPwsh; returns the absolute
8
+ # path to a working pwsh interpreter, or $null when none found. Does
9
+ # not throw on probe failures — silently skips bad candidates so the
10
+ # caller's diagnostic envelope path runs.
11
+ # Sibling files in hooks/lib/: find-pwsh.sh (POSIX counterpart),
12
+ # find-python.ps1 (PowerShell counterpart for Python — paired-template
13
+ # peer), find-python.sh (POSIX counterpart of the Python locator).
14
+
15
+ Set-StrictMode -Version Latest
16
+ $ErrorActionPreference = 'Stop'
17
+
18
+ function Find-RealPwsh {
19
+ [CmdletBinding()]
20
+ [OutputType([string])]
21
+ param(
22
+ [int]$MinMajor = 7
23
+ )
24
+
25
+ $candidates = @('pwsh', 'pwsh-preview')
26
+ $fallbackPaths = @(
27
+ (Join-Path $env:ProgramFiles 'PowerShell\7\pwsh.exe'),
28
+ (Join-Path $env:ProgramFiles 'PowerShell\7-preview\pwsh.exe'),
29
+ (Join-Path ${env:ProgramFiles(x86)} 'PowerShell\7\pwsh.exe')
30
+ )
31
+ $probe = '$PSVersionTable.PSVersion.Major'
32
+
33
+ # Phase 1 — PATH probe via Get-Command, rejecting WindowsApps stubs.
34
+ foreach ($name in $candidates) {
35
+ $cmds = @(Get-Command $name -All -ErrorAction SilentlyContinue)
36
+ foreach ($cmd in $cmds) {
37
+ $src = $cmd.Source
38
+ if (-not $src) { continue }
39
+ if ($src -match 'WindowsApps') { continue }
40
+ $info = Get-Item -LiteralPath $src -ErrorAction SilentlyContinue
41
+ if (-not $info) { continue }
42
+ if ($info.Length -lt 1024) { continue }
43
+
44
+ $output = $null
45
+ try { $output = & $src -NoProfile -Command $probe 2>$null } catch { continue }
46
+ if ($LASTEXITCODE -ne 0) { continue }
47
+ if (-not $output) { continue }
48
+ $trimmed = ($output -join '').Trim()
49
+ $maj = 0
50
+ if (-not [int]::TryParse($trimmed, [ref]$maj)) { continue }
51
+ if ($maj -ge $MinMajor) {
52
+ return $src
53
+ }
54
+ }
55
+ }
56
+
57
+ # Phase 2 — canonical Windows install paths.
58
+ foreach ($candidate in $fallbackPaths) {
59
+ if (-not $candidate) { continue }
60
+ if (-not (Test-Path -LiteralPath $candidate)) { continue }
61
+ $info = Get-Item -LiteralPath $candidate -ErrorAction SilentlyContinue
62
+ if (-not $info) { continue }
63
+ if ($info.Length -lt 1024) { continue }
64
+
65
+ $output = $null
66
+ try { $output = & $candidate -NoProfile -Command $probe 2>$null } catch { continue }
67
+ if ($LASTEXITCODE -ne 0) { continue }
68
+ if (-not $output) { continue }
69
+ $trimmed = ($output -join '').Trim()
70
+ $maj = 0
71
+ if (-not [int]::TryParse($trimmed, [ref]$maj)) { continue }
72
+ if ($maj -ge $MinMajor) {
73
+ return $candidate
74
+ }
75
+ }
76
+
77
+ return $null
78
+ }
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env bash
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ # Purpose: Locate a real PowerShell >= 7 on PATH for any bash-side surface
5
+ # that needs to spawn a pwsh subprocess, rejecting Microsoft Store launcher
6
+ # shims (zero-byte stubs at AppData/Local/Microsoft/WindowsApps under
7
+ # WSL/Git-Bash mounts that fail at exec time with "Executable not found").
8
+ # Contract: dot-source then call find_real_pwsh; prints the absolute path
9
+ # on success and returns 0; returns 1 when no candidate satisfies the
10
+ # version floor. Does not throw on probe failures — silently skips bad
11
+ # candidates so the caller's diagnostic envelope path runs.
12
+ # Sibling files in hooks/lib/: find-pwsh.ps1 (PowerShell counterpart),
13
+ # find-python.sh (POSIX counterpart for Python — paired-template peer),
14
+ # find-python.ps1 (PowerShell counterpart of the Python locator).
15
+ #
16
+ # Usage (sourced): . lib/find-pwsh.sh && p="$(find_real_pwsh)" || exit 1
17
+ # Exit codes: prints absolute path on success; exits 1 if none found.
18
+
19
+ find_real_pwsh() {
20
+ local min_major="${1:-7}"
21
+ local candidates=(pwsh pwsh-preview)
22
+ local fallback_paths=(
23
+ /usr/local/bin/pwsh
24
+ /usr/bin/pwsh
25
+ /opt/microsoft/powershell/7/pwsh
26
+ /opt/microsoft/powershell/7-preview/pwsh
27
+ )
28
+ local name path size major
29
+
30
+ # Phase 1 — PATH probe via type -ap, rejecting WindowsApps stubs.
31
+ for name in "${candidates[@]}"; do
32
+ while IFS= read -r path; do
33
+ [[ -z "$path" ]] && continue
34
+ case "$path" in *WindowsApps*) continue ;; esac
35
+ if [[ ! -x "$path" ]]; then continue; fi
36
+ size=$(wc -c < "$path" 2>/dev/null || echo 0)
37
+ [[ "$size" -lt 1024 ]] && continue
38
+ local probe_output
39
+ # SC2016: the single-quoted expression is intentionally NOT
40
+ # bash-expanded — it's a PowerShell expression evaluated by pwsh.
41
+ # shellcheck disable=SC2016
42
+ probe_output=$("$path" -NoProfile -Command '$PSVersionTable.PSVersion.Major' 2>/dev/null) || continue
43
+ probe_output="${probe_output//$'\r'/}"
44
+ probe_output="${probe_output//[[:space:]]/}"
45
+ major="$probe_output"
46
+ [[ -z "$major" ]] && continue
47
+ [[ ! "$major" =~ ^[0-9]+$ ]] && continue
48
+ if (( major >= min_major )); then
49
+ printf '%s\n' "$path"
50
+ return 0
51
+ fi
52
+ done < <(type -ap "$name" 2>/dev/null)
53
+ done
54
+
55
+ # Phase 2 — canonical install paths (Linux / macOS).
56
+ for path in "${fallback_paths[@]}"; do
57
+ [[ -x "$path" ]] || continue
58
+ size=$(wc -c < "$path" 2>/dev/null || echo 0)
59
+ [[ "$size" -lt 1024 ]] && continue
60
+ local probe_output
61
+ # SC2016: same intentional PowerShell expression as Phase 1.
62
+ # shellcheck disable=SC2016
63
+ probe_output=$("$path" -NoProfile -Command '$PSVersionTable.PSVersion.Major' 2>/dev/null) || continue
64
+ probe_output="${probe_output//$'\r'/}"
65
+ probe_output="${probe_output//[[:space:]]/}"
66
+ major="$probe_output"
67
+ [[ -z "$major" ]] && continue
68
+ [[ ! "$major" =~ ^[0-9]+$ ]] && continue
69
+ if (( major >= min_major )); then
70
+ printf '%s\n' "$path"
71
+ return 0
72
+ fi
73
+ done
74
+
75
+ return 1
76
+ }
@@ -0,0 +1,63 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ # Purpose: Locate a real CPython >= 3.10 on PATH for the PowerShell
4
+ # bootstrap stub, rejecting Microsoft Store launcher shims (zero-byte
5
+ # stubs at AppData\Local\Microsoft\WindowsApps).
6
+ # Contract: dot-source then call Find-RealPython; returns the absolute
7
+ # path to a working interpreter, or $null when none found. Does not
8
+ # throw on probe failures — silently skips bad candidates.
9
+ # Sibling files in hooks/lib/: find-python.sh (POSIX counterpart),
10
+ # bootstrap.ps1 (the script that dot-sources this locator),
11
+ # bootstrap.sh (POSIX counterpart of the bootstrap stub).
12
+
13
+ Set-StrictMode -Version Latest
14
+ $ErrorActionPreference = 'Stop'
15
+
16
+ function Find-RealPython {
17
+ [CmdletBinding()]
18
+ [OutputType([string])]
19
+ param(
20
+ [int]$MinMajor = 3,
21
+ [int]$MinMinor = 10
22
+ )
23
+
24
+ $candidates = @('python', 'python3', 'python3.14', 'python3.13', 'python3.12', 'python3.11', 'python3.10')
25
+ $probe = 'import sys; sys.stdout.write(str(sys.version_info.major) + chr(32) + str(sys.version_info.minor))'
26
+
27
+ foreach ($name in $candidates) {
28
+ # PATH resolution: Get-Command searches only the non-empty directories
29
+ # in $env:PATH and never the current directory implicitly, so an empty
30
+ # PATH segment (a doubled ';;' or a leading/trailing separator) yields
31
+ # no candidate here. The cwd-from-empty-segment footgun closed in the
32
+ # sibling find-python.sh / python_resolver.py PATH walks does not arise
33
+ # in this stub. Do NOT replace Get-Command with a manual PATH walk that
34
+ # maps empty segments to cwd: an explicit '.' entry on PATH is honored,
35
+ # an empty one is not. (Verified against Windows PowerShell.)
36
+ $cmds = @(Get-Command $name -All -ErrorAction SilentlyContinue)
37
+ foreach ($cmd in $cmds) {
38
+ $src = $cmd.Source
39
+ if (-not $src) { continue }
40
+ # Literal substring match (parity with the POSIX `${v#*WindowsApps}`
41
+ # prefix-strip in find-python.sh); -like avoids regex semantics.
42
+ if ($src -like '*WindowsApps*') { continue }
43
+ $info = Get-Item -LiteralPath $src -ErrorAction SilentlyContinue
44
+ if (-not $info) { continue }
45
+ if ($info.Length -lt 1024) { continue }
46
+
47
+ $output = $null
48
+ try { $output = & $src -c $probe 2>$null } catch { continue }
49
+ if ($LASTEXITCODE -ne 0) { continue }
50
+ if (-not $output) { continue }
51
+ $trimmed = ($output -join '').Trim()
52
+ $parts = $trimmed.Split(' ')
53
+ if ($parts.Count -lt 2) { continue }
54
+ $maj = 0; $min = 0
55
+ if (-not [int]::TryParse($parts[0], [ref]$maj)) { continue }
56
+ if (-not [int]::TryParse($parts[1], [ref]$min)) { continue }
57
+ if ($maj -gt $MinMajor -or ($maj -eq $MinMajor -and $min -ge $MinMinor)) {
58
+ return $src
59
+ }
60
+ }
61
+ }
62
+ return $null
63
+ }
@@ -0,0 +1,97 @@
1
+ #!/bin/sh
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ # Purpose: Locate a real CPython >= 3.10 on PATH for the POSIX bootstrap
5
+ # stub, rejecting Microsoft Store launcher shims (zero-byte stubs at
6
+ # AppData/Local/Microsoft/WindowsApps under WSL/Git-Bash mounts).
7
+ # Contract: dot-source then call find_real_python; prints the absolute
8
+ # path on success and returns 0; returns 1 when no candidate satisfies
9
+ # the version floor. Does not throw on probe failures — silently skips
10
+ # bad candidates so the dispatcher's diagnostic envelope path runs.
11
+ # POSIX sh only (no bashisms): runs under dash/ash as well as bash, so a
12
+ # `curl … | sh` installer that dot-sources this locator stays portable.
13
+ # Sibling files in hooks/lib/: find-python.ps1 (PowerShell counterpart),
14
+ # bootstrap.sh (the script that dot-sources this locator), bootstrap.ps1
15
+ # (PowerShell counterpart of the bootstrap stub).
16
+ #
17
+ # Usage (sourced): . lib/find-python.sh && py="$(find_real_python)" || exit 1
18
+ # Exit codes: prints absolute path on success; exits 1 if none found.
19
+
20
+ # Walk every PATH entry and print each executable file matching $1, in PATH
21
+ # order — the POSIX stand-in for bash's `type -ap`, which lists all matches
22
+ # rather than only the first (so a WindowsApps shim earlier on PATH does not
23
+ # mask a real interpreter found later).
24
+ _find_python_path_candidates() {
25
+ _fpc_name="$1"
26
+ _fpc_saved_ifs="$IFS"
27
+ IFS=:
28
+ for _fpc_dir in $PATH; do
29
+ IFS="$_fpc_saved_ifs"
30
+ # Skip an empty PATH segment (a doubled "::" or a leading/trailing
31
+ # delimiter) rather than resolving it to the current directory. POSIX
32
+ # maps an empty segment to cwd, but this locator's result is
33
+ # version-probed (executed) and wired into the hook command that runs
34
+ # on every tool use; discovering an attacker-planted cwd "python" there
35
+ # is the footgun this guard closes. A user who genuinely wants cwd
36
+ # searched adds an explicit "." entry — non-empty, still honored below.
37
+ if [ -z "$_fpc_dir" ]; then
38
+ IFS=:
39
+ continue
40
+ fi
41
+ _fpc_full="${_fpc_dir}/${_fpc_name}"
42
+ if [ -f "$_fpc_full" ] && [ -x "$_fpc_full" ]; then
43
+ printf '%s\n' "$_fpc_full"
44
+ fi
45
+ IFS=:
46
+ done
47
+ IFS="$_fpc_saved_ifs"
48
+ }
49
+
50
+ find_real_python() {
51
+ _frp_min_major="${1:-3}"
52
+ _frp_min_minor="${2:-10}"
53
+ _frp_candidates="python python3 python3.14 python3.13 python3.12 python3.11 python3.10"
54
+
55
+ for _frp_name in $_frp_candidates; do
56
+ # Probe every match for this name once. The inner loop runs in a
57
+ # command-substitution subshell, so `break` (not `return`) emits the
58
+ # first qualifying interpreter; the parent reads it back.
59
+ _frp_winner=$(
60
+ _find_python_path_candidates "$_frp_name" | while IFS= read -r _frp_path; do
61
+ [ -z "$_frp_path" ] && continue
62
+ # Skip Microsoft Store launcher shims. A POSIX prefix-strip
63
+ # test, NOT `case`: this loop body runs inside `_frp_winner=$( … )`,
64
+ # and macOS `/bin/sh` (bash 3.2) cannot parse a `case … ;; esac`
65
+ # inside a command substitution. `dash -n` accepts it, which is
66
+ # why the POSIX-parse gate missed it; `sh install.sh` on macOS
67
+ # then fails at parse time. `${v#*WindowsApps}` differs from `$v`
68
+ # exactly when `$v` contains "WindowsApps".
69
+ if [ "${_frp_path#*WindowsApps}" != "$_frp_path" ]; then
70
+ continue
71
+ fi
72
+ [ -x "$_frp_path" ] || continue
73
+ _frp_size=$(wc -c < "$_frp_path" 2>/dev/null || echo 0)
74
+ [ "$_frp_size" -lt 1024 ] && continue
75
+ _frp_probe=$("$_frp_path" -c 'import sys; sys.stdout.write(str(sys.version_info.major) + " " + str(sys.version_info.minor))' 2>/dev/null) || continue
76
+ _frp_probe=$(printf '%s' "$_frp_probe" | tr -d '\r')
77
+ _frp_major=$(printf '%s\n' "$_frp_probe" | cut -d' ' -f1)
78
+ _frp_minor=$(printf '%s\n' "$_frp_probe" | cut -d' ' -f2)
79
+ { [ -z "$_frp_major" ] || [ -z "$_frp_minor" ]; } && continue
80
+ # Reject empty or non-numeric version components without `case`
81
+ # (same bash-3.2 command-substitution limitation as above): strip
82
+ # every ASCII digit and require a non-empty value with nothing left.
83
+ { [ -z "$_frp_major" ] || [ -n "$(printf '%s' "$_frp_major" | tr -d '0123456789')" ]; } && continue
84
+ { [ -z "$_frp_minor" ] || [ -n "$(printf '%s' "$_frp_minor" | tr -d '0123456789')" ]; } && continue
85
+ if [ "$_frp_major" -gt "$_frp_min_major" ] || { [ "$_frp_major" -eq "$_frp_min_major" ] && [ "$_frp_minor" -ge "$_frp_min_minor" ]; }; then
86
+ printf '%s\n' "$_frp_path"
87
+ break
88
+ fi
89
+ done
90
+ )
91
+ if [ -n "$_frp_winner" ]; then
92
+ printf '%s\n' "$_frp_winner"
93
+ return 0
94
+ fi
95
+ done
96
+ return 1
97
+ }
@@ -0,0 +1,43 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Shared logger factory for the apothem hook scripts.
4
+
5
+ Purpose: a single source of truth for how hook modules acquire a
6
+ ``logging.Logger``. Both ``hooks/emit_hook_context.py`` and
7
+ ``hooks/session_start_bootstrap.py`` previously instantiated their
8
+ loggers via ``logging.getLogger(<hard-coded-name>)``, which drifted
9
+ over time and made downstream handler configuration inconsistent.
10
+
11
+ Contract: ``get_logger(name)`` returns a ``logging.Logger`` whose
12
+ name is the caller's ``__name__``. The hook runtime configures
13
+ handlers itself; this factory does not attach handlers, set levels,
14
+ or alter the root logger — it only provides a uniform acquisition
15
+ point so future structured-logging changes land in one file.
16
+
17
+ Sibling files in hooks/lib/: events.py (event-name single source of
18
+ truth), resolve_root.py (project-root resolver), bootstrap.sh +
19
+ bootstrap.ps1 (the entry stubs that exec the Python hook scripts
20
+ this logger serves), find-python.sh + find-python.ps1 (interpreter
21
+ locators).
22
+
23
+ Note on module name: this file is `log.py` rather than `logging.py`
24
+ because ``hooks/lib/`` is inserted at ``sys.path[0]`` by the
25
+ dispatcher; a sibling named ``logging.py`` would shadow the stdlib
26
+ ``logging`` module on first ``import logging`` and break every
27
+ caller.
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ import logging
33
+
34
+
35
+ def get_logger(name: str) -> logging.Logger:
36
+ """Return a logger named ``name``, typically the caller's ``__name__``.
37
+
38
+ The factory deliberately does no handler/level/formatter setup —
39
+ that is the hook runtime's responsibility. Centralizing the
40
+ acquisition point keeps the call sites uniform and makes future
41
+ structured-logging migrations a single-file change.
42
+ """
43
+ return logging.getLogger(name)
@@ -0,0 +1,264 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Project root resolution for the apothem ecosystem.
4
+
5
+ Resolves the absolute path of the apothem project root using a
6
+ four-level strategy: explicit environment variable, script-relative
7
+ ascent, current-working-directory walk, and a `$HOME/.claude` fallback
8
+ (the Claude Code harness's config root — one of the supported harnesses).
9
+
10
+ Two marker strategies are supported:
11
+
12
+ * ``Mode.HOOKS`` — the root must contain both ``hooks/`` and ``rules/``
13
+ subdirectories. Used by runtime hook scripts that need a populated
14
+ ecosystem.
15
+ * ``Mode.MARKER`` — the root must contain a ``CLAUDE.md`` file. Used by
16
+ scripts that may run before the full layout exists (ecosystem
17
+ scaffolding, bootstrap utilities).
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import os
23
+ from collections.abc import Callable, Iterable, Mapping
24
+ from dataclasses import dataclass
25
+ from enum import Enum
26
+ from pathlib import Path
27
+ from typing import Final
28
+
29
+ #: The Apothem-owned shared working-directory name. The sole canonical
30
+ #: project-local plans home is ``<project-root>/.apothem/plans``. The legacy
31
+ #: ``<project-root>/.plans`` layout is no longer canonical; operators upgrade an
32
+ #: existing ``.plans`` tree via ``apothem migrate-workspace``.
33
+ _APOTHEM_SUBTREE: Final[str] = ".apothem"
34
+ _PLANS_CHILD: Final[str] = "plans"
35
+
36
+ __all__ = [
37
+ "Mode",
38
+ "ResolutionStrategy",
39
+ "canonical_plans_dir",
40
+ "default_content_root",
41
+ "is_canonical_project_plans_dir",
42
+ "resolve_project_root",
43
+ ]
44
+
45
+
46
+ class Mode(str, Enum):
47
+ """Marker-set selector for root detection."""
48
+
49
+ HOOKS = "hooks"
50
+ MARKER = "marker"
51
+
52
+
53
+ _HOOKS_MARKERS: Final[tuple[str, ...]] = ("hooks", "rules")
54
+ _FILE_MARKERS: Final[tuple[str, ...]] = ("CLAUDE.md",)
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class ResolutionStrategy:
59
+ """Concrete resolution configuration derived from a `Mode`.
60
+
61
+ Attributes:
62
+ directory_markers: Subdirectories whose presence identifies a root.
63
+ file_markers: Files whose presence identifies a root.
64
+ """
65
+
66
+ directory_markers: tuple[str, ...]
67
+ file_markers: tuple[str, ...]
68
+
69
+ @classmethod
70
+ def for_mode(cls, mode: Mode) -> ResolutionStrategy:
71
+ """Return the strategy corresponding to `mode`."""
72
+ if mode is Mode.HOOKS:
73
+ return cls(directory_markers=_HOOKS_MARKERS, file_markers=())
74
+ return cls(directory_markers=(), file_markers=_FILE_MARKERS)
75
+
76
+ def matches(self, candidate: Path) -> bool:
77
+ """Return True when `candidate` contains all required markers."""
78
+ if not candidate.is_dir():
79
+ return False
80
+ if not all((candidate / name).is_dir() for name in self.directory_markers):
81
+ return False
82
+ return all((candidate / name).is_file() for name in self.file_markers)
83
+
84
+
85
+ def _iter_ancestors(start: Path) -> Iterable[Path]:
86
+ """Yield `start` and each parent up to the filesystem root."""
87
+ current = start.resolve()
88
+ yield current
89
+ yield from current.parents
90
+
91
+
92
+ def _from_env(strategy: ResolutionStrategy, env: Mapping[str, str]) -> Path | None:
93
+ """Resolve via ``$CLAUDE_PROJECT_DIR`` or ``$LLM_PROJECT_DIR``, or ``None``.
94
+
95
+ The primary variable ``CLAUDE_PROJECT_DIR`` is consulted first; if it is
96
+ unset or does not satisfy the strategy, the vendor-neutral alias
97
+ ``LLM_PROJECT_DIR`` is tried as secondary. A successor harness that only
98
+ sets ``LLM_PROJECT_DIR`` resolves without falling through to later steps.
99
+ """
100
+ for var_name in ("CLAUDE_PROJECT_DIR", "LLM_PROJECT_DIR"):
101
+ env_dir = env.get(var_name)
102
+ if not env_dir:
103
+ continue
104
+ candidate = Path(env_dir)
105
+ if strategy.matches(candidate):
106
+ return candidate.resolve()
107
+ return None
108
+
109
+
110
+ def _from_script(
111
+ strategy: ResolutionStrategy, script_path: Path | str | None
112
+ ) -> Path | None:
113
+ """Resolve via the parent of a script located in ``hooks/``."""
114
+ if script_path is None:
115
+ return None
116
+ script = Path(script_path).resolve()
117
+ if script.parent.name != "hooks":
118
+ return None
119
+ grand = script.parent.parent
120
+ return grand if strategy.matches(grand) else None
121
+
122
+
123
+ def _from_walk(strategy: ResolutionStrategy, cwd: Path | str | None) -> Path | None:
124
+ """Resolve by walking ancestors of `cwd`."""
125
+ start = Path(cwd) if cwd is not None else Path.cwd()
126
+ for ancestor in _iter_ancestors(start):
127
+ if strategy.matches(ancestor):
128
+ return ancestor
129
+ return None
130
+
131
+
132
+ def _from_home(strategy: ResolutionStrategy, home: Path | str | None) -> Path | None:
133
+ """Resolve via ``$HOME/.claude``."""
134
+ home_dir = Path(home) if home is not None else Path.home()
135
+ fallback = home_dir / ".claude"
136
+ return fallback.resolve() if strategy.matches(fallback) else None
137
+
138
+
139
+ def resolve_project_root(
140
+ mode: Mode = Mode.HOOKS,
141
+ *,
142
+ script_path: Path | str | None = None,
143
+ cwd: Path | str | None = None,
144
+ environ: Mapping[str, str] | None = None,
145
+ home: Path | str | None = None,
146
+ ) -> Path | None:
147
+ """Locate the apothem project root.
148
+
149
+ The resolution order is:
150
+
151
+ 1. ``$CLAUDE_PROJECT_DIR`` if it satisfies the strategy.
152
+ 2. ``$LLM_PROJECT_DIR`` (vendor-neutral alias) if it satisfies the
153
+ strategy.
154
+ 3. ``script_path``'s grandparent, when `script_path`'s immediate
155
+ parent is named ``hooks``.
156
+ 4. Walk from `cwd` upward; return the first ancestor that
157
+ satisfies the strategy.
158
+ 5. ``$HOME/.claude`` if it satisfies the strategy.
159
+
160
+ Returns ``None`` when no candidate satisfies the chosen strategy.
161
+
162
+ Args:
163
+ mode: Which marker set to require.
164
+ script_path: Absolute path of the calling script. When provided
165
+ and located in a ``hooks/`` directory, the parent is tested.
166
+ cwd: Starting directory for the upward walk. Defaults to
167
+ ``Path.cwd()``.
168
+ environ: Environment mapping. Defaults to ``os.environ``.
169
+ home: Home directory. Defaults to ``Path.home()``.
170
+
171
+ Returns:
172
+ Absolute `Path` of the resolved root, or `None` if unresolved.
173
+ """
174
+ strategy = ResolutionStrategy.for_mode(mode)
175
+ env: Mapping[str, str] = os.environ if environ is None else environ
176
+ resolvers: tuple[Callable[[], Path | None], ...] = (
177
+ lambda: _from_env(strategy, env),
178
+ lambda: _from_script(strategy, script_path),
179
+ lambda: _from_walk(strategy, cwd),
180
+ lambda: _from_home(strategy, home),
181
+ )
182
+ for resolver in resolvers:
183
+ result = resolver()
184
+ if result is not None:
185
+ return result
186
+ return None
187
+
188
+
189
+ def default_content_root(root: Path) -> Path:
190
+ """Resolve the harness content root for a apothem project root.
191
+
192
+ In the apothem *source* repository the harness convention surface
193
+ (``hooks/``, ``rules/``, ``commands/``, ...) lives under the
194
+ ``src/apothem/`` package directory; in an installed harness (for
195
+ example ``~/.claude/``) it sits flat at the project root. This
196
+ helper returns ``root / "src" / "apothem"`` when that path carries
197
+ the package marker (a ``hooks/`` subdirectory), otherwise ``root``
198
+ unchanged — so dev validators run bare from either layout without an
199
+ explicit ``--content-root`` flag.
200
+
201
+ Args:
202
+ root: The resolved apothem project root.
203
+
204
+ Returns:
205
+ The directory under which the harness convention surface lives.
206
+ """
207
+ src_layout = root / "src" / "apothem"
208
+ if (src_layout / "hooks").is_dir():
209
+ return src_layout
210
+ return root
211
+
212
+
213
+ def canonical_plans_dir(project_root: Path) -> Path:
214
+ """Return the canonical project-local plans directory for a root.
215
+
216
+ Apothem keeps its working state in a single shared
217
+ ``<project-root>/.apothem`` directory; the sole canonical plans tree is
218
+ ``<project-root>/.apothem/plans``. The legacy ``<project-root>/.plans``
219
+ layout is no longer canonical — operators upgrade an existing ``.plans``
220
+ tree via ``apothem migrate-workspace``.
221
+
222
+ The project-root resolution itself (git-ascent + CWD walk via
223
+ :func:`resolve_project_root`) is unchanged; this helper only names the
224
+ canonical plans location beneath an already-resolved root. The path is
225
+ computed purely; no filesystem access occurs and no directory is created.
226
+
227
+ Args:
228
+ project_root: The resolved project root.
229
+
230
+ Returns:
231
+ ``<project-root>/.apothem/plans`` — the sole canonical plans location.
232
+ """
233
+ return project_root / _APOTHEM_SUBTREE / _PLANS_CHILD
234
+
235
+
236
+ def is_canonical_project_plans_dir(candidate: Path, project_root: Path) -> bool:
237
+ """Return True iff *candidate* is the canonical project-local plans directory.
238
+
239
+ The sole canonical project-local plans directory is
240
+ ``<project-root>/.apothem/plans``. Any other plans-shaped directory — a
241
+ legacy ``<project-root>/.plans``, a stray ``.plans`` nested elsewhere, or an
242
+ ``.apothem/plans`` under a different root such as a harness-config root or
243
+ the user home — is NOT canonical and remains subject to the global-plans
244
+ deny.
245
+
246
+ The comparison is by resolved path so a relative *candidate* and an absolute
247
+ *project_root* compare correctly.
248
+
249
+ Args:
250
+ candidate: The plans-directory path under test.
251
+ project_root: The resolved project root the candidate must sit beneath.
252
+
253
+ Returns:
254
+ True when *candidate* resolves to the canonical project-local plans
255
+ directory, False otherwise.
256
+ """
257
+ try:
258
+ resolved_candidate = candidate.resolve()
259
+ except (OSError, RuntimeError):
260
+ return False
261
+ try:
262
+ return resolved_candidate == canonical_plans_dir(project_root).resolve()
263
+ except (OSError, RuntimeError):
264
+ return False
@@ -0,0 +1,14 @@
1
+ <!-- SPDX-License-Identifier: MIT -->
2
+
3
+ Post-compaction Blind Bootstrap (CM-24 §6.2). Restore working state from durable files; conversation context is now compressed.
4
+
5
+ Read sequence — execute IN ORDER:
6
+
7
+ 1. MEMORY.md (project tier, then global) and every topic file referenced in the project index.
8
+ 2. With an active plan suite: PROGRESS.md Resumption Contract — phase/task status, next action, convention anchors, blockers, watch items, critical-files manifest.
9
+ 3. Each file in the critical-files manifest, in the listed order. Skip any path already covered by a Resumption Contract snapshot to avoid redundant context spend.
10
+ 4. The active phase file (`phases/NN-topic/PHASE.md`) — scope, tasks, inputs, outputs, verification criteria.
11
+ 5. Adopt the convention anchors verbatim from the Resumption Contract; do NOT re-derive them from the preamble.
12
+ 6. Verify alignment. The user's most recent request must be fully addressable from the loaded state. If it references files, decisions, or context NOT in the loaded set, read those files BEFORE proceeding. If the request contradicts loaded state, surface the contradiction to the user — never silently override durable state.
13
+
14
+ No active suite: step 1, then re-read any files referenced in the user's most recent request, then step 6.