@sabaiway/agent-workflow-kit 14.22.0 → 14.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/SKILL.md +1 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +16 -10
- package/bridges/antigravity-cli-bridge/bin/agy-jev.test.mjs +105 -0
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +20 -6
- package/bridges/antigravity-cli-bridge/bin/agy.sh +26 -11
- package/bridges/antigravity-cli-bridge/capability.json +3 -3
- package/bridges/antigravity-cli-bridge/references/models-and-flags.md +4 -3
- package/bridges/antigravity-cli-bridge/setup/README.md +2 -1
- package/bridges/codex-cli-bridge/SKILL.md +44 -24
- package/bridges/codex-cli-bridge/bin/codex-exec-jev.test.mjs +385 -0
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +262 -42
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +16 -18
- package/bridges/codex-cli-bridge/bin/codex-model-posture.test.mjs +16 -7
- package/bridges/codex-cli-bridge/bin/codex-review-honesty.test.mjs +1 -0
- package/bridges/codex-cli-bridge/bin/codex-review-jev.test.mjs +301 -0
- package/bridges/codex-cli-bridge/bin/codex-review.sh +240 -26
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +9 -9
- package/bridges/codex-cli-bridge/capability.json +10 -10
- package/bridges/codex-cli-bridge/references/driving-codex.md +18 -14
- package/bridges/codex-cli-bridge/references/sandbox-and-flags.md +61 -22
- package/bridges/codex-cli-bridge/setup/README.md +8 -5
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/recommendations.md +1 -1
- package/references/modes/velocity.md +1 -1
- package/tools/detect-backends.mjs +3 -3
- package/tools/manifest/schema.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,55 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
|
|
|
4
4
|
is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
|
|
5
5
|
every `migrations/<version>-<slug>.md` newer than it, in semver order.
|
|
6
6
|
|
|
7
|
+
## 14.23.0 — a delegated codex or agy run uses Jev as your own run does; ships codex-cli-bridge 5.0.0 and antigravity-cli-bridge 7.0.0 (AD-171)
|
|
8
|
+
|
|
9
|
+
**Every bridge wrapper now passes `TYPESAFE_API_KEY` to the run, and on Linux with codex-cli 0.160.0 or newer a
|
|
10
|
+
`codex-exec` or `codex-review` run reaches `api.typesafe.ai` and `docs.typesafe.ai` and no other host.** The other
|
|
11
|
+
`*_API_KEY` values and `OPENAI_BASE_URL` stay unset. Where the codex permissions profile is not proven, the run keeps
|
|
12
|
+
the earlier flags with network off and its banner says why. An agy run gets the key and nothing more: no flag, no
|
|
13
|
+
setting.
|
|
14
|
+
|
|
15
|
+
- **One key rule in every wrapper.** The shared block of `codex-exec.sh`, `codex-review.sh`, `agy.sh` and
|
|
16
|
+
`agy-review.sh` gains `aw_scrub_billing_keys`, called before the first CLI spawn (login status, version, catalog,
|
|
17
|
+
run). `test/settings-reader-parity.test.mjs` finds the wrappers from the bridge manifests and
|
|
18
|
+
`test/jev-every-run.test.mjs` proves that discovery on fixture trees, so a wrapper added later is held to the same
|
|
19
|
+
block without a test edit.
|
|
20
|
+
- **codex: the permissions profile `jev`.** On Linux (WSL2 included) with codex-cli 0.160.0 or newer, fresh runs,
|
|
21
|
+
resumes and reviews carry the profile: network to the two Jev hosts only; `codex-exec` writes the repository, `/tmp`
|
|
22
|
+
and `$TMPDIR`; `codex-review` writes nothing. Not Linux, an older or unreadable codex version, an exec repository
|
|
23
|
+
or its git common dir under `/tmp` or `$TMPDIR`, or a version and profile recorded as refused: the run takes the
|
|
24
|
+
earlier flags with network off.
|
|
25
|
+
- **The banner says what the run reaches.** Both codex banners gain `jev=api.typesafe.ai,docs.typesafe.ai` or
|
|
26
|
+
`jev=unreachable (<reason>)` before `source=`; the exec banner's sandbox field reads `sandbox=jev-profile` or
|
|
27
|
+
`sandbox=workspace-write`. Receipt schemas are unchanged.
|
|
28
|
+
- **A refused profile stops loudly.** When codex rejects the profile before its first turn, or bwrap fails inside a
|
|
29
|
+
failed command, the run exits 72 with no success receipt. A rejected profile key records the codex version and
|
|
30
|
+
profile digest in `${XDG_STATE_HOME:-~/.local/state}/agent-workflow/codex-jev-profile-refused` when that file can
|
|
31
|
+
be written (otherwise one warning names it), and that wrapper's next run on that pair takes the earlier flags
|
|
32
|
+
before any spend; a `bwrap: execvp` failure records nothing.
|
|
33
|
+
- **`codex-review` sees the skill.** Its fence home links `.agents/skills` to your real Codex skill root when it
|
|
34
|
+
exists; the review directives allow reading it and name the two hosts on a profile run only.
|
|
35
|
+
- **Probe passthrough under the profile.** With `CODEX_PROBE=1`, `--add-dir`, `-C`, `--cd`, `--enable` and `--disable`
|
|
36
|
+
are refused before any spend (exit 2) while the profile is on; under the fallback they stay admitted.
|
|
37
|
+
- **agy.** With the key set, `agy-run` prints one line before dispatch: `jev: TYPESAFE_API_KEY passed; a headless agy
|
|
38
|
+
runs the Jev request only where your agy permissions allow commands — the first denied command ends the run`.
|
|
39
|
+
`agy-review` makes no Jev request while its model obeys its prompts, which forbid every tool (an advisory
|
|
40
|
+
prohibition, not a sandbox).
|
|
41
|
+
- **Manifests.** Both bridges' `networkHosts` gain `api.typesafe.ai` and `docs.typesafe.ai`, so the sandbox
|
|
42
|
+
Recommendations item shows once more on a project that acknowledged it. Guardrails and banner notes are rewritten,
|
|
43
|
+
and `tools/detect-backends.mjs`'s role-contract copy follows them.
|
|
44
|
+
- **The sandbox notes no longer promise the tier routes wrappers outside.** On 2026-10-06 Claude Code 2.1.291 ran
|
|
45
|
+
an agent's plain `codex-review` inside its sandbox although the project excluded it; a sandboxed run's Jev request
|
|
46
|
+
gets `Tunnel connection failed: 403` from the harness proxy (observed 2026-10-05). `references/modes/recommendations.md`
|
|
47
|
+
now says the tier routes the wrappers outside only where the harness honours that entry, names the refusal, and
|
|
48
|
+
points to the hand-apply `allowedDomains` shape with the recipe's hosts, which the kit never writes for you;
|
|
49
|
+
`references/modes/velocity.md` and the manifest schema's `networkHosts` note say the same.
|
|
50
|
+
- **Stated residuals.** Both bridge `SKILL.md` paragraphs say the key sits in every run's environment; the codex one
|
|
51
|
+
names codex's server-side `web_search`, which reaches pages outside the profile, the agy one a `web_search` or
|
|
52
|
+
fetch tool agy is permitted to run. A codex release that stops recognizing a profile key
|
|
53
|
+
costs one run per version and profile digest before the recorded fallback takes over.
|
|
54
|
+
- The tarball pin rises 355 → 358 (the mirrored bridge suites `codex-exec-jev`, `codex-review-jev`, `agy-jev`).
|
|
55
|
+
|
|
7
56
|
## 14.22.0 — a story runs in four sessions, each step with one checked result; the advisor renders the new review loop (AD-170)
|
|
8
57
|
|
|
9
58
|
**Your project's rules now state the story flow the engine's canon (5.12.0) defines: four sessions — spec and plan,
|
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: agent-workflow-kit
|
|
|
3
3
|
description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow". New to the epic, story and task tier? Run `/agent-workflow-kit tier`. A typed decision with a confidence from Jev? Run `/agent-workflow-kit jev`.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
metadata:
|
|
6
|
-
version: '14.
|
|
6
|
+
version: '14.23.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: antigravity-cli-bridge
|
|
3
3
|
description: Delegate work to Google's Antigravity CLI (`agy`) — the successor to Gemini CLI — to reach Gemini, Claude, and GPT-OSS models under a Google AI Pro/Ultra subscription from the terminal. Use when the user wants to run a headless `agy` prompt, hand a focused task or second-opinion review to `agy`, install or authenticate Antigravity CLI, check or economise its quota/models, bridge project context into `agy`, set up a second delegated-execution backend beside Codex, or troubleshoot `agy` flags, models, auth, conversations, or its headless behaviour.
|
|
4
4
|
metadata:
|
|
5
|
-
version: '
|
|
5
|
+
version: '7.0.0'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# antigravity-cli-bridge
|
|
@@ -43,9 +43,10 @@ wrapper [`bin/agy.sh`](bin/agy.sh) on `PATH` as `agy-run`.
|
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
Never read, print, copy, commit, or package that token — it is personal and is **never bundled** with
|
|
46
|
-
this skill. The wrapper [`bin/agy.sh`](bin/agy.sh) **unsets every `*_API_KEY
|
|
47
|
-
`GEMINI_API_KEY`, `GOOGLE_API_KEY`, `GOOGLE_GENAI_API_KEY`
|
|
48
|
-
|
|
46
|
+
this skill. The wrapper [`bin/agy.sh`](bin/agy.sh) **unsets `OPENAI_BASE_URL` and every `*_API_KEY` except
|
|
47
|
+
`TYPESAFE_API_KEY`** (`ANTIGRAVITY_API_KEY`, `GEMINI_API_KEY`, `GOOGLE_API_KEY`, `GOOGLE_GENAI_API_KEY`
|
|
48
|
+
included; `TYPESAFE_API_KEY` passes as given) before invoking `agy`, so a stray key can never silently
|
|
49
|
+
switch you to pay-as-you-go billing.
|
|
49
50
|
|
|
50
51
|
**Caveat:** the subscription has a finite quota. Keep probes short (see *How the main agent drives
|
|
51
52
|
agy*); the model every review and kept run uses is the host posture below, never a per-call pick.
|
|
@@ -223,11 +224,15 @@ AGY_MODEL="<an offered display string>" agy-run \
|
|
|
223
224
|
```
|
|
224
225
|
|
|
225
226
|
**The Jev skill in a delegated run.** A headless `agy-run` loads the vendor's Jev skill from the user root the kit's
|
|
226
|
-
`jev-skill` command fills, `~/.gemini/config/skills`
|
|
227
|
-
root was listed,
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
`jev-skill` command fills, `~/.gemini/config/skills` (measured 2026-10-02 on agy 1.2.14: a probe skill under that
|
|
228
|
+
root was listed, none under `~/.gemini/antigravity-cli/skills`), and `TYPESAFE_API_KEY` passes the wrappers as given
|
|
229
|
+
while every other `*_API_KEY` is unset; nothing in agy's permissions is widened, no flag is added and no setting is
|
|
230
|
+
written. With the key set, `agy-run` prints one line before dispatch: a headless agy runs the Jev request only where
|
|
231
|
+
the user's agy permissions allow commands, and the first denied command ends the run. `agy-review` makes no Jev
|
|
232
|
+
request while its model obeys its prompts, which forbid every tool; that prohibition is advisory, not a sandbox. The documented opt-in `-- --dangerously-skip-permissions`
|
|
233
|
+
stays admitted, and such a run carries the key into an agy whose network and file tool are unconfined. Two residuals
|
|
234
|
+
stand: the key now sits in every run's environment, and a `web_search` or fetch tool agy is permitted to run may reach
|
|
235
|
+
hosts the bridge never names.
|
|
231
236
|
|
|
232
237
|
## How the main agent drives `agy` efficiently
|
|
233
238
|
|
|
@@ -250,7 +255,8 @@ checklist, prompt templates, output handling). Essentials:
|
|
|
250
255
|
writes (branch/add/commit/stash/reset/rewrite) with the orchestrator, and tell `agy` in the prompt
|
|
251
256
|
to return findings only. Add `-- --sandbox` when delegating anything that could trigger
|
|
252
257
|
terminal/tool work; opt into `-- --add-dir . --dangerously-skip-permissions` only for a flow that
|
|
253
|
-
genuinely needs writes, then review the diff afterwards
|
|
258
|
+
genuinely needs writes, then review the diff afterwards (such a run also carries `TYPESAFE_API_KEY`,
|
|
259
|
+
when set, into an agy whose network and file tool are unconfined).
|
|
254
260
|
|
|
255
261
|
## Complementary skills (optional, standalone-first)
|
|
256
262
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// agy-jev.test.mjs — spec jev-every-run, the agy group (D5(a)): agy-run and agy-review pass TYPESAFE_API_KEY by the
|
|
2
|
+
// shared key rule and widen nothing; agy-run prints its one limit line, never as agy-review's child; the documented
|
|
3
|
+
// opt-in stays admitted. A recording stub stands in front of the harness fake agy.
|
|
4
|
+
import { describe, it, after } from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import { writeFileSync, readFileSync, existsSync, rmSync } from 'node:fs';
|
|
7
|
+
import { join, dirname } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { spawnSync } from 'node:child_process';
|
|
10
|
+
import { makeSandbox, farmFor, FAKE_AGY } from './agy-review-harness.test.mjs';
|
|
11
|
+
|
|
12
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const REVIEW = join(HERE, 'agy-review.sh');
|
|
14
|
+
const AGY_RUN = join(HERE, 'agy.sh');
|
|
15
|
+
const LIMIT = `jev: TYPESAFE_API_KEY passed; a headless agy runs the Jev request only where your agy permissions allow commands ${String.fromCharCode(0x2014)} the first denied command ends the run`;
|
|
16
|
+
const KEYS = { TYPESAFE_API_KEY: 'jev-key', ANTIGRAVITY_API_KEY: 'a', GEMINI_API_KEY: 'g', GOOGLE_API_KEY: 'o', GOOGLE_GENAI_API_KEY: 'n', FOO_API_KEY: 'foo' };
|
|
17
|
+
const PASSED = 'key=[jev-key] google=unset,unset,unset,unset foo=unset';
|
|
18
|
+
|
|
19
|
+
// Every spawn of agy appends its kind and the key states; a run also says so on stderr before the fake answers.
|
|
20
|
+
const RECORDER = [
|
|
21
|
+
'#!/usr/bin/env bash',
|
|
22
|
+
'st() { if [[ -n "${!1+x}" ]]; then printf "[%s]" "${!1}"; else printf unset; fi; }',
|
|
23
|
+
'case "${1:-}" in --help|-h) kind=help ;; --version) kind=version ;; models) kind=models ;; *) kind=run; echo STUB-DISPATCH >&2 ;; esac',
|
|
24
|
+
'echo "$kind key=$(st TYPESAFE_API_KEY) google=$(st ANTIGRAVITY_API_KEY),$(st GEMINI_API_KEY),$(st GOOGLE_API_KEY),$(st GOOGLE_GENAI_API_KEY) foo=$(st FOO_API_KEY) child=$(st AW_AGY_REVIEW_CHILD)" >>"$AGY_JEV_LOG"',
|
|
25
|
+
'exec "$AGY_JEV_FAKE" "$@"',
|
|
26
|
+
'',
|
|
27
|
+
].join('\n');
|
|
28
|
+
|
|
29
|
+
const made = [];
|
|
30
|
+
after(() => {
|
|
31
|
+
for (const home of made) rmSync(home, { recursive: true, force: true });
|
|
32
|
+
});
|
|
33
|
+
const sandbox = () => {
|
|
34
|
+
const sb = makeSandbox();
|
|
35
|
+
made.push(sb.home);
|
|
36
|
+
writeFileSync(join(sb.home, 'agy-fake'), FAKE_AGY, { mode: 0o755 });
|
|
37
|
+
writeFileSync(join(sb.bin, 'agy'), RECORDER, { mode: 0o755 });
|
|
38
|
+
writeFileSync(join(sb.repo, 'plan.md'), '# a plan under review\n');
|
|
39
|
+
return sb;
|
|
40
|
+
};
|
|
41
|
+
const drive = (sb, wrapper, args, env = {}) => {
|
|
42
|
+
const cap = (name) => join(sb.home, name);
|
|
43
|
+
for (const name of ['jev-log', 'jev-argv']) rmSync(cap(name), { force: true });
|
|
44
|
+
const r = spawnSync('bash', [wrapper, ...args], {
|
|
45
|
+
cwd: sb.repo, input: '', encoding: 'utf8', timeout: 60000,
|
|
46
|
+
env: { HOME: sb.home, PATH: `${sb.bin}:${farmFor(['agy', 'agy-run'])}`, TMPDIR: process.env.TMPDIR ?? '/tmp',
|
|
47
|
+
AGY_JEV_LOG: cap('jev-log'), AGY_JEV_FAKE: cap('agy-fake'), AGY_FAKE_ARGV: cap('jev-argv'), ...env },
|
|
48
|
+
});
|
|
49
|
+
const read = (name) => (existsSync(cap(name)) ? readFileSync(cap(name), 'utf8') : '');
|
|
50
|
+
const spawns = read('jev-log').split('\n').filter(Boolean).map((line) => [line.slice(0, line.indexOf(' ')), line.slice(line.indexOf(' ') + 1)]);
|
|
51
|
+
return { status: r.status, stdout: r.stdout, stderr: r.stderr, spawns, argv: read('jev-argv').split('\n').slice(0, -1) };
|
|
52
|
+
};
|
|
53
|
+
const runDirect = (sb, env, extra = []) => drive(sb, AGY_RUN, ['a probe prompt', ...extra], env);
|
|
54
|
+
const keysOf = (env) => env.split(' child=')[0];
|
|
55
|
+
const runSpawn = (r) => (r.spawns.find(([kind]) => kind === 'run') ?? [])[1] ?? '';
|
|
56
|
+
const limitLines = (r) => r.stderr.split('\n').filter((line) => line.startsWith('jev:'));
|
|
57
|
+
|
|
58
|
+
describe('agy-run and agy-review pass the key and unset the rest — spec:jev-every-run/S4', () => {
|
|
59
|
+
for (const [label, wrapper, args] of [['agy-run', AGY_RUN, ['a probe prompt']], ['agy-review plan', REVIEW, ['plan', 'plan.md']]]) {
|
|
60
|
+
it(`${label}: every spawn of agy sees TYPESAFE_API_KEY with the four Google keys and FOO_API_KEY unset`, () => {
|
|
61
|
+
const r = drive(sandbox(), wrapper, args, KEYS);
|
|
62
|
+
assert.equal(r.status, 0, r.stderr);
|
|
63
|
+
assert.ok(r.spawns.some(([kind]) => kind === 'run'), 'agy ran');
|
|
64
|
+
for (const [kind, env] of r.spawns) assert.equal(keysOf(env), PASSED, `${kind} spawn`);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('the agy half of S5: an empty key and an unset key on agy-run', () => {
|
|
70
|
+
it('an empty TYPESAFE_API_KEY reaches agy empty, an unset one stays unset, and the argv is the same with the key set', () => {
|
|
71
|
+
const runs = ['jev-key', '', undefined].map((value) => runDirect(sandbox(), { TYPESAFE_API_KEY: value }));
|
|
72
|
+
assert.deepEqual(runs.map((r) => keysOf(runSpawn(r)).split(' ')[0]), ['key=[jev-key]', 'key=[]', 'key=unset']);
|
|
73
|
+
assert.deepEqual([runs[1].argv, runs[2].argv], [runs[0].argv, runs[0].argv]);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('agy-run prints its one limit line — spec:jev-every-run/S20', () => {
|
|
78
|
+
it('a non-empty key: exactly the one limit line, before dispatch; an empty or an unset key: none', () => {
|
|
79
|
+
const r = runDirect(sandbox(), { TYPESAFE_API_KEY: 'jev-key' });
|
|
80
|
+
assert.equal(r.status, 0, r.stderr);
|
|
81
|
+
assert.deepEqual(limitLines(r), [LIMIT]);
|
|
82
|
+
const lines = r.stderr.split('\n');
|
|
83
|
+
assert.ok(lines.indexOf(LIMIT) < lines.indexOf('STUB-DISPATCH'), r.stderr);
|
|
84
|
+
for (const value of ['', undefined]) {
|
|
85
|
+
const quiet = runDirect(sandbox(), { TYPESAFE_API_KEY: value });
|
|
86
|
+
assert.equal(quiet.status, 0, quiet.stderr);
|
|
87
|
+
assert.deepEqual(limitLines(quiet), [], JSON.stringify(value));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
it('as agy-review\'s child: agy-run runs marked AW_AGY_REVIEW_CHILD=1 with the key, and no limit line is printed', () => {
|
|
91
|
+
const r = drive(sandbox(), REVIEW, ['plan', 'plan.md'], { TYPESAFE_API_KEY: 'jev-key' });
|
|
92
|
+
assert.equal(r.status, 0, r.stderr);
|
|
93
|
+
assert.equal(runSpawn(r), `${PASSED} child=[1]`);
|
|
94
|
+
assert.deepEqual(limitLines(r), []);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('the documented opt-in stays admitted — spec:jev-every-run/S21', () => {
|
|
99
|
+
it('agy-run -- --dangerously-skip-permissions reaches agy\'s argv, the key beside it', () => {
|
|
100
|
+
const r = runDirect(sandbox(), { TYPESAFE_API_KEY: 'jev-key' }, ['--', '--dangerously-skip-permissions']);
|
|
101
|
+
assert.equal(r.status, 0, r.stderr);
|
|
102
|
+
assert.ok(r.argv.includes('--dangerously-skip-permissions'), r.argv.join(' '));
|
|
103
|
+
assert.equal(keysOf(runSpawn(r)), PASSED);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -372,11 +372,24 @@ aw_resolve_timeout_bin() {
|
|
|
372
372
|
[[ -f "$bin" && -x "$bin" ]] || { printf ''; return 0; }
|
|
373
373
|
printf '%s' "$bin"
|
|
374
374
|
}
|
|
375
|
+
aw_scrub_billing_keys() {
|
|
376
|
+
# The one key rule (spec jev-every-run): OPENAI_BASE_URL and every *_API_KEY are unset, so a stray key can never
|
|
377
|
+
# switch a run to paid billing; TYPESAFE_API_KEY is neither read nor set, so it reaches the CLI exactly as given.
|
|
378
|
+
local name
|
|
379
|
+
unset OPENAI_BASE_URL 2>/dev/null || true
|
|
380
|
+
for name in $(compgen -v); do
|
|
381
|
+
case "$name" in
|
|
382
|
+
TYPESAFE_API_KEY) ;;
|
|
383
|
+
*_API_KEY) unset "$name" 2>/dev/null || true ;;
|
|
384
|
+
esac
|
|
385
|
+
done
|
|
386
|
+
return 0
|
|
387
|
+
}
|
|
375
388
|
|
|
376
389
|
# Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
|
|
377
390
|
# version (drift-guarded by agy-review.test.mjs against capability.json).
|
|
378
391
|
AW_RECEIPT_BACKEND="agy"
|
|
379
|
-
AW_BRIDGE_VERSION="
|
|
392
|
+
AW_BRIDGE_VERSION="7.0.0" # aw-version-anchor
|
|
380
393
|
# D5 control-byte screen — IMMEDIATELY after resolution, BEFORE any interpolation can echo raw
|
|
381
394
|
# newline/ESC bytes into stderr/the terminal (round-2 fold).
|
|
382
395
|
if [[ "$AGY_MODEL" == *[$'\x01'-$'\x1f'$'\x7f']* ]]; then
|
|
@@ -563,12 +576,9 @@ read_agy_envelope() { # $1 = captured payload, $2 = response destination, $3 =
|
|
|
563
576
|
node "$AGY_ENVELOPE_READER" "${args[@]}"
|
|
564
577
|
}
|
|
565
578
|
|
|
566
|
-
# --- Subscription invariant
|
|
579
|
+
# --- Subscription invariant: the shared key rule, before the first spawn of agy --------
|
|
567
580
|
export PATH="$HOME/.local/bin:$PATH"
|
|
568
|
-
|
|
569
|
-
while IFS= read -r _api_key_var; do
|
|
570
|
-
unset "$_api_key_var" 2>/dev/null || true
|
|
571
|
-
done < <(compgen -v 2>/dev/null | grep '_API_KEY$' || true)
|
|
581
|
+
aw_scrub_billing_keys
|
|
572
582
|
|
|
573
583
|
if ! command -v agy >/dev/null 2>&1; then
|
|
574
584
|
echo "error: 'agy' (Antigravity CLI) not found on PATH. See this skill's setup/README.md." >&2
|
|
@@ -763,6 +773,10 @@ aw_agy_catalog_check() {
|
|
|
763
773
|
exit 2
|
|
764
774
|
}
|
|
765
775
|
export AW_AGY_CATALOG_READ=1
|
|
776
|
+
# Every child agy-run is this review's (spec jev-every-run): its prompts forbid every tool, so a review whose model
|
|
777
|
+
# obeys them sends no request to api.typesafe.ai (an advisory prohibition, not a sandbox), and the child prints no
|
|
778
|
+
# TYPESAFE_API_KEY limit line.
|
|
779
|
+
export AW_AGY_REVIEW_CHILD=1
|
|
766
780
|
if [[ -n "$AGY_MODEL" ]]; then aw_agy_catalog_check "$aw_review_timeout_bin" "$DEFAULT_AGY_REVIEW_MODEL"; fi
|
|
767
781
|
if [[ "$AGY_MODEL" != "$HOST_AGY_MODEL" && "$AGY_PROBE" != "1" ]]; then
|
|
768
782
|
echo "error: $(aw_agy_shown_model) is a one-off — the host posture is '$HOST_AGY_MODEL', and only a probe (AGY_PROBE=1) runs a one-off; refusing before any run is spent." >&2
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
#
|
|
9
9
|
# Auth: SUBSCRIPTION ONLY. We use the cached OAuth token at
|
|
10
10
|
# ~/.gemini/antigravity-cli/antigravity-oauth-token (Google AI Pro) and the
|
|
11
|
-
# quota that comes with it. To make that guarantee hard, the wrapper unsets
|
|
12
|
-
#
|
|
13
|
-
# pay-as-you-go billing.
|
|
11
|
+
# quota that comes with it. To make that guarantee hard, the wrapper unsets
|
|
12
|
+
# every *_API_KEY except TYPESAFE_API_KEY (which passes as given), so a stray
|
|
13
|
+
# key can never silently switch us to paid pay-as-you-go billing.
|
|
14
14
|
#
|
|
15
15
|
# This is a THIN, FLOW-AGNOSTIC wrapper on purpose: it just runs one headless
|
|
16
16
|
# prompt and prints the text response. It does NOT encode any orchestration
|
|
@@ -65,14 +65,6 @@ esac
|
|
|
65
65
|
# 1. Make `agy` findable even when ~/.bashrc was not sourced.
|
|
66
66
|
export PATH="$HOME/.local/bin:$PATH"
|
|
67
67
|
|
|
68
|
-
# 2. Force the subscription path: never let an API key hijack billing. Unset EVERY *_API_KEY for the
|
|
69
|
-
# agy subprocess — the explicit Google/Antigravity ones first, then any other *_API_KEY that may
|
|
70
|
-
# have been added later (`compgen` is a bash builtin; the shebang guarantees bash).
|
|
71
|
-
unset ANTIGRAVITY_API_KEY GEMINI_API_KEY GOOGLE_API_KEY GOOGLE_GENAI_API_KEY 2>/dev/null || true
|
|
72
|
-
while IFS= read -r _api_key_var; do
|
|
73
|
-
unset "$_api_key_var" 2>/dev/null || true
|
|
74
|
-
done < <(compgen -v 2>/dev/null | grep '_API_KEY$' || true)
|
|
75
|
-
|
|
76
68
|
# This wrapper's applied settings-file subset (see the shared reader block below).
|
|
77
69
|
AW_SETTINGS_APPLIED="AGY_HARD_TIMEOUT"
|
|
78
70
|
DEFAULT_AGY_MODEL="Gemini 3.8 Flash (High)"
|
|
@@ -262,6 +254,23 @@ aw_resolve_timeout_bin() {
|
|
|
262
254
|
[[ -f "$bin" && -x "$bin" ]] || { printf ''; return 0; }
|
|
263
255
|
printf '%s' "$bin"
|
|
264
256
|
}
|
|
257
|
+
aw_scrub_billing_keys() {
|
|
258
|
+
# The one key rule (spec jev-every-run): OPENAI_BASE_URL and every *_API_KEY are unset, so a stray key can never
|
|
259
|
+
# switch a run to paid billing; TYPESAFE_API_KEY is neither read nor set, so it reaches the CLI exactly as given.
|
|
260
|
+
local name
|
|
261
|
+
unset OPENAI_BASE_URL 2>/dev/null || true
|
|
262
|
+
for name in $(compgen -v); do
|
|
263
|
+
case "$name" in
|
|
264
|
+
TYPESAFE_API_KEY) ;;
|
|
265
|
+
*_API_KEY) unset "$name" 2>/dev/null || true ;;
|
|
266
|
+
esac
|
|
267
|
+
done
|
|
268
|
+
return 0
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
# 2. Force the subscription path before the first spawn of agy: the shared key rule (the Google and
|
|
272
|
+
# Antigravity keys included) — no API key can hijack billing.
|
|
273
|
+
aw_scrub_billing_keys
|
|
265
274
|
|
|
266
275
|
if ! command -v agy >/dev/null 2>&1; then
|
|
267
276
|
echo "error: 'agy' (Antigravity CLI) not found on PATH. Install it and run 'agy' once to sign in." >&2
|
|
@@ -422,6 +431,12 @@ fi
|
|
|
422
431
|
|
|
423
432
|
agy_cmd=(agy "${model_flag[@]}" --print-timeout "$AGY_TIMEOUT" "${passthrough[@]}" -p "$prompt")
|
|
424
433
|
|
|
434
|
+
# A non-empty TYPESAFE_API_KEY rides into agy and nothing is widened (spec jev-every-run, D5(a)): the limit, once,
|
|
435
|
+
# before dispatch — never in agy-review's child, whose prompts forbid every tool.
|
|
436
|
+
if [[ -n "${TYPESAFE_API_KEY:-}" && "${AW_AGY_REVIEW_CHILD:-}" != "1" ]]; then
|
|
437
|
+
echo "jev: TYPESAFE_API_KEY passed; a headless agy runs the Jev request only where your agy permissions allow commands — the first denied command ends the run" >&2
|
|
438
|
+
fi
|
|
439
|
+
|
|
425
440
|
# Hard wall-clock cap via timeout(1) (GNU `timeout` on Linux, `gtimeout` from coreutils on macOS).
|
|
426
441
|
# This is the real guard — a backgrounded, hung agy survives its own --print-timeout otherwise.
|
|
427
442
|
# aw_resolve_timeout_bin: builtin type -P (an exported function can shadow neither `timeout` nor
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"schema": 1,
|
|
4
4
|
"name": "antigravity-cli-bridge",
|
|
5
5
|
"kind": "execution-backend",
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "7.0.0",
|
|
7
7
|
"provides": ["review", "probe"],
|
|
8
8
|
"posture": { "model": "Gemini 3.8 Flash (High)" },
|
|
9
9
|
"roles": {
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
{ "slot": "<extra agy flags...>", "required": false, "description": "raw agy flags after -- (a --model* or --effort* flag refuses pre-spend: the model is the host posture or the AGY_MODEL environment value)" }
|
|
181
181
|
],
|
|
182
182
|
"guardrails": [
|
|
183
|
-
{ "value": "subscription-only — every *_API_KEY env var is unset before the run", "enforcement": "enforced", "source": "bin/agy.sh" },
|
|
183
|
+
{ "value": "subscription-only — every *_API_KEY env var except TYPESAFE_API_KEY is unset before the run; TYPESAFE_API_KEY passes as given and nothing in agy's permissions is widened", "enforcement": "enforced", "source": "bin/agy.sh" },
|
|
184
184
|
{ "value": "the model is the host posture (AGY_MODEL in the bridge settings file, else Gemini 3.8 Flash (High)); AGY_MODEL in the environment sets it for one run", "enforcement": "enforced", "source": "bin/agy.sh" },
|
|
185
185
|
{ "value": "hard wall-clock cap AGY_HARD_TIMEOUT (built-in default 5m)", "enforcement": "enforced", "condition": "only while timeout(1)/gtimeout is on PATH — otherwise the wrapper warns and runs uncapped", "source": "capability.json settings.AGY_HARD_TIMEOUT" },
|
|
186
186
|
{ "value": "the prompt rides a single argv — over AGY_MAX_PROMPT_BYTES (120000) the run refuses", "enforcement": "enforced", "source": "bin/agy.sh" },
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
"effect": "agy-review code: the ceiling on the SUM of all outgoing prompt bytes the chunked feed may send (every feed-turn framing block, every body, the final turn). Checked BEFORE the first turn is spent; past it the fed review refuses. An economy guard, not the correctness guard — correctness is the per-part delivery echo."
|
|
241
241
|
}
|
|
242
242
|
],
|
|
243
|
-
"networkHosts": ["*.googleapis.com", "accounts.google.com", "antigravity-unleash.goog", "lh3.googleusercontent.com"],
|
|
243
|
+
"networkHosts": ["*.googleapis.com", "accounts.google.com", "antigravity-unleash.goog", "lh3.googleusercontent.com", "api.typesafe.ai", "docs.typesafe.ai"],
|
|
244
244
|
"writableDirs": [{ "env": null, "default": "~/.gemini/antigravity-cli" }],
|
|
245
245
|
"detect": {
|
|
246
246
|
"installed": {
|
|
@@ -51,9 +51,10 @@ Environment:
|
|
|
51
51
|
| `AGY_HARD_TIMEOUT` | `= AGY_TIMEOUT` | hard `timeout(1)` wall-clock cap (a duration string) |
|
|
52
52
|
| `AGY_MAX_PROMPT_BYTES` | `120000` | single-argv byte ceiling. `agy` takes the prompt as ONE `-p` argv; past `MAX_ARG_STRLEN` (~131072) `execve` fails with a cryptic `Argument list too long`. The wrapper measures the resolved `-`/`@file` prompt and fails loud over the ceiling. A huge **literal** `agy-run "<huge>"` fails at the wrapper's own `exec`, so route large prompts via `-`/`@file`. |
|
|
53
53
|
|
|
54
|
-
Subscription invariant: the wrapper prepends `$HOME/.local/bin` to `PATH` and clears
|
|
55
|
-
`
|
|
56
|
-
|
|
54
|
+
Subscription invariant: the wrapper prepends `$HOME/.local/bin` to `PATH` and clears `OPENAI_BASE_URL`
|
|
55
|
+
and every `*_API_KEY` except `TYPESAFE_API_KEY` (`ANTIGRAVITY_API_KEY` / `GEMINI_API_KEY` /
|
|
56
|
+
`GOOGLE_API_KEY` / `GOOGLE_GENAI_API_KEY` included) before execution; `TYPESAFE_API_KEY` passes as
|
|
57
|
+
given and widens nothing. Auth comes from the user's cached OAuth token, never from bundled credentials.
|
|
57
58
|
|
|
58
59
|
## `agy-review` contract (review role)
|
|
59
60
|
|
|
@@ -34,7 +34,8 @@ agy
|
|
|
34
34
|
This caches an OAuth token under `~/.gemini/antigravity-cli/` (`antigravity-oauth-token`). That token
|
|
35
35
|
is **personal** — never copy, commit, package, print, or share that directory or token. This skill
|
|
36
36
|
needs no API keys and must not be configured with API-key billing; the wrapper unsets every
|
|
37
|
-
`*_API_KEY`
|
|
37
|
+
`*_API_KEY` except `TYPESAFE_API_KEY` (the one key a run passes, as given) so billing can never
|
|
38
|
+
silently fall back to pay-as-you-go.
|
|
38
39
|
|
|
39
40
|
## 3. Put the wrappers on `PATH` (`agy-run` + `agy-review`)
|
|
40
41
|
|
|
@@ -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: '
|
|
5
|
+
version: '5.0.0'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# codex-cli-bridge
|
|
@@ -18,7 +18,8 @@ or a working-tree diff and only emits findings (`codex-review`).
|
|
|
18
18
|
|
|
19
19
|
Use this skill when the user wants to:
|
|
20
20
|
|
|
21
|
-
- Delegate plan or instruction EXECUTION to `codex` in a workspace-write sandbox (network
|
|
21
|
+
- Delegate plan or instruction EXECUTION to `codex` in a workspace-write sandbox (network to
|
|
22
|
+
`api.typesafe.ai` and `docs.typesafe.ai` only where the permissions profile `jev` runs, off elsewhere).
|
|
22
23
|
- Get a second-opinion ADVISORY review of an implementation plan or the current diff.
|
|
23
24
|
- Install, authenticate, smoke-test, or troubleshoot `codex`, or understand its sandbox/flags/models.
|
|
24
25
|
- Drive codex efficiently from the main agent (exec vs review, `resume`, the commit boundary).
|
|
@@ -39,8 +40,9 @@ binary, run `codex login` once under a ChatGPT subscription, then expose this sk
|
|
|
39
40
|
print, copy, commit, or package `~/.codex/auth.json` — it is personal and is **never bundled** with
|
|
40
41
|
this skill. Both wrappers enforce the subscription path before invoking codex:
|
|
41
42
|
|
|
42
|
-
- they **unset every `*_API_KEY
|
|
43
|
-
|
|
43
|
+
- they **unset `OPENAI_BASE_URL` and every `*_API_KEY` except `TYPESAFE_API_KEY`** (`OPENAI_API_KEY`
|
|
44
|
+
and `CODEX_API_KEY` included; `TYPESAFE_API_KEY` passes as given) so a stray key can never silently
|
|
45
|
+
switch you to paid api-key billing;
|
|
44
46
|
- they pass **`--ignore-user-config`** so a personal `~/.codex/config.toml` cannot change model,
|
|
45
47
|
sandbox, or approval behaviour (auth still works — codex reads the login from `CODEX_HOME`
|
|
46
48
|
regardless of that flag);
|
|
@@ -97,7 +99,7 @@ waste, never lowering quality. Full knob list: [§ Environment knobs](#environme
|
|
|
97
99
|
Drive codex only through the two wrappers (installed on `PATH`), run from the target project root:
|
|
98
100
|
|
|
99
101
|
```bash
|
|
100
|
-
# EXECUTION (workspace
|
|
102
|
+
# EXECUTION (workspace writes; network to api.typesafe.ai and docs.typesafe.ai under the profile `jev`, else off; never prompts):
|
|
101
103
|
codex-exec docs/plans/<slug>.md # drive a plan file
|
|
102
104
|
echo "apply review fix: ..." | codex-exec - # ad-hoc instruction from stdin
|
|
103
105
|
codex-exec <file|-> -- <extra codex flags...> # GUARDED passthrough after `--` (policy/model/capture flags rejected; some relaxed only under CODEX_PROBE=1)
|
|
@@ -109,7 +111,7 @@ echo "now do step 2 ..." | codex-exec --resume <session-id> -
|
|
|
109
111
|
# ACCOUNTED EXECUTION (the delegation ledger's exec lane — see "Dispatch identity" below):
|
|
110
112
|
codex-exec --nonce <n> docs/plans/<slug>-dispatch.md # mints a fail-closed exec receipt
|
|
111
113
|
|
|
112
|
-
# REVIEW (read-only
|
|
114
|
+
# REVIEW (read-only: the profile `jev` with no write entry, or --sandbox read-only — codex only emits findings):
|
|
113
115
|
codex-review plan docs/plans/<slug>.md # critique a plan
|
|
114
116
|
codex-review code # review the current working-tree diff (precomputed)
|
|
115
117
|
codex-review code "focus on the new reducer" # review with extra focus
|
|
@@ -118,12 +120,20 @@ codex-review code "focus on the new reducer" # review with extra focus
|
|
|
118
120
|
**Honesty + posture (D4/D5):** a run whose final message has no recognized
|
|
119
121
|
`Verdict: <ship|revise|rethink>` line — empty or missing output included — **exits 4 with NO
|
|
120
122
|
receipt**: treat it as a *failed review to re-run*, never a fatal session error. One stderr banner
|
|
121
|
-
states the actual posture (`review posture: model=… effort=… tier=… source=… timeout=…`) and the
|
|
123
|
+
states the actual posture (`review posture: model=… effort=… tier=… jev=… source=… timeout=…`) and the
|
|
122
124
|
receipt records the same `posture {model, effort, tier}` (tier `null` on the standard tier); control
|
|
123
125
|
bytes in a posture value refuse pre-spend in every mode. `codex-exec` states its posture the same way —
|
|
124
|
-
ONE `exec posture: model=… effort=… tier=… sandbox=workspace-write session=fresh|resume:<id>
|
|
125
|
-
source=… timeout=…` stderr line before dispatch (the resume id validated pre-spend). The `
|
|
126
|
-
field
|
|
126
|
+
ONE `exec posture: model=… effort=… tier=… sandbox=jev-profile|workspace-write session=fresh|resume:<id>
|
|
127
|
+
jev=… source=… timeout=…` stderr line before dispatch (the resume id validated pre-spend). The `jev=`
|
|
128
|
+
field says what the run reaches: `jev=api.typesafe.ai,docs.typesafe.ai` under the permissions profile `jev`
|
|
129
|
+
(Linux, codex-cli 0.160.0 or newer, for `codex-exec` a repository outside every temp root, a codex
|
|
130
|
+
version and profile digest not recorded as refused), else `jev=unreachable (<reason>)` on today's flags.
|
|
131
|
+
A run whose codex refuses the profile (a profile error before the turn starts, or `bwrap: execvp` in a
|
|
132
|
+
failed command) **exits 72** with no success receipt (a review writes none); a refused profile key is
|
|
133
|
+
recorded in `${XDG_STATE_HOME:-~/.local/state}/agent-workflow/codex-jev-profile-refused` when that file
|
|
134
|
+
can be written, so the next run of that wrapper on that version and digest takes today's flags; a
|
|
135
|
+
`bwrap: execvp` failure records nothing. The `jev=`, `source=` (`model:<s>,effort:<s>`,
|
|
136
|
+
each `default`, `setting` or `environment`) and `timeout=` fields
|
|
127
137
|
are **banner-only** (`timeout=` is exactly the duration handed to `timeout(1)`; on exec `uncapped`
|
|
128
138
|
without a capping binary, while `codex-review` **fails CLOSED pre-spend** there) — informational,
|
|
129
139
|
never a receipt field. **Quote the posture banner verbatim** when labeling a dispatch.
|
|
@@ -172,8 +182,9 @@ anything that would defeat a policy is guarded — see [§ Models](#models-the-h
|
|
|
172
182
|
| `CODEX_REVIEW_SCHEMA` | unset | `codex-review`: `=1` returns findings as a validated JSON object (`--output-schema`), with a raw-text fallback. Default off. |
|
|
173
183
|
| `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. |
|
|
174
184
|
|
|
175
|
-
The git-write shim, `--ignore-user-config`,
|
|
176
|
-
|
|
185
|
+
The git-write shim, `--ignore-user-config`, the key rule (`OPENAI_BASE_URL` and every `*_API_KEY` but
|
|
186
|
+
`TYPESAFE_API_KEY` unset) and the choice between the profile and today's flags are NOT env-tunable —
|
|
187
|
+
they are fixed invariants.
|
|
177
188
|
|
|
178
189
|
### Dispatch identity — the accounted exec lane
|
|
179
190
|
|
|
@@ -238,11 +249,17 @@ avoided). And the execution contract tells codex: if the project declares **no**
|
|
|
238
249
|
set, **STOP and report** rather than invent checks. Pass `--skip-git-repo-check` to codex only when
|
|
239
250
|
you truly mean it.
|
|
240
251
|
|
|
241
|
-
**The Jev skill in a delegated run.** A `codex-exec` run loads the vendor's Jev skill from the
|
|
242
|
-
`jev-skill` command fills, `~/.agents/skills`
|
|
243
|
-
skills
|
|
244
|
-
|
|
245
|
-
|
|
252
|
+
**The Jev skill in a delegated run.** A `codex-exec` or `codex-review` run loads the vendor's Jev skill from the
|
|
253
|
+
user root the kit's `jev-skill` command fills, `~/.agents/skills` (a run under `--ignore-user-config` listed its
|
|
254
|
+
skills, measured 2026-10-02; `codex-review` links that root into its fence home), and `TYPESAFE_API_KEY` passes the
|
|
255
|
+
wrappers as given while every other `*_API_KEY` is unset. On Linux with codex-cli 0.160.0 or newer, off a codex
|
|
256
|
+
version and profile digest recorded as refused and, for `codex-exec`, from a repository outside every temp root, the
|
|
257
|
+
run carries the permissions profile `jev`: it reaches `api.typesafe.ai` and `docs.typesafe.ai` and no other host, a review still
|
|
258
|
+
writes nothing, and the banner reads `jev=api.typesafe.ai,docs.typesafe.ai`; anywhere else the run keeps today's
|
|
259
|
+
flags with network off and the banner says `jev=unreachable (<reason>)`. Two residuals stand: codex's server-side
|
|
260
|
+
`web_search` reaches pages outside the profile, and the key now sits in every run's environment, the `web_search`
|
|
261
|
+
channel included. A codex release that stops recognizing a profile key costs one run per version and profile digest
|
|
262
|
+
(exit 72), while the state file can be written, before the recorded fallback takes over.
|
|
246
263
|
|
|
247
264
|
## How the main agent drives `codex` efficiently
|
|
248
265
|
|
|
@@ -263,11 +280,12 @@ See [`references/driving-codex.md`](references/driving-codex.md) for the full pl
|
|
|
263
280
|
resume entrypoint re-establishes EVERY wrapper invariant (subscription-only, `--ignore-user-config`,
|
|
264
281
|
the host posture's model/effort) and **restates the full posture via `-c`** — `codex exec resume` resets the
|
|
265
282
|
sandbox/approval/network posture and rejects the `-s`/`--add-dir`/`-C` posture flags, so the wrapper
|
|
266
|
-
sets `
|
|
267
|
-
`sandbox_workspace_write.network_access=false`
|
|
268
|
-
(`--resume-last`) or takes it as an argument.
|
|
269
|
-
- **Network
|
|
270
|
-
|
|
283
|
+
sets `approval_policy=never` and the run's own posture explicitly — the profile `jev`'s four overrides,
|
|
284
|
+
or `sandbox_mode=workspace-write` + `sandbox_workspace_write.network_access=false` — chosen afresh on
|
|
285
|
+
each resume. It reads the session id from the sidecar (`--resume-last`) or takes it as an argument.
|
|
286
|
+
- **Network: two hosts at most in exec.** Under the profile `jev` a run reaches `api.typesafe.ai` and
|
|
287
|
+
`docs.typesafe.ai` only; under today's flags none. New dependencies and any other network step are
|
|
288
|
+
installed by hand, then codex is re-dispatched.
|
|
271
289
|
- **`codex-review code` precomputes the diff.** The wrapper assembles the change set (repo map, status,
|
|
272
290
|
staged + unstaged diff, untracked file contents) and feeds it in, so codex does not roam the
|
|
273
291
|
filesystem rediscovering it; a clean tree exits 0 before a run is spent. Native `codex review` is
|
|
@@ -293,8 +311,10 @@ The wrappers work in any git repo where `codex` is installed and authenticated.
|
|
|
293
311
|
|
|
294
312
|
## Known limitations
|
|
295
313
|
|
|
296
|
-
- **Network
|
|
297
|
-
|
|
314
|
+
- **Network: two hosts at most** in `codex-exec` — the profile `jev` reaches `api.typesafe.ai` and
|
|
315
|
+
`docs.typesafe.ai` only, today's flags (`sandbox_workspace_write.network_access=false`) none: codex
|
|
316
|
+
cannot install dependencies — do that by hand, then re-dispatch. The profile runs only on Linux with
|
|
317
|
+
codex-cli 0.160.0 or newer; Windows and macOS keep today's flags until its round-trip is probed there.
|
|
298
318
|
- **No live approvals** — `codex exec` has no TTY, so `approval_policy=never`; an action that would
|
|
299
319
|
need escalation is reported, not approved interactively.
|
|
300
320
|
- **`resume` resets the posture** — `codex exec resume` rejects `-s`/`--add-dir`/`-C` and forgets the
|