@r1z4x/tezgah 1.0.0 → 1.1.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/MANIFEST +8 -0
- package/bin/tezgah-agents +10 -1
- package/bin/tezgah-docs +1 -1
- package/bin/tezgah-doctor +11 -0
- package/bin/tezgah-research +31 -14
- package/bin/tezgah-setup +154 -29
- package/bin/tezgah-skill +59 -0
- package/bin/tezgah-skill.py +59 -0
- package/bin/tezgah-status +62 -1
- package/bin/tezgah-triage +5 -3
- package/docs/README.md +1 -0
- package/docs/architecture.md +5 -2
- package/docs/citations-baseline.json +1 -1
- package/docs/clarity-baseline.json +9 -9
- package/docs/contract.md +68 -26
- package/docs/environment.md +6 -3
- package/docs/evidence.md +7 -0
- package/docs/gate.md +13 -7
- package/docs/glossary.md +1 -1
- package/docs/hosts.md +48 -1
- package/docs/index.json +29 -1
- package/docs/judge.md +61 -55
- package/docs/models.md +14 -8
- package/docs/operations.md +10 -5
- package/docs/orca.md +126 -0
- package/docs/research.md +38 -3
- package/docs/skills.md +74 -0
- package/docs/status-line.md +3 -1
- package/docs/testing.md +33 -21
- package/docs/vision.md +12 -8
- package/hooks/projects-pretooluse.py +17 -5
- package/hooks/tezgah_agents.py +135 -13
- package/hooks/tezgah_components.py +3 -0
- package/hooks/tezgah_context.py +65 -22
- package/hooks/tezgah_gate.py +133 -17
- package/hooks/tezgah_integrity.py +60 -13
- package/hooks/tezgah_judge.py +239 -56
- package/hooks/tezgah_models.py +41 -5
- package/hooks/tezgah_orca.py +144 -0
- package/hooks/tezgah_paths.py +40 -6
- package/hooks/tezgah_policy.py +109 -35
- package/hooks/tezgah_research.py +104 -8
- package/hooks/tezgah_skill_pick.py +459 -8
- package/hooks/tezgah_stack.py +382 -0
- package/hooks/tezgah_stopspec.py +2 -2
- package/hosts/codex/hook.py +7 -1
- package/hosts/cursor/hook.py +7 -4
- package/hosts/omp/hook.py +12 -6
- package/hosts/omp/tezgah-hook.ts.in +20 -7
- package/hosts/opencode/plugins/tezgah.js +18 -9
- package/output-styles/tezgah.md +34 -19
- package/package.json +1 -1
- package/skills/i-have-adhd/SKILL.md +2 -2
- package/skills/research/SKILL.md +60 -17
- package/skills/tezgah-contract/SKILL.md +55 -13
package/docs/hosts.md
CHANGED
|
@@ -141,6 +141,52 @@ An installed host whose core line is missing is a health check's business
|
|
|
141
141
|
(`host_checks_<host>`), not a second copy: two delivery paths for one host is the
|
|
142
142
|
same rules paid twice per session.
|
|
143
143
|
|
|
144
|
+
## Precedence: what each host loads, and in which order
|
|
145
|
+
|
|
146
|
+
Several host dirs are read by more than one host. The table gives each host's
|
|
147
|
+
documented order. "First wins" means the host keeps the first copy of a name
|
|
148
|
+
and drops the later ones.
|
|
149
|
+
|
|
150
|
+
| concern | host | order | tezgah's part |
|
|
151
|
+
|---|---|---|---|
|
|
152
|
+
| context | claude | `~/.claude/CLAUDE.md`, then the repo's `CLAUDE.md`, `.claude/CLAUDE.md`, `CLAUDE.local.md`; all load | block in the first |
|
|
153
|
+
| context | codex | `$CODEX_HOME/AGENTS.override.md`, else `AGENTS.md`, then the repo's `AGENTS.md` | block in the first |
|
|
154
|
+
| context | cursor | the `sessionStart` hook context, the repo's `AGENTS.md`, `.cursor/rules/*.mdc`, `.cursorrules` | the hook |
|
|
155
|
+
| context | opencode | `~/.config/opencode/AGENTS.md`, `opencode.json` `instructions`, the repo's `AGENTS.md` | the contract and router files in `instructions` |
|
|
156
|
+
| context | omp | `SYSTEM.md`, `APPEND_SYSTEM.md`, `RULES.md` (sticky), the repo's `.omp/AGENTS.md`, `AGENTS.md`, `CLAUDE.md`; another host's user files only with `enabledProviders` | block in `RULES.md`, the extension at session start |
|
|
157
|
+
| skills | omp | `skills.customDirectories`, then `.omp/skills` and `~/.omp/agent/skills`, Claude's project dir (user dir opt-in), `.agents/skills` and `~/.agents/skills`; first wins, identical copies collapse, a differing copy is renamed `<namespace>/<name>` | links in `~/.omp/agent/skills` |
|
|
158
|
+
| skills | claude | `.claude/skills`, `~/.claude/skills`; plugin skills are namespaced `tezgah:<name>` | the plugin copy |
|
|
159
|
+
| 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
|
+
| 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
|
+
| 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 |
|
|
162
|
+
| 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
|
+
| 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
|
+
| 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 |
|
|
165
|
+
| hooks | omp | `~/.omp/agent/extensions/` first, then `config.yml` `extensions:`, one load per absolute path; per event in that order, and the first `block` ends a tool call | the bridge in `hooks/pre/` |
|
|
166
|
+
| mcp | each | omp: project `.omp/mcp.json`, then `~/.omp/agent/mcp.json`, first name wins; claude: `~/.claude.json`, the repo's `.mcp.json`, the plugin's `.mcp.json`; codex: `$CODEX_HOME/config.toml`; cursor: `~/.cursor/mcp.json`; opencode: `opencode.json` `mcp` | one `tezgah` and one `codegraph` row per host |
|
|
167
|
+
|
|
168
|
+
Orca is a launcher, not a host. It starts omp with its own `--extension`. It
|
|
169
|
+
gives each Codex account its own `CODEX_HOME` under
|
|
170
|
+
`~/Library/Application Support/orca/codex-accounts/<id>/home`. It adds its
|
|
171
|
+
status rows to Claude's `settings.json`, to Cursor's `hooks.json`, to that
|
|
172
|
+
Codex home's `hooks.json` and to opencode's `plugins/`. Its rows sit beside
|
|
173
|
+
tezgah's. The installer arms the `CODEX_HOME` it runs under
|
|
174
|
+
(`hooks/tezgah_paths.py::HOST_DIRS`). An install from a plain terminal and one
|
|
175
|
+
from an Orca pane therefore arm two different Codex homes.
|
|
176
|
+
|
|
177
|
+
`tezgah-doctor --stack [--repo PATH] [--json]` prints this stack as it stands
|
|
178
|
+
on the machine (`hooks/tezgah_stack.py::host_stack`). It exits 1 on a conflict
|
|
179
|
+
(`hooks/tezgah_stack.py::conflicts`). The kinds are `skill-differs`, `skill-dup`,
|
|
180
|
+
`skill-stale`, `rule-twice`, `hook-twice`, `mcp-twice`, `backup-in-scan` and
|
|
181
|
+
`orphan-copy`. `skill-differs` names the copy that wins. `skill-stale` is a
|
|
182
|
+
tezgah copy that is not this tree's bytes. `orphan-copy` is a Claude plugin
|
|
183
|
+
copy that `installed_plugins.json` no longer names.
|
|
184
|
+
|
|
185
|
+
A backup tezgah writes never lands in a host dir. It goes under
|
|
186
|
+
`~/.config/tezgah/backups/` (`bin/tezgah-setup::backup_base`), because omp
|
|
187
|
+
lists every file in `hooks/pre/` as a hook. `--install` moves the backups older
|
|
188
|
+
releases left in host dirs (`bin/tezgah-setup::sweep_backups`).
|
|
189
|
+
|
|
144
190
|
## The model wire
|
|
145
191
|
|
|
146
192
|
The matrix above is about events. This is about the other side of a host: which
|
|
@@ -196,7 +242,7 @@ In order, each step verified by the one below it:
|
|
|
196
242
|
(`hosts/omp/tezgah-hook.ts.in` rendered at `hooks/tezgah_attest.py::omp_bridge`).
|
|
197
243
|
3. `install_<host>()` writing that host's files, registered in `INSTALLERS`
|
|
198
244
|
(`bin/tezgah-setup::INSTALLERS`), and `uninstall_<host>()` removing only
|
|
199
|
-
tezgah-managed links and blocks (`bin/tezgah-setup:
|
|
245
|
+
tezgah-managed links and blocks (`bin/tezgah-setup:3287-3419`).
|
|
200
246
|
4. `host_checks_<host>()` returning `(label, bool)` rows over what was actually
|
|
201
247
|
written, registered in `HOST_CHECKS` (`bin/tezgah-setup::HOST_CHECKS`); the
|
|
202
248
|
`--report` output is that list (`bin/tezgah-setup::report`). Give the row a home-qualified
|
|
@@ -398,3 +444,4 @@ In order, each step verified by the one below it:
|
|
|
398
444
|
- `hosts/opencode/plugins/tezgah.js`, `hosts/opencode/tui/tezgah-tui.tsx`
|
|
399
445
|
- `statusline.py`, `bin/tezgah-status`, `hooks/tezgah_context.py`
|
|
400
446
|
- `hooks/tezgah_models.py` - the per-host model surface in `## The model wire`
|
|
447
|
+
- `hooks/tezgah_stack.py`, `bin/tezgah-doctor` `--stack` - the order in `## Precedence`
|
package/docs/index.json
CHANGED
|
@@ -466,6 +466,34 @@
|
|
|
466
466
|
"docs/testing.md",
|
|
467
467
|
"AGENTS.md"
|
|
468
468
|
]
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"path": "docs/orca.md",
|
|
472
|
+
"title": "Orca: what it owns, what tezgah owns, where they meet",
|
|
473
|
+
"title_tr": "Orca: neyin sahibi, tezgah neyin sahibi, nerede kesişirler",
|
|
474
|
+
"audience": "maintainer, agent working inside Orca",
|
|
475
|
+
"answers": [
|
|
476
|
+
"how does a session know it runs inside Orca",
|
|
477
|
+
"should a slice use orca worktree create or git worktree add",
|
|
478
|
+
"which checkouts of this repo does Orca track",
|
|
479
|
+
"does tezgah overwrite Orca's codex home or hooks"
|
|
480
|
+
],
|
|
481
|
+
"answers_tr": [
|
|
482
|
+
"bir oturum Orca içinde çalıştığını nasıl anlar",
|
|
483
|
+
"bir dilim orca worktree create mi yoksa git worktree add mi kullanmalı",
|
|
484
|
+
"Orca bu deponun hangi çalışma kopyalarını izliyor",
|
|
485
|
+
"tezgah Orca'nın codex dizinini veya hook'larını ezer mi"
|
|
486
|
+
],
|
|
487
|
+
"sources": [
|
|
488
|
+
"hooks/tezgah_orca.py",
|
|
489
|
+
"hooks/tezgah_context.py",
|
|
490
|
+
"hooks/tezgah_policy.py",
|
|
491
|
+
"hooks/tezgah_agents.py",
|
|
492
|
+
"bin/tezgah-status",
|
|
493
|
+
"bin/tezgah-setup",
|
|
494
|
+
"skills/tezgah-contract/SKILL.md",
|
|
495
|
+
"statusline.py"
|
|
496
|
+
]
|
|
469
497
|
}
|
|
470
498
|
]
|
|
471
|
-
}
|
|
499
|
+
}
|
package/docs/judge.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Judge: the judgement seam, its five callers and its switches
|
|
2
2
|
|
|
3
|
-
The judgement seam is `hooks/tezgah_judge.py
|
|
4
|
-
|
|
5
|
-
an agent to read. Read this page when you are about to call one of its four
|
|
3
|
+
The judgement seam is `hooks/tezgah_judge.py`. It asks the session's own model,
|
|
4
|
+
through the host's CLI, for a batched structured judgement over a state tezgah
|
|
5
|
+
would otherwise pay an agent to read. Read this page when you are about to call one of its four
|
|
6
6
|
callers, when you need to say what leaves the machine, or when you have to tell a
|
|
7
7
|
user how to switch it off. It is an on-demand capability, not a rule: no paragraph
|
|
8
8
|
of it is injected into a session, and a session that never asks pays one clause in
|
|
@@ -11,7 +11,7 @@ the kill-switch paragraph and nothing else (`CORE`,
|
|
|
11
11
|
|
|
12
12
|
## What it is
|
|
13
13
|
|
|
14
|
-
One seam, five callers, one
|
|
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
17
|
down (`_request`, `hooks/tezgah_judge.py::_request`). One endpoint and one key path
|
|
@@ -21,12 +21,12 @@ are module constants (`URL`, `hooks/tezgah_judge.py::URL`; `KEY_FILE`,
|
|
|
21
21
|
endpoint's host, so a `Location` cannot carry the bearer (`guarded_opener`,
|
|
22
22
|
`hooks/tezgah_paths.py`, the one copy `bin/consult` and `bin/codegen` use too). A
|
|
23
23
|
transient failure - a timeout, a connection error, a 5xx - gets exactly one more
|
|
24
|
-
attempt
|
|
25
|
-
`hooks/tezgah_judge.py::_transient`). A hook caller asks for one
|
|
26
|
-
wall-clock `deadline` instead (`ask`, `hooks/tezgah_judge.py::ask`).
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
attempt. A 4xx, a session CLI's non-zero exit and a malformed reply never do
|
|
25
|
+
(`_transient`, `hooks/tezgah_judge.py::_transient`). A hook caller asks for one
|
|
26
|
+
attempt and a wall-clock `deadline` instead (`ask`, `hooks/tezgah_judge.py::ask`).
|
|
27
|
+
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`, `TEZGAH_OPENROUTER_URL`
|
|
29
|
+
and `TEZGAH_OMP_BIN`/`TEZGAH_CLAUDE_BIN` are the test seams.
|
|
30
30
|
|
|
31
31
|
Every caller reads an answer through the same two accessors rather than reaching
|
|
32
32
|
into the raw reply, so a Choice and a Noul are read one way for all five
|
|
@@ -39,13 +39,13 @@ still reads the selected refs and owns the finding, and the ledger's step kinds
|
|
|
39
39
|
are untouched, so a model answer can never license a "done" (`STEP_KINDS`,
|
|
40
40
|
`hooks/tezgah_integrity.py::STEP_KINDS`).
|
|
41
41
|
|
|
42
|
-
The state leaves the machine.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
The state leaves the machine. By default it goes to the session's own vendor,
|
|
43
|
+
through the session's own CLI and credential ([below](#the-providers-and-their-order)).
|
|
44
|
+
A third party - `api.typesafe.ai` or `openrouter.ai` (`OPENROUTER_URL`,
|
|
45
|
+
`hooks/tezgah_judge.py::OPENROUTER_URL`) - reads it only as the `fallback`
|
|
46
|
+
setting allows. For the triage the state is the screen's own text, so whoever
|
|
47
|
+
answers reads any personal data on it. For the docs fallback it is the query.
|
|
48
|
+
Nothing else goes: no session id, no
|
|
49
49
|
workspace path, no environment. The seam does not rewrite the state, because
|
|
50
50
|
sending it is the point. Two callers rewrite what they send. `bin/tezgah-route`
|
|
51
51
|
sends its brief through the ledger's own redactor (`redact`,
|
|
@@ -77,37 +77,42 @@ caches one answer per `(session, prompt)` (`_remember`,
|
|
|
77
77
|
`hooks/tezgah_skill_pick.py::suggest`), and asks at all only when its own marker is
|
|
78
78
|
armed. The other four are bin tools a session runs by name.
|
|
79
79
|
|
|
80
|
-
## The
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
(`openrouter_key
|
|
94
|
-
|
|
95
|
-
`hooks/tezgah_judge.py::
|
|
96
|
-
|
|
97
|
-
`hooks/tezgah_judge.py::
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
`hooks/
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
`
|
|
80
|
+
## The providers and their order
|
|
81
|
+
|
|
82
|
+
`providers()` (`hooks/tezgah_judge.py::providers`) is the order `ask()` tries.
|
|
83
|
+
The next one is asked only when the previous failed. First comes the session's own
|
|
84
|
+
CLI (`tp.session_cli`, `hooks/tezgah_paths.py::session_cli`): `omp` when
|
|
85
|
+
`OMPCODE` is set, else `claude` when `CLAUDECODE` is. It runs headless with no
|
|
86
|
+
tools, rules, skills, extensions, MCP servers or settings (`SESSION_ARGV`,
|
|
87
|
+
`hooks/tezgah_judge.py::SESSION_ARGV`). Measured 2026-10-07, a call cost $0.007
|
|
88
|
+
on claude and $0.015 on omp. The session's own credential pays, OAuth subscription
|
|
89
|
+
included. The model and usage are read from the CLI's JSON output
|
|
90
|
+
(`_session_request`, `hooks/tezgah_judge.py::_session_request`). Then come the
|
|
91
|
+
third parties. TypeSafe reads `TYPESAFE_API_KEY`, else `~/.config/typesafe/key`
|
|
92
|
+
(`key`, `hooks/tezgah_judge.py::key`). OpenRouter reads `OPENROUTER_API_KEY`, else
|
|
93
|
+
`~/.config/openrouter/key` (`openrouter_key`, `hooks/tezgah_judge.py::openrouter_key`).
|
|
94
|
+
It asks the table's cheap row unless `TEZGAH_JUDGE_MODEL` names another
|
|
95
|
+
(`fallback_model`, `hooks/tezgah_judge.py::fallback_model`). The key file is
|
|
96
|
+
read because a hook runs where `~/.zshenv` never did. A chat answer is asked for in prose
|
|
97
|
+
(`CHAT_SYSTEM`, `hooks/tezgah_judge.py::CHAT_SYSTEM`) and filtered to the ids
|
|
98
|
+
asked, a wrongly typed answer dropped (`_chat_answers`,
|
|
99
|
+
`hooks/tezgah_judge.py::_chat_answers`).
|
|
100
|
+
|
|
101
|
+
`fallback` in `~/.config/tezgah/config.json` (`fallback_policy`,
|
|
102
|
+
`hooks/tezgah_paths.py::fallback_policy`) decides who may stand in:
|
|
103
|
+
|
|
104
|
+
| `fallback` | Session CLI present | No session CLI |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `vendor` (default) | the session CLI only; when it fails, no judgement | TypeSafe, then OpenRouter |
|
|
107
|
+
| `any` | the session CLI, then TypeSafe, then OpenRouter | TypeSafe, then OpenRouter |
|
|
108
|
+
| `none` | the session CLI only | nobody: `available()` is false |
|
|
109
|
+
|
|
110
|
+
Nothing that stands in is silent. A result carries `provider`, the `model`
|
|
111
|
+
the reply named and `fallback` - None when the session answered, else why it did
|
|
112
|
+
not. That answer, and a refusal with its failures, is said on stderr as one
|
|
113
|
+
`tezgah-judge:` line. It is also kept as the last-use record (`_record`,
|
|
114
|
+
`hooks/tezgah_judge.py::_record`), which `tezgah-status --judge` prints. The skill
|
|
115
|
+
hint's cost row and the router's `route` row also carry `judge=<provider>/<model>`.
|
|
111
116
|
|
|
112
117
|
## The switches
|
|
113
118
|
|
|
@@ -152,11 +157,11 @@ known (`note`, `hooks/tezgah_integrity.py::note`), counted by the row's kind
|
|
|
152
157
|
3. **No seam-level answer cache, and no caller cache beyond the prompt-keyed one
|
|
153
158
|
that exists** (`_remember`, `hooks/tezgah_skill_pick.py::_remember`). A judgement
|
|
154
159
|
costs a fraction of a cent, so a cache is not worth its state file, and a naive
|
|
155
|
-
one would make two runs of the same command disagree.
|
|
156
|
-
keeps
|
|
157
|
-
call that ends on a 401, 402 or
|
|
158
|
-
credential down for five minutes. Until the marker
|
|
159
|
-
|
|
160
|
+
one would make two runs of the same command disagree. Beside the last-use
|
|
161
|
+
record, the seam keeps a failure marker (`DOWN_FOR`, 300 s, in `hooks/tezgah_judge.py`). A
|
|
162
|
+
call that ends on a 401, 402, 5xx or a session CLI's non-zero exit marks that
|
|
163
|
+
provider, endpoint and credential down for five minutes. Until the marker
|
|
164
|
+
expires, that provider is skipped and sent no request. A dead key or an empty account then costs
|
|
160
165
|
one refusal per five minutes, not one per prompt. A rotated key gets a new
|
|
161
166
|
marker, so the seam asks it at once.
|
|
162
167
|
4. **No SDK, no `requests`, no async, no local model.** Each would trade one of
|
|
@@ -185,8 +190,9 @@ known (`note`, `hooks/tezgah_integrity.py::note`), counted by the row's kind
|
|
|
185
190
|
- `hooks/tezgah_skill_pick.py` — the prompt-path skill hint, its threshold, its
|
|
186
191
|
per-prompt cache and its `skill-suggest-on` marker.
|
|
187
192
|
- `hooks/tezgah_policy.py` — the `**Kill switches:**` paragraph the session
|
|
188
|
-
receives; `hooks/tezgah_paths.py` — where a switch file is read,
|
|
189
|
-
redirect guard (`guarded_opener`) the seam,
|
|
193
|
+
receives; `hooks/tezgah_paths.py` — where a switch file is read, the session CLI
|
|
194
|
+
and the `fallback` setting, and the redirect guard (`guarded_opener`) the seam,
|
|
195
|
+
consult and codegen share; `bin/tezgah-status --judge` — the last-use record.
|
|
190
196
|
- `hooks/tezgah_integrity.py` — the ledger and the `judge` counter;
|
|
191
197
|
`hooks/tezgah_context.py` — the status mark and the class carve-out.
|
|
192
198
|
- `tests/test_judge.py`, `tests/test_triage.py`, `tests/test_docs_router.py` —
|
package/docs/models.md
CHANGED
|
@@ -20,7 +20,12 @@ and every slot a model per family (`SLOTS`, `hooks/tezgah_models.py::SLOTS`). Th
|
|
|
20
20
|
three tier workers - `tezgah-cheap`, `tezgah-standard`, `tezgah-frontier` - are
|
|
21
21
|
generated in every tezgah root because routing needs no capability (`ROLES`,
|
|
22
22
|
`hooks/tezgah_agents.py::ROLES`; their brief, `_worker_body`,
|
|
23
|
-
`hooks/tezgah_agents.py::_worker_body`).
|
|
23
|
+
`hooks/tezgah_agents.py::_worker_body`). So are the five specialists:
|
|
24
|
+
`tezgah-tester`, `tezgah-docs`, `tezgah-security`, `tezgah-ui` and
|
|
25
|
+
`tezgah-researcher` (`hooks/tezgah_agents.py::SPECIALISTS`). A specialist's
|
|
26
|
+
description names its slot from `AGENT_SLOT`. The tier a host shows and the
|
|
27
|
+
model line it runs therefore cannot disagree, and `tezgah-agents --list` prints
|
|
28
|
+
both. A cheaper worker that meets work above its tier
|
|
24
29
|
answers `ESCALATE: <why>`, and the router restarts the task on `tezgah-frontier`
|
|
25
30
|
with the original brief rather than handing the failed trajectory up: continuing a
|
|
26
31
|
cheap trajectory on a frontier model was the most expensive option measured
|
|
@@ -30,10 +35,10 @@ cheap trajectory on a frontier model was the most expensive option measured
|
|
|
30
35
|
|
|
31
36
|
| slot | agents | anthropic | zai (omp's own provider) | openai | any (OpenRouter id) |
|
|
32
37
|
|---|---|---|---|---|
|
|
33
|
-
| cheap | tezgah-cheap | Opus 5.5 @low | `zai/glm-5.3-flash` | GPT-6.1 Sol @low | GLM-5.3 Flash |
|
|
38
|
+
| cheap | tezgah-cheap, tezgah-tester | Opus 5.5 @low | `zai/glm-5.3-flash` | GPT-6.1 Sol @low | GLM-5.3 Flash |
|
|
34
39
|
| explore | omp's bundled `scout` | Opus 5.5 @medium | `zai/glm-5.3-flash` | GPT-6.1 Sol @low | DeepSeek V4.1 Flash |
|
|
35
|
-
| standard | tezgah-standard | Opus 5.5 @medium | `zai/glm-5.3` | GPT-6.1 Sol @high | GPT-6.1 Sol @high |
|
|
36
|
-
| frontier | tezgah-frontier, tezgah-reviewer | Opus 5.5 @high | `zai/glm-5.3` | GPT-6 Astra @high | Opus 5.5 @high |
|
|
40
|
+
| standard | tezgah-standard, tezgah-docs, tezgah-ui | Opus 5.5 @medium | `zai/glm-5.3` | GPT-6.1 Sol @high | GPT-6.1 Sol @high |
|
|
41
|
+
| frontier | tezgah-frontier, tezgah-reviewer, tezgah-security, tezgah-researcher | Opus 5.5 @high | `zai/glm-5.3` | GPT-6 Astra @high | Opus 5.5 @high |
|
|
37
42
|
|
|
38
43
|
Why these, briefly. Inside the Anthropic family the lever is effort, not model:
|
|
39
44
|
Opus 5.5 and Sonnet 5.5 read cache at the same $0.20 per 1M tokens, and on
|
|
@@ -56,7 +61,7 @@ invoices).
|
|
|
56
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) |
|
|
57
62
|
| Codex | openai | `model` and `model_reasoning_effort` in `.codex/agents/*.toml` |
|
|
58
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) |
|
|
59
|
-
| 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 **
|
|
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` |
|
|
60
65
|
| dsh | - | none: no model setting was found to write |
|
|
61
66
|
|
|
62
67
|
The orchestrator agent keeps `model: inherit`: it is the main thread's own agent.
|
|
@@ -88,11 +93,12 @@ fixed:
|
|
|
88
93
|
undone on. A 12-brief fixture pins it: 8 high-stakes briefs route to
|
|
89
94
|
frontier, 4 near-miss controls do not (`tests/test_models.py`).
|
|
90
95
|
2. Otherwise the brief - redacted with the ledger's own reader
|
|
91
|
-
(`redact`, `hooks/tezgah_integrity.py::redact`) - goes to
|
|
92
|
-
`hooks/tezgah_models.py::TIER_QUESTION`).
|
|
96
|
+
(`redact`, `hooks/tezgah_integrity.py::redact`) - goes to the judge as one Choice over three tiers (`TIER_QUESTION`,
|
|
97
|
+
`hooks/tezgah_models.py::TIER_QUESTION`). The judge asks the session's own model first ([judge](judge.md)).
|
|
98
|
+
Measured with Jev on 40 English briefs labelled by
|
|
93
99
|
the same session that wrote the rubric (2026-09-30, twice): under-route 0.025,
|
|
94
100
|
accuracy 0.925 and 0.900, 392 ms median, about 656 input tokens per call; a
|
|
95
|
-
keyword rule on the same set under-routed 0.100.
|
|
101
|
+
keyword rule on the same set under-routed 0.100. The session model was not measured on that set.
|
|
96
102
|
3. With no judgement (`judge-off`, no key, a failed call) `--phase` picks the tier
|
|
97
103
|
from the static table (`PHASE_TIER`, `hooks/tezgah_models.py::PHASE_TIER`), and
|
|
98
104
|
with no phase the middle tier is used.
|
package/docs/operations.md
CHANGED
|
@@ -23,7 +23,7 @@ before an install is considered.
|
|
|
23
23
|
| `--refresh` | Re-render every always-on contract artifact of the armed hosts - the managed blocks of `CLAUDE.md`, Codex's `AGENTS.md` and omp's `RULES.md`, opencode's contract and skill routers - after a policy edit or a kill switch; prints the paths it refreshed, else `contract is current`. Before the first install there is no hash record, so it changes nothing (`refresh_contract`, `bin/tezgah-setup::refresh_contract`). |
|
|
24
24
|
| `--uninstall` | Remove everything tezgah installed — per host the wiring it wrote, plus (a full run) the Claude plugin copy with its registry rows, the generated config state, the kill switches, the caches and the versioned install tree — then verify the removal; nonzero exit while anything tezgah wrote survives (`bin/tezgah-setup::verify_uninstall`, `bin/tezgah-setup::uninstall`). |
|
|
25
25
|
| `--adopt` | Move pre-tezgah wiring aside instead of deleting it; alone it stops there, with `--install` it runs first (`bin/tezgah-setup::main`, `bin/tezgah-setup::adopt`). |
|
|
26
|
-
| `--sync` | Copy this checkout over
|
|
26
|
+
| `--sync` | Copy this checkout over the Claude plugin [copy](glossary.md#plugin-copy) `installed_plugins.json` names, or over every copy when it names none (`bin/tezgah-setup::sync`, `bin/tezgah-setup::live_plugin_copies`). An older version dir is Claude's cache to collect, so it is left alone. Each copy is built in a staging tree beside the plugin cache and swapped in with two renames, its `.git` carried over, so a failed or killed sync leaves the previous copy whole (`bin/tezgah-setup::_swap`). Every copied file is 0644, or 0755 when the tree marks it executable, whatever mode the source has (`bin/tezgah-setup::_copy_normalised`). |
|
|
27
27
|
| `--hook-entries` | Print, as JSON, the tezgah-owned hook entries this tree arms per armed host - what `tezgah update` asks the new tree for (`bin/tezgah-setup::hook_entries`). |
|
|
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`). |
|
|
@@ -158,7 +158,7 @@ or `default`), a common block (config, the code-graph binary, the consult option
|
|
|
158
158
|
`orx`, `npx`, the artifacts dir, `git`, the manifest, a stale-contract line), one
|
|
159
159
|
block per host, then the budget (`bin/tezgah-setup::report`). Each block is
|
|
160
160
|
`host_checks_<host>` (`bin/tezgah-setup::HOST_CHECKS`), and those rows are the source of truth for
|
|
161
|
-
"is this host armed" (`AGENTS.md:
|
|
161
|
+
"is this host armed" (`AGENTS.md:147-148`) — not the presence of a directory, and
|
|
162
162
|
not the status line. A row can read ` MISS ` too: claude's `plugin copy current`
|
|
163
163
|
row fails on a machine with no copy at all, because an absent copy is not a
|
|
164
164
|
current one (`bin/tezgah-setup::host_checks_claude`).
|
|
@@ -284,8 +284,8 @@ A **full** run also takes everything the wiring was serving from:
|
|
|
284
284
|
`bin/tezgah-setup` plus the `current` flip (`remove_install_tree()`,
|
|
285
285
|
`bin/tezgah-setup::remove_install_tree`).
|
|
286
286
|
|
|
287
|
-
Kept in every run: the user's own files, every
|
|
288
|
-
|
|
287
|
+
Kept in every run: the user's own files, every host-file backup under
|
|
288
|
+
`~/.config/tezgah/backups/` (the timestamped ones too), `~/.config/tezgah/adopted/` (the only copy of the
|
|
289
289
|
predecessor wiring adopt moved aside), and every repository's `.tezgah/`
|
|
290
290
|
research state. A **partial** run also keeps config.json and the install tree,
|
|
291
291
|
because the hosts still armed read both at runtime, and says so. It also leaves
|
|
@@ -372,6 +372,7 @@ does not hold.
|
|
|
372
372
|
| `tezgah-doctor` | nothing: sizes, session and event counts, whether opencode is running, the two context-hygiene settings, the `.codegraph` bytes and index presence per repository, and the three host state dirs (`bin/tezgah-doctor::collect`, `bin/tezgah-doctor::report`) |
|
|
373
373
|
| `tezgah-doctor --clean` | vacuums opencode's database, and only when opencode is not running (`bin/tezgah-doctor::vacuum_db`, `bin/tezgah-doctor::main`); and deletes tezgah's own hook state not modified for `--retention-days` (default 30) - the ledgers under `evidence/`, `turns/`, `sessions/`, `classify.log`, `context-drops.log` and `debug.log`, in the cache and its sandbox fallback - keeping the current session's (`$TEZGAH_SESSION`) files whatever their age (`sweep_state`) |
|
|
374
374
|
| `tezgah-doctor --coverage` | every tracked file the codegraph index does not hold, in two classes — a supported extension the index is missing, and a shebang-only script with no `.py` twin — with the file counts it read, so an empty result cannot read as "everything is covered" |
|
|
375
|
+
| `tezgah-doctor --stack` | per host: the context files in load order, the skill dirs and which copy wins, the hook rows per event with their owner, the MCP servers, and every conflict; exits 1 on one ([hosts](hosts.md#precedence-what-each-host-loads-and-in-which-order), `hooks/tezgah_stack.py::report`) |
|
|
375
376
|
| `tezgah-doctor --prune-sessions DAYS` | deletes sessions idle longer than DAYS through `opencode session delete`, then vacuums; skipped when opencode is running or its CLI is missing (`bin/tezgah-doctor::prune_sessions`, `bin/tezgah-doctor::main`) |
|
|
376
377
|
|
|
377
378
|
`VACUUM` alone cannot shrink that database — its pages are all live — so
|
|
@@ -541,7 +542,11 @@ with `embed-m2v`. The fusion found it for 0.75 and 0.74, BM25 for 0.68.
|
|
|
541
542
|
|
|
542
543
|
Reversible and safe to repeat: every link and settings key it writes is
|
|
543
544
|
idempotent and re-created by `--install`. A write that changes a file first
|
|
544
|
-
copies it to `<file>.<timestamp>.tezgah-bak`.
|
|
545
|
+
copies it to `<file>.<timestamp>.tezgah-bak`. A host file's copy goes under
|
|
546
|
+
`~/.config/tezgah/backups/` (`bin/tezgah-setup::backup_base`). A host lists the
|
|
547
|
+
files in its own dirs. tezgah's own state dir
|
|
548
|
+
keeps its copies beside the file. `--install` moves the copies an older release
|
|
549
|
+
left in a host dir (`bin/tezgah-setup::sweep_backups`). The oldest of those copies is
|
|
545
550
|
always kept, beside the newest four (`backup()`, `BACKUP_CAP`). The oldest is
|
|
546
551
|
the file before tezgah's first timestamped write, which is tezgah's own content
|
|
547
552
|
for a file tezgah created. On an upgraded install the pre-tezgah copy is the
|
package/docs/orca.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Orca: what it owns, what tezgah owns, where they meet
|
|
2
|
+
|
|
3
|
+
Orca is an IDE that runs agent sessions in its own terminals and worktrees.
|
|
4
|
+
This page is for a maintainer or an agent working inside Orca. Read it when a
|
|
5
|
+
session asks how tezgah and Orca share a machine. It describes Orca 1.4.221 and
|
|
6
|
+
1.4.222 as observed on 2026-10-07. Each Orca claim names the command or file
|
|
7
|
+
behind it, so a reader can check it again after a later release.
|
|
8
|
+
|
|
9
|
+
## How a process knows it runs in Orca
|
|
10
|
+
|
|
11
|
+
Every terminal Orca starts exports its own markers. The table lists the ones
|
|
12
|
+
tezgah reads, as `env` printed them inside an Orca terminal.
|
|
13
|
+
|
|
14
|
+
| Variable | Value shape | Read by |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `ORCA_WORKTREE_ID` | `<repoId>::<absolute path>` of the Orca worktree | `hooks/tezgah_orca.py::session` |
|
|
17
|
+
| `ORCA_TERMINAL_HANDLE` | `term_<uuid>`, the handle `orca terminal` commands take | `hooks/tezgah_orca.py::session` |
|
|
18
|
+
| `ORCA_PANE_KEY` | `<tab>:<pane>` | `hooks/tezgah_orca.py::session` |
|
|
19
|
+
| `TERM_PROGRAM` | `Orca` | `hooks/tezgah_orca.py::session` |
|
|
20
|
+
| `ORCA_APP_VERSION` | `1.4.221` | `hooks/tezgah_orca.py::session` |
|
|
21
|
+
| `ORCA_CLI_COMMAND` | the wrapper Orca exports for WSL sessions (orca-cli skill) | `hooks/tezgah_orca.py::cli` |
|
|
22
|
+
| `ORCA_CLI_BIN_DIR` | `/Applications/Orca.app/Contents/Resources/bin` | `hooks/tezgah_orca.py::cli` |
|
|
23
|
+
| `CODEX_HOME`, `ORCA_CODEX_HOME` | `~/Library/Application Support/orca/codex-accounts/<id>/home` | `hooks/tezgah_paths.py::HOST_DIRS` (CODEX_HOME only) |
|
|
24
|
+
|
|
25
|
+
Orca also exports `ORCA_AGENT_HOOK_*` for its hook endpoint, port and token.
|
|
26
|
+
It exports `ORCA_OMP_*` for its omp status extension. tezgah reads none of
|
|
27
|
+
them and writes no `ORCA_*` variable. The marker set in `MARKERS` is the whole
|
|
28
|
+
contract.
|
|
29
|
+
|
|
30
|
+
A shell started from an Orca terminal inherits the variables. A subagent whose
|
|
31
|
+
working directory is a raw worktree still reports the parent's
|
|
32
|
+
`ORCA_WORKTREE_ID`. So the marker says "inside Orca", not "inside this
|
|
33
|
+
checkout".
|
|
34
|
+
|
|
35
|
+
## What Orca owns
|
|
36
|
+
|
|
37
|
+
| Surface | What Orca keeps | Evidence |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| Worktrees | a git worktree plus a card (status, comment, lineage, links), by default under `~/orca/workspaces/<repo>/<name>` | `orca worktree create --help`; `orca repo show` lists paths under `~/orca/workspaces/tezgah/` |
|
|
40
|
+
| Terminals | live PTYs with handles, read/send/wait | `orca terminal list --json` |
|
|
41
|
+
| Agent sessions | agent type and state per pane, shown in `orca worktree ps` | `agents[].agentType`, `agents[].state` in `orca worktree ps --json` |
|
|
42
|
+
| Orchestration | runs, tasks, dispatch, supervised workers, decision gates | `orca --help`, section Orchestration |
|
|
43
|
+
| Embedded browser | tabs per worktree, snapshot and element refs | `orca --help`, section Browser Automation |
|
|
44
|
+
| Artifacts | public HTML or Markdown links, off until a human enables them in Settings | `orca skills get orca-cli`, section Artifacts |
|
|
45
|
+
| Codex accounts | one codex home per account, marked by `.orca-managed-home` | the account home's directory listing |
|
|
46
|
+
| Its hooks | `~/.orca/agent-hooks/`, plus entries tagged `orca-agent-hook-form=1` in each managed codex `hooks.json` | the account home's `hooks.json` |
|
|
47
|
+
| omp extensions | `orca-agent-status.ts`, `orca-prefill.ts` and `orca-titlebar-spinner.ts` in `~/.omp/agent/extensions/` | that directory's listing |
|
|
48
|
+
|
|
49
|
+
The `orca-cli` skill is a stub. The full guide comes from the binary itself:
|
|
50
|
+
`orca skills get orca-cli`. Run it before any Orca command a session has not
|
|
51
|
+
run before.
|
|
52
|
+
|
|
53
|
+
## What tezgah owns
|
|
54
|
+
|
|
55
|
+
tezgah owns the contract text, the gate, the evidence ledger and the status
|
|
56
|
+
line. It also owns its own hook entries in each host config
|
|
57
|
+
([architecture](architecture.md), [hosts](hosts.md)). It does not create
|
|
58
|
+
worktrees or terminals in code. A parallel slice is an instruction to the
|
|
59
|
+
session: the `Tier 1` paragraph of `hooks/tezgah_policy.py::ORCHESTRATE`,
|
|
60
|
+
mirrored in `skills/tezgah-contract/SKILL.md`, and the orchestrator agent body
|
|
61
|
+
`hooks/tezgah_agents.py::_orch_body`.
|
|
62
|
+
|
|
63
|
+
## Where they meet
|
|
64
|
+
|
|
65
|
+
| Point | Behaviour | Code |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| Session start inside Orca | one `Orca:` line names the worktree and tells the session to use `orca worktree create`, `orca terminal create` and `orca worktree ps`. It reads env only and starts no process. | `hooks/tezgah_orca.py::context_line`, called from `hooks/tezgah_context.py::context_for` |
|
|
68
|
+
| Slice checkouts | inside Orca, `orca worktree create --name <slug> --parent-worktree active --json`, else `git worktree add` | `hooks/tezgah_policy.py::ORCHESTRATE`, `hooks/tezgah_agents.py::_orch_body` |
|
|
69
|
+
| Tracking | `tezgah-status --orca` lists each checkout Orca tracks (card, state, live terminals, agent states) and each git worktree Orca does not list | `bin/tezgah-status::print_orca`, `hooks/tezgah_orca.py::checkouts` |
|
|
70
|
+
| Install report | `tezgah-setup --status` prints one `orca:` line where Orca is present. The line names the runtime, the terminal and an Orca-managed CODEX_HOME. | `hooks/tezgah_orca.py::summary`, `bin/tezgah-setup::main` |
|
|
71
|
+
| Codex hooks | tezgah drops only entries holding `tezgah` and appends its own groups, so Orca's entries stay | `bin/tezgah-setup::install_codex` |
|
|
72
|
+
| Cursor hooks | the same merge | `bin/tezgah-setup::install_cursor` |
|
|
73
|
+
| Claude status line | tezgah's wrapper runs Orca's `~/.orca/agent-hooks/claude-statusline.sh` first and appends its own segment | `statusline.py::ORCA`, `bin/tezgah-setup::wire_claude_statusline` |
|
|
74
|
+
| Codex rules file | Orca links the account home's `AGENTS.md` to `~/.codex/AGENTS.md`. tezgah writes the managed block through that link with a plain `open`, so the link stays. | `bin/tezgah-setup::set_managed_md` |
|
|
75
|
+
|
|
76
|
+
### The collision this fixes
|
|
77
|
+
|
|
78
|
+
On 2026-10-07 the tezgah repository had eleven git checkouts and Orca listed
|
|
79
|
+
one. `git worktree list` printed the main checkout and ten under
|
|
80
|
+
`~/Projects/tezgah-wt/`, and `orca worktree list --repo path:<main> --json`
|
|
81
|
+
returned `totalCount: 1`. The ten came from raw `git worktree add`, so Orca
|
|
82
|
+
showed no card, terminal or agent state for them. `tezgah-status --orca` now
|
|
83
|
+
prints that gap.
|
|
84
|
+
|
|
85
|
+
A smoke run on the live runtime closed the loop. It ran `orca worktree create
|
|
86
|
+
--name tezgah-orca-smoke --parent-worktree active --setup skip --json` from the
|
|
87
|
+
main checkout. `tezgah-status --orca --json` then listed the new checkout as
|
|
88
|
+
tracked, with one terminal. `orca worktree rm --force` removed it, its branch
|
|
89
|
+
included.
|
|
90
|
+
|
|
91
|
+
### CODEX_HOME inside Orca
|
|
92
|
+
|
|
93
|
+
Inside Orca, CODEX_HOME names an Orca-managed account home. A `tezgah-setup
|
|
94
|
+
--install` run from an Orca terminal arms that home, and a run from another
|
|
95
|
+
terminal arms `~/.codex` (`hooks/tezgah_paths.py::HOST_DIRS`). On this machine
|
|
96
|
+
both homes carry tezgah's seven hook events. The Orca home keeps
|
|
97
|
+
Orca's own entries beside them. Orca also keeps
|
|
98
|
+
`.orca-hook-trust-provenance.json` there, keyed by event and entry index.
|
|
99
|
+
tezgah appends after Orca's entries, so Orca's index does not move. Whether
|
|
100
|
+
Orca re-trusts a changed tezgah entry on its own is not verified.
|
|
101
|
+
|
|
102
|
+
## What the Orca CLI does not offer
|
|
103
|
+
|
|
104
|
+
- No command adopts an existing raw git worktree as an Orca worktree. The
|
|
105
|
+
`Worktrees` section of `orca --help` lists `list`, `show`, `current`,
|
|
106
|
+
`create`, `set`, `rm` and `ps` only. `orca repo set --repo <sel>
|
|
107
|
+
--external-worktree-visibility show` makes non-Orca worktrees visible in the
|
|
108
|
+
sidebar. It does not give them cards.
|
|
109
|
+
- An agent cannot turn on artifact publishing. A human enables it in Settings
|
|
110
|
+
(the `Artifacts` section of `orca skills get orca-cli`).
|
|
111
|
+
|
|
112
|
+
## Tests
|
|
113
|
+
|
|
114
|
+
`tests/test_orca.py` runs with no real Orca. A fake `orca` on disk answers
|
|
115
|
+
`worktree ps` and `status`, and every marker is a fixture. `tests/support.py`
|
|
116
|
+
strips the developer's own `ORCA_*` markers and `TERM_PROGRAM=Orca`, and pins
|
|
117
|
+
`TEZGAH_ORCA_BIN` to a missing path. Without that, a suite run inside Orca
|
|
118
|
+
would reach the live runtime.
|
|
119
|
+
|
|
120
|
+
## Source of truth
|
|
121
|
+
|
|
122
|
+
- `hooks/tezgah_orca.py`: detection, CLI resolution, the listing and both report lines
|
|
123
|
+
- `hooks/tezgah_context.py`: where the session line joins the session-start block
|
|
124
|
+
- `hooks/tezgah_policy.py`, `skills/tezgah-contract/SKILL.md`, `hooks/tezgah_agents.py`: the slice rule
|
|
125
|
+
- `bin/tezgah-status`, `bin/tezgah-setup`: the two report surfaces
|
|
126
|
+
- `tests/test_orca.py`, `tests/support.py`
|
package/docs/research.md
CHANGED
|
@@ -65,7 +65,7 @@ nothing recorded the ask and `close --limit` accepted any string.
|
|
|
65
65
|
`state.json` `rules` is the line's format version. `init` writes `RULES`, the
|
|
66
66
|
newest set (`hooks/tezgah_research.py::RULES`). Each set keeps its own gate. Rules 2
|
|
67
67
|
are the standards rules. Rules 3 add the ask contract. Rules 4 add the protocol
|
|
68
|
-
sections below. A bump never weakens an older set.
|
|
68
|
+
sections below. Rules 5 add the scope lock. A bump never weakens an older set.
|
|
69
69
|
|
|
70
70
|
A `rules` above `RULES` means a later tezgah wrote the line. `check` then reports
|
|
71
71
|
one error that names both numbers and reads nothing else. The writers refuse the
|
|
@@ -110,14 +110,49 @@ it. The rules come from the gortex/SoL-Pi adoption's ideas 3 and 4 and from the
|
|
|
110
110
|
layer audit's P2 probe (`_check_protocol_sections`, `_token_claim_problem`).
|
|
111
111
|
Older lines keep the word rule.
|
|
112
112
|
|
|
113
|
+
## Scope lock (rules 5)
|
|
114
|
+
|
|
115
|
+
The owner reported on 2026-10-07 that research turned every question into
|
|
116
|
+
metrics. It also grew past the ask, stayed shallow, and drifted off topic. The
|
|
117
|
+
rule text pushed each of these. The injected rule sent every research task to
|
|
118
|
+
orx's experiment tree. The skill locked a metric at bootstrap. `check` refused a
|
|
119
|
+
line past `bootstrap` without one. An analysis owed three compared variants. The
|
|
120
|
+
ideation moves had no fence. Rules 5 lock a line to its question:
|
|
121
|
+
|
|
122
|
+
- `init --in "<covered>" --out "<left alone>"` (repeatable) write `state.json`
|
|
123
|
+
`scope`. The in-scope items are `S1`, `S2`, ... in order. `--method
|
|
124
|
+
qualitative|measured` writes `method`. `scope_problems`
|
|
125
|
+
(`hooks/tezgah_research.py::scope_problems`) names an empty `scope.in`, an
|
|
126
|
+
empty `scope.out` and a missing method. `check` refuses them past `bootstrap`
|
|
127
|
+
and warns at it.
|
|
128
|
+
- A claim's `trace` names the in-scope item it answers (`S<n>` or the item's
|
|
129
|
+
text). `claim_problems` and `_check_claims` both call `trace_problem`
|
|
130
|
+
(`hooks/tezgah_research.py::trace_problem`). The writer and the checker refuse
|
|
131
|
+
the same off-topic claim.
|
|
132
|
+
- A `qualitative` line owes no metric. `_check_evaluation`
|
|
133
|
+
(`hooks/tezgah_research.py::_check_evaluation`) skips it. `_check_scope`
|
|
134
|
+
refuses one that records `results.jsonl`. A measured question says `measured`
|
|
135
|
+
and locks its evaluation first.
|
|
136
|
+
- An `analysis` deliverable owes no variants (`deliverable_problems` takes the
|
|
137
|
+
line's rules). A design, plan or code still does. Older lines keep three.
|
|
138
|
+
|
|
139
|
+
The session reads the same lock in the research rule
|
|
140
|
+
(`hooks/tezgah_policy.py::RESEARCH` and the paragraph `**Research: route it to
|
|
141
|
+
OpenResearch.**`). Restate the question verbatim. Name what is in and out of
|
|
142
|
+
scope. Drop a finding that answers nothing asked. Pick the method from the
|
|
143
|
+
question. Answer a plain factual question in the reply from primary sources, with
|
|
144
|
+
no line. Cite each finding's source with a confidence. The host-subagent fallback
|
|
145
|
+
gets the question, its scope and its method in its brief. The research skill's
|
|
146
|
+
"Scope and method" section is the long form.
|
|
147
|
+
|
|
113
148
|
## One line, one directory
|
|
114
149
|
|
|
115
150
|
| Path | Holds |
|
|
116
151
|
|---|---|
|
|
117
|
-
| `state.json` | the question, the phase (`bootstrap`/`inner`/`outer`/`concluded`), the direction, the locked evaluation and its optional second gate (`capability_tolerance`, `counter_metric`), the session events (`PHASES`, `hooks/tezgah_research.py::PHASES`), `rules` (the rule set `init` opened it under, `RULES`), `deliverable` (`kind`, `path`, `ask`, `min_variants`), `supersedes` for a new version of an older line, and `closed` once `close` records a deliberate limit. The phase is the author's declaration; `derived_phase` (`hooks/tezgah_research.py::derived_phase`) reads the *other* authority beside it from the line's own artifacts, and the checker names the two disagreeing |
|
|
152
|
+
| `state.json` | the question, the phase (`bootstrap`/`inner`/`outer`/`concluded`), the direction, `method` and `scope` (rules 5, see "Scope lock"), the locked evaluation and its optional second gate (`capability_tolerance`, `counter_metric`), the session events (`PHASES`, `hooks/tezgah_research.py::PHASES`), `rules` (the rule set `init` opened it under, `RULES`), `deliverable` (`kind`, `path`, `ask`, `min_variants`), `supersedes` for a new version of an older line, and `closed` once `close` records a deliberate limit. The phase is the author's declaration; `derived_phase` (`hooks/tezgah_research.py::derived_phase`) reads the *other* authority beside it from the line's own artifacts, and the checker names the two disagreeing |
|
|
118
153
|
| `log.md` | the decision log, newest last: one line per decision, experiment, dead end or pivot, with the evidence that drove it |
|
|
119
154
|
| `findings.md` | the four sections every line answers, named by `FINDINGS_SECTIONS` (`hooks/tezgah_research.py::FINDINGS_SECTIONS`) |
|
|
120
|
-
| `claims.jsonl` | one JSON object per row: `statement`, `falsification`, `proof`, `provenance`, `status`, `kind`, `scope` (what the claim's numbers were measured on, which may not be wider than the rows it rests on), and `supersedes` when the row replaces an earlier claim |
|
|
155
|
+
| `claims.jsonl` | one JSON object per row: `statement`, `falsification`, `proof`, `provenance`, `status`, `kind`, `trace` (the in-scope item, rules 5), `scope` (what the claim's numbers were measured on, which may not be wider than the rows it rests on), and `supersedes` when the row replaces an earlier claim |
|
|
121
156
|
| `predictions.jsonl` | one JSON object per row: `commit` (a 40-character sha the row is bound to), `claim` (an id the line holds, or empty when the prediction stands alone), `metric`, `value_before`, `value_after`, `falsifier`, `components` (the keys of the components the change touches, read from `hooks/tezgah_components.py`), and `granted_by` when a human granted what the frozen paths below forbid |
|
|
122
157
|
| `experiments/<hypothesis>/protocol.md` | what the change is, what it predicts, what result would falsify it, why - committed before the run |
|
|
123
158
|
| `experiments/<hypothesis>/results.jsonl` | the rows the run produced, one JSON object per non-blank line, each carrying a non-empty `source` and, once declared, a `scope` of `real`, `fixture` or `derived`, and - when that scope is `fixture` - a `fixture` description of what was generated |
|