@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,656 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """Managed-block + JSON/YAML key-merge and the operator-owned write path."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import contextlib
8
+ import difflib
9
+ import json
10
+ from pathlib import Path
11
+ from string import Template
12
+ from typing import Any
13
+
14
+ import yaml
15
+
16
+ from apothem.lib.harness_materializer import (
17
+ merge_managed_block,
18
+ )
19
+ from apothem.lib.propagation import (
20
+ InstallEntry,
21
+ resolve_target,
22
+ )
23
+
24
+ from .install_driver_backup import write_bytes_safely
25
+ from .install_driver_pathsafety import (
26
+ _allowed_write_root,
27
+ _root_for,
28
+ _validate_target_path,
29
+ )
30
+ from .install_driver_types import (
31
+ AuthorizationRequest,
32
+ AuthorizeFn,
33
+ MaterializationOutcome,
34
+ MaterializationResult,
35
+ _path_text,
36
+ _result,
37
+ _with_detail,
38
+ resolve_source,
39
+ )
40
+
41
+
42
+ def apply_managed_block_anchor(
43
+ target: Path,
44
+ body: str,
45
+ *,
46
+ install_root: Path,
47
+ harness_name: str,
48
+ allowed_root: Path | None = None,
49
+ ) -> MaterializationResult:
50
+ """Fold a profile-projected managed block into an operator-owned anchor.
51
+
52
+ Reads the existing anchor (if any), merges *body* into the canonical Apothem
53
+ sentinel block via :func:`merge_managed_block` (operator prose outside the
54
+ sentinels preserved verbatim), and writes the result atomically with
55
+ backup-before-replace + no-op detection. This is the reusable projection
56
+ write path every instruction-anchor adapter shares: the profile-projection
57
+ seam renders *body*, this helper lands it in the harness's Markdown anchor.
58
+ """
59
+ try:
60
+ existing = target.read_text(encoding="utf-8") if target.exists() else ""
61
+ except OSError:
62
+ existing = ""
63
+ merged = merge_managed_block(existing, body)
64
+ return write_bytes_safely(
65
+ target,
66
+ merged.encode("utf-8"),
67
+ install_root=install_root,
68
+ harness_name=harness_name,
69
+ operation="sentinel_merge",
70
+ allowed_root=allowed_root,
71
+ )
72
+
73
+
74
+ def project_profile_document(
75
+ harness_root: Path,
76
+ *,
77
+ harness_id: str,
78
+ harness_name: str,
79
+ profile: dict[str, Any],
80
+ relative_path: str = "apothem/rules/00-apothem-profile.md",
81
+ ) -> MaterializationResult:
82
+ """Write the profile's projected managed block to a config adapter's anchor.
83
+
84
+ The single-file-config adapters render a native config whose schema accepts
85
+ only documented keys (skills pointers, MCP), so the profile's identity /
86
+ preferences / rules / opted-in behaviors reach the harness through this
87
+ dedicated apothem profile document under the adapter's apothem rules
88
+ directory — the same directory the native config's instructions pointer
89
+ references. Written through the gated managed-block anchor path, so it is
90
+ operator-preserving and idempotent.
91
+ """
92
+ from apothem.lib.profile import coerce_profile
93
+ from apothem.lib.profile_projection import project
94
+
95
+ for_harness = coerce_profile(profile).for_harness(harness_id)
96
+ surfaces = project(for_harness, harness_id)
97
+ return apply_managed_block_anchor(
98
+ harness_root / relative_path,
99
+ surfaces.managed_block_body,
100
+ install_root=harness_root,
101
+ harness_name=harness_name,
102
+ allowed_root=harness_root.parent,
103
+ )
104
+
105
+
106
+ #: Substrings that identify an Apothem-managed hook handler. Covers both the
107
+ #: module-invocation spelling and the installed script-path spelling (the
108
+ #: settings templates point hooks at the materialized ``hooks/dispatch.py``
109
+ #: and ``conformity/gate.py`` scripts under the harness root).
110
+ _APOTHEM_HOOK_MARKERS: tuple[str, ...] = (
111
+ "apothem.hooks.dispatch",
112
+ "apothem.conformity.gate",
113
+ "hooks/dispatch.py",
114
+ "conformity/gate.py",
115
+ )
116
+
117
+
118
+ def _is_apothem_hook(handler: object) -> bool:
119
+ """Return True when a hook handler belongs to Apothem's managed surface."""
120
+ if not isinstance(handler, dict):
121
+ return False
122
+ command = str(handler.get("command", ""))
123
+ args = handler.get("args", [])
124
+ args_text = " ".join(str(arg) for arg in args) if isinstance(args, list) else ""
125
+ haystacks = (command, args_text)
126
+ return any(
127
+ marker in haystack for marker in _APOTHEM_HOOK_MARKERS for haystack in haystacks
128
+ )
129
+
130
+
131
+ def _dedupe_json_list(existing: list[object], incoming: list[object]) -> list[object]:
132
+ """Append incoming JSON values that are not already present."""
133
+ merged = list(existing)
134
+ for item in incoming:
135
+ if item not in merged:
136
+ merged.append(item)
137
+ return merged
138
+
139
+
140
+ def _merge_hook_entry(
141
+ existing_entries: list[object],
142
+ incoming_entry: dict[str, object],
143
+ ) -> dict[str, object]:
144
+ """Merge one incoming hook matcher with existing non-Apothem handlers."""
145
+ matcher = incoming_entry.get("matcher")
146
+ preserved_handlers: list[object] = []
147
+ for entry in existing_entries:
148
+ if not isinstance(entry, dict) or entry.get("matcher") != matcher:
149
+ continue
150
+ handlers = entry.get("hooks", [])
151
+ if not isinstance(handlers, list):
152
+ continue
153
+ preserved_handlers.extend(
154
+ handler for handler in handlers if not _is_apothem_hook(handler)
155
+ )
156
+
157
+ incoming_handlers = incoming_entry.get("hooks", [])
158
+ if not isinstance(incoming_handlers, list):
159
+ incoming_handlers = []
160
+
161
+ merged_entry = dict(incoming_entry)
162
+ merged_entry["hooks"] = preserved_handlers + incoming_handlers
163
+ return merged_entry
164
+
165
+
166
+ def _merge_hooks(
167
+ existing_hooks: dict[str, object],
168
+ incoming_hooks: dict[str, object],
169
+ ) -> dict[str, object]:
170
+ """Merge Claude Code hook settings while replacing Apothem-owned handlers."""
171
+ merged = dict(existing_hooks)
172
+ for event_name, incoming_entries in incoming_hooks.items():
173
+ if not isinstance(incoming_entries, list):
174
+ merged[event_name] = incoming_entries
175
+ continue
176
+ existing_entries_obj = existing_hooks.get(event_name, [])
177
+ existing_entries = (
178
+ existing_entries_obj if isinstance(existing_entries_obj, list) else []
179
+ )
180
+ incoming_matchers = {
181
+ entry.get("matcher")
182
+ for entry in incoming_entries
183
+ if isinstance(entry, dict)
184
+ }
185
+ retained = [
186
+ entry
187
+ for entry in existing_entries
188
+ if not isinstance(entry, dict)
189
+ or entry.get("matcher") not in incoming_matchers
190
+ ]
191
+ for incoming_entry in incoming_entries:
192
+ if isinstance(incoming_entry, dict):
193
+ retained.append(_merge_hook_entry(existing_entries, incoming_entry))
194
+ else:
195
+ retained.append(incoming_entry)
196
+ merged[event_name] = retained
197
+ return merged
198
+
199
+
200
+ def _merge_json_settings(existing: object, incoming: object) -> object:
201
+ """Merge JSON settings while preserving operator-authored keys."""
202
+ return _merge_json_values(existing, incoming, prefer_existing=True)
203
+
204
+
205
+ def _overlay_json_settings(existing: object, incoming: object) -> object:
206
+ """Merge JSON settings while incoming managed values take precedence."""
207
+ return _merge_json_values(existing, incoming, prefer_existing=False)
208
+
209
+
210
+ def _merge_json_values(
211
+ existing: object, incoming: object, *, prefer_existing: bool
212
+ ) -> object:
213
+ """Merge JSON objects, preserving keys absent from the incoming object."""
214
+ if isinstance(existing, dict) and isinstance(incoming, dict):
215
+ merged: dict[str, object] = dict(existing)
216
+ for key, value in incoming.items():
217
+ current = existing.get(key)
218
+ if key == "hooks" and isinstance(current, dict) and isinstance(value, dict):
219
+ merged[key] = _merge_hooks(current, value)
220
+ elif (
221
+ prefer_existing
222
+ and isinstance(current, list)
223
+ and isinstance(value, list)
224
+ ):
225
+ merged[key] = _dedupe_json_list(current, value)
226
+ elif isinstance(current, dict) and isinstance(value, dict):
227
+ merged[key] = _merge_json_values(
228
+ current, value, prefer_existing=prefer_existing
229
+ )
230
+ elif key not in merged:
231
+ merged[key] = value
232
+ elif prefer_existing:
233
+ merged[key] = current
234
+ else:
235
+ merged[key] = value
236
+ return merged
237
+ if isinstance(existing, list) and isinstance(incoming, list):
238
+ if prefer_existing:
239
+ return _dedupe_json_list(existing, incoming)
240
+ return incoming
241
+ return existing
242
+
243
+
244
+ def _merged_json_text(
245
+ target: Path, content: str, *, prefer_existing: bool = True
246
+ ) -> str:
247
+ """Return JSON text merged with an existing JSON target when possible."""
248
+ incoming = json.loads(content)
249
+ try:
250
+ existing = json.loads(target.read_text(encoding="utf-8"))
251
+ except (OSError, json.JSONDecodeError):
252
+ return json.dumps(incoming, indent=2, ensure_ascii=False) + "\n"
253
+ merger = _merge_json_settings if prefer_existing else _overlay_json_settings
254
+ merged = merger(existing, incoming)
255
+ return json.dumps(merged, indent=2, ensure_ascii=False) + "\n"
256
+
257
+
258
+ def write_text_safely(
259
+ target: Path,
260
+ content: str,
261
+ *,
262
+ install_root: Path,
263
+ harness_name: str,
264
+ prefer_existing_json_values: bool = True,
265
+ allowed_root: Path | None = None,
266
+ ) -> MaterializationResult:
267
+ """Write text with backup-before-replace and JSON-preserving merge."""
268
+ target_error = _validate_target_path(
269
+ target,
270
+ allowed_root=allowed_root or install_root,
271
+ operation="write_text",
272
+ )
273
+ if target_error is not None:
274
+ return target_error
275
+ output = content
276
+ if target.suffix.lower() == ".json" and target.exists():
277
+ with contextlib.suppress(json.JSONDecodeError):
278
+ output = _merged_json_text(
279
+ target,
280
+ content,
281
+ prefer_existing=prefer_existing_json_values,
282
+ )
283
+ return write_bytes_safely(
284
+ target,
285
+ output.encode("utf-8"),
286
+ install_root=install_root,
287
+ harness_name=harness_name,
288
+ operation="write_text",
289
+ allowed_root=allowed_root,
290
+ )
291
+
292
+
293
+ def _leading_comment_block(text: str) -> str:
294
+ """Return the leading comment/blank lines of *text* (a managed YAML header).
295
+
296
+ PyYAML drops comments on round-trip, so the incoming config's leading
297
+ ``#`` header is captured here and re-prepended to a merged YAML body. This
298
+ keeps the merge byte-stable: re-merging identical content reproduces the
299
+ same header + body, so install stays idempotent.
300
+ """
301
+ kept: list[str] = []
302
+ for line in text.splitlines(keepends=True):
303
+ stripped = line.lstrip()
304
+ if stripped == "" or stripped.startswith("#"):
305
+ kept.append(line)
306
+ else:
307
+ break
308
+ return "".join(kept)
309
+
310
+
311
+ def _merged_yaml_text(target: Path, content: str, *, prefer_existing: bool) -> str:
312
+ """Return YAML text merged with an existing YAML target when possible.
313
+
314
+ The YAML mirror of :func:`_merged_json_text`: parse both documents, overlay
315
+ operator keys per the shared key-merge, re-dump, and re-prepend the incoming
316
+ managed header comment. Operator keys absent from the incoming managed
317
+ config are preserved; operator *comments* are not retained across a
318
+ merge-over-existing (PyYAML round-trips values, not comments). A clean
319
+ install with no existing target writes *content* verbatim.
320
+ """
321
+ try:
322
+ incoming = yaml.safe_load(content)
323
+ existing = yaml.safe_load(target.read_text(encoding="utf-8"))
324
+ except (OSError, yaml.YAMLError):
325
+ return content
326
+ if not isinstance(incoming, dict) or not isinstance(existing, dict):
327
+ return content
328
+ merger = _merge_json_settings if prefer_existing else _overlay_json_settings
329
+ merged = merger(existing, incoming)
330
+ header = _leading_comment_block(content)
331
+ return header + yaml.safe_dump(merged, sort_keys=False, allow_unicode=True)
332
+
333
+
334
+ def _merge_native_content(target: Path, content: str, *, existed: bool) -> str:
335
+ """Return the prospective merged text for a materializer-rendered config.
336
+
337
+ JSON and YAML targets key-merge with the operator's existing file (incoming
338
+ managed values authoritative, operator-added keys preserved); other suffixes
339
+ and non-existent targets render *content* verbatim.
340
+ """
341
+ if not existed:
342
+ return content
343
+ suffix = target.suffix.lower()
344
+ if suffix == ".json":
345
+ with contextlib.suppress(json.JSONDecodeError, OSError):
346
+ return _merged_json_text(target, content, prefer_existing=False)
347
+ elif suffix in {".yaml", ".yml"}:
348
+ return _merged_yaml_text(target, content, prefer_existing=False)
349
+ return content
350
+
351
+
352
+ def apply_operator_owned_content(
353
+ target: Path,
354
+ content: str,
355
+ *,
356
+ install_root: Path,
357
+ harness_name: str,
358
+ ownership_class: str = "operator-owned",
359
+ allowed_root: Path | None = None,
360
+ authorize: AuthorizeFn | None = None,
361
+ ) -> MaterializationResult:
362
+ """Write materializer-rendered content to an operator-owned native config.
363
+
364
+ The content-based sibling of :func:`_apply_operator_owned_file` (which reads
365
+ from a source file): the same gated apply path for adapters whose config is
366
+ rendered dynamically from the profile. Computes a suffix-aware
367
+ key-preserving merge (JSON / YAML), records a unified diff on the result,
368
+ consults *authorize* on a non-additive overwrite (declining leaves the
369
+ operator file untouched), then writes atomically with backup-before-replace
370
+ and no-op detection.
371
+ """
372
+ write_allowed = allowed_root or install_root
373
+ target_error = _validate_target_path(
374
+ target, allowed_root=write_allowed, operation="write_text"
375
+ )
376
+ if target_error is not None:
377
+ return target_error
378
+ existed = target.exists()
379
+ before = ""
380
+ if existed:
381
+ with contextlib.suppress(OSError):
382
+ before = target.read_text(encoding="utf-8")
383
+ merged = _merge_native_content(target, content, existed=existed)
384
+ diff = _unified_diff(before, merged, target)
385
+ detail: dict[str, str] = {"ownership_class": ownership_class}
386
+ if diff:
387
+ detail["diff"] = diff
388
+ if existed and before != merged:
389
+ detail["destructive_gate"] = "required"
390
+ if authorize is not None and not authorize(
391
+ AuthorizationRequest(
392
+ harness=harness_name,
393
+ path=_path_text(target),
394
+ operation="write_text",
395
+ ownership_class=ownership_class,
396
+ diff=diff,
397
+ )
398
+ ):
399
+ return _with_detail(
400
+ _result(
401
+ "skipped",
402
+ "write_text",
403
+ target,
404
+ "operator declined the native-config change",
405
+ ),
406
+ detail,
407
+ )
408
+ result = write_bytes_safely(
409
+ target,
410
+ merged.encode("utf-8"),
411
+ install_root=install_root,
412
+ harness_name=harness_name,
413
+ operation="write_text",
414
+ allowed_root=allowed_root,
415
+ )
416
+ return _with_detail(result, detail)
417
+
418
+
419
+ def _unified_diff(before: str, after: str, target: Path) -> str:
420
+ """Return a unified diff from *before* to *after* for *target*."""
421
+ return "".join(
422
+ difflib.unified_diff(
423
+ before.splitlines(keepends=True),
424
+ after.splitlines(keepends=True),
425
+ fromfile=f"a/{target.name}",
426
+ tofile=f"b/{target.name}",
427
+ )
428
+ )
429
+
430
+
431
+ def render_content_tokens(
432
+ content: str,
433
+ *,
434
+ harness_root: Path | None,
435
+ project_root: Path | None = None,
436
+ ) -> str:
437
+ """Substitute ``${HARNESS_ROOT}`` / ``${PROJECT_ROOT}`` inside template text.
438
+
439
+ The content-side mirror of :func:`apothem.lib.propagation.resolve_target`:
440
+ target paths resolve placeholders at the manifest layer, and this helper
441
+ resolves the same placeholders inside the template's *body* so a template
442
+ can embed install-time absolute paths — the hook entries in
443
+ ``settings.json`` and ``hooks.json`` point at the dispatcher's on-disk
444
+ location this way. Substituted paths use forward-slash form so the result
445
+ stays valid inside JSON string literals on every platform. An absent root
446
+ leaves its placeholder untouched, matching the path-resolution helper.
447
+ """
448
+ if "${" not in content:
449
+ return content
450
+ mapping: dict[str, str] = {}
451
+ if harness_root is not None:
452
+ mapping["HARNESS_ROOT"] = harness_root.resolve().as_posix()
453
+ if project_root is not None:
454
+ mapping["PROJECT_ROOT"] = project_root.resolve().as_posix()
455
+ if not mapping:
456
+ return content
457
+ return Template(content).safe_substitute(mapping)
458
+
459
+
460
+ def _operator_owned_merge_text(
461
+ entry: InstallEntry, target: Path, content: str, *, existed: bool
462
+ ) -> str:
463
+ """Return the prospective merged text for an operator-owned target.
464
+
465
+ ``sentinel_merge`` entries fold *content* into the operator anchor as a
466
+ sentinel-delimited managed block, preserving operator prose outside the
467
+ block. ``write_text`` entries on an existing JSON target run the JSON
468
+ merge with the incoming template authoritative: template-carried keys
469
+ update in place so fixes ship to existing installs, while operator-added
470
+ keys absent from the template are preserved. The backup-before-replace
471
+ and destructive-authorization gate still guard the write. A non-existent
472
+ target merges to *content* verbatim.
473
+ """
474
+ if entry.mode == "sentinel_merge":
475
+ existing = ""
476
+ if existed:
477
+ with contextlib.suppress(OSError):
478
+ existing = target.read_text(encoding="utf-8")
479
+ return merge_managed_block(existing, content)
480
+ if target.suffix.lower() == ".json" and existed:
481
+ with contextlib.suppress(json.JSONDecodeError, OSError):
482
+ return _merged_json_text(target, content, prefer_existing=False)
483
+ return content
484
+
485
+
486
+ def _operator_owned_preview(
487
+ entry: InstallEntry,
488
+ *,
489
+ harness_root: Path | None,
490
+ project_root: Path | None,
491
+ profile_body: str | None = None,
492
+ ) -> tuple[Path, MaterializationOutcome, str, bool] | None:
493
+ """Return (target, outcome, unified-diff, gate-required) for an entry.
494
+
495
+ Reads the source and the current target without writing, then computes the
496
+ prospective merge exactly as :func:`_apply_operator_owned_file` would — the
497
+ projected *profile_body* is folded into a ``sentinel_merge`` anchor so the
498
+ preview reflects the same managed block the real write lands — and
499
+ classifies the no-write outcome against the current on-disk bytes:
500
+
501
+ - ``created`` when the target does not yet exist,
502
+ - ``unchanged`` when the prospective merge reproduces the current bytes,
503
+ - ``updated`` when the prospective merge changes existing bytes.
504
+
505
+ The unified diff and the destructive-gate flag (``True`` only for an
506
+ ``updated`` outcome, i.e. an overwrite of differing operator content)
507
+ accompany the outcome so a dry-run preview can render the same diff the
508
+ gated write would show. ``None`` when the source file is absent (nothing to
509
+ preview — the plan validator already errors on a missing source, so this is
510
+ a defensive fallback).
511
+ """
512
+ src = resolve_source(entry.source)
513
+ if not src.is_file():
514
+ return None
515
+ target = resolve_target(
516
+ entry.target, harness_root=harness_root, project_root=project_root
517
+ )
518
+ content = render_content_tokens(
519
+ src.read_text(encoding="utf-8"),
520
+ harness_root=harness_root,
521
+ project_root=project_root,
522
+ )
523
+ if entry.mode == "sentinel_merge" and profile_body:
524
+ content = f"{content.rstrip()}\n\n{profile_body}"
525
+ existed = target.exists()
526
+ before = ""
527
+ if existed:
528
+ with contextlib.suppress(OSError):
529
+ before = target.read_text(encoding="utf-8")
530
+ after = _operator_owned_merge_text(entry, target, content, existed=existed)
531
+ diff = _unified_diff(before, after, target)
532
+ gate_required = existed and before != after
533
+ outcome: MaterializationOutcome = (
534
+ "created" if not existed else ("updated" if gate_required else "unchanged")
535
+ )
536
+ return target, outcome, diff, gate_required
537
+
538
+
539
+ def _apply_operator_owned_file(
540
+ entry: InstallEntry,
541
+ *,
542
+ target: Path,
543
+ src: Path,
544
+ root: Path,
545
+ harness_name: str,
546
+ allowed_root: Path,
547
+ authorize: AuthorizeFn | None,
548
+ harness_root: Path | None = None,
549
+ project_root: Path | None = None,
550
+ profile_body: str | None = None,
551
+ ) -> list[MaterializationResult]:
552
+ """Merge-write an operator-owned file with backup, diff, and gate.
553
+
554
+ The Apothem-managed content (a sentinel block for Markdown anchors, the
555
+ key-merged object for JSON config) is folded into the operator's file so
556
+ operator content is preserved. Path tokens inside the template body are
557
+ rendered first per ``render_content_tokens``. For ``sentinel_merge`` anchors,
558
+ *profile_body* (the projected shared-profile managed block) is appended to
559
+ the template governance so the anchor's managed block carries both. A
560
+ unified diff is recorded on the result. When the change is a non-additive
561
+ overwrite of an existing file and an *authorize* gate is supplied, the gate
562
+ is consulted per target; declining skips the write and leaves the operator
563
+ file untouched.
564
+ """
565
+ content = render_content_tokens(
566
+ src.read_text(encoding="utf-8"),
567
+ harness_root=harness_root,
568
+ project_root=project_root,
569
+ )
570
+ if entry.mode == "sentinel_merge" and profile_body:
571
+ content = f"{content.rstrip()}\n\n{profile_body}"
572
+ existed = target.exists()
573
+ before = ""
574
+ if existed:
575
+ with contextlib.suppress(OSError):
576
+ before = target.read_text(encoding="utf-8")
577
+ merged = _operator_owned_merge_text(entry, target, content, existed=existed)
578
+ diff = _unified_diff(before, merged, target)
579
+ detail: dict[str, str] = {"ownership_class": entry.ownership_class}
580
+ if diff:
581
+ detail["diff"] = diff
582
+ if existed and before != merged:
583
+ detail["destructive_gate"] = "required"
584
+ if authorize is not None and not authorize(
585
+ AuthorizationRequest(
586
+ harness=harness_name,
587
+ path=_path_text(target),
588
+ operation=entry.mode,
589
+ ownership_class=entry.ownership_class,
590
+ diff=diff,
591
+ )
592
+ ):
593
+ return [
594
+ _with_detail(
595
+ _result(
596
+ "skipped",
597
+ entry.mode,
598
+ target,
599
+ "operator declined the managed-block change",
600
+ source=src,
601
+ ),
602
+ detail,
603
+ )
604
+ ]
605
+ result = write_bytes_safely(
606
+ target,
607
+ merged.encode("utf-8"),
608
+ install_root=root,
609
+ harness_name=harness_name,
610
+ operation=entry.mode,
611
+ source=src,
612
+ allowed_root=allowed_root,
613
+ )
614
+ return [_with_detail(result, detail)]
615
+
616
+
617
+ def apply_sentinel_merge(
618
+ entry: InstallEntry,
619
+ *,
620
+ harness_root: Path | None = None,
621
+ project_root: Path | None = None,
622
+ harness_name: str = "manual",
623
+ authorize: AuthorizeFn | None = None,
624
+ profile_body: str | None = None,
625
+ ) -> list[MaterializationResult]:
626
+ """Apply a ``sentinel_merge`` entry: fold a managed block into an anchor.
627
+
628
+ When *profile_body* is supplied (the projected shared profile), it is folded
629
+ into the anchor's managed block alongside the template governance.
630
+ """
631
+ target = resolve_target(
632
+ entry.target, harness_root=harness_root, project_root=project_root
633
+ )
634
+ src = resolve_source(entry.source)
635
+ if not src.is_file():
636
+ return [
637
+ _result(
638
+ "skipped",
639
+ "sentinel_merge",
640
+ target,
641
+ "source file does not exist",
642
+ source=src,
643
+ )
644
+ ]
645
+ return _apply_operator_owned_file(
646
+ entry,
647
+ target=target,
648
+ src=src,
649
+ root=_root_for(harness_root, project_root),
650
+ harness_name=harness_name,
651
+ allowed_root=_allowed_write_root(harness_root, project_root),
652
+ authorize=authorize,
653
+ harness_root=harness_root,
654
+ project_root=project_root,
655
+ profile_body=profile_body,
656
+ )