@r1z4x/tezgah 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -1
- package/MANIFEST +0 -1
- package/README.md +6 -4
- package/bin/tezgah-docs +3 -3
- package/bin/tezgah-route +12 -6
- package/bin/tezgah-setup +67 -24
- package/bin/tezgah-status +3 -1
- package/bin/tezgah-task +132 -39
- package/bin/tezgah-taste +49 -31
- package/bin/tezgah-triage +12 -7
- package/docs/architecture.md +1 -1
- package/docs/clarity-baseline.json +7 -7
- 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/hosts.md +9 -0
- package/docs/judge.md +95 -27
- package/docs/layers.md +1 -1
- package/docs/models.md +17 -7
- package/docs/operations.md +23 -13
- package/docs/skills.md +1 -1
- package/docs/testing.md +1 -1
- package/docs/vision.md +10 -5
- package/hooks/tezgah_agents.py +149 -105
- package/hooks/tezgah_context.py +42 -7
- package/hooks/tezgah_judge.py +252 -79
- package/hooks/tezgah_models.py +50 -3
- package/hooks/tezgah_paths.py +180 -27
- package/hooks/tezgah_policy.py +41 -10
- package/hooks/tezgah_replay.py +26 -15
- package/hooks/tezgah_task.py +160 -46
- 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 -2
- 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 +29 -14
- package/agents/tezgah-reviewer.md +0 -70
package/docs/environment.md
CHANGED
|
@@ -56,6 +56,7 @@ the kill switches are files, not variables, and live in
|
|
|
56
56
|
| `TEZGAH_ORCA_BIN` | `hooks/tezgah_orca.py::cli` | `ORCA_CLI_COMMAND`, then `$ORCA_CLI_BIN_DIR/orca`, then `orca` on PATH (`orca-ide` on Linux outside Orca), then the macOS app's CLI | The Orca CLI `tezgah-status --orca` and `tezgah-setup --status` ask. A missing path is no CLI, never a fallback: the test suite points it at one. |
|
|
57
57
|
| `TEZGAH_OMP_BIN` | `hooks/tezgah_paths.py::omp_bin` | `omp` on PATH | The omp binary the installer, the model table, consult's session-model lookup and the judgement seam's session call run; tests point it at a stand-in. |
|
|
58
58
|
| `TEZGAH_CLAUDE_BIN` | `claude_bin`, `hooks/tezgah_paths.py::claude_bin` | `claude` on PATH | The Claude Code CLI `--install` registers the plugin with (`claude plugin`) and the judgement seam asks in a Claude Code session; the test suite points it at a path that does not exist, or at a stand-in. |
|
|
59
|
+
| `TEZGAH_OPENCODE_BIN`, `TEZGAH_CURSOR_BIN`, `TEZGAH_CODEX_BIN` | `hooks/tezgah_paths.py::opencode_bin`, `hooks/tezgah_paths.py::cursor_bin`, `hooks/tezgah_paths.py::codex_bin` | `opencode`, `cursor-agent`, `codex` on PATH or a per-user bin dir | The CLI the judgement seam asks in that host's session; tests point them at stand-ins. |
|
|
59
60
|
| `TEZGAH_DSH_BIN` | `bin/tezgah-setup::reconcile_json_servers` | the profile-local entry, then `bin/tezgah-dsh`, then npx | How the installer invokes the dsh CLI. |
|
|
60
61
|
| `TEZGAH_INDEX_BIN` | `bin/tezgah-dsh:19`, `bin/tezgah-dsh.cmd` | `~/.config/tezgah/bin/tezgah-index` | The index worker `tezgah-dsh` warms before it starts dsh. |
|
|
61
62
|
| `TEZGAH_STATUS_BIN` | `hosts/dsh/statusline/lib/index.js:24`, `hosts/opencode/tui/tezgah-tui.tsx` | `~/.config/tezgah/bin/tezgah-status` | The status renderer the dsh status line and the opencode TUI call. |
|
|
@@ -73,7 +74,7 @@ the kill switches are files, not variables, and live in
|
|
|
73
74
|
|
|
74
75
|
| Variable | Read by | Default | Effect |
|
|
75
76
|
|---|---|---|---|
|
|
76
|
-
| `OMPCODE`, `CLAUDECODE` | `hooks/tezgah_paths.py::session_cli
|
|
77
|
+
| `OMPCODE`, `CLAUDECODE`, `OPENCODE`, `CURSOR_AGENT`, `CURSOR_VERSION`, `CODEX_THREAD_ID` | `hooks/tezgah_paths.py::session_cli` (all), `bin/consult`, `hooks/tezgah_models.py::worker_model` (the first two) | set by the host | Name the host session: the judgement seam asks that host's CLI first, in the order listed (omp sets both of the first two, so `OMPCODE` wins; Cursor sets `CURSOR_AGENT` in its shell tool and `CURSOR_VERSION` in its hooks; Codex sets `CODEX_THREAD_ID` in its shell tool only). The test suite unsets all of them. |
|
|
77
78
|
| `TYPESAFE_API_KEY` | `hooks/tezgah_judge.py::key`, `hooks/tezgah_paths.py` | `~/.config/typesafe/key` | The judgement seam's first third-party credential, used as `fallback` in `config.json` allows ([judge](judge.md)); omp also reads it for its own judge. |
|
|
78
79
|
| `OPENROUTER_API_KEY` | `hooks/tezgah_judge.py::openrouter_key`, `bin/consult`, `bin/codegen`, `hooks/tezgah_models.py` | `~/.config/openrouter/key` | The seam's chat fallback, consult's and codegen's `openrouter` provider, and omp's `any` family. |
|
|
79
80
|
| `DEEPSEEK_API_KEY`, `INCEPTION_API_KEY` | `bin/consult`, `bin/codegen`, `hooks/tezgah_replay.py::label_model` | `~/.config/deepseek/key`, `~/.config/inception/key` | The `deepseek` and `inception` providers of consult and codegen; `DEEPSEEK_API_KEY` alone is also the replay sheet's `--provider deepseek` rater. |
|
|
@@ -82,6 +83,7 @@ the kill switches are files, not variables, and live in
|
|
|
82
83
|
| `TEZGAH_OPENROUTER_URL` | `hooks/tezgah_judge.py::openrouter_url` | OpenRouter's chat-completions URL | Repoints the seam's chat fallback (tests). Plain `http` is refused unless the host is this machine. |
|
|
83
84
|
| `TEZGAH_DEEPSEEK_URL` | `hooks/tezgah_replay.py::_deepseek` | `https://api.deepseek.com/chat/completions` | Repoints the replay sheet's `--provider deepseek` rater (tests). Plain `http` is refused unless the host is this machine. |
|
|
84
85
|
| `TEZGAH_JUDGE_MODEL` | `hooks/tezgah_judge.py::fallback_model` | the cheap `any` row of the models table | The model the seam's chat fallback asks. |
|
|
86
|
+
| `TEZGAH_JUDGE_CLI` | `hooks/tezgah_paths.py::session_cli` | `judge_cli` in `config.json`, else `auto` | The session CLI the judgement seam asks: `omp`, `claude`, `opencode`, `cursor` or `codex`, or `auto` to read the host's marker. A named CLI that is not installed means no session CLI, never another one. |
|
|
85
87
|
|
|
86
88
|
## consult and codegen
|
|
87
89
|
|
package/docs/evidence.md
CHANGED
|
@@ -785,11 +785,12 @@ one rater's totals would show the other rater those labels.
|
|
|
785
785
|
|
|
786
786
|
`replay --label-model --prompt <file>` is rater 2 when that rater is a model. It sends each sheet
|
|
787
787
|
row to the judge seam (`hooks/tezgah_judge.py`) as one `choice` question and writes
|
|
788
|
-
`labels-model.jsonl` beside the sheet. It redacts the row's text first (`ti.redact`)
|
|
789
|
-
only when
|
|
788
|
+
`labels-model.jsonl` beside the sheet. It redacts the row's text first (`ti.redact`). It runs
|
|
789
|
+
only when a Jev carrier answers: TypeSafe, OpenRouter System One, Cloudflare Workers AI or a
|
|
790
|
+
compatible endpoint. `--provider jev` names it, and the old name `typesafe` still works. The prompt file holds each set's instructions and criteria. A reply
|
|
790
791
|
with no label from those criteria leaves its row unlabelled. The command writes each label as it
|
|
791
792
|
arrives, so a run that stops early keeps what it paid for. A second run asks only the unlabelled rows. Every run prints the input tokens and their cost. The sheet rows leave the machine for
|
|
792
|
-
|
|
793
|
+
the Jev carrier's endpoint. The key and the corpus stay on it. Kappa against a model rater
|
|
793
794
|
measures human-model agreement, not inter-rater reliability.
|
|
794
795
|
|
|
795
796
|
`--provider deepseek --model deepseek-v4-pro` asks the same questions from the same prompt file
|
package/docs/glossary.md
CHANGED
|
@@ -98,7 +98,7 @@ A mark consumed by its own first use, so the thing it protects happens once: the
|
|
|
98
98
|
An opt-out file in the repo tree - `.no-ponytail`, `.no-adhd`, `.no-graph`, `.no-lessons`, `.no-taste` - collected by `repo_marks()` walking up to the enclosing root (`hooks/tezgah_context.py::repo_marks`). Not a [kill switch](#kill-switch): a mark travels with the repo, a switch with the machine.
|
|
99
99
|
|
|
100
100
|
### plan
|
|
101
|
-
A piece of work spanning sessions, one markdown file with frontmatter under `<repo root>/.tezgah/plans/open/`, moved to `.tezgah/plans/done/` when closed, up to three of them injected by `open_plans()` (`hooks/tezgah_context.py::open_plans`) and its work happening on a `plan/NNN-slug` branch. Not a TODO in code.
|
|
101
|
+
A piece of work spanning sessions, one markdown file with frontmatter under `<repo root>/.tezgah/plans/open/`, moved to `.tezgah/plans/done/` when closed, up to three of them injected by `open_plans()` (`hooks/tezgah_context.py::open_plans`) and its work happening on a `plan/NNN-slug` branch. An optional `after:` names the plans it waits on, and `tezgah-task status` reads it with the ticked Acceptance boxes (`hooks/tezgah_task.py::queue`). Not a TODO in code, and not the host's session todo list, which no reader syncs with it.
|
|
102
102
|
|
|
103
103
|
### plan table
|
|
104
104
|
The status table in `.tezgah/plans/README.md` (`.tezgah/plans/README.md:9`), owned by the `plan-status` skill (`skills/plan-status/SKILL.md:1`) and among the first blocks the [budget](#budget) gives up because it lives on disk (`hooks/tezgah_context.py::DROP_ORDER`). Not the injected list of open plans.
|
package/docs/hosts.md
CHANGED
|
@@ -71,6 +71,8 @@ shared config, contract hash and the CLI symlinks every host shell can call
|
|
|
71
71
|
`~/.claude/settings.json` - `statusLine` (`bin/tezgah-setup::wire_claude_statusline`) and the attribution
|
|
72
72
|
off-switch (`bin/tezgah-setup::wire_claude_attribution`) - and the always-on block in
|
|
73
73
|
`~/.claude/CLAUDE.md` (`CLAUDE_RULES`), Claude's own user-level memory file.
|
|
74
|
+
The subagent roles go to `~/.claude/agents/tezgah-*.md`
|
|
75
|
+
(`bin/tezgah-setup::write_user_agents`).
|
|
74
76
|
Its hook manifest is the plugin's own
|
|
75
77
|
`hooks/hooks.json`; no `hooks.json` is written into `~/.claude`. Claude runs a
|
|
76
78
|
**copy** of the checkout under `~/.claude/plugins/cache`, refreshed by
|
|
@@ -84,6 +86,8 @@ shared config, contract hash and the CLI symlinks every host shell can call
|
|
|
84
86
|
(one group per event, PreToolUse carrying `CODEX_PRETOOL_MATCHER` at `bin/tezgah-setup::CODEX_PRETOOL_MATCHER`),
|
|
85
87
|
`skills/*` symlinks, `~/.codex/bin/consult`, and `mcp_servers.*` tables in
|
|
86
88
|
`config.toml` (`ensure_toml_mcp`, `bin/tezgah-setup::ensure_toml_mcp`).
|
|
89
|
+
The subagent roles go to `$CODEX_HOME/agents/tezgah-*.toml`
|
|
90
|
+
(`bin/tezgah-setup::write_user_agents`).
|
|
87
91
|
- **cursor** - `install_cursor` (`bin/tezgah-setup::install_cursor`): `~/.cursor/hooks.json`
|
|
88
92
|
(tezgah entries replaced, a user's Orca entries merged), `skills/*` symlinks,
|
|
89
93
|
`mcp.json` servers, and `cli-config.json` `statusLine`.
|
|
@@ -159,6 +163,11 @@ and drops the later ones.
|
|
|
159
163
|
| skills | codex | `.agents/skills` from the cwd up to the repo root, `~/.agents/skills`, `$CODEX_HOME/skills`; one name in two dirs is listed twice, not merged | links in `$CODEX_HOME/skills` |
|
|
160
164
|
| skills | cursor | `.agents/skills`, `.cursor/skills`, `~/.agents/skills`, `~/.cursor/skills`, then Claude's and Codex's project and user dirs; no documented winner | links in `~/.cursor/skills` |
|
|
161
165
|
| skills | opencode | its own skill tool is denied; the router lists `~/.config/opencode/skills`, `~/.claude/skills`, `~/.agents/skills`, first wins (`bin/tezgah-setup::skill_groups`) | links and the router |
|
|
166
|
+
| agents | claude | managed, the `claude --agents` flag, `.claude/agents`, `~/.claude/agents`, plugin agents namespaced `plugin:name`; a dir absent at start is not watched | `~/.claude/agents`, written at install |
|
|
167
|
+
| agents | codex | `$CODEX_HOME/agents`, `/etc/codex/agents`, `.codex/agents` (trusted repos only), read at config load | `$CODEX_HOME/agents`, written at install |
|
|
168
|
+
| agents | cursor | `cursor-agent`: `.cursor/agents`, then `.claude/agents`, `.grok/agents`, plugin agents; first name wins; no user dir; read at process start. The editor's docs add `~/.cursor/agents` and `~/.claude/agents` | `.cursor/agents` per repo at session start, in the CLI's line format (`hooks/tezgah_agents.py::render_md_cursor`) |
|
|
169
|
+
| agents | opencode | `~/.config/opencode/agents`, `.opencode/agents`, merged per field | `config` hook injection, `.opencode/agents` as fallback |
|
|
170
|
+
| agents | omp | `.omp/agents`, `~/.omp/agent/agents`, extensions, bundled | `~/.omp/agent/agents`, written at install |
|
|
162
171
|
| hooks | claude | user `settings.json` rows (Orca's), project rows, the plugin's `hooks/hooks.json` (tezgah's); every matching row runs, none is ordered before another | plugin rows |
|
|
163
172
|
| hooks | codex, cursor | `hooks.json` array order, then the repo's `.codex/` or `.cursor/hooks.json`; Codex runs a row only once its hash is trusted | own rows after Orca's |
|
|
164
173
|
| hooks | opencode | every `*.js`/`*.ts` in `plugins/` and `plugin/`; `tezgah.js` is linked into both, and its `globalThis.__tezgahPluginLoaded` guard makes the second load return `{}` | the plugin |
|
package/docs/judge.md
CHANGED
|
@@ -14,9 +14,10 @@ the kill-switch paragraph and nothing else (`CORE`,
|
|
|
14
14
|
One seam, five callers, one provider order, one egress boundary, one price, one
|
|
15
15
|
redirect guard. The module is stdlib only and total - a failure is a `None`, never
|
|
16
16
|
an exception, because a hook imports it and a hook that raises takes a session
|
|
17
|
-
down (`_request`, `hooks/tezgah_judge.py::_request`).
|
|
18
|
-
|
|
19
|
-
`hooks/tezgah_judge.py::
|
|
17
|
+
down (`_request`, `hooks/tezgah_judge.py::_request`). The carriers' endpoints are
|
|
18
|
+
module constants: `URL` (`hooks/tezgah_judge.py::URL`), `JEV_OPENROUTER_URL`
|
|
19
|
+
(`hooks/tezgah_judge.py::JEV_OPENROUTER_URL`) and `CLOUDFLARE_URL`
|
|
20
|
+
(`hooks/tezgah_judge.py::CLOUDFLARE_URL`). One opener serves every call (`OPENER`,
|
|
20
21
|
`hooks/tezgah_judge.py::OPENER`), and it refuses a redirect that leaves the
|
|
21
22
|
endpoint's host, so a `Location` cannot carry the bearer (`guarded_opener`,
|
|
22
23
|
`hooks/tezgah_paths.py`, the one copy `bin/consult` and `bin/codegen` use too). A
|
|
@@ -25,15 +26,18 @@ attempt. A 4xx, a session CLI's non-zero exit and a malformed reply never do
|
|
|
25
26
|
(`_transient`, `hooks/tezgah_judge.py::_transient`). A hook caller asks for one
|
|
26
27
|
attempt and a wall-clock `deadline` instead (`ask`, `hooks/tezgah_judge.py::ask`).
|
|
27
28
|
A session CLI answers in 4-10 s (measured 2026-10-07), so the skill hint's
|
|
28
|
-
4 s deadline usually ends first. `TEZGAH_TYPESAFE_URL`, `
|
|
29
|
-
|
|
29
|
+
4 s deadline usually ends first. `TEZGAH_TYPESAFE_URL`, `TEZGAH_JEV_OPENROUTER_URL`,
|
|
30
|
+
`TEZGAH_CLOUDFLARE_URL`, `TEZGAH_OPENROUTER_URL` and
|
|
31
|
+
`TEZGAH_OMP_BIN`/`TEZGAH_CLAUDE_BIN` are the test seams. Each URL override goes
|
|
32
|
+
through `override` (`hooks/tezgah_judge.py::override`), which refuses plain http
|
|
33
|
+
off this machine.
|
|
30
34
|
|
|
31
35
|
Every caller reads an answer through the same accessors rather than reaching
|
|
32
36
|
into the raw reply, so a Choice and a Noul are read one way for all five
|
|
33
37
|
(`choice`, `hooks/tezgah_judge.py::choice`; `noul`,
|
|
34
38
|
`hooks/tezgah_judge.py::noul`). A `text` question is the one shape that asks
|
|
35
39
|
for prose. `bin/tezgah-taste` asks it for a learning's readable line, and only
|
|
36
|
-
a generative provider answers one.
|
|
40
|
+
a generative provider answers one. No Jev carrier is sent one (`text`,
|
|
37
41
|
`hooks/tezgah_judge.py::text`). All three are total: a missing or
|
|
38
42
|
wrongly-typed answer is a `None`, never an exception.
|
|
39
43
|
|
|
@@ -44,9 +48,11 @@ are untouched, so a model answer can never license a "done" (`STEP_KINDS`,
|
|
|
44
48
|
|
|
45
49
|
The state leaves the machine. By default it goes to the session's own vendor,
|
|
46
50
|
through the session's own CLI and credential ([below](#the-providers-and-their-order)).
|
|
47
|
-
A third party
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
A third party reads it only as the `fallback` setting allows. The third parties
|
|
52
|
+
are the Jev carriers' hosts - `api.typesafe.ai`, `openrouter.ai`,
|
|
53
|
+
`api.cloudflare.com` or a user's `JEV_API_BASE_URL` - and the chat endpoint
|
|
54
|
+
(`OPENROUTER_URL`, `hooks/tezgah_judge.py::OPENROUTER_URL`).
|
|
55
|
+
For the triage the state is the screen's own text, so whoever
|
|
50
56
|
answers reads any personal data on it. For the docs fallback it is the query.
|
|
51
57
|
Nothing else goes: no session id, no
|
|
52
58
|
workspace path, no environment. The seam does not rewrite the state, because
|
|
@@ -89,18 +95,76 @@ background `learn` that armed taste starts.
|
|
|
89
95
|
|
|
90
96
|
`providers()` (`hooks/tezgah_judge.py::providers`) is the order `ask()` tries.
|
|
91
97
|
The next one is asked only when the previous failed. First comes the session's own
|
|
92
|
-
CLI (`tp.session_cli`, `hooks/tezgah_paths.py::session_cli`)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
CLI (`tp.session_cli`, `hooks/tezgah_paths.py::session_cli`). The host's marker
|
|
99
|
+
names it, in this order:
|
|
100
|
+
|
|
101
|
+
| CLI | Marker | Set by |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `omp` | `OMPCODE` | omp, which sets `CLAUDECODE` too |
|
|
104
|
+
| `claude` | `CLAUDECODE` | Claude Code |
|
|
105
|
+
| `opencode` | `OPENCODE` | opencode, in its own process |
|
|
106
|
+
| `cursor` (runs `cursor-agent`) | `CURSOR_AGENT`, `CURSOR_VERSION` | Cursor: the first in its shell tool, the second in its hooks |
|
|
107
|
+
| `codex` | `CODEX_THREAD_ID` | Codex in its shell tool; tezgah's Codex hook sets it from the session id |
|
|
108
|
+
|
|
109
|
+
A marked host whose binary is missing has no session CLI. No other CLI stands
|
|
110
|
+
in. `TEZGAH_JUDGE_CLI`, else `judge_cli` in `~/.config/tezgah/config.json`,
|
|
111
|
+
names one of the five instead. `auto`, the default, reads the marker. A named CLI
|
|
112
|
+
that is not installed is no session CLI either.
|
|
113
|
+
|
|
114
|
+
The CLI runs headless in an empty temp dir. Its flags are `SESSION_ARGV`
|
|
115
|
+
(`hooks/tezgah_judge.py::SESSION_ARGV`). The omp and claude runs drop tools,
|
|
116
|
+
rules, skills, extensions, MCP servers and settings. The other three have no flag
|
|
117
|
+
that drops their tools or takes a system prompt. They run with the least their
|
|
118
|
+
`--help` offers: opencode `--pure`, cursor-agent `--mode ask`, codex
|
|
119
|
+
`-s read-only --ephemeral`. Their prompt starts with the system prompt.
|
|
120
|
+
`opencode run` ran a shell command its prompt asked for in a probe on
|
|
121
|
+
2026-10-09. So it also gets an inline config that denies every tool
|
|
122
|
+
(`SESSION_ENV`, `hooks/tezgah_judge.py::SESSION_ENV`). With it, the same probe
|
|
123
|
+
wrote nothing. cursor-agent in ask mode refused the same shell call.
|
|
124
|
+
Measured 2026-10-07, a call cost $0.007 on claude and $0.015 on omp. Measured
|
|
125
|
+
2026-10-09 on one choice question, opencode read 28,646 input tokens ($0.004 by
|
|
126
|
+
its own report), cursor-agent 17,095 and codex 20,919. The session's own
|
|
127
|
+
credential pays, OAuth subscription included. The answer and usage come from the
|
|
128
|
+
CLI's JSON output (`_session_request`, `hooks/tezgah_judge.py::_session_request`).
|
|
129
|
+
`_cli_answer` (`hooks/tezgah_judge.py::_cli_answer`) reads the last three. Only
|
|
130
|
+
omp and claude name the model. Then come the
|
|
131
|
+
third parties: first the chosen Jev carriers, each a real System One transport
|
|
132
|
+
(`_jev_call`, `hooks/tezgah_judge.py::_jev_call`), then the OpenRouter chat
|
|
133
|
+
fallback. `JEV_CARRIERS` (`hooks/tezgah_judge.py::JEV_CARRIERS`) names the six.
|
|
134
|
+
Two of them are not Jev. Clef and Clef-flash are Cloudflare's own decision
|
|
135
|
+
models. They take the same System One request. They answer in the same typed
|
|
136
|
+
shape, so a caller that needs a typed answer takes them like Jev.
|
|
137
|
+
|
|
138
|
+
| Carrier | Endpoint | Credential (env, else file, stripped) | Body |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| `typesafe` | `https://api.typesafe.ai/v1/systemone` | `TYPESAFE_API_KEY`, else `~/.config/typesafe/key`, else the active omp login (`~/.omp/agent/agent.db`, read-only; `typesafe_key`, `hooks/tezgah_paths.py::typesafe_key`) | `{state, model, questions}` |
|
|
141
|
+
| `jev-openrouter` | `https://openrouter.ai/api/v1/systemone` | `OPENROUTER_API_KEY`, else `~/.config/openrouter/key` | the same; a bare `jev-*` id is sent as it is, and OpenRouter maps it onto `typesafe/` |
|
|
142
|
+
| `jev-cloudflare` | `https://api.cloudflare.com/client/v4/accounts/<id>/ai/run` | `JEV_CLOUDFLARE_API_TOKEN`, else `CLOUDFLARE_API_TOKEN`, else `~/.config/cloudflare/token`; the account id from `CLOUDFLARE_ACCOUNT_ID`, else `~/.config/cloudflare/account_id` | `{model: "typesafe/jev", input: {state, questions}}`; the reply is read bare or inside `result` |
|
|
143
|
+
| `jev-compatible` | `JEV_API_BASE_URL`, used verbatim | `JEV_API_KEY` | TypeSafe's, the model from `TEZGAH_JEV_MODEL` if set |
|
|
144
|
+
| `clef`, `clef-flash` | `https://api.cloudflare.com/client/v4/accounts/<id>/ai/run/@cf/cloudflare/<name>` | the Cloudflare token and account id above | `{model: "<name>", state, questions}`; the reply read like Cloudflare's above |
|
|
145
|
+
|
|
146
|
+
`JEV_API_BASE_URL` and `JEV_API_KEY` are the names the public jev-mcp server
|
|
147
|
+
reads, so one export serves both. `TEZGAH_JEV_PROVIDER` chooses the carrier,
|
|
148
|
+
else `JEV_PROVIDER`, else `jev` in `~/.config/tezgah/config.json`, else `auto`
|
|
149
|
+
(`jev_choice`, `hooks/tezgah_paths.py::jev_choice`). The values are `auto`,
|
|
150
|
+
`typesafe`, `openrouter`, `cloudflare`, `compatible`, `clef` and `clef-flash`.
|
|
151
|
+
The Workers AI ids `@cf/cloudflare/clef` and `@cf/cloudflare/clef-flash` name
|
|
152
|
+
the same two (`jev_name`, `hooks/tezgah_paths.py::jev_name`).
|
|
153
|
+
`tezgah-setup --jev <value>` writes the config key
|
|
154
|
+
(`set_jev`, `bin/tezgah-setup::set_jev`). `auto`
|
|
155
|
+
asks every carrier that resolves, in the table's order (`jev_carriers`,
|
|
156
|
+
`hooks/tezgah_paths.py::jev_carriers`). The seam asks a named carrier without
|
|
157
|
+
its credential nothing, and nothing stands in for it: the call records
|
|
158
|
+
`no credential (jev=<value>)` as a failure. `tezgah-status --judge` prints the
|
|
159
|
+
choice and the carriers it resolves to (`jev_summary`,
|
|
160
|
+
`hooks/tezgah_judge.py::jev_summary`). A cost row prices the carrier that
|
|
161
|
+
answered (`input_price`, `hooks/tezgah_judge.py::input_price`). Per 1M input
|
|
162
|
+
tokens: $0.042 for Jev, $0.24 for Clef, $0.09 for Clef-flash. Output is free.
|
|
163
|
+
|
|
164
|
+
OpenRouter's chat fallback reads the OpenRouter key (`openrouter_key`,
|
|
165
|
+
`hooks/tezgah_judge.py::openrouter_key`).
|
|
102
166
|
It asks the table's cheap row unless `TEZGAH_JUDGE_MODEL` names another
|
|
103
|
-
(`fallback_model`, `hooks/tezgah_judge.py::fallback_model`). The key
|
|
167
|
+
(`fallback_model`, `hooks/tezgah_judge.py::fallback_model`). The key files are
|
|
104
168
|
read because a hook runs where `~/.zshenv` never did. A chat answer is asked for in prose
|
|
105
169
|
(`CHAT_SYSTEM`, `hooks/tezgah_judge.py::CHAT_SYSTEM`) and filtered to the ids
|
|
106
170
|
asked, a wrongly typed answer dropped (`_chat_answers`,
|
|
@@ -111,8 +175,8 @@ asked, a wrongly typed answer dropped (`_chat_answers`,
|
|
|
111
175
|
|
|
112
176
|
| `fallback` | Session CLI present | No session CLI |
|
|
113
177
|
|---|---|---|
|
|
114
|
-
| `vendor` (default) | the session CLI only; when it fails, no judgement |
|
|
115
|
-
| `any` | the session CLI, then
|
|
178
|
+
| `vendor` (default) | the session CLI only; when it fails, no judgement | the Jev carriers, then the chat fallback |
|
|
179
|
+
| `any` | the session CLI, then the Jev carriers, then the chat fallback | the Jev carriers, then the chat fallback |
|
|
116
180
|
| `none` | the session CLI only | nobody: `available()` is false |
|
|
117
181
|
|
|
118
182
|
Nothing that stands in is silent. A result carries `provider`, the `model`
|
|
@@ -124,7 +188,7 @@ hint's cost row and the router's `route` row also carry `judge=<provider>/<model
|
|
|
124
188
|
|
|
125
189
|
A caller that needs one provider in particular passes `only` (`named`,
|
|
126
190
|
`hooks/tezgah_judge.py::named`). `learn`'s decision has to come from a typed
|
|
127
|
-
model, so it passes `only=("
|
|
191
|
+
model, so it passes `only=("jev",)`, every Jev carrier that resolves. It gets `None` rather than another
|
|
128
192
|
provider's answer. The caller named the provider, so the `vendor` order does not
|
|
129
193
|
apply. `none` still keeps every third party out.
|
|
130
194
|
|
|
@@ -173,8 +237,9 @@ known (`note`, `hooks/tezgah_integrity.py::note`), counted by the row's kind
|
|
|
173
237
|
costs a fraction of a cent, so a cache is not worth its state file, and a naive
|
|
174
238
|
one would make two runs of the same command disagree. Beside the last-use
|
|
175
239
|
record, the seam keeps a failure marker (`DOWN_FOR`, 300 s, in `hooks/tezgah_judge.py`). A
|
|
176
|
-
|
|
177
|
-
provider, endpoint and credential down for five minutes.
|
|
240
|
+
401, 402, 403, 5xx or a session CLI's non-zero exit marks that
|
|
241
|
+
provider, endpoint and credential down for five minutes. A 403 is OpenRouter's
|
|
242
|
+
answer to a key past its limit. Until the marker
|
|
178
243
|
expires, that provider is skipped and sent no request. A dead key or an empty account then costs
|
|
179
244
|
one refusal per five minutes, not one per prompt. A rotated key gets a new
|
|
180
245
|
marker, so the seam asks it at once.
|
|
@@ -193,8 +258,11 @@ known (`note`, `hooks/tezgah_integrity.py::note`), counted by the row's kind
|
|
|
193
258
|
|
|
194
259
|
## Source of truth
|
|
195
260
|
|
|
196
|
-
- `hooks/tezgah_judge.py` — the seam:
|
|
197
|
-
the answer accessors, the retry class and the
|
|
261
|
+
- `hooks/tezgah_judge.py` — the seam: the carriers' endpoints and bodies,
|
|
262
|
+
`available()`, `ask()`, the answer accessors, the retry class and the
|
|
263
|
+
provider-down marker.
|
|
264
|
+
- `hooks/tezgah_paths.py` — the key channels (`typesafe_key`, `jev_carriers`)
|
|
265
|
+
and the carrier choice (`jev_choice`).
|
|
198
266
|
- `bin/tezgah-triage` — the snapshot triage and the per-state matrix; prints the
|
|
199
267
|
unit it selected, the characters it saved and the cost it paid.
|
|
200
268
|
- `bin/tezgah-docs` — the page router; its index match, then its one fallback
|
package/docs/layers.md
CHANGED
|
@@ -76,7 +76,7 @@ lessons and research lines.
|
|
|
76
76
|
Must not own the loop, the model, the tools or the network. tezgah never runs
|
|
77
77
|
the work and never rolls back on its own - rollback is the explicit
|
|
78
78
|
`bin/tezgah-rollback` - and the subagents it defines are rendered into a host's
|
|
79
|
-
own agent surface for that host to run (`hooks/tezgah_agents.py:2-
|
|
79
|
+
own agent surface for that host to run (`hooks/tezgah_agents.py:2-30`).
|
|
80
80
|
|
|
81
81
|
## The boundary, one term at a time
|
|
82
82
|
|
package/docs/models.md
CHANGED
|
@@ -59,21 +59,21 @@ invoices).
|
|
|
59
59
|
| Host | Family | Where the model lands |
|
|
60
60
|
|---|---|---|
|
|
61
61
|
| Claude Code | anthropic | the agent file's alias and `effort:` (`_model_lines`): an alias follows the provider and keeps the main session's variant, where a full id breaks on Bedrock, Vertex and a gateway (code.claude.com/docs/en/sub-agents) |
|
|
62
|
-
| Codex | openai | `model` and `model_reasoning_effort` in
|
|
62
|
+
| Codex | openai | `model` and `model_reasoning_effort` in `$CODEX_HOME/agents/*.toml` |
|
|
63
63
|
| opencode | any | a selector `--refresh` found in `opencode models` for the slot's model under any configured provider (`resolve_opencode`); none found, no model line, so the agent inherits. The slot's effort rides the JSON agent config as `reasoningEffort` (opencode.ai/docs/agents) |
|
|
64
64
|
| omp | anthropic when the session default is an Anthropic model, any otherwise (`omp_mode`); a non-Anthropic default is `any`, never a silent fall back to the Anthropic column | `task.agentModelOverrides`, which omp resolves before the agent or bundled model (omp's own docs: `omp://task-agent-discovery.md`, *Model and structured-output precedence*); every slot is written, the frontier row included, so no agent in the row runs on the session default; each override is a **fallback chain** (`omp_overrides`, `_chain`): the mode's family first, then what `fallback` in `~/.config/tezgah/config.json` allows (`tp.fallback_policy`) over the families this machine holds a credential for (`funded_families` reads omp's auth store and the provider env keys; a family it cannot see is left out, never guessed in) - `vendor`, the default, keeps only the session vendor's model (`openrouter/anthropic/claude-opus-5.5:<effort>` behind an Anthropic session, `OPENROUTER_ID`), so a 429 never moves an Opus session's subagent onto GPT or GLM; `any` adds every other funded family, rotated per agent; `none` writes the first entry alone - omp splits the chain into per-spawn patterns (omp's own docs: `omp://settings.md (its `retry.fallbackChains` section)`), so one provider's 429 falls through instead of killing the spawn, measured before this: 24 of 26 post-routing 429s hit a subagent's first request, all on one Opus account every slot shared; `apply_omp` also writes `modelRoles.plan` and `.slow` on that frontier row (same record, same ownership) so plan mode designs on it, and their fallbacks go to `retry.fallbackChains.<role>` under the same `fallback` rule, the only chain keys tezgah owns (`default` and provider-keyed chains stay the user's); `apply_omp` writes through the installer's own binary and agent dir, from HOME so a repository's `.omp/config.yml` never leaks machine-wide, and touches only the entries tezgah wrote (recorded in `~/.config/tezgah/models.json` as `omp_written`; a machine written before that record is adopted by its value, `_ours_by_shape`); a changed `fallback` reaches omp on the next `tezgah-route --refresh` or `tezgah-setup --install` |
|
|
65
65
|
| dsh | - | none: no model setting was found to write |
|
|
66
66
|
|
|
67
67
|
The orchestrator agent keeps `model: inherit`: it is the main thread's own agent.
|
|
68
68
|
|
|
69
|
-
| Cursor | - |
|
|
69
|
+
| Cursor | - | `model: inherit` in `.cursor/agents/*.md` (`render_md_cursor`): `cursor-agent` passes the value through as a raw id, an alias such as `opus` is not in its model list, and the effort belongs **inside** the id (`claude-opus-5[effort=high]`, cursor.com/docs/subagents). No id this table names was verified against Cursor's models page, so no tier model is pinned there yet |
|
|
70
70
|
|
|
71
71
|
omp's bundled agents are routed through the same record (omp's own docs: `omp://task-agent-discovery.md`, *Bundled agents*): `scout` on the explore slot, `sonic` on the cheap slot, `task` on the standard slot, and `reviewer`/`security-reviewer` left to inherit, because a review is frontier work. A user's own value for any of them wins (see the ownership rule above). Those two are the gap this leaves: the record carries no entry for them, so a session on a cheap model reviews on that model - routing them is one more `BUNDLED` entry, not decided here.
|
|
72
72
|
|
|
73
73
|
## What is not routed yet
|
|
74
74
|
|
|
75
75
|
- **Claude Code's built-in subagents** (Explore, general-purpose, Plan) run on the session model. `CLAUDE_CODE_SUBAGENT_MODEL` and a settings `env` block exist but carry no effort, and whether a project agent with a built-in's name replaces it is not stated where it can be cited - so nothing is generated on a guess. What would close it: a documented per-agent effort for built-ins, or a confirmed name-collision rule.
|
|
76
|
-
- **Codex's default subagent** (spawned with no agent file): only
|
|
76
|
+
- **Codex's default subagent** (spawned with no agent file): only `$CODEX_HOME/agents/*.toml` carries a model today. What would close it: a documented `[agents]` default settable from a file tezgah already writes.
|
|
77
77
|
- **opencode's built-in agents**: the injected JSON could carry `model`/`reasoningEffort` for them, but the merge semantics for a built-in entry are not documented where they can be cited, and a wrong merge would replace a built-in prompt instead of adding a model.
|
|
78
78
|
- **dsh**: the model is a plugin config, not an agent field. The composed profile carries `agent-default-model` with `config: {provider: deepseek-official, model: deepseek-flash}` (`dsh --profile web --dump-config`, 2026-09-30) and tezgah's managed patch block already patches plugin config by id (its `llm-pi-ai` row), so a `- id: agent-default-model` row would set the profile's model. Not written, because that knob is one model for the whole session - no `subagent*` entry in the composed tree carries a model - and a single session-wide model is the main thread's setting, which this design deliberately leaves alone ([why the main thread keeps one model](#the-shape)). What would close it: a per-agent model in dsh's config surface.
|
|
79
79
|
|
|
@@ -91,7 +91,9 @@ fixed:
|
|
|
91
91
|
(`OVERRIDE`, `hooks/tezgah_models.py::OVERRIDE`) - the class the judge
|
|
92
92
|
under-routed in its measurement, and the classes a wrong call cannot be
|
|
93
93
|
undone on. A 12-brief fixture pins it: 8 high-stakes briefs route to
|
|
94
|
-
frontier, 4 near-miss controls do not (`tests/test_models.py`).
|
|
94
|
+
frontier, 4 near-miss controls do not (`tests/test_models.py`). Such a brief
|
|
95
|
+
that only reviews goes to `tezgah-security` instead (`REVIEW_ONLY`,
|
|
96
|
+
`hooks/tezgah_models.py::REVIEW_ONLY`).
|
|
95
97
|
2. Otherwise the brief - redacted with the ledger's own reader
|
|
96
98
|
(`redact`, `hooks/tezgah_integrity.py::redact`) - goes to the judge as one Choice over three tiers (`TIER_QUESTION`,
|
|
97
99
|
`hooks/tezgah_models.py::TIER_QUESTION`). The judge asks the session's own model first ([judge](judge.md)).
|
|
@@ -99,9 +101,17 @@ fixed:
|
|
|
99
101
|
the same session that wrote the rubric (2026-09-30, twice): under-route 0.025,
|
|
100
102
|
accuracy 0.925 and 0.900, 392 ms median, about 656 input tokens per call; a
|
|
101
103
|
keyword rule on the same set under-routed 0.100. The session model was not measured on that set.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
The same call asks a second Choice (`ROLE_QUESTION`,
|
|
105
|
+
`hooks/tezgah_models.py::ROLE_QUESTION`): is the brief the whole job of a
|
|
106
|
+
specialist? A yes names that agent on its own tier (`AGENT_SLOT`,
|
|
107
|
+
`hooks/tezgah_models.py::AGENT_SLOT`). Before this question, sessions
|
|
108
|
+
spawned the five specialists 0 times in 121 delegations (2026-10-07 to 10-09).
|
|
109
|
+
Clef agreed on 9 of 10 briefs this session labelled (2026-10-09).
|
|
110
|
+
3. With no judgement (`judge-off`, no key, a failed call) `--phase review` and
|
|
111
|
+
`--phase research` name the reviewer and the researcher (`PHASE_AGENT`,
|
|
112
|
+
`hooks/tezgah_models.py::PHASE_AGENT`). Another phase picks the tier from the
|
|
113
|
+
static table (`PHASE_TIER`, `hooks/tezgah_models.py::PHASE_TIER`). With no
|
|
114
|
+
phase the middle tier is used.
|
|
105
115
|
|
|
106
116
|
The brief leaves the machine for the judge, like every judgement ([judge](judge.md)).
|
|
107
117
|
Every routed call writes one `route` row to the session's ledger. The row names the
|
package/docs/operations.md
CHANGED
|
@@ -28,7 +28,6 @@ before an install is considered.
|
|
|
28
28
|
| `--status [PATH]` | Print the armed/used checklist for PATH (default cwd) and stop — the same line as `bin/tezgah-status` (`bin/tezgah-setup::main`, `hooks/tezgah_context.py::health_lines`). It also prints the report's `config.json hosts (...) match the hosts wired (...)` row when the recorded list and the wiring on disk disagree (`hosts_row`), and nothing when they agree: install health is checked here, not only in a full report. |
|
|
29
29
|
| `--agents [PATH]` | Regenerate PATH's per-repo subagent set (default cwd); outside a [root](glossary.md#root) it prints `no agents generated` (`bin/tezgah-setup::main`). |
|
|
30
30
|
| `--write-manifest` | Regenerate the tracked `MANIFEST` from `git ls-files` and stop — the release step, its only writer, and it says so on a tree with no `.git` rather than writing an empty listing (`bin/tezgah-setup::write_manifest`, `bin/tezgah-setup::plugin_files`). |
|
|
31
|
-
| `--write-plugin-agents` | Re-render the plugin's tracked `agents/*.md` from the role bodies `hooks/tezgah_agents.py` generates per repo, and stop — the release step that keeps the shipped reviewer from drifting from the generated one; `tests/test_agents.py` fails until it has run (`write_plugin_agents`, `plugin_agents`). |
|
|
32
31
|
| `--deps` | Install the missing optional tools and stop; with `--install` the install already does it. Like `--install` and `--enable`, it exits 1 when a requested tool is still missing (`bin/tezgah-setup::main`). |
|
|
33
32
|
| `--host-deps` | With `--install` or `--deps`, also install the missing third-party host CLIs (cursor-agent, pnpm, dsh). They are opt-in because each one is a vendor `curl \| sh` that uninstall does not take back. Every installer runs with a 600 s timeout, each `curl` with `--max-time 300` and each pipeline under `pipefail`, so a stalled or refused download fails instead of hanging or reading as success (audit M-9). |
|
|
34
33
|
| `--mcp-schemas` | Measure the MCP tool-schema band by asking each registered server (`initialize` + `tools/list`) and stop (`bin/tezgah-setup::main`, `bin/tezgah-setup::mcp_schema_report`). |
|
|
@@ -435,18 +434,21 @@ builds it (`capture_signals`, `bin/tezgah-taste::capture_signals`). A signal
|
|
|
435
434
|
holds the prompt, the files written, the agent's edits, and the user's own edit
|
|
436
435
|
between two agent writes. That last one compares the after blob with the next
|
|
437
436
|
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)).
|
|
437
|
+
`bin/tezgah-taste::user_diff`). `learn` asks the Jev model for one typed decision
|
|
438
|
+
per signal (`decide`, `bin/tezgah-taste::decide`, [judge](judge.md)). Any Jev
|
|
439
|
+
carrier will do: TypeSafe, OpenRouter System One, Cloudflare Workers AI or a
|
|
440
|
+
compatible endpoint. The decision
|
|
440
441
|
names preference, defect or none. It picks one of eleven fixed categories and a
|
|
441
442
|
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
|
|
443
|
+
contradicts, narrows or unrelated. When a provider outside the Jev family answers,
|
|
444
|
+
`learn` records the decision in the `decisions` table as `unverified`. It never
|
|
445
|
+
applies it. The report counts the typed decisions under `jev`. A
|
|
444
446
|
defect goes to the `defects` table and never into the ledger.
|
|
445
447
|
|
|
446
448
|
Armed taste also learns by itself. At session start, `learn` starts in the
|
|
447
449
|
background when new signals arrived since the last start. It starts at most
|
|
448
450
|
once an hour per repository (`learn_later`, `hooks/tezgah_taste.py::learn_later`). It runs
|
|
449
|
-
with `--no-fallback` and only when a
|
|
451
|
+
with `--no-fallback` and only when a Jev carrier resolves, so it never pays a
|
|
450
452
|
generative provider for a decision it could not apply. It does not run on
|
|
451
453
|
Windows, which has no ledger lock yet. The stamp is a `taste_learn` row of the
|
|
452
454
|
cache's `tezgah.db`. The log lives under the cache dir, in `taste-learn/`.
|
|
@@ -661,7 +663,7 @@ or its optional tools and config, on its own initiative
|
|
|
661
663
|
|
|
662
664
|
## Triage: `tezgah-triage` and the `judge-off` switch
|
|
663
665
|
|
|
664
|
-
One judgement seam serves five callers, each of them asking
|
|
666
|
+
One judgement seam serves five callers, each of them asking the judge a batched
|
|
665
667
|
question instead of paying an agent to read a page: the analyze-app loop's snapshot
|
|
666
668
|
triage (`bin/tezgah-triage`), `bin/tezgah-docs` for a query its keyword index
|
|
667
669
|
cannot place, and the prompt-path skill hint (`hooks/tezgah_skill_pick.py`), the
|
|
@@ -700,7 +702,10 @@ made - no credential, the switch below, or a failed call - and the loop reads th
|
|
|
700
702
|
tree directly instead.
|
|
701
703
|
|
|
702
704
|
The state leaves the machine. A judgement sends the state and the questions to
|
|
703
|
-
|
|
705
|
+
the host of whichever provider answers - the session's own CLI (omp, claude,
|
|
706
|
+
opencode, cursor, codex), or the chosen Jev
|
|
707
|
+
carrier's (`api.typesafe.ai`, `openrouter.ai`, `api.cloudflare.com` or a
|
|
708
|
+
`JEV_API_BASE_URL`, see [judge](judge.md)) (`ask()`, `hooks/tezgah_judge.py::ask`) - for the triage that is
|
|
704
709
|
the snapshot's own text, so a screen carrying personal data is read by a third
|
|
705
710
|
party, and for the docs fallback it is the reader's query. Nothing else goes: no
|
|
706
711
|
session id, no workspace path, no credential beyond the bearer header, and the
|
|
@@ -710,11 +715,16 @@ request cannot drift. That is why the two shell callers are on-demand - an agent
|
|
|
710
715
|
asks for a judgement, no gate does - while the skill hint asks only with its own
|
|
711
716
|
marker armed, and why the switch below is the off button for the whole path.
|
|
712
717
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
`
|
|
717
|
-
|
|
718
|
+
With no session CLI, the third party is the Jev model through one of its carriers.
|
|
719
|
+
TypeSafe's credential resolves from `TYPESAFE_API_KEY`, else from
|
|
720
|
+
`~/.config/typesafe/key`, else from the active omp login (`typesafe_key()`,
|
|
721
|
+
`hooks/tezgah_paths.py::typesafe_key`). `jev` chooses which of the other Jev
|
|
722
|
+
carriers the seam asks - OpenRouter's System One endpoint, Cloudflare Workers AI
|
|
723
|
+
and any System One-compatible URL (`jev_carriers()`,
|
|
724
|
+
`hooks/tezgah_paths.py::jev_carriers`). The OpenRouter chat fallback's key rides
|
|
725
|
+
`OPENROUTER_API_KEY` and then `~/.config/openrouter/key` (`openrouter_key()`,
|
|
726
|
+
`hooks/tezgah_judge.py::openrouter_key`). When no carrier answers, the same
|
|
727
|
+
questions go to that chat fallback. The file is the channel that
|
|
718
728
|
matters on a machine exporting the variable from `~/.zshenv`: a hook or a bin tool
|
|
719
729
|
runs in a non-interactive shell, where that export never ran, so the file is what a
|
|
720
730
|
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/testing.md
CHANGED
|
@@ -171,7 +171,7 @@ into the test process would answer about the developer's real machine.
|
|
|
171
171
|
| `tests/_probe_paths.py` | argv op, no payload (`:11`) | `roots`, `root_for`, `off`, `default_root`, `config`, `off_dirs`, `cache_dir`, `which_user`, `orx_bin`, `consult_options`, `have_typesafe_key`, `codegraph_bin` |
|
|
172
172
|
| `tests/_probe_context.py` | JSON on stdin, `{"fn": ...}` (`:4-5`) | `context_for`, `health_lines`, `health_segments`, `record` |
|
|
173
173
|
| `tests/_probe_integrity.py` | JSON on stdin (`:4-6`) | `note`, `note_tool`, `note_turn`, `kinds`, `events`, `prior_calls`, `counters`, `shortcut_command`, `shortcut_edit`, `stop_reason`, `verify_command` |
|
|
174
|
-
| `tests/_probe_agents.py` | JSON on stdin (`:3-4`) | `sync_root`, `opencode_json`, `cleanup`, `detect` |
|
|
174
|
+
| `tests/_probe_agents.py` | JSON on stdin (`:3-4`) | `sync_root`, `opencode_json`, `cleanup`, `detect`, `omp`, `user`, `steering` |
|
|
175
175
|
| `tests/_probe_gate.py` | JSON on stdin (`:4-8`) | the shared gate `decision(tool, input, cwd, session_id)`; `capture_log` plants a stub `tezgah_snapshot` in `sys.modules`, so the snapshot call site is pinned whether or not that module has landed |
|
|
176
176
|
|
|
177
177
|
A probe is invoked through `support.run`/`run_json` with its path constant
|
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.
|