@r1z4x/tezgah 1.11.0 → 1.14.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 +507 -1
- package/MANIFEST +40 -0
- package/NOTICE +152 -0
- package/README.de.md +41 -20
- package/README.es.md +39 -19
- package/README.fr.md +41 -20
- package/README.md +18 -10
- package/README.tr.md +39 -21
- package/bin/codegen +9 -2
- package/bin/consult +6 -0
- package/bin/tezgah-adhd +3 -0
- package/bin/tezgah-agents +3 -0
- package/bin/tezgah-capture +3 -0
- package/bin/tezgah-design +329 -54
- package/bin/tezgah-docs +158 -42
- package/bin/tezgah-dsh +1 -1
- package/bin/tezgah-gate +7 -2
- package/bin/tezgah-import-ai-research +16 -4
- package/bin/tezgah-index +3 -0
- package/bin/tezgah-lessons +13 -4
- package/bin/tezgah-mcp +4 -0
- package/bin/tezgah-migrate +3 -0
- package/bin/tezgah-ocr-review +2 -1
- package/bin/tezgah-optimize +4 -1
- package/bin/tezgah-pony +3 -0
- package/bin/tezgah-research +51 -10
- package/bin/tezgah-rollback +3 -0
- package/bin/tezgah-route +1 -1
- package/bin/tezgah-setup +1741 -95
- package/bin/tezgah-status +11 -1
- package/bin/tezgah-task +58 -17
- package/bin/tezgah.js +10 -3
- package/commands/adhd.md +1 -1
- package/docs/README.md +19 -8
- package/docs/architecture.md +2 -2
- package/docs/citations-baseline.json +11 -17
- package/docs/clarity-baseline.json +12 -6
- package/docs/contract.md +83 -34
- package/docs/environment.md +59 -24
- package/docs/evidence.md +128 -25
- package/docs/gate.md +77 -23
- package/docs/glossary.md +1 -1
- package/docs/hosts.md +343 -48
- package/docs/layers.md +2 -2
- package/docs/models.md +6 -0
- package/docs/operations.md +83 -29
- package/docs/research.md +37 -11
- package/docs/skills.md +31 -8
- package/docs/status-line.md +39 -23
- package/docs/testing.md +50 -17
- package/docs/vision.md +6 -2
- package/hooks/hooks.json +1 -1
- package/hooks/lang/en.json +16 -2
- package/hooks/lang/tr.json +14 -2
- package/hooks/projects-posttooluse.py +11 -3
- package/hooks/projects-stop.py +3 -2
- package/hooks/tezgah_agents.py +27 -3
- package/hooks/tezgah_attest.py +79 -10
- package/hooks/tezgah_context.py +61 -31
- package/hooks/tezgah_gate.py +480 -126
- package/hooks/tezgah_integrity.py +577 -133
- package/hooks/tezgah_lessons.py +5 -2
- package/hooks/tezgah_paths.py +60 -8
- package/hooks/tezgah_policy.py +48 -18
- package/hooks/tezgah_replay.py +8 -2
- package/hooks/tezgah_research.py +167 -24
- package/hooks/tezgah_skill_pick.py +1 -1
- package/hooks/tezgah_snapshot.py +6 -3
- package/hooks/tezgah_stack.py +236 -1
- package/hooks/tezgah_stopspec.py +2 -1
- package/hooks/tezgah_task.py +2 -1
- package/hosts/amp/hook.py +217 -0
- package/hosts/amp/tezgah-plugin.ts.in +396 -0
- package/hosts/antigravity/hook.py +255 -0
- package/hosts/codex/hook.py +3 -2
- package/hosts/commandcode/hook.py +239 -0
- package/hosts/copilot/hook.py +284 -0
- package/hosts/cursor/hook.py +4 -2
- package/hosts/droid/hook.py +259 -0
- package/hosts/dsh/hooks.json +1 -1
- package/hosts/gemini/hook.py +213 -0
- package/hosts/goose/hook.py +145 -0
- package/hosts/omp/hook.py +5 -2
- package/hosts/omp/tezgah-hook.ts.in +157 -42
- package/hosts/opencode/plugins/tezgah.js +209 -63
- package/hosts/qwen/hook.py +206 -0
- package/output-styles/tezgah.md +11 -6
- package/package.json +6 -3
- package/packaging/build.sh +4 -4
- package/packaging/install.sh +11 -0
- package/packaging/upgrade.sh +3 -0
- package/skills/ai-research/LICENSE +21 -0
- package/skills/design-contract/SKILL.md +27 -6
- package/skills/design-library/LICENSE +21 -0
- package/skills/harness/SKILL.md +2 -0
- package/skills/i-have-adhd/SKILL.md +10 -1
- package/skills/plan-add/SKILL.md +5 -1
- package/skills/plan-add/render_table.py +7 -0
- package/skills/pm-frameworks/LICENSE +21 -0
- package/skills/research/SKILL.md +22 -9
- package/skills/rl-env/LICENSE +201 -0
- package/skills/tezgah-contract/SKILL.md +21 -8
- package/statusline.py +20 -9
- package/third_party/open-code-review/LICENSE +201 -0
- package/third_party/open-code-review/README.md +15 -0
- package/third_party/open-code-review/prompts/main_task_system.md +26 -0
- package/third_party/open-code-review/prompts/review_filter_task_system.md +13 -0
- package/workflows/graph-map.js +14 -5
- package/workflows/graph-review.js +14 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,504 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.14.0] - 2026-11-01
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **The gate reads hook skips behind wrappers (plan 147).** It refuses a hook
|
|
14
|
+
skip behind a wrapper with arguments (`nice -n 5`, `timeout 60`). That covers
|
|
15
|
+
long value options, option clusters and `env -S`. It also refuses one inside
|
|
16
|
+
`eval`, `eval --` or `builtin eval`. One wrapper reader serves three rules:
|
|
17
|
+
shortcut, control and `VERIFY`. So a wrapped check meets the neuter and piped
|
|
18
|
+
refusals. A check piped into `rg`, `awk`, `sort`, `cat`, `less`, `sed` or
|
|
19
|
+
`tee` meets a refusal too. A trap other than plain cleanup on exit records
|
|
20
|
+
the check as ran, never as passed.
|
|
21
|
+
|
|
22
|
+
- **The gate closes control-plane, credit, language and credential bypasses
|
|
23
|
+
(plan 148).** Git config hooks settings meet a refusal: `core.hooksPath`,
|
|
24
|
+
`include.path`, `includeIf` and worktree config. The gate reads them in a
|
|
25
|
+
file, in `git config`, in `--file` and in `-c`. It refuses credits through `--trailer`, a git
|
|
26
|
+
path or `bash -c`. It refuses non-English names from `git worktree add -b`,
|
|
27
|
+
`git branch -m`, `gh -t`, `git tag` and push refspecs. It refuses credential
|
|
28
|
+
files staged by `git stage`, `git commit <path>` or `update-index --add`. It
|
|
29
|
+
refuses `ditto`, `mkfifo` and `${VAR:-…}` into the control plane. It refuses
|
|
30
|
+
MCP writes, moves and deletes into protected paths. It refuses a write racing
|
|
31
|
+
another session's in-flight write.
|
|
32
|
+
|
|
33
|
+
- **opencode sends shell writes to the core gate first (plan 149).** Every shell
|
|
34
|
+
write, swallowed check and hook-skipping line goes to the core gate. It gets
|
|
35
|
+
the core control, credential, workspace and shortcut refusals verbatim. A
|
|
36
|
+
refusal the plugin decides itself writes the `began` row the core writes.
|
|
37
|
+
`TEZGAH_HOME` is no longer exported.
|
|
38
|
+
|
|
39
|
+
- **The Stop rule reads more claim shapes (plan 150).** An empty Claude Bash
|
|
40
|
+
result is no pass. English past-tense and bare test claims and "not
|
|
41
|
+
tested/checked" admissions read like their Turkish twins. Prose-only and
|
|
42
|
+
benchmark claim reads honour the question and negation window. A plan claim
|
|
43
|
+
records as a claim. A subagent brief authorizes no switch.
|
|
44
|
+
|
|
45
|
+
- **Uninstall restores what the install found (plans 151, 152, 154).** Every
|
|
46
|
+
key and file goes back to its pre-install state. That covers your statusLine,
|
|
47
|
+
opencode compaction, omp codegraph row and `{}` settings files. It covers the
|
|
48
|
+
no-attribution values of Copilot, Command Code, Amp and Droid, and JSON
|
|
49
|
+
indent. It removes the directories tezgah created. It counts only tezgah's
|
|
50
|
+
own markers as leftovers. A partial uninstall keeps the farm the still-armed
|
|
51
|
+
hosts run from. A HOME behind a symlink no longer leaves
|
|
52
|
+
`~/.codex/bin/consult`.
|
|
53
|
+
|
|
54
|
+
- **Install names a host file it cannot read (plan 152).** Such a host rules or
|
|
55
|
+
settings file makes install exit 1. It no longer overwrites that file or
|
|
56
|
+
crashes. Install skips a commented host settings file with exit 0 and names it.
|
|
57
|
+
|
|
58
|
+
- **omp gates MCP device writes and `ast_edit` (plan 153).** An MCP device write
|
|
59
|
+
(`xd://mcp__…`) and `ast_edit` reach the gate as the calls they carry. The
|
|
60
|
+
device write itself meets the gate too. A glob or directory edit target takes the
|
|
61
|
+
control state it reaches. An MCP query records as external, not an edit.
|
|
62
|
+
|
|
63
|
+
- **`--uninstall` fails while anything tezgah wrote survives (plan 154).** It
|
|
64
|
+
exits 1 in that case. The farm carries `tezgah-optimize` and `tezgah-taste`.
|
|
65
|
+
Install refuses abbreviated flags. Piped `--upgrade` output reads in order.
|
|
66
|
+
Install names an unwritable HOME instead of printing a traceback. It refuses
|
|
67
|
+
Python below 3.10 early and names the version found.
|
|
68
|
+
|
|
69
|
+
- **The npm package and the READMEs match what ships (plan 156).** The package
|
|
70
|
+
ships NOTICE and the open-code-review prompts and no `__pycache__`. Every
|
|
71
|
+
vendored skill tree carries its upstream LICENSE. package.json and all five
|
|
72
|
+
READMEs name the fourteen hosts and the 17 refusal rules plus the nudge. They
|
|
73
|
+
also name the 17 rule switches and the current state of the Turkish claim
|
|
74
|
+
reader.
|
|
75
|
+
|
|
76
|
+
- **Farm CLIs answer help (plan 158).** They answer `-h/--help` with exit 0 and
|
|
77
|
+
refuse unknown flags. The `consult` CLI no longer sends a mistyped flag to the
|
|
78
|
+
panel. `tezgah-research check --json` prints pure JSON. `tezgah-status
|
|
79
|
+
--observable=` refuses an unknown measure.
|
|
80
|
+
|
|
81
|
+
- **Build and upgrade scripts fail clearly (plan 159).** `build.sh` without
|
|
82
|
+
`--version` names the artifact after the newest release heading instead of
|
|
83
|
+
`Unreleased`. `upgrade.sh` stops early with a clear message when `curl` or
|
|
84
|
+
`tar` is missing. The Windows CI leg checks that `install.ps1` refuses a
|
|
85
|
+
tampered artifact.
|
|
86
|
+
|
|
87
|
+
- **The graph-map workflow names a failed agent (plan 160).** A failed survey,
|
|
88
|
+
module reader, synthesize or gap-check agent lands in an `unknown` list. It is
|
|
89
|
+
no longer reported as an empty, clean result.
|
|
90
|
+
|
|
91
|
+
- **Subagents read the parent's switches (plan 165).** A subagent latches kill
|
|
92
|
+
switches on its parent's first ledger row when that came first. Every adapter
|
|
93
|
+
takes the parent from the host, the omp and Amp bridges and the opencode
|
|
94
|
+
plugin included. A switch the parent made mid-session no longer disarms rules
|
|
95
|
+
in subagents it spawns later.
|
|
96
|
+
|
|
97
|
+
- **The design chain reaches real UI work (plan 144).** `uygulamayı redesign et`
|
|
98
|
+
arms the design rule, and the frozen arming corpus stays the same. A
|
|
99
|
+
route-file write (`src/app/dashboard/page.tsx`, `src/routes/+page.svelte`)
|
|
100
|
+
owes the design check. `tezgah-design derive` reads a nested Tailwind palette
|
|
101
|
+
(`brand: {50..900}`) and every config in a monorepo, not only the first.
|
|
102
|
+
|
|
103
|
+
- **The citation ratchet holds in every checkout (plan 168).** `bin/tezgah-docs
|
|
104
|
+
--citations` never judges a path under the private `.tezgah/`. The unjudged
|
|
105
|
+
ratchet now holds the same in CI, worktrees and the main checkout.
|
|
106
|
+
|
|
107
|
+
### Added
|
|
108
|
+
|
|
109
|
+
- **`derive` reads JS/TS theme modules (plan 145).** A repository whose only
|
|
110
|
+
token source is a module such as `src/config/theme.ts` now derives a contract.
|
|
111
|
+
It carries `source: theme-module` with its colours, spacing unit and type
|
|
112
|
+
scale. `read_text` opens each path component with `O_NOFOLLOW` under the
|
|
113
|
+
repository root. It refuses a parent swapped for a symlink.
|
|
114
|
+
|
|
115
|
+
- **`derive --suggest` prints a candidate component inventory (plan 146).** It
|
|
116
|
+
lists `{name, kind}` candidates read off component files and writes nothing.
|
|
117
|
+
It skips tests, stories and names already in the contract. It guesses `kind`
|
|
118
|
+
only from the name and exits 2 when there is no candidate. A person adds the
|
|
119
|
+
ones the repository owns.
|
|
120
|
+
|
|
121
|
+
- **`tezgah-docs --citations` judges more citation shapes (plan 166).** It
|
|
122
|
+
judges bare `(N-M)` and `:N-M` ranges after a cited path, and JS/TS top-level
|
|
123
|
+
symbols. It flags ranges past a file end. Stale opencode plugin citations are
|
|
124
|
+
re-anchored by symbol.
|
|
125
|
+
|
|
126
|
+
### Changed
|
|
127
|
+
|
|
128
|
+
- **Two sessions meet on their first write of one file (plan 171).** The race
|
|
129
|
+
rule counts another session's unanswered write for 60 seconds. After that it
|
|
130
|
+
counts only if that host answers its writes. A refused prompt holds the file
|
|
131
|
+
about a minute.
|
|
132
|
+
|
|
133
|
+
- **The gate parses a command once per call (plan 169).** Its readers share
|
|
134
|
+
one parse of a command's heredocs and shell commands. Median gate latency is
|
|
135
|
+
back at the 1.13.0 figure.
|
|
136
|
+
|
|
137
|
+
- **Docs match the code again (plan 161).** The hosts, operations, skills,
|
|
138
|
+
research and testing pages document the tezgah-mcp tools and tezgah-decisions.
|
|
139
|
+
They list the omp events and the opencode `event` hook. They state that
|
|
140
|
+
`--install --dry-run` writes. Live probes no longer read as host obedience.
|
|
141
|
+
Drifted citations now name their symbol. tests/test_docs_reach.py keeps them
|
|
142
|
+
in step.
|
|
143
|
+
|
|
144
|
+
- **Ledger rows carry their version (plan 162).** Snapshot and rollback rows now
|
|
145
|
+
carry the row version `v`. The evidence page (`docs/evidence.md`) lists every
|
|
146
|
+
ledger kind, all optional fields and every `subagent_end` writer. It also
|
|
147
|
+
lists the exact prose-exemption names, and a new test checks it.
|
|
148
|
+
|
|
149
|
+
- **docs/contract.md and docs/environment.md match the code (plan 157).** They
|
|
150
|
+
cover the switch table, every environment variable read, budgets, DROP_ORDER
|
|
151
|
+
and the label-anchored composition order. The core and the reminder name the
|
|
152
|
+
kill-switch directory from XDG_CONFIG_HOME. The Ponytail Off line names its
|
|
153
|
+
switches. The suite never runs a real gh on upgrade.
|
|
154
|
+
|
|
155
|
+
- **Status-line marks and docs are complete (plan 163).** `python3
|
|
156
|
+
bin/tezgah-docs` and `python3 bin/tezgah-research` earn the judge and research
|
|
157
|
+
marks. The legend and docs name every host that cannot observe skill reads.
|
|
158
|
+
docs/status-line.md documents the extension `{"segments": [...]}` output and
|
|
159
|
+
an unknown `--observable` measure exiting 2. `/tezgah:adhd` states `on` as the
|
|
160
|
+
default.
|
|
161
|
+
|
|
162
|
+
- **`reminder-off` drops only the per-turn reminder line (plan 164).** Armed
|
|
163
|
+
rules, the gate-inactive notice and the off-note stay. Kill-switch off-notes
|
|
164
|
+
also name the matching section of the `tezgah` output style.
|
|
165
|
+
|
|
166
|
+
- **The impacted test map covers docs pages (plan 167).** tests/impacted.py runs
|
|
167
|
+
tests/test_docs_reach.py for docs/ page changes. It maps the omp status-line
|
|
168
|
+
e2e by the generic helper rule. The research seal test parses `check --json`
|
|
169
|
+
stdout as pure JSON.
|
|
170
|
+
|
|
171
|
+
- **Neuter rows for the audit guards (plan 155).** The neuter matrix gains 59
|
|
172
|
+
rows. Each guard the audit fixes added has one, with a behavioural killer.
|
|
173
|
+
It writes its killer cache only with `--update-killers`.
|
|
174
|
+
It answers `--help`. It runs on a push touching any mutated file. Gate vectors
|
|
175
|
+
cover every refusal rule: stateless ones by vector, stateful ones by named
|
|
176
|
+
tests.
|
|
177
|
+
|
|
178
|
+
## [1.13.0] - 2026-10-29
|
|
179
|
+
|
|
180
|
+
### Fixed
|
|
181
|
+
|
|
182
|
+
- **omp handed the Stop rule a message object, not the reply (plan 143).**
|
|
183
|
+
omp's `session_stop` carries `last_assistant_message` as the object its
|
|
184
|
+
`getLastAssistantMessage()` returns. The bridge passed it through, so the
|
|
185
|
+
rule judged `str(dict)`: one line, no list items, diluted prose.
|
|
186
|
+
- Every line-shaped class read a text with no lines: the list cap, the
|
|
187
|
+
residual sections, the question the reply ends on, the handed step. The
|
|
188
|
+
language check read a share that was not the reply's.
|
|
189
|
+
- Measured on the owner's evidence database: 1643 of 1656 omp `shape` rows
|
|
190
|
+
of 45 days carried `lines: 1`. Every other host wrote 209 multi-line of
|
|
191
|
+
231. Of three days' refusals, 24 were `reply language` over such a row.
|
|
192
|
+
- `stop_reason` reads every reply through `reply_prose` now, so no host can
|
|
193
|
+
repeat it. The omp bridge sends the text blocks.
|
|
194
|
+
|
|
195
|
+
### Added
|
|
196
|
+
|
|
197
|
+
- **The Stop rule knows the host's plan mode (plan 142).** Every Stop adapter
|
|
198
|
+
passes the host's `permission_mode` to the core now. omp's extension sends
|
|
199
|
+
`plan` from `ctx.sessionModes.getState()`. `plan` and Droid's `spec` are the
|
|
200
|
+
read-only ones.
|
|
201
|
+
- In such a turn the rule lets the approval question through. It used to
|
|
202
|
+
refuse it as a `needless ask` - the one question that mode allows.
|
|
203
|
+
- A first-person claim that a command or check ran, made in such a turn, is
|
|
204
|
+
the new `plan claim` class. Nothing could run, so the claim says what
|
|
205
|
+
cannot have happened. A check that passed anyway clears it, and a plan's
|
|
206
|
+
own acceptance line ("Done when all tests pass") is no claim.
|
|
207
|
+
- The new `handed step` class refuses a reply that tells the reader to run a
|
|
208
|
+
command. It asks only of a turn that ran commands of its own, outside plan
|
|
209
|
+
mode. An outward step, one no default may take, the owner's consent,
|
|
210
|
+
tezgah's own install and a `brew` step stay the user's. So does a line that
|
|
211
|
+
types its blocker, and an answer about how a command is run.
|
|
212
|
+
- Measured on the owner's transcripts: of 3307 user turns, 27 replies handed
|
|
213
|
+
back a command and no class refused any of them. The shipped shapes refuse
|
|
214
|
+
9 turns, 8 of them a step the session could have taken.
|
|
215
|
+
|
|
216
|
+
## [1.12.0] - 2026-10-29
|
|
217
|
+
|
|
218
|
+
### Added
|
|
219
|
+
|
|
220
|
+
- **Amp is a host (`amp`, plan 140).** `tezgah-setup --install --hosts amp`
|
|
221
|
+
writes one TypeScript plugin, `tezgah.ts`, into Amp's system plugin dir.
|
|
222
|
+
That dir is `$XDG_CONFIG_HOME/amp/plugins/`, else `~/.config/amp/plugins/`.
|
|
223
|
+
The install renders it from `hosts/amp/tezgah-plugin.ts.in`. Amp loads every
|
|
224
|
+
`.ts` there, and a running Amp needs `plugins: reload`. The install links the
|
|
225
|
+
skills into `~/.config/amp/skills` and writes the always-on block into
|
|
226
|
+
`~/.config/amp/AGENTS.md`. It sets Amp's two commit trailers
|
|
227
|
+
(`amp.git.commit.coauthor.enabled`, `amp.git.commit.ampThread.enabled`) to
|
|
228
|
+
false in `settings.json` unless the user set them. It writes that file only
|
|
229
|
+
while it is plain JSON with no `settings.jsonc` beside it. The uninstall
|
|
230
|
+
removes the plugin only when it is tezgah's render. It drops a trailer key
|
|
231
|
+
only while that key is still false.
|
|
232
|
+
- The plugin spawns `hosts/amp/hook.py` without blocking. One plugin process
|
|
233
|
+
serves many threads, so it keys its state by thread id. A dead, slow or
|
|
234
|
+
crashing hook allows every call, and the plugin tells each thread once.
|
|
235
|
+
- `tool.call` refuses with `{action: "reject-and-continue"}`. It asks the gate
|
|
236
|
+
for `Bash`, `shell_command`, the edit tools, `Task` and MCP effect names. A
|
|
237
|
+
shell call's text reaches the gate as `command`, also when Amp sends `cmd`.
|
|
238
|
+
- A tool result counts as passed only with an integer `exitCode` on its
|
|
239
|
+
output object. `error` and `cancelled` are failures. A bare `done` shell
|
|
240
|
+
result is a run, never a pass.
|
|
241
|
+
- `agent.end` judges a `done` turn and continues it with `[tezgah:stop]
|
|
242
|
+
<reason>`. The plugin never sends that prompt as the user's. So it writes no
|
|
243
|
+
turn row, grants nothing and cannot reset the re-ask budget. A thread with
|
|
244
|
+
a parent thread is a subagent. It gets the subagent brief, and its end is a
|
|
245
|
+
record-only row.
|
|
246
|
+
- The session brief rides the thread's first `agent.start`. The status line
|
|
247
|
+
goes on Amp's experimental status item for the active thread.
|
|
248
|
+
- `--report` has Amp rows. `--report --live` loads the plugin with node and
|
|
249
|
+
drives its `tool.call` and `tool.result`. The row stays UNVERIFIED, since
|
|
250
|
+
Amp's own loader did not run it. `tezgah-doctor --stack` reads Amp's
|
|
251
|
+
guidance files, skills, plugins and `amp.mcpServers`. `read_web_page` is a
|
|
252
|
+
web channel for the untrusted label. README and docs name all fourteen
|
|
253
|
+
hosts.
|
|
254
|
+
- **Goose is a host (`goose`, plan 139 slice 5).** `tezgah-setup --install
|
|
255
|
+
--hosts goose` writes tezgah's own plugin dir, `~/.agents/plugins/tezgah/`.
|
|
256
|
+
It holds `plugin.json`, `hooks/hooks.json` and `skills/` links, and it is
|
|
257
|
+
wholly tezgah's. Goose loads the skills as `tezgah:<skill>`. The timeouts are in seconds: Stop 30, the
|
|
258
|
+
rest 5. `on_failure` stays at Goose's default `allow`, so the gate fails open
|
|
259
|
+
on a hook fault. The always-on block goes in `~/.config/goose/.goosehints`.
|
|
260
|
+
Goose adds no co-author trailer and names no setting for one, so there is
|
|
261
|
+
nothing to turn off. The uninstall deletes the plugin dir and the block and
|
|
262
|
+
leaves the rest of `~/.agents` alone.
|
|
263
|
+
- `hosts/goose/hook.py` handles SessionStart (attestation only),
|
|
264
|
+
UserPromptSubmit (the turn row only), PreToolUse, PostToolUse,
|
|
265
|
+
PostToolUseFailure and Stop. The event is the payload's `event`, the cwd its
|
|
266
|
+
`working_dir`, else the hook's own. `shell`, `write` and `edit` map to Bash,
|
|
267
|
+
Write and Edit, with `path` as `file_path` and `before`/`after` as
|
|
268
|
+
`old_string`/`new_string`. `<extension>__<tool>` becomes
|
|
269
|
+
`mcp__<extension>__<tool>`.
|
|
270
|
+
- PreToolUse and Stop block with `{"decision": "block", "reason": ...}` on
|
|
271
|
+
stdout. The outcome is the event: PostToolUse is a pass, PostToolUseFailure
|
|
272
|
+
a failure. Stop judges `last_assistant_message`, or writes a
|
|
273
|
+
`reply_unread` row. With no host block count, the turn rows bound the
|
|
274
|
+
re-asks.
|
|
275
|
+
- `--report` has Goose rows, including one for `disabledPlugins`. `--report
|
|
276
|
+
--live` probes the hook command with Goose's payload and block shape.
|
|
277
|
+
`tezgah-doctor --stack` reads Goose's hints, skills, plugins and the
|
|
278
|
+
`extensions:` map of `config.yaml`. No run has shown the binary obeying the
|
|
279
|
+
block. README and docs/layers.md now name all thirteen hosts.
|
|
280
|
+
- **Antigravity CLI is a host (`antigravity`, plan 139 slice 4).**
|
|
281
|
+
`tezgah-setup --install --hosts antigravity` writes tezgah's hook set under
|
|
282
|
+
the `tezgah` name of `~/.gemini/config/hooks.json`. The user's other names
|
|
283
|
+
stay. The Antigravity App and IDE load that file too. The timeouts are in
|
|
284
|
+
seconds: Stop 30, the rest 5. The status line goes in
|
|
285
|
+
`~/.gemini/antigravity-cli/settings.json` while it is plain JSON, and the skill
|
|
286
|
+
links go in `antigravity-cli/skills`. Antigravity adds no co-author
|
|
287
|
+
trailer of its own, so there is nothing to turn off. The always-on block is
|
|
288
|
+
the `~/.gemini/GEMINI.md` one Gemini CLI shares. An uninstall now keeps it only
|
|
289
|
+
while another armed host reads the same file, so with `GEMINI_CLI_HOME` set
|
|
290
|
+
the two blocks come and go apart.
|
|
291
|
+
- `hosts/antigravity/hook.py` handles SessionStart, PreInvocation,
|
|
292
|
+
PreToolUse, PostToolUse and Stop. The payload names no event, so each
|
|
293
|
+
command passes it as its first argument. `conversationId` is the session
|
|
294
|
+
and `workspacePaths[0]` the cwd. The adapter renames the PascalCase tool
|
|
295
|
+
arguments into the gate's fields: `CommandLine`, `TargetFile`, `CodeContent`,
|
|
296
|
+
`TargetContent`/`ReplacementContent` and `ReplacementChunks`.
|
|
297
|
+
- PreToolUse denies with a top-level `decision: deny`. An allowed call
|
|
298
|
+
answers `decision: allow`, since Antigravity requires the field. PostToolUse reads
|
|
299
|
+
the outcome off `error`: empty is a pass, anything else a failure. The first
|
|
300
|
+
invocation of a turn writes the turn row and carries the reminder as an
|
|
301
|
+
`ephemeralMessage`. A loop that a refusal re-entered writes no turn row, so
|
|
302
|
+
the refusal budget holds.
|
|
303
|
+
- Stop reads the reply from `transcriptPath`, or writes a `reply_unread` row.
|
|
304
|
+
It judges only an idle `model_stop`, and `decision: continue` sends the
|
|
305
|
+
model back into the loop with the reason.
|
|
306
|
+
- `--report` has Antigravity rows, including one for `enabled: false` on the
|
|
307
|
+
`tezgah` name. `--report --live` probes the hook command with Antigravity's
|
|
308
|
+
camelCase payload and deny shape. No run has shown the binary obeying the
|
|
309
|
+
deny.
|
|
310
|
+
- **Gemini CLI is a host (`gemini`, plan 139 slice 3).** `tezgah-setup
|
|
311
|
+
--install --hosts gemini` writes tezgah's own extension dir,
|
|
312
|
+
`~/.gemini/extensions/tezgah/`. It holds `gemini-extension.json`,
|
|
313
|
+
`hooks/hooks.json` and links to the skills.
|
|
314
|
+
`GEMINI_CLI_HOME` moves `~/.gemini` under it. The timeouts are in
|
|
315
|
+
milliseconds: AfterAgent 30000, the rest 5000. settings.json is never
|
|
316
|
+
written, since it is JSON with comments and holds the user's keys. Gemini's
|
|
317
|
+
default prompt adds no co-author trailer and no setting names one. The
|
|
318
|
+
always-on block goes in `~/.gemini/GEMINI.md`, which Antigravity reads too.
|
|
319
|
+
`--uninstall` deletes the extension dir and strips the block only while no
|
|
320
|
+
other host that reads it stays armed.
|
|
321
|
+
- `hosts/gemini/hook.py` handles SessionStart, BeforeAgent, BeforeTool,
|
|
322
|
+
AfterTool and AfterAgent. BeforeAgent writes the turn row and carries the
|
|
323
|
+
per-turn reminder. BeforeTool maps `run_shell_command`, `write_file`,
|
|
324
|
+
`replace`, the grep tools and the subagent tools into the gate's names, and
|
|
325
|
+
`mcp_<server>_<tool>` into `mcp__<server>_<tool>`. It denies with a
|
|
326
|
+
top-level `decision: deny` on exit 0.
|
|
327
|
+
- AfterTool reads the outcome off `tool_response`: an `error` is a failure,
|
|
328
|
+
and a shell result's `Exit Code: N` names a non-zero code. A shell run that
|
|
329
|
+
printed its `Output:` with no exit-code line is a pass, since Gemini writes
|
|
330
|
+
that line only for a non-zero code. AfterAgent judges `prompt_response` and
|
|
331
|
+
denies with `decision: deny`. Gemini sends the reason back through
|
|
332
|
+
BeforeAgent as the next prompt, and that turn row does not reset the
|
|
333
|
+
refusal budget. The status segment rides `systemMessage`.
|
|
334
|
+
- `--report` has Gemini rows, including one for `hooksConfig.enabled: false`
|
|
335
|
+
in settings.json, which runs no hook at all. `--report --live` probes the
|
|
336
|
+
hook command with Gemini's own payload and deny shape. No run has shown the
|
|
337
|
+
binary loading the extension or obeying the deny.
|
|
338
|
+
- **GitHub Copilot CLI is a host (`copilot`, plan 139 slice 2).** `tezgah-setup
|
|
339
|
+
--install --hosts copilot` writes `$COPILOT_HOME/hooks/tezgah.json`, a hooks
|
|
340
|
+
file that is wholly tezgah's. `COPILOT_HOME` defaults to `~/.copilot`. The
|
|
341
|
+
timeouts are in seconds: PreToolUse 10, Stop and SubagentStop 30, the rest 5.
|
|
342
|
+
The inline `hooks` key of settings.json is never used, since one bad item
|
|
343
|
+
there rejects every hook in it. The install sets two keys in settings.json
|
|
344
|
+
while it is plain JSON. The status line runs `tezgah-statusline --copilot`.
|
|
345
|
+
`includeCoAuthoredBy` is `false`, so the agent's commits carry no co-author
|
|
346
|
+
trailer. A value the user set stays. The install links the skills into
|
|
347
|
+
`$COPILOT_HOME/skills` and writes the always-on block in
|
|
348
|
+
`copilot-instructions.md`. `--uninstall` deletes tezgah.json and takes back
|
|
349
|
+
only tezgah's settings keys, links and block.
|
|
350
|
+
- `hosts/copilot/hook.py` uses the PascalCase events, so payloads carry
|
|
351
|
+
snake_case fields and Claude tool names. It maps the runtime spellings too.
|
|
352
|
+
An Edit that names no file but carries a patch reaches the gate as
|
|
353
|
+
`apply_patch`. An MCP tool's `<server>-<tool>` becomes
|
|
354
|
+
`mcp__<server>__<tool>` for a server `mcp-config.json` names. It denies
|
|
355
|
+
with a top-level `permissionDecision: deny` on exit 0.
|
|
356
|
+
- A PreToolUse hook that times out lets the call through, by Copilot's own
|
|
357
|
+
rule. One that crashes denies the call. A repo's `.claude/settings.json`
|
|
358
|
+
hooks run there too.
|
|
359
|
+
- PostToolUse records a pass and PostToolUseFailure a failure. A shell
|
|
360
|
+
result's `exit code N` overrides either. Stop carries no reply, so the hook
|
|
361
|
+
reads the last `assistant.message` from `transcript_path`. A turn end with
|
|
362
|
+
none there becomes a `reply_unread` row. Copilot drops a command hook's
|
|
363
|
+
UserPromptSubmit output, so there is no per-turn reminder. The event still
|
|
364
|
+
writes the turn row. subagentStart gives a delegate the brief. A
|
|
365
|
+
SubagentStop only records its verdict.
|
|
366
|
+
- `--report` has Copilot rows, and `--report --live` probes the hook command
|
|
367
|
+
with Copilot's own payload and deny shape. No run has shown the binary
|
|
368
|
+
obeying the deny.
|
|
369
|
+
- **Command Code is a host (`commandcode`, plan 139 slice 1).** `tezgah-setup
|
|
370
|
+
--install --hosts commandcode` merges tezgah's hook groups into the `hooks`
|
|
371
|
+
key of `~/.commandcode/settings.json` beside the user's. Their timeouts are in
|
|
372
|
+
seconds. The same write sets `attribution.commit` to `""`, so commits carry no
|
|
373
|
+
`CommandCodeBot` co-author trailer. A value the user set stays. The install
|
|
374
|
+
links the skills into `~/.commandcode/skills`. It writes the always-on block
|
|
375
|
+
in `~/.commandcode/AGENTS.md`. `--uninstall` takes back only tezgah's groups,
|
|
376
|
+
links and block. It drops the attribution key only while it holds what the
|
|
377
|
+
install wrote.
|
|
378
|
+
- Command Code's settings hooks see only shell, read, write and edit. So the
|
|
379
|
+
PreToolUse matcher is `shell|write|edit`. The gate there never sees read,
|
|
380
|
+
MCP, subagent or web calls, and plan mode skips every hook.
|
|
381
|
+
- `hosts/commandcode/hook.py` maps `shell_command`, `write_file` and
|
|
382
|
+
`edit_file` onto the gate. It folds a shell call's `args` into `command`.
|
|
383
|
+
It hands `old_value`/`new_value` over as `old_string`/`new_string`. It
|
|
384
|
+
denies with `permissionDecision: deny` on exit 0. It reads a shell call's
|
|
385
|
+
outcome off an `exit code N` in its result. A result with no code counts
|
|
386
|
+
as a run, never a pass.
|
|
387
|
+
- Stop carries no reply, so the hook reads it from `transcript_path`. A turn
|
|
388
|
+
end with none there becomes a `reply_unread` row. The status segment rides
|
|
389
|
+
`systemMessage` at SessionStart and Stop. There is no prompt event, so no
|
|
390
|
+
per-turn reminder.
|
|
391
|
+
- `--report` has Command Code rows, and `--report --live` probes the hook
|
|
392
|
+
command with Command Code's own payload. No run has shown the binary
|
|
393
|
+
obeying the deny.
|
|
394
|
+
- **Factory Droid is a host (`droid`, plan 138 wave 1).** `tezgah-setup --install
|
|
395
|
+
--hosts droid` merges tezgah's hook groups into `~/.factory/hooks.json` beside
|
|
396
|
+
the user's. Their timeouts are in seconds, as Droid reads them. The install
|
|
397
|
+
also links the skills into `~/.factory/skills` beside the user's own links.
|
|
398
|
+
It writes the always-on block in `~/.factory/AGENTS.md`. It sets the
|
|
399
|
+
`statusLine` command and `includeCoAuthoredByDroid: false` in `settings.json`.
|
|
400
|
+
The install edits a settings.json with comments in place and keeps its
|
|
401
|
+
comments (plan 141). `--uninstall` takes back only tezgah's groups, links and keys.
|
|
402
|
+
- Droid reads the `hooks` key of settings.json only while hooks.json is
|
|
403
|
+
absent. So the install creates no hooks.json beside such a key, and the
|
|
404
|
+
report row says why. Then settings.json stays untouched.
|
|
405
|
+
- `hosts/droid/hook.py` maps Droid's tool ids (`Execute`, `Create`,
|
|
406
|
+
`ApplyPatch`, `FetchUrl`) onto the gate and hands ApplyPatch's `input` over
|
|
407
|
+
as `patch`. It denies with `permissionDecision: deny` on exit 0 and reads a
|
|
408
|
+
shell call's outcome off its `[Process exited with code N]` line.
|
|
409
|
+
- Droid's Stop carries no reply, so the hook reads the reply from
|
|
410
|
+
`transcript_path`. A turn end whose reply is not there yet becomes a
|
|
411
|
+
`reply_unread` row and is not judged. SubagentStop records `task_result`
|
|
412
|
+
as a `subagent_end` row.
|
|
413
|
+
- `--report` has Droid rows, and `--report --live` probes the hook command
|
|
414
|
+
with Droid's own payload. `tests/e2e_droid.py` runs the real binary only
|
|
415
|
+
under `TEZGAH_E2E_SPEND=1`, because it spends a model call.
|
|
416
|
+
|
|
417
|
+
- **Qwen Code is a host (`qwen`, plan 138 wave 1).** `tezgah-setup --install
|
|
418
|
+
--hosts qwen` merges tezgah's hook groups into `~/.qwen/settings.json` beside
|
|
419
|
+
Orca's. Their timeouts are in milliseconds, as Qwen reads them. The install
|
|
420
|
+
also adds the `ui.statusLine` command, the skill links and the always-on
|
|
421
|
+
block in `~/.qwen/QWEN.md`. `--uninstall` takes back only tezgah's groups and keys.
|
|
422
|
+
- `hosts/qwen/hook.py` maps Qwen's tool ids (`run_shell_command`,
|
|
423
|
+
`write_file`, `edit`, `agent`, `grep_search`) onto the gate. It denies with
|
|
424
|
+
`permissionDecision: deny` on exit 0, blocks Stop on
|
|
425
|
+
`last_assistant_message`, briefs a subagent at SubagentStart and records
|
|
426
|
+
its end at SubagentStop.
|
|
427
|
+
- `--report` has Qwen rows, and `--report --live` probes the hook command
|
|
428
|
+
with Qwen's own payload. `tests/e2e_qwen.py` runs the real binary only
|
|
429
|
+
under `TEZGAH_E2E_SPEND=1`, because it spends a model call.
|
|
430
|
+
- `tezgah-doctor --stack` and the session attestation know the host. An
|
|
431
|
+
unknown host no longer crashes the attestation.
|
|
432
|
+
- A host-file backup is now owner-only, and a rewritten host config keeps
|
|
433
|
+
its file mode, because Qwen's settings.json holds provider keys.
|
|
434
|
+
|
|
435
|
+
- **Review rules taken from google/elephant-goldfish-model (plan 137).** The
|
|
436
|
+
owner chose them from research line `egm-lessons`. No EGM file ships:
|
|
437
|
+
- `tezgah-task review NNN <r> approve` refuses a plan with no review slice
|
|
438
|
+
record. A host with no slice journal passes `--no-slice "<why>"`, and the
|
|
439
|
+
reason lands on the review line (`bin/tezgah-task`).
|
|
440
|
+
- The contract says that no fresh subagent means no review verdict. It also
|
|
441
|
+
says the author contests a finding only with a file:line and never lowers
|
|
442
|
+
a severity (`hooks/tezgah_policy.py`).
|
|
443
|
+
- tezgah-reviewer has a plan-readiness mode for a plan file. A design choice
|
|
444
|
+
left to the implementer is a major finding, and so is a section it cannot
|
|
445
|
+
paraphrase. plan-add runs it before `phase implementation`
|
|
446
|
+
(`hooks/tezgah_agents.py`).
|
|
447
|
+
- graph-review merges findings with the same file, line and title before its
|
|
448
|
+
verification cap, and reports `caps.deduplicated`.
|
|
449
|
+
- `tests/test_links.py` resolves every relative markdown link the repository
|
|
450
|
+
owns.
|
|
451
|
+
|
|
452
|
+
### Changed
|
|
453
|
+
|
|
454
|
+
- **The gate refuses a credit verb with "with" or "using" too.** The attribution
|
|
455
|
+
rule read `written by` and `built by`, so `Drafted with Claude` passed. The
|
|
456
|
+
credit verbs now include `drafted`, `produced` and `composed`, and each takes
|
|
457
|
+
`by`, `with` or `using` before a model or vendor name. Prose such as
|
|
458
|
+
`drafted with the owner` still passes (`hooks/tezgah_gate.py::_CREDIT`, plan
|
|
459
|
+
137).
|
|
460
|
+
|
|
461
|
+
- **A release tag must sit on main.** A new `on-main` job in `release.yml`
|
|
462
|
+
fails the run on a tag off `origin/main`. Then no job builds or uploads
|
|
463
|
+
anything (plan 137).
|
|
464
|
+
|
|
465
|
+
- **An owner-only choice waits for the owner.** Class F now names three more
|
|
466
|
+
steps. One is picking a variant a research, analysis or review recommends.
|
|
467
|
+
The others are a way around a tezgah refusal and deciding about another
|
|
468
|
+
session's work. The core
|
|
469
|
+
Ask policy, the per-turn reminder and the ask warning carry them too. The Stop
|
|
470
|
+
rule's `needless ask` lets a question that asks the owner to pick between
|
|
471
|
+
options through (`OWNER_CHOICE`, `hooks/tezgah_integrity.py`). A worker returns
|
|
472
|
+
such a question as `ESCALATE: owner`, and the orchestrator relays it to the
|
|
473
|
+
user instead of answering it (plan 136).
|
|
474
|
+
|
|
475
|
+
- **A research line records the owner's pick apart from its own.** A rules-9
|
|
476
|
+
line writes its pick as `recommended:` in `decision.md`. A `chosen:` line
|
|
477
|
+
needs the owner's words, which `tezgah-research choose <slug> <decision>
|
|
478
|
+
<variant> --ack "<words>"` writes. The line's rules judge its own pick, never
|
|
479
|
+
the owner's, so an owner may take a dominated variant. `conclude` says when a
|
|
480
|
+
recommendation still waits for the owner (`hooks/tezgah_research.py`).
|
|
481
|
+
|
|
482
|
+
- **A line in flight no longer blocks `init --allow-open`.** A line whose only
|
|
483
|
+
`check` errors are pending verdicts is in flight, not broken. Both `init`
|
|
484
|
+
refusals now say that another session's line goes to the owner.
|
|
485
|
+
|
|
486
|
+
### Fixed
|
|
487
|
+
|
|
488
|
+
- **Three new hosts no longer record a check that did not pass as a pass.**
|
|
489
|
+
Antigravity's PostToolUse has no output. A command that went to the
|
|
490
|
+
background also ends with an empty `error`. So the hook records each
|
|
491
|
+
Antigravity shell call as ran, never a pass, and Antigravity can never show
|
|
492
|
+
a passing check. A Copilot shell success with no `exit code N` text (a
|
|
493
|
+
background launch) is ran, never a pass. A Gemini result with a `Signal:`
|
|
494
|
+
line (a runner killed by a signal) is a failure.
|
|
495
|
+
- **The gate guards Gemini's and Goose's hook-off keys.** These are Gemini's
|
|
496
|
+
`hooksConfig` and Goose's `disabledPlugins`. Claude's `disableAllHooks` had
|
|
497
|
+
the same guard.
|
|
498
|
+
- **The Command Code uninstall removes tezgah's `attribution.commit: ""`
|
|
499
|
+
beside the user's other attribution keys**, not only when it stood alone.
|
|
500
|
+
|
|
501
|
+
- **A hidden research dir is no longer invisible.** A dot dir under
|
|
502
|
+
`.tezgah/research/` is an error in `status` and in `check` with no slug. The
|
|
503
|
+
gate refuses a write there (`research_hidden_reason`, `hooks/tezgah_gate.py`).
|
|
504
|
+
A session had run a whole line under `.tezgah/research/.staging/` after an
|
|
505
|
+
`init` refusal.
|
|
506
|
+
|
|
9
507
|
## [1.11.0] - 2026-10-23
|
|
10
508
|
|
|
11
509
|
### Added
|
|
@@ -36,6 +534,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
36
534
|
|
|
37
535
|
- **A contract reads Hallmark's locked `design.md`, and one precedence table decides the floor.** A `design.md` or `DESIGN.md` at the repository root now feeds `derive`. It gives the palette and font roles, with `source: design-md`. The palette converts from OKLCH to the hex `check` compares. A token file beside it no longer competes. The contract gains a `precedence` block. It names `ours` (states, components, evidence, facts) and `theirs` (material, motion character). It names `shared` (contrast, focus-visible, reduced-motion, tap-target) and `verbatim: style`. `check` refuses with exit 2 a key named by two classes. It also refuses `facts` handed to a theme or to the user's own words.
|
|
38
536
|
|
|
537
|
+
- **`tezgah-ocr-review` runs open-code-review's loop on omp's model.** It reaches the model through a loopback shim.
|
|
538
|
+
|
|
539
|
+
- **`tezgah-review-quote` places review findings on the diff.** It finds each finding's location by the code it quotes.
|
|
540
|
+
|
|
39
541
|
|
|
40
542
|
### Changed
|
|
41
543
|
|
|
@@ -1299,7 +1801,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
1299
1801
|
the copy could not find `hooks/` and died on import. It now links into the
|
|
1300
1802
|
installed tree, and also installs the command as `tezgah`.
|
|
1301
1803
|
|
|
1302
|
-
[Unreleased]: https://github.com/r1z4x/tezgah/compare/v1.
|
|
1804
|
+
[Unreleased]: https://github.com/r1z4x/tezgah/compare/v1.14.0...HEAD
|
|
1805
|
+
[1.14.0]: https://github.com/r1z4x/tezgah/releases/tag/v1.14.0
|
|
1806
|
+
[1.13.0]: https://github.com/r1z4x/tezgah/releases/tag/v1.13.0
|
|
1807
|
+
[1.12.0]: https://github.com/r1z4x/tezgah/releases/tag/v1.12.0
|
|
1808
|
+
[1.11.0]: https://github.com/r1z4x/tezgah/releases/tag/v1.11.0
|
|
1303
1809
|
[1.10.1]: https://github.com/r1z4x/tezgah/releases/tag/v1.10.1
|
|
1304
1810
|
[1.10.0]: https://github.com/r1z4x/tezgah/releases/tag/v1.10.0
|
|
1305
1811
|
[1.9.2]: https://github.com/r1z4x/tezgah/releases/tag/v1.9.2
|