@sabaiway/agent-workflow-kit 5.3.0 → 5.4.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 +70 -0
- package/README.md +1 -1
- package/SKILL.md +1 -1
- package/bridges/codex-cli-bridge/SKILL.md +3 -2
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +6 -6
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +31 -2
- package/bridges/codex-cli-bridge/bin/codex-review.sh +1 -1
- package/bridges/codex-cli-bridge/capability.json +1 -1
- package/bridges/codex-cli-bridge/references/sandbox-and-flags.md +16 -12
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/core-evidence.md +1 -1
- package/references/modes/coverage-check.md +1 -1
- package/references/modes/gates.md +7 -2
- package/references/modes/recommendations.md +3 -1
- package/references/modes/upgrade.md +1 -1
- package/references/modes/velocity.md +5 -1
- package/references/scripts/migrate-gates.mjs +102 -10
- package/references/scripts/migrate-gates.test.mjs +37 -0
- package/tools/core-evidence.mjs +42 -2
- package/tools/coverage-check.mjs +23 -7
- package/tools/coverage-producer.mjs +68 -0
- package/tools/coverage-state.mjs +24 -0
- package/tools/declared-paths.mjs +32 -0
- package/tools/doc-parity.mjs +19 -4
- package/tools/gates-declaration.mjs +49 -0
- package/tools/gates-init.mjs +83 -6
- package/tools/recommendations.mjs +63 -19
- package/tools/run-gates.mjs +111 -32
- package/tools/velocity-profile.mjs +102 -23
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,76 @@ 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
|
+
## 5.4.0 — a check that certifies nothing now says so, and the render stops promising what no host guarantees (AD-089)
|
|
8
|
+
|
|
9
|
+
**A gate matrix could run green while verifying nothing, and the kit itself was what built it.**
|
|
10
|
+
Neither declaration path ever wired a coverage PRODUCER, yet both declared the coverage CHECKER — so
|
|
11
|
+
a fresh `gates-init` and an `upgrade` alike could leave a project whose `--final` prints three
|
|
12
|
+
`PASS`, `lcov-sha256=none`, `attested=yes`, `status=ok`, exit 0. The honest signal existed on one
|
|
13
|
+
inner line; it reached no surface a consumer keys on. This release stops both kit-owned declaration
|
|
14
|
+
paths from ever ADDING a producer-less pair, makes the withheld verdict travel, and stops the
|
|
15
|
+
autonomy render asserting host behaviour it cannot know. A pair you declare by hand stays yours —
|
|
16
|
+
the kit reports it, it never removes it. Nothing gains a state: exit codes, the `status=` token, the
|
|
17
|
+
receipt `status` enum, `--final` acceptance and the commit-guard disposition are untouched, so an
|
|
18
|
+
optional-coverage project never goes red by surprise.
|
|
19
|
+
|
|
20
|
+
- **Neither kit-owned declaration path ADDS a coverage checker without a producer.**
|
|
21
|
+
`gates-init` wires the lcov reporter flags onto the one allowlist suite body that produces
|
|
22
|
+
coverage unaided, WITHHOLDS the `coverage-check` candidate with a named reason when neither the
|
|
23
|
+
offer nor the existing declaration carries a producer, and — this path alone — refuses at WRITE
|
|
24
|
+
time on the MERGED declaration, because an offer-level check alone still let
|
|
25
|
+
`--apply --only coverage-check` write a dead checker, still let a producer land after an
|
|
26
|
+
already-last checker, and still let a SECOND canonical checker in under a different id. The
|
|
27
|
+
ordering refusal names ORDERING as the cause, so you reorder instead of concluding the producer
|
|
28
|
+
was rejected. `migrate-gates` stops adding the checker into a producer-less declaration and
|
|
29
|
+
reports an already-declared one as INERT — loudly, with the remedy, and removing nothing for you.
|
|
30
|
+
- **One CLOSED producer predicate, shared by every consumer.** Recognition covers the full command
|
|
31
|
+
forms the kit itself emits — never a substring probe, because `echo "$AW_GIT_DIR/…"` or a
|
|
32
|
+
half-written flag set would pass one. The tail rule is a POSITIVE path-shaped grammar rather than
|
|
33
|
+
an operator blocklist: `node --test <flags> && rm -f <lcov>` runs the suite and then deletes the
|
|
34
|
+
file, so an open-ended tail would certify a producer that leaves nothing behind. The residual is
|
|
35
|
+
stated in the source rather than papered over — the screen judges source bytes, so the claim is
|
|
36
|
+
"configured with the reporters", never "the lcov survives the command"; a run that produces none
|
|
37
|
+
is still caught honestly at runtime as `skipped-no-lcov`.
|
|
38
|
+
- **`attested=` binds to the BYTES consumed.** A run that read nothing never certifies, however
|
|
39
|
+
valid its final-run context. The field states that a VERDICT WAS ISSUED — not that coverage
|
|
40
|
+
passed — so a valid handshake over uncovered lines still reads `yes` and still exits 1.
|
|
41
|
+
- **The summary line carries a new closed `coverage=` field** — `certified` / `not-run` / `none` /
|
|
42
|
+
`unknown`, one value defined for every run outcome — and the checker's table row names a withheld
|
|
43
|
+
verdict. Both are derived by CROSS-READING the checker's two anchored machine lines, so a missing,
|
|
44
|
+
duplicated or self-contradicting pair reads `unknown` rather than `certified`. The `--final`
|
|
45
|
+
receipt records the run's own token, and `core-evidence summary` renders the qualifier FROM it
|
|
46
|
+
instead of guessing from `lcovSha256` — which says what a receipt binds and never whether a
|
|
47
|
+
verdict was issued. A pre-5.4.0 receipt is named as a legacy receipt, never as a claim about what
|
|
48
|
+
it read.
|
|
49
|
+
- **New advisor item `gates-inert`** for a declaration that runs green and certifies nothing, with
|
|
50
|
+
two causes and two remedies. Cause A — a canonical `coverage-check` with no producer BEFORE it
|
|
51
|
+
(none at all, or one declared after it, which writes the lcov too late and lets stale bytes be
|
|
52
|
+
certified) — is HAND-APPLY, since the append-only fill cannot reorder an existing declaration.
|
|
53
|
+
Cause B — every declared gate is one of the kit's own checkers — renders the consent-gated
|
|
54
|
+
`gates-init` preview. Cause A decides through the SAME producer-before-checker rule the
|
|
55
|
+
`gates-init` fill enforces at write time — one home, so the advisor and the fill cannot drift
|
|
56
|
+
apart; cause B is advisor-only, with no refusal path behind it. `--final` acceptance is unchanged
|
|
57
|
+
either way: it still requires exactly one canonical coverage checker declared last, and it never
|
|
58
|
+
inspects producers. `flow optimal` no longer renders over either cause.
|
|
59
|
+
- **Every settings-derived RUNTIME claim in the autonomy render is now host-conditional.** Not only
|
|
60
|
+
the bridge-tier exclusion: `allowWrite`, `allowedDomains` and foreign exclusions are all claims
|
|
61
|
+
about what a HOST does with a settings key, and whether a host honours them is runtime-unknowable
|
|
62
|
+
— this kit's own mode doc has recorded that from live observation, while three separate surfaces
|
|
63
|
+
went on promising the bridge wrappers run outside the sandbox. The classification is unchanged;
|
|
64
|
+
only the unconditional promise is gone. The `allowWrite` degrade now resolves its entries
|
|
65
|
+
(tilde, relative and absolute, on segment-aware containment shared with the advisor's
|
|
66
|
+
worktrees-dir lane) and NAMES the external survivors instead of counting them — an entry pointing
|
|
67
|
+
inside the repo or `$TMPDIR` is no longer reported as an `fs_outside_repo` weakening at all, and
|
|
68
|
+
an unreadable value is its own UNVERIFIABLE class that asserts no weakening.
|
|
69
|
+
- **The bundled `codex-cli-bridge` mirror moves to 3.4.1** — a bundled-only bump carrying the fixed
|
|
70
|
+
`codex exec resume` argv, so the changed bridge bytes in this tarball ship under a version of
|
|
71
|
+
their own instead of silently.
|
|
72
|
+
|
|
73
|
+
Upgrading an existing project: nothing breaks and nothing is rewritten for you. If your declaration
|
|
74
|
+
already carries the dead pair, `status`/`upgrade` now say so and hand you the remedy — the reorder
|
|
75
|
+
case deliberately stays hand-applied.
|
|
76
|
+
|
|
7
77
|
## 5.3.0 — a check must speak where it is built to speak: the two silent checks (AD-088)
|
|
8
78
|
|
|
9
79
|
**Two shipped checks stayed SILENT at exactly the point they exist to speak** — one a GATE that
|
package/README.md
CHANGED
|
@@ -239,7 +239,7 @@ file), or run the guarded `/agent-workflow-kit uninstall`.
|
|
|
239
239
|
| `/agent-workflow-kit sandbox-masks` | any time | **cosmetic exclude lane for sandbox device masks** — an OS sandbox (Claude Code) injects character-device masks into the work tree as untracked `git status` noise; the review domain already ignores them **by construction** (never-committable untracked classes — char/block devices, FIFOs, sockets — are excluded from the fingerprint, the assembled review payload, and the clean checks). This mode hides them from `git status` too: flagless = read-only probe (derives the CURRENT mask set from the unfiltered walk + lstat — never a frozen list — and revalidates fenced entries, loudly flagging one that became a real path); `--apply` = consent-gated FULL-BLOCK replace of its own fenced block in `git rev-parse --git-path info/exclude` (stale masks drop by construction; `--clear` always means REMOVE the block — it takes precedence over the derivation). Writes ONLY its fence — never `.gitignore`, never global config; symlinked/non-regular exclude paths and malformed fences fail closed. Watch note: a real file at an excluded path is silently skipped by bulk staging (`git add -A`/`git add .`) — delete the stale line first; the probe flags exactly this case. |
|
|
240
240
|
| `/agent-workflow-kit grounding` | any time | **grounded-review facts assembler** — mechanizes populating `agy-review --facts @f`: slices your entry-point's **Hard Constraints** section verbatim (exactly one match, else a loud stop) and/or a plan's decision-bearing sections (`## Approach` + `## Verification` required, `## Decisions (locked)` when present; duplicates stop), under the same byte budget the agy wrapper enforces (minus `--reserve-bytes` for the artifact share), with a loud tail-trim on overflow. `--autonomy` (AD-044) appends the COMPUTED effective autonomy policy from the git-top `docs/ai/autonomy.json` (every red-line + per-activity level, stated source line; absent file → the computed defaults ARE the policy, exit 0; a malformed policy fails CLOSED, exit 1). Prints to stdout; `--out` writes **one scratch file only** — system-temp outside the repo ($TMPDIR / /tmp, rewritable) or a **fresh** gitignored in-repo path (create-only, exclusive write; an existing in-repo file, even gitignored, is refused — the `.env` clobber class); tracked, not-ignored-in-repo, other outside-repo, and symlink/non-regular destinations are all refused. Never commits, never runs a subscription CLI. |
|
|
241
241
|
| `/agent-workflow-kit core-evidence` | any time | **the ONE loop-evidence writer** (strip-the-kit) — every core evidence record lands in a single append-only JSONL store inside the git dir (never committable; versioned schema, latest-per-key supersession, byte-identical duplicates refused, malformed lines fail every reader closed). `red-proof "<file>#<pattern>"` declares an observed-red **BEFORE a bugfix** (N/N red runs + content custody + base + the pre-fix fingerprint; green/mixed/timeout are DISTINGUISHED refusals — nothing written); `degrade --backend --reason` is the ONLY escape for an unavailable review backend (per-tree, never all backends); `summary` renders the whole loop state statelessly (gate result · per-backend verdicts · red-proofs · degrades) — no ledger, no rounds, nothing remembered. Honest residual: records are forgeable — self-discipline, not a security boundary. Never commits, never runs a subscription CLI. |
|
|
242
|
-
| `/agent-workflow-kit coverage-check` | any time | **the final-run checker** (D3(c)+(d)) — **certifies coverage ONLY inside the `--final` run that owns the lcov** (ownership is exclusive by CONVENTION over the fixed path, not enforced — a concurrent writer to it is a stated residual, queued as LCOV-EXCLUSIVE-OWNERSHIP): an artifact on disk proves nothing about the tree it came from, so a standalone run prints its findings and states `attested=no` / `NO VERDICT` rather than a PASS (an lcov that predates an edit would otherwise certify a line the suite never executed). The runner passes a nonce whose one-way commitment over `{nonce, fingerprint, base}` is the `final-start.attempt` it recorded; a context describing another tree, or matching no recorded attempt, is a REFUSAL, never a verdict. Findings are unchanged — reads the lcov the declared `unit-tests` gate produced at the FIXED git-dir path and fails on any uncovered CHANGED executable Node line (listed `file:line`; a changed file absent from the map is a file-level red; out-of-domain/unsupported files are LISTED — the claim narrowed honestly); VERIFIES every current-base red-proof declaration (bound test exists · custody hash unchanged · green N/N now · pre-fix fingerprint differs); prints `lcov-sha256=<hex|none>` of the exact bytes it consumed — the sha the `--final` receipt binds and re-hashes. An absent lcov is a LOUD `skipped-no-lcov`; a symlinked path is a refusal. `--check` is the gate exit code — declare it as the LAST gate (`run-gates --final` refuses otherwise). Read-only. |
|
|
242
|
+
| `/agent-workflow-kit coverage-check` | any time | **the final-run checker** (D3(c)+(d)) — **certifies coverage ONLY inside the `--final` run that owns the lcov** (ownership is exclusive by CONVENTION over the fixed path, not enforced — a concurrent writer to it is a stated residual, queued as LCOV-EXCLUSIVE-OWNERSHIP): an artifact on disk proves nothing about the tree it came from, so a standalone run prints its findings and states `attested=no` / `NO VERDICT` rather than a PASS (an lcov that predates an edit would otherwise certify a line the suite never executed). `attested=` claims a verdict was ISSUED, pass or fail — a run over uncovered lines still reads `attested=yes` and still exits 1, and a run whose coverage arm never executed (no lcov) reads `attested=no` even inside `--final`, because nothing was read and nothing is certified. The runner passes a nonce whose one-way commitment over `{nonce, fingerprint, base}` is the `final-start.attempt` it recorded; a context describing another tree, or matching no recorded attempt, is a REFUSAL, never a verdict. Findings are unchanged — reads the lcov the declared `unit-tests` gate produced at the FIXED git-dir path and fails on any uncovered CHANGED executable Node line (listed `file:line`; a changed file absent from the map is a file-level red; out-of-domain/unsupported files are LISTED — the claim narrowed honestly); VERIFIES every current-base red-proof declaration (bound test exists · custody hash unchanged · green N/N now · pre-fix fingerprint differs); prints `lcov-sha256=<hex|none>` of the exact bytes it consumed — the sha the `--final` receipt binds and re-hashes. An absent lcov is a LOUD `skipped-no-lcov`; a symlinked path is a refusal. `--check` is the gate exit code — declare it as the LAST gate (`run-gates --final` refuses otherwise). Read-only. |
|
|
243
243
|
| `/agent-workflow-kit commit-guard` | any time | **the read-only pre-commit guard** (D10) — makes the commit capture the whole current working tree, so «verified» and «about to be committed» are the same bytes (the receipt itself has a stated residual — see the mode doc). FIRST it refuses an **INDEX that lags the verified working tree** (the gates and the fingerprint describe the WORKING tree while `git commit` takes the INDEX alone, and the fingerprint cannot tell them apart — so a lagging index used to ship a strict subset of what was verified): unstaged tracked paths or reviewable untracked-not-ignored paths, named up to a bounded cap with the remainder stated, a dirty tracked **submodule** named separately with its own recovery, and fail-closed on an undecidable probe. This deliberately blocks a partial commit. Then it binds the LATEST completed `run-gates --final` receipt to the EXACT current tree: refuses on a missing/red/stale receipt, fingerprint drift under the run, a dangling later attempt, declaration content drift, evidence-hash or lcov drift, or unsatisfied review obligations (the same review-state decision, recomputed over a sanitized env — forged out-of-repo stores never satisfy). Re-runs NO gate or test. Wire it into `.git/hooks/pre-commit` (the installer writes the RESOLVED invocation). `git commit --no-verify` stays the stated residual. |
|
|
244
244
|
| `/agent-workflow-kit recommendations` | any time (every `upgrade` ends with it) | **read-only deployment advisor** (AD-044) — computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, OS sandbox unavailable, gates undeclared, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe) and renders **verdict-first**: one composed verdict line (does anything need attention?), then each item as **{severity · what · one-line benefit · an optional `recipe:` line (the sandbox-lane live recipe, the worktrees-dir hand-apply-first grant advice, or the agents hidden-mode reconcile follow-up) · the exact consent-gated apply one-liner}**. The agent PRESENTS the section in the user's conversational language — every fact and count, nothing added or dropped; commands, paths, hosts and rule strings byte-exact; raw tool block on request — and runs EXACTLY the rendered one-liners only on your yes, surfacing each item's posture note first. Renders **present-even-when-empty** (`no recommendations — flow optimal.`); a failed probe degrades to a stated skip line. Registry strings are fact-true frozen one-line data (posture/risk notes live in the mode doc at the consent moment); the kit never seeds `sandbox.network.allowedDomains` / `filesystem.allowWrite` (**HAND-APPLY** territory), and the sandbox-lane item's convergence is a neutral fingerprint acknowledgement recorded by a consent-gated ack writer into `docs/ai/acks.json` — never a security key (the recipe is documented per bridge in `capability.json` `networkHosts` + `writableDirs`). `--cwd` is required (the target project is explicit); never writes, never commits, never runs a subscription CLI. |
|
|
245
245
|
| `/agent-workflow-kit doc-parity` | any time | **read-only doc-parity lint** (AD-049) — kills the doc-drift class where a mode-contract doc silently lags a code constant (a `--check` doc still reading `300` after the diff cap moved to `400`): a **closed, exported registry** binds each live constant (review caps, schema versions, the ledger's own class/scope vocabulary, and the autonomy-doctor EXIT/status/trusted-dir contract) to the exact token its `references/modes/*.md` contract must carry, and asserts the CURRENT value renders into every bound file — a drifted doc, an unreadable file, or an absent token **fails closed**. The values are sourced from the live imports (never re-typed), so the lint can't itself go stale; adding a binding is adding a checked entry (closed-world, edit-safe). `--check` is a gate exit code for `docs/ai/gates.json`. Never writes, never commits, never runs a subscription CLI. |
|
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".
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
metadata:
|
|
6
|
-
version: '5.
|
|
6
|
+
version: '5.4.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
|
@@ -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.4.
|
|
5
|
+
version: '3.4.1'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# codex-cli-bridge
|
|
@@ -112,7 +112,8 @@ receipt field. **Quote the posture banner verbatim** when labeling a dispatch.
|
|
|
112
112
|
escalation is refused and reported, never interactively approved. The wrappers capture only codex's
|
|
113
113
|
**final message** (`-o`), so output is clean; the JSON event stream + reasoning go to a run trace
|
|
114
114
|
that is **read before it is discarded**. Fresh and resumed runs share **ONE** capture posture
|
|
115
|
-
(`-o` + `--json
|
|
115
|
+
(`-o` + `--json`, everything redirected into the trace; `--color never` rides the fresh lane only —
|
|
116
|
+
`codex exec resume` does not accept it), so both modes have the
|
|
116
117
|
same evidence surface — and the wrapper scans that surface on **every completed run**: a run that
|
|
117
118
|
SURVIVES a nested-sandbox failure exits 0 with an ungrounded answer, so on `rc == 0` it prints the
|
|
118
119
|
answer first and then warns loudly on stderr when one `command_execution` item with a **proven**
|
|
@@ -619,11 +619,12 @@ chmod 755 "$shim_dir/git"
|
|
|
619
619
|
|
|
620
620
|
# --- Build the codex invocation + the prompt ---------------------------------
|
|
621
621
|
if [[ -n "$resume_mode" ]]; then
|
|
622
|
-
# Resume RESETS posture and rejects the -s/--add-dir/-C posture flags, so restate
|
|
623
|
-
#
|
|
624
|
-
#
|
|
625
|
-
#
|
|
626
|
-
#
|
|
622
|
+
# Resume RESETS posture and rejects the -s/--add-dir/-C posture flags, so restate the entire
|
|
623
|
+
# policy via -c. Its accepted flag set is NARROWER than `codex exec`'s and is probed, never
|
|
624
|
+
# assumed: `codex exec resume --help` (codex-cli 0.147.0) accepts -o and --json but NOT --color,
|
|
625
|
+
# so the capture posture is shared with a fresh run MINUS that flag. Shipping --color here once
|
|
626
|
+
# broke every resume invocation with a pre-spend exit 2 — the fake CLI in the suite accepts any
|
|
627
|
+
# argv, so only the real one can answer this question. See RESUME_ACCEPTED_FLAGS in the test.
|
|
627
628
|
codex_cmd=(codex exec resume "$resume_id"
|
|
628
629
|
--ignore-user-config
|
|
629
630
|
-m "$CODEX_MODEL"
|
|
@@ -634,7 +635,6 @@ if [[ -n "$resume_mode" ]]; then
|
|
|
634
635
|
-c hide_agent_reasoning=true
|
|
635
636
|
-c model_reasoning_summary=none
|
|
636
637
|
"${tier_flags[@]+"${tier_flags[@]}"}"
|
|
637
|
-
--color never
|
|
638
638
|
-o "$out"
|
|
639
639
|
--json
|
|
640
640
|
-)
|
|
@@ -644,6 +644,33 @@ describe('codex-exec.sh — resume entrypoint restates every invariant (3.1)', (
|
|
|
644
644
|
/approval_policy=never/, /sandbox_workspace_write\.network_access=false/,
|
|
645
645
|
];
|
|
646
646
|
|
|
647
|
+
// `codex exec resume` accepts a NARROWER flag set than `codex exec`, and the difference is not
|
|
648
|
+
// guessable: the hermetic fake accepts any argv, so a flag the real CLI rejects passes every unit
|
|
649
|
+
// test and then fails pre-spend on the first live resume. That happened — `--color never` was
|
|
650
|
+
// added to this lane unprobed and broke it outright. This list is transcribed from
|
|
651
|
+
// `codex exec resume --help` on codex-cli 0.147.0 (probed 2026-08-08); anything the wrapper sends
|
|
652
|
+
// that is not on it fails HERE instead of in front of a user.
|
|
653
|
+
const RESUME_ACCEPTED_FLAGS = new Set([
|
|
654
|
+
'--last', '--all', '-c', '--config', '--enable', '-i', '--image', '--strict-config', '--disable',
|
|
655
|
+
'-m', '--model', '--dangerously-bypass-approvals-and-sandbox', '--dangerously-bypass-hook-trust',
|
|
656
|
+
'--skip-git-repo-check', '--ephemeral', '--ignore-user-config', '--ignore-rules',
|
|
657
|
+
'--output-schema', '--json', '-o', '--output-last-message', '-h', '--help',
|
|
658
|
+
]);
|
|
659
|
+
|
|
660
|
+
it('every flag the resume lane sends is one the REAL `codex exec resume` accepts', () => {
|
|
661
|
+
const sb = makeSandbox();
|
|
662
|
+
const r = run(sb, { args: ['--resume', 'sess-flags', '-'], input: 'go' });
|
|
663
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
664
|
+
assert.equal(r.status, 0, r.stderr);
|
|
665
|
+
const sent = r.argv.split('\n').filter((a) => a.startsWith('-') && a !== '-');
|
|
666
|
+
assert.ok(sent.length > 0, 'the resume argv must carry flags at all');
|
|
667
|
+
for (const flag of sent) {
|
|
668
|
+
assert.ok(RESUME_ACCEPTED_FLAGS.has(flag),
|
|
669
|
+
`resume sends ${flag}, which \`codex exec resume --help\` does not list — it would exit 2 pre-spend`);
|
|
670
|
+
}
|
|
671
|
+
assert.equal(sent.includes('--color'), false, 'the regression this list exists to prevent');
|
|
672
|
+
});
|
|
673
|
+
|
|
647
674
|
it('--resume <id>: composes `exec resume <id>` with the full restated policy', () => {
|
|
648
675
|
const sb = makeSandbox();
|
|
649
676
|
const r = run(sb, { args: ['--resume', 'sess-xyz', '-'], input: 'continue please' });
|
|
@@ -657,14 +684,16 @@ describe('codex-exec.sh — resume entrypoint restates every invariant (3.1)', (
|
|
|
657
684
|
// The capture unification: resume used to be the odd mode out — no -o, no --json, its event
|
|
658
685
|
// stream nowhere — which is precisely why the lane the nested-sandbox incident fired on had no
|
|
659
686
|
// evidence surface. `codex exec resume` accepts both (live-probed, codex-cli 0.147.0).
|
|
660
|
-
it('resume composes the unified capture —
|
|
687
|
+
it('resume composes the unified capture — -o and --json, and NOT --color (which it rejects)', () => {
|
|
661
688
|
const sb = makeSandbox();
|
|
662
689
|
const r = run(sb, { args: ['--resume', 'sess-unified', '-'], input: 'continue please' });
|
|
663
690
|
rmSync(sb.root, { recursive: true, force: true });
|
|
664
691
|
assert.equal(r.status, 0, r.stderr);
|
|
665
692
|
assert.match(r.argv, /(^|\n)-o(\n|$)/, 'resume writes the final message through -o');
|
|
666
693
|
assert.match(r.argv, /(^|\n)--json(\n|$)/, 'resume streams the structured events');
|
|
667
|
-
|
|
694
|
+
// The evidence surface is shared with a fresh run; the COLOUR flag is not, because
|
|
695
|
+
// `codex exec resume` does not accept it. Sending it exits 2 before the run starts.
|
|
696
|
+
assert.equal(/(^|\n)--color(\n|$)/.test(r.argv), false, 'resume rejects --color — probed on codex-cli 0.147.0');
|
|
668
697
|
assert.match(r.stdout, /FAKE_FINAL_MESSAGE/, 'resume stdout is still the final message');
|
|
669
698
|
});
|
|
670
699
|
|
|
@@ -278,7 +278,7 @@ DEFAULT_CODEX_EFFORT="xhigh"
|
|
|
278
278
|
# Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
|
|
279
279
|
# version (drift-guarded by codex-review.test.mjs against capability.json).
|
|
280
280
|
AW_RECEIPT_BACKEND="codex"
|
|
281
|
-
AW_BRIDGE_VERSION="3.4.
|
|
281
|
+
AW_BRIDGE_VERSION="3.4.1"
|
|
282
282
|
CODEX_MODEL="${CODEX_MODEL:-$DEFAULT_CODEX_MODEL}"
|
|
283
283
|
CODEX_EFFORT="${CODEX_EFFORT:-$DEFAULT_CODEX_EFFORT}"
|
|
284
284
|
# Generous hard cap for a slow xhigh review (subscription latency varies).
|
|
@@ -43,10 +43,10 @@ and passes no separate network flag — the `sandbox_workspace_write.*` config (
|
|
|
43
43
|
codex's final message; `--json` streams the structured event stream (incl. `thread.started`, which
|
|
44
44
|
carries the session id) into the run trace, with stderr merged into it; `--color never` +
|
|
45
45
|
`-c hide_agent_reasoning=true` + `-c model_reasoning_summary=none` strip colour and chain-of-thought.
|
|
46
|
-
`codex exec resume` accepts `-o` and `--json` too (live-probed on codex-cli 0.147.0
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
`codex exec resume` accepts `-o` and `--json` too (live-probed on codex-cli 0.147.0 — though NOT
|
|
47
|
+
`--color`, which stays on the fresh lane), so the resume lane is no longer the odd one out: it used
|
|
48
|
+
to print its final message straight to stdout with the event stream nowhere, which left the very
|
|
49
|
+
mode a nested-sandbox incident fired on without a structured evidence surface. Net effect: the wrapper prints just the final answer. **Reasoning still runs at
|
|
50
50
|
`xhigh`** — quality is unchanged; only the *noise* is dropped. On success `codex-exec` extracts the
|
|
51
51
|
session id from the trace and records it to `${CODEX_SESSION_FILE:-./.codex-last-session}` (so
|
|
52
52
|
`--resume-last` can find it) and echoes `session: <id>` to stderr. On a missing/empty final-message
|
|
@@ -145,14 +145,18 @@ the prompt fence ("do not read outside the working tree, except the precomputed-
|
|
|
145
145
|
|
|
146
146
|
## `resume` — resets posture, restated via `-c`
|
|
147
147
|
|
|
148
|
-
`codex exec resume` re-dispatches an existing session without re-sending context.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
148
|
+
`codex exec resume` re-dispatches an existing session without re-sending context. Its accepted flag
|
|
149
|
+
set is **NARROWER than `codex exec`'s** and must be read off `codex exec resume --help`, never
|
|
150
|
+
assumed from the parent command: it **rejects the posture flags** `-s`/`--add-dir`/`-C`, **resets**
|
|
151
|
+
the sandbox/approval/network posture, and — probed on codex-cli 0.147.0 — accepts
|
|
152
|
+
`-c`/`-m`/`--last`/`-o`/`--json` but **NOT `--color`**. Sending an unaccepted flag exits 2 before the
|
|
153
|
+
run starts, so the failure is loud and costs no quota; the wrapper's own test pins the accepted set
|
|
154
|
+
(`RESUME_ACCEPTED_FLAGS`) precisely because the hermetic fake CLI accepts any argv and cannot answer
|
|
155
|
+
this question. The `codex-exec --resume`/`--resume-last` entrypoint handles the reset: it restates
|
|
156
|
+
the entire policy via `-c` (`sandbox_mode=workspace-write`, `approval_policy=never`,
|
|
157
|
+
`sandbox_workspace_write.network_access=false`) plus the pinned `-m`/effort and
|
|
158
|
+
`--ignore-user-config`, reads the session id from the sidecar (or an argument), and applies the same
|
|
159
|
+
EVIDENCE posture as a fresh run — `-o` for the final message, `--json` into the trace. Only a *raw*
|
|
156
160
|
`codex exec resume` outside the wrapper loses the posture.
|
|
157
161
|
|
|
158
162
|
## Hard timeout
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -8,7 +8,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/core-evidence.mjs <verb> …`:
|
|
|
8
8
|
|
|
9
9
|
1. **`red-proof "<test-file>#<test-name-pattern>"`** — the D3(c) observed-red DECLARATION, minted **BEFORE a bugfix is applied**: it runs the named test N times (default 3, `AW_CORE_EVIDENCE_RERUNS`; per-run timeout `AW_CORE_EVIDENCE_TIMEOUT_S`) on the CURRENT (pre-fix) tree, requires red N/N (observed green / unresolvable / mixed / timed-out are DISTINGUISHED refusals — nothing is written; mixed/timeout is QUARANTINE, no override lane), and records { testId · repo-relative file · content sha256 (custody) · N/N red · base = HEAD sha · the pre-fix tree fingerprint }. The final run (`coverage-check --check`) then requires every current-base record's test green N/N with the hash unchanged; a record whose pre-fix fingerprint EQUALS the current tree never satisfies (nothing changed — reuse/forgery); a commit expires records (base moves); editing a bound test file means re-observing red (the new record supersedes the old — same {base, testId} key).
|
|
10
10
|
2. **`degrade --backend <name> --reason "<why>"`** — the ONLY escape from a required review backend (D3(b)): an explicit per-backend, per-tree record at the CURRENT fingerprint. Never all backends: the review gate still requires ≥1 non-degraded ship-class receipt whenever ≥1 backend is configured. Any tree edit re-stales the record (fingerprint-bound).
|
|
11
|
-
3. **`summary`** — the ONE stateless end-of-loop render (D6): gate result from the latest final attempt, per-backend verdicts from the review receipts, red-proof outcomes, degrade records. Computed from the stores at read time — no ledger, no rounds, nothing remembered. A malformed store exits non-zero and WITHHOLDS the affected section, never renders a partial as complete.
|
|
11
|
+
3. **`summary`** — the ONE stateless end-of-loop render (D6): gate result from the latest final attempt, per-backend verdicts from the review receipts, red-proof outcomes, degrade records. Computed from the stores at read time — no ledger, no rounds, nothing remembered. A malformed store exits non-zero and WITHHOLDS the affected section, never renders a partial as complete. The final-run line NAMES an absent coverage verdict from the `coverage` token the run RECORDED (an ADDITIVE optional field on the `final` record — the closed `certified | not-run | unknown` set, never `none`, and `certified` requires a bound `lcovSha256`): GREEN never renders unqualified over a run that issued no verdict. A LEGACY receipt carrying no token and no lcov digest is named as exactly that, never as a claim about what it read — the withheld verdict travels here too, as DETAIL beside the unchanged status word.
|
|
12
12
|
|
|
13
13
|
**Promptless writer lane (D7):** both verbs ride plain `node ${CLAUDE_SKILL_DIR}/tools/core-evidence.mjs …` invocations — surface the paste-ready allow entries once (`.claude/settings.json`), and a full loop transcript runs at zero writer approval prompts.
|
|
14
14
|
|
|
@@ -6,7 +6,7 @@ The **final-run checker** (strip-the-kit D3(c)+(d)) — two deterministic arms o
|
|
|
6
6
|
|
|
7
7
|
Run `node ${CLAUDE_SKILL_DIR}/tools/coverage-check.mjs --check [--cwd <dir>]`:
|
|
8
8
|
|
|
9
|
-
0. **Attestation precondition (the provenance arm).** An lcov on disk carries no evidence of the tree it came from, so reading one and issuing a verdict certifies whatever happens to be there — the false GREEN direction is the dangerous one, because a line appended AFTER the suite ran has no `DA` entry and therefore reads non-executable ("nothing to cover"). Provenance is a CONSEQUENCE in exactly one context: a `run-gates --final` run deletes the artifact before any gate spawns. That runner mints a random nonce and writes `final-start.attempt` as a ONE-WAY COMMITMENT over `{nonce, tree fingerprint, base}`; the raw nonce rides the environment to this child, which recomputes the commitment and requires the record to carry it. Neither half suffices alone — a bare nonce is unverifiable, a persisted attempt id is reconstructible from public repo state — and the commitment is also the only place the BASE is bound, since no record stores it. The raw nonce is stripped from the red-proof probe environment so no descendant retains a live capability. Outcomes: **attested** → the coverage verdict is issued; **no handshake** → `attested=no` + `NO VERDICT` (exit 0, findings still printed, uncovered lines still exit 1 — the findings contract is unchanged); **a handshake describing another tree or matching no recorded attempt** → `REFUSED` (exit 1), never a verdict in either direction. One fully anchored `coverage-check: attested=<yes|no>` machine line rides every run, on the same exactly-once contract as the sha line. Stated residuals, both named rather than implied: (a) an operator who runs both processes can forge the store or the code — the kit's standing self-discipline posture, not a security boundary; (b) **"the run owns the artifact" is exclusive by CONVENTION over the fixed path, not enforced** — a writer outside the run (a second `run-gates`, a hand-run `--only unit-tests`, an orphaned test process) can place foreign evidence between the deletion and the checker's read, and every check then agrees. Closing (b) needs an attempt-unique artifact path, which the runner can name but the declared producer cmd must reference — queued as LCOV-EXCLUSIVE-OWNERSHIP. What this arm removes is the false green that needs no second process and nobody trying: evidence that predates the edit.
|
|
9
|
+
0. **Attestation precondition (the provenance arm).** An lcov on disk carries no evidence of the tree it came from, so reading one and issuing a verdict certifies whatever happens to be there — the false GREEN direction is the dangerous one, because a line appended AFTER the suite ran has no `DA` entry and therefore reads non-executable ("nothing to cover"). Provenance is a CONSEQUENCE in exactly one context: a `run-gates --final` run deletes the artifact before any gate spawns. That runner mints a random nonce and writes `final-start.attempt` as a ONE-WAY COMMITMENT over `{nonce, tree fingerprint, base}`; the raw nonce rides the environment to this child, which recomputes the commitment and requires the record to carry it. Neither half suffices alone — a bare nonce is unverifiable, a persisted attempt id is reconstructible from public repo state — and the commitment is also the only place the BASE is bound, since no record stores it. The raw nonce is stripped from the red-proof probe environment so no descendant retains a live capability. `attested=` states whether a coverage VERDICT was ISSUED — pass **or** fail — never whether coverage passed: a valid handshake over an lcov that lists uncovered lines still reads `attested=yes` and still exits 1. Outcomes: **attested** → the coverage verdict is issued; **no handshake** → `attested=no` + `NO VERDICT` (exit 0, findings still printed, uncovered lines still exit 1 — the findings contract is unchanged); **a valid handshake over a run that read NO lcov BYTES** (the file is absent, or the path was refused as a non-regular file) → `attested=no` + `NO VERDICT`: the run owned the artifact's lifetime and read nothing, so it certifies NOTHING — reading `yes` there would be the false green this arm exists to close, one layer up. The predicate is the consumed bytes (`lcov-sha256` is a digest, not `none`), never the skip flag, so a refused path can never attest either. The two halves are independent: WITHHOLDING the verdict never changes an exit code — an absent file stays exit 0 (the loud `skipped-no-lcov`), and the refused non-regular path keeps its OWN fail-closed exit 1; **a handshake describing another tree or matching no recorded attempt** → `REFUSED` (exit 1), never a verdict in either direction. One fully anchored `coverage-check: attested=<yes|no>` machine line rides every run, on the same exactly-once contract as the sha line — and a withheld verdict TRAVELS: `run-gates` carries it as `coverage=not-run` on the summary line and names it on the checker's table row, and `core-evidence summary` never renders an unqualified GREEN over a final record that consumed no lcov. Stated residuals, both named rather than implied: (a) an operator who runs both processes can forge the store or the code — the kit's standing self-discipline posture, not a security boundary; (b) **"the run owns the artifact" is exclusive by CONVENTION over the fixed path, not enforced** — a writer outside the run (a second `run-gates`, a hand-run `--only unit-tests`, an orphaned test process) can place foreign evidence between the deletion and the checker's read, and every check then agrees. Closing (b) needs an attempt-unique artifact path, which the runner can name but the declared producer cmd must reference — queued as LCOV-EXCLUSIVE-OWNERSHIP. What this arm removes is the false green that needs no second process and nobody trying: evidence that predates the edit.
|
|
10
10
|
1. **Coverage arm (D3(d)):** every CHANGED executable Node line (`.mjs`/`.cjs`/`.js`, tracked working-vs-HEAD changes + untracked-not-ignored files) must be covered — uncovered lines are LISTED `file:line` and fail; a changed file ABSENT from the lcov map is a file-level red (never "non-executable" by silence); changed out-of-domain files (e.g. `.sh`) and unsupported-source files (e.g. `.ts`) are LISTED — the claim is narrowed honestly, not widened. NO lcov file at the path = a LOUD `skipped-no-lcov` (exit 0, stated — produce the file via the unit-tests gate's lcov reporters); a symlink at the path is a refusal (lstat, no-follow).
|
|
11
11
|
2. **Red-proof arm (D3(c)):** every authoritative current-base `red-proof` declaration must verify — the bound test file exists (deleted fails), its content sha256 matches the declaration (custody), the test resolves (zero-match fails) and runs green N/N NOW, and the declaration's pre-fix fingerprint differs from the current tree (equal = reuse/forgery, refused). A malformed evidence store fails CLOSED.
|
|
12
12
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
### Mode: gates
|
|
2
2
|
|
|
3
3
|
<!-- opt-in-capability: gates-declaration -->
|
|
4
|
+
<!-- opt-in-capability: gates-verification -->
|
|
4
5
|
|
|
5
6
|
The **generic project gate runner** — it batches the project's OWN declared verification commands into one run. The runner itself **writes nothing on a plain run, never commits, and never runs a subscription CLI**; what it EXECUTES is the project's own declaration, with the caller's privileges (trust posture: a batching convenience over commands the project already runs by hand — **not a sandbox**). Two modes write state: **`--final`** runs the FULL declared matrix as the D3(a) final verification run and mints the receipt the commit guard consumes (step 4), and an ARMED **`--pre-review`** records its subset attempt in the flow store (step 3; unarmed repos byte-unchanged).
|
|
6
7
|
|
|
7
8
|
Run `node ${CLAUDE_SKILL_DIR}/tools/run-gates.mjs [--cwd <project>] [--only <id>]… [--final]`:
|
|
8
9
|
|
|
9
10
|
1. **Reads `docs/ai/gates.json`** (strict JSON, hand-editable; seeded from `references/templates/gates.json`). Each gate is `{ id, title, cmd }` — `id` a unique kebab handle, `cmd` **ONE bash command line** (brace/glob expansion works; a host without bash gets a loud preflight error, exit 6 — never a silent reinterpretation under another shell). The declaration names **WHAT to check, never who executes it** — the schema has no lane/model/routing fields and rejects unknown keys loudly.
|
|
10
|
-
2. **Runs each gate from the project root** and prints a per-gate **PASS/FAIL table** plus **one machine-readable summary line** as the last line (`[run-gates] status=… gates=… passed=… failed=… failed_ids=…`). A failing gate's own output is preserved **verbatim** (triage without re-running); a green gate's output is not echoed; gates after a failure still run. **Exit 0 iff all selected gates are green.**
|
|
11
|
+
2. **Runs each gate from the project root** and prints a per-gate **PASS/FAIL table** plus **one machine-readable summary line** as the last line (`[run-gates] status=… gates=… passed=… failed=… failed_ids=… coverage=…`). A failing gate's own output is preserved **verbatim** (triage without re-running); a green gate's output is not echoed; gates after a failure still run. **Exit 0 iff all selected gates are green.**
|
|
11
12
|
3. **Honest outcomes, each distinct — never a silent green:** a **missing** declaration (exit 3 — the report names the recovery: create `docs/ai/gates.json` from the template; `upgrade` re-seeds a missing one), an **empty** `gates` list (exit 4), a **malformed/invalid** declaration (exit 5, loud `path: reason`). Repeatable **`--only <id>`** re-runs a subset; an unknown id is a loud usage error (exit 2). **`--pre-review`** runs the DERIVED mechanical subset (#66): the full matrix minus every gate whose cmd is a canonical kit checker invocation — derivation **matches canonical checker paths in the cmd strings** (realpath-resolved `--check` forms of review-state / commit-guard / coverage-check / flow-check, never a project-authored id), so a project abstracting a checker behind its own script declares it in `flow.pregateExclude` (an unknown id refuses loudly, exit 5). A failing subset gate gets the review-dependent diagnosis, naming the mechanical reset (a declared exclude changes the `subsetDigest`). **Under an ARMED flow (exactly one open adopted chain owned by this worktree) every subset run is RECORDED** as a `subset-attempt` via the flow store's locked append factory — the context keys `{planId, cycle, stepId, foldBatch, subsetDigest}`; index + hard-stop state are computed under the lock against the pre-run identity. **Hard stop (Decision 7/8):** the SECOND red records and exits red; past two reds every attempt needs `--diagnosis "<non-empty, byte-distinct from the prior>"` (recorded, self-servable); the THIRD red EXHAUSTS the context — further solo runs refuse, and only a recorded fresh-eyes consult verdict (a grounded bridge consult-attestation at this round context) reopens ONE further attempt. Armed-but-unrecordable (zero/several open chains, broken store) refuses loudly; a spawn failure records NO attempt; unarmed repos stay byte-unchanged. Mutually exclusive with `--only`/`--final` (exit 2); plain and `--final` runs never load the config.
|
|
12
13
|
4. **`--final`** — the D3(a) final verification run: it REFUSES `--only` (a subset never attests) and a declaration lacking the canonical core checks (ONE plain invocation each of the kit's OWN `review-state.mjs --check` and `coverage-check.mjs --check`, the checker declared LAST — a masked form, a compound, or a lookalike path never counts); deletes the stale git-dir lcov before the suite; exports `AW_GIT_DIR` + `AW_LCOV_FILE` to every gate cmd; records EVERY attempt (start + completed green/red) in the core-evidence store via its sole writer; and binds the receipt to { fingerprint before/after · the full declaration · per-gate results · the canonical red-proof + degrade evidence hashes · the sha of the lcov the checker actually read (exactly ONE `lcov-sha256` machine line, end-re-hashed) · **`evidenceHashes.flow`** when a flow store exists (D10: the sha of the OWNER-SCOPED flow projection — foreign worktrees never move it, except same-fingerprint planId-less globals, which share this tree's decision context; absent store → absent field; a broken store refuses up front) }. An artifact moving UNDER the run — the flow projection included — is a named `integrityFailure`; the receipt lands red. Stated residual: the movement arm is best-effort — an append racing the receipt write is refused at commit by the guard. A receipt that cannot be written is its own distinct outcome (exit 8): green gates never read as success without it. `${CLAUDE_SKILL_DIR}/references/modes/commit-guard.md` consumes the receipt at commit time (the guard re-hashes the live projection against it — a post-final append, or the store vanishing, refuses the commit).
|
|
13
14
|
|
|
@@ -19,6 +20,10 @@ Declared gates can also be **auto-approved** (no permission prompt on a byte-exa
|
|
|
19
20
|
|
|
20
21
|
**Candidate line — the review-receipt gate (opt-in, never auto-seeded; AD-021).** Projects that configure a reviewed/council `plan-execution.review` recipe can declare the review-state check as one more gate — the exact candidate `{ id, title, cmd }` line and its contract live under `${CLAUDE_SKILL_DIR}/references/modes/review-state.md` (step 3).
|
|
21
22
|
|
|
22
|
-
**Consent-gated filling — the init preview, not part of the runner (D9).** The template `gates.json` is seeded EMPTY; FILLING it is a consented preview at init (`node ${CLAUDE_SKILL_DIR}/tools/gates-init.mjs --cwd <project>`, dry-run by default — prints the derived entries and **writes NOTHING**; `--apply [--only <id>]…` appends exactly the consented entries on your explicit yes; append-only, id collisions refused). The offer derivation is **closed-world** (AD-052): only a terminating-class script NAME (test / lint / type-check / build — never dev/watch/serve, never a write-mode or release/publish/deploy variant) whose BODY is a member of the literal runner allowlist is offered — membership, never blocklist screening: the worst case is a legit command not offered, never a dangerous one offered. The offered cmd is the uniform hook-free **`COREPACK_ENABLE_NETWORK=0 <pm> exec -- <allowlisted-body>`** — `exec` runs a command, not a named script, so no pre/post hook can fire (npm/pnpm/yarn alike; never `<pm> run <name>`, which re-exposes hooks), and the Corepack env prefix blocks a hostile `packageManager` pin from fetching the PM binary before exec. npm is pinned `--offline --script-shell /bin/sh`; pnpm/yarn refuse an absent runner without network (a user-installed cache/global/PATH runner executing is user machine state — part of the disclosed residual); a family without a verified fail-closed exec contract is WITHHELD loudly. **Disclose before the yes** (the preview prints it): gates.json is a PRIVILEGED file — the wired hook auto-approves byte-exact declared commands — and a script gate runs project-controlled tooling the preview does not sandbox (safe-by-construction = the OFFER DERIVATION). At upgrade the only gates.json writer is the consented legacy migration (`${CLAUDE_SKILL_DIR}/references/modes/upgrade.md`).
|
|
23
|
+
**Consent-gated filling — the init preview, not part of the runner (D9).** The template `gates.json` is seeded EMPTY; FILLING it is a consented preview at init (`node ${CLAUDE_SKILL_DIR}/tools/gates-init.mjs --cwd <project>`, dry-run by default — prints the derived entries and **writes NOTHING**; `--apply [--only <id>]…` appends exactly the consented entries on your explicit yes; append-only, id collisions refused). The offer derivation is **closed-world** (AD-052): only a terminating-class script NAME (test / lint / type-check / build — never dev/watch/serve, never a write-mode or release/publish/deploy variant) whose BODY is a member of the literal runner allowlist is offered — membership, never blocklist screening: the worst case is a legit command not offered, never a dangerous one offered. The offered cmd is the uniform hook-free **`COREPACK_ENABLE_NETWORK=0 <pm> exec -- <allowlisted-body>`** — `exec` runs a command, not a named script, so no pre/post hook can fire (npm/pnpm/yarn alike; never `<pm> run <name>`, which re-exposes hooks), and the Corepack env prefix blocks a hostile `packageManager` pin from fetching the PM binary before exec. npm is pinned `--offline --script-shell /bin/sh`; pnpm/yarn refuse an absent runner without network (a user-installed cache/global/PATH runner executing is user machine state — part of the disclosed residual); a family without a verified fail-closed exec contract is WITHHELD loudly. A screened-out body is always named — and when nothing but kit checkers remains, the preview says so in plain words: the offer carries **no project-verification gate at all**. **Disclose before the yes** (the preview prints it): gates.json is a PRIVILEGED file — the wired hook auto-approves byte-exact declared commands — and a script gate runs project-controlled tooling the preview does not sandbox (safe-by-construction = the OFFER DERIVATION). At upgrade the only gates.json writer is the consented legacy migration (`${CLAUDE_SKILL_DIR}/references/modes/upgrade.md`).
|
|
24
|
+
|
|
25
|
+
**The coverage PRODUCER and the canonical checker are declared together or not at all.** `coverage-check` READS an lcov; something must WRITE it, and a checker with no producer PASSES (`skipped-no-lcov`) certifying nothing. A **producer** is a CLOSED set of full command forms, never a substring probe: the suite body `node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination="$AW_GIT_DIR/agent-workflow-lcov.info" --test-reporter=spec --test-reporter-destination=stdout` (optionally + the project's own test paths), bare or behind ONE verified per-PM `exec` wrapper. A cmd that merely MENTIONS the destination (in an `echo`, as a bare substring) or carries a PARTIAL flag set is **not** one. The tail must be path-shaped — path/glob/quoting bytes only, nothing that could sequence, redirect or substitute a command, no plain leading `-`. **Residual:** the screen judges SOURCE bytes — brace *sequence* expansion can produce others (`{Y..a}`), though bash never re-scans an expansion result as syntax, so such a byte is literal argument data, not an operator; the leading-`-` rule is first-order only (`'--flag'`, `{path,--flag}` pass); neither proves the lcov SURVIVES — "producer" means *configured with the reporters*, and a run producing none is caught at runtime as `skipped-no-lcov`. The destination rides `AW_GIT_DIR`, exported to every gate child on plain and `--final` runs alike (`AW_LCOV_FILE` is `--final`-only), so one cmd survives the unmet-producer preflight in both modes. On BOTH declaration paths: the fill preview WIRES those reporters onto a `node --test` body — the one allowlist member producing lcov unaided, every other body is emitted unchanged — WITHHOLDS the `coverage-check` candidate, with a named note, when neither the offer nor the declaration carries a producer; and `--apply` REFUSES a checker with no producer, a checker that is not LAST (an ORDERING refusal — reorder by hand; the fill is append-only), or a SECOND canonical checker. The legacy migration likewise never ADDS the checker into a producer-less declaration, and reports an already-declared one as INERT. A producer declared AFTER the checker leaves it just as inert (it reads nothing, or stale bytes) — ORDER is the rule. An already-declared inert pair, and a matrix of nothing but kit checkers, are surfaced by the advisor's `gates-inert` item (`${CLAUDE_SKILL_DIR}/references/modes/recommendations.md`); its cause-A remedy is HAND-APPLY because the fill cannot reorder.
|
|
26
|
+
|
|
27
|
+
**`coverage=` states what the run can honestly say about coverage.** A CLOSED four-value set, always present, DETAIL only — exit code, `status=`, the receipt status, `--final` acceptance and the commit-guard disposition are untouched. `coverage=certified` — the checker consumed an lcov and ISSUED a verdict, pass **or** fail (one listing uncovered lines still reads certified and still exits 1). `coverage=not-run` — the checker ran and issued NO verdict (no lcov bytes were read, or the run holds no attestation context). `coverage=none` — no canonical checker ran here (an `--only` subset, the `--pre-review` subset). `coverage=unknown` — the run ended before the gates produced a signal (missing / empty / malformed declaration, no bash, a pre-spend refusal), or that signal is unreadable: the checker could not spawn, or its two anchored lines are missing, duplicated, or CONTRADICTORY (`attested=yes` over `lcov-sha256=none` certifies nothing) — fail closed. The value is DERIVED by cross-reading both anchored machine lines, the bytes the `--final` receipt binds, so it can never disagree with what the checker printed; the checker's table row names a withheld verdict in the same words, and a `--final` receipt RECORDS the token (`none` never rides one — a final run always selects the checker).
|
|
23
28
|
|
|
24
29
|
**Invariants:** the runner writes nothing on a plain run; `--final`'s ONE evidence write rides the core-evidence sole writer (the runner never opens the store itself) · an ARMED `--pre-review`'s ONE flow write rides the flow store's locked append factory (unarmed: byte-unchanged) · never commits · never runs a subscription CLI · executes only the project's OWN declared commands (never a kit-invented one) · the bash contract fails loud, never reinterprets · gates-init is a separate consent-per-run preview — append-only, never pre-approved by any velocity tier.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md
|
|
6
6
|
|
|
7
|
-
The **read-only deployment advisor** — the deterministic section every `upgrade` run ends with, also invocable on its own. It computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, sandbox unavailable, gates undeclared, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe) and renders **verdict-first**: one composed verdict line, then each item as **{severity · what is sub-optimal · the benefit in ONE plain line · an optional `recipe:` line (the `sandbox-lane` live recipe — egress hosts + resolved writable dirs — the `worktrees-dir` hand-apply-first grant advice, or the `agents` hidden-mode reconcile follow-up) · the exact consent-gated apply one-liner}**. The tool computes deterministic English DATA; **you PRESENT the section in the user's conversational language** — every fact, count and item from the tool, nothing added or dropped; commands, paths, hosts and rule strings stay **byte-exact**; show the raw tool block on request (the AD-032 report-contract lane — the tool cannot know the dialogue language, so the language rendering is your presentation layer).
|
|
7
|
+
The **read-only deployment advisor** — the deterministic section every `upgrade` run ends with, also invocable on its own. It computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, sandbox unavailable, gates undeclared, a declared gate matrix that verifies nothing, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe) and renders **verdict-first**: one composed verdict line, then each item as **{severity · what is sub-optimal · the benefit in ONE plain line · an optional `recipe:` line (the `sandbox-lane` live recipe — egress hosts + resolved writable dirs — the `worktrees-dir` hand-apply-first grant advice, or the `agents` hidden-mode reconcile follow-up) · the exact consent-gated apply one-liner}**. The tool computes deterministic English DATA; **you PRESENT the section in the user's conversational language** — every fact, count and item from the tool, nothing added or dropped; commands, paths, hosts and rule strings stay **byte-exact**; show the raw tool block on request (the AD-032 report-contract lane — the tool cannot know the dialogue language, so the language rendering is your presentation layer).
|
|
8
8
|
|
|
9
9
|
**Live host/session facts are tool-composed only.** Every fact this section states about the current
|
|
10
10
|
host or session — prompts fired, sandbox scope, whether a bypass was needed, network reachability,
|
|
@@ -27,6 +27,8 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/recommendations.mjs --cwd <project-root> [--
|
|
|
27
27
|
- `read-lane` — enabling the opt-in read-only compound lane auto-approves *compounds* (and singles) of the seeded read-only core that carry ZERO shell metaprogramming: an UNATTENDED trust extension, bounded by the audited read-only core (never a command outside it; prompt-bypass only, never a sandbox bypass) and applied regardless of which of those core commands you seeded as individual settings rules. It is a PROJECT-PERSISTENT declaration in `docs/ai/lanes.json` — every future session, subagents' Bash too where the host fires hooks on subagent Bash, and (committed) every checkout. The apply depends on state: when the lane is OFF, it is the `gate-hook --read-lane` preview (whose own currency check refuses a stale hook — a pre-1.48 hook never reads `lanes.json`); when the placed hook is STALE (an enabled lane over an old hook) or MISSING, the item instead surfaces a **delete-to-reseed** / re-place recovery (a destructive `rm` + `--apply`, an attention item — never the safe preview). Risk profile: a bounded read-only trust-posture extension — no write/exec exposure beyond the audited core.
|
|
28
28
|
- `worktrees-dir` — on a settings-native host that honors the key, the HAND-APPLY line widens the OS-sandbox WRITE surface to the whole worktrees parent dir: every sibling path under it (other repositories included) becomes agent-writable, and the widening persists for every later session. A harness-managed host may ignore that project setting; grant the narrow parent through host/session controls or use the provision terminal fallback instead. When that scope is wider than you want, narrow it FIRST: create a dedicated dir yourself (outside the agent's write surface), point `docs/ai/worktrees.json` `parentDir` at it, then re-run recommendations — the item re-renders with the narrowed dir. The kit never writes sandbox filesystem allowances itself; the line is always yours to paste. **Convergence** is two-path: a declared `sandbox.filesystem.allowWrite` entry covering the probed dir (either settings scope — `~` and `~/…` resolve against home, and coverage is path-segment-aware, so a grant on a sibling or on a child never counts), or — for a host that ignores that key — the neutral dir-bound acknowledgement recorded by this item's consent-gated apply one-liner (`ack-write --lane worktrees-dir` — a dry-run preview that prints the exact `--apply`; recorded as `worktreesDirAck` in the family-owned `docs/ai/acks.json`, never a security key), while the grant advice itself rides the `recipe:` line as the labeled FIRST step; against a trusted host NO the apply stays the HAND-APPLY grant advice and no ack is offered. Neither is proof of write CAPABILITY: the provision preflight's real create+delete probe stays the runtime truth, and the fingerprint is bound to the **resolved probe dir**, so the item re-fires only when that resolved dir changes (two absent `parentDir` values sharing an existing ancestor resolve to the same dir and keep the same ack). Risk profile: a real write-surface widening where honored — scope it deliberately.
|
|
29
29
|
|
|
30
|
+
- `gates-inert` — the gate matrix is DECLARED but verifies nothing, and the two causes have different remedies, so the item renders a different apply for each. **Cause A** — a canonical `coverage-check` gate with no producer gate declared BEFORE it (none at all, or one declared after it, which writes the lcov too late): the run certifies no coverage of its own — `coverage=not-run` when nothing wrote an lcov, or a verdict over STALE bytes an earlier run left in the git dir, which is worse because it reads as `coverage=certified`. This item is what surfaces that state at upgrade instead of leaving it to be noticed. The remedy needs the producer to run BEFORE the checker — declared or MOVED there — and the `gates-init` fill is append-only, so it cannot reorder an existing declaration; this arm is therefore **HAND-APPLY**: the maintainer edits `docs/ai/gates.json` (the exact producer form lives in `${CLAUDE_SKILL_DIR}/references/modes/gates.md`), never you, never the kit. **Cause B** — every declared gate is one of the kit's own canonical checkers, so the matrix runs no project-verification command at all: the apply is the `gates-init` dry-run preview, the same consent-gated seeder the `gates-declaration` item renders, and after the SAME confirmation you run the `--apply` line it prints. Neither cause changes any gate result, exit code or receipt — the item adds no enforcement, only the offer. Risk profile: `docs/ai/gates.json` is a PRIVILEGED file (a declared gate is auto-approvable by the wired hook), so cause A stays maintainer-only editing and cause B appends a project-controlled command on your explicit yes.
|
|
31
|
+
|
|
30
32
|
- `adr-store-migration` — other items write project files too; what is unique here is that the crossing **overwrites and deletes files the project already has**: it replaces the deployed enforcement scripts in `scripts/` (the directional subset — only basenames the project already has; a locally-edited copy is snapshotted first, never silently clobbered) and, where a retired archive file exists, DELETES it once conservation has been proven. That is why it is **HAND-APPLY** and why the command shown in the apply slot is a **`--dry-run`** — it writes nothing and prints the whole plan. `--apply` is a SEPARATE step, run only after that plan has been shown and **fresh consent** obtained for it; the consent flow executes only the apply slot, so an item that needs consent AFTER its preview cannot use that lane at all. Every write is idempotent and the run is re-runnable to completion after any interruption, so a re-run repairs rather than double-applies. It never commits. Risk profile: overwrite + delete of existing project files, gated on a preview you have actually read.
|
|
31
33
|
|
|
32
34
|
**Sandbox lanes (what to DO with the `sandbox-lane` recipe, per host class):**
|
|
@@ -24,7 +24,7 @@ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKI
|
|
|
24
24
|
|
|
25
25
|
**Gate-declaration ensure (seed-if-missing) — stamp-independent, same gate, BEFORE the equal-head short-circuit.** Ensure `docs/ai/gates.json` exists: **create it from `${CLAUDE_SKILL_DIR}/references/templates/gates.json` if missing** — the kit's OWN template twin, so this works even when the installed memory substrate predates the gates feature (a stale memory never silently loses it); **an existing file is preserved byte-for-byte** (a project's declared gate matrix is authored content — never clobbered, never refreshed in place; unlike the orchestration `_README` there is no note-refresh here). Report it in the step 4 / step 8 success report (*seeded* / *already present*). Like the config ensure, this reaches an equal-head deployment without a lineage-head bump or a migration file (a `.json`, inherently outside the docs cap-validator).
|
|
26
26
|
|
|
27
|
-
**Legacy gates.json migration (consented preview — D8).** An EXISTING declaration may still carry the retired review-ledger / fold-completeness checks. Run the preview `node ${CLAUDE_SKILL_DIR}/references/scripts/migrate-gates.mjs --kit-tools ${CLAUDE_SKILL_DIR}/tools --cwd <project>` (dry-run — writes NOTHING), show the user the exact plan, and only on an explicit yes re-run it with `--apply`: canonical legacy entries (matched by their documented single-invocation cmd forms) are REMOVED, the canonical `unit-tests` cmd gains the built-in lcov reporters, and the coverage-check gate is ADDED last — atomic and COMPLETE, so the migrated declaration satisfies `run-gates --final`. CUSTOMIZED entries are NEVER auto-touched: the preview names each with a paste-ready recovery, and the commit guard must NOT be installed until they are resolved. This is the ONLY gates.json writer at upgrade (the consented FILL preview runs at init).
|
|
27
|
+
**Legacy gates.json migration (consented preview — D8).** An EXISTING declaration may still carry the retired review-ledger / fold-completeness checks. Run the preview `node ${CLAUDE_SKILL_DIR}/references/scripts/migrate-gates.mjs --kit-tools ${CLAUDE_SKILL_DIR}/tools --cwd <project>` (dry-run — writes NOTHING), show the user the exact plan, and only on an explicit yes re-run it with `--apply`: canonical legacy entries (matched by their documented single-invocation cmd forms) are REMOVED, the canonical `unit-tests` cmd gains the built-in lcov reporters, and the coverage-check gate is ADDED last — atomic and COMPLETE, so the migrated declaration satisfies `run-gates --final`. **The checker rides a PRODUCER or is not declared at all** (`${CLAUDE_SKILL_DIR}/references/modes/gates.md`): with no gate producing the lcov it reads, the migration does NOT add it, an already-declared one is reported INERT, the result is not called final-run-capable, and the preview prints the paste-ready suite cmd to declare by hand — nothing is ever removed for you. CUSTOMIZED entries are NEVER auto-touched: the preview names each with a paste-ready recovery, and the commit guard must NOT be installed until they are resolved. This is the ONLY gates.json writer at upgrade (the consented FILL preview runs at init).
|
|
28
28
|
|
|
29
29
|
**Autonomy-declaration ensure (seed-if-missing) — stamp-independent, same gate, BEFORE the equal-head short-circuit.** Ensure `docs/ai/autonomy.json` exists: **create it from `${CLAUDE_SKILL_DIR}/references/templates/autonomy.json` if missing** (the kit's OWN template twin, mirrored from memory — so a stale memory never silently loses the seed); **an existing file is preserved byte-for-byte** (a declared policy is authored content — never clobbered, never refreshed in place). The seed is SPARSE (the onboarding note only) and **defaults-equivalent** — deploying it never changes behavior (the computed defaults stay the policy until the user declares levels with `/agent-workflow-kit set-autonomy` or by hand). Report it in the step 4 / step 8 success report (*seeded* / *already present, preserved*). Like the other config ensures, no lineage-head bump or migration file (a `.json`, outside the docs cap-validator).
|
|
30
30
|
|
|
@@ -42,7 +42,11 @@ Honesty notes: tier entries get **NO PreToolUse-hook residual coverage — with
|
|
|
42
42
|
|
|
43
43
|
**Invariants:** creates `.claude/` if absent and writes **only** `.claude/settings.json` (no other file); **never** allowlists commit/push/publish; **never** writes `settings.local.json`; never commits; opt-in `acceptEdits`, never silent.
|
|
44
44
|
|
|
45
|
-
**
|
|
45
|
+
**Every settings-derived RUNTIME claim on this mode's surfaces is host-conditional.** Whether a host applies the `sandbox.*` settings keys is **not knowable from here** — a settings-native host honors them; an IDE/session-imposed sandbox was observed ignoring hand-applied `sandbox.network.allowedDomains` / `sandbox.filesystem.allowWrite` in BOTH scopes. So every statement about what a settings key DOES at run time is stated **`where the host honors the settings sandbox keys`**, never promised — the bridge tier's exclusion routing; the autonomy render's `allowedDomains` / `allowWrite` / `allowUnsandboxedCommands` / `excludedCommands` degrade lines over FOREIGN keys; and equally the render's claims about the keys it writes ITSELF (the `sandbox:` line, the `fs_outside_repo` confinement note, the network prompt-on-egress and credentials-coverage degrades), which is where a clean deployment reads a promise. The qualifier rides every such line, and one notice naming the unknown closes **every** `--autonomy` render, clean settings included. A malformed `allowWrite` (not an array, or an entry that is not a non-empty string) is reported as unreadable rather than assumed empty — as UNVERIFIABLE, never as a weakening: nothing may be claimed about what a value the tool cannot read would widen.
|
|
46
|
+
|
|
47
|
+
**The boundary of that qualifier, stated so it is not guessed.** It covers claims about `sandbox.*` keys — the block whose honouring was observed to vary by host. It deliberately does NOT cover `permissions.*` semantics (an allow rule auto-approving a command, `local > project` precedence for a non-sandbox key): that is the harness's own documented permission model, the layer this whole mode rests on, and hedging it would say nothing true. **Stated residual:** which sentences count as settings-derived runtime claims is decided by review, not by a checker — deciding whether a sentence asserts a runtime effect is a question about prose meaning, and this family deliberately has no mechanism that judges that (the same limit that retired the byte-scanning deny rung). A new claim-bearing line therefore has to carry the qualifier by authorship; the acceptance criterion is that every line stating what a `sandbox.*` key DOES carries it, and the tests pin the surfaces that exist today. What does NOT change is the CLASSIFICATION: which red-line a key would weaken, and that a proven bridge-tier exclusion is a note rather than a weakening, are properties of the declaration and stay flat statements.
|
|
48
|
+
|
|
49
|
+
**The `--bridge-tier` (own opt-in, AD-044).** Seeds what a promptless council review run needs — BOTH surfaces: `permissions.allow` prefix rules AND the wrapper names in `sandbox.excludedCommands` (where the host honors the settings sandbox keys the harness runs an excluded command OUTSIDE the sandbox — the wrappers need network — so a plain allowlisted invocation triggers no sandbox-bypass approval; where it does not, the wrapper starts sandboxed and simply prompts or fails loudly — fail-safe, never a silent widening). Both land in the **project** `.claude/settings.json` — the file this writer owns; an exclusion placed only in `settings.local.json` was live-observed NOT to route the command outside the sandbox (2026-07-11: the wrapper then starts sandboxed and dies on a read-only HOME + a network prompt), so hand-wiring the local file is not a working substitute for this tier. **Honesty note:** a session whose sandbox is imposed by the harness runtime itself (e.g. an IDE-managed session sandbox) may ignore settings-level exclusions entirely — there the wrappers need the session-level sandbox config (or a per-run consented bypass); the tier's seeded posture is correct for the settings-native sandbox and simply prompts again elsewhere (fail-safe, never a silent widening). Each bridge's observed egress hosts are declared in its `capability.json` `networkHosts` — the single documentation source (observed-minimal — a blocked host names itself at run time; read the manifests, this doc deliberately retypes no host list). The kit **never seeds** `sandbox.network.allowedDomains` or `sandbox.filesystem.allowWrite` (bridge council 2026-07-11, both backends concur): a network pre-allow widens egress for EVERY sandboxed command, and a write allowance on CLI state dirs (`~/.codex`, `~/.gemini/…`) would make credential dirs writable to every sandboxed command. Per-bridge picture under a harness-managed sandbox (live-observed 2026-07-11/12): an IDE-managed session sandbox ignores hand-applied `sandbox.network.allowedDomains` / `sandbox.filesystem.allowWrite` in BOTH settings scopes — its own per-host network consents govern egress; the durable zero-prompt lanes there are the session/host sandbox config (hosts from `networkHosts` + the CLI state-dir writes) or the per-run consented bypass. codex additionally needs a writable HOME (EROFS `~/.codex`); note the apex-vs-wildcard nuance — an apex domain is NOT covered by its `*.`-wildcard form, so the manifests carry both forms where observed (the blocked host names itself at run time). The upgrade Recommendations advisor surfaces exactly this recipe (hosts ∪ resolved `writableDirs`) as the `sandbox-lane` discoverability item — a consent-gated **ack writer** converging on a neutral fingerprint acknowledgement recorded into the family-owned `docs/ai/acks.json` (the kit still never seeds the security keys — those stay hand-apply), with the posture notes at the consent moment (`${CLAUDE_SKILL_DIR}/references/modes/recommendations.md`). Membership is the FROZEN review-wrapper constant, **never** the execution/probe wrappers (`codex-exec`, `agy-run` keep their human prompt — delegated execution is not covered by this consent; codex-exec's nested-sandbox recovery is the canon's observed-failure lane, not a preemptive tier seed), and only the **`code` review mode** — a `plan`/`diff` invocation takes a file argument that can point OUTSIDE the repo, so those modes keep their prompt; each wrapper entry derives ONLY when its bridge is **placed on PATH** (an absent bridge is a stated skip). The seeded byte-forms (this list IS the documented-invocation source for the bridge tier):
|
|
46
50
|
|
|
47
51
|
- `Bash(codex-review code:*)` — the code-mode prefix, args wildcard; plus `codex-review` in `sandbox.excludedCommands`
|
|
48
52
|
- `Bash(agy-review code:*)` — the code-mode prefix, args wildcard; plus `agy-review` in `sandbox.excludedCommands`
|