@r1z4x/tezgah 1.5.1 → 1.7.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.
Files changed (81) hide show
  1. package/CHANGELOG.md +126 -1
  2. package/MANIFEST +11 -0
  3. package/README.md +6 -3
  4. package/bin/consult +13 -10
  5. package/bin/tezgah-docs +18 -16
  6. package/bin/tezgah-doctor +152 -0
  7. package/bin/tezgah-research +286 -12
  8. package/bin/tezgah-route +48 -1
  9. package/bin/tezgah-setup +27 -14
  10. package/bin/tezgah-task +771 -46
  11. package/bin/tezgah-taste +48 -10
  12. package/docs/architecture.md +7 -4
  13. package/docs/citations-baseline.json +1 -1
  14. package/docs/clarity-baseline.json +5 -5
  15. package/docs/contract.md +112 -25
  16. package/docs/evidence.md +201 -28
  17. package/docs/feature-audit.md +25 -4
  18. package/docs/gate.md +70 -33
  19. package/docs/glossary.md +4 -4
  20. package/docs/hosts.md +8 -8
  21. package/docs/index.json +30 -10
  22. package/docs/judge.md +9 -3
  23. package/docs/models.md +35 -2
  24. package/docs/operations.md +103 -3
  25. package/docs/research.md +392 -13
  26. package/docs/skills.md +24 -6
  27. package/docs/status-line.md +5 -5
  28. package/docs/testing.md +2 -2
  29. package/docs/vision.md +12 -4
  30. package/hooks/hooks.json +2 -2
  31. package/hooks/lang/en.json +323 -0
  32. package/hooks/lang/tr.json +344 -0
  33. package/hooks/projects-posttooluse.py +24 -5
  34. package/hooks/projects-pretooluse.py +9 -4
  35. package/hooks/projects-stop.py +28 -16
  36. package/hooks/tezgah_agents.py +29 -9
  37. package/hooks/tezgah_clarity.py +7 -3
  38. package/hooks/tezgah_components.py +2 -1
  39. package/hooks/tezgah_context.py +460 -390
  40. package/hooks/tezgah_gate.py +640 -104
  41. package/hooks/tezgah_integrity.py +1480 -197
  42. package/hooks/tezgah_models.py +337 -15
  43. package/hooks/tezgah_paths.py +103 -10
  44. package/hooks/tezgah_policy.py +286 -130
  45. package/hooks/tezgah_product.py +107 -0
  46. package/hooks/tezgah_rank.py +29 -27
  47. package/hooks/tezgah_replay.py +200 -30
  48. package/hooks/tezgah_research.py +1297 -12
  49. package/hooks/tezgah_skill_pick.py +58 -17
  50. package/hooks/tezgah_stopspec.py +7 -0
  51. package/hooks/tezgah_store.py +74 -27
  52. package/hooks/tezgah_task.py +917 -8
  53. package/hosts/codex/hook.py +9 -10
  54. package/hosts/cursor/hook.py +21 -14
  55. package/hosts/dsh/hooks.json +2 -2
  56. package/hosts/omp/hook.py +44 -23
  57. package/hosts/omp/tezgah-hook.ts.in +93 -7
  58. package/hosts/opencode/plugins/tezgah.js +119 -39
  59. package/output-styles/tezgah.md +76 -42
  60. package/package.json +1 -1
  61. package/skills/analyze-app/SKILL.md +57 -0
  62. package/skills/design-contract/EVALS.md +24 -1
  63. package/skills/design-contract/SKILL.md +17 -1
  64. package/skills/design-contract/data-views.md +86 -0
  65. package/skills/feature-audit/SKILL.md +32 -3
  66. package/skills/i-have-adhd/EVALS.md +22 -2
  67. package/skills/i-have-adhd/SKILL.md +12 -5
  68. package/skills/plan-add/EVALS.md +8 -8
  69. package/skills/plan-add/SKILL.md +22 -21
  70. package/skills/plan-sync/EVALS.md +2 -2
  71. package/skills/plan-sync/SKILL.md +14 -8
  72. package/skills/pm-frameworks/SKILL.md +6 -0
  73. package/skills/ponytail/EVALS.md +21 -2
  74. package/skills/ponytail/SKILL.md +4 -4
  75. package/skills/product-analysis/EVALS.md +23 -1
  76. package/skills/product-analysis/SKILL.md +50 -11
  77. package/skills/product-flow/EVALS.md +81 -0
  78. package/skills/product-flow/SKILL.md +91 -0
  79. package/skills/research/SKILL.md +99 -2
  80. package/skills/tezgah-contract/EVALS.md +52 -7
  81. package/skills/tezgah-contract/SKILL.md +204 -85
@@ -224,7 +224,7 @@ After a change to the contract text (`hooks/tezgah_policy.py`,
224
224
  - `--refresh` does that without a reinstall, for every armed host's static
225
225
  block and not only opencode's (`refresh_contract`). opencode has no
226
226
  session-start hook, so its plugin runs it once per session
227
- (`hosts/opencode/plugins/tezgah.js:2666-2670`). Until 2026-10-02 it
227
+ (`hosts/opencode/plugins/tezgah.js:2689-2693`). Until 2026-10-02 it
228
228
  re-rendered opencode's files alone and reset the one shared hash, so a rule
229
229
  edit left the other static files stale while `--report` went green (audit
230
230
  M-5).
@@ -371,6 +371,7 @@ does not hold.
371
371
  | `tezgah-doctor` | nothing: sizes, session and event counts, whether opencode is running, the two context-hygiene settings, the `.codegraph` bytes and index presence per repository, and the three host state dirs (`bin/tezgah-doctor::collect`, `bin/tezgah-doctor::report`) |
372
372
  | `tezgah-doctor --clean` | vacuums opencode's database, and only when opencode is not running (`bin/tezgah-doctor::vacuum_db`, `bin/tezgah-doctor::main`); deletes every evidence ledger whose newest row is older than `--retention-days` (default 30), rows, import offsets and old JSONL file together (`hooks/tezgah_store.py::sweep_evidence`), and the turn stamps and used-tool marks last written before then (`hooks/tezgah_store.py::sweep_cache`); and deletes the files not modified for that long - `classify.log`, `context-drops.log`, `debug.log` and the `turns/` and `sessions/` files a running older release still writes - in the cache and its sandbox fallback, keeping the current session's (`$TEZGAH_SESSION`) ledger, stamp and marks whatever their age (`sweep_state`) |
373
373
  | `tezgah-doctor --import-evidence` | imports every old `evidence/*.jsonl` file into the cache's `tezgah.db` now, in the cache and its sandbox fallback (`bin/tezgah-doctor::import_evidence`); session start runs the same import detached at most once a day (`hooks/tezgah_store.py::import_later`) |
374
+ | `tezgah-doctor --repair-evidence [--apply]` | counts, per session, the evidence rows an old `evidence/*.jsonl` file put in again when a volume remount gave it another device id, in the cache and its sandbox fallback. Every `imported` row of one file is one import stream, which put the file's first `bytes` in. For a row text, the longest stream's count stays and every other stream's count is a copy: that many of the newest rows go, so a row written to the database directly beside them stays. A session holding a file line fewer times than its streams put it in is left whole and printed for manual review. A file gone from its name, holding another inode or shorter than its longest stream is printed and skipped, not guessed (`bin/tezgah-doctor::evidence_plan`). It writes nothing without `--apply`, which backs `tezgah.db` up to `tezgah.db.bak-<YYYYmmdd-HHMMSS>` through SQLite's backup API, deletes those rows and leaves one import offset per file in one transaction. Before that transaction commits it counts the rows against the plan, and it rolls back and exits 1 when a row it kept is gone or a copy it deleted is still there (`bin/tezgah-doctor::repair_evidence`) |
374
375
  | `tezgah-doctor --coverage` | every tracked file the codegraph index does not hold, in two classes — a supported extension the index is missing, and a shebang-only script with no `.py` twin — with the file counts it read, so an empty result cannot read as "everything is covered" |
375
376
  | `tezgah-doctor --stack` | per host: the context files in load order, the skill dirs and which copy wins, the hook rows per event with their owner, the MCP servers, and every conflict; exits 1 on one ([hosts](hosts.md#precedence-what-each-host-loads-and-in-which-order), `hooks/tezgah_stack.py::report`) |
376
377
  | `tezgah-doctor --prune-sessions DAYS` | deletes sessions idle longer than DAYS through `opencode session delete`, then vacuums; skipped when opencode is running or its CLI is missing (`bin/tezgah-doctor::prune_sessions`, `bin/tezgah-doctor::main`) |
@@ -412,7 +413,7 @@ ledger row. A rollback therefore never reads it as a pre-state (`capture_after`,
412
413
  `hooks/tezgah_snapshot.py::capture_after`). A file outside the repository gets no
413
414
  after blob.
414
415
  opencode reaches the same call through a process (`noteTaste`,
415
- `hosts/opencode/plugins/tezgah.js:2413-2423`).
416
+ `hosts/opencode/plugins/tezgah.js:2436-2446`).
416
417
 
417
418
  ```sh
418
419
  touch ~/.config/tezgah/taste-on # arm; rm it to disarm
@@ -425,7 +426,8 @@ bin/tezgah-taste export # accepted learnings into AGENTS.m
425
426
  bin/tezgah-taste label; bin/tezgah-taste label ID preference # the calibration sample
426
427
  bin/tezgah-taste calibrate # the bound a rule needs
427
428
  bin/tezgah-taste gate # the pooled before/after test
428
- bin/tezgah-taste mine --host omp --stats # sessions, writes, prompts after a writing turn
429
+ bin/tezgah-taste mine --host omp --stats # this repository's sessions, writes, prompts after a writing turn
430
+ bin/tezgah-taste mine --all-projects # every session under ~/Projects, each repo pseudonymised
429
431
  bin/tezgah-taste measure --samples S --labels L [--typed] # judge precision/recall
430
432
  ```
431
433
 
@@ -614,6 +616,102 @@ it costs nothing there. On held-out Turkish phrasings of the docs index,
614
616
  meaning alone found the page in the top three for 0.91 with `embed-mrl` and 0.78
615
617
  with `embed-m2v`. The fusion found it for 0.75 and 0.74, BM25 for 0.68.
616
618
 
619
+ ## Slice journal: `tezgah-task slice`
620
+
621
+ A delegated slice can die with its parent. A crash, an omp `/clear`, a quota or
622
+ 429 answer, or a model or host switch ends the parent session. The child's
623
+ worktree and commits stay, but no one remembers them. The slice journal is that
624
+ memory, and it is host-neutral.
625
+
626
+ Each spawned slice gets one row in `<repo root>/.tezgah/slices/slices.db`, a SQLite
627
+ file opened like the taste store (`hooks/tezgah_task.py::SLICE_SCHEMA`).
628
+ An older release wrote one JSON file per record there. The first open imports each one and deletes it.
629
+ `.gitignore` excludes `.tezgah/`, a private directory, so the journal never reaches a commit.
630
+ The id is the host's own agent name: the omp task `name` or the Codex
631
+ `task_name`. A Claude `Agent`/`Task` input may carry a `name` too. Otherwise the
632
+ id is the first 12 hex digits of the brief's sha1. A record holds the host, the agent
633
+ type, the first 4000 characters of the brief, the parent session and the cwd.
634
+ It also holds the linked worktree the brief names, its branch, and the root's
635
+ HEAD at open. Its `status` is `open`, `done`, `stopped`, `resumed` or `stale`.
636
+ Its `failure` is one of `quota`, `rate_limit`, `aborted`, `timeout`, `cut_off`
637
+ or `error`. `attempts` counts each re-open of the same id
638
+ (`hooks/tezgah_task.py::open_slice`, `hooks/tezgah_task.py::close_slice`).
639
+ Another session's record of the same name is not re-opened under another brief.
640
+ The spawn gets this session's own record of that name, else `<name>-<sha1[:6]>` of its brief.
641
+ `name` keeps the spawned name, and the same brief from another session still re-opens the record
642
+ (`hooks/tezgah_task.py::_own_id`). The record stays in cwd's journal, the one its
643
+ owner's Stop rule, resume block and review guard read. When every absolute path its
644
+ brief names lies in one other repository, `repo` names that repository, and the
645
+ slice line says `(in <name>)` (`hooks/tezgah_task.py::_brief_repo`). A repository's
646
+ own `.tezgah` counts as that repository (`hooks/tezgah_task.py::main_repo`).
647
+
648
+ The slice's own task text (without a batch's shared `context`) decides its
649
+ worktree and its lease. The worktree is the one the task names last, else the
650
+ brief (`hooks/tezgah_task.py::_worktree_in`). `declared` holds the checkout a
651
+ `Worktree:`, `Checkout` or `Cwd:` line declares, which only the main-checkout
652
+ refusal reads (`hooks/tezgah_task.py::_declared_in`). Its `Owns:` lines name
653
+ repository-relative globs, and only that slice may write those paths while its
654
+ record runs (`hooks/tezgah_task.py::owned_globs`, `hooks/tezgah_task.py::owner_of`). A
655
+ Claude background child's record also keeps the launch's `agentId` as `child`,
656
+ which its own calls carry (`hooks/tezgah_task.py::slice_of`). The
657
+ gate holds siblings to the lease (`docs/gate.md`, the Lease rule), and the
658
+ spawn-time warning names two writing slices that share one worktree
659
+ (`hooks/tezgah_task.py::worktree_clash`).
660
+
661
+ The hooks write it. A spawn call - omp `task`, Claude, dsh and Cursor
662
+ `Agent`/`Task`, Codex `spawn_agent`, opencode `task` - opens one record per
663
+ slice (`hooks/tezgah_task.py::spawned`, `hooks/tezgah_task.py::note_spawn`).
664
+ Claude, dsh, Cursor and opencode answer the call once the child ended. So the
665
+ record closes at once (`hooks/tezgah_task.py::classify`). A failed call becomes
666
+ `stopped` with its failure class, and a good one `done`. The omp `task` and Codex
667
+ `spawn_agent` calls answer while the child runs, so the record stays `open`. So
668
+ does a Claude launch sent with `run_in_background` or one whose result names a
669
+ background child. That child's SubagentStop closes it as `done`
670
+ (`hooks/tezgah_task.py::close_child`). An omp
671
+ record settles from the newest child transcript in the parent's session dir.
672
+ omp names a same-name re-dispatch `<name>-2.jsonl`. The last 64 KB of that file
673
+ decide `stopped` or `done` (`hooks/tezgah_task.py::pending`). A record
674
+ nothing moved for six hours closes `stale`, and a background `job` after
675
+ omp's 3600 s deadline. Codex reports no child end tezgah can see, so its
676
+ records end `stale`. Every prompt lists up to three pending records, newest
677
+ first, each with the command that resumes it (`hooks/tezgah_task.py::slice_lines`).
678
+ They are the records this session spawned or nobody owns, such as one opened by hand. The resume block at
679
+ session start and after a compaction adds one line that counts the other
680
+ sessions' records. `tezgah-task slice reconcile` lists them all.
681
+
682
+ | Command | What it does |
683
+ |---|---|
684
+ | `tezgah-task slice open --id ID [--kind agent\|job] [--host H] [--agent A] [--brief TEXT\|--brief-file F] [--parent P] [--cwd PATH]` | records a slice by hand, for a host whose spawn the hooks do not see |
685
+ | `tezgah-task slice done ID` / `slice stop ID [--class C]` | closes a record as done, or as stopped with a failure class. An exact record id answers from any session. A spawned name answers too, and under `TEZGAH_SESSION` only for that session's records and unowned ones (`hooks/tezgah_task.py::find_slice`) |
686
+ | `tezgah-task slice reconcile [--prune]` | lists every pending record with a resume brief. `--prune` also removes landed worktrees and marks those records done. It deletes a landed local branch only when no worktree holds it, it tracks no upstream and its reflog shows a commit of its own; it never deletes main, master or the current branch |
687
+ | `tezgah-task slice resume ID` | prints the native path first: omp `write agent://<id>` while the parent lives, Claude `SendMessage` when the id is an agent name. Otherwise it prints a re-dispatch brief: the original brief plus the last commit, the uncommitted files and "do not redo committed steps". A quota or rate-limit stop is sent to another provider. It sets the status to `resumed` |
688
+ | `tezgah-task slice stats [--window DAYS] [--json]` | counts records per status, failure class and host. A `class+host` signature with 3 or more events is an RSI lever candidate, and so is one with 5% of a window that holds 20 or more slices. The line names the lever |
689
+ | `tezgah-task slice board [--parent P]` | lists the open slices one parent spawned - the session's own, or for a subagent its parent's - newest first: the `Owns:` globs, worktree, branch and last commit of each, bounded to 12 lines (`hooks/tezgah_task.py::board`) |
690
+ | `tezgah-task slice merge-plan [--base REF]` | forecasts every done slice branch that carries unmerged work against REF (HEAD) and against the others with `git merge-tree`, and leaves out a `merge=union` file such as CHANGELOG.md. A branch touching `MANIFEST` or the citation baseline comes last, the rest fewest conflicts first. A branch merge-tree cannot forecast is printed as `not judged` and the exit is 1 (`bin/tezgah-task::merge_plan`) |
691
+
692
+ `tezgah-task review NNN <reviewer> approve` refuses while an open, stopped or
693
+ stale record names that reviewer as its id, agent or spawned name. Under
694
+ `TEZGAH_SESSION` only that session's records and unowned ones count. The refusal
695
+ prints the exact id to resume or close. A record keeps the plan
696
+ that was active when it opened, and only that plan's records count. A record
697
+ with no plan counts when it changed after the plan's checkpoint commit. A
698
+ `resumed` record hands the guard to its re-dispatch's own record
699
+ (`bin/tezgah-task::unfinished_review`).
700
+ The lever map is a closed set. `rate_limit` and `quota` point at the
701
+ `hooks/tezgah_models.py` fallback chain. `cut_off` and `timeout` point at a
702
+ per-slice deadline, `aborted` at the `wip:` commit cadence, a duplicate job at
703
+ journalling background jobs. Plain `error` has no lever: read the transcript.
704
+
705
+ The orchestration text carries the session's rule
706
+ (`hooks/tezgah_policy.py::ORCHESTRATE`, `hooks/tezgah_agents.py::_orch_body`). A
707
+ slice commits `wip: <step>` after each step. The session resumes or re-dispatches
708
+ a stopped slice and never absorbs it inline. `slice board` shows the sibling
709
+ leases and `slice merge-plan` orders the landed branches. `slice reconcile
710
+ --prune` runs before the turn that merged slices ends.
711
+ The `~/.config/tezgah/slices-off` switch
712
+ stops the hooks from writing records (`hooks/tezgah_paths.py::UNCLASSIFIED_SWITCHES`).
713
+ A cwd outside a git repository writes nothing either.
714
+
617
715
  ## Troubleshooting
618
716
 
619
717
  | Symptom | First check | Likely cause |
@@ -760,6 +858,8 @@ page exits 1 with the message it always printed (`available()`,
760
858
  its pins, the fetch and conversion, the reader and `fuse`; the `embed-mrl` and
761
859
  `embed-m2v` registry rows that `--enable`, `--disable` and `--features` read.
762
860
  `tests/test_embed.py` builds tiny models in the test and pins the rest.
861
+ - `hooks/tezgah_task.py`, `bin/tezgah-task` — the slice journal: the record, the
862
+ spawn parser, reconcile, resume, prune and stats.
763
863
  - `hooks/tezgah_paths.py`, `hooks/tezgah_context.py` — the paths and `off()`; the
764
864
  marks and the kill-switch filtering.
765
865
  - `RELEASING.md`, `README.md`, `AGENTS.md`, `.gitignore`, `tests/test_setup.py` —