@r1z4x/tezgah 1.4.0 → 1.5.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 +71 -1
- package/agents/tezgah-reviewer.md +19 -10
- package/bin/tezgah-docs +3 -3
- package/bin/tezgah-route +5 -2
- package/bin/tezgah-setup +24 -1
- package/bin/tezgah-status +3 -1
- package/bin/tezgah-task +130 -37
- package/bin/tezgah-taste +49 -31
- package/bin/tezgah-triage +12 -7
- package/docs/clarity-baseline.json +6 -6
- package/docs/contract.md +21 -11
- package/docs/environment.md +3 -1
- package/docs/evidence.md +4 -3
- package/docs/glossary.md +1 -1
- package/docs/judge.md +93 -27
- package/docs/operations.md +23 -12
- package/docs/skills.md +1 -1
- package/docs/vision.md +10 -5
- package/hooks/tezgah_agents.py +22 -11
- package/hooks/tezgah_context.py +40 -6
- package/hooks/tezgah_judge.py +245 -79
- package/hooks/tezgah_paths.py +165 -27
- package/hooks/tezgah_policy.py +35 -8
- package/hooks/tezgah_replay.py +26 -15
- package/hooks/tezgah_task.py +146 -40
- package/hooks/tezgah_taste.py +2 -2
- package/hooks/tezgah_taste_ledger.py +13 -4
- package/hosts/codex/hook.py +5 -0
- package/package.json +1 -1
- package/skills/harness/SKILL.md +4 -0
- package/skills/plan-add/SKILL.md +23 -7
- package/skills/plan-add/render_table.py +3 -2
- package/skills/plan-status/SKILL.md +12 -4
- package/skills/plan-sync/SKILL.md +19 -9
- package/skills/tezgah-contract/SKILL.md +25 -12
package/docs/operations.md
CHANGED
|
@@ -435,18 +435,21 @@ builds it (`capture_signals`, `bin/tezgah-taste::capture_signals`). A signal
|
|
|
435
435
|
holds the prompt, the files written, the agent's edits, and the user's own edit
|
|
436
436
|
between two agent writes. That last one compares the after blob with the next
|
|
437
437
|
write's pre-state, or with the file on disk (`user_diff`,
|
|
438
|
-
`bin/tezgah-taste::user_diff`). `learn` asks
|
|
439
|
-
signal (`decide`, `bin/tezgah-taste::decide`, [judge](judge.md)).
|
|
438
|
+
`bin/tezgah-taste::user_diff`). `learn` asks the Jev model for one typed decision
|
|
439
|
+
per signal (`decide`, `bin/tezgah-taste::decide`, [judge](judge.md)). Any Jev
|
|
440
|
+
carrier will do: TypeSafe, OpenRouter System One, Cloudflare Workers AI or a
|
|
441
|
+
compatible endpoint. The decision
|
|
440
442
|
names preference, defect or none. It picks one of eleven fixed categories and a
|
|
441
443
|
scope. It also says how the signal relates to each learning held: supports,
|
|
442
|
-
contradicts, narrows or unrelated. When
|
|
443
|
-
the decision in the `decisions` table as `unverified
|
|
444
|
+
contradicts, narrows or unrelated. When a provider outside the Jev family answers,
|
|
445
|
+
`learn` records the decision in the `decisions` table as `unverified`. It never
|
|
446
|
+
applies it. The report counts the typed decisions under `jev`. A
|
|
444
447
|
defect goes to the `defects` table and never into the ledger.
|
|
445
448
|
|
|
446
449
|
Armed taste also learns by itself. At session start, `learn` starts in the
|
|
447
450
|
background when new signals arrived since the last start. It starts at most
|
|
448
451
|
once an hour per repository (`learn_later`, `hooks/tezgah_taste.py::learn_later`). It runs
|
|
449
|
-
with `--no-fallback` and only when a
|
|
452
|
+
with `--no-fallback` and only when a Jev carrier resolves, so it never pays a
|
|
450
453
|
generative provider for a decision it could not apply. It does not run on
|
|
451
454
|
Windows, which has no ledger lock yet. The stamp is a `taste_learn` row of the
|
|
452
455
|
cache's `tezgah.db`. The log lives under the cache dir, in `taste-learn/`.
|
|
@@ -661,7 +664,7 @@ or its optional tools and config, on its own initiative
|
|
|
661
664
|
|
|
662
665
|
## Triage: `tezgah-triage` and the `judge-off` switch
|
|
663
666
|
|
|
664
|
-
One judgement seam serves five callers, each of them asking
|
|
667
|
+
One judgement seam serves five callers, each of them asking the judge a batched
|
|
665
668
|
question instead of paying an agent to read a page: the analyze-app loop's snapshot
|
|
666
669
|
triage (`bin/tezgah-triage`), `bin/tezgah-docs` for a query its keyword index
|
|
667
670
|
cannot place, and the prompt-path skill hint (`hooks/tezgah_skill_pick.py`), the
|
|
@@ -700,7 +703,10 @@ made - no credential, the switch below, or a failed call - and the loop reads th
|
|
|
700
703
|
tree directly instead.
|
|
701
704
|
|
|
702
705
|
The state leaves the machine. A judgement sends the state and the questions to
|
|
703
|
-
|
|
706
|
+
the host of whichever provider answers - the session's own CLI (omp, claude,
|
|
707
|
+
opencode, cursor, codex), or the chosen Jev
|
|
708
|
+
carrier's (`api.typesafe.ai`, `openrouter.ai`, `api.cloudflare.com` or a
|
|
709
|
+
`JEV_API_BASE_URL`, see [judge](judge.md)) (`ask()`, `hooks/tezgah_judge.py::ask`) - for the triage that is
|
|
704
710
|
the snapshot's own text, so a screen carrying personal data is read by a third
|
|
705
711
|
party, and for the docs fallback it is the reader's query. Nothing else goes: no
|
|
706
712
|
session id, no workspace path, no credential beyond the bearer header, and the
|
|
@@ -710,11 +716,16 @@ request cannot drift. That is why the two shell callers are on-demand - an agent
|
|
|
710
716
|
asks for a judgement, no gate does - while the skill hint asks only with its own
|
|
711
717
|
marker armed, and why the switch below is the off button for the whole path.
|
|
712
718
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
`
|
|
717
|
-
|
|
719
|
+
With no session CLI, the third party is the Jev model through one of its carriers.
|
|
720
|
+
TypeSafe's credential resolves from `TYPESAFE_API_KEY`, else from
|
|
721
|
+
`~/.config/typesafe/key`, else from the active omp login (`typesafe_key()`,
|
|
722
|
+
`hooks/tezgah_paths.py::typesafe_key`). `jev` chooses which of the other Jev
|
|
723
|
+
carriers the seam asks - OpenRouter's System One endpoint, Cloudflare Workers AI
|
|
724
|
+
and any System One-compatible URL (`jev_carriers()`,
|
|
725
|
+
`hooks/tezgah_paths.py::jev_carriers`). The OpenRouter chat fallback's key rides
|
|
726
|
+
`OPENROUTER_API_KEY` and then `~/.config/openrouter/key` (`openrouter_key()`,
|
|
727
|
+
`hooks/tezgah_judge.py::openrouter_key`). When no carrier answers, the same
|
|
728
|
+
questions go to that chat fallback. The file is the channel that
|
|
718
729
|
matters on a machine exporting the variable from `~/.zshenv`: a hook or a bin tool
|
|
719
730
|
runs in a non-interactive shell, where that export never ran, so the file is what a
|
|
720
731
|
judgement actually resolves. Cost is input tokens alone - $0.042 per
|
package/docs/skills.md
CHANGED
|
@@ -176,7 +176,7 @@ it (`tests/test_skills.py::SkillStandards`).
|
|
|
176
176
|
| `no-ai-slop` | Edits a draft sharper and more human without losing the voice, or flags slop; fires on a draft review, on a draft in a language other than English, on text that must keep terms, identifiers or unit symbols verbatim, and before publishing English prose tezgah writes itself. |
|
|
177
177
|
| `analyze-app` | Inspects and drives a running web or mobile app from its accessibility / DOM / view tree, its rendered screen (screenshots, blur and grayscale tests, breakpoints) and measurements taken in the page; fires when a task must verify behaviour or read the UI, not just read source. |
|
|
178
178
|
| `plan-add` | Creates a plan under `.tezgah/plans/open/` with its own `allowed_paths:` scope, bootstraps the `.tezgah/plans/` layer if missing, commits it in the private `.tezgah` repository (`git -C .tezgah`, never the project's git); fires on `/tezgah:plan-add`, "track this as a plan". |
|
|
179
|
-
| `plan-status` | Reads every open plan, enriches rows with live PR state from `gh`, rewrites the README table (committed in the private `.tezgah` repository) and recommends the next plan; fires on `/tezgah:plan-status` or "what plans are open". |
|
|
179
|
+
| `plan-status` | Reads every open plan and `tezgah-task status` (each plan's Acceptance boxes ticked, the plans its `after:` waits on, the ready plans that can run at once), enriches rows with live PR state from `gh`, rewrites the README table (committed in the private `.tezgah` repository) and recommends the next plan; fires on `/tezgah:plan-status` or "what plans are open". |
|
|
180
180
|
| `plan-sync` | Closes finished plans whose PR merged or closed through `tezgah-task close`, which moves a plan to `.tezgah/plans/done/` as done only when it records an approving `review:`; commits one message per plan in the private `.tezgah` repository; fires on `/tezgah:plan-sync`, "sync plans". |
|
|
181
181
|
| `research` | Runs an auditable research line - two loops, protocol before run, six-dimension review, provenance; fires when the deliverable is evidence: a lit review, a hypothesis, a benchmark or ablation. |
|
|
182
182
|
| `product-analysis` | Runs a product analysis across five axes - value (HEART), usability (heuristics, the cognitive walkthrough, WCAG 2.2, axe-core, the running app read through `analyze-app` down to component x state, tree and image both), feasibility (a cited `path:line`), competition (a dated teardown) and triage (keep/fix/cut/bet) - with one named evidence class per finding, executed as a research line; fires on a product, feature, retention or roadmap question rather than a code change. |
|
package/docs/vision.md
CHANGED
|
@@ -22,11 +22,16 @@ the workspace's own records; every number below names where it came from.
|
|
|
22
22
|
runs, 106 minutes, 10 of them green confirmations, in one session - the rule
|
|
23
23
|
"run the full suite once, on the final tree" was already written down and
|
|
24
24
|
`AGENTS.md` said "before every commit".)
|
|
25
|
-
3. **
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
3. **One review per plan, two rounds, fanned out.** Reviewers read the plan's
|
|
26
|
+
whole diff once, in its verification phase. Round one spawns them together,
|
|
27
|
+
one per dimension. Only a confirmed critical or major finding opens round two,
|
|
28
|
+
and round two reads the fix's delta. After round two the user gets what is
|
|
29
|
+
left, or the plan lists it as fix-later. `tezgah-task review` refuses a third
|
|
30
|
+
round (`hooks/tezgah_agents.py::_reviewer_body`, `bin/tezgah-task::cmd_review`).
|
|
31
|
+
(Measured: the old loop opened a round on any finding and ended only on a
|
|
32
|
+
clean round. It reviewed one finished plan round after round. In another plan,
|
|
33
|
+
fixes brought two of four severe defects. So round two reads the fix, and a
|
|
34
|
+
severe finding left after it blocks.)
|
|
30
35
|
4. **Doubt lowers nothing and hides nothing.** An unverifiable check never
|
|
31
36
|
downgrades a finding, an unknown criterion never relaxes a cap, and a line
|
|
32
37
|
whose own criteria are unmet is reported as unanswered rather than concluded.
|
package/hooks/tezgah_agents.py
CHANGED
|
@@ -206,15 +206,22 @@ def _reviewer_body(host):
|
|
|
206
206
|
"is lowered only by evidence: a check you could not complete never\n"
|
|
207
207
|
"downgrades a confirmed finding - keep its severity and mark it\n"
|
|
208
208
|
"provisional. Disclose the order you read the files in.\n\n"
|
|
209
|
-
"Scope and budget.
|
|
210
|
-
"
|
|
211
|
-
"
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
"
|
|
215
|
-
"
|
|
216
|
-
"
|
|
217
|
-
"
|
|
209
|
+
"Scope and budget. One review per plan, over its whole diff in the\n"
|
|
210
|
+
"verification phase; at most two rounds - only a confirmed critical or\n"
|
|
211
|
+
"major finding opens round two, a minor or suggestion one is recorded\n"
|
|
212
|
+
"fix-later, and after round two what is left goes to the user or is\n"
|
|
213
|
+
"recorded fix-later, never a third round. A round may be a fan-out of\n"
|
|
214
|
+
"reviewers spawned at once, one per dimension (correctness and contract,\n"
|
|
215
|
+
"security, tests and performance) or per file group: when your brief\n"
|
|
216
|
+
"names a dimension or files, review only those - a sibling owns the rest.\n"
|
|
217
|
+
"Round two reads only the delta since the sha round one recorded\n"
|
|
218
|
+
"(`tezgah-task review` prints it), plus the round-one hunks and direct\n"
|
|
219
|
+
"callers of the symbols that delta touches, and marks every round-one\n"
|
|
220
|
+
"finding closed or open: re-reading the whole diff re-reports what was\n"
|
|
221
|
+
"already triaged. Test results are input, not a task - read the author's\n"
|
|
222
|
+
"output file; do not run the suite, and run at most one `-k` test when a\n"
|
|
223
|
+
"specific accusation needs it. The same defect family confirmed in both\n"
|
|
224
|
+
"rounds is a sign the design needs a pivot, not another patch.\n\n"
|
|
218
225
|
"%s" % (_graph_howto(host), _blast_radius(host), EMPTY_IS_NOT_PROOF,
|
|
219
226
|
_may_use(host)))
|
|
220
227
|
|
|
@@ -343,7 +350,8 @@ ROLES = (
|
|
|
343
350
|
("tezgah-reviewer",
|
|
344
351
|
"Adversarial, read-only review of a diff, branch or PR: derives the blast "
|
|
345
352
|
"radius, checks correctness, contract, security, tests and performance, and "
|
|
346
|
-
"classifies every finding confirmed/refuted/unverified."
|
|
353
|
+
"classifies every finding confirmed/refuted/unverified. One review per plan, "
|
|
354
|
+
"at most two rounds; spawn one per dimension in one message for a large diff.",
|
|
347
355
|
lambda infra: infra["caps"]["graph"], _reviewer_body, True),
|
|
348
356
|
("tezgah-cheap",
|
|
349
357
|
"Mechanical, fully specified edits on the cheapest model tier: renames, "
|
|
@@ -389,7 +397,10 @@ def _orch_body(names):
|
|
|
389
397
|
"verify; you delegate execution and read the evidence back. Available\n"
|
|
390
398
|
"specialists: %s.\n\n"
|
|
391
399
|
"Fan out by default: when the request or your todo list holds two or more\n"
|
|
392
|
-
"independent items, spawn one subagent per item in ONE
|
|
400
|
+
"independent items, count them and spawn one subagent per item in ONE\n"
|
|
401
|
+
"message - at every phase: a plan's tasks, its acceptance commands and the\n"
|
|
402
|
+
"sources of a survey are items too, and checks that share no state run as\n"
|
|
403
|
+
"tool calls in one message, never a queue. Give\n"
|
|
393
404
|
"every writing slice its own branch and checkout - `orca worktree create\n"
|
|
394
405
|
"--name <slug> --parent-worktree active --json` when the session runs\n"
|
|
395
406
|
"inside Orca, else `git worktree add -b <branch> <absolute path>` - and\n"
|
package/hooks/tezgah_context.py
CHANGED
|
@@ -26,8 +26,9 @@ from tezgah_integrity import (STEP_KINDS, _heredocs, _path as _ledger_path,
|
|
|
26
26
|
UNTRUSTED_CHANNEL)
|
|
27
27
|
from tezgah_lessons import (lesson_key, lines as lesson_lines,
|
|
28
28
|
tainted as tainted_lessons)
|
|
29
|
-
from tezgah_policy import (CONDITIONAL_KEYS, CORE,
|
|
30
|
-
REPLY_LANG_TEXT, open_lines_note,
|
|
29
|
+
from tezgah_policy import (CONDITIONAL_KEYS, CORE, FANOUT_ACTION, POINTERS,
|
|
30
|
+
PROMPT_REMINDER, REPLY_LANG_TEXT, open_lines_note,
|
|
31
|
+
pony_level_line)
|
|
31
32
|
from tezgah_paths import (CACHE, REPO_MARKS, SWITCHES, ai_research_dir, armed,
|
|
32
33
|
cache_dir, codegraph_bin, consult_options,
|
|
33
34
|
ensure_workspace, fallback_cache, have_judge_key, off,
|
|
@@ -106,6 +107,21 @@ def _tr_ui_ask(word):
|
|
|
106
107
|
return (r"(?:\b(?:%s)\w*[^.!?\n]{0,40}\b(?:%s))" % (TR_UI_OBJECTS, word))
|
|
107
108
|
|
|
108
109
|
|
|
110
|
+
# The fan-out hint's parts (PROMPT_HINTS["fanout"]). A list item's marker:
|
|
111
|
+
# `1.`, `1)`, `1 -`, `1:`, `a)`, or a `-`/`*`/`+`/`•` bullet, then its text.
|
|
112
|
+
_FAN_ITEM = r"(?:\d+[ \t]*[.):\u2013-]|[a-z]\)|[-*+\u2022])[ \t]+\S"
|
|
113
|
+
# A file a prompt names: a path with a directory, or a name with an extension.
|
|
114
|
+
# Anchored at a token start: unanchored, a long run of word characters made
|
|
115
|
+
# every position a start and the search quadratic (100 KB took minutes).
|
|
116
|
+
_FAN_FILE = (r"(?<![\w./-])[`'\"]?(?:(?:[\w.-]+/)+[\w.-]*\w|"
|
|
117
|
+
r"\w[\w-]*\.[a-z]{1,4}\b)[`'\"]?")
|
|
118
|
+
# The imperative that opens an English clause and closes a Turkish one.
|
|
119
|
+
_FAN_VERB_EN = (r"(?:fix|add|update|write|remove|delete|rename|move|refactor|"
|
|
120
|
+
r"document|bump|create|implement|migrate|replace)")
|
|
121
|
+
_FAN_VERB_TR = (r"(?:düzelt|güncelle|ekle|yaz|sil|kaldır|taşı|bitir|tamamla|"
|
|
122
|
+
r"incele|oluştur|değiştir)")
|
|
123
|
+
|
|
124
|
+
|
|
109
125
|
PROMPT_HINTS = (
|
|
110
126
|
("spec", r"\b(normal (user )?behaviou?r|clean ui|nicer|more intuitive|"
|
|
111
127
|
r"un?professional|polish(ed)?|improve the (ui|ux)|make it (better|"
|
|
@@ -340,9 +356,22 @@ PROMPT_HINTS = (
|
|
|
340
356
|
# had to say "do everything with subagents and in parallel" on every task
|
|
341
357
|
# because nothing armed the fan-out rule from the shape of the request.
|
|
342
358
|
# `parallelize` alone is code work, so only the delegation phrasings count.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
359
|
+
# The owner's own shapes armed nothing until 2026-10-09: `1 - `, `1- `,
|
|
360
|
+
# `1:`, `a)`, `+` items, an inline `1. ... 2. ...`, "subagentlerle", three
|
|
361
|
+
# files named as one list, "First, ... Second, ...", and three imperative
|
|
362
|
+
# clauses in one sentence (clause-initial in English, clause-final in
|
|
363
|
+
# Turkish). A timestamp, a range and a traceback stay out (the corpus).
|
|
364
|
+
("fanout", r"(?ms:^[ \t]*" + _FAN_ITEM + r".*?^[ \t]*" + _FAN_ITEM + r")|"
|
|
365
|
+
r"(?<![\w.])1[ \t]*[.)-][ \t]+\S[^\n]*?(?<![\w.])2[ \t]*[.)-][ \t]+\S|"
|
|
366
|
+
+ _FAN_FILE + r"(?:[ \t]*(?:,[ \t]*(?:(?:and|ve)[ \t]+)?|"
|
|
367
|
+
r"(?:and|ve|&)[ \t]+)" + _FAN_FILE + r"){2,}|"
|
|
368
|
+
r"(?s:\bfirst(?:ly)?[,:].*?\bsecond(?:ly)?[,:])|"
|
|
369
|
+
r"(?s:\bbirinci(?:si)?[,:].*?\bikinci(?:si)?[,:])|"
|
|
370
|
+
r"(?m:(?:(?:^|[,;]|\band\b)[ \t]*(?:and[ \t]+)?" + _FAN_VERB_EN
|
|
371
|
+
+ r"\b[^\n]*?){3})|"
|
|
372
|
+
r"(?m:(?:\b" + _FAN_VERB_TR + r"\w{0,4}[ \t]*(?:[,;.]|\bve\b|$)"
|
|
373
|
+
r"[^\n]*?){3})|"
|
|
374
|
+
r"\b(?:in parallel|paralel\w*|sub-?agent\w*|alt ?ajan\w*|"
|
|
346
375
|
r"worktrees?|fan[- ]?out|orchestrat\w*|orkestra\w*)\b"),
|
|
347
376
|
)
|
|
348
377
|
|
|
@@ -1094,8 +1123,13 @@ ARMED_RESURFACE = 20
|
|
|
1094
1123
|
def armed_again(key):
|
|
1095
1124
|
"""The one line a matching prompt pays for a paragraph this session was
|
|
1096
1125
|
already shown. The research rule keeps its `{OPEN_LINES}` slot: the open
|
|
1097
|
-
lines are a fact about the repo now, not rule text the session holds.
|
|
1126
|
+
lines are a fact about the repo now, not rule text the session holds. The
|
|
1127
|
+
fan-out rule keeps its action (`FANOUT_ACTION`): the rule is a thing to do
|
|
1128
|
+
on this turn's list, and a bare reminder that it exists was not done."""
|
|
1098
1129
|
label = dict(CORE_RULES)[key]
|
|
1130
|
+
if key == "fanout":
|
|
1131
|
+
return ("%s Armed again: %s The full rule is in the `tezgah-contract` "
|
|
1132
|
+
"skill." % (label, FANOUT_ACTION))
|
|
1099
1133
|
return ("%s Armed again: the full rule was given earlier this session and "
|
|
1100
1134
|
"is in the `tezgah-contract` skill.%s"
|
|
1101
1135
|
% (label, "{OPEN_LINES}" if key == "research" else ""))
|