@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.
- package/CHANGELOG.md +60 -0
- package/LICENSE +21 -0
- package/LICENSES/MIT.txt +18 -0
- package/LICENSES/PSF-2.0.txt +47 -0
- package/README.md +549 -0
- package/bin/README.md +37 -0
- package/bin/apothem.mjs +78 -0
- package/package.json +75 -0
- package/pyproject.toml +347 -0
- package/src/apothem/README.md +52 -0
- package/src/apothem/__init__.py +66 -0
- package/src/apothem/__main__.py +28 -0
- package/src/apothem/_vendor/.keep +0 -0
- package/src/apothem/_vendor/__init__.py +25 -0
- package/src/apothem/_vendor/attr/__init__.py +104 -0
- package/src/apothem/_vendor/attr/__init__.pyi +389 -0
- package/src/apothem/_vendor/attr/_cmp.py +160 -0
- package/src/apothem/_vendor/attr/_cmp.pyi +13 -0
- package/src/apothem/_vendor/attr/_compat.py +99 -0
- package/src/apothem/_vendor/attr/_config.py +31 -0
- package/src/apothem/_vendor/attr/_funcs.py +497 -0
- package/src/apothem/_vendor/attr/_make.py +3406 -0
- package/src/apothem/_vendor/attr/_next_gen.py +674 -0
- package/src/apothem/_vendor/attr/_typing_compat.pyi +15 -0
- package/src/apothem/_vendor/attr/_version_info.py +89 -0
- package/src/apothem/_vendor/attr/_version_info.pyi +9 -0
- package/src/apothem/_vendor/attr/converters.py +162 -0
- package/src/apothem/_vendor/attr/converters.pyi +19 -0
- package/src/apothem/_vendor/attr/exceptions.py +95 -0
- package/src/apothem/_vendor/attr/exceptions.pyi +17 -0
- package/src/apothem/_vendor/attr/filters.py +72 -0
- package/src/apothem/_vendor/attr/filters.pyi +6 -0
- package/src/apothem/_vendor/attr/py.typed +0 -0
- package/src/apothem/_vendor/attr/setters.py +79 -0
- package/src/apothem/_vendor/attr/setters.pyi +20 -0
- package/src/apothem/_vendor/attr/validators.py +750 -0
- package/src/apothem/_vendor/attr/validators.pyi +140 -0
- package/src/apothem/_vendor/attr.LICENSE +21 -0
- package/src/apothem/_vendor/attrs/__init__.py +72 -0
- package/src/apothem/_vendor/attrs/__init__.pyi +314 -0
- package/src/apothem/_vendor/attrs/converters.py +3 -0
- package/src/apothem/_vendor/attrs/exceptions.py +3 -0
- package/src/apothem/_vendor/attrs/filters.py +3 -0
- package/src/apothem/_vendor/attrs/py.typed +0 -0
- package/src/apothem/_vendor/attrs/setters.py +3 -0
- package/src/apothem/_vendor/attrs/validators.py +3 -0
- package/src/apothem/_vendor/attrs.LICENSE +21 -0
- package/src/apothem/_vendor/jsonschema/__init__.py +120 -0
- package/src/apothem/_vendor/jsonschema/__main__.py +6 -0
- package/src/apothem/_vendor/jsonschema/_format.py +546 -0
- package/src/apothem/_vendor/jsonschema/_keywords.py +449 -0
- package/src/apothem/_vendor/jsonschema/_legacy_keywords.py +449 -0
- package/src/apothem/_vendor/jsonschema/_types.py +204 -0
- package/src/apothem/_vendor/jsonschema/_typing.py +29 -0
- package/src/apothem/_vendor/jsonschema/_utils.py +355 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/__init__.py +5 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/const_vs_enum.py +30 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/contains.py +28 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/import_benchmark.py +31 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/issue232/issue.json +2653 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/issue232.py +25 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/json_schema_test_suite.py +12 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/nested_schemas.py +56 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/subcomponents.py +42 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/unused_registry.py +35 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/useless_applicator_schemas.py +106 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/useless_keywords.py +32 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/validator_creation.py +14 -0
- package/src/apothem/_vendor/jsonschema/cli.py +292 -0
- package/src/apothem/_vendor/jsonschema/exceptions.py +490 -0
- package/src/apothem/_vendor/jsonschema/protocols.py +230 -0
- package/src/apothem/_vendor/jsonschema/validators.py +1410 -0
- package/src/apothem/_vendor/jsonschema.LICENSE +19 -0
- package/src/apothem/_vendor/jsonschema_specifications/__init__.py +12 -0
- package/src/apothem/_vendor/jsonschema_specifications/_core.py +38 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/metaschema.json +42 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/applicator +56 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/content +17 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/core +57 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/format +14 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data +37 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/validation +98 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/metaschema.json +58 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/applicator +48 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/content +17 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/core +51 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation +14 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion +14 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data +37 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated +15 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/validation +98 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft3/metaschema.json +172 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft4/metaschema.json +149 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft6/metaschema.json +153 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft7/metaschema.json +166 -0
- package/src/apothem/_vendor/jsonschema_specifications.LICENSE +19 -0
- package/src/apothem/_vendor/referencing/__init__.py +7 -0
- package/src/apothem/_vendor/referencing/_attrs.py +31 -0
- package/src/apothem/_vendor/referencing/_attrs.pyi +21 -0
- package/src/apothem/_vendor/referencing/_core.py +739 -0
- package/src/apothem/_vendor/referencing/exceptions.py +165 -0
- package/src/apothem/_vendor/referencing/jsonschema.py +642 -0
- package/src/apothem/_vendor/referencing/py.typed +0 -0
- package/src/apothem/_vendor/referencing/retrieval.py +94 -0
- package/src/apothem/_vendor/referencing/typing.py +61 -0
- package/src/apothem/_vendor/referencing.LICENSE +19 -0
- package/src/apothem/_vendor/rpds/__init__.py +251 -0
- package/src/apothem/_vendor/typing_extensions.LICENSE +279 -0
- package/src/apothem/_vendor/typing_extensions.py +4317 -0
- package/src/apothem/_vendor/vendor.txt +22 -0
- package/src/apothem/_vendor/yaml/__init__.py +389 -0
- package/src/apothem/_vendor/yaml/composer.py +138 -0
- package/src/apothem/_vendor/yaml/constructor.py +748 -0
- package/src/apothem/_vendor/yaml/cyaml.py +100 -0
- package/src/apothem/_vendor/yaml/dumper.py +61 -0
- package/src/apothem/_vendor/yaml/emitter.py +1137 -0
- package/src/apothem/_vendor/yaml/error.py +74 -0
- package/src/apothem/_vendor/yaml/events.py +85 -0
- package/src/apothem/_vendor/yaml/loader.py +63 -0
- package/src/apothem/_vendor/yaml/nodes.py +48 -0
- package/src/apothem/_vendor/yaml/parser.py +588 -0
- package/src/apothem/_vendor/yaml/reader.py +185 -0
- package/src/apothem/_vendor/yaml/representer.py +388 -0
- package/src/apothem/_vendor/yaml/resolver.py +226 -0
- package/src/apothem/_vendor/yaml/scanner.py +1435 -0
- package/src/apothem/_vendor/yaml/serializer.py +110 -0
- package/src/apothem/_vendor/yaml/tokens.py +103 -0
- package/src/apothem/_vendor/yaml.LICENSE +20 -0
- package/src/apothem/agents/README.md +60 -0
- package/src/apothem/agents/codebase-explorer.md +91 -0
- package/src/apothem/agents/convention-auditor.md +93 -0
- package/src/apothem/agents/dependency-auditor.md +97 -0
- package/src/apothem/agents/fact-checker.md +84 -0
- package/src/apothem/agents/mcp-builder.md +86 -0
- package/src/apothem/agents/memory-auditor.md +93 -0
- package/src/apothem/agents/prompt-evaluator.md +87 -0
- package/src/apothem/agents/quality-gate.md +103 -0
- package/src/apothem/agents/refactor-surgeon.md +74 -0
- package/src/apothem/agents/research-scout.md +73 -0
- package/src/apothem/agents/security-scanner.md +83 -0
- package/src/apothem/agents/test-runner.md +84 -0
- package/src/apothem/audit/README.md +73 -0
- package/src/apothem/audit/_scan_lib.py +182 -0
- package/src/apothem/audit/analyze_graph.py +260 -0
- package/src/apothem/audit/build_capability_graph.py +607 -0
- package/src/apothem/audit/build_inventory.py +657 -0
- package/src/apothem/audit/build_plans_provenance.py +997 -0
- package/src/apothem/audit/check_links.py +389 -0
- package/src/apothem/audit/classify_artifacts.py +381 -0
- package/src/apothem/audit/deprecated-tokens.txt +10 -0
- package/src/apothem/audit/execute_plans_migration.py +491 -0
- package/src/apothem/audit/known-projects.txt +15 -0
- package/src/apothem/audit/render_capability_index.py +467 -0
- package/src/apothem/audit/render_inventory.py +405 -0
- package/src/apothem/audit/scan_ai_surfaces.py +1125 -0
- package/src/apothem/audit/scan_ai_surfaces_coarse.py +261 -0
- package/src/apothem/audit/scan_drift_features.py +143 -0
- package/src/apothem/audit/scan_frontmatter.py +293 -0
- package/src/apothem/audit/scan_header_coverage.py +1134 -0
- package/src/apothem/audit/scan_plan_leakage.py +540 -0
- package/src/apothem/audit/scan_plans_discipline.py +188 -0
- package/src/apothem/audit/scan_secrets_pii.py +245 -0
- package/src/apothem/audit/scan_stale_tokens.py +296 -0
- package/src/apothem/audit/synthesize_drift.py +205 -0
- package/src/apothem/benchmarks/README.md +33 -0
- package/src/apothem/benchmarks/__init__.py +3 -0
- package/src/apothem/benchmarks/bench_agents.py +63 -0
- package/src/apothem/benchmarks/bench_hooks.py +93 -0
- package/src/apothem/benchmarks/bench_install.py +58 -0
- package/src/apothem/benchmarks/bench_tests.py +93 -0
- package/src/apothem/benchmarks/bench_validate_ecosystem.py +84 -0
- package/src/apothem/cli/README.md +33 -0
- package/src/apothem/cli/__init__.py +229 -0
- package/src/apothem/cli/_cmd_completion.py +88 -0
- package/src/apothem/cli/_cmd_diff.py +181 -0
- package/src/apothem/cli/_cmd_doctor.py +143 -0
- package/src/apothem/cli/_cmd_harnesses.py +167 -0
- package/src/apothem/cli/_cmd_install.py +327 -0
- package/src/apothem/cli/_cmd_migrate_workspace.py +143 -0
- package/src/apothem/cli/_cmd_profile.py +341 -0
- package/src/apothem/cli/_cmd_status.py +180 -0
- package/src/apothem/cli/_cmd_uninstall.py +215 -0
- package/src/apothem/cli/_cmd_update.py +397 -0
- package/src/apothem/cli/_cmd_verify.py +194 -0
- package/src/apothem/cli/_common_flags.py +90 -0
- package/src/apothem/cli/_epilogs.py +296 -0
- package/src/apothem/cli/_helpers.py +857 -0
- package/src/apothem/cli/_json_formatter.py +21 -0
- package/src/apothem/cli/_materialize.py +376 -0
- package/src/apothem/cli/completions/apothem.bash +30 -0
- package/src/apothem/cli/completions/apothem.fish +19 -0
- package/src/apothem/cli/completions/apothem.ps1 +27 -0
- package/src/apothem/cli/completions/apothem.zsh +42 -0
- package/src/apothem/cli/reference_export.py +126 -0
- package/src/apothem/commands/README.md +125 -0
- package/src/apothem/commands/a11y-audit.md +203 -0
- package/src/apothem/commands/architecture-review.md +194 -0
- package/src/apothem/commands/audit.md +165 -0
- package/src/apothem/commands/code-audit.md +218 -0
- package/src/apothem/commands/code-review.md +193 -0
- package/src/apothem/commands/dependency-audit.md +209 -0
- package/src/apothem/commands/docs-review.md +199 -0
- package/src/apothem/commands/elevate.md +285 -0
- package/src/apothem/commands/eval.md +149 -0
- package/src/apothem/commands/fortress.md +172 -0
- package/src/apothem/commands/freshify.md +168 -0
- package/src/apothem/commands/github-deploy-fresh.md +178 -0
- package/src/apothem/commands/github-deploy-next.md +167 -0
- package/src/apothem/commands/perf-audit.md +198 -0
- package/src/apothem/commands/plan-amend.md +104 -0
- package/src/apothem/commands/plan-audit.md +127 -0
- package/src/apothem/commands/plan-design.md +257 -0
- package/src/apothem/commands/plan-execute.md +495 -0
- package/src/apothem/commands/plan-generate.md +351 -0
- package/src/apothem/commands/plan-review.md +555 -0
- package/src/apothem/commands/plan-spec.md +359 -0
- package/src/apothem/commands/plan-status.md +222 -0
- package/src/apothem/commands/plan.md +173 -0
- package/src/apothem/commands/projectify.md +142 -0
- package/src/apothem/commands/release-readiness.md +142 -0
- package/src/apothem/commands/research-analysis.md +241 -0
- package/src/apothem/commands/research-design.md +231 -0
- package/src/apothem/commands/research-disseminate.md +225 -0
- package/src/apothem/commands/research-experiment.md +232 -0
- package/src/apothem/commands/research-ideate.md +213 -0
- package/src/apothem/commands/research-paper.md +252 -0
- package/src/apothem/commands/research-proposal.md +220 -0
- package/src/apothem/commands/research-publish.md +255 -0
- package/src/apothem/commands/research-review.md +251 -0
- package/src/apothem/commands/research-sources.md +266 -0
- package/src/apothem/commands/research-spec.md +255 -0
- package/src/apothem/commands/research-synthesis.md +233 -0
- package/src/apothem/commands/research-theory.md +218 -0
- package/src/apothem/commands/research.md +181 -0
- package/src/apothem/commands/security-audit.md +196 -0
- package/src/apothem/commands/supply-chain-audit.md +192 -0
- package/src/apothem/commands/test-suite.md +146 -0
- package/src/apothem/commands/threat-model-audit.md +199 -0
- package/src/apothem/commands/ux-review.md +202 -0
- package/src/apothem/commands/workflow.md +162 -0
- package/src/apothem/conformity/README.md +173 -0
- package/src/apothem/conformity/__init__.py +1 -0
- package/src/apothem/conformity/_grep_base.py +93 -0
- package/src/apothem/conformity/agent_capability_grep.py +306 -0
- package/src/apothem/conformity/agents_md_coverage_grep.py +382 -0
- package/src/apothem/conformity/agnosticism_grep.py +311 -0
- package/src/apothem/conformity/always_on_budget_grep.py +318 -0
- package/src/apothem/conformity/bare_except_grep.py +115 -0
- package/src/apothem/conformity/binding_reciprocity_grep.py +151 -0
- package/src/apothem/conformity/brand_mark_grep.py +272 -0
- package/src/apothem/conformity/commented_out_code_grep.py +176 -0
- package/src/apothem/conformity/completion_claim_grep.py +169 -0
- package/src/apothem/conformity/conventional_commit_grep.py +319 -0
- package/src/apothem/conformity/copilot_instructions_presence_grep.py +324 -0
- package/src/apothem/conformity/cross_platform_matrix_grep.py +297 -0
- package/src/apothem/conformity/determinism_grep.py +306 -0
- package/src/apothem/conformity/diagram_staleness_grep.py +154 -0
- package/src/apothem/conformity/dynamism_grep.py +284 -0
- package/src/apothem/conformity/editorconfig_presence_grep.py +281 -0
- package/src/apothem/conformity/file_header_grep.py +502 -0
- package/src/apothem/conformity/freshness_token_grep.py +233 -0
- package/src/apothem/conformity/frontmatter_grep.py +274 -0
- package/src/apothem/conformity/frontmatter_value_grep.py +386 -0
- package/src/apothem/conformity/gate.py +1386 -0
- package/src/apothem/conformity/gitattributes_presence_grep.py +238 -0
- package/src/apothem/conformity/harden_runner_grep.py +320 -0
- package/src/apothem/conformity/hedging_grep.py +129 -0
- package/src/apothem/conformity/license_author_consistency_grep.py +204 -0
- package/src/apothem/conformity/link_check.py +327 -0
- package/src/apothem/conformity/magic_number_grep.py +182 -0
- package/src/apothem/conformity/multi_surface_coherence_grep.py +620 -0
- package/src/apothem/conformity/naming_grep.py +224 -0
- package/src/apothem/conformity/no_global_plans_grep.py +339 -0
- package/src/apothem/conformity/no_toplevel_docs_grep.py +120 -0
- package/src/apothem/conformity/oidc_trusted_publishing_grep.py +291 -0
- package/src/apothem/conformity/option_annotation_grep.py +352 -0
- package/src/apothem/conformity/orphan_output_grep.py +206 -0
- package/src/apothem/conformity/permissions_minimum_scope_grep.py +299 -0
- package/src/apothem/conformity/plain_language_grep.py +559 -0
- package/src/apothem/conformity/plan_next_step_consistency_grep.py +450 -0
- package/src/apothem/conformity/plan_suite_structure_grep.py +534 -0
- package/src/apothem/conformity/plans_discipline_language_grep.py +245 -0
- package/src/apothem/conformity/production_ready_pr_grep.py +200 -0
- package/src/apothem/conformity/recommend_next_step_grep.py +250 -0
- package/src/apothem/conformity/redundancy_grep.py +401 -0
- package/src/apothem/conformity/reference_token_grep.py +230 -0
- package/src/apothem/conformity/registry_capability_consistency_grep.py +368 -0
- package/src/apothem/conformity/secret_leak_grep.py +193 -0
- package/src/apothem/conformity/semver_stability_grep.py +358 -0
- package/src/apothem/conformity/smoke_install_grep.py +194 -0
- package/src/apothem/conformity/static_version_grep.py +284 -0
- package/src/apothem/conformity/token_efficiency_grep.py +185 -0
- package/src/apothem/conformity/unpinned_action_grep.py +115 -0
- package/src/apothem/conformity/user_confirm_grep.py +74 -0
- package/src/apothem/conformity/workflow_concurrency_grep.py +283 -0
- package/src/apothem/harnesses/README.md +63 -0
- package/src/apothem/harnesses/__init__.py +16 -0
- package/src/apothem/harnesses/_shared/README.md +36 -0
- package/src/apothem/harnesses/_shared/__init__.py +12 -0
- package/src/apothem/harnesses/_shared/install_driver.py +281 -0
- package/src/apothem/harnesses/_shared/install_driver_apply.py +612 -0
- package/src/apothem/harnesses/_shared/install_driver_backup.py +535 -0
- package/src/apothem/harnesses/_shared/install_driver_converters.py +310 -0
- package/src/apothem/harnesses/_shared/install_driver_lifecycle.py +495 -0
- package/src/apothem/harnesses/_shared/install_driver_materialize.py +675 -0
- package/src/apothem/harnesses/_shared/install_driver_merge.py +656 -0
- package/src/apothem/harnesses/_shared/install_driver_pathsafety.py +137 -0
- package/src/apothem/harnesses/_shared/install_driver_planvalidation.py +240 -0
- package/src/apothem/harnesses/_shared/install_driver_removal.py +366 -0
- package/src/apothem/harnesses/_shared/install_driver_treeops.py +248 -0
- package/src/apothem/harnesses/_shared/install_driver_types.py +330 -0
- package/src/apothem/harnesses/_shared/wrapper_factories.py +448 -0
- package/src/apothem/harnesses/antigravity/STANDARD-CONVENTION-PIN.md +91 -0
- package/src/apothem/harnesses/antigravity/__init__.py +70 -0
- package/src/apothem/harnesses/antigravity/capabilities.yml +40 -0
- package/src/apothem/harnesses/antigravity/install.py +63 -0
- package/src/apothem/harnesses/antigravity/templates/GEMINI.md +40 -0
- package/src/apothem/harnesses/antigravity/templates/plugin.json +5 -0
- package/src/apothem/harnesses/antigravity/uninstall.py +22 -0
- package/src/apothem/harnesses/antigravity/update.py +10 -0
- package/src/apothem/harnesses/antigravity/verify.py +11 -0
- package/src/apothem/harnesses/claude_code/STANDARD-CONVENTION-PIN.md +65 -0
- package/src/apothem/harnesses/claude_code/__init__.py +107 -0
- package/src/apothem/harnesses/claude_code/capabilities.yml +42 -0
- package/src/apothem/harnesses/claude_code/install.py +147 -0
- package/src/apothem/harnesses/claude_code/templates/settings.json +351 -0
- package/src/apothem/harnesses/claude_code/uninstall.py +23 -0
- package/src/apothem/harnesses/claude_code/update.py +10 -0
- package/src/apothem/harnesses/claude_code/verify.py +11 -0
- package/src/apothem/harnesses/codebuddy/STANDARD-CONVENTION-PIN.md +74 -0
- package/src/apothem/harnesses/codebuddy/__init__.py +49 -0
- package/src/apothem/harnesses/codebuddy/capabilities.yml +34 -0
- package/src/apothem/harnesses/codebuddy/install.py +40 -0
- package/src/apothem/harnesses/codebuddy/templates/apothem-rules.md +37 -0
- package/src/apothem/harnesses/codebuddy/uninstall.py +25 -0
- package/src/apothem/harnesses/codebuddy/update.py +10 -0
- package/src/apothem/harnesses/codebuddy/verify.py +11 -0
- package/src/apothem/harnesses/codex/STANDARD-CONVENTION-PIN.md +79 -0
- package/src/apothem/harnesses/codex/__init__.py +72 -0
- package/src/apothem/harnesses/codex/capabilities.yml +40 -0
- package/src/apothem/harnesses/codex/install.py +69 -0
- package/src/apothem/harnesses/codex/templates/AGENTS.md +40 -0
- package/src/apothem/harnesses/codex/templates/hooks.json +127 -0
- package/src/apothem/harnesses/codex/uninstall.py +23 -0
- package/src/apothem/harnesses/codex/update.py +10 -0
- package/src/apothem/harnesses/codex/verify.py +11 -0
- package/src/apothem/harnesses/cursor/STANDARD-CONVENTION-PIN.md +79 -0
- package/src/apothem/harnesses/cursor/__init__.py +48 -0
- package/src/apothem/harnesses/cursor/capabilities.yml +42 -0
- package/src/apothem/harnesses/cursor/install.py +38 -0
- package/src/apothem/harnesses/cursor/templates/apothem-rules.mdc +40 -0
- package/src/apothem/harnesses/cursor/uninstall.py +25 -0
- package/src/apothem/harnesses/cursor/update.py +10 -0
- package/src/apothem/harnesses/cursor/verify.py +11 -0
- package/src/apothem/harnesses/gemini_cli/STANDARD-CONVENTION-PIN.md +102 -0
- package/src/apothem/harnesses/gemini_cli/__init__.py +52 -0
- package/src/apothem/harnesses/gemini_cli/capabilities.yml +43 -0
- package/src/apothem/harnesses/gemini_cli/install.py +43 -0
- package/src/apothem/harnesses/gemini_cli/templates/GEMINI.md +38 -0
- package/src/apothem/harnesses/gemini_cli/uninstall.py +25 -0
- package/src/apothem/harnesses/gemini_cli/update.py +10 -0
- package/src/apothem/harnesses/gemini_cli/verify.py +11 -0
- package/src/apothem/harnesses/github_copilot/STANDARD-CONVENTION-PIN.md +84 -0
- package/src/apothem/harnesses/github_copilot/__init__.py +47 -0
- package/src/apothem/harnesses/github_copilot/capabilities.yml +42 -0
- package/src/apothem/harnesses/github_copilot/install.py +40 -0
- package/src/apothem/harnesses/github_copilot/templates/copilot-instructions.md +33 -0
- package/src/apothem/harnesses/github_copilot/uninstall.py +25 -0
- package/src/apothem/harnesses/github_copilot/update.py +10 -0
- package/src/apothem/harnesses/github_copilot/verify.py +11 -0
- package/src/apothem/harnesses/glm/STANDARD-CONVENTION-PIN.md +77 -0
- package/src/apothem/harnesses/glm/__init__.py +56 -0
- package/src/apothem/harnesses/glm/capabilities.yml +33 -0
- package/src/apothem/harnesses/glm/install.py +45 -0
- package/src/apothem/harnesses/glm/templates/glm.toml +58 -0
- package/src/apothem/harnesses/glm/uninstall.py +25 -0
- package/src/apothem/harnesses/glm/update.py +10 -0
- package/src/apothem/harnesses/glm/verify.py +11 -0
- package/src/apothem/harnesses/hermes/STANDARD-CONVENTION-PIN.md +57 -0
- package/src/apothem/harnesses/hermes/__init__.py +33 -0
- package/src/apothem/harnesses/hermes/capabilities.yml +36 -0
- package/src/apothem/harnesses/hermes/install.py +17 -0
- package/src/apothem/harnesses/hermes/materializer.py +35 -0
- package/src/apothem/harnesses/hermes/uninstall.py +33 -0
- package/src/apothem/harnesses/hermes/update.py +10 -0
- package/src/apothem/harnesses/hermes/verify.py +11 -0
- package/src/apothem/harnesses/kimi_code/STANDARD-CONVENTION-PIN.md +128 -0
- package/src/apothem/harnesses/kimi_code/__init__.py +59 -0
- package/src/apothem/harnesses/kimi_code/capabilities.yml +40 -0
- package/src/apothem/harnesses/kimi_code/install.py +42 -0
- package/src/apothem/harnesses/kimi_code/templates/AGENTS.md +43 -0
- package/src/apothem/harnesses/kimi_code/uninstall.py +27 -0
- package/src/apothem/harnesses/kimi_code/update.py +10 -0
- package/src/apothem/harnesses/kimi_code/verify.py +11 -0
- package/src/apothem/harnesses/kiro/STANDARD-CONVENTION-PIN.md +77 -0
- package/src/apothem/harnesses/kiro/__init__.py +49 -0
- package/src/apothem/harnesses/kiro/capabilities.yml +36 -0
- package/src/apothem/harnesses/kiro/install.py +39 -0
- package/src/apothem/harnesses/kiro/templates/apothem-rules.md +36 -0
- package/src/apothem/harnesses/kiro/uninstall.py +25 -0
- package/src/apothem/harnesses/kiro/update.py +10 -0
- package/src/apothem/harnesses/kiro/verify.py +11 -0
- package/src/apothem/harnesses/open_claw/STANDARD-CONVENTION-PIN.md +62 -0
- package/src/apothem/harnesses/open_claw/__init__.py +35 -0
- package/src/apothem/harnesses/open_claw/capabilities.yml +35 -0
- package/src/apothem/harnesses/open_claw/install.py +17 -0
- package/src/apothem/harnesses/open_claw/materializer.py +36 -0
- package/src/apothem/harnesses/open_claw/uninstall.py +32 -0
- package/src/apothem/harnesses/open_claw/update.py +10 -0
- package/src/apothem/harnesses/open_claw/verify.py +11 -0
- package/src/apothem/harnesses/opencode/STANDARD-CONVENTION-PIN.md +76 -0
- package/src/apothem/harnesses/opencode/__init__.py +35 -0
- package/src/apothem/harnesses/opencode/capabilities.yml +43 -0
- package/src/apothem/harnesses/opencode/install.py +17 -0
- package/src/apothem/harnesses/opencode/materializer.py +31 -0
- package/src/apothem/harnesses/opencode/uninstall.py +34 -0
- package/src/apothem/harnesses/opencode/update.py +10 -0
- package/src/apothem/harnesses/opencode/verify.py +11 -0
- package/src/apothem/harnesses/qwen_code/STANDARD-CONVENTION-PIN.md +87 -0
- package/src/apothem/harnesses/qwen_code/__init__.py +37 -0
- package/src/apothem/harnesses/qwen_code/capabilities.yml +43 -0
- package/src/apothem/harnesses/qwen_code/install.py +19 -0
- package/src/apothem/harnesses/qwen_code/materializer.py +174 -0
- package/src/apothem/harnesses/qwen_code/templates/QWEN.md +30 -0
- package/src/apothem/harnesses/qwen_code/uninstall.py +34 -0
- package/src/apothem/harnesses/qwen_code/update.py +10 -0
- package/src/apothem/harnesses/qwen_code/verify.py +11 -0
- package/src/apothem/harnesses/trae/STANDARD-CONVENTION-PIN.md +70 -0
- package/src/apothem/harnesses/trae/__init__.py +49 -0
- package/src/apothem/harnesses/trae/capabilities.yml +34 -0
- package/src/apothem/harnesses/trae/install.py +38 -0
- package/src/apothem/harnesses/trae/templates/apothem-rules.md +37 -0
- package/src/apothem/harnesses/trae/uninstall.py +25 -0
- package/src/apothem/harnesses/trae/update.py +10 -0
- package/src/apothem/harnesses/trae/verify.py +11 -0
- package/src/apothem/harnesses/windsurf/STANDARD-CONVENTION-PIN.md +91 -0
- package/src/apothem/harnesses/windsurf/__init__.py +52 -0
- package/src/apothem/harnesses/windsurf/capabilities.yml +40 -0
- package/src/apothem/harnesses/windsurf/install.py +41 -0
- package/src/apothem/harnesses/windsurf/templates/apothem-rules.md +37 -0
- package/src/apothem/harnesses/windsurf/uninstall.py +25 -0
- package/src/apothem/harnesses/windsurf/update.py +10 -0
- package/src/apothem/harnesses/windsurf/verify.py +11 -0
- package/src/apothem/harnesses/zed/STANDARD-CONVENTION-PIN.md +92 -0
- package/src/apothem/harnesses/zed/__init__.py +57 -0
- package/src/apothem/harnesses/zed/capabilities.yml +38 -0
- package/src/apothem/harnesses/zed/install.py +41 -0
- package/src/apothem/harnesses/zed/templates/apothem-rules.md +32 -0
- package/src/apothem/harnesses/zed/uninstall.py +28 -0
- package/src/apothem/harnesses/zed/update.py +10 -0
- package/src/apothem/harnesses/zed/verify.py +11 -0
- package/src/apothem/hooks/README.md +81 -0
- package/src/apothem/hooks/__init__.py +24 -0
- package/src/apothem/hooks/askuserquestion_validator.py +380 -0
- package/src/apothem/hooks/dispatch.py +296 -0
- package/src/apothem/hooks/emit_hook_context.py +444 -0
- package/src/apothem/hooks/hooks.json +318 -0
- package/src/apothem/hooks/lib/README.md +39 -0
- package/src/apothem/hooks/lib/__init__.py +18 -0
- package/src/apothem/hooks/lib/bootstrap.ps1 +129 -0
- package/src/apothem/hooks/lib/bootstrap.sh +103 -0
- package/src/apothem/hooks/lib/events.py +51 -0
- package/src/apothem/hooks/lib/find-pwsh.ps1 +78 -0
- package/src/apothem/hooks/lib/find-pwsh.sh +76 -0
- package/src/apothem/hooks/lib/find-python.ps1 +63 -0
- package/src/apothem/hooks/lib/find-python.sh +97 -0
- package/src/apothem/hooks/lib/log.py +43 -0
- package/src/apothem/hooks/lib/resolve_root.py +264 -0
- package/src/apothem/hooks/messages/postcompact.md +14 -0
- package/src/apothem/hooks/messages/posttooluse-proactive-compaction.md +46 -0
- package/src/apothem/hooks/messages/precompact.md +14 -0
- package/src/apothem/hooks/messages/pretooluse-askuserquestion-recommended.md +65 -0
- package/src/apothem/hooks/messages/pretooluse-bash-plan-guard.md +97 -0
- package/src/apothem/hooks/messages/pretooluse-bash.md +39 -0
- package/src/apothem/hooks/messages/pretooluse-conformity.md +70 -0
- package/src/apothem/hooks/messages/pretooluse-dependency-guard.md +21 -0
- package/src/apothem/hooks/messages/pretooluse-edit-header-guard.md +61 -0
- package/src/apothem/hooks/messages/pretooluse-edit.md +21 -0
- package/src/apothem/hooks/messages/pretooluse-eval-guard.md +39 -0
- package/src/apothem/hooks/messages/pretooluse-notebookedit.md +11 -0
- package/src/apothem/hooks/messages/pretooluse-write-header-guard.md +45 -0
- package/src/apothem/hooks/messages/pretooluse-write-plan-guard.md +72 -0
- package/src/apothem/hooks/messages/pretooluse-write.md +21 -0
- package/src/apothem/hooks/messages/sessionstart.md +15 -0
- package/src/apothem/hooks/messages/stop.md +27 -0
- package/src/apothem/hooks/proactive_compaction_tracker.py +327 -0
- package/src/apothem/hooks/session_start_bootstrap.py +472 -0
- package/src/apothem/lib/README.md +42 -0
- package/src/apothem/lib/__init__.py +13 -0
- package/src/apothem/lib/atomic_io.py +189 -0
- package/src/apothem/lib/auditor.py +687 -0
- package/src/apothem/lib/clean_slate.py +396 -0
- package/src/apothem/lib/contexts.py +352 -0
- package/src/apothem/lib/data_home.py +255 -0
- package/src/apothem/lib/frontmatter.py +101 -0
- package/src/apothem/lib/harness_materializer.py +213 -0
- package/src/apothem/lib/harness_protocol.py +59 -0
- package/src/apothem/lib/harness_registry.py +282 -0
- package/src/apothem/lib/harness_registry_data.py +843 -0
- package/src/apothem/lib/install_ledger.py +347 -0
- package/src/apothem/lib/learning.py +540 -0
- package/src/apothem/lib/memory.py +347 -0
- package/src/apothem/lib/parallel_sweep.py +234 -0
- package/src/apothem/lib/plan_tiers.py +200 -0
- package/src/apothem/lib/plugin_bootstrap.py +132 -0
- package/src/apothem/lib/plugin_tree.py +599 -0
- package/src/apothem/lib/profile.py +755 -0
- package/src/apothem/lib/profile_projection.py +198 -0
- package/src/apothem/lib/propagation-manifest.yaml +878 -0
- package/src/apothem/lib/propagation.py +220 -0
- package/src/apothem/lib/python_resolver.py +189 -0
- package/src/apothem/lib/reporter.py +62 -0
- package/src/apothem/lib/workspace_migration.py +323 -0
- package/src/apothem/output-styles/README.md +41 -0
- package/src/apothem/output-styles/concise-engineer.md +49 -0
- package/src/apothem/output-styles/default-architect.md +52 -0
- package/src/apothem/output-styles/default.md +113 -0
- package/src/apothem/output-styles/forensic-auditor.md +63 -0
- package/src/apothem/py.typed +0 -0
- package/src/apothem/rules/README.md +121 -0
- package/src/apothem/rules/agent-capability-discipline-matrix.md +89 -0
- package/src/apothem/rules/agent-capability-discipline.md +78 -0
- package/src/apothem/rules/agent-orchestration-patterns.md +144 -0
- package/src/apothem/rules/agent-orchestration.md +65 -0
- package/src/apothem/rules/agents-md-convention.md +86 -0
- package/src/apothem/rules/agile-sprints-elements.md +135 -0
- package/src/apothem/rules/agile-sprints.md +64 -0
- package/src/apothem/rules/agnostic-posture-checklist.md +47 -0
- package/src/apothem/rules/agnostic-posture.md +48 -0
- package/src/apothem/rules/authoritative-referencing-quotation.md +50 -0
- package/src/apothem/rules/authoritative-referencing.md +66 -0
- package/src/apothem/rules/authority-inquiry-categories.md +58 -0
- package/src/apothem/rules/authority-inquiry.md +54 -0
- package/src/apothem/rules/auto-memory-topic-files.md +86 -0
- package/src/apothem/rules/auto-memory.md +67 -0
- package/src/apothem/rules/bidirectional-binding.md +123 -0
- package/src/apothem/rules/canonical-layout-reporting-tiers.md +212 -0
- package/src/apothem/rules/canonical-layout.md +60 -0
- package/src/apothem/rules/clean-architecture-layers.md +186 -0
- package/src/apothem/rules/clean-room-generation-protocols.md +124 -0
- package/src/apothem/rules/clean-room-generation.md +59 -0
- package/src/apothem/rules/code-craft-conventions.md +101 -0
- package/src/apothem/rules/code-craft-markdown.md +138 -0
- package/src/apothem/rules/code-craft-python.md +154 -0
- package/src/apothem/rules/code-craft-shell.md +192 -0
- package/src/apothem/rules/cognitive-identity-techniques.md +180 -0
- package/src/apothem/rules/cognitive-identity.md +81 -0
- package/src/apothem/rules/context-management-budget.md +46 -0
- package/src/apothem/rules/context-management-protocol.md +161 -0
- package/src/apothem/rules/context-management-scratch.md +128 -0
- package/src/apothem/rules/context-management.md +85 -0
- package/src/apothem/rules/definitiveness-virtues.md +67 -0
- package/src/apothem/rules/definitiveness.md +58 -0
- package/src/apothem/rules/determinism.md +81 -0
- package/src/apothem/rules/disclosure-ledger-markers.md +58 -0
- package/src/apothem/rules/disclosure-ledger.md +52 -0
- package/src/apothem/rules/dynamism.md +38 -0
- package/src/apothem/rules/etc-extension.md +57 -0
- package/src/apothem/rules/expertise-posture-elements.md +68 -0
- package/src/apothem/rules/expertise-posture.md +54 -0
- package/src/apothem/rules/freshness-facade.md +64 -0
- package/src/apothem/rules/harness-adapter-shape-schemas.md +162 -0
- package/src/apothem/rules/harness-adapter-shape.md +42 -0
- package/src/apothem/rules/host-discovery-manifests.md +50 -0
- package/src/apothem/rules/host-discovery.md +56 -0
- package/src/apothem/rules/i18n-discipline-locale-cohorts.md +120 -0
- package/src/apothem/rules/i18n-discipline.md +70 -0
- package/src/apothem/rules/interactive-questions-canonical-shapes.md +590 -0
- package/src/apothem/rules/interactive-questions-detail.md +41 -0
- package/src/apothem/rules/interactive-questions-sweep-matchers.md +184 -0
- package/src/apothem/rules/interactive-questions.md +89 -0
- package/src/apothem/rules/large-file-generation.md +112 -0
- package/src/apothem/rules/large-file-reading.md +59 -0
- package/src/apothem/rules/living-docs.md +85 -0
- package/src/apothem/rules/multi-agent-workflow.md +57 -0
- package/src/apothem/rules/operational-mandates-expanded.md +78 -0
- package/src/apothem/rules/operational-mandates.md +88 -0
- package/src/apothem/rules/option-annotation-form.md +60 -0
- package/src/apothem/rules/option-annotation.md +45 -0
- package/src/apothem/rules/own-voice-reimplementation.md +86 -0
- package/src/apothem/rules/performance-discipline.md +91 -0
- package/src/apothem/rules/persistent-conventions-vigilance-checklist.md +54 -0
- package/src/apothem/rules/persistent-conventions-vigilance.md +61 -0
- package/src/apothem/rules/plain-language.md +56 -0
- package/src/apothem/rules/planning-techniques.md +130 -0
- package/src/apothem/rules/pre-emission-gate-bars.md +86 -0
- package/src/apothem/rules/pre-emission-gate.md +54 -0
- package/src/apothem/rules/production-ready-prs-surfaces.md +162 -0
- package/src/apothem/rules/production-ready-prs.md +83 -0
- package/src/apothem/rules/propagation.md +63 -0
- package/src/apothem/rules/recommend-next-step.md +106 -0
- package/src/apothem/rules/refactoring-discipline.md +76 -0
- package/src/apothem/rules/session-closure.md +44 -0
- package/src/apothem/rules/sota-elevation-exemplars.md +76 -0
- package/src/apothem/rules/sota-elevation.md +52 -0
- package/src/apothem/rules/source-accessibility.md +58 -0
- package/src/apothem/rules/surgical-manipulation.md +48 -0
- package/src/apothem/rules/systemic-participation-relations.md +108 -0
- package/src/apothem/rules/systemic-participation.md +70 -0
- package/src/apothem/rules/ten-dimension-check-dimensions.md +52 -0
- package/src/apothem/rules/ten-dimension-check.md +59 -0
- package/src/apothem/rules/token-budget-discipline.md +81 -0
- package/src/apothem/rules/token-efficiency-rewrite-protocol.md +79 -0
- package/src/apothem/rules/token-efficiency-rewrite.md +77 -0
- package/src/apothem/rules/tool-use-discipline.md +48 -0
- package/src/apothem/rules/visual-leverage.md +102 -0
- package/src/apothem/schemas/NOTICE.md +9 -0
- package/src/apothem/schemas/README.md +104 -0
- package/src/apothem/schemas/__init__.py +176 -0
- package/src/apothem/schemas/advisory-finding.schema.json +111 -0
- package/src/apothem/schemas/agent.schema.json +106 -0
- package/src/apothem/schemas/authorship-header.txt +1 -0
- package/src/apothem/schemas/cohort-manifest.yaml +248 -0
- package/src/apothem/schemas/cohort-metadata-vocabulary.yaml +168 -0
- package/src/apothem/schemas/cohort.schema.json +113 -0
- package/src/apothem/schemas/command.schema.json +68 -0
- package/src/apothem/schemas/compatibility-matrix.yaml +432 -0
- package/src/apothem/schemas/context-fragment.schema.json +64 -0
- package/src/apothem/schemas/freshness-token-denylist.txt +51 -0
- package/src/apothem/schemas/handoff-manifest.yaml +353 -0
- package/src/apothem/schemas/header-exceptions.txt +141 -0
- package/src/apothem/schemas/header-visibility.yaml +39 -0
- package/src/apothem/schemas/learning-signal.schema.json +46 -0
- package/src/apothem/schemas/memory-record.schema.json +61 -0
- package/src/apothem/schemas/output-style.schema.json +40 -0
- package/src/apothem/schemas/plan.schema.json +51 -0
- package/src/apothem/schemas/plugin.schema.json +83 -0
- package/src/apothem/schemas/profile.example.yaml +70 -0
- package/src/apothem/schemas/profile.minimal.yaml +6 -0
- package/src/apothem/schemas/profile.schema.json +396 -0
- package/src/apothem/schemas/reference-token-denylist.txt +25 -0
- package/src/apothem/schemas/skill.schema.json +75 -0
- package/src/apothem/skills/README.md +93 -0
- package/src/apothem/skills/dependency-upgrade/SKILL.md +105 -0
- package/src/apothem/skills/dev-toolkit/SKILL.md +120 -0
- package/src/apothem/skills/diagram-authoring/SKILL.md +113 -0
- package/src/apothem/skills/document-authoring/SKILL.md +118 -0
- package/src/apothem/skills/ecosystem-audit/SKILL.md +108 -0
- package/src/apothem/skills/ecosystem-audit/references/audit-fortress.md +85 -0
- package/src/apothem/skills/ecosystem-audit/references/procedure.md +162 -0
- package/src/apothem/skills/eval-harness/SKILL.md +88 -0
- package/src/apothem/skills/incident-runbook/SKILL.md +92 -0
- package/src/apothem/skills/multi-source-research/SKILL.md +90 -0
- package/src/apothem/skills/plan-suite/SKILL.md +118 -0
- package/src/apothem/skills/plan-suite/master_template.md +1324 -0
- package/src/apothem/skills/projectify/SKILL.md +117 -0
- package/src/apothem/skills/prompt-engineering/SKILL.md +122 -0
- package/src/apothem/skills/refactor-extract/SKILL.md +85 -0
- package/src/apothem/skills/research-suite/SKILL.md +170 -0
- package/src/apothem/skills/research-suite/references/directory-structure.md +47 -0
- package/src/apothem/skills/research-suite/references/lifecycle.md +67 -0
- package/src/apothem/skills/research-suite/references/principal-investigator-framework.md +37 -0
- package/src/apothem/skills/research-suite/references/rigor-mandates.md +30 -0
- package/src/apothem/skills/research-suite/research_template.md +476 -0
- package/src/apothem/skills/secret-rotation/SKILL.md +87 -0
- package/src/apothem/skills/source-synthesis/SKILL.md +92 -0
- package/src/apothem/skills/surgical-guard/SKILL.md +118 -0
- package/src/apothem/skills/test-authoring/SKILL.md +85 -0
- package/src/apothem/skills/vuln-triage/SKILL.md +91 -0
- package/src/apothem/skills/workflow/SKILL.md +139 -0
- package/src/apothem/statuslines/README.md +26 -0
- package/src/apothem/statuslines/__init__.py +20 -0
- package/src/apothem/statuslines/conformity.json +5 -0
- package/src/apothem/statuslines/render.py +334 -0
- package/src/apothem/statuslines/statusline.md +50 -0
- package/src/apothem/templates/README.md +43 -0
- package/src/apothem/templates/agents-md-template.md +80 -0
- package/src/apothem/templates/consideration-log.md +39 -0
- package/src/apothem/templates/expertise-gap-log.md +56 -0
- package/src/apothem/templates/master-index-template.md +93 -0
- package/src/apothem/templates/potency-map.md +53 -0
- package/src/apothem/templates/preservation-audit.md +60 -0
- package/src/apothem/templates/question-resolution-audit.md +52 -0
- package/src/apothem/templates/trace-matrix-template.md +77 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Proactive-compaction tracker for PostToolUse tool calls.
|
|
4
|
+
|
|
5
|
+
> Advisory: this hook reports; it never blocks. A PostToolUse hook cannot block the tool call that already ran.
|
|
6
|
+
|
|
7
|
+
This handler mechanically operationalizes the CM-19 proactive-compaction
|
|
8
|
+
triggers (`rules/context-management-protocol.md` §2): the ~18-tool-call window
|
|
9
|
+
and the large-cumulative-emission band. The dispatcher routes this message
|
|
10
|
+
basename to the per-session activity tracker (`hooks/proactive_compaction_tracker.py`)
|
|
11
|
+
rather than emitting this static context — the tracker maintains lightweight
|
|
12
|
+
per-session counters keyed off the `session_id` field of the hook stdin payload
|
|
13
|
+
and surfaces a concise proactive-compaction advisory once a threshold crosses,
|
|
14
|
+
then resets the counters (anti-spam back-off) so it does not fire on every
|
|
15
|
+
subsequent tool call.
|
|
16
|
+
|
|
17
|
+
**Scope.** Fires on every PostToolUse tool call (empty matcher — all tools).
|
|
18
|
+
Per session, it tracks the tool-call count and a cumulative tool-output-size
|
|
19
|
+
estimate since the last advisory.
|
|
20
|
+
|
|
21
|
+
**Thresholds (configurable).**
|
|
22
|
+
|
|
23
|
+
- `APOTHEM_PROACTIVE_COMPACTION_TOOL_THRESHOLD` (default `18`) — tool calls
|
|
24
|
+
since the last advisory; mirrors the §2 "~18 tool calls" trigger.
|
|
25
|
+
- `APOTHEM_PROACTIVE_COMPACTION_OUTPUT_THRESHOLD` (default `20000`) — cumulative
|
|
26
|
+
tool-output bytes since the last advisory; a mechanical proxy for the §2
|
|
27
|
+
"500-line emission" / heavy-read band (~20 KB). A non-positive or
|
|
28
|
+
unparseable override falls back to the default, so a typo can never silently
|
|
29
|
+
disable the tracker.
|
|
30
|
+
|
|
31
|
+
**Advisory shape.** When a threshold crosses, the tracker emits a `systemMessage`
|
|
32
|
+
plus `additionalContext` recommending the operator externalize in-conversation
|
|
33
|
+
state (PROGRESS.md Resumption Contract + PLAN-NOTES.md, or a scratch file under
|
|
34
|
+
the active harness's config root when no suite is active) and then compact, so
|
|
35
|
+
context stays lean per the blind-execution invariant.
|
|
36
|
+
|
|
37
|
+
**State.** Per-session counters live under the OS temp dir
|
|
38
|
+
(`<tempdir>/apothem-proactive-compaction/<session>.json`) — never inside the
|
|
39
|
+
repository's tracked tree. A missing, empty, or corrupt counter file degrades to
|
|
40
|
+
"start counting again", never a crash.
|
|
41
|
+
|
|
42
|
+
**Fail-disposition.** Fail-open at every layer. The Python dispatcher at
|
|
43
|
+
`hooks/dispatch.py` converts any handler error to a structured failure envelope
|
|
44
|
+
on stdout; the tracker's own `main` swallows every exception and emits an empty
|
|
45
|
+
envelope. A tracker fault therefore costs nothing — never a blocked or stalled
|
|
46
|
+
tool call.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Pre-compaction protocol (CM-24 §2.3). Externalize all in-conversation state BEFORE the harness compresses context.
|
|
4
|
+
|
|
5
|
+
With an active plan suite — execute IN ORDER (all mandatory):
|
|
6
|
+
|
|
7
|
+
1. Verify PROGRESS.md Resumption Contract reflects current state — phase, task, next action, convention anchors, critical-files manifest. Update any stale fields.
|
|
8
|
+
2. Verify every decision made this session is recorded in PLAN-NOTES.md § Resolved Decisions.
|
|
9
|
+
3. Verify Phase Output Registry reflects every artifact produced this phase with verified status (and actual path).
|
|
10
|
+
4. Identify any state that exists ONLY in conversation (not in any durable file). Externalize now — task state → PROGRESS.md, decisions → PLAN-NOTES.md, working notes → scratch file under the active suite's `_inputs/` directory (or the active harness's config root when no suite is active).
|
|
11
|
+
|
|
12
|
+
No active suite: externalize accumulated session decisions and working notes to a scratch file under the active harness's config root.
|
|
13
|
+
|
|
14
|
+
Gate. If externalization is incomplete, complete it BEFORE compaction proceeds — compaction with state still in conversation loses that state.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Call-time `(Recommended)`-marker guard for `AskUserQuestion` tool calls.
|
|
4
|
+
|
|
5
|
+
> Advisory: this guard reports; it does not block by default. The strict
|
|
6
|
+
> opt-in (`APOTHEM_CONFORMITY_STRICT=1` or `--strict`) escalates
|
|
7
|
+
> well-formedness violations to a block.
|
|
8
|
+
|
|
9
|
+
This guard closes the previously documented-but-unenforced call-time gap in the
|
|
10
|
+
`(Recommended)` interactive-question guarantee. The option-annotation matchers
|
|
11
|
+
(`conformity/option_annotation_grep.py`) scan committed `*.md` artifacts only;
|
|
12
|
+
nothing inspected the LIVE `AskUserQuestion` tool payload at the moment the
|
|
13
|
+
agent asks the operator. This dispatch-routed `PreToolUse` handler
|
|
14
|
+
(`hooks/askuserquestion_validator.py`) inspects the live payload — the
|
|
15
|
+
`questions` array, each question's `options[].label` and `multiSelect` — and
|
|
16
|
+
validates marker well-formedness against the canonical rule at
|
|
17
|
+
`rules/interactive-questions-canonical-shapes.md` §2.1.
|
|
18
|
+
|
|
19
|
+
**Scope.** Fires on `AskUserQuestion` tool calls. The dispatcher routes this
|
|
20
|
+
message basename to the validator rather than emitting a static context, so the
|
|
21
|
+
check runs on the live payload at call time.
|
|
22
|
+
|
|
23
|
+
**Well-formedness findings (block-eligible under the strict opt-in).** Each is
|
|
24
|
+
objectively decidable from the payload alone:
|
|
25
|
+
|
|
26
|
+
- **non-canonical-postfix-case** — a label ends with the banned lowercase
|
|
27
|
+
`(recommended)`; the canonical form is the capital `(Recommended)`.
|
|
28
|
+
- **non-canonical-postfix-form** — a label names a recommended token in a
|
|
29
|
+
non-canonical bracket / spacing form (`[Recommended]`, `(Rec)`,
|
|
30
|
+
`(Recommended )`, `( Recommended )`); the canonical form is the exact
|
|
31
|
+
` (Recommended)` postfix with one leading space at the end of the label.
|
|
32
|
+
- **recommended-on-destructive** — the marker rides a clearly-destructive
|
|
33
|
+
option label (delete / remove / discard / overwrite / revert / …); an
|
|
34
|
+
irreversible action must not be the recommended (and easy) path, per the
|
|
35
|
+
destructive-op no-default floor at
|
|
36
|
+
`rules/interactive-questions-canonical-shapes.md` §5.8.
|
|
37
|
+
- **single-select-multi-recommended** — a `multiSelect: false` question carries
|
|
38
|
+
the marker on more than one option; at most one is permitted (set
|
|
39
|
+
`multiSelect: true` to recommend several).
|
|
40
|
+
|
|
41
|
+
**Nudge (advisory only — never blocks).** A `multiSelect: false` question with
|
|
42
|
+
two or more substantive options and zero `(Recommended)` markers is *advised*
|
|
43
|
+
to mark its recommended option. The native `AskUserQuestion` payload carries no
|
|
44
|
+
separate "recommended" field — the marker IS the only signal of which option is
|
|
45
|
+
recommended — so a missing marker cannot be proven a defect. This is a
|
|
46
|
+
heuristic nudge, not a hard rule.
|
|
47
|
+
|
|
48
|
+
**What the runtime check CAN and CANNOT guarantee.** It CAN guarantee marker
|
|
49
|
+
well-formedness (a present marker is in the canonical form, placed correctly,
|
|
50
|
+
not on a destructive option, at most one per single-select question). It CANNOT
|
|
51
|
+
force a recommendation to exist — that is a behavioral-convention obligation the
|
|
52
|
+
rules carry, surfaced here only as the advisory nudge.
|
|
53
|
+
|
|
54
|
+
**Advisory vs. strict.** By default the guard emits a `systemMessage` surfacing
|
|
55
|
+
the findings and nudges; the question proceeds. Under the strict opt-in
|
|
56
|
+
(`APOTHEM_CONFORMITY_STRICT=1` or `--strict`, mirroring `conformity/gate.py`),
|
|
57
|
+
well-formedness findings (never the nudge) escalate to a
|
|
58
|
+
`{"decision":"block","reason":"…"}` envelope.
|
|
59
|
+
|
|
60
|
+
**Fail-disposition.** Fail-open. Any exception inside the validator — a
|
|
61
|
+
malformed payload, a shapeless `questions` array, an unexpected option type —
|
|
62
|
+
yields an empty (allow) envelope, so a validator error never crashes the
|
|
63
|
+
operator's question. The dispatcher's outer boundary is fail-open too: a
|
|
64
|
+
dispatch error converts to a structured failure envelope on stdout and the
|
|
65
|
+
question proceeds.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Plans-Discipline write guard for Bash tool calls (companion to
|
|
4
|
+
`pretooluse-write-plan-guard.md`).
|
|
5
|
+
|
|
6
|
+
> Advisory: this hook reports; it does not block. Mechanical enforcement runs in CI.
|
|
7
|
+
|
|
8
|
+
This guard surfaces the Plans-Locality discipline at the shell-redirection
|
|
9
|
+
surface so a shell-redirected write does not bypass the Write-route guard. It
|
|
10
|
+
reports a redirection that would land a plan outside the sole canonical
|
|
11
|
+
project-local plans tree `<project-root>/.apothem/plans/` and recommends a
|
|
12
|
+
redirection; the operator decides. A legacy `<project-root>/.plans/` tree is no
|
|
13
|
+
longer canonical and is redirect-recommended to `.apothem/plans/` (operators
|
|
14
|
+
upgrade it via `apothem migrate-workspace`). Mechanical enforcement of
|
|
15
|
+
Plans-Locality runs in CI and pre-commit via the strict conformity corpus gate
|
|
16
|
+
(`no_global_plans_grep`), not at this tool call.
|
|
17
|
+
|
|
18
|
+
**Scope.** Fires on every PreToolUse Bash event. Scans the Bash command
|
|
19
|
+
string for **output-redirection patterns** that would write a file
|
|
20
|
+
under a global plans directory (a `.plans/` or `.apothem/plans/` directory
|
|
21
|
+
under a non-project root — such as `~/.claude/.plans/` or `~/.apothem/plans/`
|
|
22
|
+
for users on the Claude Code harness) or any other global-ecosystem path with
|
|
23
|
+
plan-shaped content. Applies the same redirect-required / soft-flag / allow verdict matrix
|
|
24
|
+
that the Write / Edit / NotebookEdit guard applies, projected onto the
|
|
25
|
+
shell-redirection surface. Surfaces the foundational Plans-Locality
|
|
26
|
+
mandate (`CLAUDE.md` Plans Discipline; spec `_spec/spec.md` §3 +
|
|
27
|
+
§5.5.1) at the Bash tool-call surface so shell-redirected writes do not
|
|
28
|
+
bypass the Write-route guard.
|
|
29
|
+
|
|
30
|
+
**Output-redirection patterns inspected.**
|
|
31
|
+
|
|
32
|
+
| Pattern class | Examples |
|
|
33
|
+
|---------------|----------|
|
|
34
|
+
| **POSIX redirect** | `cmd > path` · `cmd >> path` · `cmd 2> path` · `cmd 2>> path` · `cmd &> path` · `cmd >| path` |
|
|
35
|
+
| **Heredoc emission** | `cat > path <<EOF` · `cat >> path <<'EOF'` · `tee path <<EOF` (with or without `-a`) |
|
|
36
|
+
| **`tee` invocations** | `cmd \| tee path` · `cmd \| tee -a path` · `cmd \| tee path1 path2` |
|
|
37
|
+
| **File-creation utilities** | `touch path` · `cp src path` · `mv src path` · `install -m … src path` |
|
|
38
|
+
| **Editor-pipe** | `printf '...' > path` · `echo '...' > path` · `python -c '...' > path` |
|
|
39
|
+
| **PowerShell analogs** | `Out-File -FilePath path` · `Set-Content -Path path` · `Add-Content -Path path` · `... > path` (PowerShell pipeline redirect) |
|
|
40
|
+
|
|
41
|
+
The scanner extracts every `path` argument from these patterns and
|
|
42
|
+
applies the same path-classification predicate as
|
|
43
|
+
`pretooluse-write-plan-guard.md`:
|
|
44
|
+
|
|
45
|
+
1. Resolve every extracted path to its absolute form (relative paths are
|
|
46
|
+
resolved against the Bash command's working directory, falling back to
|
|
47
|
+
the tool-call's `cwd` field when present).
|
|
48
|
+
2. Resolve the **current project root** by walking from the working
|
|
49
|
+
directory to the nearest enclosing `.git/` directory; when no
|
|
50
|
+
enclosing repo exists, the working directory is the project root.
|
|
51
|
+
3. Apply the verdict matrix (recursion-self allow / redirect-required /
|
|
52
|
+
soft-flag / allow-otherwise) per the table in
|
|
53
|
+
`pretooluse-write-plan-guard.md`.
|
|
54
|
+
|
|
55
|
+
**Action — redirect-required path.**
|
|
56
|
+
|
|
57
|
+
Invoke the structured-inquiry channel using the canonical Plans-Locality option-set at `rules/interactive-questions-canonical-shapes.md` §5.9.1 (the 2-option redirect-required variant; Bash-tool label form: `rewrite-redirect-to-project-plans` / `cancel`). Substitute the actual rejected path and resolved project root at invocation time. The recommended option redirects the shell-redirected write to the canonical project-local plans tree `<project-root>/.apothem/plans/`; the operator decides.
|
|
58
|
+
|
|
59
|
+
Recursion-self case: when the resolved project root IS the Apothem source repo itself (for Claude Code users this is `~/.claude/`), the redirection IS canonical. Pass through silently. The recursion case is the ONLY allowed shell-redirect path under the apothem-source-repo plans tree `.apothem/plans/`.
|
|
60
|
+
|
|
61
|
+
**Action — soft-flag path.**
|
|
62
|
+
|
|
63
|
+
Invoke the structured-inquiry channel using the canonical Plans-Locality option-set at `rules/interactive-questions-canonical-shapes.md` §5.9.2 (soft-flag 3-option variant; Bash-tool label form: `rewrite-redirect-to-project-plans` / `run-as-proposed` / `cancel`). Substitute the actual flagged path at invocation time.
|
|
64
|
+
|
|
65
|
+
**Action — allow path.**
|
|
66
|
+
|
|
67
|
+
When every extracted path is allow-class (the canonical project-local plans
|
|
68
|
+
tree `<project-root>/.apothem/plans/`, or any non-plan-shaped path outside the
|
|
69
|
+
protected classes, or no redirection at all), pass through silently. The vast
|
|
70
|
+
majority of Bash commands fall into this class.
|
|
71
|
+
|
|
72
|
+
**Heuristic robustness.**
|
|
73
|
+
|
|
74
|
+
- Quoted paths are unwrapped (`> "path with spaces.md"` → `path with spaces.md`).
|
|
75
|
+
- Variable expansions are best-effort (`> $HOME/.plans/x.md` resolves
|
|
76
|
+
`$HOME` against the tool-call's environment block when present;
|
|
77
|
+
otherwise treated as a soft-flag candidate pending operator review).
|
|
78
|
+
- Glob patterns are inspected as literal paths (a redirect target is a
|
|
79
|
+
single file, not a glob expansion site).
|
|
80
|
+
- Subshell-piped commands (`(cmd1; cmd2) > path`) are inspected at the
|
|
81
|
+
outer redirect.
|
|
82
|
+
- Multi-statement commands separated by `;` / `&&` / `||` are inspected
|
|
83
|
+
per-statement.
|
|
84
|
+
|
|
85
|
+
**Fail-disposition.** Two layers govern failure. (a) The Python dispatcher at
|
|
86
|
+
`hooks/dispatch.py` is fail-open: a hook error (parse failure on the Bash
|
|
87
|
+
command, path normalization exception, project-root resolution failure, Python
|
|
88
|
+
exception inside the predicate) converts to a structured failure envelope on
|
|
89
|
+
stdout and the Bash call proceeds, so a harness error never silently blocks the
|
|
90
|
+
tool call. (b) The assistant's interpretation of this context is fail-closed on
|
|
91
|
+
a detected verdict: when the scan returns redirect-required or soft-flag, the
|
|
92
|
+
directive is to surface the redirection via the structured-inquiry channel and
|
|
93
|
+
let the operator decide before re-issuing the command. The two layers are
|
|
94
|
+
non-redundant: the dispatcher protects the runtime, this context protects the
|
|
95
|
+
Plans-Locality discipline. The Plans-Locality invariant itself is enforced
|
|
96
|
+
mechanically in CI and pre-commit via the strict conformity corpus gate
|
|
97
|
+
(`no_global_plans_grep`).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
CM-7 git-artifact isolation + M12 numeric-prefix discipline + M15 human-only authorship.
|
|
4
|
+
|
|
5
|
+
Trigger. Bash command contains any of `git commit`, `git checkout -b`, `git branch`, `git tag`, `git merge -m`, `git rebase --exec`, `git stash push -m`, `git notes add`, `git mv`, `git rm`.
|
|
6
|
+
|
|
7
|
+
The hook scans the message / name / path argument for three independent classes of finding. Any one finding is a STOP — fix the cause, do not silently strip, and re-issue the Bash call.
|
|
8
|
+
|
|
9
|
+
## Scan 1 — CM-7 plan-internal isolation
|
|
10
|
+
|
|
11
|
+
Scan the message / name argument for any term in the canonical forbidden-terms block at CM-7 (TM-N, CM-N, CP-N, "Resumption Contract", "Phase Output Registry", "convention anchors", phase-folder names, plan-suite file names, seriousness-level names).
|
|
12
|
+
|
|
13
|
+
On hit: STOP. Rewrite the message in natural domain language describing the WHAT and WHY of the change, not the plan structure that produced it. Re-issue.
|
|
14
|
+
|
|
15
|
+
## Scan 2 — M12 numeric-prefix discipline (suite-root and root-level singletons)
|
|
16
|
+
|
|
17
|
+
Scan the path argument of `git mv`, `git rm`, and any path appearing in the commit message body (referenced files, renames). Detect candidate violations:
|
|
18
|
+
|
|
19
|
+
- A target path matching `<plans-root>/{suite}/00-<NAME>.md` (or any `0[0-9]-<NAME>.md` at the suite root, not inside `phases/`), where `<plans-root>` is the active plan-suite root — `<project-root>/.apothem/plans/` in host projects, and the apothem-source-repo plan-suite tree during ecosystem authoring (the legacy `.plans/` tree resolves to `~/.claude/.plans/` for Claude Code users) — the `NN-` numeric prefix is forbidden on suite-root infrastructure files per `rules/canonical-layout.md` §2.1. Numeric prefixes apply only where ordering is intrinsic (phase folders, sub-phase folders, host-discovered ordinal naming schemes).
|
|
20
|
+
- A new file class introduced at any root level whose first instance carries a numeric prefix without sibling-set evidence that ordering is intrinsic — the prefix mis-signals an ordering relationship that does not exist.
|
|
21
|
+
|
|
22
|
+
On hit: STOP. Re-issue the operation against an unprefixed target path. Existing prefixed instances at suite roots that pre-date this discipline are migrated through a normal rename change-set, not silently overwritten.
|
|
23
|
+
|
|
24
|
+
## Scan 3 — M15 human-only authorship discipline
|
|
25
|
+
|
|
26
|
+
Scan the message / name / annotation argument of every git-write command (commit, tag annotation, stash name, notes body, branch name, PR-relevant text in `gh pr create` invocations) for **agent-attribution patterns**:
|
|
27
|
+
|
|
28
|
+
- Trailer patterns: any line matching `^\s*Co-Authored-By:.*` whose value contains a non-human-author signal — `claude` / `gpt` / `chatgpt` / `copilot` / `cursor` / `gemini` / `llama` / `bard` / `anthropic` / `openai` / `microsoft` / `noreply@.*ai` / `noreply@.*-bot` / `bot@` / any other LLM / AI assistant / automated agent name.
|
|
29
|
+
- Body-narrative patterns: phrases like "🤖 Generated with", "Generated with [Claude Code]", "Generated by an AI", "Co-authored by an AI", "with assistance from `<agent>`", "written by `<model>`", "`<agent>` implemented this", "`<agent>` drafted", "based on `<model>`'s suggestion".
|
|
30
|
+
- Subject-line patterns: any subject containing an agent-authorship marker (`[claude]`, `[gpt]`, `[ai]`, `🤖`, `Generated by:`, `From: <agent>`).
|
|
31
|
+
- Author / committer field manipulation: detect `git -c user.email=…` overrides where the override targets a non-human address (`noreply@anthropic.com`, `noreply@openai.com`, `<bot>@…`).
|
|
32
|
+
|
|
33
|
+
On hit: STOP. Strip the agent-attribution and re-issue without it. The sole authorship surface git resolves at commit time is the operator's own identity, per `rules/production-ready-prs.md` §6 Human-only authorship. The agent acts as an instrument the operator wields; never as a co-author of record.
|
|
34
|
+
|
|
35
|
+
**Carve-out — legitimate product / runtime references.** Subject lines and body text that reference a product or runtime by name (e.g., "Claude Code never stalls", "harness honors Claude Code's hook contract", `CLAUDE_PROJECT_DIR`) are descriptions of the product, not authorship signals; they pass the scan. The discriminator: authorship signals attach the named entity to the **act of authoring** ("co-authored by Claude", "generated by Claude"); product references attach the named entity to the **subject under discussion** ("Claude Code's hook contract", "the CLAUDE.md file"). When in doubt, rephrase to refer to the product as a noun rather than to the agent as a verb-doer.
|
|
36
|
+
|
|
37
|
+
## Non-matching commands
|
|
38
|
+
|
|
39
|
+
No action. The hook is scoped to the ten git-write triggers above; other Bash commands pass unaffected.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
# Conformity-gate orchestrator (PreToolUse Write/Edit)
|
|
4
|
+
|
|
5
|
+
> Advisory: this hook reports; it does not block. Mechanical enforcement runs in CI.
|
|
6
|
+
|
|
7
|
+
The conformity-gate orchestrator at `<harness-root>/apothem/conformity/gate.py`
|
|
8
|
+
runs the registered per-Write greps against the Write/Edit tool input before the
|
|
9
|
+
tool fires. The orchestrator reads the harness's tool-input JSON from stdin,
|
|
10
|
+
extracts the content (Write `content` field, Edit `new_string` field) and the
|
|
11
|
+
target path, and dispatches every registered per-Write matcher via `importlib`.
|
|
12
|
+
Each grep returns a structured result; the orchestrator aggregates them into a
|
|
13
|
+
single JSON report. The findings are surfaced as an advisory nudge plus a
|
|
14
|
+
definitive next step — the per-Write surface does not block the tool call (the
|
|
15
|
+
EN-1 advisory-by-default posture). Strict enforcement runs separately in CI and
|
|
16
|
+
pre-commit via the corpus gate (`gate --all-perwrite --strict`).
|
|
17
|
+
|
|
18
|
+
## Per-Write grep coverage
|
|
19
|
+
|
|
20
|
+
The authoritative full set is `conformity/gate.py` `GREP_MODULES`; the per-Write
|
|
21
|
+
dispatch runs **every** registered matcher in that tuple (count derived from the
|
|
22
|
+
registry, never hardcoded here). The matchers partition into a small blocking set
|
|
23
|
+
(`_BLOCKING_PER_WRITE_GREPS` — deterministic, low-false-positive, green over the
|
|
24
|
+
tracked corpus, so a finding fails the strict corpus run) and the remaining
|
|
25
|
+
advisory set (`_ADVISORY_PER_WRITE_GREPS` — reported with a named remediation
|
|
26
|
+
owner per `_ADVISORY_RATIONALE`, never gating). Representative matchers and their
|
|
27
|
+
cited rules:
|
|
28
|
+
|
|
29
|
+
| Grep | Rule cited | Partition |
|
|
30
|
+
|------|------------|-----------|
|
|
31
|
+
| user-confirm-grep | M5 authority-inquiry §10 | advisory |
|
|
32
|
+
| option-annotation-grep | M7 option-annotation | blocking |
|
|
33
|
+
| binding-reciprocity-grep | M10 bidirectional-binding §Notation | blocking |
|
|
34
|
+
| completion-claim-grep | M12 / M15 completion claims | blocking |
|
|
35
|
+
| unpinned-action-grep | M15 production-ready §Supply-chain | blocking |
|
|
36
|
+
| hedging-grep | M8 definitiveness §Hedging | advisory |
|
|
37
|
+
| secret-leak-grep | M13.8 + M15 production-ready | advisory |
|
|
38
|
+
| file-header-grep | SPDX authorship-header policy | advisory |
|
|
39
|
+
| always-on-budget-grep | token-budget-discipline §Always-on body budget | advisory |
|
|
40
|
+
|
|
41
|
+
The blocking-vs-advisory classification is asserted at import time
|
|
42
|
+
(`_assert_perwrite_partition`) so every registered matcher is classified.
|
|
43
|
+
|
|
44
|
+
## Performance budget
|
|
45
|
+
|
|
46
|
+
Per-grep wall-clock is bounded by `PER_GREP_BUDGET_SECONDS` (0.520 s) in
|
|
47
|
+
`gate.py`; `over_budget: true` in the JSON output flags a matcher that exceeded
|
|
48
|
+
it. The budget surfaces as a watch item in the report — it does not block the
|
|
49
|
+
write (the hook's own ceiling and the fail-open dispatcher govern hard limits).
|
|
50
|
+
|
|
51
|
+
## Exit / disposition contract
|
|
52
|
+
|
|
53
|
+
- **Advisory finding (per-Write hook):** the orchestrator surfaces the JSON
|
|
54
|
+
report (one entry per matcher, with findings) and a recommended next step; the
|
|
55
|
+
Write/Edit proceeds. The operator decides whether to address a finding before
|
|
56
|
+
re-issuing.
|
|
57
|
+
- **Strict enforcement (CI / pre-commit corpus):** `gate --all-perwrite . --strict`
|
|
58
|
+
exits non-zero when a **blocking** matcher reports a finding over the tracked
|
|
59
|
+
corpus; that is where the conformity floor is enforced, not at the tool call.
|
|
60
|
+
- **Fail-disposition:** the dispatcher at `hooks/dispatch.py` is fail-open — any
|
|
61
|
+
exception inside a matcher or the orchestrator converts to a structured failure
|
|
62
|
+
envelope on stdout and the tool call proceeds, so a harness error never
|
|
63
|
+
silently blocks a write.
|
|
64
|
+
|
|
65
|
+
## Action on a finding
|
|
66
|
+
|
|
67
|
+
The operator inspects the JSON report (one entry per matcher, with findings for
|
|
68
|
+
the matchers that flagged), addresses the reported violations in the candidate
|
|
69
|
+
content where warranted, and re-issues the Write/Edit. Each finding carries its
|
|
70
|
+
rule anchor for routing.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Dependency-manifest supply-chain guard (advisory).
|
|
4
|
+
|
|
5
|
+
> Advisory: this hook reports; it does not block. Mechanical enforcement runs in CI.
|
|
6
|
+
|
|
7
|
+
Scope. Fires on Write/Edit to dependency manifests and their lockfiles: `pyproject.toml`, `requirements*.txt`, `package.json`, `Cargo.toml`, `go.mod`, `Gemfile`, and the matching lockfiles (`uv.lock`, `poetry.lock`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `Cargo.lock`, `go.sum`, `Gemfile.lock`). Non-matching paths pass unaffected.
|
|
8
|
+
|
|
9
|
+
This guard protects the operator's supply-chain posture per `rules/production-ready-prs.md` §3. It is advisory — it never blocks a correct manifest; it surfaces a dependency the operator should ratify before it lands.
|
|
10
|
+
|
|
11
|
+
Trigger / inspected patterns. The guard diffs the new content against the prior manifest and flags a newly-introduced or changed dependency line that matches any of three classes:
|
|
12
|
+
|
|
13
|
+
- **Unpinned where the host pins exact.** A version range, caret, tilde, or wildcard (`^1.2.0`, `~=2.3`, `>=4`, `*`, `latest`, an unbounded constraint) on a dependency in a manifest whose sibling dependencies are pinned to exact versions (`==1.2.3`, `=1.2.3`, an exact lockfile hash). The discriminator is the host's own ratified pinning policy discovered from the surrounding lines, not an absolute rule — library manifests legitimately carry ranges; production manifests pin.
|
|
14
|
+
- **Untrusted or unknown source.** A dependency pointing at a registry, index URL, or scope the manifest's siblings do not already use (`--index-url`, `--extra-index-url`, a private registry host, an unrecognized npm scope, a non-default crates source).
|
|
15
|
+
- **Git or URL dependency.** A dependency resolved from a git ref or a direct URL (`git+https://…`, a `git = …` table, a `path`/`url` source, a tarball link) rather than a published registry release.
|
|
16
|
+
|
|
17
|
+
Action — advisory flag. On any flagged line: surface the dependency through the structured-inquiry channel per `rules/interactive-questions.md` with a three-option set — **pin-to-exact (Recommended)** / **accept-as-proposed** / **cancel** — annotated per the canonical option-set discipline at `rules/interactive-questions-canonical-shapes.md` §2 (three-segment body, concrete-driver rationale, named default). The recommended option pins the flagged dependency to the exact resolvable version, citing the supply-chain posture as the driver. The operator's pick is the gate; the guard does not pin silently.
|
|
18
|
+
|
|
19
|
+
Fail-disposition. Two layers govern failure. (a) The Python dispatcher at `hooks/dispatch.py` is fail-open: a hook error — the diff cannot be parsed, the manifest cannot be read, or any Python exception inside the predicate — converts to a structured failure envelope on stdout and the Write proceeds, so a harness error never silently blocks the tool call. (b) The assistant's interpretation of this context is fail-closed on a detected finding: when a flagged dependency line is found, the directive is to surface it through the structured-inquiry channel and let the operator decide before the line lands. The two layers are non-redundant: the dispatcher protects the runtime, this context protects the supply-chain discipline, which is enforced mechanically in CI and pre-commit.
|
|
20
|
+
|
|
21
|
+
Non-matching paths. No action. The guard is scoped to the dependency-manifest and lockfile patterns above; every other path class passes unaffected.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
SPDX-header inject guard for Edit tool calls.
|
|
4
|
+
|
|
5
|
+
> Advisory: this hook reports; it does not block. Mechanical enforcement runs in CI.
|
|
6
|
+
|
|
7
|
+
This guard surfaces the SPDX / authorship-header discipline: every applicable
|
|
8
|
+
file MUST carry the canonical `SPDX-License-Identifier: MIT` header, and an
|
|
9
|
+
edit MUST NOT strip it. It reports a create-via-edit missing the header or an
|
|
10
|
+
edit that would remove the header, and recommends the corrected content; the
|
|
11
|
+
operator decides. Mechanical enforcement of the header invariant runs in CI
|
|
12
|
+
and pre-commit via the strict conformity corpus gate, not at this tool call.
|
|
13
|
+
|
|
14
|
+
**Scope.** Fires on two corner cases; is a pass-through on all others.
|
|
15
|
+
|
|
16
|
+
**Corner case A — create-via-edit (new file).** An Edit tool call where the
|
|
17
|
+
target path does not yet exist on disk (the Edit will create the file) and
|
|
18
|
+
the proposed `new_string` constitutes the entire file content. Applies only
|
|
19
|
+
when the target path is an applicable file — not matching any glob in
|
|
20
|
+
`src/apothem/schemas/header-exceptions.txt` and whose suffix or basename maps to a known
|
|
21
|
+
variant family in `src/apothem/conformity/file_header_grep.py` SUFFIX_VARIANT /
|
|
22
|
+
BASENAME_VARIANT — and `file_header_grep.check()` returns HEADER_ABSENT or
|
|
23
|
+
HEADER_MALFORMED for `new_string`.
|
|
24
|
+
|
|
25
|
+
**Corner case B — header removal (existing file).** An Edit tool call where
|
|
26
|
+
the target path already exists on disk and currently carries the canonical
|
|
27
|
+
`SPDX-License-Identifier: MIT` header line, but the proposed edit would
|
|
28
|
+
remove or overwrite that line (i.e., the `old_string` matches all or part of
|
|
29
|
+
the SPDX header and the `new_string` does not reinstate it). Applies when the
|
|
30
|
+
file is applicable per the same criteria as corner case A.
|
|
31
|
+
|
|
32
|
+
**Pass-through.** Any Edit that modifies an existing file without touching
|
|
33
|
+
the canonical SPDX header region is a pass-through — no action is taken and
|
|
34
|
+
the edit proceeds uninterrupted.
|
|
35
|
+
|
|
36
|
+
**Action (both corner cases).**
|
|
37
|
+
|
|
38
|
+
1. Determine the corrected content. Read `src/apothem/schemas/authorship-header.txt` to
|
|
39
|
+
obtain the single `SPDX-License-Identifier: MIT` line. Call
|
|
40
|
+
`_render_canonical_block` (from `src/apothem/conformity/file_header_grep.py`) for the
|
|
41
|
+
file's variant family to produce the canonical block (the one SPDX line
|
|
42
|
+
rendered in the family's comment syntax, followed by one trailing blank
|
|
43
|
+
line). Set the insertion index to 1 when the proposed content opens
|
|
44
|
+
with a shebang `#!`, otherwise 0. Insert the canonical block at that index
|
|
45
|
+
into the proposed content to produce the corrected content.
|
|
46
|
+
|
|
47
|
+
2. Invoke the structured-inquiry channel using the canonical Authorship-Header option-set at `rules/interactive-questions-canonical-shapes.md` §5.10 (3-option set + override-record schema specified there). Substitute the actual path, corner-case label (`create-via-edit` | `header-removal`), and variant at invocation time. The override-record schema's `rule` column carries the Edit-route corner-case label for this hook.
|
|
48
|
+
|
|
49
|
+
**Fail-disposition.** Two layers govern failure. (a) The Python dispatcher at
|
|
50
|
+
`hooks/dispatch.py` is fail-open: a hook-emission error — `src/apothem/schemas/authorship-header.txt`
|
|
51
|
+
unreadable, `_render_canonical_block` raising, the variant lookup failing, or
|
|
52
|
+
any Python exception inside the predicate — converts to a structured failure
|
|
53
|
+
envelope on stdout and the Edit proceeds, so a harness error never silently
|
|
54
|
+
blocks the tool call. (b) The assistant's interpretation of this context is
|
|
55
|
+
fail-closed on a detected gap: when the validator reports HEADER_ABSENT or
|
|
56
|
+
HEADER_MALFORMED on a create-via-edit, or a header-removing edit, the directive
|
|
57
|
+
is to surface the corrected content via the structured-inquiry channel and let
|
|
58
|
+
the operator decide before re-issuing the Edit. The two layers are
|
|
59
|
+
non-redundant: the dispatcher protects the runtime, this context protects the
|
|
60
|
+
header discipline. The header invariant itself is enforced mechanically in CI
|
|
61
|
+
and pre-commit via the strict conformity corpus gate.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
CM-7 codebase isolation (Edit scope).
|
|
4
|
+
|
|
5
|
+
Scope. Triggered on every Edit. Skip when target is inside the Apothem source repo or the active harness's config root (for the Claude Code harness, `~/.claude/`). Apply otherwise.
|
|
6
|
+
|
|
7
|
+
Action. Scan ONLY the `new_string` (Edit is partial; pre-existing violations elsewhere in the file are out of scope unless this Edit touches them) for any term in the canonical forbidden-terms block at `CLAUDE.md` §CM-7.
|
|
8
|
+
|
|
9
|
+
On hit: STOP. Rewrite `new_string` in natural domain language. Re-issue the Edit.
|
|
10
|
+
|
|
11
|
+
Always-on rule body budget. When the Edit target matches `rules/*.md` and the file's frontmatter declares `alwaysApply: true` AND `pathFilter:` empty, the post-Edit body's substantive-token count must satisfy the 500-token ceiling per `rules/token-budget-discipline.md`. The conformity-gate orchestrator runs `conformity/always_on_budget_grep.py` and reports `over_budget` when the ceiling is exceeded. On `over_budget: true`: STOP, decompose along a path-filtered seam into a companion sub-rule, trim the parent body, re-issue.
|
|
12
|
+
|
|
13
|
+
Scratch-convention path check.
|
|
14
|
+
|
|
15
|
+
Trigger. Every Edit.
|
|
16
|
+
|
|
17
|
+
Action. Examine the target `file_path` against the scratch-convention discipline at `rules/context-management-scratch.md` §1 (scratch-file naming + closed-purpose vocabulary) and §2 (Plan-Workflow Directories + suite-locality invariant). REJECT an Edit whose target violates the closed-purpose vocabulary, the disjoint-vocabulary rule, or the suite-locality invariant; ACCEPT otherwise. On a REJECT: STOP and re-issue the Edit at the corrected target per the rule's recovery clause.
|
|
18
|
+
|
|
19
|
+
Non-matching paths: no action. The scratch-convention check is scoped to the `_inputs/` and `_spec/` directory patterns defined at `rules/context-management-scratch.md` §1–§2 and does not interact with other path classes.
|
|
20
|
+
|
|
21
|
+
**Fail-disposition.** Two layers govern failure. (a) The Python dispatcher at `hooks/dispatch.py` is fail-open: a hook-emission error converts to a structured failure envelope on stdout and the Edit proceeds, so a harness error never silently blocks the tool call. (b) The assistant's interpretation of this context is fail-closed on a detected violation: when the CM-7 scan, an over-budget body, or a scratch-path REJECT class is hit, the directive is to STOP and re-issue the Edit corrected. The two layers are non-redundant: the dispatcher protects the runtime, this context protects the rule. Mechanical enforcement runs in CI and pre-commit via the strict conformity corpus gate.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Dynamic-eval / unsafe-deserialization guard — advisory prompt-injection defense.
|
|
4
|
+
|
|
5
|
+
> Advisory: this hook reports; it does not block. Mechanical enforcement runs in CI.
|
|
6
|
+
|
|
7
|
+
This guard is ADVISORY, not a correctness gate. It surfaces a flagged construct for the operator's decision; it never rewrites code on its own and never blocks on a false positive without a confirmation step. Its purpose is to intercept the prompt-injection and unsafe-eval attack surface before a construct that evaluates untrusted or model-derived input lands in the codebase, per the security-conscious-code discipline (no `eval` / `exec` on untrusted input).
|
|
8
|
+
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Fires on every Write, Edit, and Bash command that introduces dynamic evaluation or unsafe deserialization of a value flowing from an untrusted or model-derived source — a language-model prompt, a language-model response, a tool-call result, network input, or any other input the program does not control. The guard is language- and runtime-agnostic: it inspects the construct's shape, not any specific vendor or framework. Skip the scan when the target is inside the Apothem source repo's own fixture trees that document these patterns as test material.
|
|
12
|
+
|
|
13
|
+
## Trigger / inspected patterns
|
|
14
|
+
|
|
15
|
+
The hook flags a construct when a dynamic-evaluation or unsafe-deserialization primitive receives an argument that originates from an untrusted source:
|
|
16
|
+
|
|
17
|
+
- Dynamic code evaluation — `eval(`, `exec(`, `Function(` / `new Function(`, `compile(` followed by `exec`, or an equivalent eval primitive in the target language — applied to interpolated prompt or response text.
|
|
18
|
+
- Shell-out on interpolated text — `subprocess` / `child_process` / `os.system` / backtick or `Popen` invocations with `shell=True` (or the runtime's shell-on equivalent) where the command string interpolates model-derived or untrusted input.
|
|
19
|
+
- Unsafe deserialization — `pickle.loads`, `yaml.load` without a safe loader, `marshal.loads`, or an equivalent native-object deserializer applied to model output or network input.
|
|
20
|
+
|
|
21
|
+
The discriminator is the data-flow: the primitive is benign on a trusted literal and a finding on a value that traces back to a prompt, a response, a tool result, or external input.
|
|
22
|
+
|
|
23
|
+
## Action — advisory flag
|
|
24
|
+
|
|
25
|
+
On a flagged construct: surface it through the structured-inquiry channel per `rules/interactive-questions.md` with a single-select three-option set, annotated per the canonical option-set discipline at `rules/interactive-questions-canonical-shapes.md` (three-segment body; concrete-driver rationale on every non-neutral recommendation). Do not author the full YAML here.
|
|
26
|
+
|
|
27
|
+
- **refactor-to-safe (Recommended)** — replace the construct with a non-evaluating equivalent (dispatch table over `eval`, argument-vector subprocess over shell interpolation, safe loader over native deserialization). Recommended because it removes the attack surface rather than documenting it.
|
|
28
|
+
- **accept-with-justification** — proceed with the construct, recording a justification that names why the input is trusted or already sanitized.
|
|
29
|
+
- **cancel** — block the edit; no file is modified.
|
|
30
|
+
|
|
31
|
+
Every option carries `default-pointer: no-default: user decision required` — the guard proposes no silent default on a security-relevant construct.
|
|
32
|
+
|
|
33
|
+
## Fail-disposition
|
|
34
|
+
|
|
35
|
+
Two layers govern failure. (a) The Python dispatcher at `hooks/dispatch.py` is fail-open: a hook error — the inspection itself fails to complete, or any Python exception inside the predicate — converts to a structured failure envelope on stdout and the tool call proceeds, so a harness error never silently blocks it. (b) The assistant's interpretation of this context is fail-closed on a detected construct: when the scan flags a dynamic-evaluation or unsafe-deserialization primitive on untrusted input, the directive is to surface it through the structured-inquiry channel and let the operator decide before the construct lands. The two layers are non-redundant: the dispatcher protects the runtime, this context protects the security discipline, which is enforced mechanically in CI and pre-commit (`bare_except_grep` and the security matchers).
|
|
36
|
+
|
|
37
|
+
## Non-matching writes
|
|
38
|
+
|
|
39
|
+
No action. The guard is scoped to the dynamic-evaluation and unsafe-deserialization primitives above applied to untrusted input; every other construct passes unaffected.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
CM-7 codebase isolation (notebook scope).
|
|
4
|
+
|
|
5
|
+
Scope. Triggered on every NotebookEdit. Skip when target is inside the Apothem source repo or the active harness's config root (for the Claude Code harness, `~/.claude/`). Apply otherwise.
|
|
6
|
+
|
|
7
|
+
Action. Apply the CM-7 scan to the new cell content regardless of cell type — code cells, markdown cells, and existing execution-output cells are all artifacts visible outside the Apothem meta-config locations. Reject any term in the canonical forbidden-terms block at `CLAUDE.md` §CM-7.
|
|
8
|
+
|
|
9
|
+
On hit: STOP. Rewrite the cell in natural domain language. Re-issue the NotebookEdit. Output cells produced by subsequent execution are not scanned at write time but must be cleared before commit if they contain plan-term leaks.
|
|
10
|
+
|
|
11
|
+
**Fail-disposition.** Two layers govern failure: (a) the Python dispatcher at `hooks/dispatch.py` is fail-open — a hook-emission error converts to a structured failure envelope on stdout and the NotebookEdit proceeds, so harness errors never silently block tool calls; (b) the assistant's interpretation of this context is fail-closed on rule-violation detection — when the CM-7 scan hits, the directive is to STOP and re-issue with the cell rewritten in natural domain language. The two layers are non-redundant: the dispatcher protects the runtime; this context protects the rule.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
SPDX-header inject guard for Write tool calls.
|
|
4
|
+
|
|
5
|
+
> Advisory: this hook reports; it does not block. Mechanical enforcement runs in CI.
|
|
6
|
+
|
|
7
|
+
This guard surfaces the SPDX / authorship-header discipline: every applicable
|
|
8
|
+
new file MUST begin with the canonical `SPDX-License-Identifier: MIT` header.
|
|
9
|
+
It reports a missing or malformed header and recommends the corrected content;
|
|
10
|
+
the operator decides. Mechanical enforcement of the header invariant runs in CI
|
|
11
|
+
and pre-commit via the strict conformity corpus gate, not at this tool call.
|
|
12
|
+
|
|
13
|
+
**Scope.** Fires when a Write tool call targets an applicable file — any file
|
|
14
|
+
whose path does not match a glob in `src/apothem/schemas/header-exceptions.txt` and whose
|
|
15
|
+
suffix or basename maps to a known variant family in
|
|
16
|
+
`src/apothem/conformity/file_header_grep.py` SUFFIX_VARIANT / BASENAME_VARIANT — and
|
|
17
|
+
`file_header_grep.check()` returns HEADER_ABSENT or HEADER_MALFORMED for the
|
|
18
|
+
proposed content.
|
|
19
|
+
|
|
20
|
+
**Action.**
|
|
21
|
+
|
|
22
|
+
1. Determine the corrected content. Read `src/apothem/schemas/authorship-header.txt` to
|
|
23
|
+
obtain the single `SPDX-License-Identifier: MIT` line. Call
|
|
24
|
+
`_render_canonical_block` (from `src/apothem/conformity/file_header_grep.py`) for the
|
|
25
|
+
file's variant family to produce the canonical block (the one SPDX line
|
|
26
|
+
rendered in the family's comment syntax, followed by one trailing blank
|
|
27
|
+
line). Set the insertion index to 1 when the proposed content opens
|
|
28
|
+
with a shebang `#!`, otherwise 0. Insert the canonical block at that index
|
|
29
|
+
to produce the corrected content.
|
|
30
|
+
|
|
31
|
+
2. Invoke the structured-inquiry channel using the canonical Authorship-Header option-set at `rules/interactive-questions-canonical-shapes.md` §5.10 (3-option set + override-record schema specified there). Substitute the actual path, rule, and variant at invocation time. The override-record schema's `rule` column carries the Write-route rule label for this hook.
|
|
32
|
+
|
|
33
|
+
**Fail-disposition.** Two layers govern failure. (a) The Python dispatcher at
|
|
34
|
+
`hooks/dispatch.py` is fail-open: a hook-emission error — `src/apothem/schemas/authorship-header.txt`
|
|
35
|
+
unreadable, `_render_canonical_block` raising, the variant lookup failing, or
|
|
36
|
+
any Python exception inside the predicate — converts to a structured failure
|
|
37
|
+
envelope on stdout and the Write proceeds, so a harness error never silently
|
|
38
|
+
blocks the tool call. (b) The assistant's interpretation of this context is
|
|
39
|
+
fail-closed on a detected gap: when the validator reports HEADER_ABSENT or
|
|
40
|
+
HEADER_MALFORMED, the directive is to surface the corrected content via the
|
|
41
|
+
structured-inquiry channel and let the operator decide before re-issuing the
|
|
42
|
+
Write. The two layers are non-redundant: the dispatcher protects the runtime,
|
|
43
|
+
this context protects the header discipline. The header invariant itself is
|
|
44
|
+
enforced mechanically in CI and pre-commit via the strict conformity corpus
|
|
45
|
+
gate.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Plans-Discipline write guard for Write / Edit / NotebookEdit tool calls.
|
|
4
|
+
|
|
5
|
+
> Advisory: this hook reports; it does not block. Mechanical enforcement runs in CI.
|
|
6
|
+
|
|
7
|
+
This guard surfaces the Plans-Locality discipline: planning artifacts live at
|
|
8
|
+
the sole canonical project-local plans tree `<project-root>/.apothem/plans/` —
|
|
9
|
+
never at the active harness's config root and never at any other global
|
|
10
|
+
location. A legacy `<project-root>/.plans/` tree is no longer canonical;
|
|
11
|
+
operators upgrade it via `apothem migrate-workspace`. It reports a write that
|
|
12
|
+
would land a plan outside the canonical tree and recommends a redirection; the
|
|
13
|
+
operator decides. Mechanical enforcement of Plans-Locality runs in CI and
|
|
14
|
+
pre-commit via the strict conformity corpus gate (`no_global_plans_grep`), not
|
|
15
|
+
at this tool call.
|
|
16
|
+
|
|
17
|
+
**Scope.** Fires when a write-capable tool call (Write, Edit, NotebookEdit)
|
|
18
|
+
targets a path under one of the protected plans-discipline regions, OR targets
|
|
19
|
+
a non-canonical plans path with plan-shaped content. Enforces the
|
|
20
|
+
foundational Plans-Locality mandate: planning artifacts live at the sole
|
|
21
|
+
canonical project-local plans tree `<project-root>/.apothem/plans/`, never at
|
|
22
|
+
the active harness's config root and never at any other global location (per
|
|
23
|
+
`CLAUDE.md` Plans Discipline and the suite-locality and operator-authorship
|
|
24
|
+
contract).
|
|
25
|
+
|
|
26
|
+
**Decision predicate.**
|
|
27
|
+
|
|
28
|
+
1. Resolve the **target path** to its absolute form.
|
|
29
|
+
2. Resolve the **current project root** by walking from the working directory
|
|
30
|
+
to the nearest enclosing `.git/` directory; when no enclosing repo exists,
|
|
31
|
+
the current working directory is the project root.
|
|
32
|
+
3. Apply the verdict matrix below.
|
|
33
|
+
|
|
34
|
+
In the conditions below, the **canonical project-local plans tree** is the sole
|
|
35
|
+
location `<project-root>/.apothem/plans/` (the shared Apothem working
|
|
36
|
+
directory's plans child). A legacy `<project-root>/.plans/` tree is no longer
|
|
37
|
+
canonical and is redirect-recommended to `.apothem/plans/`. A **global plans
|
|
38
|
+
location** is a `.plans/` OR `.apothem/plans/` directory under a root that is
|
|
39
|
+
NOT the resolved project root (a harness-config root such as `~/.claude/`, the
|
|
40
|
+
user home such as `~/.apothem/plans/`, or any other non-project location).
|
|
41
|
+
|
|
42
|
+
| Case | Condition | Verdict |
|
|
43
|
+
|------|-----------|---------|
|
|
44
|
+
| **Project-local (allow)** | Target path is under the resolved project's canonical plans tree `<project-root>/.apothem/plans/` | **Allow** — the canonical project-local plans location |
|
|
45
|
+
| **Legacy-local (redirect-recommended)** | Target path is under the resolved project's legacy `<project-root>/.plans/` tree | **Redirect-recommended** — surface a structured inquiry recommending redirection to `<project-root>/.apothem/plans/` (run `apothem migrate-workspace` to upgrade the legacy tree) |
|
|
46
|
+
| **Recursion-self (allow)** | Resolved project root IS the Apothem source repo itself (case-insensitive on Windows; for Claude Code users that working tree is `~/.claude/`) AND target path is under the apothem-source-repo canonical plans tree `.apothem/plans/` | **Allow** — the working tree IS the Apothem source repo; its own plans tree is the canonical destination for this project |
|
|
47
|
+
| **Redirect-required** | Target path is under a global plans location (a harness-config-root `.plans/` or `.apothem/plans/` directory — e.g., `~/.claude/.plans/`, `~/.claude/<anything>/.plans/`, `~/.apothem/plans/` — for the Claude Code harness) AND project root is NOT the Apothem source repo | **Redirect-required** — surface a structured inquiry recommending redirection to the project-local plans tree |
|
|
48
|
+
| **Soft-flag** | Target path is in another global-ecosystem location (`~/Desktop`, `~/Downloads`, `~/Documents`, `~/`, OR any path outside the resolved project root) AND filename matches `*plan*.md`, `*notes*.md`, `*draft*.md` (case-insensitive) OR proposed content carries plan-shaped frontmatter (`name:`, `phases:`, `master-plan:`, `phase-id:`) | **Soft-flag** — surface a structured inquiry proposing redirection |
|
|
49
|
+
| **Allow** | Any other write | **Allow** unchanged |
|
|
50
|
+
|
|
51
|
+
**Action — redirect-required path.**
|
|
52
|
+
|
|
53
|
+
Invoke the structured-inquiry channel using the canonical Plans-Locality option-set at `rules/interactive-questions-canonical-shapes.md` §5.9.1 (the 2-option redirect-required variant). Substitute the actual rejected path and resolved project root at invocation time. The recommended option redirects the write to the canonical project-local plans tree `<project-root>/.apothem/plans/`; the operator decides.
|
|
54
|
+
|
|
55
|
+
Recursion-self case: when the resolved project root IS the Apothem source repo itself (for Claude Code users that working tree is `~/.claude/`), the write IS canonical. Pass through silently with no structured inquiry. The recursion case is the ONLY allowed write path under the apothem-source-repo plans tree `.apothem/plans/`.
|
|
56
|
+
|
|
57
|
+
**Action — soft-flag path.**
|
|
58
|
+
|
|
59
|
+
Invoke the structured-inquiry channel using the canonical Plans-Locality option-set at `rules/interactive-questions-canonical-shapes.md` §5.9.2 (soft-flag 3-option variant). Substitute the actual flagged path at invocation time.
|
|
60
|
+
|
|
61
|
+
**Fail-disposition.** Two layers govern failure. (a) The Python dispatcher at
|
|
62
|
+
`hooks/dispatch.py` is fail-open: a hook error (project-root resolution failure,
|
|
63
|
+
path normalization exception, Python exception inside the predicate) converts to
|
|
64
|
+
a structured failure envelope on stdout and the write proceeds, so a harness
|
|
65
|
+
error never silently blocks the tool call. (b) The assistant's interpretation of
|
|
66
|
+
this context is fail-closed on a detected verdict: when the predicate returns
|
|
67
|
+
redirect-required or soft-flag, the directive is to surface the redirection via
|
|
68
|
+
the structured-inquiry channel and let the operator decide before re-issuing the
|
|
69
|
+
write. The two layers are non-redundant: the dispatcher protects the runtime,
|
|
70
|
+
this context protects the Plans-Locality discipline. The Plans-Locality
|
|
71
|
+
invariant itself is enforced mechanically in CI and pre-commit via the strict
|
|
72
|
+
conformity corpus gate (`no_global_plans_grep`).
|