@r1z4x/tezgah 1.9.2 → 1.13.0
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 +415 -1
- package/MANIFEST +404 -144
- package/README.de.md +1 -1
- package/README.es.md +1 -1
- package/README.fr.md +1 -1
- package/README.md +5 -4
- package/README.tr.md +1 -1
- package/bin/codegen +5 -2
- package/bin/tezgah-design +288 -1
- package/bin/tezgah-docs +1 -1
- package/bin/tezgah-doctor +39 -2
- package/bin/tezgah-import-ai-research +26 -12
- package/bin/tezgah-ocr-review +296 -0
- package/bin/tezgah-research +255 -44
- package/bin/tezgah-review-quote +185 -0
- package/bin/tezgah-setup +1365 -55
- package/bin/tezgah-skill +1 -1
- package/bin/tezgah-status +201 -3
- package/bin/tezgah-task +258 -20
- package/commands/adhd.md +2 -2
- package/commands/ponytail.md +4 -4
- package/docs/architecture.md +2 -2
- package/docs/citations-baseline.json +3 -3
- package/docs/clarity-baseline.json +11 -5
- package/docs/contract.md +91 -43
- package/docs/environment.md +5 -2
- package/docs/evidence.md +109 -17
- package/docs/feature-audit.md +2 -2
- package/docs/gate.md +60 -33
- package/docs/glossary.md +6 -3
- package/docs/hosts.md +313 -17
- package/docs/index.json +34 -8
- package/docs/judge.md +4 -2
- package/docs/layers.md +4 -4
- package/docs/models.md +37 -9
- package/docs/operations.md +141 -5
- package/docs/research.md +815 -8
- package/docs/skills.md +137 -13
- package/docs/status-line.md +121 -1
- package/docs/testing.md +3 -1
- package/hooks/hooks.json +2 -2
- package/hooks/lang/en.json +21 -0
- package/hooks/lang/tr.json +22 -1
- package/hooks/projects-stop.py +2 -1
- package/hooks/tezgah_agents.py +65 -25
- package/hooks/tezgah_apps.py +18 -0
- package/hooks/tezgah_attest.py +79 -10
- package/hooks/tezgah_components.py +4 -0
- package/hooks/tezgah_context.py +207 -55
- package/hooks/tezgah_extension.py +337 -0
- package/hooks/tezgah_gate.py +267 -79
- package/hooks/tezgah_integrity.py +864 -143
- package/hooks/tezgah_judge.py +6 -4
- package/hooks/tezgah_models.py +59 -19
- package/hooks/tezgah_orca.py +1 -1
- package/hooks/tezgah_paths.py +145 -8
- package/hooks/tezgah_policy.py +128 -57
- package/hooks/tezgah_rank.py +9 -6
- package/hooks/tezgah_replay.py +12 -6
- package/hooks/tezgah_research.py +1414 -76
- package/hooks/tezgah_research_capture.py +1544 -0
- package/hooks/tezgah_research_evidence.py +842 -0
- package/hooks/tezgah_research_stats.py +258 -0
- package/hooks/tezgah_skill_pick.py +408 -106
- package/hooks/tezgah_stack.py +236 -1
- package/hooks/tezgah_stopspec.py +8 -1
- package/hooks/tezgah_task.py +14 -5
- package/hooks/tezgah_taste_ledger.py +1 -1
- package/hosts/amp/hook.py +217 -0
- package/hosts/amp/tezgah-plugin.ts.in +386 -0
- package/hosts/antigravity/hook.py +255 -0
- package/hosts/codex/hook.py +2 -1
- package/hosts/commandcode/hook.py +239 -0
- package/hosts/copilot/hook.py +284 -0
- package/hosts/cursor/hook.py +31 -3
- package/hosts/droid/hook.py +259 -0
- package/hosts/dsh/hooks.json +1 -1
- package/hosts/gemini/hook.py +213 -0
- package/hosts/goose/hook.py +145 -0
- package/hosts/omp/hook.py +4 -1
- package/hosts/omp/tezgah-hook.ts.in +30 -7
- package/hosts/opencode/plugins/tezgah.js +309 -48
- package/hosts/opencode/tui/cli/tui.tsx +100 -0
- package/hosts/opencode/tui/tezgah-tui.tsx +2 -1
- package/hosts/qwen/hook.py +206 -0
- package/output-styles/tezgah.md +20 -15
- package/package.json +1 -1
- package/skills/ai-research/SKILL.md +21 -14
- package/skills/ai-research/SOURCE +7 -5
- package/skills/ai-research/index/1-frame.md +6 -6
- package/skills/ai-research/index/2-data.md +9 -9
- package/skills/ai-research/index/3-train.md +36 -36
- package/skills/ai-research/index/4-measure.md +13 -13
- package/skills/ai-research/index/5-run.md +11 -11
- package/skills/ai-research/index/6-write.md +23 -23
- package/skills/ai-research/library.json +104 -104
- package/skills/analyze-app/SKILL.md +17 -12
- package/skills/design-contract/SKILL.md +42 -7
- package/skills/design-contract/data-views.md +2 -2
- package/skills/design-library/EVALS.md +1 -1
- package/skills/design-library/INDEX.md +39 -39
- package/skills/design-library/SKILL.md +19 -13
- package/skills/design-library/SOURCE +45 -43
- package/skills/feature-audit/SKILL.md +20 -14
- package/skills/hallmark/LICENSE +21 -0
- package/skills/hallmark/SKILL.md +154 -0
- package/skills/hallmark/SOURCE +207 -0
- package/skills/hallmark/agents/openai.yaml +13 -0
- package/skills/hallmark/references/anatomy.md +71 -0
- package/skills/hallmark/references/brand-truth.md +40 -0
- package/skills/hallmark/references/comp.md +104 -0
- package/skills/hallmark/references/craft.md +116 -0
- package/skills/hallmark/references/dark-mode.md +49 -0
- package/skills/hallmark/references/data-viz.md +48 -0
- package/skills/hallmark/references/design-md.md +53 -0
- package/skills/hallmark/references/direction.md +52 -0
- package/skills/hallmark/references/export-formats.md +80 -0
- package/skills/hallmark/references/flow.md +131 -0
- package/skills/hallmark/references/fonts.md +58 -0
- package/skills/hallmark/references/gates.md +243 -0
- package/skills/hallmark/references/genres/atmospheric.md +24 -0
- package/skills/hallmark/references/genres/editorial.md +24 -0
- package/skills/hallmark/references/genres/modern-minimal.md +24 -0
- package/skills/hallmark/references/genres/playful.md +24 -0
- package/skills/hallmark/references/imagery.md +99 -0
- package/skills/hallmark/references/interaction-and-states.md +89 -0
- package/skills/hallmark/references/layout.md +104 -0
- package/skills/hallmark/references/macrostructures/01-bento-grid.md +21 -0
- package/skills/hallmark/references/macrostructures/02-long-document.md +35 -0
- package/skills/hallmark/references/macrostructures/03-marquee-hero.md +21 -0
- package/skills/hallmark/references/macrostructures/04-stat-led.md +21 -0
- package/skills/hallmark/references/macrostructures/05-workbench.md +21 -0
- package/skills/hallmark/references/macrostructures/06-conversational-faq.md +28 -0
- package/skills/hallmark/references/macrostructures/07-manifesto.md +28 -0
- package/skills/hallmark/references/macrostructures/08-photographic.md +21 -0
- package/skills/hallmark/references/macrostructures/09-quote-led.md +21 -0
- package/skills/hallmark/references/macrostructures/10-specimen.md +21 -0
- package/skills/hallmark/references/macrostructures/11-catalogue.md +21 -0
- package/skills/hallmark/references/macrostructures/12-letter.md +21 -0
- package/skills/hallmark/references/macrostructures/13-index-first.md +21 -0
- package/skills/hallmark/references/macrostructures/14-narrative-workflow.md +21 -0
- package/skills/hallmark/references/macrostructures/15-split-studio.md +21 -0
- package/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -0
- package/skills/hallmark/references/macrostructures/17-type-specimen.md +19 -0
- package/skills/hallmark/references/macrostructures/18-portfolio-grid.md +21 -0
- package/skills/hallmark/references/macrostructures/19-map-diagram.md +21 -0
- package/skills/hallmark/references/macrostructures/20-ecosystem-index.md +19 -0
- package/skills/hallmark/references/macrostructures/21-component-playground.md +21 -0
- package/skills/hallmark/references/macrostructures.md +119 -0
- package/skills/hallmark/references/microinteractions.md +80 -0
- package/skills/hallmark/references/patterns.md +202 -0
- package/skills/hallmark/references/redesign.md +88 -0
- package/skills/hallmark/references/responsive.md +46 -0
- package/skills/hallmark/references/review-finish.md +19 -0
- package/skills/hallmark/references/review-hero.md +20 -0
- package/skills/hallmark/references/scroll-choreography.md +110 -0
- package/skills/hallmark/references/texture.md +90 -0
- package/skills/hallmark/references/themes/README.md +58 -0
- package/skills/hallmark/references/themes/almanac.jpg +0 -0
- package/skills/hallmark/references/themes/almanac.md +103 -0
- package/skills/hallmark/references/themes/arcade.jpg +0 -0
- package/skills/hallmark/references/themes/arcade.md +102 -0
- package/skills/hallmark/references/themes/atelier.jpg +0 -0
- package/skills/hallmark/references/themes/atelier.md +98 -0
- package/skills/hallmark/references/themes/bloom.jpg +0 -0
- package/skills/hallmark/references/themes/bloom.md +102 -0
- package/skills/hallmark/references/themes/blueprint.jpg +0 -0
- package/skills/hallmark/references/themes/blueprint.md +103 -0
- package/skills/hallmark/references/themes/broadside.jpg +0 -0
- package/skills/hallmark/references/themes/broadside.md +108 -0
- package/skills/hallmark/references/themes/brutal.jpg +0 -0
- package/skills/hallmark/references/themes/brutal.md +95 -0
- package/skills/hallmark/references/themes/carnival.jpg +0 -0
- package/skills/hallmark/references/themes/carnival.md +104 -0
- package/skills/hallmark/references/themes/cobalt.jpg +0 -0
- package/skills/hallmark/references/themes/cobalt.md +101 -0
- package/skills/hallmark/references/themes/console.jpg +0 -0
- package/skills/hallmark/references/themes/console.md +99 -0
- package/skills/hallmark/references/themes/coral.jpg +0 -0
- package/skills/hallmark/references/themes/coral.md +102 -0
- package/skills/hallmark/references/themes/darkroom.jpg +0 -0
- package/skills/hallmark/references/themes/darkroom.md +99 -0
- package/skills/hallmark/references/themes/dose.jpg +0 -0
- package/skills/hallmark/references/themes/dose.md +98 -0
- package/skills/hallmark/references/themes/dusk.jpg +0 -0
- package/skills/hallmark/references/themes/dusk.md +105 -0
- package/skills/hallmark/references/themes/editorial.jpg +0 -0
- package/skills/hallmark/references/themes/editorial.md +97 -0
- package/skills/hallmark/references/themes/formwork.jpg +0 -0
- package/skills/hallmark/references/themes/formwork.md +107 -0
- package/skills/hallmark/references/themes/furrow.jpg +0 -0
- package/skills/hallmark/references/themes/furrow.md +98 -0
- package/skills/hallmark/references/themes/garden.jpg +0 -0
- package/skills/hallmark/references/themes/garden.md +97 -0
- package/skills/hallmark/references/themes/grid.jpg +0 -0
- package/skills/hallmark/references/themes/grid.md +101 -0
- package/skills/hallmark/references/themes/halftone.jpg +0 -0
- package/skills/hallmark/references/themes/halftone.md +106 -0
- package/skills/hallmark/references/themes/hedgerow.jpg +0 -0
- package/skills/hallmark/references/themes/hedgerow.md +104 -0
- package/skills/hallmark/references/themes/hum.jpg +0 -0
- package/skills/hallmark/references/themes/hum.md +99 -0
- package/skills/hallmark/references/themes/index.json +2191 -0
- package/skills/hallmark/references/themes/ink.jpg +0 -0
- package/skills/hallmark/references/themes/ink.md +106 -0
- package/skills/hallmark/references/themes/kiln.jpg +0 -0
- package/skills/hallmark/references/themes/kiln.md +108 -0
- package/skills/hallmark/references/themes/loom.jpg +0 -0
- package/skills/hallmark/references/themes/loom.md +106 -0
- package/skills/hallmark/references/themes/lumen.jpg +0 -0
- package/skills/hallmark/references/themes/lumen.md +103 -0
- package/skills/hallmark/references/themes/manifesto.jpg +0 -0
- package/skills/hallmark/references/themes/manifesto.md +101 -0
- package/skills/hallmark/references/themes/midnight.jpg +0 -0
- package/skills/hallmark/references/themes/midnight.md +97 -0
- package/skills/hallmark/references/themes/newsprint.jpg +0 -0
- package/skills/hallmark/references/themes/newsprint.md +102 -0
- package/skills/hallmark/references/themes/overprint.jpg +0 -0
- package/skills/hallmark/references/themes/overprint.md +101 -0
- package/skills/hallmark/references/themes/pasteup.jpg +0 -0
- package/skills/hallmark/references/themes/pasteup.md +100 -0
- package/skills/hallmark/references/themes/piste.jpg +0 -0
- package/skills/hallmark/references/themes/piste.md +99 -0
- package/skills/hallmark/references/themes/ribbon.jpg +0 -0
- package/skills/hallmark/references/themes/ribbon.md +106 -0
- package/skills/hallmark/references/themes/rim.jpg +0 -0
- package/skills/hallmark/references/themes/rim.md +96 -0
- package/skills/hallmark/references/themes/riso.jpg +0 -0
- package/skills/hallmark/references/themes/riso.md +98 -0
- package/skills/hallmark/references/themes/solstice.jpg +0 -0
- package/skills/hallmark/references/themes/solstice.md +104 -0
- package/skills/hallmark/references/themes/specimen.jpg +0 -0
- package/skills/hallmark/references/themes/specimen.md +100 -0
- package/skills/hallmark/references/themes/spore.jpg +0 -0
- package/skills/hallmark/references/themes/spore.md +104 -0
- package/skills/hallmark/references/themes/sport.jpg +0 -0
- package/skills/hallmark/references/themes/sport.md +101 -0
- package/skills/hallmark/references/themes/squeeze.jpg +0 -0
- package/skills/hallmark/references/themes/squeeze.md +99 -0
- package/skills/hallmark/references/themes/sticker.jpg +0 -0
- package/skills/hallmark/references/themes/sticker.md +106 -0
- package/skills/hallmark/references/themes/studio.jpg +0 -0
- package/skills/hallmark/references/themes/studio.md +99 -0
- package/skills/hallmark/references/themes/terminal.jpg +0 -0
- package/skills/hallmark/references/themes/terminal.md +96 -0
- package/skills/hallmark/references/themes/terrazzo.jpg +0 -0
- package/skills/hallmark/references/themes/terrazzo.md +106 -0
- package/skills/hallmark/references/themes/ultraviolet.jpg +0 -0
- package/skills/hallmark/references/themes/ultraviolet.md +106 -0
- package/skills/hallmark/references/themes/vellum.jpg +0 -0
- package/skills/hallmark/references/themes/vellum.md +105 -0
- package/skills/hallmark/references/themes/wayfind.jpg +0 -0
- package/skills/hallmark/references/themes/wayfind.md +105 -0
- package/skills/hallmark/references/themes/werkstatt.jpg +0 -0
- package/skills/hallmark/references/themes/werkstatt.md +105 -0
- package/skills/hallmark/scripts/capture.mjs +125 -0
- package/skills/hallmark/scripts/fixtures/exemplars/atmospheric.html +324 -0
- package/skills/hallmark/scripts/fixtures/exemplars/editorial.html +363 -0
- package/skills/hallmark/scripts/fixtures/exemplars/modern-minimal.html +527 -0
- package/skills/hallmark/scripts/fixtures/exemplars/playful.html +353 -0
- package/skills/hallmark/scripts/fixtures/eyebrow-fail/index.html +118 -0
- package/skills/hallmark/scripts/fixtures/eyebrow-pass/index.html +137 -0
- package/skills/hallmark/scripts/fixtures/kept/after.html +27 -0
- package/skills/hallmark/scripts/fixtures/kept/before.html +26 -0
- package/skills/hallmark/scripts/fixtures/slopped.html +145 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/Feature.vue +14 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/Hero.tsx +33 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/index.html +74 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/style.css +6 -0
- package/skills/hallmark/scripts/fixtures/tailwind-pass/Hero.tsx +33 -0
- package/skills/hallmark/scripts/fixtures/tailwind-pass/index.html +57 -0
- package/skills/hallmark/scripts/fixtures/tailwind-pass/style.css +15 -0
- package/skills/hallmark/scripts/fixtures/waiver/index.html +54 -0
- package/skills/hallmark/scripts/imagegen.mjs +85 -0
- package/skills/hallmark/scripts/install-hook.mjs +70 -0
- package/skills/hallmark/scripts/install.mjs +141 -0
- package/skills/hallmark/scripts/lint-hook.mjs +49 -0
- package/skills/hallmark/scripts/photos.json +1 -0
- package/skills/hallmark/scripts/picture.mjs +71 -0
- package/skills/hallmark/scripts/refcheck.mjs +352 -0
- package/skills/hallmark/scripts/sloplint-render.mjs +1252 -0
- package/skills/hallmark/scripts/sloplint.mjs +4422 -0
- package/skills/hallmark/scripts/theme.mjs +650 -0
- package/skills/harness/SKILL.md +17 -8
- package/skills/i-have-adhd/SKILL.md +32 -12
- package/skills/no-ai-slop/SKILL.md +15 -1
- package/skills/plan-add/SKILL.md +38 -27
- package/skills/plan-status/SKILL.md +13 -7
- package/skills/plan-sync/SKILL.md +18 -12
- package/skills/pm-frameworks/SKILL.md +19 -10
- package/skills/pm-frameworks/SOURCE +7 -5
- package/skills/ponytail/SKILL.md +19 -14
- package/skills/product-analysis/SKILL.md +22 -18
- package/skills/product-flow/SKILL.md +14 -9
- package/skills/research/SKILL.md +97 -48
- package/skills/rl-env/SKILL.md +25 -13
- package/skills/rl-env/SOURCE +8 -6
- package/skills/tezgah-contract/SKILL.md +65 -47
- package/statusline.py +20 -9
- package/workflows/graph-review.js +14 -2
- package/bin/tezgah-skill.py +0 -59
- /package/skills/ai-research/0-autoresearch-skill/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/litgpt/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/mamba/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/nanogpt/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/rwkv/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/torchtitan/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/02-tokenization/huggingface-tokenizers/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/02-tokenization/sentencepiece/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/axolotl/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/llama-factory/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/peft/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/unsloth/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/nnsight/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/pyvene/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/saelens/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/05-data-processing/nemo-curator/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/05-data-processing/ray-data/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/grpo-rl-training/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/miles/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/openrlhf/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/simpo/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/slime/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/torchforge/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/trl-fine-tuning/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/verl/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/constitutional-ai/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/llamaguard/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/nemo-guardrails/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/prompt-guard/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/accelerate/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/deepspeed/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/megatron-core/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/pytorch-fsdp2/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/pytorch-lightning/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/ray-train/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/09-infrastructure/lambda-labs/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/09-infrastructure/modal/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/09-infrastructure/skypilot/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/awq/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/bitsandbytes/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/flash-attention/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/gguf/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/gptq/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/hqq/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/ml-training-recipes/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/11-evaluation/lm-evaluation-harness/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/11-evaluation/nemo-evaluator/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/llama-cpp/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/sglang/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/tensorrt-llm/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/vllm/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/mlflow/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/swanlab/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/tensorboard/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/weights-and-biases/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/a-evolve/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/autogpt/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/crewai/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/langchain/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/llamaindex/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/chroma/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/faiss/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/pinecone/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/qdrant/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/sentence-transformers/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/dspy/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/guidance/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/instructor/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/outlines/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/17-observability/langsmith/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/17-observability/phoenix/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/audiocraft/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/blip-2/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/clip/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/cosmos-policy/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/llava/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/openpi/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/openvla-oft/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/segment-anything/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/stable-diffusion/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/whisper/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/knowledge-distillation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/long-context/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/model-merging/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/model-pruning/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/moe-training/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/speculative-decoding/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/academic-plotting/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/21-research-ideation/brainstorming-research-ideas/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/21-research-ideation/creative-thinking-for-research/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/22-agent-native-research-artifact/compiler/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/22-agent-native-research-artifact/research-manager/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/colour-independence/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/flexible-typography/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/information-density/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/preference-audit/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/responsive-accessibility/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/responsive-review/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/simplified-views/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/specify/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/user-preference-respect/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/adaptive-personalisation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/assess-load/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/cognitive-load-assessment/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/contextual-help-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/error-prevention-recovery/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/focus-attention-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/memory-load-reduction/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/plain-language-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/review/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/simplify/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/wayfinding-navigation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/design-research/skills/behavioural-analytics/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/design-research/skills/qual-quant-triangulation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/audit/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/design-flow/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/feedback-and-status/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/gesture-alternatives/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/keyboard-navigation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/keyboard-review/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/motion-sensitivity/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/multi-modal-input/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/touch-target-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/voice-interaction/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-affordance/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-brand-consistency/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-color/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-composition/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-information-density/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-typography/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-visual-hierarchy/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/pm-frameworks/intended-vs-implemented/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/pm-frameworks/opportunity-solution-tree/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-nemo-gym-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-openenv-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-ors-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-verifiers-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/rl-env-from-description/{SKILL.md → ENTRY.md} +0 -0
package/docs/evidence.md
CHANGED
|
@@ -49,7 +49,7 @@ written path as an absolute real path, resolved against the call's cwd (`_abs_ta
|
|
|
49
49
|
now compares `target`, and a row without one (written before the field landed) is ignored by that
|
|
50
50
|
guard rather than matched by its spelling (audit M-6). Both writers write `tool` — `note_tool`, and opencode's
|
|
51
51
|
plugin, whose row carries the same field under the same empty-means-absent rule
|
|
52
|
-
(`hosts/opencode/plugins/tezgah.js:
|
|
52
|
+
(`hosts/opencode/plugins/tezgah.js:1282-1293`) — so no live host leaves it out. A row written *before*
|
|
53
53
|
the field landed names its tool only where the name survived in `detail` — an `unknown` row and an
|
|
54
54
|
MCP `external` row — so the one cause of an under-count is the corpus's age, and it shrinks as
|
|
55
55
|
sessions run. The append is one INSERT in autocommit (`hooks/tezgah_integrity.py::_append`,
|
|
@@ -115,17 +115,18 @@ a write tool is `edit`, a shell call is `verify` when its command matches the ch
|
|
|
115
115
|
| Kind | Written by | Read by |
|
|
116
116
|
|---|---|---|
|
|
117
117
|
| `turn` | `hooks/tezgah_integrity.py::note_turn`, from the prompt path | `hooks/tezgah_integrity.py::_turn_start`, scoping every turn rule; `hooks/tezgah_integrity.py::_claim_key` |
|
|
118
|
-
| `run`, `edit`, `verify`, `verify_ok`, `verify_fail`, `interrupted` | `hooks/tezgah_integrity.py::note_tool`, the call's own name in `tool`, on opencode the plugin writes these same kinds and the same field (`hosts/opencode/plugins/tezgah.js:
|
|
118
|
+
| `run`, `edit`, `verify`, `verify_ok`, `verify_fail`, `interrupted` | `hooks/tezgah_integrity.py::note_tool`, the call's own name in `tool`, on opencode the plugin writes these same kinds and the same field (`hosts/opencode/plugins/tezgah.js:1244-1322`) | the Stop rule's `worked` set `hooks/tezgah_integrity.py::WORK_KINDS`; `counters.steps` `hooks/tezgah_integrity.py::_counts`; `last_verify`/`partial_state`; the `--trend` tool histogram |
|
|
119
119
|
| `external`, `unknown` | `hooks/tezgah_integrity.py::note_tool` | the taint notice, via `source`; the `--trend` tool histogram; nothing counts them as work |
|
|
120
120
|
| `todo` | `hooks/tezgah_integrity.py::note_todo`, from `note_tool` for a todo call: omp `todo` (the bridge sends the list from the result's `details`), Claude and dsh `TodoWrite` (their PostToolUse matcher), opencode `todowrite` (the plugin's own `recordTodo`), Cursor `todo_write` and Codex `update_plan`, which arrive with no matcher. `open`, `ready` and `blocked` count the list, `detail` holds the ready items' heads, one per line, `taken` holds the in-progress items' heads, and `partial` marks a Cursor `merge: true` list | the `ready steps` and `open todo` Stop classes (`hooks/tezgah_integrity.py::ready_left`, `hooks/tezgah_integrity.py::open_left`) and the idle-wait warning (`hooks/tezgah_gate.py::ready_advice`) |
|
|
121
121
|
| `wait` | `hooks/tezgah_integrity.py::note_tool`, for omp's `wait` | `hooks/tezgah_gate.py::ready_advice`, which counts it as idle; nothing counts it as work |
|
|
122
122
|
| `ask` | `hooks/tezgah_gate.py::ask_advice`, for an omp `ask` or Claude AskUserQuestion call: `detail` holds the questions, cut; `questions` counts them and `defaults` the ones with a recommended option | nothing refuses on it; the row is the record of what the session asked |
|
|
123
123
|
| `grant` | `hooks/tezgah_context.py::context_for`, from each prompt's `user_grants` (`hooks/tezgah_context.py::user_grants`): `detail` holds the user's clause, `target` the outward class it covers (`push`, `release`, `publish`, `pr` or `all`), or `lift:<class>` when the prompt took it back | `hooks/tezgah_integrity.py::grants_in_force`, read by the `needless ask` Stop class and the ask-tool warning |
|
|
124
|
-
| `began` | the gate's allow path for a write or shell call `hooks/tezgah_gate.py::decision`; on opencode the plugin's before-hook when the core was not asked (`hosts/opencode/plugins/tezgah.js:
|
|
124
|
+
| `began` | the gate's allow path for a write or shell call `hooks/tezgah_gate.py::decision`; on opencode the plugin's before-hook when the core was not asked (`hosts/opencode/plugins/tezgah.js:2602-2618`) | `hooks/tezgah_integrity.py::unanswered`, behind a claim in the Stop rule and in `counters.unanswered` |
|
|
125
125
|
| `claim` | `hooks/tezgah_integrity.py::stop_reason`, only for a reply in the claim vocabulary - a completion or verification word (`DONE`/`VERIFIED`), blocked or allowed, or a refused claim about an external system's state (`_external_claim`) | `hooks/tezgah_integrity.py::counters` |
|
|
126
126
|
| `refusal` | `stop_reason`, for a blocked reply that claimed nothing - a work-only or a shape refusal - with the same `blocked: <class>` detail (row version 3) | `counters.refusals`, and `shape_blocked` for a shape class; never a claim; `NOT_TOOL_HOOK` lists it |
|
|
127
127
|
| `after_block` | `hooks/tezgah_integrity.py::stop_reason`, on a reply after this rule's own block (a turn holding a `blocked:` claim or refusal row) that is not refused again (`_record_only`) on Claude, Codex, Cursor and omp; `detail` is `would block: <class>`, `ok` or `no claim` | nothing yet: a record for the after-block observation window, not a claim and not a second `shape` row, so `counters` counts it neither as a claim nor as a reply; `NOT_TOOL_HOOK` lists it |
|
|
128
|
-
| `subagent_end` | `stop_reason(..., subagent=True)`, from Claude's SubagentStop (`hooks/hooks.json`)
|
|
128
|
+
| `subagent_end` | `stop_reason(..., subagent=True)`, from Claude's SubagentStop (`hooks/hooks.json`), Cursor's subagentStop `summary` and Droid's SubagentStop `task_result`; the evidence half only, never a block (ADR 011); `detail` as `after_block`'s | nothing yet: the rows plan 055 replays before a subagent end may block; `NOT_TOOL_HOOK` lists it. On Claude a subagent's tool rows sit in the parent's ledger, so until the agent key (plan 050) lands the row judges the parent's turn |
|
|
129
|
+
| `reply_unread` | Droid's, Command Code's and Copilot's Stop (`hosts/droid/hook.py::main`, `hosts/commandcode/hook.py::main`, `hosts/copilot/hook.py::main`) when the transcript yields no closing assistant text (`hosts/droid/hook.py::last_reply`, `hosts/copilot/hook.py::last_reply`); `detail` names the transcript, or says there was none. No such Stop event carries the reply, and an empty reply judged would pass any claim as "no claim", so the turn end is recorded and not judged | nothing yet; `NOT_TOOL_HOOK` lists it |
|
|
129
130
|
| `stop_spec` | nothing since plan 101. Plan 063's shadow wrote one per reply that left a claim or a refusal row: `agree`, `disagree` or `error`, and `fold` or `selector`. The fold it compared against is gone | nothing. `NOT_TOOL_HOOK` still lists it and the replay keeps it beside its claim (`hooks/tezgah_replay.py::SIDE_KINDS`), so an old ledger reads as it did |
|
|
130
131
|
| `deny`, `nudge` | the [gate](gate.md)'s `hooks/tezgah_gate.py::_deny`, first-nudge `hooks/tezgah_gate.py::decision` | `hooks/tezgah_integrity.py::counters` |
|
|
131
132
|
| `snapshot`, `rollback` | `hooks/tezgah_snapshot.py::_capture_one`, `hooks/tezgah_snapshot.py::restore` | `hooks/tezgah_integrity.py::_snapshot_hash`; no counter |
|
|
@@ -296,12 +297,31 @@ The checker is `_stop_block` (`hooks/tezgah_integrity.py::_stop_block`), reached
|
|
|
296
297
|
(`hosts/omp/hook.py::handle`) — all with `{"decision": "block", "reason": …}`, all inert outside a
|
|
297
298
|
[root](glossary.md#root) and under the `verify-off` [kill switch](glossary.md#kill-switch)
|
|
298
299
|
(`hooks/projects-stop.py::main`). Each of these hosts judges the reply after a block again.
|
|
300
|
+
The reply the rule judges is read through `reply_prose`
|
|
301
|
+
(`hooks/tezgah_integrity.py::reply_prose`). A string passes through. A host that hands over
|
|
302
|
+
a message object yields its `text` blocks, joined the way the model wrote them. A thinking
|
|
303
|
+
or tool block is left out. omp's `session_stop` carries `last_assistant_message` as the object
|
|
304
|
+
its `getLastAssistantMessage()` returns, and the bridge passed it through, so the rule judged
|
|
305
|
+
`str(dict)`: one line, no list items, diluted prose. Measured on
|
|
306
|
+
the owner's evidence database (2026-10-29): 1643 of 1656 omp `shape` rows of 45 days carried
|
|
307
|
+
`lines: 1`. Every other host wrote 209 multi-line rows of 231. Of the three days' refusals, 24
|
|
308
|
+
were `reply language` over such a row, and every line-shaped class read a text that had no
|
|
309
|
+
lines. The bridge now sends the text too
|
|
310
|
+
(`hosts/omp/tezgah-hook.ts.in`), but the core is where a host cannot repeat it (plan 143).
|
|
299
311
|
The re-ask budget is the core's (`_record_only`, `hooks/tezgah_integrity.py::_record_only`): at
|
|
300
312
|
most `STOP_REASKS` = 2 refusals in one user turn, and never two for one reason class. The count
|
|
301
313
|
comes from the turn's `blocked:` claim and refusal rows, not from the host's payload. The omp host
|
|
302
|
-
hands a block back as a queued message. Its prompt hook writes that text as a new `turn` row.
|
|
303
|
-
|
|
304
|
-
|
|
314
|
+
hands a block back as a queued message. Its prompt hook writes that text as a new `turn` row.
|
|
315
|
+
Gemini does the same: an AfterAgent deny comes back through BeforeAgent as the next prompt
|
|
316
|
+
(`hosts/gemini/hook.py::main`). A refusal row stores the key of its text as `reask`. A `turn` row with that key starts no new user
|
|
317
|
+
turn for the count (`_turn_refusals`, `hooks/tezgah_integrity.py::_turn_refusals`). Antigravity's
|
|
318
|
+
`continue` re-enters the loop with no prompt, so its first-invocation hook writes no `turn` row
|
|
319
|
+
while the ledger's last row is that refusal (`hosts/antigravity/hook.py::reentered`). A Goose Stop
|
|
320
|
+
block keeps the turn going with no new prompt and no host count, so its turn rows alone decide
|
|
321
|
+
(`hosts/goose/hook.py::main`). Amp's plugin continues a blocked turn with a user message that
|
|
322
|
+
starts with `[tezgah:stop]`. The plugin never sends that prompt as a `user_prompt`. So it writes
|
|
323
|
+
no `turn` row and grants nothing. The Stop rule then judges that turn with `stop_hook_active`
|
|
324
|
+
(`hosts/amp/tezgah-plugin.ts.in`). The omp host
|
|
305
325
|
caps the continuations it starts itself, but never a chain of blocks, so tezgah's count bounds that
|
|
306
326
|
chain. So a reply that fixes the first class but adds a new one gets one more refusal. A blocker
|
|
307
327
|
list with no evidence is such a new class. A reply after a block that is not refused writes one
|
|
@@ -310,7 +330,7 @@ while the turn holds no refusal of this rule. That reply gets no refusal and no
|
|
|
310
330
|
Stop hook may have blocked. The host's count rules only where the ledger cannot. A session with no
|
|
311
331
|
`turn` row allows one refusal per chain. A Cursor `loop_count` of 2 ends the chain. The opencode
|
|
312
332
|
host has no Stop rule and so no budget. Its plugin API has no end-of-turn hook with an output. The
|
|
313
|
-
`event` hook of `hosts/opencode/plugins/tezgah.js` only observes.
|
|
333
|
+
`event` hook of `hosts/opencode/plugins/tezgah.js` only observes. Fifteen triggers, in order, each naming its reason class (`_stop_block`
|
|
314
334
|
`hooks/tezgah_integrity.py::_stop_block`).
|
|
315
335
|
The first four judge how the reply is written (`_shape_block`, `hooks/tezgah_integrity.py::_shape_block`); the rest judge its evidence:
|
|
316
336
|
|
|
@@ -516,18 +536,71 @@ The four shape classes share their switches with the text they enforce: `adhd-of
|
|
|
516
536
|
(`hooks/tezgah_integrity.py::QUESTION_END`). Its paragraph names no recommended default, and
|
|
517
537
|
it names no step the ask policy keeps from a default (`hooks/tezgah_integrity.py::never_default`).
|
|
518
538
|
Such steps are a force push, a delete, production, a credential, a third party, or a spend
|
|
519
|
-
over `spend_cap`.
|
|
539
|
+
over `spend_cap`. Building a plan the reply wrote is one too
|
|
540
|
+
(`hooks/tezgah_integrity.py::PLAN_BUILD`). So is a last line that asks the owner to pick a
|
|
541
|
+
variant ("V4 mü V1 mi?"), to take a way around a tezgah refusal, or to decide about another
|
|
542
|
+
session's work (`hooks/tezgah_integrity.py::OWNER_CHOICE`, plan 136). The
|
|
543
|
+
class then refuses a process question: the packs' `ask.process`
|
|
520
544
|
shapes, such as "Başlayayım mı?", "shall I proceed?" and "which first?"
|
|
521
545
|
(`hooks/tezgah_integrity.py::PROCESS_ASK`). It also refuses a question about an outward
|
|
522
546
|
step the user granted this session (`hooks/tezgah_integrity.py::grants_in_force`). A question
|
|
523
547
|
about an outward step the user has not granted is the one the policy asks, so it passes. The
|
|
524
|
-
refusal says to take the step, or to move
|
|
548
|
+
refusal says to take the step, or to move a taste or intent fork into the approval batch
|
|
549
|
+
with a default. A class-F step waits for the answer. Under
|
|
525
550
|
`tr` it opens with "Bu soruyu sorma". `_residual_block` asks it after `residual work` and
|
|
526
551
|
before `ready steps` (`hooks/tezgah_integrity.py::needless_ask`). Unlike those two, it needs
|
|
527
|
-
no work in the turn, because a
|
|
552
|
+
no work in the turn, because a reply that ends on a bare "Başlayayım mı?" is its measured case.
|
|
528
553
|
The research line counted 33 process questions among 48 question endings in the owner's omp
|
|
529
554
|
transcripts. It refuses once per turn and counts like `residual work`
|
|
530
555
|
(`hooks/tezgah_integrity.py::LIST_BLOCKS`).
|
|
556
|
+
14. **handed step** — a turn that ran a command of its own ends by telling the reader to run
|
|
557
|
+
one (plan 142). The line names a command in backticks and addresses the reader as the one
|
|
558
|
+
who runs it: the packs' `ask.hand_over` shapes, "komutunu sen çalıştır", "çalıştırman
|
|
559
|
+
gerekiyor", "senin adımın", "please run", "your step:"
|
|
560
|
+
(`hooks/tezgah_integrity.py::handed_steps`). An answer about how something is done is not
|
|
561
|
+
one of them. "you can run `git config --global ...`" answers the question the reader
|
|
562
|
+
asked, and the review of this plan caught the wider wording refusing it. The turn must
|
|
563
|
+
hold a
|
|
564
|
+
`run`/`verify*` row (`hooks/tezgah_integrity.py::COMMAND_KINDS`). A turn that ran nothing
|
|
565
|
+
could not have run this either, which keeps the class inert on a host that sends no mode. A
|
|
566
|
+
read-only mode closes it outright: there every step waits for the approval. A table row and
|
|
567
|
+
a quoted line are not the
|
|
568
|
+
reply speaking, so the class skips them. The line stays the user's when it names an
|
|
569
|
+
outward step (`hooks/tezgah_integrity.py::outward_classes`), a class-F step
|
|
570
|
+
(`hooks/tezgah_integrity.py::never_default`), the owner's consent, tezgah's own install or a
|
|
571
|
+
`brew` step (`hooks/tezgah_integrity.py::OWNER_STEP`), or when it types its own blocker. The
|
|
572
|
+
refusal says to run each one and report what it printed. `_residual_block` asks it after
|
|
573
|
+
`needless ask` and before `ready steps`. A handover under a residual label ("Sonraki adım:")
|
|
574
|
+
belongs to `residual work`, which comes first. This class is the plain sentence that one
|
|
575
|
+
never saw. It refuses once per turn and counts like `residual work`
|
|
576
|
+
(`hooks/tezgah_integrity.py::LIST_BLOCKS`). Measured on the owner's top-level omp and Claude
|
|
577
|
+
transcripts (2026-10-29): of 3307 user turns, 27 replies handed the reader a command and no
|
|
578
|
+
class refused any of them. The shipped shapes refuse 9 of those turns, 8 of them a step the
|
|
579
|
+
session could have taken. Those eight are four `tezgah-task phase` moves, a local merge,
|
|
580
|
+
two "the next step is yours" and a server command that owes an ACCESS line. The ninth
|
|
581
|
+
quotes the gate's own refusal. The wider wording of the first two review rounds refused 40
|
|
582
|
+
turns and then 14, an answer about how a command is run among them.
|
|
583
|
+
15. **plan claim** — a first-person claim that a command or check ran, in a turn the host ran
|
|
584
|
+
in a read-only mode (plan 142).
|
|
585
|
+
The host sends the mode with the Stop payload: `permission_mode` on Claude, Command Code,
|
|
586
|
+
Qwen and Droid, and omp's extension sends `plan` from `ctx.sessionModes`. `plan` and Droid's
|
|
587
|
+
`spec` are the read-only ones (`hooks/tezgah_integrity.py::READ_ONLY_MODES`). Nothing could
|
|
588
|
+
run in such a turn, so the claim says what cannot have happened. `_stop_block` asks it right
|
|
589
|
+
after the tamper classes and before the
|
|
590
|
+
admission, since "doğrulanmadı" repairs an unverified claim and here there was nothing to
|
|
591
|
+
check. A check that passed in the turn anyway clears it, like any other
|
|
592
|
+
evidence: a host may allow a read-only command in the mode. The trigger is the packs'
|
|
593
|
+
`ask.ran_it` vocabulary (`hooks/tezgah_integrity.py::RAN_IT`) - "test ettim", "i ran the
|
|
594
|
+
suite". It is read through the question and negation filter a claim is read through
|
|
595
|
+
(`hooks/tezgah_integrity.py::_asserted`). The done and verified vocabularies are not the
|
|
596
|
+
trigger: a plan states its acceptance in those words ("Done when all tests pass", "testler
|
|
597
|
+
yeşil olunca"), and the review of this plan caught both refused. It counts
|
|
598
|
+
as a false completion. The same mode exempts `needless ask` and closes `handed step`
|
|
599
|
+
(`hooks/tezgah_integrity.py::_residual_block`): the approval question is what plan mode asks
|
|
600
|
+
for, and every step it names waits for that approval. Every row of such a turn carries
|
|
601
|
+
`mode`, so a replay judges it as the mode it ran in
|
|
602
|
+
(`hooks/tezgah_replay.py::build_corpus`). A host that sends no
|
|
603
|
+
mode reads as `default`, which is what every rule did before the field.
|
|
531
604
|
|
|
532
605
|
A past-time temporal spec decides classes 5–10 (`hooks/tezgah_stopspec.py::FORMULAS`,
|
|
533
606
|
plan 063). Seven formulas read ten row atoms (`ROW_ATOMS`) and the turn marker. The module compiles
|
|
@@ -556,11 +629,30 @@ whole session instead of the turn:
|
|
|
556
629
|
after the work, where the turn fold saw nothing to judge (audit M-2, INT-01).
|
|
557
630
|
- **A turn of reads.** The rule treats a turn of known reads as a turn with no work (plan 086,
|
|
558
631
|
S4). Each command in it is a known read: a program in `READ_ONLY_PROGRAMS` or a git read in
|
|
559
|
-
`GIT_READS`, with no option in `WRITING_OPTIONS`. `
|
|
632
|
+
`GIT_READS`, with no option in `WRITING_OPTIONS`. `printf -v` assigns a variable, so `-v` is
|
|
633
|
+
such an option. `sed`, `awk`, `uniq`, `gh` and `codegraph`
|
|
560
634
|
count with no writing script, one operand or a read verb. A `sqlite3` read-only open counts,
|
|
561
635
|
from the option or the database URI, and so does an `ssh` whose remote command is
|
|
562
636
|
such a read (`hooks/tezgah_integrity.py::_bookkeeping_command`). Any other command, a commit included,
|
|
563
|
-
keeps the turn worked and owes the check.
|
|
637
|
+
keeps the turn worked and owes the check. So does a word bash turns into more than it shows
|
|
638
|
+
(`hooks/tezgah_integrity.py::_shell_read`). A brace list (`BRACE_EXPANSION`) is two words:
|
|
639
|
+
`{-delete,-print}`. A `$` other than a plain `$name` or `${name}` counts too (`PLAIN_DOLLAR`).
|
|
640
|
+
`${x:--delete}` gives an option, and the arithmetic in `$[x]`, `$((x))` and `${a[x]}` runs a
|
|
641
|
+
`$( )` held in its value. A function definition runs its body with arguments no reader saw.
|
|
642
|
+
Plan 126 measured 4 of 6
|
|
643
|
+
live advice turns refused for reads in a loop
|
|
644
|
+
(`for f in $(find src -type f); do cat -n "$f"; done`). Now a reply that claims
|
|
645
|
+
nothing also ends such a turn. The reader counts a `for NAME in WORDS` loop, the `if`/`while`/`{`
|
|
646
|
+
words around reads and an unquoted `$( )` whose body reads (`loops=True`). A value they bind, or a
|
|
647
|
+
positional parameter, reaches only a reader with no writing option (`OPTION_FREE`). The loop name
|
|
648
|
+
is one lowercase letter: not `PATH` or `IFS`, and not a zsh name tied to a setting (`path`,
|
|
649
|
+
`fpath`, `status`). A done/tested claim over such a turn keeps the worked turn's fold. A build
|
|
650
|
+
(`npm run build > log`) is a check, never a read. It records as `verify`, or as `verify_ok` or
|
|
651
|
+
`verify_fail` when its status shows. A `set` of shell options (`set -o pipefail;`, `set -eu`)
|
|
652
|
+
counts as a read, because the contract asks a check line to open with it. A `set` with any other
|
|
653
|
+
word stays work (`SET_FLAGS`, `SET_NAMES`). `find ... | xargs sh -c '...'` stays work: the
|
|
654
|
+
reader does not follow a command string into `sh -c`. A command of `DETAIL_MAX` (200) characters
|
|
655
|
+
or more stays work too, because the ledger cut it and the rest is unread.
|
|
564
656
|
- **A bookkeeping turn after a pass.** A turn whose only rows are read-only or VCS-bookkeeping
|
|
565
657
|
commands ends without a fresh check, as long as nothing but bookkeeping ran after the session's
|
|
566
658
|
newest pass, the session fold above allows it, and the reply makes no external-state claim
|
|
@@ -653,7 +745,7 @@ line never asked. Three surfaces recognise a read, and they have to agree on the
|
|
|
653
745
|
bridge calls (`hosts/omp/hook.py::classify`), omp's own filter, which decides whether python hears about the
|
|
654
746
|
read at all (`hosts/omp/tezgah-hook.ts.in:227-264`, its catalogue the checkout `@HOOK@` names), and
|
|
655
747
|
opencode's plugin, which classifies in process because that host has no Python hook
|
|
656
|
-
(`hosts/opencode/plugins/tezgah.js:
|
|
748
|
+
(`hosts/opencode/plugins/tezgah.js:2214-2272`, its catalogue the host's own installed skill dir
|
|
657
749
|
(`dirname(CONFIG)/opencode/skills`), which `tezgah-setup` fills with every shipped skill).
|
|
658
750
|
|
|
659
751
|
Claude loads a skill through its `Skill` tool, never a read, so a Claude load used to leave no row.
|
|
@@ -675,7 +767,7 @@ still count through the two marks; and only the hosts that classify a read in pr
|
|
|
675
767
|
here, so the count is a floor, not a census. Which host records what, since this store is the
|
|
676
768
|
report's only source: **omp** (the extension's filter lets the read through,
|
|
677
769
|
`hosts/omp/tezgah-hook.ts.in:257-264`, and the hook classifies it, `hosts/omp/hook.py::classify`) and
|
|
678
|
-
**opencode** (the plugin classifies it, `hosts/opencode/plugins/tezgah.js:
|
|
770
|
+
**opencode** (the plugin classifies it, `hosts/opencode/plugins/tezgah.js:2256-2272`) record the mark
|
|
679
771
|
or `skill:<name>` for every shipped skill, in either form; **Claude** sees a read, but only in its
|
|
680
772
|
transcript, which feeds the status line and writes no row here (`statusline.py::claude_used`), so a Claude
|
|
681
773
|
session reads in this report as one that opened nothing - marks included; **codex**, **cursor** and
|
|
@@ -792,7 +884,7 @@ empty stand-in for the result body its bridge never sends, so a subagent's repor
|
|
|
792
884
|
cannot import the core in process and mirrors the control in JavaScript instead — the channel on the
|
|
793
885
|
call's own row, the label and the taint notice in front of the result the hook is handed, including
|
|
794
886
|
the `external` row an MCP answer or a fetched page earns (`untrustedSource`
|
|
795
|
-
`hosts/opencode/plugins/tezgah.js:
|
|
887
|
+
`hosts/opencode/plugins/tezgah.js:1971`, `labelResult` `:2022`, with the tier's argv reader
|
|
796
888
|
`tierRead` at `:1902`). The two halves are pinned against each other over a shared corpus, so neither
|
|
797
889
|
can move without failing the other's test (`tests/test_opencode_plugin.py::OpenCodePlugin.test_the_classifier_agrees_with_the_python_half_on_a_shared_corpus`). One difference is deliberate:
|
|
798
890
|
opencode's plugin writes that `external` row itself and carries the channel alone, since the UI rule
|
|
@@ -875,7 +967,7 @@ disagree with the number it is drawn from; both are off unless the flag asks, so
|
|
|
875
967
|
name at all - `classify` folded it into a kind - so an old corpus under-counts, which is the
|
|
876
968
|
honest ceiling and the reason the field exists; every row written since carries it, because both
|
|
877
969
|
writers write it (`hooks/tezgah_integrity.py::note_tool`, and opencode's plugin
|
|
878
|
-
`hosts/opencode/plugins/tezgah.js:
|
|
970
|
+
`hosts/opencode/plugins/tezgah.js:1282-1293` - before that second one did, an opencode work row was
|
|
879
971
|
the other half of this under-count, with its name unrecoverable in the command `detail`). A read
|
|
880
972
|
tool is not in it either: reads record no row by design.
|
|
881
973
|
- **The shipped programs** — `programs`, the `bin/` programs a command row really ran, read with the
|
package/docs/feature-audit.md
CHANGED
|
@@ -21,8 +21,8 @@ sourced to WAI-ARIA APG and WCAG 2.2.
|
|
|
21
21
|
It is reached the same way `product-analysis` is: the `product` task class arms the
|
|
22
22
|
rule (`hooks/tezgah_context.py::PROMPT_HINTS`), whose coherence paragraph
|
|
23
23
|
(`hooks/tezgah_policy.py::CORE`) names the feature unit and the matrices, and
|
|
24
|
-
`skills/product-analysis/SKILL.md:
|
|
25
|
-
`skills/tezgah-contract/SKILL.md:
|
|
24
|
+
`skills/product-analysis/SKILL.md:78` runs the coherence pass before its axes.
|
|
25
|
+
`skills/tezgah-contract/SKILL.md:743-755` carries the long form for a session that
|
|
26
26
|
reads the contract.
|
|
27
27
|
|
|
28
28
|
The unit is the feature, not the screen, and every interface element and every data
|
package/docs/gate.md
CHANGED
|
@@ -8,7 +8,10 @@ report, and for the session that has just met a refusal in its transcript. [arch
|
|
|
8
8
|
|
|
9
9
|
One function decides every refusal: `decision(tool, inp, cwd, session_id)` returns a reason string or `None`, and nothing else
|
|
10
10
|
(`hooks/tezgah_gate.py::decision`). It answers only inside a tezgah [root](glossary.md#root): outside one `root_for` returns nothing and every call passes
|
|
11
|
-
(`hooks/tezgah_gate.py::decision`).
|
|
11
|
+
(`hooks/tezgah_gate.py::decision`). A repository that commits `tezgah.owner` with `harness: excluded` is out of every root the same way. One that
|
|
12
|
+
says `tasks: off` keeps the root and turns off only the task rules. The record rule then holds no write to its own
|
|
13
|
+
plan files ([operations.md](operations.md#a-repository-that-is-not-this-harnesss)).
|
|
14
|
+
The `pretooluse-off` kill switch drops the whole gate (`hooks/tezgah_gate.py::decision`). `decision` binds the session first.
|
|
12
15
|
It reads every switch through the session latch ([contract.md](contract.md#how-a-rule-is-disarmed)).
|
|
13
16
|
|
|
14
17
|
Each host's pre-tool hook calls it and wraps the string in that host's own deny envelope — opencode's is its `tool.execute.before`, which throws
|
|
@@ -34,7 +37,7 @@ writes stays under `~/.cache/tezgah/replay`. The corpus, the exclusions and the
|
|
|
34
37
|
|---|---|---|
|
|
35
38
|
| claude, dsh | `hooks/projects-pretooluse.py::main` (`hosts/dsh/hooks.json:13-14`) | `hookSpecificOutput.permissionDecision: "deny"` |
|
|
36
39
|
| codex, cursor, omp | `hosts/codex/hook.py::main`, `hosts/cursor/hook.py::dispatch`, `hosts/omp/hook.py::handle` | that host's own envelope — [hosts.md](hosts.md) |
|
|
37
|
-
| opencode | `hosts/opencode/plugins/tezgah.js:
|
|
40
|
+
| opencode | `hosts/opencode/plugins/tezgah.js:2988` | `new Error(deny)` thrown at `hosts/opencode/plugins/tezgah.js:3152` |
|
|
38
41
|
|
|
39
42
|
Every refusal is also recorded before it is returned: `_deny` appends a ledger row `deny` whose `detail` is `"<rule>: <reason, first 80 chars>"`, plus any
|
|
40
43
|
`extra` (`hooks/tezgah_gate.py::_deny`). That row, not the reason wording, is where "why was this denied" is answered, and `<rule>` is the name used below.
|
|
@@ -80,7 +83,7 @@ it first after the root check (`decision` `hooks/tezgah_gate.py::decision`). The
|
|
|
80
83
|
| tezgah's configuration | all of `~/.config/tezgah` (`config.json`, `bin/`, `ponytail.level`, the `hook:<host>:...` rows of `contract.sha256`, ...) | any write |
|
|
81
84
|
| evidence and session state | the cache's `tezgah.db` (with its `-wal` and `-shm` files), `evidence/`, the `sessions/`, `switches/`, `gate-inactive/`, `harness-drift/` and `import-crash/` directories that database imports once, and `workspace-index.json`, in the global cache and the temp fallback (`hooks/tezgah_gate.py::CONTROL_CACHE`) | any write |
|
|
82
85
|
| hook wiring | the opencode plugin file, the omp hook, the Claude plugin copy, the install prefix, and the tree the hooks run from unless the session works inside it (`hooks/tezgah_gate.py::_registration`, `hooks/tezgah_gate.py::_install_trees`) | any write |
|
|
83
|
-
| shared registration files | `.claude/settings.json` and `settings.local.json`, `~/.claude/plugins/installed_plugins.json` and `known_marketplaces.json`, Codex's and Cursor's `hooks.json`, Codex's `config.toml` | a shell write; a write tool only when it changes an entry that is tezgah's - `statusLine`, `attribution`, `disableAllHooks`, a key or item naming tezgah (the user's own hook beside tezgah's in one matcher group stays theirs), or any `[hooks...]` line of `config.toml`, where the trust entries live (`hooks/tezgah_gate.py::_shared_change`) |
|
|
86
|
+
| shared registration files | `.claude/settings.json` and `settings.local.json`, `~/.claude/plugins/installed_plugins.json` and `known_marketplaces.json`, Codex's and Cursor's `hooks.json`, Codex's `config.toml`, Gemini's `settings.json`, Goose's `~/.config/goose/settings.json` | a shell write; a write tool only when it changes an entry that is tezgah's - `statusLine`, `attribution`, a key that turns hooks off (Claude's `disableAllHooks`, Gemini's `hooksConfig`; `hooks/tezgah_gate.py::OWNED_KEYS`), a key or item naming tezgah, such as `tezgah` in Goose's `disabledPlugins` (the user's own hook beside tezgah's in one matcher group stays theirs), or any `[hooks...]` line of `config.toml`, where the trust entries live (`hooks/tezgah_gate.py::_shared_change`) |
|
|
84
87
|
| repository marks and hooks | a `REPO_MARKS` name under a root, the session checkout's `.git/hooks` (a `.sample` file and a clone elsewhere pass), `git config core.hooksPath` set or unset there or `--global` | any write |
|
|
85
88
|
| | `.husky` | a delete, a chmod that takes a permission away, or a move |
|
|
86
89
|
| | a directory holding any protected path (`rm -rf ~/.cache`, `mv .git /tmp/x`), also through a link (`rm -rf link/`), including `.tezgah/plans/open/` itself, every ancestor of it (`rm -rf .tezgah`, `mv .tezgah/plans /tmp/x`) and a glob or brace directly under it (`rm -rf .tezgah/plans/open/*`) | a delete or move |
|
|
@@ -110,7 +113,7 @@ request is refused.
|
|
|
110
113
|
|
|
111
114
|
Trigger, shell: `--no-verify`, or `SKIP=`/`HUSKY_SKIP_HOOKS=`/`HUSKY=0`, next to a git/hook word; or a `core.hooksPath` assignment (`git -c core.hooksPath=...`, `git config core.hooksPath <dir>` with a quoted value too, `--config-env`, `GIT_CONFIG_KEY_n`/`GIT_CONFIG_PARAMETERS`) in the same command as a `git commit`/`git push` (`HOOKS_KEY`/`GIT_VALUE_OPTS`/`CONFIG_READS`/`ROUGH_WORDS` `hooks/tezgah_integrity.py::HOOKS_KEY`, `hooks/tezgah_integrity.py::GIT_VALUE_OPTS`, `hooks/tezgah_integrity.py::CONFIG_READS`, `hooks/tezgah_integrity.py::ROUGH_WORDS`, `hooks/tezgah_integrity.py::_shell_segments` reads the line word by word the way shlex does - an unquoted backtick ends a command (`hooks/tezgah_integrity.py::_unquoted_backticks`; one inside double quotes is read as data, the blind spot `mask` has) and a line shlex cannot read is read roughly rather than dropped - `hooks/tezgah_integrity.py::_hooks_redirect`; husky's standalone setup, a read or `--unset`, a hook install naming `pre-push`, and a commit message naming the key or the env var pass); or a verification command chained with `|| true`/`; true`
|
|
112
115
|
(`hooks/tezgah_integrity.py::_shortcut_command`, `hooks/tezgah_integrity.py::NO_VERIFY`, `hooks/tezgah_integrity.py::SKIP_ENV`, `hooks/tezgah_integrity.py::NEUTER`, `hooks/tezgah_integrity.py::GITISH`).
|
|
113
|
-
These shell predicates read the line through `mask()` (`hooks/tezgah_integrity.py::mask`), which blanks quotes and comments the way bash reads them. A URL's `//`, a word's `#`, a `/* */` glob pair and `'x\'` are words there, so they do not hide the command after them. The word reader takes a `$'...'` as one word and a `$( )` or backtick body as a command of its own (`hooks/tezgah_integrity.py::_for_shlex`). Trigger, edit/write: a skip marker newly
|
|
116
|
+
These shell predicates read the line through `mask()` (`hooks/tezgah_integrity.py::mask`), which blanks quotes and comments the way bash reads them. A URL's `//`, a word's `#`, a `/* */` glob pair and `'x\'` are words there, so they do not hide the command after them. The word reader takes a `$'...'` as one word and a `$( )` or backtick body as a command of its own (`hooks/tezgah_integrity.py::_for_shlex`). Every shell reader asks one rule for a comment and a line continuation (`hooks/tezgah_integrity.py::_opens_comment`, `hooks/tezgah_integrity.py::CONTINUATION`). A `#` opens a comment only at a word's start, so `x\ #`, `x\<newline>#` and `x\r#` hide nothing. A `)` that closes a substitution or an array is no word end either (`$(:)#`, `<(:)#`, `x=(a)#`, `hooks/tezgah_integrity.py::_kept`). A subshell's `(true)#` does open a comment. The readers drop a backslash-newline where bash drops it, so `-de\<newline>lete` reads as `-delete`. `mask()` moves it to its word's start, so its rules read `tr\<newline>ue` as `true` and `|\<newline>|` as `||`. A rule that slices the raw line reads it at the same offsets (`hooks/tezgah_integrity.py::joined`). The opencode mirror asks its port, `opensComment`. Trigger, edit/write: a skip marker newly
|
|
114
117
|
introduced into a test file — the path must match `tests?/`, `test_*`, `*_test`, `*.test.*` (`hooks/tezgah_integrity.py::TEST_PATH`), the marker must survive `mask_source()` so one
|
|
115
118
|
inside a string or comment does not count, and `_added` compares against the file's own text on disk for a `Write` (`hooks/tezgah_integrity.py::_added`, `hooks/tezgah_integrity.py::SKIP_TEST`). Every write dialect is read
|
|
116
119
|
through one reader (`hooks/tezgah_integrity.py::write_texts`, over `hooks/tezgah_taste.py::edit_text`): `new_string`/`newString`, `new_str`, `content`/`file_text`, `edits[]` and an `apply_patch` body, which is split per `*** Update File:`/`*** Add File:` header so the test-path gate and the count run per file (`hooks/tezgah_integrity.py::PATCH_FILE`). Told:
|
|
@@ -130,23 +133,24 @@ Passes: a line that opens with `set -o pipefail` (`hooks/tezgah_integrity.py::PI
|
|
|
130
133
|
(`verify_ok`/`verify_fail`, [evidence.md](evidence.md)); a redirect to a file; a pipe of anything that is not a check (`git log | head`). The
|
|
131
134
|
remedy is one sentence, `hooks/tezgah_integrity.py::PIPED_REMEDY`, which the always-on core and the contract skill quote too. Told: keep the check last with its output in a file, then read the file in a separate call, or open the line with `set -o pipefail;`. A `; tail` on the same line hands the status to `tail`. The refusal names the check as it was typed. Standing, under `verify-off`
|
|
132
135
|
(`hooks/tezgah_gate.py::decision`). opencode asks the core for this rule on any shell line that pipes a check
|
|
133
|
-
(`hosts/opencode/plugins/tezgah.js:
|
|
136
|
+
(`hosts/opencode/plugins/tezgah.js:3069-3073`) and records such a line as `verify` when a pipe or a later command owns its status (`statusHidden`, `hosts/opencode/plugins/tezgah.js:505`).
|
|
134
137
|
|
|
135
138
|
### Attribution — an AI/model credit on its way into an artifact
|
|
136
139
|
|
|
137
140
|
Trigger, shell: a write command (`hooks/tezgah_gate.py::WRITE_CMD` — `git commit|merge|tag|notes`, `gh api`,
|
|
138
141
|
`gh pr|issue|release create|edit|comment|review|merge|close`) carrying a credit form (`hooks/tezgah_gate.py::ATTRIB` — `co-authored-by:`, `generated with`, `made with`,
|
|
139
|
-
`built
|
|
142
|
+
a credit verb, `noreply@anthropic`, a robot emoji). A credit verb is `built`, `written`, `drafted` or a like verb, then `by`, `with` or `using`, then a model or vendor name. Trigger, edit/write: one of the content fields `EDIT_TEXT` (`hooks/tezgah_gate.py::EDIT_TEXT`)
|
|
140
143
|
containing a line that *starts* with a credit (`hooks/tezgah_gate.py::ATTRIB_LINE`). Told: remove it and re-run; naming a tool in order to use it is fine, crediting it
|
|
141
144
|
as author is not (`hooks/tezgah_gate.py::ATTRIB_DENY`). Standing. The line anchor is why prose that merely names the banned forms passes (`hooks/tezgah_gate.py::_CREDIT`).
|
|
142
145
|
The same twin as the shortcut rule's: a credit a heredoc writes into a file is refused from the body (`hooks/tezgah_gate.py::decision`), and no command has to be
|
|
143
146
|
a `git`/`gh` write for it to be this rule's. An MCP `write` or `publish` call meets `ATTRIB_LINE` over its payload text ([MCP](#mcp-a-servers-effect-tool)).
|
|
147
|
+
A folded `.tezgah` (`hooks/tezgah_research.py::folded`) makes `tezgah-research commit` write the project's own history with a message the gate never reads in the command. The CLI runs it through this rule's reader, `hooks/tezgah_gate.py::ATTRIB`, and the language rule's (`hooks/tezgah_lang.py::refusal`, under `lang-off`) before committing. It prints the same refusal, with exit 2 and nothing committed (`bin/tezgah-research::message_refusal`).
|
|
144
148
|
|
|
145
149
|
### Language — an identifier or message that is not English
|
|
146
150
|
|
|
147
|
-
Trigger, shell: a command that would create an identifier - `git checkout -b`/`git switch -c`, `git branch` with a new name, a commit subject (`git commit -m`/`--message`/`-F`), or a `gh pr|issue create --title` (the language section `hooks/tezgah_gate.py
|
|
151
|
+
Trigger, shell: a command that would create an identifier - `git checkout -b`/`git switch -c`, `git branch` with a new name, a commit subject (`git commit -m`/`--message`/`-F`), or a `gh pr|issue create --title` (the language section `hooks/tezgah_gate.py::lang_reason`, `hooks/tezgah_gate.py::BRANCH_NEW`, `hooks/tezgah_gate.py::COMMIT_MSG`, `hooks/tezgah_gate.py::GH_NEW`, `hooks/tezgah_gate.py::created_texts`; the text is read from the raw command, because `mask()` blanks quoted strings and a commit subject is one) - whose name or subject is **not English**: a letter outside ASCII anywhere (`hooks/tezgah_lang.py::non_english` - a predicate rather than one language's letter list, so Russian, Greek, Arabic, Chinese and accented Latin hit it exactly as Turkish does) or an ASCII-folded Turkish word from the curated list (`hooks/tezgah_lang.py::ENGLISH`, wi…
|
|
148
152
|
|
|
149
|
-
The rule is a **heuristic** and its own text says so: a word list is not a language detector, so it cannot tell a proper noun or a product name in another language from a word that ought to be English, and a listed word may be the user's own term. A command that only names the words - `echo`, `grep`, `git log --grep` - creates nothing and passes. An identifier outlives the session that typed it, which is the reason the rule exists at all: `plan/004-admin-durum-onarimi` is in a public history from the moment it exists. On **opencode** the rule is not ported: the plugin asks the core for it through `bin/tezgah-gate check`, one spawn for a command its pre-test reads as identifier-creating (`IDENT_CMD` `hosts/opencode/plugins/tezgah.js:
|
|
153
|
+
The rule is a **heuristic** and its own text says so: a word list is not a language detector, so it cannot tell a proper noun or a product name in another language from a word that ought to be English, and a listed word may be the user's own term. A command that only names the words - `echo`, `grep`, `git log --grep` - creates nothing and passes. An identifier outlives the session that typed it, which is the reason the rule exists at all: `plan/004-admin-durum-onarimi` is in a public history from the moment it exists. On **opencode** the rule is not ported: the plugin asks the core for it through `bin/tezgah-gate check`, one spawn for a command its pre-test reads as identifier-creating (`IDENT_CMD` `hosts/opencode/plugins/tezgah.js:632`, the call site `hosts/opencode/plugins/tezgah.js:3069-3073`).
|
|
150
154
|
|
|
151
155
|
Off: `lang-off`, the rule's own switch (`hooks/tezgah_gate.py::decision`), and `pretooluse-off` drops it with the whole gate.
|
|
152
156
|
|
|
@@ -201,7 +205,9 @@ checkpoint that is a plain sha (the boundary is already real), a `pending` with
|
|
|
201
205
|
|
|
202
206
|
### Workspace — tezgah state outside `.tezgah/`
|
|
203
207
|
|
|
204
|
-
Trigger: a write tool, or a shell redirect/`tee` (`write_paths`), whose target relative to the repo root starts with `plans/`, `research/` or `analysis/` while the project tracks no file under that directory (`workspace_reason`, `hooks/tezgah_gate.py`). The refusal names `.tezgah/<kind>/` as the place to write. A directory the project already tracks is its own and passes. `mkdir` and positional shell targets (`cp`, `mv`) are not read - the same ceiling as `write_paths`. Off: `workspace-off`.
|
|
208
|
+
Trigger: a write tool, or a shell redirect/`tee` (`write_paths`), whose target relative to the repo root starts with `plans/`, `research/` or `analysis/` while the project tracks no file under that directory (`workspace_reason`, `hooks/tezgah_gate.py`). The refusal names `.tezgah/<kind>/` as the place to write. It also names the commit form for the workspace's shape (`hooks/tezgah_research.py::folded`). An own repository gets `git -C .tezgah` (`hooks/tezgah_gate.py::WORKSPACE_OWN`). A folded one the project tracks gets its own `git add`/`git commit` (`hooks/tezgah_gate.py::WORKSPACE_FOLDED`). A directory the project already tracks is its own and passes. `mkdir` and positional shell targets (`cp`, `mv`) are not read - the same ceiling as `write_paths`. Off: `workspace-off`.
|
|
209
|
+
|
|
210
|
+
A second trigger under the same switch: a write under a dot dir directly below `.tezgah/research/`, such as `.tezgah/research/.staging/x/state.json` (`hooks/tezgah_gate.py::research_hidden_reason`). It is read against the main checkout and against the session's own root. `slugs()` skips dot dirs, so a line there is invisible to `status` and `check`. The refusal says a refused line goes to the owner (`hooks/tezgah_gate.py::RESEARCH_HIDDEN_DENY`). `open/`, `done/` and a dot file directly in `research/` pass.
|
|
205
211
|
|
|
206
212
|
### Secret — a credential on its way into a file
|
|
207
213
|
|
|
@@ -250,9 +256,10 @@ nothing, and Orca's `r1z4x/<slug>` branches bind by declaration. The task rule h
|
|
|
250
256
|
declares. The count folds the turn's own write rows (`hooks/tezgah_integrity.py::turn_rows`) together with the files the call in hand names, so it needs no state of its own, and it counts DISTINCT
|
|
251
257
|
paths - a turn that rewrites one file three times is still one file's work. A product path is any path in the checkout, whatever the project's layout (`apps/`, `packages/`, `.maestro/` count as
|
|
252
258
|
`hooks/` does). Tezgah's and git's own state does not count: `.tezgah/`, `.codegraph/` and `.git/` (`hooks/tezgah_gate.py::PLAN_SKIP`). Neither does a host's generated `agents/` set
|
|
253
|
-
(`hooks/tezgah_gate.py::PLAN_AGENT_HOSTS`). A path outside any git repository never counts. Told: the branch it read, how many files the turn has written, and
|
|
254
|
-
the command that opens a plan - the `plan-add` skill, `/tezgah:plan-add <description>` (`hooks/tezgah_gate.py::PLAN_DENY`).
|
|
255
|
-
<branch>` writes the plan's `branch:` (`bin/tezgah-task::cmd_start`).
|
|
259
|
+
(`hooks/tezgah_gate.py::PLAN_AGENT_HOSTS`). A path outside any git repository never counts. Nor does a path that names no file on this disk: a URI such as `agent://<id>` or `local://x.md`, or a `file://` URL naming another host. A local `file://` URL counts as the file it names, in the checkout that holds that file. The writer stores that file as the row's `target`, and any other URI's own spelling. The race guard compares that spelling, and this rule skips it (`hooks/tezgah_integrity.py::file_url_path`). Told: the branch it read, how many files the turn has written, and
|
|
260
|
+
the command that opens a plan - the `plan-add` skill, `/tezgah:plan-add <description>` (`hooks/tezgah_gate.py::PLAN_DENY`). Off the trunk it also names the bind route: `tezgah-task start NNN
|
|
261
|
+
--phase P --branch <branch>` writes the plan's `branch:` (`hooks/tezgah_gate.py::PLAN_BIND`, `bin/tezgah-task::cmd_start`). On `main` or `master` it names only the `plan/NNN-slug` route or
|
|
262
|
+
another branch an open plan declares (`hooks/tezgah_gate.py::PLAN_BIND_TRUNK`). `cmd_start` refuses `--branch main` or `--branch master` too. The record rule refuses a hand edit of a phased record. Standing: only changing the tree's state changes it - the
|
|
256
263
|
work moves to the `plan/NNN-slug` branch the skill creates or to a bound branch (a one- or two-file fix is free either way), or the repository carries a `.no-plan-gate` mark (the shape of
|
|
257
264
|
`.no-graph` and `.no-lessons`). It passes while a merge or rebase is in progress (`MERGE_HEAD`, `rebase-merge/` or `rebase-apply/` in the checkout's gitdir, `hooks/tezgah_gate.py::_merging`):
|
|
258
265
|
resolving conflicts is not new work. It passes wherever the question cannot be answered: no session or ledger, a directory that is not a git repository, and a detached HEAD with no branch to name.
|
|
@@ -301,7 +308,11 @@ Codex and Cursor read it with their PostToolUse result (`hosts/codex/hook.py`, `
|
|
|
301
308
|
|
|
302
309
|
Trigger: 25 work rows (`hooks/tezgah_gate.py::DRIFT_STEPS`) in the current user turn and an effectful call — a write tool, or a git/gh artifact command (`effectful`
|
|
303
310
|
`hooks/tezgah_gate.py::effectful`). An MCP call of any verb class counts as an effectful call too. Told: the standing constraints re-stated, or the delta since the turn began; "re-issue this call unchanged and carry on" (`hooks/tezgah_gate.py::DRIFT_DENY`,
|
|
304
|
-
`hooks/tezgah_gate.py::drift_reason`). A refusal, last in `decision` after every other rule
|
|
311
|
+
`hooks/tezgah_gate.py::drift_reason`). A refusal, last in `decision` after every other built-in rule. Only a repository's own rule runs after it ([Adding a rule](#a-repositorys-own-rule)). Its only delivery: no host's PostToolUse side carries it, and opencode gets it from the core through `bin/tezgah-gate` on its write path. Once per turn: the `drift` mark is written *before* the refusal, so the identical call passes on the next attempt. The count behind it is the turn's own — a bounded read (`hooks/tezgah_gate.py::DRIFT_TAIL`) falls back to the turn's own start (`hooks/tezgah_integrity.py::turn_rows`) when the turn outgrew the window. Governed by `reminder-off`, not `verify-off` (`hooks/tezgah_gate.py::drift_reason`).
|
|
312
|
+
|
|
313
|
+
### Repo-rule — a repository's own `.tezgah/gate.py` refuses the call
|
|
314
|
+
|
|
315
|
+
Trigger: the repository's rule file, in the git index, answers `{"deny": "<reason>"}` for this call (`hooks/tezgah_gate.py::repo_rule_reason`). Told: that reason, capped at 600 characters, inside a label naming it repository-supplied (`hooks/tezgah_gate.py::REPO_RULE_DENY`). Last in `decision`, after every built-in refusal. A timeout, a non-zero exit or malformed output allows. Off with `pretooluse-off`, or `TEZGAH_REPO_RULE=0` in the environment. The contract is [A repository's own rule](#a-repositorys-own-rule).
|
|
305
316
|
|
|
306
317
|
### Ask — an ask-tool question with no recommended option
|
|
307
318
|
|
|
@@ -328,7 +339,7 @@ Read this before filing a security-ish issue; each is a decision, not an oversig
|
|
|
328
339
|
A grant the user writes in chat ("bana sormadan pushla") lifts the ask for its class. Outward commands still run with no refusal.
|
|
329
340
|
- A write inside the root after a fetch: left to the taint notice that `hooks/tezgah_untrusted.py` rides the first effect with, because it is recoverable from
|
|
330
341
|
the snapshot.
|
|
331
|
-
- `grep -A 3 foo`: a flag with its own value shifts the token, so the search passes unnudged (`hooks/tezgah_gate.py
|
|
342
|
+
- `grep -A 3 foo`: a flag with its own value shifts the token, so the search passes unnudged (`hooks/tezgah_gate.py::BASH_SEARCH`).
|
|
332
343
|
- A foreign `apply_patch` write: the PostToolUse writer records no path for that row (`hooks/tezgah_gate.py::write_paths`); and the guard skips a row an older writer left with no
|
|
333
344
|
`target`, because that row names no file (`hooks/tezgah_integrity.py::writers_elsewhere`).
|
|
334
345
|
- Which rule the user meant when a turn drifts: "a guess about intent wearing a check's clothes" (`hooks/tezgah_gate.py::drift_reason`).
|
|
@@ -373,17 +384,17 @@ widen a list a regex already covers.
|
|
|
373
384
|
## The mirror: the opencode plugin
|
|
374
385
|
|
|
375
386
|
opencode cannot run Python hooks, so `hosts/opencode/plugins/tezgah.js` is an independent JavaScript re-implementation of the same rules, dispatched from
|
|
376
|
-
`tool.execute.before` (hosts/opencode/plugins/tezgah.js:
|
|
377
|
-
`SKIP_ENV` hosts/opencode/plugins/tezgah.js:
|
|
387
|
+
`tool.execute.before` (hosts/opencode/plugins/tezgah.js:2988, exported `hosts/opencode/plugins/tezgah.js:2936`) in the gate's own order (`hosts/opencode/plugins/tezgah.js:2988-3153`); its shortcut constants restate the same regexes (`NEUTER` `hosts/opencode/plugins/tezgah.js:314`,
|
|
388
|
+
`SKIP_ENV` hosts/opencode/plugins/tezgah.js:315, `NO_VERIFY` hosts/opencode/plugins/tezgah.js:316, `GITISH` hosts/opencode/plugins/tezgah.js:317, `SKIP_TEST` hosts/opencode/plugins/tezgah.js:575). What keeps the two halves honest is a test, not a shared module:
|
|
378
389
|
`tests/test_opencode_plugin.py` drives the plugin's hooks through a node harness with a throwaway HOME, and imports the Python `tezgah_integrity.call_id` so a
|
|
379
|
-
separator or canonical-form drift in the action id fails there instead of silently in a session (`tests/test_opencode_plugin.py:1-7`, `tests/test_opencode_plugin.py:
|
|
380
|
-
|
|
381
|
-
The shell rule kinds mirrored last are each pinned in both suites: the shell's write body (`SHELL_WRITE` `hosts/opencode/plugins/tezgah.js:
|
|
382
|
-
`heredocBodies` `hosts/opencode/plugins/tezgah.js:
|
|
383
|
-
`hosts/opencode/plugins/tezgah.js:
|
|
384
|
-
ordering obligation (`COMMIT_CMD` `hosts/opencode/plugins/tezgah.js:
|
|
385
|
-
`hosts/opencode/plugins/tezgah.js:
|
|
386
|
-
`hosts/opencode/plugins/tezgah.js:
|
|
390
|
+
separator or canonical-form drift in the action id fails there instead of silently in a session (`tests/test_opencode_plugin.py:1-7`, `tests/test_opencode_plugin.py:27-30`, `tests/test_opencode_plugin.py::OpenCodePlugin.test_the_id_is_the_hash_the_python_writer_computes`).
|
|
391
|
+
|
|
392
|
+
The shell rule kinds mirrored last are each pinned in both suites: the shell's write body (`SHELL_WRITE` `hosts/opencode/plugins/tezgah.js:1039`,
|
|
393
|
+
`heredocBodies` `hosts/opencode/plugins/tezgah.js:1045`, `shellWriteBody` `hosts/opencode/plugins/tezgah.js:1078`, the shortcut and attribution twins at
|
|
394
|
+
`hosts/opencode/plugins/tezgah.js:3043-3044` and `hosts/opencode/plugins/tezgah.js:2010`, the credential twin at `hosts/opencode/plugins/tezgah.js:1970-1974`) and the
|
|
395
|
+
ordering obligation (`COMMIT_CMD` `hosts/opencode/plugins/tezgah.js:1899`, `ORDER_DENY`
|
|
396
|
+
`hosts/opencode/plugins/tezgah.js:1901`, `lastVerify` `hosts/opencode/plugins/tezgah.js:1911`, `orderReason` `hosts/opencode/plugins/tezgah.js:1936`, dispatched at
|
|
397
|
+
`hosts/opencode/plugins/tezgah.js:3084-3087`). `lastVerify` folds the tail exactly as `_last_verify` does, minus the `passing_check` narrowing - this rule reads only
|
|
387
398
|
`fail`, and a row that narrowing would refuse reads `ok`/`ran` on both sides, so the outcome is identical.
|
|
388
399
|
|
|
389
400
|
The control rule has no JavaScript copy. The plugin's `CONTROL_CMD` pre-test picks the shell lines that could touch the control plane. The plugin puts each
|
|
@@ -410,17 +421,18 @@ rule's triggers are the classes `_stop_block` returns, the four `_shape_block` h
|
|
|
410
421
|
| `shortcut` | E7c: with the write tools refused, 3 of 25 armed runs wrote a test skip through a heredoc | an internal benchmark (block E7, not published) | `tests/test_gate.py::test_a_shell_write_that_disables_a_test_is_denied` |
|
|
411
422
|
| `piped` | a real omp session: 13 checks ran piped and 3 of 6 completion claims were blocked | the Piped section above | `tests/test_gate.py::test_a_piped_check_is_refused_and_pipefail_passes` |
|
|
412
423
|
| `attribution` | E7c: the same 3 of 25 runs, a credit written through a heredoc | an internal benchmark (block E7, not published) | `tests/test_gate.py::test_attribution_denies_a_credit_written_by_the_shell` |
|
|
413
|
-
| `lang` | a plan branch was created as `plan/004-admin-durum-onarimi`, and its slug is in the public history for good | `hooks/tezgah_gate.py
|
|
414
|
-
| `race` | two sessions on one file - a parent and its subagent, or two worktrees - landing on a stale read | `hooks/tezgah_gate.py
|
|
424
|
+
| `lang` | a plan branch was created as `plan/004-admin-durum-onarimi`, and its slug is in the public history for good | the comment above `hooks/tezgah_gate.py::BRANCH_NEW` | `tests/test_gate.py::test_a_turkish_branch_name_is_refused` |
|
|
425
|
+
| `race` | two sessions on one file - a parent and its subagent, or two worktrees - landing on a stale read | the comment above `hooks/tezgah_gate.py::RACE_WINDOW_MIN` | `tests/test_gate.py::test_a_write_to_a_file_another_session_wrote_is_refused` |
|
|
415
426
|
| `lease` | plan 086 wave 1: two slices wrote into the main checkout through relative paths; 24 sibling race refusals in real transcripts, all in a shared worktree, tree or record | the Lease section above | `tests/test_gate.py::test_a_sibling_slices_lease_refuses_its_file_and_frees_the_owner` |
|
|
416
427
|
| `task` | E7: with the unlocking command printed, an armed arm removed or disabled the gate in 25 of 25 runs; E7b: the heredoc redirect in 3 of 25 | the Task section above (the checkpoint refusal) | `tests/test_gate.py::test_a_reading_phase_refuses_a_write_inside_the_allowlist` |
|
|
417
428
|
| `secret` | E7c: the same 3 of 25 runs, a key written through a heredoc | an internal benchmark (block E7, not published) | `tests/test_gate.py::test_a_credential_written_by_a_heredoc_is_denied` |
|
|
418
|
-
| `workspace` | sessions wrote root `plans/`, `research/` and `analysis/` (observed across several unrelated projects on one machine) | `hooks/tezgah_gate.py
|
|
419
|
-
| `plan` | a turn wrote four product files - a hook, its tests, its docs and the changelog - straight onto `main` | `hooks/tezgah_gate.py
|
|
429
|
+
| `workspace` | sessions wrote root `plans/`, `research/` and `analysis/` (observed across several unrelated projects on one machine) | the comment above `hooks/tezgah_gate.py::WORKSPACE_KINDS` | `tests/test_gate.py::test_untracked_root_kinds_are_refused_for_tools_and_redirects` |
|
|
430
|
+
| `plan` | a turn wrote four product files - a hook, its tests, its docs and the changelog - straight onto `main` | the comment above `hooks/tezgah_gate.py::PLAN_TRUNKS` | `tests/test_gate.py::test_the_third_product_write_on_main_is_refused` |
|
|
420
431
|
| `order` | FAVA: the shape found in 90% of real agent-instruction projects ("do not commit before running the tests") | the Ordering section above | `tests/test_gate.py::test_a_commit_is_refused_while_the_newest_check_failed` |
|
|
421
432
|
| `loop` | designed | the turn's own repeated failure; no incident recorded | `tests/test_gate.py::test_an_identical_failed_call_is_denied_after_the_ceiling` |
|
|
422
433
|
| `retry` | designed | the session ceiling over the same guard; no incident recorded | `tests/test_gate.py::test_a_fourth_identical_call_is_refused_whatever_the_outcome` |
|
|
423
|
-
| `drift` | an internal plan's flip rule on the 2026-09-20 move to a result-channel notice: at 27 sessions the blocked-claim rate in turns under 25 work rows read 112/140 = 0.8000, against 59/142 = 0.4155 before |
|
|
434
|
+
| `drift` | an internal plan's flip rule on the 2026-09-20 move to a result-channel notice: at 27 sessions the blocked-claim rate in turns under 25 work rows read 112/140 = 0.8000, against 59/142 = 0.4155 before | an internal plan (not published) | `tests/test_gate.py::test_a_long_turn_restates_the_constraints_before_a_write` |
|
|
435
|
+
| `repo-rule` | designed | a repository's own refusal through the extension seam (plan 124), no incident recorded | `tests/test_gate.py::test_a_repo_rule_denies_its_call_and_allows_the_rest` |
|
|
424
436
|
| `evidence tampered` | a terminated garbage line made `_parse` raise, and the guard then failed the Stop rule open for the turn; corrupting a `verify_fail` row was an allow route. A `verify_ok` appended with `python3 -c` licensed a claim (security-03), so a pass with no `began` row is an orphan (`hooks/tezgah_integrity.py::_pair`) | `hooks/tezgah_integrity.py::_parse` | `tests/test_integrity.py::test_a_damaged_ledger_blocks_a_done_claim_as_evidence_tampered` |
|
|
425
437
|
| `check failed` | designed | the newest check failing is its own class; no incident recorded | `tests/test_integrity.py::test_failed_check_blocks` |
|
|
426
438
|
| `partial failure` | designed | a failure the turn never resolved; no incident recorded | `tests/test_integrity.py::test_an_unresolved_failure_blocks_even_after_an_earlier_pass` |
|
|
@@ -433,15 +445,17 @@ rule's triggers are the classes `_stop_block` returns, the four `_shape_block` h
|
|
|
433
445
|
| `open todo` | the owner's report (2026-10-12, plan 097 item 2): `ready_left` counted only `pending` items, so a done claim over an `in_progress` todo item ended the turn | `hooks/tezgah_integrity.py::open_left` | `tests/test_integrity.py::test_a_done_claim_over_an_in_progress_todo_is_refused_once` |
|
|
434
446
|
| `needless ask` | research line `orchestrator-flow-audit` S3: 33 of 48 final replies that ended on a question in the owner's omp transcripts were process questions ("Başlayayım mı?"), and 9 of 47 next prompts were a bare "devam" or "evet" | `hooks/tezgah_integrity.py::needless_ask` | `tests/test_integrity.py::test_a_process_question_at_the_end_is_refused_once` |
|
|
435
447
|
| `stopped slice` | measured 2026-10-11 (research line `subagent-resume-orchestration`): 118 of 1413 omp subagent runs ended stopped, and in the newest 20 the parent absorbed the work inline 16 times instead of resuming it | `hooks/tezgah_integrity.py::_stopped_slice` | `tests/test_integrity.py::test_a_stopped_slice_of_this_session_refuses_the_turn_once` |
|
|
448
|
+
| `handed step` | measured 2026-10-29 on the owner's top-level omp and Claude transcripts: of 3307 user turns, 27 replies handed the reader a command in backticks and no class refused any of them; the `needless ask` refusal pushes the same step out of a question and into prose. The shipped shapes refuse 9 of those turns, 8 a real handover; the two review rounds of plan 142 cut the wordings that refused an answer about how a command is run | `hooks/tezgah_integrity.py::handed_steps` | `tests/test_integrity.py::test_a_handed_step_is_refused_once` |
|
|
449
|
+
| `plan claim` | probe 2026-10-29: a read-only plan turn whose reply claimed "test ettim" ended the turn, because every evidence class needs a work row and plan mode produces none; the same mode's approval question was refused as `needless ask`. The trigger is the first-person run claim alone: review round 2 found the done and verified vocabularies refusing a plan's own acceptance line | `hooks/tezgah_integrity.py::RAN_IT` | `tests/test_integrity.py::test_a_done_claim_in_plan_mode_is_refused` |
|
|
436
450
|
| `placating opener` | designed | output rule 10 read at the Stop event; no incident recorded | `tests/test_integrity.py::test_sycophantic_opener_blocks` |
|
|
437
451
|
| `forbidden closer` | designed | output rule 10 read at the Stop event; no incident recorded | `tests/test_integrity.py::test_a_closer_from_the_skills_own_list_blocks` |
|
|
438
452
|
| `list cap` | designed | output rule 8 read at the Stop event; no incident recorded | `tests/test_integrity.py::test_a_list_over_the_cap_blocks_with_its_size` |
|
|
439
|
-
| `reply language` | measured 2026-09-19: the 161 final replies the claim vocabulary was read off | `hooks/tezgah_integrity.py
|
|
453
|
+
| `reply language` | measured 2026-09-19: the 161 final replies the claim vocabulary was read off | `hooks/tezgah_integrity.py::DONE` | `tests/test_integrity.py::test_english_prose_blocks_and_names_the_language` |
|
|
440
454
|
|
|
441
455
|
## Adding a rule
|
|
442
456
|
|
|
443
457
|
1. Write the check inside `decision` (`hooks/tezgah_gate.py::decision`). A rule is a function returning a `str` reason or `None`; keep an argument-shaped rule
|
|
444
|
-
above the repeat guards (`hooks/tezgah_gate.py::decision`) — the drift refusal stays last,
|
|
458
|
+
above the repeat guards (`hooks/tezgah_gate.py::decision`) — the drift refusal stays last among the built-in rules, followed only by the repo rule below — and put its constants beside its own section.
|
|
445
459
|
A citation into this file names its symbol, so moving code inside it shifts nothing. Renaming or removing a cited symbol does, and `bin/tezgah-docs --citations`
|
|
446
460
|
flags it - re-run it in the same pass as the suite and re-anchor what it flags.
|
|
447
461
|
2. Return through `_deny(session_id, "<rule>", reason, tool, inp, base)` so the ledger counts the refusal (`hooks/tezgah_gate.py::_deny`); gate it on the kill switch it belongs
|
|
@@ -457,12 +471,25 @@ rule's triggers are the classes `_stop_block` returns, the four `_shape_block` h
|
|
|
457
471
|
A host gets the call only when its own matcher routes that name (`hooks/hooks.json`, `hosts/dsh/hooks.json`, `hosts/codex/hooks.json`, `hosts/cursor/hooks.json`,
|
|
458
472
|
omp's `GATED` list). A cell that disagrees with the core fails the suite. The corpus may name it a ceiling, with the plan that closes it. A ceiling that agrees fails too.
|
|
459
473
|
|
|
474
|
+
### A repository's own rule
|
|
475
|
+
|
|
476
|
+
A repository adds a refusal without editing the harness: it commits a Python file at `<repo>/.tezgah/gate.py`, run with the gate's own interpreter (`hooks/tezgah_gate.py::repo_rule_reason`).
|
|
477
|
+
The gate finds it with the status line's walk - nearest above the call's cwd, at most `MAX_WALK` levels, never above the configured root (`hooks/tezgah_gate.py::repo_rule_path`). A repo without one pays one `isfile` per level and no fork. Both it and the manifest are control plane (`hooks/tezgah_gate.py::_target_label`): the session stages them and the user's own terminal owns them.
|
|
478
|
+
The file runs only when it is in the git index of the repository that holds its directory - the project's, or the workspace's own `.tezgah` repository (`git ls-files --error-unmatch`, `hooks/tezgah_gate.py::_indexed`). An uncommitted drop is inert, and staging it is enough.
|
|
479
|
+
The file runs as a bounded child in the repo root, with one JSON object on stdin: `{"api": 1, "event": "pretool", "cwd", "repo_root", "session_id", "tool", "input"}` (the extension envelope, `hooks/tezgah_extension.py::call_envelope`, plus the call).
|
|
480
|
+
It answers `{"deny": "<reason>"}` on stdout to refuse, and nothing to allow. The reason reaches the agent cut to 600 characters (`hooks/tezgah_gate.py::REPO_RULE_CAP`). It opens with `Repository-supplied rule:`. A line then says the text is the repository's data, not tezgah's instruction (`hooks/tezgah_gate.py::REPO_RULE_DENY`). The labelled text leaves a `deny` row under `repo-rule`.
|
|
481
|
+
Fail-open: a non-zero exit, a timeout (1000 ms, `hooks/tezgah_extension.py::DEFAULT_TIMEOUT_MS`) and malformed output allow. The rule runs after every built-in refusal, so a built-in one wins and the repo rule only adds. `pretooluse-off` drops it with the whole gate. `TEZGAH_REPO_RULE=0` in the hook's environment skips it alone, before any fork (`hooks/tezgah_gate.py::REPO_RULE_VALVE`).
|
|
482
|
+
The dry check (`tezgah-gate check`) runs it too, since it is part of `decision`. What the file can do is in [SECURITY.md](../SECURITY.md#threat-model).
|
|
483
|
+
opencode runs the same file, with the same envelope, index check, valve, cap and label (`hosts/opencode/plugins/tezgah.js`, `repoRuleReason`). It does so when the core was not asked.
|
|
484
|
+
Its interpreter is the plugin's `pythonBin()`, not the gate's `sys.executable`. That is `TEZGAH_PYTHON`, else the first of `python3`, `python`, `py` on PATH.
|
|
485
|
+
The opencode classifier does not read the manifest's `checks`, so a declared check records there as a plain run. That is a lost credit, never a false one.
|
|
486
|
+
|
|
460
487
|
## Source of truth
|
|
461
488
|
|
|
462
|
-
- `hooks/tezgah_gate.py` — `hooks/tezgah_gate.py::decision`; every rule constant and refusal text `hooks/tezgah_gate.py
|
|
489
|
+
- `hooks/tezgah_gate.py` — `hooks/tezgah_gate.py::decision`; every rule constant and refusal text `hooks/tezgah_gate.py::DENY_RULES`, `hooks/tezgah_gate.py::SECRET_DENY`, `hooks/tezgah_gate.py::SECRET_EDIT_DENY`, `hooks/tezgah_gate.py::SECRET_ADD_DENY`, `hooks/tezgah_gate.py::MCP_SECRET_DENY`, `hooks/tezgah_gate.py::EXPLORE_DENY`, `hooks/tezgah_gate.py::ATTRIB_DENY`, `hooks/tezgah_gate.py::RACE_DENY`, `hooks/tezgah_gate.py::RACE_WHO`, `hooks/tezgah_gate.py::LEASE_DENY`, `hooks/tezgah_gate.py::MAIN_CHECKOUT_DENY`, `hooks/tezgah_gate.py::TASK_PHASE_DENY`, `hooks/tezgah_gate.py::TASK_SCOPE_DENY`, `hooks/tezgah_gate.py::TASK_SCOPE_OUTSIDE`, `hooks/tezgah_gate.py::TASK_RECORD_DENY`, `hooks/tezgah_gate.py::TASK_SHELL_DENY`, `hooks/tezgah_gate.py::CHECKPOINT_DENY`, `hooks/tezgah_gate.py::WORKSPACE_DENY`, `hooks/tezgah_gate.py::ORDER_DENY`, `hooks/tezgah_gate.py::DRIFT_DENY`, `hooks/tezgah_gate.py::CONTROL_DENY`; `attribution`/`attribution_edit` `hooks/tezgah_gate.py::attribution`, `hooks/tezgah_gate.py::attribution_edit`; `explored`
|
|
463
490
|
`hooks/tezgah_gate.py::explored`; `hooks/tezgah_gate.py::searched_symbol`, `hooks/tezgah_gate.py::index_slug`, `hooks/tezgah_gate.py::first_nudge`, `hooks/tezgah_gate.py::nudge_reason`, `hooks/tezgah_gate.py::graph_advice`; `hooks/tezgah_gate.py::LOOP_ATTEMPTS`, `hooks/tezgah_gate.py::loop_reason`,
|
|
464
491
|
`hooks/tezgah_gate.py::RETRY_CEILING`, `hooks/tezgah_gate.py::retry_reason`; `hooks/tezgah_gate.py::secret_command`, `hooks/tezgah_gate.py::race_reason`,
|
|
465
|
-
`hooks/tezgah_gate.py::drift_reason`, `hooks/tezgah_gate.py::effectful`, `hooks/tezgah_gate.py::_deny`; the plan rule's own section `hooks/tezgah_gate.py
|
|
492
|
+
`hooks/tezgah_gate.py::drift_reason`, `hooks/tezgah_gate.py::effectful`, `hooks/tezgah_gate.py::_deny`; the plan rule's own section `hooks/tezgah_gate.py::PLAN_TRUNKS`, `hooks/tezgah_gate.py::PLAN_SKIP`, `hooks/tezgah_gate.py::PLAN_AGENT_HOSTS`, `hooks/tezgah_gate.py::PLAN_WRITES`, `hooks/tezgah_gate.py::PLAN_MERGING`, `hooks/tezgah_gate.py::PLAN_BIND`, `hooks/tezgah_gate.py::PLAN_BIND_TRUNK`, `hooks/tezgah_gate.py::_gitdir`, `hooks/tezgah_gate.py::_head`, `hooks/tezgah_gate.py::_merging`, `hooks/tezgah_gate.py::_unplanned` — `hooks/tezgah_gate.py::plan_reason`, `hooks/tezgah_gate.py::_branch`, `hooks/tezgah_gate.py::_checkout`, `hooks/tezgah_gate.py::_product`, `hooks/tezgah_gate.py::PLAN_DENY`; `hooks/tezgah_gate.py::write_paths`, `hooks/tezgah_gate.py::shell_target`, `hooks/tezgah_gate.py::SHELL_AS_WRITE`; the `capture` call `hooks/tezgah_gate.py::decision` (a write tool's target, and a shell write's)
|
|
466
493
|
- `hooks/projects-pretooluse.py` — the Claude and dsh envelope; `hooks/tezgah_paths.py` — `off`, `root_for`, `cache_dir`
|
|
467
494
|
- `hooks/tezgah_integrity.py` — `hooks/tezgah_integrity.py::WRITE_TOOLS`, `hooks/tezgah_integrity.py::BASH_TOOLS`; `NEUTER`/`SKIP_ENV`/`NO_VERIFY`/`GITISH` `hooks/tezgah_integrity.py::NEUTER`, `hooks/tezgah_integrity.py::SKIP_ENV`, `hooks/tezgah_integrity.py::NO_VERIFY`, `hooks/tezgah_integrity.py::GITISH`; `HOOKS_KEY`/`GIT_VALUE_OPTS`/`CONFIG_READS`/`ROUGH_WORDS` `hooks/tezgah_integrity.py::HOOKS_KEY`, `hooks/tezgah_integrity.py::GIT_VALUE_OPTS`, `hooks/tezgah_integrity.py::CONFIG_READS`, `hooks/tezgah_integrity.py::ROUGH_WORDS`; `hooks/tezgah_integrity.py::SKIP_TEST`; `TEST_PATH`
|
|
468
495
|
`hooks/tezgah_integrity.py::TEST_PATH`; `hooks/tezgah_integrity.py::call_id`; `hooks/tezgah_integrity.py::_path`, `hooks/tezgah_integrity.py::note`, `hooks/tezgah_integrity.py::events`, `hooks/tezgah_integrity.py::writers_elsewhere`, `hooks/tezgah_integrity.py::mask`, `hooks/tezgah_integrity.py::shortcut_command`,
|
package/docs/glossary.md
CHANGED
|
@@ -19,7 +19,7 @@ The part of the contract every session pays for - the invariants plus the one-li
|
|
|
19
19
|
The per-session check of tezgah's own hook entries against the install record. `run()` (`hooks/tezgah_attest.py::run`) reads each host's entries. It compares them with the `hook:<host>:<entry>` lines in `contract.sha256` (`bin/tezgah-setup::record_hooks`). It writes one `attest` [row](#row) and sets or clears the `drift` [mark](#mark). Not integrity: whoever can edit a hook can edit the record. A clean row is evidence, not proof.
|
|
20
20
|
|
|
21
21
|
### budget
|
|
22
|
-
The byte ceiling one injected event may spend: `CONTEXT_BUDGET` per event with `DEFAULT_BUDGET` behind it (`hooks/tezgah_context.py::CONTEXT_BUDGET`), enforced by `budgeted()` (`hooks/tezgah_context.py::budgeted`), which gives up blocks lowest value first along `DROP_ORDER` (`hooks/tezgah_context.py::DROP_ORDER`) - the skill hint
|
|
22
|
+
The byte ceiling one injected event may spend: `CONTEXT_BUDGET` per event with `DEFAULT_BUDGET` behind it (`hooks/tezgah_context.py::CONTEXT_BUDGET`), enforced by `budgeted()` (`hooks/tezgah_context.py::budgeted`), which gives up blocks lowest value first along `DROP_ORDER` (`hooks/tezgah_context.py::DROP_ORDER`) - the skill hint after the per-turn lessons and the index line, then the task phase, the delta and the pointer last - shrinking a block in `SHRINK` (the per-turn relevant lessons, to their first lesson) before it drops it (`hooks/tezgah_context.py::SHRINK`). The core, the reminder, an armed paragraph and the pinned user constraints sit outside `DROP_ORDER`. An event can therefore stay over its budget, and its note says so. The ceiling counts bytes, never tokens, because the module has no tokenizer. Not the [metadata band](#metadata-band), which is the installer's measurement of the same text rather than a runtime bound.
|
|
23
23
|
|
|
24
24
|
### capture
|
|
25
25
|
The pre-write copy the gate takes of every file a write is about to change, `capture()` (`hooks/tezgah_snapshot.py::capture`), called on the gate's allow path (`hooks/tezgah_gate.py::decision`) and capped at `CAP` snapshots and `MAX_BYTES` per file (`hooks/tezgah_snapshot.py:55-56`); a file too large or unreadable is left uncaptured and writes no row, so nothing claims a copy that is not there. Not a transaction: the copy is bytes on disk, not a rollback that runs itself.
|
|
@@ -62,7 +62,7 @@ The partition a status [mark](#mark) carries so a renderer separates the marks t
|
|
|
62
62
|
This project's own frame for the work, tezgah being the wrapper it puts around a coding agent - the injected contract, the [gate](#gate) and the [ledger](#evidence-ledger) - whose per-turn text still travels in the `<harness-reminder>` envelope (`hooks/tezgah_policy.py::PROMPT_REMINDER`). Two neighbours share the word: the agent runtime itself, which the current literature calls a complete agent harness (arXiv 2606.10106; `README.md:27-28` calls dsh one) and the multi-agent selection of the `harness` [skill](#skill), including the graph workflows the policy lists under "Graph harnesses" (`hooks/tezgah_policy.py::WORKFLOWS`); [layers](layers.md) draws the three apart. Not the [host](#host): the host is the agent, the harness is what tezgah puts around it.
|
|
63
63
|
|
|
64
64
|
### harness skill
|
|
65
|
-
The [skill](#skill) that picks and runs a multi-agent harness for a task too wide for one context window - a code-graph workflow such as `graph-map` or a briefed subagent set (`skills/harness/SKILL.md:
|
|
65
|
+
The [skill](#skill) that picks and runs a multi-agent harness for a task too wide for one context window - a code-graph workflow such as `graph-map` or a briefed subagent set (`skills/harness/SKILL.md:11-20`). Not tezgah's own wrapper around a [host](#host) ([harness](#harness), [layers](layers.md)).
|
|
66
66
|
|
|
67
67
|
### host
|
|
68
68
|
One coding agent tezgah is installed into - claude, codex, cursor, opencode, dsh, omp - with its config location in `HOST_DIRS` (`hooks/tezgah_paths.py::HOST_DIRS`), its presence test in `host_installed()` (`hooks/tezgah_paths.py::host_installed`) and its adapter under `hosts/<name>/` ([hosts](hosts.md)); also written "agent host", and the agent runtime the current literature calls the agent harness ([harness](#harness), [layers](layers.md)). Not a [root](#root): a host is a program, a root is a directory tezgah is armed over.
|
|
@@ -94,6 +94,9 @@ A used-mark a surface is able to see at all, so it can say "armed, not used yet"
|
|
|
94
94
|
### once-only
|
|
95
95
|
A mark consumed by its own first use, so the thing it protects happens once: the grep [nudge](#nudge) is written before the deny so later greps pass (`hooks/tezgah_gate.py::decision`). Not a licence for the session: the identical call passes on the retry.
|
|
96
96
|
|
|
97
|
+
### owner marker
|
|
98
|
+
The file a repository commits to say who owns its workspace: `tezgah.owner` at its own top, a few `key: value` lines read by `owner_marker()` (`hooks/tezgah_paths.py::owner_marker`). `tasks: off` stops the plan/task machine there (`hooks/tezgah_paths.py::tasks_disabled`) and `harness: excluded` makes `root_for` answer None, so nothing here runs at all (`hooks/tezgah_paths.py::harness_excluded`). Not a [per-repo mark](#per-repo-mark): it turns seams off rather than dropping one rule's paragraph, and not a [kill switch](#kill-switch), because it travels with the repository.
|
|
99
|
+
|
|
97
100
|
### per-repo mark
|
|
98
101
|
An opt-out file in the repo tree - `.no-ponytail`, `.no-adhd`, `.no-graph`, `.no-lessons`, `.no-taste` - collected by `repo_marks()` walking up to the enclosing root (`hooks/tezgah_context.py::repo_marks`). Not a [kill switch](#kill-switch): a mark travels with the repo, a switch with the machine.
|
|
99
102
|
|
|
@@ -161,7 +164,7 @@ The value of one status [mark](#mark): `on`, `ready`, `off` or `info` (`hooks/te
|
|
|
161
164
|
One of the row kinds that count as a step of work - `run`, `edit`, `verify`, `verify_ok`, `verify_fail`, `interrupted` (`STEP_KINDS`, `hooks/tezgah_integrity.py::STEP_KINDS`), summed into `steps` and into the drift threshold, while `deny`, `nudge`, `claim` and `turn` are the machinery around the work (`hooks/tezgah_integrity.py:1420-1422`). `interrupted` is the one that is not a failure: the host said the call was stopped, so the row carries no `exit` and no `fail_class`, no reader folds it as a failed check and no attempt is spent on it (`hooks/tezgah_integrity.py:1426-1429`). Not any row.
|
|
162
165
|
|
|
163
166
|
### Stop rule
|
|
164
|
-
The end-of-turn refusal, `stop_reason()` (`hooks/tezgah_integrity.py::stop_reason`), run by the Stop hooks of Claude, Codex, Cursor and omp (`hooks/projects-stop.py::main`, `hosts/codex/hook.py::main`, `hosts/cursor/hook.py::dispatch`, `hosts/omp/hook.py::handle`): it blocks on a placating opener or a banned sign-off on the last prose line, on a completion claim the newest check does not support, on a check that passed before the newest write the gate saw change the tree, on a turn that recorded work with no passing check,
|
|
167
|
+
The end-of-turn refusal, `stop_reason()` (`hooks/tezgah_integrity.py::stop_reason`), run by the Stop hooks of Claude, Codex, Cursor and omp (`hooks/projects-stop.py::main`, `hosts/codex/hook.py::main`, `hosts/cursor/hook.py::dispatch`, `hosts/omp/hook.py::handle`): it blocks on a placating opener or a banned sign-off on the last prose line, on a completion claim the newest check does not support, on a check that passed before the newest write the gate saw change the tree, on a turn that recorded work with no passing check, on a working turn that ends on a list of what is left with an item no blocker accounts for, or on a reply that hands the reader a command the turn ran commands beside (`handed_steps()`, `hooks/tezgah_integrity.py::handed_steps`) (`_stop_block()`, `hooks/tezgah_integrity.py::_stop_block`). An explicit "doğrulanmadı" clears a check-repair refusal only after a check that ran and failed since the newest change (`hooks/tezgah_integrity.py::_admitted`). A claim in a turn with no work is judged against the whole session, and a read-only or VCS-bookkeeping turn after a pass on an unchanged tree is exempt ([evidence](evidence.md#the-stop-rule-end-to-end)). In a host plan mode (`read_only_turn()`, `hooks/tezgah_integrity.py::read_only_turn`) the approval question is not refused and a done/tested claim is. Not the [gate](#gate), which runs before a call ([evidence](evidence.md)).
|
|
165
168
|
|
|
166
169
|
### surface
|
|
167
170
|
A place a host can show tezgah's output - a status line, a TUI widget, a `systemMessage` - and therefore the reason the same [marks](#mark) render differently per host (`hooks/tezgah_context.py::health_segments`, `hooks/tezgah_context.py::render_line`); each host's surfaces are [hosts](hosts.md)'s. Not the host itself.
|