omnilane 0.42.9 → 0.44.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.
@@ -5,122 +5,61 @@ description: 'Universal model-routing table + cross-vendor dispatch for ANY harn
5
5
 
6
6
  # omnilane — one routing table, every harness
7
7
 
8
- You (the main loop) may be Claude, GPT, Grok, or Gemini. The procedure is identical:
9
-
10
- 1. **Identify the main model from current runtime metadata.** If the identity is unavailable, report it as unverified instead of guessing from a skill name or prior session.
11
- 2. **Split the work into subtasks and classify each into a lane** (table below).
12
- 3. **Delegate every task by default, even to the commander's exact model.**
13
- Native agents count as delegation; a model match is not permission for
14
- commander self-execution. Resolve vendor/model/effort separately from
15
- executor selection. Terminal `auto` without capabilities stays legacy CLI.
16
- The commander owns planning, task briefs, handoff/completion orchestration,
17
- reading public results, acceptance, operator replies, git commit/push and
18
- governance edits. Workers execute the assigned task and never delegate again.
19
- Read-only work uses advise; edits require `--mode work --workdir <repo>`.
20
- `<repo>/scripts/dispatch.sh --caller-context FILE [--executor auto|native|cli] [--native-context FILE] [--vendor V] [--mode work] [--workdir DIR] <lane> "<task>"`
21
-
22
- A model caller needs a verifiable caller identity. Codex app-server reads the
23
- current turn from its rollout; other launches read the model and effort from
24
- the CLI that launched you, so an ordinary session passes nothing. When that
25
- identity cannot be read, dispatch is refused with `missing-caller-context`
26
- before a job exists: run `omnilane whoami` (or `<repo>/bin/omnilane whoami`)
27
- and pass the file it prints as `--caller-context`. See **Frozen exact-AA
28
- downward gate** for the schema and what to do when effort is genuinely
29
- unverifiable.
30
-
31
- Add `--background` for long tasks; poll with `scripts/jobs.sh status|result <id>`.
32
- Use `--thread NAME` when later claude, codex, grok or gemini dispatches
33
- must retain earlier context. Threads in 0.33.0 pin vendor, model, effort and
34
- physical workdir; inspect or remove local state with `scripts/jobs.sh threads`,
35
- `threads show NAME`, and `threads rm NAME` (removal leaves the vendor session).
36
- Implementation dispatches (code edits, new files, tests, builds, deploys)
37
- must carry `--mode work --workdir <repo>` and a `--timeout` of at least
38
- 3600 seconds. The advise default is a read-only worker under a 600 s
39
- per-call watchdog, and on an implementation task it yields zero output.
40
- Advise stays the default for reviews, questions, and second opinions.
41
- Before changing lane order from anecdotal outcomes, run
42
- `scripts/jobs.sh recommend [--last N] [--lane L] [--min-samples N]` and report
43
- its evidence threshold. The command is read-only and never changes routing.
44
- Preview old completed-job cleanup with `scripts/jobs.sh prune --keep <N>`;
45
- deletion requires the explicit `--apply` flag and never targets running jobs.
46
- A deep task whose CLI call may outrun the 600s per-call watchdog can raise its
47
- cap with `--timeout <seconds>` (e.g. `--timeout 1200` for hard-judgment /
48
- long-context). It bounds each CLI call, not the whole dispatch.
49
- For one aggregate fuse across lock wait, retries, voters, and rounds, add
50
- `--job-timeout <seconds>`. It is disabled by default; deep full-repository
51
- audits typically need 7200–14400 seconds, and expiry returns 124. The one
52
- automatic exception is non-Git Codex `work`: without an explicit, lane, or
53
- global job timeout, its resolved per-call timeout becomes the whole-job fuse,
54
- capped at the supervisor's 999999999-second maximum. If the bundled Perl
55
- supervisor is unavailable, it warns and continues through the existing
56
- per-call watchdog path.
57
-
58
- Run `scripts/dispatch.sh --list` to see the effective table (local overrides win).
59
- When routing is unexpectedly unavailable, run `bin/omnilane doctor` before
60
- changing configuration; it reports state and dependencies without repairing them.
61
- Doctor remains offline unless the operator explicitly adds `--probe V`; that
62
- bounded probe returns metadata only. Use `bin/omnilane benchmark` for a fixed
63
- no-call route plan, and add `--run` only when actual advise-mode comparison calls
64
- were explicitly requested. Neither command changes routing.
65
- Without native context, fallback chains use the first vendor CLI installed,
66
- so the same table works with any subset of subscriptions.
67
-
68
- ## Caller-owned native delegation
69
-
70
- Use explicit current-harness capabilities from the real agent-tool contract:
71
- active harness/vendor, exact supported model/effort combinations, optional known
72
- current model, task modes/workdirs, tools, isolation, and lifecycle. Codex
73
- `collaboration.spawn_agent` has no sandbox/tool/workdir restriction parameters;
74
- it inherits the parent's tools and filesystem. Advertise `shared-inherited` in
75
- both request and matching capability row, with empty tool arrays. Treat
76
- `advise`/`work` and workdir as task intent, not an OS sandbox. Hard isolation is
77
- CLI-only. Same vendor is not same model. Unknown capabilities do not match.
78
- Never inspect credentials or infer support from installed CLIs. Explicit
79
- vendor/model/effort survive native fallback; no next-vendor substitution.
8
+ You are the **commander**: the main loop of Claude Code, Codex, Grok Build or
9
+ Antigravity. omnilane gives you one table that says which model does which kind
10
+ of work, and one command that hands the work to it. Follow the steps in order.
11
+
12
+ **What you keep for yourself:** planning, writing task briefs, reading results,
13
+ acceptance, replies to the operator, `git commit`/`push`, governance edits.
14
+ **Everything else is dispatched**, even when the best model for it is your own.
15
+ A worker executes its one task and never dispatches again.
16
+
17
+ Commands below are written `omnilane …`. If that is not on `PATH`, use
18
+ `<omnilane-repo>/bin/omnilane …`; `omnilane route …` is the same as
19
+ `<omnilane-repo>/scripts/dispatch.sh …`. `/absolute/repo` below always means the
20
+ project the work is about, not omnilane's own directory.
21
+
22
+ **Run every omnilane command as the only command of its tool call.** No
23
+ `; echo $?`, `&&`, pipe or `F=$(…)`. Read output and exit code from the tool
24
+ result; when a later command needs a path that an earlier one printed, type the
25
+ path into it. (Codex cannot be identified through a wrapping shell; see Step 1.)
26
+
27
+ ## Step 1 — Find out who you are
80
28
 
81
29
  ```sh
82
- omnilane route --executor native --native-context /absolute/capability.json --workdir /absolute/repo hardest-coding "Review the change"
83
- omnilane jobs --json complete-native JOB_ID /absolute/completion.json
84
- omnilane jobs --json status JOB_ID
85
- omnilane jobs --json result JOB_ID
30
+ omnilane whoami
86
31
  ```
87
32
 
88
- For explicit reuse, the capability must prove the exact existing agent and its
89
- idle state, and explicitly preserve its existing context. Recheck idle immediately
90
- before `collaboration.followup_task`; completion must match the reuse strategy,
91
- agent ID and backend. Do not substitute an unknown inherited model or reuse a busy
92
- agent. New-agent capacity exhaustion is not success; see `docs/native-executor.md`.
93
-
94
- Route returns **pending handoff JSON**, not a successful agent run. The host calls
95
- its own agent tool with the resolved exact model and effort, passes workdir,
96
- mode, task, and deadline as intent, then ingests the actual agent ID, runtime
97
- vendor/model/effort/harness/backend, outcome, public result, and evidence. An
98
- explicit model override uses `fork_turns: "none"` or bounded positive history;
99
- never combine a model override with `fork_turns: "all"`. An unknown caller
100
- current model may be omitted when the route explicitly selects an exact model
101
- declared by the matching capability row. Never report completion before
102
- ingestion. Native is not a shell executable. The host
103
- passes **no nested delegation** to native workers; shell workers retain their
104
- depth guard. Workers do not create handoffs or call agent-spawn tools.
105
-
106
- Forced CLI retains external workers. Auto explains its CLI fallback reason;
107
- forced native rejects missing/incompatible capability. CLI sessions (background,
108
- live, named threads, explicit single-shot), durable/multi-round work,
109
- vote/arbitration, sysops and unsupported isolation remain CLI-only. The native
110
- deadline is host-enforced, not a shell watchdog. Native cancellation changes
111
- pending state without PID signals; the host separately stops any spawned agent.
112
- Native goal-loop, retry, mailbox, CLI wait and managed-block sync are not included.
113
-
114
- See [native protocol](../../docs/native-executor.md) for strict schemas, terminal
115
- examples, lifecycle and public-data boundaries. The parent alone backs up and
116
- syncs the host's managed `~/.codex/AGENTS.md` block after review.
117
-
118
- ## Lanes (defaults; see routing.yaml for the live values)
119
-
120
- Each lane's **backup** is the next candidate in its `routing.yaml` chain —
121
- what dispatch picks when the first-choice vendor CLI is not installed.
122
-
123
- | Lane | First choice | Backup | When |
33
+ Success prints `omnilane: caller is <vendor>/<model>-<effort> (score N)` and the
34
+ path of a caller-context file. You do not pass that file on: every dispatch reads
35
+ the same identity by itself. N is your **ceiling**: you may dispatch only to a
36
+ target that scores at or below N. Nothing you say raises it. Codex means every
37
+ Codex surface here: CLI, desktop app and IDE (the latter two are "app-server").
38
+
39
+ | `whoami` says | Meaning | Do this |
40
+ |---|---|---|
41
+ | `caller is …` | identified | go to Step 2 |
42
+ | `degraded to its lowest-scored row … (ceiling N)` | Codex turn with no recorded effort (a heartbeat automation, or `codex` launched without `model_reasoning_effort`). You are held to your model's lowest score | carry on; low lanes work. A lane above the floor needs a session launched with an explicit effort, or the operator |
43
+ | `codex direct child CODEX_THREAD_ID is missing … (read from pid N, zsh)` | you wrapped the command. Codex starts `zsh -lc '<command>'`; one simple command becomes that process and is read, but `; echo $?`, `&&`, a pipe or `F=$(…)` leaves a shell in between | run the same omnilane command again as the only command of the tool call |
44
+ | `… rerun … outside the Codex sandbox` | process inspection, `~/.omnilane` writes and networking are blocked in the sandbox | request the unsandboxed run; do not retry inside it with a hand-made file |
45
+ | `no vendor CLI among this process's ancestors` or any other refusal | not readable | report the exact message to the operator. Only if the operator is unavailable: declare the **lowest**-scoring row of your model in a caller-context file (schema at the end) and say so in your report |
46
+
47
+ Never raise a declared effort to unblock a target. Never pass
48
+ `--operator-asserted-human` for yourself: it is the human operator's statement.
49
+
50
+ ## Step 2 — Pick the lane
51
+
52
+ Split the work into subtasks; give each one lane. `omnilane list` shows the live
53
+ table (local overrides win). The backup is what dispatch uses when the first
54
+ choice's CLI is not installed. When a task fits two lanes, pick by what failure
55
+ costs: unknown root cause or correctness-critical → `hardest-coding`; a change you
56
+ could specify line by line → `bulk-mechanical`.
57
+
58
+ The table shows no scores, and you cannot tell from it whether a target is within
59
+ your ceiling. Ask: add `--dry-run` to the dispatch in Step 3. It prints the
60
+ decision and calls nothing. A refusal names the lanes you *can* reach (Step 4).
61
+
62
+ | Lane | First choice | Backup | Use for |
124
63
  |---|---|---|---|
125
64
  | hardest-coding | Claude Fable 5.1 (max) | GPT-6 Astra (xhigh) → Grok 4.6 → Gemini 3.8 Flash (High) | Hardest implementation, deep root-cause debug, correctness-critical edits |
126
65
  | bulk-mechanical | GPT-5.6 Sol (high) | Gemini 3.8 Flash (High) → Claude Sonnet 5 (high) | Refactors, migrations, tests, review sweeps — mechanical endurance |
@@ -133,35 +72,269 @@ what dispatch picks when the first-choice vendor CLI is not installed.
133
72
  | fast-agentic | Gemini 3.8 Flash (Low) | GPT-5.6 Luna (high) → Claude Haiku 4.5 | Fast multi-step agentic loops and multimodal checks |
134
73
  | live-search | Grok 4.6 | Gemini 3.8 Flash (High) → Claude Sonnet 5 (high) → off | Realtime X/web search; non-Grok fallbacks provide generic web search, not equivalent X context |
135
74
  | coding-overflow | Grok 4.6 | Gemini 3.8 Flash (High) → Kimi K3 → Qwen3 Coder Plus → OpenCode → off | Explicit Codex-quota relief; no automatic cross-vendor retry after provider failure |
136
- | arbitrate | off (opt-in vote panel) | — | Disabled by default. Enable with `arbitrate: vote codex,claude,grok -` in routing.local.yaml or via the configurator (any 1-4 voters). One quota hit PER VOTER PER ROUND; you chair: read the opinions and own the decision. Effort field 2 = debate round (voters rebut each other) |
137
-
138
- Claude Fable 5.1 leads the current hardest-coding, hard-judgment, and
139
- taste-final defaults at task-specific max/xhigh efforts. GPT-6 Astra is the
140
- Codex-family fallback and independent-review path. Fable max is the quality-first prompt-level controller. Opus high/xhigh is
141
- the balanced controller/independent-review option; Astra is the existing-
142
- Codex-quota backup/reviewer. These are role recommendations, not a lane or
143
- automatic selector. Opus remains explicitly selectable and in long-context
144
- fallback.
145
-
146
- Astra defaults to `xhigh` on the high-difficulty lanes. For an explicitly needed
147
- upgrade, use `--vendor codex --effort max`; no automatic risk classification or
148
- failure-triggered effort escalation is added. AA API task costs do not prove
149
- subscription-quota savings.
150
-
151
- ## Natural-language consultation
152
-
153
- Users may speak normally; they do not need lane names.
154
-
155
- 1. Capability-only question (`which model`, `what can Claude do`, `哪個模型`,
156
- `誰適合`) → classify the need, then answer with the first available model
157
- shown for that lane by `dispatch.sh --list`; do not dispatch unless execution
158
- is also requested.
159
- 2. Generic vendor name (`Claude`, `Codex`, `Grok`, `Gemini`, `OpenCode`) → run
160
- `dispatch.sh --vendor <vendor> consult "<task>"`.
161
- 3. Canonical model alias → pass its vendor, model, and effort from the table
162
- below. Never silently substitute another model family.
163
- 4. No named target → classify into an existing lane and dispatch normally.
164
- 5. Unknown or ambiguous nickname → ask for clarification; do not guess or run.
75
+ | arbitrate | off (opt-in vote panel) | — | Disabled by default. The operator enables it with `arbitrate: vote codex,claude,grok -` in routing.local.yaml (1-4 voters; a `2` in place of the final `-` adds a rebuttal round). One quota hit PER VOTER PER ROUND; you chair and own the decision |
76
+
77
+ Astra defaults to `xhigh` on the hard lanes; ask for more only explicitly with
78
+ `--vendor codex --effort max`. There is no automatic effort escalation, and a
79
+ higher effort never bypasses your ceiling.
80
+
81
+ **When the operator names a model or asks a question:**
82
+
83
+ 1. "Which model is good at X?" → answer from `omnilane list` (reading the table is your own work); do **not** dispatch.
84
+ 2. A vendor name (`Claude`, `Codex`, `Grok`, `Gemini`, `OpenCode`) → `omnilane route --vendor <vendor> consult "<task>"`.
85
+ 3. A model alias → pass its vendor, model and effort from the alias table at the end. Never substitute another family.
86
+ 4. No named target → classify into a lane and dispatch.
87
+ 5. Unknown or ambiguous nickname → ask; do not guess or run.
88
+
89
+ Never drop `--vendor` to get a fallback; a missing explicit target fails clearly.
90
+
91
+ ## Step 3 — Dispatch
92
+
93
+ **Read-only work** (reviews, questions, scans, second opinions) — the default
94
+ `advise` mode, 600 s per CLI call:
95
+
96
+ ```sh
97
+ omnilane route <lane> "<task brief>"
98
+ ```
99
+
100
+ **Anything that edits files, runs tests, builds or deploys** — all three flags,
101
+ every time. Without them you get a read-only worker that produces nothing:
102
+
103
+ ```sh
104
+ omnilane route --mode work --workdir /absolute/repo --timeout 3600 <lane> "<task brief>"
105
+ ```
106
+
107
+ Without `--background` the command blocks and prints the worker's answer on
108
+ stdout. With it, stdout is just the job id; collect the answer in Step 5.
109
+ `--workdir` defaults to your current directory; a read-only worker can read it.
110
+ Put what the worker needs into the brief, or name the files by absolute path.
111
+
112
+ Every task brief states the goal, the files, what must not be touched, the
113
+ acceptance criteria and the **exact verification command**. "Done" without
114
+ evidence is not accepted. For example:
115
+
116
+ ```text
117
+ Goal: find which of the 40 files under /srv/app/logs/2026-09-19/ contain "ECONNRESET upstream".
118
+ Do not modify, move or delete anything.
119
+ Report: one line per matching file with its match count, then the total.
120
+ Verify with: grep -c "ECONNRESET upstream" /srv/app/logs/2026-09-19/*.log
121
+ ```
122
+
123
+ Useful flags:
124
+
125
+ | Flag | When |
126
+ |---|---|
127
+ | `--background` | long tasks; returns a job id at once |
128
+ | `--timeout N` | cap for each CLI call (raise to 1200+ for hard-judgment / long-context) |
129
+ | `--job-timeout N` | one fuse over the whole dispatch incl. lock wait, retries, voters; off by default, 7200–14400 for full-repo audits, expiry returns 124 |
130
+ | `--thread NAME` | later dispatches must keep earlier context; a thread pins vendor, model, effort and workdir (`omnilane jobs threads`, `threads show NAME`, `threads rm NAME`) |
131
+ | `--vendor V [--model M] [--effort E]` | an explicit target; still subject to your ceiling |
132
+ | `--live` | keep a Codex or Grok background job open for follow-up messages (Claude and Gemini background jobs already are) |
133
+ | `--caller-context FILE` | only when you were handed a context as a worker, or for the last-resort fallback in Step 1 |
134
+ | `--mode sysops` | unrestricted native policy for service/host operations; per dispatch only, never a default, and the brief must name the allowed operations |
135
+ | `--dry-run` | print the decision without calling anything |
136
+
137
+ `work` confines file and command changes to `--workdir` and disables the
138
+ worker's tool networking (not the model connection); `advise` is read-only with
139
+ the vendor's native web tools. Neither turns into `sysops` by itself. macOS Grok
140
+ `work` is blocked (its child-network isolation is Linux-only). Same-directory
141
+ Codex dispatches are serialized by a lock; do not parallelize them yourself.
142
+
143
+ ### When the target is your own harness, use your own sub-agent tool
144
+
145
+ If your harness has a sub-agent tool, prefer it over an external CLI for work
146
+ your own vendor's model will do: no second login, no overlay, no process to
147
+ supervise. It is a preference, not a rule. The plain `omnilane route …` of the
148
+ previous section always remains correct, and when it sends your own vendor's
149
+ model out through the CLI, dispatch prints a notice on stderr (not a refusal)
150
+ with the command that would have kept it inside. Two ways to stay inside:
151
+
152
+ **A. A worker on your own runtime — `--inherit`.** Your sub-agent, spawned with
153
+ **no model and no effort argument**, runs what you run, so it scores what you
154
+ score and can never be an upward dispatch. It needs no vendor CLI and no
155
+ transport overlay, and it works when your effort is unrecorded. Use it for
156
+ diagnosis, evidence gathering and work your own model is good enough for.
157
+
158
+ ```sh
159
+ omnilane native-context --workdir /absolute/repo --inherits-caller-runtime
160
+ omnilane route --inherit --native-context /path/printed/above --workdir /absolute/repo <lane> "<task brief>"
161
+ ```
162
+
163
+ Pass `--inherits-caller-runtime` only if it is true of your tool:
164
+
165
+ | Harness | True when |
166
+ |---|---|
167
+ | Claude Code | you call `Agent` with no `model` argument, the agent type's definition sets neither `model` (other than `inherit`) nor `effort`, and `CLAUDE_CODE_SUBAGENT_MODEL` is unset. The built-in general-purpose agent qualifies; a custom or plugin agent with its own frontmatter does not |
168
+ | Codex | you call `collaboration.spawn_agent` with no model and no effort |
169
+ | Grok Build | model inheritance is documented (`spawn_subagent`, bundled `general-purpose` is `model: inherit`, no `[subagents.models]` pin); effort inheritance is not verified |
170
+ | Antigravity | no sub-agent tool verified; do not assert it |
171
+
172
+ Here the lane is only a label for what kind of work it is; it is not checked
173
+ against your ceiling, because no lane target runs. The handoff says
174
+ `effort: "inherited"`, `model_override: false` and
175
+ **`satisfies_lane_target: false`**, and you report it that way: "my own sub-agent
176
+ did this", never "hardest-coding did this". So it is not a way around a lane that
177
+ needs a stronger model than you: work that needs that model still needs that
178
+ model, and that dispatch is still refused.
179
+
180
+ `--inherit` accepts `--mode work --workdir DIR` and `--timeout N` (the deadline
181
+ you enforce on the sub-agent; default 600). It takes no
182
+ `--vendor`/`--model`/`--effort`, has no CLI fallback, and refuses `--background`,
183
+ `--live`, `--thread`, `--mode sysops`, `--job-timeout` and `--idle-timeout`.
184
+
185
+ If `whoami` cannot read you even when run alone, `--inherit` still works on your
186
+ own statement — add `--vendor <yours> --model <the model you really run>` to
187
+ `native-context`. The handoff then says `caller_identity_verified: false` and
188
+ carries no ceiling; completion is checked against what you stated. Lane dispatch
189
+ stays refused while you are unread; report that instead of guessing an identity.
190
+
191
+ **B. A specific model your sub-agent tool can select.** Describe your tool's real
192
+ contract in a capability file (start from `omnilane native-context`, add rows for
193
+ the exact model/effort pairs your tool accepts) and pass it:
194
+
195
+ ```sh
196
+ omnilane route --native-context /absolute/capability.json --workdir /absolute/repo <lane> "<task brief>"
197
+ ```
198
+
199
+ A row matches only on the exact model, effort, mode, workdir, tools, isolation
200
+ (`shared-inherited`: a native sub-agent shares your tools and filesystem, there
201
+ is no OS sandbox) and lifecycle (`single-shot`). Same vendor is not same model;
202
+ nothing is inferred from installed CLIs. `--executor native` fails instead of
203
+ falling back; `--executor cli` forces the external CLI. With a Codex model
204
+ override use `fork_turns: "none"` or a bounded count, never `"all"`.
205
+
206
+ **Both A and B print a PENDING handoff as one JSON object on stdout, not a
207
+ result.** Its `job_id`, `task`, `workdir`, `mode`, `timeout` and
208
+ `worker_contract` are what you need. You then:
209
+
210
+ 1. Call your own sub-agent tool with the handoff's task, workdir, mode and
211
+ deadline, and tell it: no nested delegation.
212
+ 2. Verify its result yourself.
213
+ 3. Write a completion file and ingest it:
214
+
215
+ ```json
216
+ {"schema_version": 1, "job_id": "<from the handoff>", "agent_id": "<the real agent id>",
217
+ "runtime": {"vendor": "<v>", "model": "<exact model>", "effort": "<observed, or \"unknown\">",
218
+ "harness": "<as in the handoff>", "backend": "<your agent tool's name>"},
219
+ "outcome": "success", "result": "<public summary, not raw logs>",
220
+ "evidence": ["<command/result or artifact reference>"]}
221
+ ```
222
+
223
+ ```sh
224
+ omnilane jobs --json complete-native JOB_ID /absolute/completion.json
225
+ omnilane jobs --json status JOB_ID
226
+ ```
227
+
228
+ `outcome` is `"success"` or `"failure"`; report a failure as a failure. `vendor`,
229
+ `model` and `harness` must equal the handoff's; a mismatch is rejected.
230
+ Never report completion before ingestion. Background, live, named-thread,
231
+ multi-round, vote, `sysops` and hard-isolation work stays on the CLI path. Reuse
232
+ of an existing agent, cancellation and the strict schemas are in
233
+ [docs/native-executor.md](../../docs/native-executor.md).
234
+
235
+ ## Step 4 — If dispatch refuses
236
+
237
+ A refusal is one JSON line on stderr and no job exists. Read `failed_gate`,
238
+ `reason`, `next_command` and `eligible_lanes`, and act on them instead of guessing:
239
+
240
+ ```json
241
+ {"allowed": false, "code": "target-above-effective-ceiling", "failed_gate": "downward-ceiling",
242
+ "required_caller_effort": "xhigh", "next_command": "omnilane list",
243
+ "lane_requirement": {"lane": "hardest-coding", "target": "codex/gpt-6-astra-xhigh", "score": 54},
244
+ "eligible_lanes": [{"lane": "bulk-mechanical", "target": "codex/gpt-5-6-sol-high", "score": 48, "transport_verified": true}]}
245
+ ```
246
+
247
+ `eligible_lanes` is every lane you can reach right now. Moving to one of them is
248
+ right only when that lane also fits the work. If the work needs the refused
249
+ lane's quality, do not downgrade it: report the refusal, `required_caller_effort`
250
+ and the eligible lanes to the operator and wait. The same holds when your
251
+ operator's rules say a reroute needs their approval.
252
+
253
+ | `failed_gate` / `code` | Meaning | Do this |
254
+ |---|---|---|
255
+ | `caller-identity` · `missing-caller-context` | nobody could tell who is asking | run `omnilane whoami` alone and apply Step 1 |
256
+ | `caller-identity` · `invalid-degraded-caller` | a context file is marked `effort_unverified` but is not its model's lowest row | use the file `whoami` writes; do not edit it |
257
+ | `downward-ceiling` · `target-above-effective-ceiling` | the target scores above you | a fitting lane from `eligible_lanes`, or report `required_caller_effort` to the operator |
258
+ | `target-transport` · `runtime-mapping-unverified` / `unknown-target-runtime` | you are identified; this host has not (or no longer) proven that target. Usually a vendor CLI updated itself | tell the operator to run `omnilane resign`; meanwhile a fitting lane from `eligible_lanes` whose `transport_verified` is true |
259
+ | `native-capability` · `native-inherit-unavailable` | your capability file does not allow the inherited worker; `reason` says why | fix the file (`omnilane native-context …`) or drop the CLI-only flag named in `reason` |
260
+ | `invalid-policy-input` "transport contract evidence changed" | the overlay will not load; nothing is wrong with you or your target | `omnilane doctor`, then the operator runs `omnilane resign` |
261
+ | `inherit-requires-model-caller` | a human has no runtime to inherit | dispatch a lane |
262
+
263
+ `omnilane resign --approve …`, `--record-signers` and `--trust-adhoc …` are
264
+ operator actions. A model never runs them. After two failed attempts at a task, reassess the scope;
265
+ an upward move needs the human. On vendor quota exhaustion (429, "stream
266
+ disconnected", usage limit) send mid-tier coding through `coding-overflow`;
267
+ never silently downgrade `hardest-coding` — wait or escalate.
268
+
269
+ ## Step 5 — Collect, verify, close
270
+
271
+ A job id, a PENDING handoff, exit 0 or "scheduled" is **not** completion.
272
+
273
+ ```sh
274
+ omnilane jobs wait JOB_ID # block until it ends
275
+ omnilane jobs status JOB_ID
276
+ omnilane jobs result JOB_ID # the worker's public result
277
+ ```
278
+
279
+ Read the result, run the verification command from your brief (or send a second
280
+ worker to), and only then report. Other job commands: `cancel JOB_ID`;
281
+ `send JOB_ID "<text>"` and `close JOB_ID` for a live session (Claude and Gemini
282
+ background jobs stay resident; Codex and Grok are single-shot unless `--live`,
283
+ and Grok live needs `--mode sysops`); `retry JOB_ID --caller-context FILE` (keeps
284
+ the original target and never inherits an earlier human exemption);
285
+ `recommend`, `stats`, `audit` (read-only, never change routing);
286
+ `prune --keep N [--apply]`.
287
+
288
+ How you hear about a background job finishing:
289
+
290
+ - **Codex:** before ending a turn with unobserved jobs, register an active
291
+ callback: `scripts/completion-wakeup.py prepare` with the real controller
292
+ thread, host, a unique run id and the exact job list, then the app's
293
+ `automation_update` heartbeat tool, then record the receipt. On callback:
294
+ `poll`, acknowledge, verify, acknowledge acceptance, and close the automation
295
+ when every tracked job is handled. Details: `docs/completion-wakeup.md`.
296
+ - **Claude Code:** the completion inbox arrives with the *next* prompt; it does
297
+ not wake an idle controller. With nothing else to do, stay on `omnilane jobs wait`.
298
+ - **Native sub-agents:** the host's own callback gives you the result; still
299
+ ingest and verify it.
300
+
301
+ When the next step depends on the previous result, group the dispatches:
302
+ `omnilane goal open "<objective>" --workdir DIR`, then `goal dispatch <id> …`,
303
+ `goal note`, `goal status`, `goal close --summary`. A single obvious task is
304
+ dispatched directly.
305
+
306
+ `omnilane doctor` reports health without repairing anything (offline unless
307
+ `--probe V`). `omnilane benchmark` prints a no-call route plan. `omnilane ui
308
+ start|status|url|stop` runs a read-only board of jobs; it cannot dispatch.
309
+
310
+ ## Notes for your main model
311
+
312
+ These never widen what you may execute yourself. With no matching row, use the
313
+ lane table; do not assume an older model is equivalent.
314
+
315
+ - **Claude Fable 5.1:** quality-first controller. Hardest coding at max, judgment
316
+ and taste at xhigh. Send bulk work to Sol high, long/fast work to Gemini 3.8
317
+ Flash, and use Astra as an independent review path.
318
+ - **Claude Opus 5:** balanced controller and independent reviewer when explicitly
319
+ selected (`high`, or `xhigh` for deeper review); Claude's long-context fallback.
320
+ - **Claude Sonnet:** coordination, tools, mid-tier coding; fallback in
321
+ bulk-mechanical and live-search. Never self-assign top judgment or hardest coding.
322
+ - **GPT Astra:** controller backup and independent reviewer. Resolve your real
323
+ effort first; an explicit higher-effort request does not bypass the ceiling.
324
+ - **GPT Sol / Terra / Luna:** mechanical work, long context and triage
325
+ respectively, only within your exact ceiling. Do not infer eligibility from the
326
+ family name, and do not promote Luna's low price into correctness-critical work.
327
+ - **Grok 4.6:** live-search and coding-overflow are yours, plus fallback in hard
328
+ lanes. Verify API signatures and cited facts before shipping.
329
+ - **Gemini 3.8 Flash:** long-context at medium, fast-agentic and triage at low,
330
+ bulk/overflow/web fallbacks at high. Do not infer visual taste or controller
331
+ authority from coding benchmarks.
332
+ - **Gemini 3.1 Pro:** directly selectable, not promoted; route hard coding and
333
+ judgment to the stronger lanes.
334
+
335
+ ## Reference
336
+
337
+ ### Model aliases
165
338
 
166
339
  | Alias | Vendor | Model | Effort |
167
340
  |---|---|---|---|
@@ -184,333 +357,68 @@ Users may speak normally; they do not need lane names.
184
357
  | OpenCode | opencode | provider/model form, or `-` for its own default | - |
185
358
  | OpenRouter | openrouter | explicit OpenRouter slug (e.g. anthropic/claude-sonnet-5) | - |
186
359
 
187
- OpenCode is the multi-provider aggregator CLI (75+ providers): work-capable,
188
- last resort in coding-overflow. OpenRouter is direct-API — no CLI needed, only
189
- `OPENROUTER_API_KEY` — and is **advise/consult only** (it cannot edit files);
190
- its model slug is mandatory. "Ask <any hosted model> via OpenRouter" →
191
- `dispatch.sh --vendor openrouter --model <slug> consult "<task>"`.
192
-
193
- Examples:
194
-
195
- - Ask Opus to challenge this architecture →
196
- `dispatch.sh --vendor claude --model claude-opus-5 --effort high consult "challenge this architecture"`
197
- - 請 Grok 查最新公開資訊 →
198
- `dispatch.sh --vendor grok consult "查最新公開資訊"`
199
- - 哪個模型適合檢查大型 repo? → answer only; do not dispatch.
200
-
201
- Consultation defaults to `advise`. Use `--mode work --workdir <dir>` only for
202
- an explicit edit request. Missing explicit targets fail clearly; never remove
203
- `--vendor` to obtain a fallback.
204
-
205
- ## Live UI is observation only
206
-
207
- The optional Live UI is a read-only observer, not a prompt or dispatch path.
208
- It displays existing jobs' `task.txt` and public `out.txt`, but never raw logs;
209
- its history search and state filters can export only the currently visible public
210
- metadata as local JSON; tokens and task/result bodies are excluded from export.
211
- it cannot interpret natural language, choose routes, dispatch, retry, cancel,
212
- delete jobs, or edit configuration. Natural-language interpretation and
213
- dispatch stay in this skill and the CLI. Manage the local board with
214
- `omnilane ui start|status|url|stop`, and stop it when monitoring is finished.
215
-
216
- ## Job lifecycle defaults
217
-
218
- - **Active completion (Codex)**: after background CLI dispatch, use
219
- `scripts/completion-wakeup.py prepare` with the actual controller app thread,
220
- host, unique run ID and exact job allowlist. Use the returned handoff with the
221
- app `automation_update` heartbeat tool (reuse an existing monitor), then record
222
- the actual registration receipt. Do this before ending a turn with unobserved
223
- jobs. On callback, `poll`, keep unchanged state quiet, acknowledge delivery,
224
- inspect public results and verify, then acknowledge acceptance with evidence.
225
- Pause the real automation and record `closed` after all tracked events are
226
- handled. Never reuse a historical run ID or infer delivery from registration.
227
- See `docs/completion-wakeup.md` for exact commands and receipt schemas.
228
- - **Other completion surfaces**: native agent callbacks provide the host result;
229
- still ingest and verify it. Claude's `UserPromptSubmit` inbox is passive and
230
- requires another prompt; it does not wake an idle controller. If no supported
231
- active callback exists, keep the controller active with `scripts/jobs.sh wait`
232
- and resume acceptance on return rather than asking the user to check again.
233
- - **Live mailbox**: Claude and Gemini retain automatic resident background
234
- sessions for supported modes. Codex and Grok remain single-shot by default;
235
- explicit `--live` opts in. Grok live requires explicit `--mode sysops` because
236
- ACP has no enforceable restricted-mode boundary. Send follow-up instructions
237
- with `scripts/jobs.sh send <id> "<text>"` and finish with
238
- `scripts/jobs.sh close <id>`. `--single-shot` forces one-shot execution.
239
- - **Goal orchestration**: when the next step depends on the previous result,
240
- wrap the dispatches in `omnilane goal open "<objective>" --workdir DIR`, then
241
- `goal dispatch <goal-id> ...`, `goal note`, `goal status`, `goal close --summary`.
242
- Budgets are unlimited unless `--budget-jobs` / `--budget-seconds` is passed.
243
- A single obvious task is dispatched directly, never through a goal.
244
- - **Job hygiene**: `scripts/jobs.sh cancel <id>` stops a runaway job.
245
- `stats`, `recommend`, and `audit` are read-only and never change routing.
246
-
247
- ## Rules
248
-
249
- - **Dispatch in `advise` mode by default** (read-only worker). Use `--mode work`
250
- only when the worker must edit files, and give it an explicit `--workdir`.
251
- - **Mode contract**: `advise` is read-only with supported native web tools;
252
- `work` confines file/command changes to explicit `--workdir` and disables
253
- agent-tool networking, not the model connection. Codex and Claude have
254
- distinct policies for these modes. Agy 1.1.27 work has bounded new/resume
255
- acceptance with native sandboxed commands and four validated tools; external
256
- temp/cache reads are also restricted. A separate two-turn work live/FIFO
257
- check passed readback, outside-write denial and normal close. macOS Grok work remains blocked because native child-network
258
- isolation is Linux-only. Do not turn gaps into sysops implicitly or claim
259
- every provider/mode/session path has passed the runtime matrix.
260
- - **Agy work tools** are `view_file`, `write_to_file`, `run_command`, and `finish`.
261
- The native `commandExecutionPolicy: sandbox`, `--sandbox`, and
262
- `proceed-in-sandbox` policy permits tested workspace edits/builds and denies
263
- tested outside writes, shell networking and explicit unsandboxed execution.
264
- Settings are rewritten explicitly before each start/resume: native omission
265
- of false/empty fields has not been proven default-equivalent. Workspace-local
266
- caches and the verified empty owned policy directory remain; external cached
267
- dependencies may be inaccessible, and the tested successful C build still
268
- emitted an xcrun default-cache denial warning. See the dated capability notes
269
- for the exact evidence boundary; complete effective SBPL was not captured.
270
- - **`--mode sysops`** explicitly selects unrestricted native policies for
271
- Codex, Claude, Grok, and Agy; it is not an alias for work. It is a per-dispatch
272
- opt-in, never a lane default, and task text must name the allowed operations.
273
- Codex `work`/`sysops` supports non-Git directories through
274
- `--skip-git-repo-check`. Without an existing whole-job timeout, dispatch
275
- adds one when its supervisor is available; otherwise it warns and retains
276
- the per-call watchdog path.
277
- The CLI defaults an omitted `--workdir` to the caller’s current directory;
278
- task briefs must still specify it explicitly. The MCP work interface
279
- separately requires an explicit `workdir`.
280
- - **Grok advise web tools** use internal `web_search` / `web_fetch` selectors,
281
- while permission rules keep their native `WebSearch` / `WebFetch` class names.
282
- The complete single-shot `plain` path has real search, fetched-page, and native
283
- denied-write evidence on Grok 1.0.13. MCP readiness is job-local because this
284
- mode denies MCPTool; hooks and their security checks remain enabled. A caller
285
- supplied nonempty `CONTEXT_MODE_MCP_SENTINEL_DIR` is a conflict and stops before provider
286
- startup rather than being overwritten. Do not extend this result to restricted
287
- live or macOS work.
288
- - **Every dispatched task states acceptance criteria and the exact verification
289
- command.** Do not accept "done" without evidence.
290
- - **No nested dispatch**: workers must not fan out again (enforced via
291
- `OMNILANE_DEPTH`). Escalate back to the main loop instead.
292
- - **Same-directory codex dispatches are serialized automatically** (lock);
293
- do not try to parallelize them yourself.
294
- - After two failed attempts, reassess scope and retry only an eligible exact configuration.
295
- An upward AA move requires the human to take over; a model cannot approve its own uplift.
296
- - Vendor quota exhausted (429 / "stream disconnected" / usage-limit message):
297
- send mid-tier coding through coding-overflow instead; never silently downgrade
298
- hardest-coding — wait or escalate to the user.
299
-
300
- ## Per-model notes (apply the row matching YOUR main model)
301
-
302
- These notes never expand the commander's reserved self-execution scope. If the verified main model has no matching row, use the configured lane table under the current user request and `rules.d/60`; do not assume the nearest older model is equivalent or silently override vendor/model/effort. If a required capability or explicit model choice is unresolved, report that exact gap before dispatch rather than inventing a fallback.
303
-
304
- - **Claude Fable 5.1 main**: recommended prompt-level controller for
305
- quality-sensitive work (not a lane or automatic selector). Hardest coding
306
- uses max; judgment and taste use xhigh. Dispatch bulk work to Sol high,
307
- long/fast work to Gemini 3.8 Flash, and use Astra as an independent Codex
308
- review path.
309
- - **Claude Opus 5 main**: balanced prompt-level controller and independent
310
- reviewer when explicitly selected (`high`, or `xhigh` for deeper review),
311
- plus Claude long-context fallback. This is a role/opt-in choice, not a new
312
- lane or the current hard-judgment default.
313
- - **Claude Sonnet main**: coordination/tools/mid-tier coding only, plus fallback
314
- duty in bulk-mechanical and live-search; never self-assign top judgment or
315
- hardest implementation.
316
- - **GPT Astra main**: controller backup and independent reviewer. Resolve the
317
- actual caller effort first; select only an exact target at or below its ceiling.
318
- An explicit higher-effort request does not bypass model-level AA policy.
319
- - **GPT Sol main**: mechanical work and constrained UI drafts only within the
320
- exact effective ceiling; return higher-score needs to the operator.
321
- - **GPT Terra main**: long-context and mechanical work only within the exact
322
- effective ceiling; do not infer eligibility from the Terra family label.
323
- - **GPT Luna main**: high-volume triage is delegated at high; do not promote its
324
- low price into correctness-critical or controller work.
325
- - **Grok 4.6 main**: live-search and coding-overflow are yours, plus fallback
326
- duty in hard lanes. Grok effort remains ignored; verify API signatures and
327
- cited facts before shipping.
328
- - **Gemini 3.8 Flash main**: long-context uses medium, fast-agentic and triage
329
- use low, and bulk/overflow/web fallbacks use high. Do not infer visual taste
330
- or controller authority from agent/coding benchmarks.
331
- - **Gemini 3.1 Pro main**: remains directly selectable, but is not promoted by
332
- this refresh; route hard coding and judgment to the stronger configured lanes.
333
-
334
- ## Frozen exact-AA downward gate
335
-
336
- All lane and per-model preferences above are subordinate to this gate, including
337
- explicit vendor/model/effort requests. Supply `--caller-context /absolute/context.json`
338
- with schema_version=1, snapshot_id, kind=model, caller containing exact vendor/model/
339
- effort/reasoning/fallback, and inherited_ceiling. Effective ceiling is the minimum of
340
- that exact frozen score and the inherited ceiling. Targets at or below it are allowed;
341
- unknown identities and unresolved request-selector mappings fail closed. No family,
342
- displayed grade, highest-effort assumption, retry or fallback grants an uplift.
343
-
344
- Build the file before the first dispatch, not after a refusal. Every field is an
345
- exact identity: `caller` must reproduce one `scored_configs` row byte-for-byte,
346
- and `snapshot_id` must equal the registry's own `snapshot.id`.
360
+ OpenCode is a multi-provider CLI, work-capable, last resort in coding-overflow.
361
+ OpenRouter is direct API (`OPENROUTER_API_KEY`), **advise/consult only**, and its
362
+ slug is mandatory: `omnilane route --vendor openrouter --model <slug> consult "<task>"`.
363
+
364
+ Examples: "Ask Opus to challenge this architecture" →
365
+ `omnilane route --vendor claude --model claude-opus-5 --effort high consult "challenge this architecture"`.
366
+ 「請 Grok 查最新公開資訊」→ `omnilane route --vendor grok consult "查最新公開資訊"`.
367
+ 「哪個模型適合檢查大型 repo?」→ answer only.
368
+
369
+ ### How your identity is read
370
+
371
+ Dispatch finds the nearest vendor CLI among your process's ancestors; nearest
372
+ wins, so a Codex worker started by a Claude session is a Codex caller. Claude,
373
+ Grok and Agy are read from their launch flags (`--model`, `--effort`). Codex
374
+ outside app-server is read from `-m`/`--model` or `-c model=…` plus
375
+ `model_reasoning_effort`; a profile is not a selector. Codex app-server ignores
376
+ launch flags and reads the **current turn** instead: `CODEX_THREAD_ID` must match
377
+ between your process and codex's direct child, the rollout
378
+ `$CODEX_HOME/sessions/**/rollout-*-<thread>*.jsonl` most recently written must
379
+ carry that thread id, and its last `turn_context` must name a model and a turn
380
+ that has not ended. Missing, ambiguous or stale evidence refuses; there is no
381
+ config-default or other-thread fallback, and only identity metadata is read,
382
+ never message content. An explicit `--caller-context`, an identity inherited as a
383
+ worker, and the operator's `--operator-asserted-human` all take precedence over
384
+ this process reader; `OMNILANE_AA_CALLER_FROM_PROCESS=0` turns it off. This is host
385
+ request-selector evidence, not proof of the upstream provider's identity.
386
+
387
+ ### The caller-context file
388
+
389
+ Only for the fallback in Step 1, or when you are handed one as a child.
390
+ `caller` must reproduce one `scored_configs` row of `config/aa-model-policy.json`
391
+ exactly, and `snapshot_id` must equal that registry's `snapshot.id`:
347
392
 
348
393
  ```json
349
- {
350
- "schema_version": 1,
351
- "snapshot_id": "<registry snapshot.id>",
352
- "kind": "model",
353
- "caller": {"vendor": "claude", "model": "claude-opus-5", "effort": "high",
354
- "reasoning": "adaptive", "fallback": null},
355
- "inherited_ceiling": 52
356
- }
394
+ {"schema_version": 1, "snapshot_id": "<registry snapshot.id>", "kind": "model",
395
+ "caller": {"vendor": "claude", "model": "claude-opus-5", "effort": "high",
396
+ "reasoning": "adaptive", "fallback": null},
397
+ "inherited_ceiling": 52}
357
398
  ```
358
399
 
359
- Set `inherited_ceiling` to your own row's score when you are the root caller, or
360
- to the ceiling you were handed when you are a child.
361
-
362
- **Your identity is read from the CLI that launched you.** Without explicit or
363
- inherited caller-context, dispatch finds the nearest vendor CLI. Claude, Grok
364
- and Agy retain their launch selectors. Codex outside app-server retains explicit
365
- `-m` / `--model` or `-c model=...` / `--config` selectors; TOML model overrides
366
- require Python 3.11+. A profile is not an explicit model selector.
367
-
368
- Codex app-server always ignores startup selectors, even explicit model flags;
369
- other Codex launches without a model use the same current-turn rollout reader.
370
- It requires matching UUID-shaped `CODEX_THREAD_ID` values in this process and the
371
- codex direct child's initial environment (not text embedded in argv). The rollout
372
- is looked up under `$CODEX_HOME/sessions` (default `~/.codex`) as
373
- `rollout-*-<thread>.jsonl` and, once a thread has been resumed,
374
- `rollout-*-<thread>_<session>.jsonl`; the most recently written match is read and
375
- must have matching `session_meta.id`. The last `turn_context` must provide
376
- non-empty model, effort and turn id, with no later `task_complete`,
377
- `turn_complete` or `turn_aborted` carrying that same turn id. A refusal names
378
- both turn ids and how long ago that rollout was last written.
379
- Missing, ambiguous, malformed or stale evidence refuses: no config defaults,
380
- model-list, archive or other-thread fallback. JSONL is streamed; only identity
381
- metadata and event types reach diagnostics, never message content.
382
-
383
- `omnilane whoami` prints the resulting caller-context path and reports thread
384
- and turn ids for rollout evidence. The existing scored-row resolver still makes
385
- the decision; this is host request-selector evidence, not proof of upstream
386
- provider identity. Nearest wins, including workers launched by another vendor.
387
- Explicit `--caller-context`, inherited identity and `--operator-asserted-human`
388
- retain their precedence; `OMNILANE_AA_CALLER_FROM_PROCESS=0` disables both readers.
389
-
390
- Ancestor lookup still runs first. If it fails under `CODEX_SANDBOX=seatbelt`,
391
- `whoami` explains that process inspection, `~/.omnilane` writes and networking
392
- require rerunning the command outside the Codex sandbox; do not retry with a
393
- caller-context inside that sandbox.
394
-
395
- Only when `omnilane whoami` refuses: ask the operator, or declare the
396
- lowest-scoring row of your model and say so in your report. Understating only
397
- narrows what you may dispatch to, so it fails in the safe direction — but it is
398
- the fallback, not the first move, and an unnecessarily low ceiling silently
399
- closes lanes and pushes the question back onto the operator. Never raise the
400
- declared effort to unblock a refused target, and never assert
401
- `--operator-asserted-human` on your own behalf.
402
-
403
- Three refusal codes mean different things and need different fixes.
404
- `missing-caller-context` means no identity reached the gate: you passed no file
405
- and dispatch could not read one from your launching CLI. Run `omnilane whoami`;
406
- its refusal says exactly why, and that reason is what to fix or report.
407
- `runtime-mapping-unverified` means the file is fine but the *target* has no proven
408
- host-local request selector; that is fixed by a `--transport-overlay` entry backed
409
- by real evidence, never by editing the frozen registry (its sha256 is pinned in
410
- `scripts/lib/aa_policy.py`, so any edit fails the whole gate closed).
411
- `invalid-policy-input` with "transport contract evidence changed" is neither: the
412
- overlay itself will not load, so nothing about your caller or your target is wrong.
413
- Run `omnilane doctor` first — its `transport-overlay` check names the offending
414
- file and the vendor it belongs to. Do not go hunting by hand.
415
-
416
- Upgrading a vendor CLI is the usual cause. The overlay pins the sha256 of each
417
- vendor's executable and runner script, so a new release invalidates that vendor's
418
- selector evidence. Evidence entries carry a `vendor` tag: a tagged entry that
419
- drifts marks only its own vendor stale, and the other three keep dispatching.
420
- Untagged evidence — `probe-manifest.json`, and any overlay built before the tags
421
- existed — still fails the whole gate closed, which is what an unpatched host
422
- looks like. Codex and Claude resolve through version directories
423
- (`releases/0.153.4-…`, `versions/2.1.266`), so their upgrades remove the anchored
424
- file rather than change its digest; both are treated as staleness, not corruption.
425
-
426
- Do not expect these upgrades to be operator actions. agy and grok update
427
- themselves in the background when invoked — agy's own `cli.log` records
428
- `auto_updater.go: Spawned background update process`, and both binaries changed
429
- under a probing session on 2026-09-10, minutes after their first call. Overlay
430
- drift is therefore a routine consequence of using a vendor, not an occasional
431
- maintenance event, which is why per-vendor degradation matters more than it
432
- looks. It also means any test asserting a fixed number of verified live
433
- mappings will go red on its own schedule.
434
-
435
- Because of that, `build_overlay.py` anchors the executable `shutil.which` resolves
436
- rather than a version written into the script. A pinned path drifts out of use
437
- silently: before 0.42.6 the overlay hashed claude `2.1.263` while every dispatch
438
- ran `2.1.266`, so eleven mappings were "verified" against a binary that had not
439
- run for a day.
440
-
441
- Re-signing is a probe, a rebuild, and an install, in that order. Back up
442
- `~/.omnilane/transport-contracts.local.json` first; restoring it is the rollback.
443
- `scripts/lib/probe.py --expect TOKEN [--vendor V] NAME COMMAND…` invokes the CLI
444
- directly through `subprocess`, so it works while the gate is refusing everything —
445
- this is what breaks the deadlock. `scripts/provider-probe.sh` goes through
446
- `dispatch.sh` and therefore through the gate, so it is useless in this state.
447
- Then `scripts/lib/build_overlay.py` rebuilds, and you copy the result over the
448
- live overlay. Verify with a real dispatch on a lane belonging to the vendor you
449
- re-probed; loading the registry in Python is not the runtime surface.
450
-
451
- Keep the sweep where its default `--root` puts it,
452
- `~/.omnilane/transport-evidence/<sweep-id>/`. The rebuilt overlay anchors
453
- `probe-manifest.json` by absolute path as untagged evidence, so a sweep parked
454
- inside a repository is one `git clean -fdx` away from taking every vendor down
455
- at once — the same global refusal a re-signing session is usually trying to end.
456
-
457
- Every mapping carries an `evidence_tier` saying how strongly its probe pinned the
458
- responder. `billed-model` means the provider named the model it charged for —
459
- Claude's `modelUsage`, grok's under `--output-format json`. `client-echo` means
460
- the CLI wrote down the model it asked for — codex's session rollout, agy's
461
- `cli.log` resolver line. `selector-only` means the CLI accepted the selector and
462
- said nothing more. Put plainly: `client-echo` is the CLI's copy of your order,
463
- `billed-model` is the provider's receipt. Neither certifies upstream identity,
464
- but only one of them was written by the party that answered.
465
-
466
- The tier is reported, never enforced. Dispatch still turns on `runtime_verified`
467
- alone, so a mapping that drops to `selector-only` keeps working and simply shows
468
- up in doctor as worth re-probing. Do not add a tier check to the gate: that would
469
- rebuild the failure 0.42.5 removed, where evidence quality could refuse a lane
470
- that runs. The tier is read off the evidence a run produced rather than assigned
471
- per vendor, so a sweep predating 0.42.6 re-judges as `selector-only` and a CLI
472
- that starts reporting a billed model is promoted with no code change.
473
-
474
- Two probe details follow from this. Codex needs `exec --json` (the thread id that
475
- locates the rollout) and must *not* use `--ephemeral`, which suppresses the very
476
- rollout the tier reads. agy needs its own app data directory, prepared exactly
477
- the way `run-gemini.sh` does it — `prepare-agy-mode.py --mode advise` returns a
478
- path relative to `~/.gemini` that is passed as `--app_data_dir=`; the environment
479
- variables that look like they would do this are ignored.
480
-
481
- Never sign a probe you did not read. `probe.py` records a `verdict` because exit
482
- status alone is not evidence: the Claude CLI answers a quota refusal with a JSON
483
- body carrying `is_error`, and it accepts an unknown `--effort` by silently using
484
- the default, returning exit 0, the right `modelUsage`, and the expected token
485
- with only a stderr warning to show for it. Effort is half of a scored identity,
486
- so that path would certify a mapping at the wrong tier. Configurations whose
487
- probes failed are recorded in the overlay's `unproven[]` and surfaced by doctor
488
- instead of vanishing — six Fable rows sat unusable for two days in September
489
- 2026 because a 429 quota refusal left no trace anywhere. A refused probe is not
490
- always transient: re-probing those six two days later returned the same 429, so
491
- an `unproven[]` entry can mean the account, not the moment. Read the reason
492
- before assuming a retry will clear it.
493
-
494
- A `--transport-overlay /absolute/overlay.json` may prove a small set of host-local
495
- request selectors using exact identities and hashed local contract evidence. It does
496
- not change frozen AA scores or certify upstream provider identity. The explicit
497
- `--operator-asserted-human` exemption is cooperative operator metadata, not automatic
498
- model detection or OS authentication; model callers must not assert it for themselves.
499
-
500
- CLI jobs atomically save an original authorizer, exact child caller context, decision,
501
- and registry snapshot. Provider processes receive the child identity, not the parent's.
502
- Retries preserve original target config, check stored hashes, and intersect the
503
- current exact caller score/inherited ceiling with the original authorizer ceiling.
504
- Use `omnilane jobs retry ID --caller-context FILE`; missing current identity fails
505
- closed, and a model retry never inherits an earlier human exemption. Native handoffs carry the same decision plus a job-owned
506
- `worker_contract.caller_context_path`; pass that context to the native child together
507
- with the no-nested-dispatch requirement. `OMNILANE_DEPTH` remains an independent guard.
508
-
509
- A background job or PENDING native handoff is not completion. Observe its terminal
510
- result and acceptance evidence before closing the controller task. Completion wakeup
511
- availability must be separately verified; never claim delivery from scheduling alone.
512
-
513
- For Gemini `model_id_encoded_effort` selectors, the proven native model ID encodes
514
- the AA effort. An absent parity effort or the matching effort is accepted; a conflicting
515
- parity effort is rejected. Do not represent a discarded EFFORT parameter as an active
516
- provider setting. Frozen reasoning=`unspecified` remains a literal, not a wildcard.
400
+ `inherited_ceiling` is your own row's score when you are the root caller, or the
401
+ ceiling you were handed when you are a child. Your effective ceiling is the lower
402
+ of the two. Pass it as `--caller-context /absolute/context.json`. Unknown
403
+ identities fail closed; no family name, displayed grade, retry or fallback grants
404
+ an uplift. The registry is frozen: its sha256 is pinned in
405
+ `scripts/lib/aa_policy.py`, so editing it fails the whole gate.
406
+
407
+ ### What a job records
408
+
409
+ A CLI job stores the original authorizer, the narrowed child identity, the
410
+ decision and the registry snapshot; the provider process receives the child
411
+ identity, not yours. A retry keeps the original target and intersects your
412
+ current ceiling with the original one. A native handoff carries the same decision
413
+ and `worker_contract.caller_context_path`; give that context to the sub-agent
414
+ with the no-nested-dispatch rule. `OMNILANE_DEPTH` is an independent guard:
415
+ workers that try to dispatch are stopped.
416
+
417
+ For Gemini, the model id encodes the effort (`gemini-3.8-flash-high`); a matching
418
+ or absent `--effort` is accepted, a conflicting one is rejected.
419
+
420
+ ### For the operator, not the model
421
+
422
+ Why the transport overlay goes stale, how `omnilane resign` re-signs it, evidence
423
+ tiers and hand re-signing: [docs/transport-overlay.md](../../docs/transport-overlay.md).
424
+ First install and the daily re-sign job: the README.