@sabaiway/agent-workflow-kit 14.20.0 → 14.22.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +2 -2
  3. package/SKILL.md +1 -1
  4. package/bridges/antigravity-cli-bridge/SKILL.md +38 -50
  5. package/bridges/antigravity-cli-bridge/bin/agy-model-posture.test.mjs +257 -0
  6. package/bridges/antigravity-cli-bridge/bin/agy-review-harness.test.mjs +10 -3
  7. package/bridges/antigravity-cli-bridge/bin/agy-review-honesty.test.mjs +20 -21
  8. package/bridges/antigravity-cli-bridge/bin/agy-review-model-screen.test.mjs +4 -4
  9. package/bridges/antigravity-cli-bridge/bin/agy-review.sh +120 -48
  10. package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +22 -62
  11. package/bridges/antigravity-cli-bridge/bin/agy.sh +109 -16
  12. package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +5 -5
  13. package/bridges/antigravity-cli-bridge/capability.json +14 -7
  14. package/bridges/antigravity-cli-bridge/references/driving-agy.md +16 -20
  15. package/bridges/antigravity-cli-bridge/references/models-and-flags.md +10 -27
  16. package/bridges/codex-cli-bridge/SKILL.md +51 -49
  17. package/bridges/codex-cli-bridge/bin/codex-exec.sh +145 -46
  18. package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +28 -55
  19. package/bridges/codex-cli-bridge/bin/codex-model-posture.test.mjs +371 -0
  20. package/bridges/codex-cli-bridge/bin/codex-review.sh +134 -36
  21. package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +33 -45
  22. package/bridges/codex-cli-bridge/capability.json +22 -8
  23. package/bridges/codex-cli-bridge/references/driving-codex.md +18 -15
  24. package/bridges/codex-cli-bridge/references/sandbox-and-flags.md +16 -12
  25. package/bridges/codex-cli-bridge/setup/README.md +3 -3
  26. package/capability.json +1 -1
  27. package/package.json +1 -1
  28. package/references/authoring/TASK_TEMPLATE.md +11 -16
  29. package/references/modes/agents.md +2 -2
  30. package/references/modes/bridge-settings.md +10 -7
  31. package/references/modes/procedures.md +7 -7
  32. package/references/modes/recipes.md +2 -2
  33. package/references/modes/review-state.md +1 -1
  34. package/references/modes/set-recipe.md +1 -1
  35. package/references/modes/tier.md +1 -1
  36. package/references/modes/velocity.md +1 -1
  37. package/references/reference-profile.json +1 -1
  38. package/references/templates/SPEC_TEMPLATE.md +2 -1
  39. package/references/templates/agent_rules.md +7 -7
  40. package/tools/bridge-catalog.mjs +114 -0
  41. package/tools/bridge-posture.mjs +11 -2
  42. package/tools/bridge-settings-read.mjs +41 -5
  43. package/tools/bridge-settings.mjs +111 -23
  44. package/tools/carriers.mjs +6 -4
  45. package/tools/cheap-agents.mjs +1 -1
  46. package/tools/detect-backends.mjs +6 -6
  47. package/tools/family-registry.mjs +3 -3
  48. package/tools/held-session.mjs +1 -33
  49. package/tools/manifest/schema.md +1 -1
  50. package/tools/manifest/validate.mjs +3 -2
  51. package/tools/procedures.mjs +86 -116
  52. package/tools/recipes.mjs +2 -2
  53. package/tools/review-state.mjs +1 -1
  54. package/tools/rules-regions.mjs +2 -1
  55. package/tools/tier-guide-facts.mjs +145 -159
  56. package/tools/tier-guide.mjs +8 -14
@@ -2,7 +2,7 @@
2
2
  name: codex-cli-bridge
3
3
  description: Delegate work to the OpenAI Codex CLI (`codex`) under a ChatGPT subscription — run plan/instruction EXECUTION in a sandboxed workspace, or get a read-only ADVISORY review of a plan or working-tree diff — as a second delegated-execution backend beside Antigravity. Use when the user wants to hand a bounded coding task or plan to `codex exec`, get a second-opinion review from codex, install or authenticate Codex CLI, understand its sandbox/network/approval policy, drive codex efficiently from the main agent (exec vs review, resume, the commit boundary), bridge project context (`AGENTS.md`) into codex, or troubleshoot codex flags, models, auth, or its no-TTY headless behaviour.
4
4
  metadata:
5
- version: '3.8.1'
5
+ version: '4.0.0'
6
6
  ---
7
7
 
8
8
  # codex-cli-bridge
@@ -46,39 +46,40 @@ this skill. Both wrappers enforce the subscription path before invoking codex:
46
46
  regardless of that flag);
47
47
  - they **preflight `codex login status`** and refuse to run unless it reports `Logged in using ChatGPT`.
48
48
 
49
- ## Models quality-first pinned
50
-
51
- Delegated codex work ALWAYS runs on the **PINNED model at the PINNED reasoning effort**: the wrappers
52
- **pin** `gpt-6-astra` / `high` and **refuse** (exit 2, loud) a non-default `CODEX_MODEL` / `CODEX_EFFORT`
53
- — knowingly-worse output is never traded for quota. The pin is deliberate: an explicit `-m gpt-6-astra`
54
- names one model rather than following the CLI's current default. That the pinned id is also the
55
- *strongest* selectable Codex model is a **separate, time-bounded claim**, checked BY HAND against
56
- <https://developers.openai.com/codex/models>. There is **no automated gate and this file records no
57
- date for that check**, so treat "strongest" as unverified until someone looks. Upstream can move
58
- either way between releases:
59
- - **retirement** is loud — the pinned id stops being served and codex fails with an error naming the
60
- model. That is an upstream failure, not a wrapper refusal; the fix is a pin bump in its own reviewed
61
- commit, never a `CODEX_PROBE=1` run, whose output is never delegated work.
62
- - **a newer, stronger model is SILENT** — nothing fails, and the pin simply stops being the best
63
- available until someone re-checks the page.
64
-
65
- The guard is therefore a **pin-integrity** guard, not a quality guarantee: it enforces that runs use
66
- the id named here, and it refuses a *stronger* model exactly as it refuses a weaker one. The effort
67
- pin is the same kind of decision: `high` is a deliberate posture, not the catalog maximum (`xhigh`,
68
- `max` and `ultra` exist above it), and the guard refuses a higher effort exactly as it refuses a lower
69
- one. Read a refusal as "not the pinned id", never as "a downgrade was prevented".
49
+ ## Models: the host posture
50
+
51
+ Delegated codex work runs on the **host posture**: `CODEX_MODEL` and `CODEX_EFFORT` from the bridge
52
+ settings file `${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf`, else the built-in
53
+ default `gpt-6.1-sol` / `high`. **`/agent-workflow-kit bridge-settings`** shows the models the
54
+ installed `codex` offers and sets the host posture (checked against that list before it writes).
55
+ Before any run is spent the wrappers check the effective model and
56
+ effort against the installed CLI's catalog (`codex debug models`, the entries offered for listing): a
57
+ model or effort it does not offer is refused (exit 2) with the offered list and the settings-file lines
58
+ that set an offered posture. An unreadable catalog is one stderr warning and the run proceeds — codex
59
+ itself then refuses a model it does not serve.
60
+
61
+ The environment overrides the host posture for one run. A run on anything other than the host posture
62
+ is a **one-off**, whatever set it, and only a probe runs one: without `CODEX_PROBE=1` the wrappers refuse
63
+ it pre-spend (exit 2) and name the remedy — the settings-file lines that make it the host posture, plus
64
+ unsetting `CODEX_MODEL` and `CODEX_EFFORT` in the environment. An environment value equal to the host
65
+ posture is not a one-off; an explicitly empty `CODEX_MODEL=` or `CODEX_EFFORT=` selects the built-in
66
+ default. A nonced `codex-exec` probe one-off is refused too (the exec receipt could not say it ran off
67
+ the host posture), and a probe review's receipt is `probe:true` and never attests.
68
+
69
+ A weaker model is therefore the user's choice in the setting, never the orchestrator's per call. `high`
70
+ is the default effort, not the catalog maximum (`xhigh`, `max` and `ultra` exist above it). Whether the
71
+ default is also the *strongest* selectable Codex model is a hand-checked claim against
72
+ <https://developers.openai.com/codex/models>, with **no automated gate and no recorded date** — a newer
73
+ model is silent until the user sets it or a bridge release moves the default. A retired model fails
74
+ loudly: the catalog check refuses it pre-spend with the offered list and the remedy.
70
75
 
71
76
  Economy comes only from **quality-neutral waste removal** (clean capture, a hard timeout,
72
- a precomputed review diff, `resume` instead of re-sending context), never from a downgrade.
73
-
74
- The ONLY escape is a **throwaway probe** whose result is effort-independent (a reachability / smoke
75
- check): set `CODEX_PROBE=1` (echoed loudly) to relax the model/effort guard. Never use a probe run's
76
- output as real delegated work.
77
+ a precomputed review diff, `resume` instead of re-sending context), never from a per-call downgrade.
77
78
 
78
79
  | Variable | Default | Effect |
79
80
  |---|---|---|
80
- | `CODEX_MODEL` | `gpt-6-astra` (pinned) | model passed to `-m`; a non-default is REFUSED unless `CODEX_PROBE=1` |
81
- | `CODEX_EFFORT` | `high` (pinned) | reasoning effort (`-c model_reasoning_effort=…`); non-default REFUSED unless `CODEX_PROBE=1` |
81
+ | `CODEX_MODEL` | the setting, else `gpt-6.1-sol` | model passed to `-m`; an environment value off the host posture is a one-off, REFUSED unless `CODEX_PROBE=1` |
82
+ | `CODEX_EFFORT` | the setting, else `high` | reasoning effort (`-c model_reasoning_effort=…`); an environment value off the host posture is a one-off, REFUSED unless `CODEX_PROBE=1` |
82
83
 
83
84
  `codex --version` reports the CLI version, **not** the model list. Quota is metered in **messages**
84
85
  (a rolling 5h window + a weekly cap), not raw tokens — which is why the levers above are about removing
@@ -117,14 +118,15 @@ codex-review code "focus on the new reducer" # review with extra focus
117
118
  **Honesty + posture (D4/D5):** a run whose final message has no recognized
118
119
  `Verdict: <ship|revise|rethink>` line — empty or missing output included — **exits 4 with NO
119
120
  receipt**: treat it as a *failed review to re-run*, never a fatal session error. One stderr banner
120
- states the actual posture (`review posture: model=… effort=… tier=… timeout=…`) and the receipt
121
- records the same `posture {model, effort, tier}` (tier `null` on the standard tier); control bytes
122
- in a posture value refuse pre-spend in every mode. `codex-exec` states its posture the same way —
121
+ states the actual posture (`review posture: model=… effort=… tier=… source=… timeout=…`) and the
122
+ receipt records the same `posture {model, effort, tier}` (tier `null` on the standard tier); control
123
+ bytes in a posture value refuse pre-spend in every mode. `codex-exec` states its posture the same way —
123
124
  ONE `exec posture: model=… effort=… tier=… sandbox=workspace-write session=fresh|resume:<id>
124
- timeout=…` stderr line before dispatch (the resume id validated pre-spend). The `timeout=` field
125
- is **banner-only** (exactly the duration handed to `timeout(1)`; on exec `uncapped` without a
126
- capping binary, while `codex-review` **fails CLOSED pre-spend** there) — informational, never a
127
- receipt field. **Quote the posture banner verbatim** when labeling a dispatch.
125
+ source=… timeout=…` stderr line before dispatch (the resume id validated pre-spend). The `source=`
126
+ field (`model:<s>,effort:<s>`, each `default`, `setting` or `environment`) and the `timeout=` field
127
+ are **banner-only** (`timeout=` is exactly the duration handed to `timeout(1)`; on exec `uncapped`
128
+ without a capping binary, while `codex-review` **fails CLOSED pre-spend** there) — informational,
129
+ never a receipt field. **Quote the posture banner verbatim** when labeling a dispatch.
128
130
 
129
131
  Every successful review receipt carries integer `durationS` and `blocking`; the wrapper prints
130
132
  `review duration: <n>s`. A plan receipt also carries `artifactPath`, normalized to a repo-relative
@@ -146,29 +148,29 @@ failure carries both a sandbox-mechanism and a permission/read-only token in its
146
148
  The exit status stays 0 there (warning, not gate) — read the stderr line. A successful **non-resume**
147
149
  `codex-exec` also records the session id to a sidecar
148
150
  (`${CODEX_SESSION_FILE:-./.codex-last-session}`) so `--resume-last` can find it. Extra `codex` flags
149
- go after a literal `--`; the wrapper rejects any that would defeat the policy or the pinned model (see
151
+ go after a literal `--`; the wrapper rejects any that would defeat the policy or the host posture (see
150
152
  [§ Environment knobs](#environment-knobs) and the flag tiers in
151
153
  [`references/sandbox-and-flags.md`](references/sandbox-and-flags.md)); args without the separator are
152
154
  rejected, never silently dropped.
153
155
 
154
156
  ## Environment knobs
155
157
 
156
- All optional; the defaults are the supported path. Anything that would lower quality (model/effort) or
157
- defeat a policy is guarded — see [§ Models](#models-quality-first-pinned).
158
+ All optional; the defaults are the supported path. The model and effort are the host posture, and
159
+ anything that would defeat a policy is guarded — see [§ Models](#models-the-host-posture).
158
160
 
159
161
  | Variable | Default | Effect |
160
162
  |---|---|---|
161
- | `CODEX_MODEL` | `gpt-6-astra` (pinned) | model; non-default REFUSED unless `CODEX_PROBE=1` |
162
- | `CODEX_EFFORT` | `high` (pinned) | reasoning effort; non-default REFUSED unless `CODEX_PROBE=1` |
163
+ | `CODEX_MODEL` | the setting, else `gpt-6.1-sol` | model; off the host posture REFUSED unless `CODEX_PROBE=1` |
164
+ | `CODEX_EFFORT` | the setting, else `high` | reasoning effort; off the host posture REFUSED unless `CODEX_PROBE=1` |
163
165
  | `CODEX_HARD_TIMEOUT` | `3600` (exec) / `1800` (review) | hard wall-clock cap (seconds) via `timeout`/`gtimeout`; exit 124/137 ⇒ "exceeded hard cap". No `timeout` binary ⇒ a nonce-less exec warns loudly + runs uncapped, a **nonced** exec REFUSES pre-spend (an accounted dispatch that cannot be capped can never honour the terminal-exit rule), and `codex-review` REFUSES pre-spend (fail-closed preflight). |
164
- | `CODEX_SERVICE_TIER` | unset (standard tier) | **SPEND knob**: `priority` (catalog name "Fast") = "2x speed, **increased usage**" in the codex catalog's own words for gpt-6-astra (cache fetched 2026-09-05); it states no credit-rate figure — quality-neutral (same model). codex accepts any `-c service_tier` string silently (probe-verified), so the wrapper validates: an unsupported value warns and runs standard. Env or settings file. |
166
+ | `CODEX_SERVICE_TIER` | unset (standard tier) | **SPEND knob**: `priority` (catalog name "Fast") = "2x speed, **increased usage**" in the codex catalog's own words for gpt-6.1-sol (cache fetched 2026-10-03); it states no credit-rate figure — quality-neutral (same model). codex accepts any `-c service_tier` string silently (probe-verified), so the wrapper validates: an unsupported value warns and runs standard. Env or settings file. |
165
167
  | `CODEX_SESSION_FILE` | `./.codex-last-session` | where `codex-exec` records the session id and where `--resume-last` reads it |
166
168
  | `CODEX_REVIEW_MAX_TOTAL_BYTES` | `1500000` | `codex-review code`: above this the assembled diff goes via a git-dir temp file instead of inline — never truncated |
167
169
  | `AW_REVIEW_NONCE` | unset | the flow dispatch nonce (safe grammar `[A-Za-z0-9._-]{1,64}` — anything else refuses pre-spend). `codex-review … --nonce <n>` is the plain-argument equivalent (one seam; flag and a non-empty env must agree, a disagreeing pair refuses pre-spend) — the lane for hosts whose dispatch policy has no env-prefix form. When supplied, a successful review first mints the finding MANIFEST `agent-workflow-finding-manifest-codex-<nonce>.json` beside the receipts file (atomic, no-clobber, ORDERED before the receipt append) — a failed mint EXCLUDES the receipt, so a nonce-supplied dispatch never lands a receipt without its readable manifest; nonce-less runs add no nonce field and mint nothing (the `wrapperVersion` field every receipt carries moves with each release) |
168
170
  | `AW_DISPATCH_NONCE` | unset | the **delegation** dispatch nonce (same safe grammar; anything else refuses pre-spend). `codex-exec [--nonce <n>] <plan-file>` is the plain-argument equivalent — ONE seam, recognised only BEFORE the prompt operand (after it, or after a literal `--`, it is passthrough payload). When supplied, the run is ACCOUNTED: see [§ Dispatch identity](#dispatch-identity-the-accounted-exec-lane). |
169
171
  | `AW_DELEGATION_STORE` | unset (the git common dir) | absolute path of the delegation ledger; its **dirname** is where a nonced run's receipt and report land. Relative, or ending in a path separator, refuses pre-spend — the same rule the kit's store applies. |
170
172
  | `CODEX_REVIEW_SCHEMA` | unset | `codex-review`: `=1` returns findings as a validated JSON object (`--output-schema`), with a raw-text fallback. Default off. |
171
- | `CODEX_PROBE` | unset | `=1` ⇒ throwaway-probe mode: relaxes the model/effort guard AND the tier-2 passthrough guard (echoed loudly). Never for real work. |
173
+ | `CODEX_PROBE` | unset | `=1` ⇒ throwaway-probe mode: the one route to a one-off model or effort, and it relaxes the tier-2 passthrough guard (echoed loudly); a probe review's receipt never attests. Never for real work. |
172
174
 
173
175
  The git-write shim, `--ignore-user-config`, and the `*_API_KEY` scrub are NOT env-tunable — they are
174
176
  fixed invariants.
@@ -212,11 +214,11 @@ skipped entirely without a nonce: the wrapper is byte-unchanged, writes no artif
212
214
  `${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf` holds `KEY=VALUE` lines,
213
215
  **parsed, never sourced** — a file line can never execute code. Precedence: explicit env (even
214
216
  empty — `KEY=` disables a knob for one run) > file > built-in default. File-settable keys for this
215
- bridge: `CODEX_SERVICE_TIER` (the Fast tier — **increased usage**; enabling it is a consented
216
- per-host spend decision, never a default), `CODEX_HARD_TIMEOUT`, `CODEX_REVIEW_MAX_TOTAL_BYTES` —
217
- exactly the manifest `settings` block (the single source; the wrapper constants and `--help` are
218
- drift-guarded against it). Model/effort keys are **not** file-settable — the quality guard above
219
- is untouched. The file lives **outside every kit-managed tree**, so a kit refresh/upgrade can
217
+ bridge: `CODEX_MODEL` and `CODEX_EFFORT` (the host posture — see [§ Models](#models-the-host-posture)),
218
+ `CODEX_SERVICE_TIER` (the Fast tier — **increased usage**; enabling it is a consented per-host spend
219
+ decision, never a default), `CODEX_HARD_TIMEOUT`, `CODEX_REVIEW_MAX_TOTAL_BYTES` — exactly the
220
+ manifest `settings` block (the single source; the wrapper constants and `--help` are drift-guarded
221
+ against it, the model keys read by the posture reader instead). The file lives **outside every kit-managed tree**, so a kit refresh/upgrade can
220
222
  never wipe it; edit it by hand or via `/agent-workflow-kit bridge-settings` (preview-first,
221
223
  consent-gated).
222
224
 
@@ -259,7 +261,7 @@ See [`references/driving-codex.md`](references/driving-codex.md) for the full pl
259
261
  embed the goal, the relevant paths, and the expected result; codex reads `AGENTS.md` for the rules.
260
262
  - **Iterate with `codex-exec --resume-last` / `--resume <id>`** instead of re-sending context. The
261
263
  resume entrypoint re-establishes EVERY wrapper invariant (subscription-only, `--ignore-user-config`,
262
- the pinned model/effort) and **restates the full posture via `-c`** — `codex exec resume` resets the
264
+ the host posture's model/effort) and **restates the full posture via `-c`** — `codex exec resume` resets the
263
265
  sandbox/approval/network posture and rejects the `-s`/`--add-dir`/`-C` posture flags, so the wrapper
264
266
  sets `sandbox_mode=workspace-write` + `approval_policy=never` +
265
267
  `sandbox_workspace_write.network_access=false` explicitly. It reads the session id from the sidecar
@@ -13,17 +13,17 @@
13
13
  # - network access OFF: new dependencies / network installs are done by a human
14
14
  # - approval_policy=never: there is no TTY in exec; anything needing escalation
15
15
  # is refused and reported, then handled by hand
16
- # - the PINNED model at the PINNED reasoning effort (quality-first — see below)
16
+ # - the host posture's model and reasoning effort (see below)
17
17
  # - git WRITES are blocked by a physical shim (codex spawns git via execve, which
18
18
  # bypasses shell functions) — the orchestrator owns the commit boundary.
19
19
  #
20
- # Quality-first (hard rule): delegated codex work ALWAYS runs on the PINNED
21
- # model at the PINNED reasoning effort. The defaults below are pinned and the wrapper
22
- # REFUSES a non-default CODEX_MODEL/CODEX_EFFORT — knowingly-worse output is never
23
- # traded for quota. The ONLY exception is a throwaway probe whose result does not
24
- # depend on effort: set CODEX_PROBE=1 (echoed loudly) to relax the guard. Economy
25
- # comes from quality-neutral waste removal (clean capture, a hard timeout, a lean
26
- # prompt, resume instead of re-sending context), never from a downgrade.
20
+ # Host posture (hard rule): delegated codex work runs on the host posture — CODEX_MODEL and
21
+ # CODEX_EFFORT from the bridge settings file, else the built-in default gpt-6.1-sol at effort high
22
+ # (`/agent-workflow-kit bridge-settings` shows the models offered and sets one) — checked against the
23
+ # installed CLI's catalog before any spend. A run on anything else is a one-off, refused unless
24
+ # it is a probe (CODEX_PROBE=1); a nonced dispatch never runs a one-off. Economy comes from
25
+ # quality-neutral waste removal (clean capture, a hard timeout, a lean prompt, resume instead of
26
+ # re-sending context), never from a per-call downgrade.
27
27
  #
28
28
  # Auth: SUBSCRIPTION ONLY. Uses the cached ChatGPT login under CODEX_HOME
29
29
  # (~/.codex). The wrapper unsets every *_API_KEY plus OPENAI_BASE_URL and passes
@@ -37,7 +37,7 @@
37
37
  # codex-exec --resume-last <file|-> # continue the last session (iterate, no re-send)
38
38
  # codex-exec --resume <session-id> <file|-> # continue a specific session
39
39
  # CODEX_HARD_TIMEOUT=7200 codex-exec <file> # raise the hard wall-clock cap (integer seconds)
40
- # CODEX_PROBE=1 CODEX_MODEL=<slug> codex-exec <file> # throwaway probe (relaxes the guard)
40
+ # CODEX_PROBE=1 CODEX_MODEL=<slug> codex-exec <file> # throwaway probe (the one route to a one-off)
41
41
  set -euo pipefail
42
42
 
43
43
  # --- --help / -h (pre-preflight: no codex, no login, no git tree needed) -------
@@ -113,7 +113,7 @@ Receipt:
113
113
  reads it, report-if-present). The post-report lane never claims the reservation still stands,
114
114
  because after that point its fate is no longer something this run observed. Every lane names the
115
115
  tree as partial/dirtied rather than untouched. A nonce-LESS invocation is byte-unchanged: no
116
- reservation, no receipt, no artifact, no node.
116
+ reservation, no receipt, no artifact, and it needs no node.
117
117
 
118
118
  Notes:
119
119
  nested-sandbox limit: codex-exec ships its OWN OS sandbox (bwrap workspace-write) and cannot run
@@ -121,7 +121,7 @@ Notes:
121
121
  (excludedCommands / a per-run consented bypass) on the OBSERVED bwrap/EPERM failure, never a
122
122
  preemptive blanket
123
123
  exec posture banner: ONE stderr line before dispatch states the ACTUAL run posture —
124
- exec posture: model=… effort=… tier=… sandbox=workspace-write session=fresh|resume:<id> timeout=… —
124
+ exec posture: model=… effort=… tier=… sandbox=workspace-write session=fresh|resume:<id> source=… timeout=… —
125
125
  from RESOLVED post-validation values; the resume id is validated pre-spend, and control bytes in
126
126
  any banner field refuse pre-spend
127
127
  threat model: the sidecar byte and grammar screens detect corrupted input under a trusted parent
@@ -129,9 +129,10 @@ Notes:
129
129
  substitution of core/backend commands — is outside the threat model and can substitute the
130
130
  backend itself. Targeted shadow-proof resolution protects banner/dispatch honesty from accidental
131
131
  shadowing; it is not an environment security boundary
132
- the exec posture banner appends a banner-only timeout=<duration|uncapped> field — exactly the
133
- duration handed to timeout(1), uncapped when no timeout/gtimeout binary caps the run;
134
- INFORMATIONAL only: it is never persisted in a receipt or session sidecar
132
+ the exec posture banner appends a banner-only source=model:<s>,effort:<s> field — where each value
133
+ came from: default, setting or environment — then a banner-only timeout=<duration|uncapped> field
134
+ — exactly the duration handed to timeout(1), uncapped when no timeout/gtimeout binary caps the
135
+ run; INFORMATIONAL only: neither is persisted in a receipt or session sidecar
135
136
  quote the posture banner verbatim when labeling this dispatch — the banner is the machine-stated
136
137
  posture; a prose re-type drifts
137
138
  every-run nested-sandbox scan (DUAL policy, deliberately two different rules): the scan runs on
@@ -149,7 +150,7 @@ Notes:
149
150
 
150
151
  Settings file (KEY=VALUE, parsed never sourced; env wins over file, file wins over built-in default):
151
152
  ${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf
152
- CODEX_SERVICE_TIER — service tier: 'priority' (Fast — "2x speed, increased usage", the codex catalog's own words for gpt-6-astra, cache fetched 2026-09-05; it states no credit-rate figure); a consented SPEND knob, default off (standard tier)
153
+ CODEX_SERVICE_TIER — service tier: 'priority' (Fast — "2x speed, increased usage", the codex catalog's own words for gpt-6.1-sol, cache fetched 2026-10-03; it states no credit-rate figure); a consented SPEND knob, default off (standard tier)
153
154
  CODEX_HARD_TIMEOUT — hard wall-clock cap, integer seconds 1..86400 (built-in default 3600)
154
155
 
155
156
  Environment: CODEX_HARD_TIMEOUT (seconds, default 3600), CODEX_PROBE=1 (throwaway probe only), AW_DISPATCH_NONCE (delegation dispatch nonce — mints the exec receipt; the --nonce <n> flag is its plain-argument equivalent), AW_DELEGATION_STORE (absolute delegation-store path; its dirname is where the receipt lands).
@@ -161,6 +162,8 @@ esac
161
162
 
162
163
  # This wrapper's applied settings-file subset (see the shared reader block below).
163
164
  AW_SETTINGS_APPLIED="CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT"
165
+ DEFAULT_CODEX_MODEL="gpt-6.1-sol"
166
+ DEFAULT_CODEX_EFFORT="high"
164
167
 
165
168
  # --- Bridge settings file (host-level, kit-independent) — byte-identical across the four wrappers ---
166
169
  # ${XDG_CONFIG_HOME:-$HOME/.config}/agent-workflow/bridge-settings.conf holds KEY=VALUE lines,
@@ -181,7 +184,7 @@ aw_settings_file() {
181
184
  printf '%s/agent-workflow/bridge-settings.conf' "${XDG_CONFIG_HOME:-$HOME/.config}"
182
185
  }
183
186
  aw_settings_known() {
184
- case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR AGY_REVIEW_MAX_TOTAL_BYTES " in
187
+ case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR AGY_REVIEW_MAX_TOTAL_BYTES CODEX_MODEL CODEX_EFFORT AGY_MODEL " in
185
188
  *" $1 "*) return 0 ;;
186
189
  *) return 1 ;;
187
190
  esac
@@ -266,6 +269,37 @@ aw_apply_settings() {
266
269
  done
267
270
  return 0
268
271
  }
272
+ aw_read_posture() {
273
+ local key="$1" default="$2" empty="$3" file line value notify=1
274
+ AW_HOST_VALUE="$default"
275
+ AW_HOST_SOURCE="default"
276
+ file="$(aw_settings_file)"
277
+ [[ -n "${AW_SETTINGS_NOTIFIED:-}" ]] && notify=0
278
+ if [[ -f "$file" && -r "$file" ]]; then
279
+ line="$(grep "^${key}=" "$file" 2>/dev/null || true)"
280
+ if [[ -n "$line" ]]; then
281
+ value="${line##*$'\n'}"
282
+ value="${value#*=}"
283
+ if [[ -n "$value" && "$value" != *[$'\x01'-$'\x1f'$'\x7f']* ]]; then
284
+ AW_HOST_VALUE="$value"
285
+ AW_HOST_SOURCE="setting"
286
+ elif (( notify )); then
287
+ echo "warning: $key in bridge settings file '$file' is empty or carries a control byte — using the built-in default '$default'." >&2
288
+ fi
289
+ fi
290
+ fi
291
+ AW_RUN_VALUE="$AW_HOST_VALUE"
292
+ AW_RUN_SOURCE="$AW_HOST_SOURCE"
293
+ if [[ -n "${!key+x}" ]]; then
294
+ AW_RUN_VALUE="${!key:-$empty}"
295
+ AW_RUN_SOURCE="environment"
296
+ fi
297
+ return 0
298
+ }
299
+ aw_read_posture CODEX_MODEL "$DEFAULT_CODEX_MODEL" "$DEFAULT_CODEX_MODEL"
300
+ HOST_CODEX_MODEL="$AW_HOST_VALUE"; CODEX_MODEL="$AW_RUN_VALUE"; CODEX_MODEL_SOURCE="$AW_RUN_SOURCE"
301
+ aw_read_posture CODEX_EFFORT "$DEFAULT_CODEX_EFFORT" "$DEFAULT_CODEX_EFFORT"
302
+ HOST_CODEX_EFFORT="$AW_HOST_VALUE"; CODEX_EFFORT="$AW_RUN_VALUE"; CODEX_EFFORT_SOURCE="$AW_RUN_SOURCE"
269
303
  aw_apply_settings
270
304
 
271
305
  # --- Effective-timeout resolver (D5 banner honesty; AD-061) --------------------
@@ -319,19 +353,15 @@ aw_resolve_timeout_bin() {
319
353
  printf '%s' "$bin"
320
354
  }
321
355
 
322
- DEFAULT_CODEX_MODEL="gpt-6-astra" # pinned model id (see SKILL.md: strongest-model status is hand-checked, ungated)
323
- DEFAULT_CODEX_EFFORT="high" # pinned reasoning effort — a deliberate posture, not the catalog maximum
324
- CODEX_MODEL="${CODEX_MODEL:-$DEFAULT_CODEX_MODEL}"
325
- CODEX_EFFORT="${CODEX_EFFORT:-$DEFAULT_CODEX_EFFORT}"
326
- # Generous hard wall-clock cap, sized for a slow run at the pinned effort (subscription latency
356
+ # Generous hard wall-clock cap, sized for a slow run at the host posture's effort (subscription latency
327
357
  # varies — a trivial reply was observed taking minutes). Raise for a known-healthy
328
358
  # long run; lowering it only risks killing real work.
329
359
  CODEX_HARD_TIMEOUT="${CODEX_HARD_TIMEOUT:-3600}"
330
360
  # Codex service tier (quality-neutral speed knob): default EMPTY ⇒ no
331
361
  # service_tier flag (standard tier) — enabling Fast is a consented per-host SPEND act, never a
332
362
  # silent default. The only server-catalog tier id on this subscription is 'priority' (catalog
333
- # display name "Fast": "2x speed, increased usage" in the catalog's own words for gpt-6-astra, cache
334
- # fetched 2026-09-05; it states no credit-rate figure; quality-neutral — same model). codex itself
363
+ # display name "Fast": "2x speed, increased usage" in the catalog's own words for gpt-6.1-sol, cache
364
+ # fetched 2026-10-03; it states no credit-rate figure; quality-neutral — same model). codex itself
335
365
  # accepts ANY -c service_tier string silently (probe-verified), so
336
366
  # the wrapper validates the effective value: an unsupported one warns and runs on the standard
337
367
  # tier — a typo can never silently masquerade as Fast.
@@ -373,31 +403,15 @@ CHATGPT_LOGIN_GUARD="Logged in using ChatGPT"
373
403
  # receipt this wrapper mints; scripts/release/version-sync.mjs bumps it under the one-anchor-per-file
374
404
  # rule, so a release can never leave it behind (the AD-053 drift class).
375
405
  AW_RECEIPT_BACKEND="codex"
376
- AW_BRIDGE_VERSION="3.8.1" # aw-version-anchor
406
+ AW_BRIDGE_VERSION="4.0.0" # aw-version-anchor
377
407
  # The kill grace handed to timeout(1) as --kill-after, and recorded in the receipt as killGraceS:
378
408
  # ONE constant, so the number the ledger checks against the dispatch deadline is the number the run
379
409
  # actually applied.
380
410
  CODEX_KILL_GRACE_S=15
381
411
 
382
- # --- Quality-first guard: refuse any non-pinned model/effort ---------------
383
- # Real delegated runs must use the pinned model at the pinned effort. A throwaway probe
384
- # (effort-independent result) may opt out with CODEX_PROBE=1, announced loudly.
385
412
  if [[ "${CODEX_PROBE:-}" == "1" ]]; then
386
413
  echo "warning: CODEX_PROBE=1 — THROWAWAY PROBE MODE. Quality guards relaxed; do NOT use this run's" >&2
387
414
  echo " output as real delegated work (model='$CODEX_MODEL' effort='$CODEX_EFFORT')." >&2
388
- else
389
- if [[ "$CODEX_MODEL" != "$DEFAULT_CODEX_MODEL" ]]; then
390
- echo "error: CODEX_MODEL='$CODEX_MODEL' is not the pinned model '$DEFAULT_CODEX_MODEL'." >&2
391
- echo " Delegated codex work must run on the pinned model at the pinned effort (quality-first)." >&2
392
- echo " For a throwaway probe whose result is effort-independent, set CODEX_PROBE=1." >&2
393
- exit 2
394
- fi
395
- if [[ "$CODEX_EFFORT" != "$DEFAULT_CODEX_EFFORT" ]]; then
396
- echo "error: CODEX_EFFORT='$CODEX_EFFORT' is not the pinned effort '$DEFAULT_CODEX_EFFORT'." >&2
397
- echo " Delegated codex work must run at the pinned reasoning effort (quality-first)." >&2
398
- echo " For a throwaway probe whose result is effort-independent, set CODEX_PROBE=1." >&2
399
- exit 2
400
- fi
401
415
  fi
402
416
 
403
417
  # --- Subscription-only guard -------------------------------------------------
@@ -624,10 +638,10 @@ else
624
638
  # (1) ALWAYS rejected — they would defeat the subscription / sandbox / approval /
625
639
  # config-isolation policy (-c/-s/--full-auto/bypass), switch the provider off
626
640
  # the subscription (--oss/--local-provider), load alternate config (-p/--profile),
627
- # override the pinned model (-m), or break the wrapper-owned clean
641
+ # override the host posture's model (-m), or break the wrapper-owned clean
628
642
  # output / session capture (-o/--json/--color/--output-schema/--ephemeral).
629
643
  # CODEX_PROBE=1 NEVER relaxes these: a probe still runs on the subscription, in
630
- # the sandbox, with clean capture; its model is chosen via CODEX_MODEL, not -m.
644
+ # the sandbox, with clean capture; its model is chosen via CODEX_MODEL, never a flag.
631
645
  # (2) Probe-relaxable — context/discovery knobs the wrapper otherwise pins; a
632
646
  # throwaway probe (CODEX_PROBE=1) may pass them. Need more? invoke `codex` direct.
633
647
  if [[ ${#passthrough[@]} -gt 0 ]]; then
@@ -635,7 +649,7 @@ else
635
649
  case "$_arg" in
636
650
  -c*|--config*|-s*|--sandbox*|--dangerously-bypass-approvals-and-sandbox|--dangerously-bypass-hook-trust|--full-auto|--oss|--local-provider*|-p*|--profile*|-m*|--model*|-o*|--output-last-message*|--json*|--color*|--output-schema*|--ephemeral*)
637
651
  echo "error: passthrough flag '$_arg' is not allowed — it would defeat the subscription / sandbox /" >&2
638
- echo " approval / config-isolation policy, the pinned model, or the clean output/session" >&2
652
+ echo " approval / config-isolation policy, the host posture, or the clean output/session" >&2
639
653
  echo " capture. It stays blocked even under CODEX_PROBE=1. Invoke 'codex' directly if you must." >&2
640
654
  exit 2
641
655
  ;;
@@ -666,7 +680,7 @@ if [[ -z "${task//[[:space:]]/}" ]]; then
666
680
  fi
667
681
 
668
682
  # --- The ACCOUNTED lane: everything below fires only for a NONCED run ---------
669
- # A nonce-LESS invocation is byte-unchanged — no reservation, no receipt, no artifact, no node —
683
+ # A nonce-LESS invocation is byte-unchanged — no reservation, no receipt, no artifact, needs no node —
670
684
  # which is what keeps every existing caller working. The whole mint core rides ONE node script per
671
685
  # step (the family floor, codex-review.sh's finding-manifest precedent): a bash re-implementation of
672
686
  # atomic no-clobber publication, JSON composition and canonical digesting would be a second, drifting
@@ -933,7 +947,7 @@ if [[ -n "$resume_mode" ]]; then
933
947
  else
934
948
  # `-o` writes ONLY codex's final message; `--json` streams structured events
935
949
  # (thread.started carries the session id). CoT is dropped and colour disabled, so
936
- # the captured surfaces stay clean. Reasoning still runs at the pinned effort — quality is
950
+ # the captured surfaces stay clean. Reasoning still runs at the run's effort — quality is
937
951
  # unchanged; we only stop printing the noise.
938
952
  codex_cmd=(codex exec
939
953
  --ignore-user-config
@@ -981,6 +995,91 @@ if [[ -z "$timeout_bin" ]]; then
981
995
  echo " (install coreutils to enable CODEX_HARD_TIMEOUT=$CODEX_HARD_TIMEOUT)." >&2
982
996
  fi
983
997
 
998
+ # --- The effective model checked against the installed CLI's catalog, then the one-off rule ---
999
+ # Both refuse BEFORE any spend. The read runs after the subscription guard, with the run's
1000
+ # CODEX_HOME and the built-in provider, bounded by the same timeout binary as the run.
1001
+ catalog_env=(env)
1002
+ CODEX_CATALOG_TIMEOUT_S=15
1003
+ aw_codex_remedy() {
1004
+ echo " remedy: set these lines in $(aw_settings_file):" >&2
1005
+ echo " CODEX_MODEL=$1" >&2
1006
+ echo " CODEX_EFFORT=$2" >&2
1007
+ echo " and unset CODEX_MODEL and CODEX_EFFORT in the environment." >&2
1008
+ }
1009
+ aw_codex_catalog_check() {
1010
+ local raw="" rc=0 verdict="" kind="" offered="" model="" effort="" catalog_js=""
1011
+ if [[ -n "$timeout_bin" ]]; then
1012
+ raw="$("${catalog_env[@]}" "$timeout_bin" --kill-after=5s "$CODEX_CATALOG_TIMEOUT_S" codex debug models -c model_provider=openai </dev/null 2>/dev/null)" || rc=$?
1013
+ else
1014
+ raw="$("${catalog_env[@]}" codex debug models -c model_provider=openai </dev/null 2>/dev/null)" || rc=$?
1015
+ fi
1016
+ if (( rc == 124 || rc == 137 )); then
1017
+ verdict="unreadable"$'\t'"it exceeded ${CODEX_CATALOG_TIMEOUT_S}s"
1018
+ elif (( rc != 0 )); then
1019
+ verdict="unreadable"$'\t'"codex debug models exited $rc"
1020
+ elif ! command -v node >/dev/null 2>&1; then
1021
+ verdict="unreadable"$'\t'"no node to parse it"
1022
+ else
1023
+ IFS= read -r -d '' catalog_js <<'CATALOG_JS' || true
1024
+ const [model, effort, defaultModel, defaultEffort] = process.argv.slice(1);
1025
+ const answer = (...fields) => { process.stdout.write(fields.join("\t")); process.exit(0); };
1026
+ const CONTROL = /[\u0000-\u001f\u007f]/;
1027
+ let doc;
1028
+ try { doc = JSON.parse(require("node:fs").readFileSync(0, "utf8")); } catch { answer("unreadable", "its output is not JSON"); }
1029
+ if (doc === null || typeof doc !== "object" || !Array.isArray(doc.models)) answer("unreadable", "it carries no models[]");
1030
+ const offered = doc.models.filter((m) => m !== null && typeof m === "object" && m.visibility === "list");
1031
+ if (offered.some((m) => typeof m.slug !== "string" || m.slug === "" || CONTROL.test(m.slug))) answer("unreadable", "an offered entry carries no usable slug");
1032
+ if (offered.length === 0) answer("unreadable", "it offers no model");
1033
+ const effortsOf = (m) => (Array.isArray(m.supported_reasoning_levels)
1034
+ && m.supported_reasoning_levels.every((l) => l !== null && typeof l === "object" && typeof l.effort === "string" && !CONTROL.test(l.effort))
1035
+ ? m.supported_reasoning_levels.map((l) => l.effort) : null);
1036
+ const rank = (m) => (typeof m.priority === "number" ? m.priority : Number.MAX_SAFE_INTEGER);
1037
+ const refuse = (kind, list) => {
1038
+ const builtIn = offered.find((m) => m.slug === defaultModel);
1039
+ if (builtIn && (effortsOf(builtIn) ?? []).includes(defaultEffort)) answer(kind, list, defaultModel, defaultEffort);
1040
+ const first = [...offered].sort((a, b) => rank(a) - rank(b))[0];
1041
+ const level = first.default_reasoning_level;
1042
+ if (typeof level !== "string" || level === "" || CONTROL.test(level)) answer("unreadable", "the entry for " + first.slug + " carries no default_reasoning_level");
1043
+ answer(kind, list, first.slug, level);
1044
+ };
1045
+ const entry = offered.find((m) => m.slug === model);
1046
+ if (entry === undefined) refuse("model", offered.map((m) => m.slug).join(", "));
1047
+ const efforts = effortsOf(entry);
1048
+ if (efforts === null) answer("unreadable", "the entry for " + model + " carries no supported_reasoning_levels");
1049
+ if (!efforts.includes(effort)) refuse("effort", efforts.join(", "));
1050
+ answer("ok");
1051
+ CATALOG_JS
1052
+ verdict="$(printf '%s' "$raw" | NODE_OPTIONS= node -e "$catalog_js" -- "$CODEX_MODEL" "$CODEX_EFFORT" "$DEFAULT_CODEX_MODEL" "$DEFAULT_CODEX_EFFORT" 2>/dev/null)" || verdict="unreadable"$'\t'"its parser failed"
1053
+ fi
1054
+ IFS=$'\t' read -r kind offered model effort <<<"$verdict" || true
1055
+ case "$kind" in
1056
+ ok) return 0 ;;
1057
+ model)
1058
+ echo "error: CODEX_MODEL='$CODEX_MODEL' ($CODEX_MODEL_SOURCE) is not a model the installed codex offers — refusing before any run is spent." >&2
1059
+ echo " offered: $offered" >&2 ;;
1060
+ effort)
1061
+ echo "error: CODEX_EFFORT='$CODEX_EFFORT' ($CODEX_EFFORT_SOURCE) is not an effort the installed codex offers for $CODEX_MODEL — refusing before any run is spent." >&2
1062
+ echo " offered: $offered" >&2 ;;
1063
+ *)
1064
+ echo "warning: the codex model catalog is unreadable (${offered:-no answer}) — the run proceeds unchecked; codex itself refuses a model it does not serve." >&2
1065
+ return 0 ;;
1066
+ esac
1067
+ aw_codex_remedy "$model" "$effort"
1068
+ exit 2
1069
+ }
1070
+ aw_codex_catalog_check
1071
+ if [[ "$CODEX_MODEL" != "$HOST_CODEX_MODEL" || "$CODEX_EFFORT" != "$HOST_CODEX_EFFORT" ]]; then
1072
+ if [[ "${CODEX_PROBE:-}" != "1" ]]; then
1073
+ echo "error: model=$CODEX_MODEL effort=$CODEX_EFFORT is a one-off — the host posture is model=$HOST_CODEX_MODEL effort=$HOST_CODEX_EFFORT, and only a probe (CODEX_PROBE=1) runs a one-off; refusing before any run is spent." >&2
1074
+ aw_codex_remedy "$CODEX_MODEL" "$CODEX_EFFORT"
1075
+ exit 2
1076
+ fi
1077
+ if [[ -n "$aw_nonce" ]]; then
1078
+ echo "error: a probe one-off (model=$CODEX_MODEL effort=$CODEX_EFFORT) cannot carry a dispatch nonce — the exec receipt could not say it ran off the host posture; refusing before any run is spent (drop the nonce, or run on the host posture)." >&2
1079
+ exit 2
1080
+ fi
1081
+ fi
1082
+
984
1083
  # --- D5 exec banner (one line, the ACTUAL run posture; AD-061) -----------------
985
1084
  # Emitted from RESOLVED post-validation values, AFTER the resume id is resolved and validated,
986
1085
  # BEFORE the dispatch. The timeout field is banner-only (never a receipt/sidecar field): it
@@ -988,7 +1087,7 @@ fi
988
1087
  aw_timeout_banner="$(aw_timeout_label "$timeout_bin" "$CODEX_HARD_TIMEOUT")"
989
1088
  aw_session_label="fresh"
990
1089
  [[ -n "$resume_mode" ]] && aw_session_label="resume:$resume_id"
991
- echo "exec posture: model=$CODEX_MODEL effort=$CODEX_EFFORT tier=${CODEX_SERVICE_TIER:-standard} sandbox=workspace-write session=$aw_session_label timeout=$aw_timeout_banner" >&2
1090
+ echo "exec posture: model=$CODEX_MODEL effort=$CODEX_EFFORT tier=${CODEX_SERVICE_TIER:-standard} sandbox=workspace-write session=$aw_session_label source=model:$CODEX_MODEL_SOURCE,effort:$CODEX_EFFORT_SOURCE timeout=$aw_timeout_banner" >&2
992
1091
 
993
1092
  # --- The PRE-SPEND reservation (delegation Plan 2 / D1) ------------------------
994
1093
  # Written immediately before the CLI runs — after EVERY preflight and after the posture banner, so a