@r1z4x/tezgah 1.0.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 +738 -0
- package/LICENSE +21 -0
- package/MANIFEST +753 -0
- package/README.de.md +169 -0
- package/README.es.md +168 -0
- package/README.fr.md +166 -0
- package/README.md +161 -0
- package/README.tr.md +163 -0
- package/agents/tezgah-reviewer.md +70 -0
- package/bin/codegen +337 -0
- package/bin/consult +797 -0
- package/bin/tezgah-adhd +50 -0
- package/bin/tezgah-agents +45 -0
- package/bin/tezgah-capture +66 -0
- package/bin/tezgah-context +96 -0
- package/bin/tezgah-decisions +213 -0
- package/bin/tezgah-design +953 -0
- package/bin/tezgah-docs +1199 -0
- package/bin/tezgah-doctor +497 -0
- package/bin/tezgah-dsh +37 -0
- package/bin/tezgah-dsh.cmd +70 -0
- package/bin/tezgah-gate +75 -0
- package/bin/tezgah-import-ai-research +439 -0
- package/bin/tezgah-index +32 -0
- package/bin/tezgah-lessons +148 -0
- package/bin/tezgah-mcp +322 -0
- package/bin/tezgah-migrate +324 -0
- package/bin/tezgah-pony +50 -0
- package/bin/tezgah-research +772 -0
- package/bin/tezgah-rollback +93 -0
- package/bin/tezgah-route +124 -0
- package/bin/tezgah-setup +5798 -0
- package/bin/tezgah-status +383 -0
- package/bin/tezgah-task +607 -0
- package/bin/tezgah-taste +423 -0
- package/bin/tezgah-triage +485 -0
- package/bin/tezgah.js +36 -0
- package/commands/adhd.md +21 -0
- package/commands/ponytail.md +21 -0
- package/docs/README.md +112 -0
- package/docs/architecture.md +226 -0
- package/docs/citations-baseline.json +59 -0
- package/docs/clarity-baseline.json +116 -0
- package/docs/contract.md +416 -0
- package/docs/environment.md +141 -0
- package/docs/evidence.md +831 -0
- package/docs/feature-audit.md +139 -0
- package/docs/gate.md +407 -0
- package/docs/glossary.md +201 -0
- package/docs/hosts.md +400 -0
- package/docs/index.json +471 -0
- package/docs/judge.md +193 -0
- package/docs/layers.md +189 -0
- package/docs/models.md +160 -0
- package/docs/operations.md +666 -0
- package/docs/research.md +809 -0
- package/docs/results/paired-outcome-2026-10.jsonl +254 -0
- package/docs/results/paired-outcome-2026-10.md +204 -0
- package/docs/skills.md +236 -0
- package/docs/status-line.md +315 -0
- package/docs/testing.md +287 -0
- package/docs/vision.md +117 -0
- package/hooks/hooks.json +33 -0
- package/hooks/projects-auto-init.py +98 -0
- package/hooks/projects-posttooluse.py +149 -0
- package/hooks/projects-pretooluse.py +40 -0
- package/hooks/projects-stop.py +60 -0
- package/hooks/tezgah_agents.py +817 -0
- package/hooks/tezgah_apps.py +266 -0
- package/hooks/tezgah_attest.py +255 -0
- package/hooks/tezgah_clarity.py +171 -0
- package/hooks/tezgah_components.py +140 -0
- package/hooks/tezgah_context.py +2953 -0
- package/hooks/tezgah_embed.py +765 -0
- package/hooks/tezgah_gate.py +2736 -0
- package/hooks/tezgah_guard.py +177 -0
- package/hooks/tezgah_index.py +124 -0
- package/hooks/tezgah_integrity.py +5141 -0
- package/hooks/tezgah_judge.py +487 -0
- package/hooks/tezgah_lang.py +230 -0
- package/hooks/tezgah_lessons.py +210 -0
- package/hooks/tezgah_models.py +855 -0
- package/hooks/tezgah_paths.py +1132 -0
- package/hooks/tezgah_policy.py +1039 -0
- package/hooks/tezgah_rank.py +77 -0
- package/hooks/tezgah_replay.py +1109 -0
- package/hooks/tezgah_research.py +5176 -0
- package/hooks/tezgah_shapes.py +305 -0
- package/hooks/tezgah_skill_pick.py +227 -0
- package/hooks/tezgah_snapshot.py +490 -0
- package/hooks/tezgah_stopspec.py +320 -0
- package/hooks/tezgah_task.py +458 -0
- package/hooks/tezgah_taste.py +201 -0
- package/hooks/tezgah_untrusted.py +112 -0
- package/hooks/tezgah_update.py +430 -0
- package/hosts/codex/hook.py +268 -0
- package/hosts/codex/hooks.json +26 -0
- package/hosts/cursor/hook.py +461 -0
- package/hosts/cursor/hooks.json +44 -0
- package/hosts/dsh/hooks.json +21 -0
- package/hosts/dsh/statusline/lib/client.js +138 -0
- package/hosts/dsh/statusline/lib/index.js +104 -0
- package/hosts/dsh/statusline/package.json +28 -0
- package/hosts/omp/hook.py +277 -0
- package/hosts/omp/tezgah-hook.ts.in +701 -0
- package/hosts/opencode/plugins/tezgah.js +2742 -0
- package/hosts/opencode/tui/tezgah-tui.tsx +151 -0
- package/output-styles/tezgah.md +142 -0
- package/package.json +32 -0
- package/packaging/build.sh +342 -0
- package/packaging/install.ps1 +166 -0
- package/packaging/install.sh +56 -0
- package/packaging/upgrade.sh +142 -0
- package/skills/ai-research/0-autoresearch-skill/SKILL.md +411 -0
- package/skills/ai-research/0-autoresearch-skill/references/agent-continuity.md +95 -0
- package/skills/ai-research/0-autoresearch-skill/references/progress-reporting.md +166 -0
- package/skills/ai-research/0-autoresearch-skill/references/skill-routing.md +219 -0
- package/skills/ai-research/0-autoresearch-skill/templates/findings.md +44 -0
- package/skills/ai-research/0-autoresearch-skill/templates/research-log.md +41 -0
- package/skills/ai-research/01-model-architecture/litgpt/SKILL.md +469 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/custom-models.md +569 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/distributed-training.md +452 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/supported-models.md +337 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/training-recipes.md +620 -0
- package/skills/ai-research/01-model-architecture/mamba/SKILL.md +260 -0
- package/skills/ai-research/01-model-architecture/mamba/references/architecture-details.md +207 -0
- package/skills/ai-research/01-model-architecture/mamba/references/benchmarks.md +256 -0
- package/skills/ai-research/01-model-architecture/mamba/references/training-guide.md +389 -0
- package/skills/ai-research/01-model-architecture/nanogpt/SKILL.md +290 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/architecture.md +383 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/data.md +477 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/training.md +565 -0
- package/skills/ai-research/01-model-architecture/rwkv/SKILL.md +260 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/architecture-details.md +345 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/rwkv7.md +387 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/state-management.md +370 -0
- package/skills/ai-research/01-model-architecture/torchtitan/SKILL.md +358 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/checkpoint.md +182 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/custom-models.md +259 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/float8.md +134 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/fsdp.md +127 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/SKILL.md +516 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/algorithms.md +654 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/integration.md +638 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/pipeline.md +724 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/training.md +566 -0
- package/skills/ai-research/02-tokenization/sentencepiece/SKILL.md +235 -0
- package/skills/ai-research/02-tokenization/sentencepiece/references/algorithms.md +201 -0
- package/skills/ai-research/02-tokenization/sentencepiece/references/training.md +305 -0
- package/skills/ai-research/03-fine-tuning/axolotl/SKILL.md +158 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/api.md +5549 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/dataset-formats.md +1030 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/index.md +16 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/other.md +3564 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/SKILL.md +80 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/_images.md +24 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/advanced.md +1056 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/getting_started.md +350 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/index.md +20 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/other.md +32 -0
- package/skills/ai-research/03-fine-tuning/peft/SKILL.md +431 -0
- package/skills/ai-research/03-fine-tuning/peft/references/advanced-usage.md +515 -0
- package/skills/ai-research/03-fine-tuning/peft/references/troubleshooting.md +481 -0
- package/skills/ai-research/03-fine-tuning/unsloth/SKILL.md +80 -0
- package/skills/ai-research/03-fine-tuning/unsloth/references/index.md +8 -0
- package/skills/ai-research/03-fine-tuning/unsloth/references/llms.md +83 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/SKILL.md +436 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/README.md +79 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/api.md +345 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/tutorials.md +301 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/SKILL.md +473 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/README.md +74 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/api.md +384 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/tutorials.md +377 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/SKILL.md +386 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/README.md +71 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/api.md +334 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/tutorials.md +319 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/SKILL.md +346 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/README.md +55 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/api.md +363 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/tutorials.md +340 -0
- package/skills/ai-research/05-data-processing/nemo-curator/SKILL.md +383 -0
- package/skills/ai-research/05-data-processing/nemo-curator/references/deduplication.md +88 -0
- package/skills/ai-research/05-data-processing/nemo-curator/references/filtering.md +103 -0
- package/skills/ai-research/05-data-processing/ray-data/SKILL.md +326 -0
- package/skills/ai-research/05-data-processing/ray-data/references/integration.md +83 -0
- package/skills/ai-research/05-data-processing/ray-data/references/transformations.md +84 -0
- package/skills/ai-research/06-post-training/grpo-rl-training/README.md +98 -0
- package/skills/ai-research/06-post-training/grpo-rl-training/SKILL.md +572 -0
- package/skills/ai-research/06-post-training/miles/SKILL.md +315 -0
- package/skills/ai-research/06-post-training/miles/references/api-reference.md +142 -0
- package/skills/ai-research/06-post-training/miles/references/troubleshooting.md +353 -0
- package/skills/ai-research/06-post-training/openrlhf/SKILL.md +249 -0
- package/skills/ai-research/06-post-training/openrlhf/references/algorithm-comparison.md +405 -0
- package/skills/ai-research/06-post-training/openrlhf/references/custom-rewards.md +531 -0
- package/skills/ai-research/06-post-training/openrlhf/references/hybrid-engine.md +288 -0
- package/skills/ai-research/06-post-training/openrlhf/references/multi-node-training.md +455 -0
- package/skills/ai-research/06-post-training/simpo/SKILL.md +219 -0
- package/skills/ai-research/06-post-training/simpo/references/datasets.md +479 -0
- package/skills/ai-research/06-post-training/simpo/references/hyperparameters.md +453 -0
- package/skills/ai-research/06-post-training/simpo/references/loss-functions.md +351 -0
- package/skills/ai-research/06-post-training/slime/SKILL.md +464 -0
- package/skills/ai-research/06-post-training/slime/references/api-reference.md +393 -0
- package/skills/ai-research/06-post-training/slime/references/troubleshooting.md +387 -0
- package/skills/ai-research/06-post-training/torchforge/SKILL.md +433 -0
- package/skills/ai-research/06-post-training/torchforge/references/api-reference.md +328 -0
- package/skills/ai-research/06-post-training/torchforge/references/troubleshooting.md +410 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/SKILL.md +455 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/dpo-variants.md +228 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/online-rl.md +83 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/reward-modeling.md +123 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/sft-training.md +169 -0
- package/skills/ai-research/06-post-training/verl/SKILL.md +391 -0
- package/skills/ai-research/06-post-training/verl/references/api-reference.md +302 -0
- package/skills/ai-research/06-post-training/verl/references/troubleshooting.md +392 -0
- package/skills/ai-research/07-safety-alignment/constitutional-ai/SKILL.md +290 -0
- package/skills/ai-research/07-safety-alignment/llamaguard/SKILL.md +337 -0
- package/skills/ai-research/07-safety-alignment/nemo-guardrails/SKILL.md +297 -0
- package/skills/ai-research/07-safety-alignment/prompt-guard/SKILL.md +312 -0
- package/skills/ai-research/08-distributed-training/accelerate/SKILL.md +332 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/custom-plugins.md +454 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/megatron-integration.md +490 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/performance.md +526 -0
- package/skills/ai-research/08-distributed-training/deepspeed/SKILL.md +141 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/08.md +18 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/09.md +174 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/2020.md +379 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/2023.md +280 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/assets.md +180 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/index.md +36 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/mii.md +119 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/other.md +1192 -0
- package/skills/ai-research/08-distributed-training/megatron-core/SKILL.md +366 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/benchmarks.md +250 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/parallelism-guide.md +405 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/production-examples.md +474 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/training-recipes.md +548 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/SKILL.md +231 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_async_recipe.md +14 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_overview.md +19 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_recipe.md +18 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_ddp_notes.md +10 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_device_mesh_tutorial.md +22 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_examples_fsdp2.md +15 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp1_api.md +9 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp2_tutorial.md +45 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fully_shard_api.md +49 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_tp_tutorial.md +22 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/ray_train_fsdp2_example.md +13 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/torchtitan_fsdp_notes.md +14 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/SKILL.md +346 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/callbacks.md +437 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/distributed.md +491 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/hyperparameter-tuning.md +557 -0
- package/skills/ai-research/08-distributed-training/ray-train/SKILL.md +406 -0
- package/skills/ai-research/08-distributed-training/ray-train/references/multi-node.md +629 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/SKILL.md +545 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/references/advanced-usage.md +612 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/references/troubleshooting.md +531 -0
- package/skills/ai-research/09-infrastructure/modal/SKILL.md +341 -0
- package/skills/ai-research/09-infrastructure/modal/references/advanced-usage.md +504 -0
- package/skills/ai-research/09-infrastructure/modal/references/troubleshooting.md +495 -0
- package/skills/ai-research/09-infrastructure/skypilot/SKILL.md +509 -0
- package/skills/ai-research/09-infrastructure/skypilot/references/advanced-usage.md +492 -0
- package/skills/ai-research/09-infrastructure/skypilot/references/troubleshooting.md +571 -0
- package/skills/ai-research/10-optimization/awq/SKILL.md +310 -0
- package/skills/ai-research/10-optimization/awq/references/advanced-usage.md +325 -0
- package/skills/ai-research/10-optimization/awq/references/troubleshooting.md +345 -0
- package/skills/ai-research/10-optimization/bitsandbytes/SKILL.md +411 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/memory-optimization.md +522 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/qlora-training.md +522 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/quantization-formats.md +448 -0
- package/skills/ai-research/10-optimization/flash-attention/SKILL.md +367 -0
- package/skills/ai-research/10-optimization/flash-attention/references/benchmarks.md +216 -0
- package/skills/ai-research/10-optimization/flash-attention/references/transformers-integration.md +294 -0
- package/skills/ai-research/10-optimization/gguf/SKILL.md +427 -0
- package/skills/ai-research/10-optimization/gguf/references/advanced-usage.md +505 -0
- package/skills/ai-research/10-optimization/gguf/references/troubleshooting.md +443 -0
- package/skills/ai-research/10-optimization/gptq/SKILL.md +450 -0
- package/skills/ai-research/10-optimization/gptq/references/calibration.md +338 -0
- package/skills/ai-research/10-optimization/gptq/references/integration.md +130 -0
- package/skills/ai-research/10-optimization/gptq/references/troubleshooting.md +96 -0
- package/skills/ai-research/10-optimization/hqq/SKILL.md +445 -0
- package/skills/ai-research/10-optimization/hqq/references/advanced-usage.md +529 -0
- package/skills/ai-research/10-optimization/hqq/references/troubleshooting.md +504 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/SKILL.md +319 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/architecture.md +320 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/biomedical.md +498 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/domain-specific.md +626 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/experiment-loop.md +129 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/optimizers.md +330 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/scaling-and-selection.md +428 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/SKILL.md +405 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/benchmarks.md +394 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/custom-tasks.md +425 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/issues.md +395 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/SKILL.md +490 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/api-evaluation.md +491 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/benchmark-guide.md +489 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/custom-tasks.md +603 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/distributed-eval.md +520 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/SKILL.md +494 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/adapter-system.md +341 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/configuration.md +448 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/custom-benchmarks.md +316 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/execution-backends.md +362 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/SKILL.md +258 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/optimization.md +90 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/quantization.md +214 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/server.md +126 -0
- package/skills/ai-research/12-inference-serving/sglang/SKILL.md +442 -0
- package/skills/ai-research/12-inference-serving/sglang/references/deployment.md +491 -0
- package/skills/ai-research/12-inference-serving/sglang/references/radix-attention.md +414 -0
- package/skills/ai-research/12-inference-serving/sglang/references/structured-generation.md +542 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/SKILL.md +187 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/multi-gpu.md +299 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/optimization.md +243 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/serving.md +471 -0
- package/skills/ai-research/12-inference-serving/vllm/SKILL.md +364 -0
- package/skills/ai-research/12-inference-serving/vllm/references/optimization.md +227 -0
- package/skills/ai-research/12-inference-serving/vllm/references/quantization.md +285 -0
- package/skills/ai-research/12-inference-serving/vllm/references/server-deployment.md +256 -0
- package/skills/ai-research/12-inference-serving/vllm/references/troubleshooting.md +448 -0
- package/skills/ai-research/13-mlops/mlflow/SKILL.md +704 -0
- package/skills/ai-research/13-mlops/mlflow/references/deployment.md +745 -0
- package/skills/ai-research/13-mlops/mlflow/references/model-registry.md +771 -0
- package/skills/ai-research/13-mlops/mlflow/references/tracking.md +681 -0
- package/skills/ai-research/13-mlops/swanlab/SKILL.md +406 -0
- package/skills/ai-research/13-mlops/swanlab/references/integrations.md +305 -0
- package/skills/ai-research/13-mlops/swanlab/references/visualization.md +234 -0
- package/skills/ai-research/13-mlops/tensorboard/SKILL.md +629 -0
- package/skills/ai-research/13-mlops/tensorboard/references/integrations.md +639 -0
- package/skills/ai-research/13-mlops/tensorboard/references/profiling.md +546 -0
- package/skills/ai-research/13-mlops/tensorboard/references/visualization.md +621 -0
- package/skills/ai-research/13-mlops/weights-and-biases/SKILL.md +590 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/artifacts.md +585 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/integrations.md +701 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/sweeps.md +848 -0
- package/skills/ai-research/14-agents/a-evolve/SKILL.md +383 -0
- package/skills/ai-research/14-agents/a-evolve/references/README.md +831 -0
- package/skills/ai-research/14-agents/a-evolve/references/api.md +594 -0
- package/skills/ai-research/14-agents/a-evolve/references/architecture.md +417 -0
- package/skills/ai-research/14-agents/a-evolve/references/design-patterns.md +462 -0
- package/skills/ai-research/14-agents/a-evolve/references/examples.md +352 -0
- package/skills/ai-research/14-agents/a-evolve/references/issues.md +591 -0
- package/skills/ai-research/14-agents/a-evolve/references/releases.md +112 -0
- package/skills/ai-research/14-agents/a-evolve/references/tutorials.md +819 -0
- package/skills/ai-research/14-agents/autogpt/SKILL.md +403 -0
- package/skills/ai-research/14-agents/autogpt/references/advanced-usage.md +536 -0
- package/skills/ai-research/14-agents/autogpt/references/troubleshooting.md +421 -0
- package/skills/ai-research/14-agents/crewai/SKILL.md +498 -0
- package/skills/ai-research/14-agents/crewai/references/flows.md +439 -0
- package/skills/ai-research/14-agents/crewai/references/tools.md +430 -0
- package/skills/ai-research/14-agents/crewai/references/troubleshooting.md +481 -0
- package/skills/ai-research/14-agents/langchain/SKILL.md +480 -0
- package/skills/ai-research/14-agents/langchain/references/agents.md +500 -0
- package/skills/ai-research/14-agents/langchain/references/integration.md +563 -0
- package/skills/ai-research/14-agents/langchain/references/rag.md +601 -0
- package/skills/ai-research/14-agents/llamaindex/SKILL.md +569 -0
- package/skills/ai-research/14-agents/llamaindex/references/agents.md +84 -0
- package/skills/ai-research/14-agents/llamaindex/references/data_connectors.md +109 -0
- package/skills/ai-research/14-agents/llamaindex/references/query_engines.md +407 -0
- package/skills/ai-research/15-rag/chroma/SKILL.md +406 -0
- package/skills/ai-research/15-rag/chroma/references/integration.md +39 -0
- package/skills/ai-research/15-rag/faiss/SKILL.md +221 -0
- package/skills/ai-research/15-rag/faiss/references/index_types.md +281 -0
- package/skills/ai-research/15-rag/pinecone/SKILL.md +358 -0
- package/skills/ai-research/15-rag/pinecone/references/deployment.md +182 -0
- package/skills/ai-research/15-rag/qdrant/SKILL.md +493 -0
- package/skills/ai-research/15-rag/qdrant/references/advanced-usage.md +649 -0
- package/skills/ai-research/15-rag/qdrant/references/troubleshooting.md +632 -0
- package/skills/ai-research/15-rag/sentence-transformers/SKILL.md +255 -0
- package/skills/ai-research/15-rag/sentence-transformers/references/models.md +124 -0
- package/skills/ai-research/16-prompt-engineering/dspy/SKILL.md +590 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/examples.md +664 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/modules.md +476 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/optimizers.md +567 -0
- package/skills/ai-research/16-prompt-engineering/guidance/SKILL.md +572 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/backends.md +555 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/constraints.md +675 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/examples.md +768 -0
- package/skills/ai-research/16-prompt-engineering/instructor/SKILL.md +740 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/examples.md +108 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/providers.md +71 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/validation.md +607 -0
- package/skills/ai-research/16-prompt-engineering/outlines/SKILL.md +652 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/backends.md +616 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/examples.md +774 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/json_generation.md +653 -0
- package/skills/ai-research/17-observability/langsmith/SKILL.md +422 -0
- package/skills/ai-research/17-observability/langsmith/references/advanced-usage.md +549 -0
- package/skills/ai-research/17-observability/langsmith/references/troubleshooting.md +538 -0
- package/skills/ai-research/17-observability/phoenix/SKILL.md +475 -0
- package/skills/ai-research/17-observability/phoenix/references/advanced-usage.md +620 -0
- package/skills/ai-research/17-observability/phoenix/references/troubleshooting.md +539 -0
- package/skills/ai-research/18-multimodal/audiocraft/SKILL.md +564 -0
- package/skills/ai-research/18-multimodal/audiocraft/references/advanced-usage.md +667 -0
- package/skills/ai-research/18-multimodal/audiocraft/references/troubleshooting.md +505 -0
- package/skills/ai-research/18-multimodal/blip-2/SKILL.md +564 -0
- package/skills/ai-research/18-multimodal/blip-2/references/advanced-usage.md +681 -0
- package/skills/ai-research/18-multimodal/blip-2/references/troubleshooting.md +527 -0
- package/skills/ai-research/18-multimodal/clip/SKILL.md +253 -0
- package/skills/ai-research/18-multimodal/clip/references/applications.md +208 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/SKILL.md +402 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/references/libero-commands.md +175 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/references/robocasa-commands.md +147 -0
- package/skills/ai-research/18-multimodal/llava/SKILL.md +304 -0
- package/skills/ai-research/18-multimodal/llava/references/training.md +198 -0
- package/skills/ai-research/18-multimodal/openpi/SKILL.md +480 -0
- package/skills/ai-research/18-multimodal/openpi/references/checkpoints-and-env-map.md +86 -0
- package/skills/ai-research/18-multimodal/openpi/references/config-recipes.md +50 -0
- package/skills/ai-research/18-multimodal/openpi/references/pytorch-gotchas.md +49 -0
- package/skills/ai-research/18-multimodal/openpi/references/remote-client-pattern.md +48 -0
- package/skills/ai-research/18-multimodal/openpi/references/training-debugging.md +46 -0
- package/skills/ai-research/18-multimodal/openvla-oft/SKILL.md +441 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/aloha-workflow.md +141 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/config-troubleshooting.md +97 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/libero-workflow.md +115 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/paper-and-checkpoints.md +84 -0
- package/skills/ai-research/18-multimodal/segment-anything/SKILL.md +500 -0
- package/skills/ai-research/18-multimodal/segment-anything/references/advanced-usage.md +590 -0
- package/skills/ai-research/18-multimodal/segment-anything/references/troubleshooting.md +485 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/SKILL.md +519 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/references/advanced-usage.md +717 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/references/troubleshooting.md +556 -0
- package/skills/ai-research/18-multimodal/whisper/SKILL.md +317 -0
- package/skills/ai-research/18-multimodal/whisper/references/languages.md +190 -0
- package/skills/ai-research/19-emerging-techniques/knowledge-distillation/SKILL.md +458 -0
- package/skills/ai-research/19-emerging-techniques/knowledge-distillation/references/minillm.md +335 -0
- package/skills/ai-research/19-emerging-techniques/long-context/SKILL.md +536 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/extension_methods.md +469 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/fine_tuning.md +612 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/rope.md +403 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/SKILL.md +497 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/coefficient-tuning.md +415 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/evaluation.md +463 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/examples.md +429 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/methods.md +353 -0
- package/skills/ai-research/19-emerging-techniques/model-pruning/SKILL.md +495 -0
- package/skills/ai-research/19-emerging-techniques/model-pruning/references/wanda.md +348 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/SKILL.md +526 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/architectures.md +433 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/inference.md +349 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/training.md +426 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/SKILL.md +467 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/lookahead.md +310 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/medusa.md +351 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/SKILL.md +479 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/data-visualization.md +509 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/diagram-generation.md +395 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/style-guide.md +305 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/SKILL.md +982 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/checklists.md +348 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/citation-workflow.md +563 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/reviewer-guidelines.md +349 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/sources.md +165 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/writing-guide.md +477 -0
- package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/SKILL.md +298 -0
- package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/references/slide-templates.md +505 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/SKILL.md +270 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/checklist.md +279 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/reviewer-guidelines.md +116 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/section-blueprints.md +400 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/systems-conferences.md +261 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/writing-patterns.md +231 -0
- package/skills/ai-research/21-research-ideation/brainstorming-research-ideas/SKILL.md +384 -0
- package/skills/ai-research/21-research-ideation/creative-thinking-for-research/SKILL.md +366 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/SKILL.md +245 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/ara-schema.md +439 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/exploration-tree-spec.md +125 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/validation-checklist.md +149 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/SKILL.md +324 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/event-taxonomy.md +124 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/provenance-tags.md +190 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/session-protocol.md +162 -0
- package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/SKILL.md +322 -0
- package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/references/review-dimensions.md +182 -0
- package/skills/ai-research/SKILL.md +101 -0
- package/skills/ai-research/SOURCE +38 -0
- package/skills/ai-research/index/1-frame.md +18 -0
- package/skills/ai-research/index/2-data.md +21 -0
- package/skills/ai-research/index/3-train.md +48 -0
- package/skills/ai-research/index/4-measure.md +25 -0
- package/skills/ai-research/index/5-run.md +23 -0
- package/skills/ai-research/index/6-write.md +35 -0
- package/skills/ai-research/library.json +3456 -0
- package/skills/analyze-app/EVALS.md +82 -0
- package/skills/analyze-app/SKILL.md +188 -0
- package/skills/design-contract/EVALS.md +80 -0
- package/skills/design-contract/SKILL.md +171 -0
- package/skills/design-library/EVALS.md +85 -0
- package/skills/design-library/INDEX.md +59 -0
- package/skills/design-library/SKILL.md +58 -0
- package/skills/design-library/SOURCE +131 -0
- package/skills/design-library/adaptive-interfaces/skills/colour-independence/SKILL.md +90 -0
- package/skills/design-library/adaptive-interfaces/skills/flexible-typography/SKILL.md +83 -0
- package/skills/design-library/adaptive-interfaces/skills/information-density/SKILL.md +87 -0
- package/skills/design-library/adaptive-interfaces/skills/preference-audit/SKILL.md +70 -0
- package/skills/design-library/adaptive-interfaces/skills/responsive-accessibility/SKILL.md +86 -0
- package/skills/design-library/adaptive-interfaces/skills/responsive-review/SKILL.md +76 -0
- package/skills/design-library/adaptive-interfaces/skills/simplified-views/SKILL.md +97 -0
- package/skills/design-library/adaptive-interfaces/skills/specify/SKILL.md +63 -0
- package/skills/design-library/adaptive-interfaces/skills/user-preference-respect/SKILL.md +100 -0
- package/skills/design-library/cognitive-accessibility/skills/adaptive-personalisation/SKILL.md +61 -0
- package/skills/design-library/cognitive-accessibility/skills/assess-load/SKILL.md +48 -0
- package/skills/design-library/cognitive-accessibility/skills/cognitive-load-assessment/SKILL.md +60 -0
- package/skills/design-library/cognitive-accessibility/skills/contextual-help-design/SKILL.md +61 -0
- package/skills/design-library/cognitive-accessibility/skills/error-prevention-recovery/SKILL.md +71 -0
- package/skills/design-library/cognitive-accessibility/skills/focus-attention-design/SKILL.md +67 -0
- package/skills/design-library/cognitive-accessibility/skills/memory-load-reduction/SKILL.md +60 -0
- package/skills/design-library/cognitive-accessibility/skills/plain-language-design/SKILL.md +78 -0
- package/skills/design-library/cognitive-accessibility/skills/review/SKILL.md +56 -0
- package/skills/design-library/cognitive-accessibility/skills/simplify/SKILL.md +39 -0
- package/skills/design-library/cognitive-accessibility/skills/wayfinding-navigation/SKILL.md +64 -0
- package/skills/design-library/design-research/skills/behavioural-analytics/SKILL.md +33 -0
- package/skills/design-library/design-research/skills/qual-quant-triangulation/SKILL.md +33 -0
- package/skills/design-library/inclusive-interaction/skills/audit/SKILL.md +50 -0
- package/skills/design-library/inclusive-interaction/skills/design-flow/SKILL.md +58 -0
- package/skills/design-library/inclusive-interaction/skills/feedback-and-status/SKILL.md +76 -0
- package/skills/design-library/inclusive-interaction/skills/gesture-alternatives/SKILL.md +70 -0
- package/skills/design-library/inclusive-interaction/skills/keyboard-navigation/SKILL.md +99 -0
- package/skills/design-library/inclusive-interaction/skills/keyboard-review/SKILL.md +54 -0
- package/skills/design-library/inclusive-interaction/skills/motion-sensitivity/SKILL.md +79 -0
- package/skills/design-library/inclusive-interaction/skills/multi-modal-input/SKILL.md +70 -0
- package/skills/design-library/inclusive-interaction/skills/touch-target-design/SKILL.md +71 -0
- package/skills/design-library/inclusive-interaction/skills/voice-interaction/SKILL.md +68 -0
- package/skills/design-library/visual-critique/skills/critique-affordance/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-brand-consistency/SKILL.md +42 -0
- package/skills/design-library/visual-critique/skills/critique-color/SKILL.md +44 -0
- package/skills/design-library/visual-critique/skills/critique-composition/SKILL.md +46 -0
- package/skills/design-library/visual-critique/skills/critique-information-density/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-typography/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-visual-hierarchy/SKILL.md +40 -0
- package/skills/feature-audit/EVALS.md +83 -0
- package/skills/feature-audit/SKILL.md +326 -0
- package/skills/harness/EVALS.md +81 -0
- package/skills/harness/SKILL.md +88 -0
- package/skills/i-have-adhd/EVALS.md +80 -0
- package/skills/i-have-adhd/SKILL.md +183 -0
- package/skills/no-ai-slop/EVALS.md +89 -0
- package/skills/no-ai-slop/SKILL.md +209 -0
- package/skills/no-ai-slop/eval.md +52 -0
- package/skills/plan-add/EVALS.md +79 -0
- package/skills/plan-add/SKILL.md +179 -0
- package/skills/plan-add/render_table.py +72 -0
- package/skills/plan-status/EVALS.md +78 -0
- package/skills/plan-status/SKILL.md +52 -0
- package/skills/plan-sync/EVALS.md +80 -0
- package/skills/plan-sync/SKILL.md +69 -0
- package/skills/pm-frameworks/SKILL.md +33 -0
- package/skills/pm-frameworks/SOURCE +39 -0
- package/skills/pm-frameworks/intended-vs-implemented/SKILL.md +42 -0
- package/skills/pm-frameworks/opportunity-solution-tree/SKILL.md +64 -0
- package/skills/ponytail/EVALS.md +80 -0
- package/skills/ponytail/SKILL.md +124 -0
- package/skills/product-analysis/EVALS.md +103 -0
- package/skills/product-analysis/SKILL.md +361 -0
- package/skills/research/EVALS.md +104 -0
- package/skills/research/SKILL.md +570 -0
- package/skills/rl-env/SKILL.md +53 -0
- package/skills/rl-env/SOURCE +41 -0
- package/skills/rl-env/generate-nemo-gym-env/SKILL.md +169 -0
- package/skills/rl-env/generate-nemo-gym-env/references/architecture.md +114 -0
- package/skills/rl-env/generate-openenv-env/SKILL.md +183 -0
- package/skills/rl-env/generate-openenv-env/references/architecture.md +82 -0
- package/skills/rl-env/generate-ors-env/SKILL.md +209 -0
- package/skills/rl-env/generate-ors-env/references/architecture.md +113 -0
- package/skills/rl-env/generate-verifiers-env/SKILL.md +188 -0
- package/skills/rl-env/generate-verifiers-env/references/architecture.md +119 -0
- package/skills/rl-env/rl-env-from-description/SKILL.md +124 -0
- package/skills/rl-env/rl-env-from-description/references/interview.md +75 -0
- package/skills/rl-env/rl-env-from-description/references/nemo_gym.md +41 -0
- package/skills/rl-env/rl-env-from-description/references/openenv.md +35 -0
- package/skills/rl-env/rl-env-from-description/references/ors.md +50 -0
- package/skills/rl-env/rl-env-from-description/references/verifiers.md +39 -0
- package/skills/tezgah-contract/EVALS.md +78 -0
- package/skills/tezgah-contract/SKILL.md +792 -0
- package/statusline.py +129 -0
- package/workflows/graph-impact.js +153 -0
- package/workflows/graph-map.js +158 -0
- package/workflows/graph-review.js +170 -0
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Per-repo subagent definitions, generated from the detected infrastructure.
|
|
3
|
+
|
|
4
|
+
When a session starts inside a tezgah root, the enclosing repo gets a small set
|
|
5
|
+
of specialized agents, rendered into every host surface that actually exists:
|
|
6
|
+
|
|
7
|
+
Claude Code / Cursor `.claude/agents/*.md` (Cursor reads this dir natively)
|
|
8
|
+
opencode `.opencode/agents/*.md` (fallback) + config injection
|
|
9
|
+
Codex `.codex/agents/*.toml`
|
|
10
|
+
|
|
11
|
+
A role is only emitted when the capability it needs is present (the reviewer
|
|
12
|
+
needs the code graph); the three tier workers are emitted in every root,
|
|
13
|
+
because `tezgah-route` names one of them for every delegated task. The whole set is regenerated when either this manifest
|
|
14
|
+
or the repo's infrastructure changes, so the definitions stay updatable instead
|
|
15
|
+
of drifting. Hosts with no such surface (dsh) get nothing here; the orchestrator
|
|
16
|
+
directive in the injected contract already covers them. The generated dirs are
|
|
17
|
+
ignored through the clone's own `info/exclude`, never through the tracked
|
|
18
|
+
`.gitignore`: a session must not hand the user back a modified file.
|
|
19
|
+
|
|
20
|
+
Every write fails open: a hook must never fail a session because a file could
|
|
21
|
+
not be written. Stdlib only.
|
|
22
|
+
"""
|
|
23
|
+
import glob
|
|
24
|
+
import hashlib
|
|
25
|
+
import json
|
|
26
|
+
import os
|
|
27
|
+
import re
|
|
28
|
+
import subprocess
|
|
29
|
+
|
|
30
|
+
import tezgah_models as tm
|
|
31
|
+
from tezgah_paths import (CONFIG_DIR, HOME, codegraph_bin, host_installed, off,
|
|
32
|
+
root_for)
|
|
33
|
+
|
|
34
|
+
MARKER = "# tezgah: managed by tezgah-agents; do not edit"
|
|
35
|
+
STATE = os.path.join(CONFIG_DIR, "agents.state.json")
|
|
36
|
+
# hosts with a file-based custom-agent surface, and where it lives, relative to
|
|
37
|
+
# the repo. Cursor reads .claude/agents/ natively, so one markdown dir serves
|
|
38
|
+
# both when either is installed; the *detection* of whether a host is installed
|
|
39
|
+
# lives in tezgah_paths.host_installed, not here.
|
|
40
|
+
FILE_HOSTS = ("claude", "opencode", "codex", "cursor")
|
|
41
|
+
HOST_DIRS = {"claude": os.path.join(".claude", "agents"),
|
|
42
|
+
"cursor": os.path.join(".claude", "agents"),
|
|
43
|
+
"opencode": os.path.join(".opencode", "agents"),
|
|
44
|
+
"codex": os.path.join(".codex", "agents")}
|
|
45
|
+
# Stack markers -> a short hint. Exact commands are left to the repo's own docs
|
|
46
|
+
# so a guess never becomes a fabricated test run.
|
|
47
|
+
STACK_FILES = (("pyproject.toml", "python"), ("setup.py", "python"),
|
|
48
|
+
("requirements.txt", "python"), ("package.json", "node"),
|
|
49
|
+
("go.mod", "go"), ("Cargo.toml", "rust"), ("Makefile", "make"))
|
|
50
|
+
# The codegraph surface a brief may name: the MCP tools tezgah's server row
|
|
51
|
+
# enables (CODEGRAPH_MCP_TOOLS in bin/tezgah-setup; `affected` is not among
|
|
52
|
+
# them) and the CLI verbs a role with a shell reaches. A brief that named a tool
|
|
53
|
+
# outside this set would be naming a call the role cannot make.
|
|
54
|
+
GRAPH_TOOL = "codegraph_explore"
|
|
55
|
+
GRAPH_MCP = ("codegraph_explore", "codegraph_impact", "codegraph_callers",
|
|
56
|
+
"codegraph_node")
|
|
57
|
+
# Claude names a server's tools by where it was registered: the plugin's server
|
|
58
|
+
# as `mcp__plugin_tezgah_codegraph__*`, a checkout's own `.mcp.json` server as
|
|
59
|
+
# `mcp__codegraph__*`. A select line names both, so it loads whichever exists.
|
|
60
|
+
MCP_PREFIXES = ("mcp__codegraph__", "mcp__plugin_tezgah_codegraph__")
|
|
61
|
+
GRAPH_SELECT = ",".join(p + t for t in GRAPH_MCP for p in MCP_PREFIXES)
|
|
62
|
+
GRAPH_CLI = ("callers", "callees", "impact", "node", "files")
|
|
63
|
+
GRAPH_TOOLS = ", ".join("`codegraph %s`" % verb for verb in GRAPH_CLI)
|
|
64
|
+
# A role with no shell (Claude `disallowedTools` Bash, opencode `bash: deny`)
|
|
65
|
+
# cannot run `git diff` or the CLI, so its blast radius comes from the caller's
|
|
66
|
+
# brief and the MCP impact tool; a role with a shell runs the diff itself.
|
|
67
|
+
NO_SHELL = ("claude", "opencode")
|
|
68
|
+
# The floor every graph role carries (gortex edge provenance): the index holds
|
|
69
|
+
# only the edges its parser saw, so an absence of callers is a coverage gap
|
|
70
|
+
# until shown otherwise, never a safety verdict.
|
|
71
|
+
EMPTY_IS_NOT_PROOF = (
|
|
72
|
+
"An empty or short caller list is not proof that a change is safe: the\n"
|
|
73
|
+
"index records only the edges its parser saw, so say what it cannot see\n"
|
|
74
|
+
"(dynamic dispatch, string or config lookups, unindexed files) instead of\n"
|
|
75
|
+
"implying the list is complete.")
|
|
76
|
+
# The task class each generated specialist is for, in the order the steering
|
|
77
|
+
# line names them. The orchestrator is not here: it is a primary agent, not one
|
|
78
|
+
# the main thread delegates to.
|
|
79
|
+
STEER = (("mechanical edit (tier from `tezgah-route`)", "tezgah-cheap"),
|
|
80
|
+
("bounded code or tests", "tezgah-standard"),
|
|
81
|
+
("design, invariants, unknown-cause debugging", "tezgah-frontier"),
|
|
82
|
+
("review of a diff", "tezgah-reviewer"))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def manifest_sha():
|
|
86
|
+
try:
|
|
87
|
+
with open(os.path.abspath(__file__), "rb") as fh:
|
|
88
|
+
return hashlib.sha256(fh.read()).hexdigest()[:16]
|
|
89
|
+
except OSError:
|
|
90
|
+
return "unknown"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _stack(root):
|
|
94
|
+
return sorted({name for f, name in STACK_FILES if os.path.exists(os.path.join(root, f))})
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _graph_howto(host):
|
|
98
|
+
if host == "claude":
|
|
99
|
+
# Claude defers MCP schemas, so the tools have to be selected before the
|
|
100
|
+
# first call; the role has no shell, so the MCP tools are its whole graph.
|
|
101
|
+
return ('Load the graph tools first: ToolSearch("select:%s"). You have no\n'
|
|
102
|
+
"shell, so the codegraph CLI is out of reach: use those MCP tools."
|
|
103
|
+
% GRAPH_SELECT)
|
|
104
|
+
if host == "omp":
|
|
105
|
+
# omp's MCP device refuses a second session's call while another one
|
|
106
|
+
# holds the index ("Concurrent write refused"), and a subagent always
|
|
107
|
+
# runs beside its parent, so the CLI is the only graph it can reach.
|
|
108
|
+
return ("Use the codegraph CLI through bash (%s, `codegraph query`,\n"
|
|
109
|
+
"`codegraph status`). Do not call the `xd://mcp__codegraph_*`\n"
|
|
110
|
+
"devices: omp refuses them with \"Concurrent write refused\"\n"
|
|
111
|
+
"while the parent session holds the index." % GRAPH_TOOLS)
|
|
112
|
+
if host == "opencode":
|
|
113
|
+
return ("codegraph is registered as an MCP server (%s). You have no\n"
|
|
114
|
+
"shell, so the codegraph CLI is out of reach: use those MCP tools."
|
|
115
|
+
% ", ".join("`%s`" % t for t in GRAPH_MCP))
|
|
116
|
+
return ("codegraph is registered as an MCP server (default tool\n"
|
|
117
|
+
"`%s`) and the rest of the surface is the CLI (%s); use both as-is."
|
|
118
|
+
% (GRAPH_TOOL, GRAPH_TOOLS))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _blast_radius(host):
|
|
122
|
+
"""How the reviewer derives the blast radius on this host."""
|
|
123
|
+
if host in NO_SHELL:
|
|
124
|
+
return ("You have no shell, so you cannot run `git diff`: the caller passes\n"
|
|
125
|
+
"the changed files and symbols of the target (a base branch, a ref or\n"
|
|
126
|
+
"the PR under review). Run the MCP `codegraph_impact` tool per changed\n"
|
|
127
|
+
"symbol - that is the blast radius. If the brief names no changed files,\n"
|
|
128
|
+
"say so and ask for them instead of guessing.")
|
|
129
|
+
return ("Take the changed files and symbols from `git diff <target>` (a base\n"
|
|
130
|
+
"branch, a ref or the PR under review), then run `codegraph impact\n"
|
|
131
|
+
"<symbol>` per changed symbol - that is the blast radius.\n"
|
|
132
|
+
"`git diff --name-only <target> | codegraph affected --stdin` names the\n"
|
|
133
|
+
"test files the change reaches.")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _may_use(host):
|
|
137
|
+
"""The read-only roles' tool sentence: on omp and Codex the role has a shell,
|
|
138
|
+
and the sentence bounds it to the codegraph CLI and read-only git."""
|
|
139
|
+
if host in ("omp", "codex"):
|
|
140
|
+
return ("You may use: read, grep, glob, and a shell for the `codegraph` CLI\n"
|
|
141
|
+
"and read-only `git` (diff, log, show) only. Read-only: no writes, no\n"
|
|
142
|
+
"edits, no other shell command.")
|
|
143
|
+
return ("You may use: the codegraph MCP tools, read, grep and glob. Read-only:\n"
|
|
144
|
+
"no writes, no edits, no shell.")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def detect_infra(root):
|
|
148
|
+
"""Capabilities + stack + file-surface hosts for the enclosing repo."""
|
|
149
|
+
caps = {
|
|
150
|
+
"graph": bool(codegraph_bin()) and not os.path.exists(
|
|
151
|
+
os.path.join(root, ".no-graph")),
|
|
152
|
+
}
|
|
153
|
+
try:
|
|
154
|
+
cfg = json.load(open(os.path.join(CONFIG_DIR, "config.json"), encoding="utf-8"))
|
|
155
|
+
configured = cfg.get("hosts")
|
|
156
|
+
except Exception:
|
|
157
|
+
configured = None
|
|
158
|
+
if configured:
|
|
159
|
+
# An explicit list is the answer, even when it names no file host: omp
|
|
160
|
+
# keeps its subagents user-level, and rendering .claude/.cursor files
|
|
161
|
+
# for a host the user did not list is not what that list asked for.
|
|
162
|
+
hosts = [h for h in configured if h in FILE_HOSTS]
|
|
163
|
+
else:
|
|
164
|
+
hosts = [h for h in FILE_HOSTS if host_installed(h)]
|
|
165
|
+
return {"caps": caps, "stack": _stack(root), "hosts": hosts}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ------------------------------------------------------------------ roles ----
|
|
169
|
+
|
|
170
|
+
def _reviewer_body(host):
|
|
171
|
+
return (
|
|
172
|
+
"You are tezgah-reviewer, an adversarial code reviewer. Review a change,\n"
|
|
173
|
+
"not the whole repo, with the code graph as below.\n\n"
|
|
174
|
+
"%s\n\n"
|
|
175
|
+
"Review the raw artifact, never a summary of it and never the author's\n"
|
|
176
|
+
"self-assessment. Format, schema, frontmatter and spec-compliance problems\n"
|
|
177
|
+
"live in the exact text, and a framing you were handed is a finding you will\n"
|
|
178
|
+
"not make: a reviewer given the implementer's view finds measurably fewer\n"
|
|
179
|
+
"defects. If you were handed a paraphrase, read the files instead.\n\n"
|
|
180
|
+
"%s Read the changed code and any caller you intend to accuse.\n"
|
|
181
|
+
"%s\n"
|
|
182
|
+
"Look only for defects the change causes: correctness, contract/callers,\n"
|
|
183
|
+
"security, tests, concurrency and performance. Classify every candidate as\n"
|
|
184
|
+
"confirmed (concrete failure scenario + file:line), refuted (a guard,\n"
|
|
185
|
+
"caller contract, type or test already prevents it) or unverified (not\n"
|
|
186
|
+
"settled). Default to refuted when the evidence is unclear. Only the code\n"
|
|
187
|
+
"or a run you observed settles a candidate: a doc, a comment, a lessons\n"
|
|
188
|
+
"file, a memory note or an earlier report may raise a question but never\n"
|
|
189
|
+
"makes it confirmed or refuted on its own. Report only confirmed findings\n"
|
|
190
|
+
"as bugs; no style notes, no praise; empty is the correct answer for a\n"
|
|
191
|
+
"clean change.\n\n"
|
|
192
|
+
"Score the constraints separately from the defects. For every constraint\n"
|
|
193
|
+
"the task stated - keep this behaviour, touch no other file, preserve this\n"
|
|
194
|
+
"format - report kept or violated with the file:line that shows which. A\n"
|
|
195
|
+
"patch that passes the tests and breaks a stated constraint is not clean,\n"
|
|
196
|
+
"and a functional test will not notice it.\n\n"
|
|
197
|
+
"Every finding carries a severity - critical (the change cannot stand as\n"
|
|
198
|
+
"written), major (a real weakness that must be fixed), minor (noticeable),\n"
|
|
199
|
+
"suggestion (an improvement, not a flaw) - and a verbatim quote of the\n"
|
|
200
|
+
"code it accuses; a finding about an absence carries no quote. A severity\n"
|
|
201
|
+
"is lowered only by evidence: a check you could not complete never\n"
|
|
202
|
+
"downgrades a confirmed finding - keep its severity and mark it\n"
|
|
203
|
+
"provisional. Disclose the order you read the files in.\n\n"
|
|
204
|
+
"Scope and budget. Every round that confirms a defect is followed by a\n"
|
|
205
|
+
"round over that fix's delta; the review ends when a round confirms none.\n"
|
|
206
|
+
"A later round reads only the delta since the sha the previous round\n"
|
|
207
|
+
"recorded (`tezgah-task review` prints it): re-reading the whole diff\n"
|
|
208
|
+
"re-reports what was already triaged. Test results are input, not a task\n"
|
|
209
|
+
"- read the author's output file; do not run the suite, and run at most one\n"
|
|
210
|
+
"`-k` test when a specific accusation needs it. The same defect family\n"
|
|
211
|
+
"confirmed three times is a sign the design needs a pivot, not another\n"
|
|
212
|
+
"patch.\n\n"
|
|
213
|
+
"%s" % (_graph_howto(host), _blast_radius(host), EMPTY_IS_NOT_PROOF,
|
|
214
|
+
_may_use(host)))
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _worker_body(tier):
|
|
218
|
+
def body(_host):
|
|
219
|
+
if tier == "frontier":
|
|
220
|
+
scope = ("You take the work the cheaper tiers must not: design choices,\n"
|
|
221
|
+
"stored-data and ordering invariants, security-sensitive code,\n"
|
|
222
|
+
"failures with an unknown cause, hard-to-reverse changes.")
|
|
223
|
+
else:
|
|
224
|
+
scope = ("If the work needs a judgement above this tier - a design choice,\n"
|
|
225
|
+
"a stored-data or ordering invariant, security-sensitive code, or\n"
|
|
226
|
+
"a failure whose cause you cannot find - stop editing and answer\n"
|
|
227
|
+
"`ESCALATE: <why>`; the router restarts it on tezgah-frontier.")
|
|
228
|
+
return ("You are tezgah-%s, a worker on the %s model tier. Do exactly the\n"
|
|
229
|
+
"brief: stay inside the files it names, run the checks it names, and\n"
|
|
230
|
+
"report what changed and what each check printed, verbatim. Report\n"
|
|
231
|
+
"progress, but never redefine the work. Never widen or narrow the brief's\n"
|
|
232
|
+
"scope, budget or question. If the brief cannot be met as written, say\n"
|
|
233
|
+
"so and stop rather than answering a different question.\n%s\n"
|
|
234
|
+
"Never spawn subagents." % (tier, tier, scope))
|
|
235
|
+
return body
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# name, description, capability gate, body(host), read-only?
|
|
239
|
+
ROLES = (
|
|
240
|
+
("tezgah-reviewer",
|
|
241
|
+
"Adversarial, read-only review of a diff, branch or PR: derives the blast "
|
|
242
|
+
"radius, checks correctness, contract, security, tests and performance, and "
|
|
243
|
+
"classifies every finding confirmed/refuted/unverified.",
|
|
244
|
+
lambda infra: infra["caps"]["graph"], _reviewer_body, True),
|
|
245
|
+
("tezgah-cheap",
|
|
246
|
+
"Mechanical, fully specified edits on the cheapest model tier: renames, "
|
|
247
|
+
"fixtures, formatting, version bumps, commit messages, a listed migration. "
|
|
248
|
+
"Chosen by `tezgah-route`; answers ESCALATE when the work needs judgement.",
|
|
249
|
+
lambda infra: True, _worker_body("cheap"), False),
|
|
250
|
+
("tezgah-standard",
|
|
251
|
+
"Bounded code, tests, search-and-summarise or a small review on the standard "
|
|
252
|
+
"model tier. Chosen by `tezgah-route`; answers ESCALATE when the work needs "
|
|
253
|
+
"judgement above it.",
|
|
254
|
+
lambda infra: True, _worker_body("standard"), False),
|
|
255
|
+
("tezgah-frontier",
|
|
256
|
+
"Design, stored-data or ordering invariants, security-sensitive code, "
|
|
257
|
+
"unknown-cause debugging and hard-to-reverse changes on the strongest model "
|
|
258
|
+
"tier; also where an ESCALATE from a cheaper worker is restarted.",
|
|
259
|
+
lambda infra: True, _worker_body("frontier"), False),
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# The roles gated on the code graph, which a repo's `.no-graph` turns off.
|
|
263
|
+
GRAPH_ROLES = ("tezgah-reviewer",)
|
|
264
|
+
# Every agent name tezgah ever generated: the live roles, the orchestrator and
|
|
265
|
+
# the retired roles. omp's files carry no MARKER, so this list - not the
|
|
266
|
+
# `tezgah-` prefix - is what makes a file there tezgah's to sweep.
|
|
267
|
+
RETIRED_ROLES = ("tezgah-explorer", "tezgah-verifier", "tezgah-researcher")
|
|
268
|
+
OWNED_NAMES = tuple(r[0] for r in ROLES) + ("tezgah-orchestrator",) + RETIRED_ROLES
|
|
269
|
+
|
|
270
|
+
ORCH_DESC = ("Route work in this repo to the generated tezgah-* subagents. The "
|
|
271
|
+
"main thread decides and verifies; delegate bounded, well-specified "
|
|
272
|
+
"work and never let a subagent orchestrate another.")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _orch_body(names):
|
|
276
|
+
listed = ", ".join(names) if names else "(none active yet)"
|
|
277
|
+
return (
|
|
278
|
+
"You are the tezgah orchestrator for this repository. You decide and\n"
|
|
279
|
+
"verify; you delegate bounded, well-specified work and read the evidence\n"
|
|
280
|
+
"back. Available specialists: %s.\n\n"
|
|
281
|
+
"Route reviews to tezgah-reviewer, with the changed files and symbols in\n"
|
|
282
|
+
"the brief: where it has no shell it cannot run `git diff` itself. Brief a\n"
|
|
283
|
+
"code-discovery task to a tier worker with the codegraph tools; a second\n"
|
|
284
|
+
"opinion (`consult`) and research (`orx`) stay with the main thread. Other\n"
|
|
285
|
+
"work goes to the tier worker\n"
|
|
286
|
+
"`tezgah-route \"<brief>\"` names (tezgah-cheap, tezgah-standard,\n"
|
|
287
|
+
"tezgah-frontier); an ESCALATE answer is restarted on tezgah-frontier with\n"
|
|
288
|
+
"the same brief. Never delegate a task a specialist is not\n"
|
|
289
|
+
"listed for, and never let a subagent spawn its own subagents. Verify each\n"
|
|
290
|
+
"returned claim against the code before acting." % listed)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# ---------------------------------------------------------------- renderers --
|
|
294
|
+
|
|
295
|
+
# Claude Code's own aliases: an alias follows the provider (and keeps the main
|
|
296
|
+
# session's variant and context), while a full id breaks on Bedrock, Vertex and
|
|
297
|
+
# a gateway (code.claude.com/docs/en/sub-agents, model/effort table).
|
|
298
|
+
CLAUDE_ALIAS = (("claude-opus", "opus"), ("claude-sonnet", "sonnet"),
|
|
299
|
+
("claude-haiku", "haiku"), ("claude-fable", "fable"))
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _claude_model(model):
|
|
303
|
+
for prefix, alias in CLAUDE_ALIAS:
|
|
304
|
+
if model.startswith(prefix):
|
|
305
|
+
return alias
|
|
306
|
+
return model
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _model_lines(name, family, model_fmt, effort_fmt):
|
|
310
|
+
"""The model (and effort) lines the table gives this agent on a family;
|
|
311
|
+
`model: inherit` on Claude/Cursor for an agent with no slot. Cursor reads
|
|
312
|
+
this same file but wants its own ids and the effort inside the id
|
|
313
|
+
(`claude-opus-5[effort=high]`, cursor.com/docs/subagents) - unverified for
|
|
314
|
+
the ids this table names, so Cursor is documented, not guessed at."""
|
|
315
|
+
picked = tm.pick(name, family)
|
|
316
|
+
if not picked:
|
|
317
|
+
return ["model: inherit"] if family == "anthropic" else []
|
|
318
|
+
model, effort = picked
|
|
319
|
+
if family == "anthropic":
|
|
320
|
+
model = _claude_model(model)
|
|
321
|
+
return [model_fmt % model] + ([effort_fmt % effort] if effort else [])
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _fold(desc, width=74):
|
|
325
|
+
out = []
|
|
326
|
+
for chunk in re.findall(r".{1,%d}(?:\s|$)" % width, desc.strip()):
|
|
327
|
+
if chunk.strip():
|
|
328
|
+
out.append(" " + chunk.strip())
|
|
329
|
+
return out or [" " + desc.strip()]
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def render_md(name, description, readonly, body):
|
|
333
|
+
"""Claude Code / Cursor markdown. Cursor ignores unknown keys and honours
|
|
334
|
+
`readonly`; Claude denies the write/shell tools explicitly."""
|
|
335
|
+
lines = ["---", MARKER + " (manifest %s)" % manifest_sha(),
|
|
336
|
+
"name: %s" % name, "description: >"]
|
|
337
|
+
lines += _fold(description)
|
|
338
|
+
lines += _model_lines(name, "anthropic", "model: %s", "effort: %s")
|
|
339
|
+
if readonly:
|
|
340
|
+
# `disallowedTools` is Claude's; `readonly` is Cursor's. Both parsers
|
|
341
|
+
# ignore the other's field.
|
|
342
|
+
lines.append("readonly: true")
|
|
343
|
+
lines.append("disallowedTools: Write, Edit, NotebookEdit, Bash, Agent")
|
|
344
|
+
lines.append("---")
|
|
345
|
+
return "\n".join(lines) + "\n\n" + body.strip() + "\n"
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def plugin_agents():
|
|
349
|
+
"""{filename: text} for the plugin's own tracked `agents/` dir.
|
|
350
|
+
|
|
351
|
+
The graph roles' Claude render, from the same body the per-repo files get,
|
|
352
|
+
so the shipped copy cannot drift from the generated one. The MARKER line is
|
|
353
|
+
dropped: the copy is tracked, never swept by `_remove_stale`, and its
|
|
354
|
+
manifest sha would turn every edit of this module into a stale file.
|
|
355
|
+
`tezgah-setup --write-plugin-agents` writes it; a test pins it."""
|
|
356
|
+
out = {}
|
|
357
|
+
for name, desc, _cap, body, readonly in ROLES:
|
|
358
|
+
if name in GRAPH_ROLES:
|
|
359
|
+
lines = render_md(name, desc, readonly, body("claude")).split("\n")
|
|
360
|
+
out[name + ".md"] = "\n".join(lines[:1] + lines[2:])
|
|
361
|
+
return out
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def render_md_opencode(name, description, readonly, body):
|
|
365
|
+
"""opencode `.opencode/agents/*.md`. opencode validates `tools` as an object
|
|
366
|
+
(the Claude `Agent(...)` string is rejected), so this uses opencode's own
|
|
367
|
+
`mode` + `permission` keys and never emits a `tools` string."""
|
|
368
|
+
lines = ["---", MARKER + " (manifest %s)" % manifest_sha(),
|
|
369
|
+
"name: %s" % name, "description: >"]
|
|
370
|
+
lines += _fold(description)
|
|
371
|
+
lines.append("mode: subagent")
|
|
372
|
+
if tm.opencode_model(name):
|
|
373
|
+
lines.append("model: %s" % tm.opencode_model(name))
|
|
374
|
+
if readonly:
|
|
375
|
+
lines += ["permission:", " edit: deny", " bash: deny", " task: deny"]
|
|
376
|
+
lines.append("---")
|
|
377
|
+
return "\n".join(lines) + "\n\n" + body.strip() + "\n"
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _toml_str(s):
|
|
381
|
+
"""A literal multi-line TOML string, safe for our controlled bodies."""
|
|
382
|
+
return "'''" + s.replace("'''", "''\\'") + "'''"
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def render_md_omp(name, description, body, tools=("read", "grep", "glob", "bash")):
|
|
386
|
+
"""omp subagent markdown: name/description frontmatter plus a tool list.
|
|
387
|
+
|
|
388
|
+
omp has no `readonly` key. Every role gets bash: the read-only ones are the
|
|
389
|
+
graph roles, whose graph on omp is the `codegraph` CLI (see _graph_howto),
|
|
390
|
+
and their body bounds the shell to that CLI."""
|
|
391
|
+
lines = ["---", "name: %s" % name, "description: >"]
|
|
392
|
+
lines += _fold(description)
|
|
393
|
+
if tools: # None: every tool the session has (a tier worker edits)
|
|
394
|
+
lines.append("tools:")
|
|
395
|
+
lines += [" - %s" % t for t in tools]
|
|
396
|
+
lines.append("---")
|
|
397
|
+
return "\n".join(lines) + "\n\n" + body.strip() + "\n"
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def omp_user_agents(root="~"):
|
|
401
|
+
"""{filename: text} for omp's user agent dir (~/.omp/agent/agents); empty
|
|
402
|
+
under `agents-off`, so the installer's sweep removes the files."""
|
|
403
|
+
if off("agents-off"):
|
|
404
|
+
return {}
|
|
405
|
+
infra = detect_infra(os.path.expanduser(root))
|
|
406
|
+
active = [r for r in ROLES if r[2](infra)]
|
|
407
|
+
names = [r[0] for r in active]
|
|
408
|
+
if not names:
|
|
409
|
+
return {}
|
|
410
|
+
out = {name + ".md": render_md_omp(
|
|
411
|
+
name, desc, body("omp"),
|
|
412
|
+
**({"tools": None} if name[len("tezgah-"):] in tm.TIERS else {}))
|
|
413
|
+
for name, desc, _cap, body, _readonly in active}
|
|
414
|
+
out["tezgah-orchestrator.md"] = render_md_omp(
|
|
415
|
+
"tezgah-orchestrator", ORCH_DESC, _orch_body(names),
|
|
416
|
+
tools=("read", "grep", "glob", "bash", "task"))
|
|
417
|
+
return out
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def steering(root, host=None):
|
|
421
|
+
"""One line naming the generated specialists this host can spawn, or None.
|
|
422
|
+
|
|
423
|
+
Nothing else in the contract points the main agent at them, so a model
|
|
424
|
+
reached for the host's generic explorer instead. Existence is read from
|
|
425
|
+
disk, not from the capabilities: a specialist is named only when its file
|
|
426
|
+
is there for the host to load - omp's user agent dir on omp, the repo's
|
|
427
|
+
generated dirs everywhere else. A repo's `.no-graph` turns the graph off
|
|
428
|
+
there, so a graph role is not named in it even when omp's user-level file
|
|
429
|
+
exists."""
|
|
430
|
+
if host == "omp":
|
|
431
|
+
dirs = [os.path.join(HOME, ".omp", "agent", "agents")]
|
|
432
|
+
else:
|
|
433
|
+
dirs = [os.path.join(root, d) for d in set(HOST_DIRS.values())]
|
|
434
|
+
have = {os.path.splitext(os.path.basename(p))[0]
|
|
435
|
+
for d in dirs for p in glob.glob(os.path.join(d, "tezgah-*.*"))}
|
|
436
|
+
if os.path.exists(os.path.join(root, ".no-graph")):
|
|
437
|
+
have -= set(GRAPH_ROLES)
|
|
438
|
+
pairs = ["%s -> %s" % (task, name) for task, name in STEER if name in have]
|
|
439
|
+
if not pairs:
|
|
440
|
+
return None
|
|
441
|
+
return ("Specialists for this host: %s. Spawn them by name instead of a "
|
|
442
|
+
"generic explorer or task agent." % "; ".join(pairs))
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def render_toml(name, description, readonly, body):
|
|
446
|
+
"""Codex `.codex/agents/*.toml` (name/description/developer_instructions)."""
|
|
447
|
+
lines = [MARKER + " (manifest %s)" % manifest_sha(),
|
|
448
|
+
'name = "%s"' % name,
|
|
449
|
+
"description = " + _toml_str(description)]
|
|
450
|
+
lines += _model_lines(name, "openai", 'model = "%s"', 'model_reasoning_effort = "%s"')
|
|
451
|
+
if readonly:
|
|
452
|
+
lines.append('sandbox_mode = "read-only"')
|
|
453
|
+
lines.append("developer_instructions = " + _toml_str(body.strip()))
|
|
454
|
+
return "\n".join(lines) + "\n"
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def render_orch_md(names):
|
|
458
|
+
tools = ", ".join(names) if names else "Read, Grep, Glob"
|
|
459
|
+
fm = ("---\n%s (manifest %s)\nname: tezgah-orchestrator\n"
|
|
460
|
+
"description: %s\nmodel: inherit\ntools: Agent(%s), Read, Grep, Glob\n---\n"
|
|
461
|
+
% (MARKER, manifest_sha(), ORCH_DESC, tools))
|
|
462
|
+
return fm + "\n" + _orch_body(names) + "\n"
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def render_orch_md_opencode(names):
|
|
466
|
+
fm = ("---\n%s (manifest %s)\nname: tezgah-orchestrator\n"
|
|
467
|
+
"description: %s\nmode: primary\n"
|
|
468
|
+
"permission:\n task:\n \"*\": deny\n \"tezgah-*\": allow\n---\n"
|
|
469
|
+
% (MARKER, manifest_sha(), ORCH_DESC))
|
|
470
|
+
return fm + "\n" + _orch_body(names) + "\n"
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def orch_opencode_entry(names):
|
|
474
|
+
return {"description": ORCH_DESC, "mode": "primary", "prompt": _orch_body(names),
|
|
475
|
+
"permission": {"task": {"*": "deny", "tezgah-*": "allow"}}}
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def _role_oc_entry(name, desc, body, readonly):
|
|
479
|
+
entry = {"description": desc, "mode": "subagent", "prompt": body}
|
|
480
|
+
if tm.opencode_model(name):
|
|
481
|
+
entry["model"] = tm.opencode_model(name)
|
|
482
|
+
picked = tm.pick(name, "any")
|
|
483
|
+
if picked and picked[1]:
|
|
484
|
+
# the JSON agent config is where opencode documents the effort
|
|
485
|
+
# (opencode.ai/docs/agents, `reasoningEffort`)
|
|
486
|
+
entry["reasoningEffort"] = picked[1]
|
|
487
|
+
if readonly:
|
|
488
|
+
entry["permission"] = {"edit": "deny", "bash": "deny", "task": "deny"}
|
|
489
|
+
return entry
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
# ------------------------------------------------------------------- sync ----
|
|
493
|
+
|
|
494
|
+
def _read(path):
|
|
495
|
+
try:
|
|
496
|
+
with open(path, encoding="utf-8") as fh:
|
|
497
|
+
return fh.read()
|
|
498
|
+
except OSError:
|
|
499
|
+
return None
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _is_managed(text):
|
|
503
|
+
return bool(text) and MARKER in text
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def _write_if_changed(path, text):
|
|
507
|
+
"""True when the file changed. Fails open, as the module promises: a hook
|
|
508
|
+
must never fail a session because a file could not be written."""
|
|
509
|
+
if _read(path) == text:
|
|
510
|
+
return False
|
|
511
|
+
tmp = path + ".tezgah-tmp"
|
|
512
|
+
try:
|
|
513
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
514
|
+
with open(tmp, "w", encoding="utf-8") as fh:
|
|
515
|
+
fh.write(text)
|
|
516
|
+
os.replace(tmp, path)
|
|
517
|
+
except OSError:
|
|
518
|
+
try:
|
|
519
|
+
os.remove(tmp) # os.replace onto a directory leaves it behind
|
|
520
|
+
except OSError:
|
|
521
|
+
pass
|
|
522
|
+
return False
|
|
523
|
+
return True
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def _remove_stale(directory, wanted):
|
|
527
|
+
"""Delete only tezgah-managed files no longer in the wanted set."""
|
|
528
|
+
for path in glob.glob(os.path.join(directory, "tezgah-*.*")):
|
|
529
|
+
if os.path.basename(path) not in wanted and _is_managed(_read(path)):
|
|
530
|
+
try:
|
|
531
|
+
os.remove(path)
|
|
532
|
+
except OSError:
|
|
533
|
+
pass
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
BLOCK_BEGIN = ("# tezgah: generated agents (managed; removed by "
|
|
537
|
+
"tezgah-setup --uninstall)")
|
|
538
|
+
BLOCK_END = "# tezgah: end generated agents"
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def _strip_block(text):
|
|
542
|
+
out, skip = [], False
|
|
543
|
+
for line in text.splitlines(keepends=True):
|
|
544
|
+
stripped = line.strip()
|
|
545
|
+
if stripped == BLOCK_BEGIN:
|
|
546
|
+
skip = True
|
|
547
|
+
continue
|
|
548
|
+
if stripped == BLOCK_END:
|
|
549
|
+
skip = False
|
|
550
|
+
continue
|
|
551
|
+
if not skip:
|
|
552
|
+
out.append(line)
|
|
553
|
+
return "".join(out)
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def _block_dirs(text):
|
|
557
|
+
"""The dir names already inside the managed block of `text`."""
|
|
558
|
+
out, inside = set(), False
|
|
559
|
+
for line in text.splitlines():
|
|
560
|
+
s = line.strip()
|
|
561
|
+
if s == BLOCK_BEGIN:
|
|
562
|
+
inside = True
|
|
563
|
+
elif s == BLOCK_END:
|
|
564
|
+
inside = False
|
|
565
|
+
elif inside and s.startswith("/") and s.endswith("/"):
|
|
566
|
+
out.add(s.strip("/"))
|
|
567
|
+
return out
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def _put_block(old, block):
|
|
571
|
+
"""Put the managed block where it already is, or append it at the end.
|
|
572
|
+
|
|
573
|
+
Rebuilding the file around the block used to move it to the end of any file
|
|
574
|
+
whose block sat mid-file, so the first session start in a fresh checkout
|
|
575
|
+
dirtied the tree with a pure move. Replacing it in place keeps the user's
|
|
576
|
+
ordering, and the caller's `new != old` check then writes nothing."""
|
|
577
|
+
out, inside, replaced = [], False, False
|
|
578
|
+
for line in old.splitlines():
|
|
579
|
+
s = line.strip()
|
|
580
|
+
if s == BLOCK_BEGIN:
|
|
581
|
+
inside, replaced = True, True
|
|
582
|
+
out.extend(block.splitlines())
|
|
583
|
+
continue
|
|
584
|
+
if s == BLOCK_END:
|
|
585
|
+
inside = False
|
|
586
|
+
continue
|
|
587
|
+
if not inside:
|
|
588
|
+
out.append(line)
|
|
589
|
+
if not replaced:
|
|
590
|
+
body = "\n".join(out).strip("\n")
|
|
591
|
+
return (body + "\n\n" if body else "") + block
|
|
592
|
+
return "\n".join(out).strip("\n") + "\n"
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
def _exclude_path(root):
|
|
596
|
+
"""The clone's own `info/exclude`, or None when `root` is not a git tree.
|
|
597
|
+
|
|
598
|
+
A plain checkout answers from the directory listing, so a session start
|
|
599
|
+
keeps its two git forks; a linked worktree or submodule (`.git` is a file)
|
|
600
|
+
asks git, which resolves the path through the common dir - the file git
|
|
601
|
+
actually reads, not a per-worktree path it ignores. GIT_DIR/GIT_WORK_TREE
|
|
602
|
+
move the repository out from under that listing, so a set environment means
|
|
603
|
+
only git can answer."""
|
|
604
|
+
dot = os.path.join(root, ".git")
|
|
605
|
+
if (os.path.isdir(dot) and not os.environ.get("GIT_DIR")
|
|
606
|
+
and not os.environ.get("GIT_WORK_TREE")):
|
|
607
|
+
return os.path.join(dot, "info", "exclude")
|
|
608
|
+
if not os.path.exists(dot) and not os.environ.get("GIT_DIR"):
|
|
609
|
+
return None
|
|
610
|
+
try:
|
|
611
|
+
out = subprocess.run(("git", "-C", root, "rev-parse", "--git-path",
|
|
612
|
+
"info/exclude"),
|
|
613
|
+
capture_output=True, text=True, timeout=5)
|
|
614
|
+
except (OSError, subprocess.SubprocessError):
|
|
615
|
+
return None
|
|
616
|
+
path = out.stdout.strip()
|
|
617
|
+
if out.returncode != 0 or not path:
|
|
618
|
+
return None
|
|
619
|
+
return path if os.path.isabs(path) else os.path.join(root, path)
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
def ensure_exclude(root, dirs):
|
|
623
|
+
"""Ignore the generated agent dirs in the clone's own exclude file.
|
|
624
|
+
|
|
625
|
+
NOT in `.gitignore`: that file is tracked, so writing it handed the user a
|
|
626
|
+
repository back with a modification nobody asked for. `info/exclude` is
|
|
627
|
+
per-clone, never committed and still keeps `git status` clean, which is all
|
|
628
|
+
the ignore line was ever for. The block is a UNION with what is already
|
|
629
|
+
there: a dir ignored by an earlier install keeps its line even when its host
|
|
630
|
+
is not in the current set, so a config change can never un-ignore a
|
|
631
|
+
generated-agent dir. Returns the exclude path, or None when opted out with
|
|
632
|
+
TEZGAH_NO_EXCLUDE=1, when the root is not a git work tree, or when there is
|
|
633
|
+
nothing to ignore."""
|
|
634
|
+
if os.environ.get("TEZGAH_NO_EXCLUDE") == "1":
|
|
635
|
+
return None
|
|
636
|
+
path = _exclude_path(root)
|
|
637
|
+
if not path:
|
|
638
|
+
return None
|
|
639
|
+
old = _read(path) or ""
|
|
640
|
+
dirs = sorted(set(d for d in dirs if d) | _block_dirs(old))
|
|
641
|
+
if not dirs:
|
|
642
|
+
return None
|
|
643
|
+
block = "\n".join([BLOCK_BEGIN] + ["/" + d + "/" for d in dirs]
|
|
644
|
+
+ [BLOCK_END]) + "\n"
|
|
645
|
+
new = _put_block(old, block)
|
|
646
|
+
_write_if_changed(path, new)
|
|
647
|
+
return path
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def sync_root(root, report_steady=False):
|
|
651
|
+
"""Generate/refresh this repo's agents.
|
|
652
|
+
|
|
653
|
+
Returns a one-line status - a write, a removal, or, only when
|
|
654
|
+
`report_steady`, "N agent(s) current". A steady state returns None by
|
|
655
|
+
default because the session hook injects this line: a session that changed
|
|
656
|
+
nothing was being told about tezgah's own files in the repo. The explicit
|
|
657
|
+
CLI asks for the steady line, since it is answering a user's command.
|
|
658
|
+
|
|
659
|
+
Under `agents-off` nothing is generated and the sweep below still runs:
|
|
660
|
+
the switch removes what an earlier session wrote, so the host stops
|
|
661
|
+
loading it."""
|
|
662
|
+
if not root_for(root):
|
|
663
|
+
return None
|
|
664
|
+
disabled = off("agents-off")
|
|
665
|
+
infra = detect_infra(root)
|
|
666
|
+
hosts = set() if disabled else set(infra["hosts"])
|
|
667
|
+
active = [] if disabled else [r for r in ROLES if r[2](infra)]
|
|
668
|
+
names = [r[0] for r in active]
|
|
669
|
+
|
|
670
|
+
# markdown: one dir serves Claude and Cursor (Cursor reads .claude/agents/)
|
|
671
|
+
md_dir = os.path.join(root, HOST_DIRS["claude"]) if hosts & {"claude", "cursor"} else None
|
|
672
|
+
oc_dir = os.path.join(root, HOST_DIRS["opencode"]) if "opencode" in hosts else None
|
|
673
|
+
codex_dir = os.path.join(root, HOST_DIRS["codex"]) if "codex" in hosts else None
|
|
674
|
+
|
|
675
|
+
written, removed = 0, 0
|
|
676
|
+
paths = []
|
|
677
|
+
|
|
678
|
+
def emit(directory, wanted, name, text):
|
|
679
|
+
nonlocal written
|
|
680
|
+
wanted.add(name)
|
|
681
|
+
path = os.path.join(directory, name)
|
|
682
|
+
if _write_if_changed(path, text):
|
|
683
|
+
written += 1
|
|
684
|
+
paths.append(path)
|
|
685
|
+
|
|
686
|
+
wanted_md, wanted_oc, wanted_codex = set(), set(), set()
|
|
687
|
+
|
|
688
|
+
def sweep(directory, wanted):
|
|
689
|
+
nonlocal removed
|
|
690
|
+
before = set(os.path.basename(p) for p in glob.glob(os.path.join(directory, "tezgah-*.*")))
|
|
691
|
+
_remove_stale(directory, wanted)
|
|
692
|
+
after = set(os.path.basename(p) for p in glob.glob(os.path.join(directory, "tezgah-*.*")))
|
|
693
|
+
removed += len(before - after)
|
|
694
|
+
|
|
695
|
+
if md_dir and names: # Claude Code + Cursor
|
|
696
|
+
for name, desc, _cap, body, readonly in active:
|
|
697
|
+
emit(md_dir, wanted_md, name + ".md", render_md(name, desc, readonly, body("claude")))
|
|
698
|
+
emit(md_dir, wanted_md, "tezgah-orchestrator.md", render_orch_md(names))
|
|
699
|
+
|
|
700
|
+
if oc_dir and names: # opencode
|
|
701
|
+
for name, desc, _cap, body, readonly in active:
|
|
702
|
+
emit(oc_dir, wanted_oc, name + ".md",
|
|
703
|
+
render_md_opencode(name, desc, readonly, body("opencode")))
|
|
704
|
+
emit(oc_dir, wanted_oc, "tezgah-orchestrator.md", render_orch_md_opencode(names))
|
|
705
|
+
|
|
706
|
+
if codex_dir and names: # Codex (no orchestrator agent; the main thread orchestrates)
|
|
707
|
+
for name, desc, _cap, body, readonly in active:
|
|
708
|
+
emit(codex_dir, wanted_codex, name + ".toml",
|
|
709
|
+
render_toml(name, desc, readonly, body("codex")))
|
|
710
|
+
|
|
711
|
+
# The sweep runs over every dir this module can write, not only the selected
|
|
712
|
+
# ones: a host dropped from the config, or a capability that disappeared,
|
|
713
|
+
# must not leave tezgah agents behind for the host to keep loading.
|
|
714
|
+
sweep(os.path.join(root, HOST_DIRS["claude"]), wanted_md)
|
|
715
|
+
sweep(os.path.join(root, HOST_DIRS["opencode"]), wanted_oc)
|
|
716
|
+
sweep(os.path.join(root, HOST_DIRS["codex"]), wanted_codex)
|
|
717
|
+
|
|
718
|
+
if paths:
|
|
719
|
+
dirs = set()
|
|
720
|
+
if md_dir:
|
|
721
|
+
dirs.add(HOST_DIRS["claude"])
|
|
722
|
+
if oc_dir:
|
|
723
|
+
dirs.add(HOST_DIRS["opencode"])
|
|
724
|
+
if codex_dir:
|
|
725
|
+
dirs.add(HOST_DIRS["codex"])
|
|
726
|
+
ex = ensure_exclude(root, dirs)
|
|
727
|
+
if ex:
|
|
728
|
+
paths.append(ex)
|
|
729
|
+
_record(root, paths)
|
|
730
|
+
# A steady-state session stays silent about the files tezgah keeps in this
|
|
731
|
+
# repo: the "N agent(s) current" line rode into every session brief and read
|
|
732
|
+
# as work tezgah was asking for. Only a change is worth a line.
|
|
733
|
+
if written:
|
|
734
|
+
return ("%d agent(s) written%s"
|
|
735
|
+
% (len(names), ", %d removed" % removed if removed else ""))
|
|
736
|
+
if removed:
|
|
737
|
+
return "%d stale agent file(s) removed" % removed
|
|
738
|
+
if report_steady and names and (md_dir or oc_dir or codex_dir):
|
|
739
|
+
return "%d agent(s) current" % len(names)
|
|
740
|
+
return None
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def opencode_agents_json(root):
|
|
744
|
+
"""The active roles as opencode `config.agent` entries, or {}.
|
|
745
|
+
|
|
746
|
+
The opencode plugin calls this at config load (via `tezgah-agents --json`) so
|
|
747
|
+
the generated agents exist in the SAME session, not only the next one."""
|
|
748
|
+
if off("agents-off") or not root_for(root):
|
|
749
|
+
return {}
|
|
750
|
+
infra = detect_infra(root)
|
|
751
|
+
if "opencode" not in infra["hosts"]:
|
|
752
|
+
return {}
|
|
753
|
+
active = [r for r in ROLES if r[2](infra)]
|
|
754
|
+
names = [r[0] for r in active]
|
|
755
|
+
if not names:
|
|
756
|
+
return {}
|
|
757
|
+
agent = {r[0]: _role_oc_entry(r[0], r[1], r[3]("opencode"), r[4]) for r in active}
|
|
758
|
+
agent["tezgah-orchestrator"] = orch_opencode_entry(names)
|
|
759
|
+
return {"agent": agent}
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
def _record(root, paths):
|
|
763
|
+
"""Remember generated paths so --uninstall can remove exactly them."""
|
|
764
|
+
try:
|
|
765
|
+
data = json.load(open(STATE, encoding="utf-8"))
|
|
766
|
+
if not isinstance(data, dict):
|
|
767
|
+
data = {}
|
|
768
|
+
except Exception:
|
|
769
|
+
data = {}
|
|
770
|
+
slug = re.sub(r"[^A-Za-z0-9]+", "-", os.path.realpath(root)).strip("-")
|
|
771
|
+
data[slug] = sorted(set(paths))
|
|
772
|
+
try:
|
|
773
|
+
os.makedirs(CONFIG_DIR, exist_ok=True)
|
|
774
|
+
tmp = STATE + ".tmp"
|
|
775
|
+
with open(tmp, "w", encoding="utf-8") as fh:
|
|
776
|
+
json.dump(data, fh, indent=2, sort_keys=True)
|
|
777
|
+
fh.write("\n")
|
|
778
|
+
os.replace(tmp, STATE)
|
|
779
|
+
except OSError:
|
|
780
|
+
pass
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
def cleanup():
|
|
784
|
+
"""--uninstall: remove every tezgah-generated agent file, keep user files."""
|
|
785
|
+
try:
|
|
786
|
+
data = json.load(open(STATE, encoding="utf-8"))
|
|
787
|
+
except Exception:
|
|
788
|
+
return 0
|
|
789
|
+
removed = 0
|
|
790
|
+
for paths in (data.values() if isinstance(data, dict) else []):
|
|
791
|
+
for path in paths:
|
|
792
|
+
text = _read(path)
|
|
793
|
+
if text and BLOCK_BEGIN in text:
|
|
794
|
+
# the exclude file, or a .gitignore an older install edited:
|
|
795
|
+
# strip tezgah's block and keep every line the user owns
|
|
796
|
+
rest = _strip_block(text).strip("\n")
|
|
797
|
+
try:
|
|
798
|
+
if rest:
|
|
799
|
+
with open(path, "w", encoding="utf-8") as fh:
|
|
800
|
+
fh.write(rest + "\n")
|
|
801
|
+
else:
|
|
802
|
+
os.remove(path)
|
|
803
|
+
removed += 1
|
|
804
|
+
except OSError:
|
|
805
|
+
pass
|
|
806
|
+
continue
|
|
807
|
+
if _is_managed(text):
|
|
808
|
+
try:
|
|
809
|
+
os.remove(path)
|
|
810
|
+
removed += 1
|
|
811
|
+
except OSError:
|
|
812
|
+
pass
|
|
813
|
+
try:
|
|
814
|
+
os.remove(STATE)
|
|
815
|
+
except OSError:
|
|
816
|
+
pass
|
|
817
|
+
return removed
|