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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +177 -1
- package/README.ja.md +169 -20
- package/README.ko.md +169 -20
- package/README.md +270 -61
- package/README.zh-CN.md +169 -19
- package/README.zh-TW.md +159 -41
- package/VERSION +1 -1
- package/bin/omnilane +29 -0
- package/completions/_omnilane +1 -1
- package/completions/omnilane.bash +1 -1
- package/completions/omnilane.fish +2 -0
- package/docs/native-executor.md +59 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/dispatch.sh +54 -4
- package/scripts/doctor.sh +7 -1
- package/scripts/lib/aa_lanes.py +135 -0
- package/scripts/lib/aa_policy.py +154 -1
- package/scripts/lib/build_overlay.py +45 -18
- package/scripts/lib/caller_identity.py +75 -13
- package/scripts/lib/cli_provenance.py +82 -0
- package/scripts/lib/native.py +107 -2
- package/scripts/lib/native_context.py +145 -0
- package/scripts/lib/overlay_health.py +24 -2
- package/scripts/lib/probe.py +2 -0
- package/scripts/lib/probe_sweep.py +176 -0
- package/scripts/lib/resign.py +475 -0
- package/scripts/release-audit.sh +31 -0
- package/skills/omnilane/SKILL.md +375 -467
package/skills/omnilane/SKILL.md
CHANGED
|
@@ -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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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.
|