@sabaiway/agent-workflow-kit 3.14.0 → 4.0.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 +98 -0
- package/README.md +3 -3
- package/SKILL.md +1 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +12 -8
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +735 -55
- package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +899 -51
- package/bridges/antigravity-cli-bridge/bin/agy.sh +4 -3
- package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +23 -0
- package/bridges/antigravity-cli-bridge/capability.json +14 -4
- package/bridges/antigravity-cli-bridge/references/driving-agy.md +12 -4
- package/bridges/antigravity-cli-bridge/references/models-and-flags.md +4 -3
- package/bridges/antigravity-cli-bridge/references/review-prompt.md +65 -2
- package/bridges/codex-cli-bridge/SKILL.md +1 -1
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +2 -1
- package/bridges/codex-cli-bridge/bin/codex-review.sh +63 -13
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +38 -0
- package/bridges/codex-cli-bridge/capability.json +1 -1
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/agents/review-lens.md +39 -0
- package/references/hooks/gate-approve.mjs +15 -0
- package/references/modes/agents.md +11 -2
- package/references/modes/autonomy-doctor.md +2 -0
- package/references/modes/backends.md +2 -0
- package/references/modes/bootstrap.md +2 -0
- package/references/modes/bridge-settings.md +4 -1
- package/references/modes/commit-guard.md +2 -0
- package/references/modes/core-evidence.md +2 -0
- package/references/modes/coverage-check.md +2 -0
- package/references/modes/doc-parity.md +2 -0
- package/references/modes/gates.md +2 -0
- package/references/modes/grounding.md +2 -0
- package/references/modes/help.md +2 -0
- package/references/modes/hook.md +4 -1
- package/references/modes/migrate-adr-store.md +2 -0
- package/references/modes/procedures.md +2 -0
- package/references/modes/recipes.md +2 -0
- package/references/modes/recommendations.md +4 -3
- package/references/modes/review-state.md +2 -0
- package/references/modes/sandbox-masks.md +2 -0
- package/references/modes/set-autonomy.md +2 -0
- package/references/modes/set-recipe.md +3 -0
- package/references/modes/setup.md +2 -0
- package/references/modes/state-block-guard.md +9 -5
- package/references/modes/status.md +4 -1
- package/references/modes/uninstall.md +2 -0
- package/references/modes/upgrade.md +2 -0
- package/references/modes/velocity.md +7 -0
- package/references/modes/worktrees.md +2 -0
- package/tools/bridge-settings-read.mjs +40 -10
- package/tools/bridge-settings.mjs +22 -7
- package/tools/cheap-agents.mjs +15 -5
- package/tools/commands.mjs +2 -2
- package/tools/core-evidence.mjs +29 -2
- package/tools/detect-backends.mjs +1 -1
- package/tools/manifest/schema.md +7 -0
- package/tools/manifest/validate.mjs +8 -0
- package/tools/presentation.mjs +1 -1
- package/tools/procedures.mjs +9 -2
- package/tools/recipes.mjs +4 -1
- package/tools/recommendations.mjs +157 -59
- package/tools/renderers.mjs +10 -1
- package/tools/review-state.mjs +4 -0
- package/tools/view-model.mjs +3 -1
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
# AGY_HARD_TIMEOUT=8m agy-run "..." # override the hard wall-clock cap (timeout(1))
|
|
31
31
|
# AGY_MAX_PROMPT_BYTES=60000 agy-run @big.md # LOWER the single-argv byte ceiling (default 120000;
|
|
32
32
|
# # the override only tightens it — it can never exceed the OS ~131072 limit)
|
|
33
|
-
# agy-run "..." -- --add-dir .
|
|
34
|
-
# #
|
|
33
|
+
# agy-run "..." -- --add-dir . # passthrough agy flags (this wrapper stays
|
|
34
|
+
# # flow-agnostic; it never widens agy's own permissions)
|
|
35
35
|
set -euo pipefail
|
|
36
36
|
|
|
37
37
|
# --- --help / -h (pre-preflight: no agy, no login needed) ----------------------
|
|
@@ -94,7 +94,7 @@ aw_settings_file() {
|
|
|
94
94
|
printf '%s/agent-workflow/bridge-settings.conf' "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
95
95
|
}
|
|
96
96
|
aw_settings_known() {
|
|
97
|
-
case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR " in
|
|
97
|
+
case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR AGY_REVIEW_MAX_TOTAL_BYTES " in
|
|
98
98
|
*" $1 "*) return 0 ;;
|
|
99
99
|
*) return 1 ;;
|
|
100
100
|
esac
|
|
@@ -117,6 +117,7 @@ aw_settings_valid() {
|
|
|
117
117
|
CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
|
|
118
118
|
AGY_HARD_TIMEOUT) [[ "$v" =~ $dur_re && ! "$v" =~ $zero_re ]] ;;
|
|
119
119
|
AGY_REVIEW_ALLOW_ADDDIR) [[ "$v" == "0" || "$v" == "1" ]] ;;
|
|
120
|
+
AGY_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
|
|
120
121
|
*) return 1 ;;
|
|
121
122
|
esac
|
|
122
123
|
}
|
|
@@ -83,6 +83,15 @@ const RECORDING_STUB = [
|
|
|
83
83
|
'',
|
|
84
84
|
].join('\n');
|
|
85
85
|
|
|
86
|
+
// Records the full argv it was invoked with, one token per line.
|
|
87
|
+
const ARGV_STUB = [
|
|
88
|
+
'#!/usr/bin/env bash',
|
|
89
|
+
'if [[ -n "${AGY_STUB_ARGV:-}" ]]; then { for a in "$@"; do printf "%s\\n" "$a"; done; } > "$AGY_STUB_ARGV"; fi',
|
|
90
|
+
'echo "OK reply"',
|
|
91
|
+
'exit 0',
|
|
92
|
+
'',
|
|
93
|
+
].join('\n');
|
|
94
|
+
|
|
86
95
|
// Run the wrapper with an explicit argv (so a `@file` / `-` prompt form can be passed)
|
|
87
96
|
// and optional stdin. AGY_MODEL='' drops --model so the stub argv stays clean.
|
|
88
97
|
const runArgs = (home, { args, env = {}, input } = {}) =>
|
|
@@ -217,6 +226,20 @@ describe('agy.sh — --help (pre-preflight, candidate C)', () => {
|
|
|
217
226
|
}
|
|
218
227
|
});
|
|
219
228
|
|
|
229
|
+
// D3b: what Phase 4 retires is the AUTOMATICALLY-CONSTRUCTED --add-dir inside `agy-review code`.
|
|
230
|
+
// The PUBLIC passthrough contract is deliberately preserved: agy-run is a thin, flow-agnostic
|
|
231
|
+
// wrapper and an operator who asks for --add-dir explicitly still gets it.
|
|
232
|
+
it('agy-run keeps the direct --add-dir passthrough (the retirement is scoped to the review offload)', () => {
|
|
233
|
+
const home = makeSandbox(ARGV_STUB);
|
|
234
|
+
const argvFile = join(home, 'argv');
|
|
235
|
+
const r = runArgs(home, { args: ['prompt', '--', '--add-dir', '.'], env: { AGY_STUB_ARGV: argvFile } });
|
|
236
|
+
const argv = existsSync(argvFile) ? readFileSync(argvFile, 'utf8') : '';
|
|
237
|
+
rmSync(home, { recursive: true, force: true });
|
|
238
|
+
assert.equal(r.status, 0, r.stderr);
|
|
239
|
+
assert.match(argv, /(^|\n)--add-dir(\n|$)/, 'an operator-supplied --add-dir still reaches agy');
|
|
240
|
+
assert.match(argv, /(^|\n)\.(\n|$)/, 'with its argument intact');
|
|
241
|
+
});
|
|
242
|
+
|
|
220
243
|
it('--help after the -- separator is passthrough payload, never intercepted', () => {
|
|
221
244
|
const home = makeSandbox(RECORDING_STUB);
|
|
222
245
|
const sentinel = join(home, 'sentinel');
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"schema": 1,
|
|
4
4
|
"name": "antigravity-cli-bridge",
|
|
5
5
|
"kind": "execution-backend",
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "5.0.0",
|
|
7
7
|
"provides": ["review", "probe"],
|
|
8
8
|
"posture": { "model": "Gemini 3.1 Pro (High)" },
|
|
9
9
|
"roles": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"agy-review --continue [--decided @f] [--focus \"…\"]",
|
|
31
31
|
"agy-review --conversation <id> [--decided @f] [--focus \"…\"]"
|
|
32
32
|
],
|
|
33
|
-
"receipt": "side effect — a successful review appends one JSON receipt line to <git dir>/agent-workflow-review-receipts.jsonl (AW_REVIEW_RECEIPTS overrides; plan/diff outside a git tree: warn + skip unless overridden): fingerprint = sha256 over the canonical uncommitted-state payload (staged diff + unstaged diff + untracked-not-ignored contents — the review-payload domain; never-committable untracked paths — character/block devices, FIFOs, sockets — are excluded from the domain entirely, untracked symlinks/directories ride as name-only notes) in code mode, the artifact-file sha256 in plan/diff mode; verdict recorded verbatim from the mandated '### Verdict' section (SHIP / SHIP WITH NITS / REWORK); grounded = whether a NON-EMPTY --facts payload was supplied (code mode refuses pre-spend without one — no run, no receipt — unless --ungrounded/AGY_PROBE=1; in plan/diff an empty payload records grounded:false — fail-closed, the state gate rejects it), factsHash = sha256 of the facts payload; a continuation receipt is fresh:false (informational-only — it cannot attest the folded tree); probe = whether the run relaxed the quality guards (AGY_PROBE=1), written on EVERY receipt so it self-declares — the kit's review-state gate rejects a probe-marked receipt (a probe review never attests) and equally rejects an unmarked one (silence is not a declaration); posture = the ACTUAL run posture {model} (agy has no tier), written on EVERY receipt (D5) — the gate rejects a receipt with an absent/invalid posture (a pre-D5 wrapper minted it; re-run the review), one stderr banner line states the same posture, an ATTESTING review with AGY_MODEL explicitly emptied refuses pre-spend, and a model string carrying control bytes refuses pre-spend in every mode; a run whose output carries NO recognized '### Verdict' section — empty output included — exits 4 with NO receipt (D4: a FAILED review to RE-RUN, never a fatal session error); a write failure warns, never fails the review",
|
|
33
|
+
"receipt": "side effect — a successful review appends one JSON receipt line to <git dir>/agent-workflow-review-receipts.jsonl (AW_REVIEW_RECEIPTS overrides; plan/diff outside a git tree: warn + skip unless overridden): fingerprint = sha256 over the canonical uncommitted-state payload (staged diff + unstaged diff + untracked-not-ignored contents — the review-payload domain; never-committable untracked paths — character/block devices, FIFOs, sockets — are excluded from the domain entirely, untracked symlinks/directories ride as name-only notes) in code mode, the artifact-file sha256 in plan/diff mode; verdict recorded verbatim from the mandated '### Verdict' section (SHIP / SHIP WITH NITS / REWORK); grounded = whether a NON-EMPTY --facts payload was supplied (code mode refuses pre-spend without one — no run, no receipt — unless --ungrounded/AGY_PROBE=1; in plan/diff an empty payload records grounded:false — fail-closed, the state gate rejects it), factsHash = sha256 of the facts payload; a continuation receipt is fresh:false (informational-only — it cannot attest the folded tree); probe = whether the run relaxed the quality guards (AGY_PROBE=1), written on EVERY receipt so it self-declares — the kit's review-state gate rejects a probe-marked receipt (a probe review never attests) and equally rejects an unmarked one (silence is not a declaration); posture = the ACTUAL run posture {model} (agy has no tier), written on EVERY receipt (D5) — the gate rejects a receipt with an absent/invalid posture (a pre-D5 wrapper minted it; re-run the review), one stderr banner line states the same posture, an ATTESTING review with AGY_MODEL explicitly emptied refuses pre-spend, and a model string carrying control bytes refuses pre-spend in every mode; delivery = how the change set REACHED the model, currently emitted as 'inline' (the whole set rode one prompt — proven by construction) or 'fed' (a chunked feed whose per-part echo proof verified); REQUIRED on every agy code receipt and its ABSENCE is what stops a pre-fed-lane receipt attesting, while the gate accepts any well-formed declaration rather than a particular value; absent by construction on plan/diff/continuation receipts, which carry no change set; a run whose output carries NO recognized '### Verdict' section — empty output included — exits 4 with NO receipt (D4: a FAILED review to RE-RUN, never a fatal session error); a write failure warns, never fails the review",
|
|
34
34
|
"notes": [
|
|
35
35
|
"pre-dispatch host-diff: before the FIRST dispatch of this bridge, diff its declared networkHosts against the live sandbox allow-list — a missing host is surfaced to the maintainer BEFORE dispatching, never fired into a known prompt",
|
|
36
36
|
"the review posture banner appends a banner-only timeout=<duration|uncapped> field — exactly the duration agy-run hands to timeout(1), uncapped when no timeout/gtimeout binary caps the run; INFORMATIONAL only: it never enters the receipt posture or the D5 banner↔receipt parity",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
{ "value": "an ungrounded review guesses — stale-model and partial-diff false positives", "enforcement": "advisory", "source": "bin/agy-review.sh" },
|
|
67
67
|
{ "value": "without a non-empty --facts payload the run refuses BEFORE the spend (exit 2) — the only escapes are --ungrounded and AGY_PROBE=1", "enforcement": "enforced", "source": "bin/agy-review.sh" },
|
|
68
68
|
{ "value": "an ungrounded run records grounded:false and the review-state gate rejects it", "enforcement": "enforced", "source": "capability.json roles.review.contract.receipt" },
|
|
69
|
-
{ "value": "an oversized prompt
|
|
69
|
+
{ "value": "an oversized prompt is never truncated", "enforcement": "enforced", "condition": "code mode DELIVERS it as a chunked feed whose per-part delivery proof must verify (a missing or wrong echo exits 4 with no receipt); plan/diff refuse over the cap", "source": "bin/agy-review.sh plan_fed_review + verify_delivery_proof" }
|
|
70
70
|
],
|
|
71
71
|
"customHooks": ["AGY_PROBE"]
|
|
72
72
|
},
|
|
@@ -213,7 +213,17 @@
|
|
|
213
213
|
"kind": "boolean",
|
|
214
214
|
"default": "0",
|
|
215
215
|
"appliesTo": ["agy-review"],
|
|
216
|
-
"
|
|
216
|
+
"retired": "the --add-dir offload is retired: headless agy AUTO-DENIES its own read_file tool, so an offloaded change set could return a confident fabrication with no way to tell. An oversized code review is now DELIVERED as a chunked feed with a per-part delivery proof. The key stays recognized so an existing settings line never warns as unknown, but it arms nothing; clear it with --unset.",
|
|
217
|
+
"effect": "RETIRED — recognized so an existing settings line never warns as unknown, but it arms NOTHING. A set value prints the retirement notice naming the chunked-feed lane that replaced it."
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"key": "AGY_REVIEW_MAX_TOTAL_BYTES",
|
|
221
|
+
"kind": "integer",
|
|
222
|
+
"min": 1,
|
|
223
|
+
"max": 100000000,
|
|
224
|
+
"default": "240000",
|
|
225
|
+
"appliesTo": ["agy-review"],
|
|
226
|
+
"effect": "agy-review code: the ceiling on the SUM of all outgoing prompt bytes the chunked feed may send (every envelope, 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."
|
|
217
227
|
}
|
|
218
228
|
],
|
|
219
229
|
"networkHosts": ["*.googleapis.com", "accounts.google.com", "antigravity-unleash.goog", "lh3.googleusercontent.com"],
|
|
@@ -82,10 +82,18 @@ What it does for you, and what YOU must supply:
|
|
|
82
82
|
@round1-decisions.md --focus "only the still-open items"`. The continuation sends a small DELTA
|
|
83
83
|
(restated posture + new focus + the output shape + the decided list) and never re-sends the artifact
|
|
84
84
|
— `agy` holds it in the conversation.
|
|
85
|
-
- **Oversized `code` review
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
- **Oversized `code` review — a CHUNKED FEED, not a refusal.** Past the byte ceiling
|
|
86
|
+
(`AGY_MAX_PROMPT_BYTES`, default 120000) the assembled change set is cut into under-cap parts at
|
|
87
|
+
line boundaries, fed over continuation turns (each turn: reply `OK` only), and reviewed in a final
|
|
88
|
+
turn. **Delivery is proven, not assumed:** the wrapper picks an interior line from each part AFTER
|
|
89
|
+
assembly and asks for it BY ADDRESS in a `### Delivery proof` section that comes FIRST in the
|
|
90
|
+
output; a missing or non-matching echo is a FAILED review — `exit 4`, **no receipt**. The cost is
|
|
91
|
+
stated before it is spent (N parts = N+1 subscription turns) and `AGY_REVIEW_MAX_TOTAL_BYTES`
|
|
92
|
+
(default 240000) refuses an over-large feed BEFORE turn 1. `plan`/`diff` keep refusing over the cap
|
|
93
|
+
— their artifact is an operator-supplied file the operator can split.
|
|
94
|
+
`AGY_REVIEW_ALLOW_ADDDIR` is **RETIRED** (recognized, arms nothing): headless `agy` auto-denies its
|
|
95
|
+
own `read_file`, so the offload it armed could return a confident fabrication with no way to tell.
|
|
96
|
+
The kit never grants that permission — the feed exists so none is needed.
|
|
89
97
|
- **Model:** frontier default `Gemini 3.1 Pro (High)`; any model is allowed (a sub-frontier one earns a
|
|
90
98
|
silenceable `AGY_PROBE=1` advisory). The service can still **stall on large/substantive prompts**
|
|
91
99
|
(Issue-001) — keep reviews **focused**; the hard timeout is the guard.
|
|
@@ -57,13 +57,14 @@ agy-review --continue | --conversation <id> [--decided @f] [--focus "…"] #
|
|
|
57
57
|
|---|---|---|
|
|
58
58
|
| `AGY_MODEL` | `Gemini 3.1 Pro (High)` | frontier default; **any** model is allowed — a sub-frontier one earns a silenceable advisory (quality-first, not a gate) |
|
|
59
59
|
| `AGY_PROBE` | `0` | `1` silences the off-frontier model advisory AND lets `code` run without `--facts` (an ungrounded probe never attests — its receipt is probe-marked) |
|
|
60
|
-
| `
|
|
60
|
+
| `AGY_REVIEW_MAX_TOTAL_BYTES` | `240000` | the ceiling on the SUM of all outgoing prompt bytes an oversized `code` review's chunked feed may send; checked BEFORE the first turn is spent |
|
|
61
|
+
| `AGY_REVIEW_ALLOW_ADDDIR` | `0` | **RETIRED** — recognized so an existing settings line never warns as unknown, but it arms nothing. An oversized `code` review is a chunked feed with a per-part delivery proof; the `--add-dir` offload it armed could not be verified (headless `agy` auto-denies `read_file`) |
|
|
61
62
|
| `AGY_HARD_TIMEOUT` | `30m` | the review's hard cap (longer default than a probe — reviews are slower) |
|
|
62
|
-
| `AGY_MAX_PROMPT_BYTES` | `120000` | the same single-argv byte ceiling; oversized
|
|
63
|
+
| `AGY_MAX_PROMPT_BYTES` | `120000` | the same single-argv byte ceiling; oversized `code` is DELIVERED as a chunked feed (see above), oversized `plan`/`diff` refuses with trim/split guidance |
|
|
63
64
|
|
|
64
65
|
`agy-review` is **read-only** and **advisory**: it never edits, commits, or passes a stray `--`
|
|
65
66
|
passthrough (it owns the posture). The service can still **stall on large/substantive prompts**
|
|
66
|
-
(Issue-001)
|
|
67
|
+
(Issue-001), so keep reviews **focused**; the hard timeout is the guard.
|
|
67
68
|
|
|
68
69
|
## Models
|
|
69
70
|
|
|
@@ -32,8 +32,8 @@ GUARD Do NOT comment on AI model names/versions or your own knowledge cutoff
|
|
|
32
32
|
{{FOCUS}} # from --focus "…" + any trailing focus words, merged in parse order (optional)
|
|
33
33
|
|
|
34
34
|
## The change set / plan / diff under review
|
|
35
|
-
{{ARTIFACT}} # code: the assembled, repo-complete working-tree change set (
|
|
36
|
-
#
|
|
35
|
+
{{ARTIFACT}} # code: the assembled, repo-complete working-tree change set (when oversized it
|
|
36
|
+
# is not inlined at all — see the chunked feed below)
|
|
37
37
|
# plan/diff: the supplied file, inlined
|
|
38
38
|
|
|
39
39
|
## Output — Markdown, this exact shape, nothing else
|
|
@@ -47,6 +47,69 @@ Numbered. Simplifications, reuse, naming, missing tests. Cite file:line. Empty?
|
|
|
47
47
|
Anything ambiguous that would change your verdict if answered.
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
## Over-cap `code`: the change set is DELIVERED, and delivery is PROVEN
|
|
51
|
+
|
|
52
|
+
`agy` takes its prompt as ONE argv value, and headless `agy` **auto-denies its own `read_file` tool**
|
|
53
|
+
(probed twice, including for a file inside the working tree). So an over-cap change set can never be
|
|
54
|
+
**fetched** by the model. Past `AGY_MAX_PROMPT_BYTES` a `code` review is therefore **delivered**:
|
|
55
|
+
the assembled change set is cut into under-cap parts, fed over continuation turns, and reviewed in a
|
|
56
|
+
final turn. `plan` / `diff` keep refusing over the cap — their artifact is an operator-supplied file
|
|
57
|
+
the operator can split.
|
|
58
|
+
|
|
59
|
+
- **Envelope and body are formally separate.** Each fed turn = an ENVELOPE the wrapper authors
|
|
60
|
+
(framing, part index, the acknowledge-only instruction) plus a **pristine BODY**, a verbatim slice
|
|
61
|
+
of the change set. Only BODIES concatenate, and they concatenate **byte-for-byte**: nothing the
|
|
62
|
+
wrapper adds ever enters the reviewed artifact, and the receipt's fingerprint domain is untouched.
|
|
63
|
+
- **Delivery is proven, never assumed.** After assembly the wrapper picks, per part, an interior line
|
|
64
|
+
the model cannot anticipate, and asks for it **by address only**. The mandated shape gains
|
|
65
|
+
`### Delivery proof` as its **FIRST** section, so output truncation cannot silently drop it:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
### Delivery proof
|
|
69
|
+
part <K> line <L>: <the text of line L of part K, VERBATIM>
|
|
70
|
+
Requested addresses, one per line:
|
|
71
|
+
part 1 line 743
|
|
72
|
+
part 2 line 512
|
|
73
|
+
### Verdict
|
|
74
|
+
…
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The addresses ride **one per line, each shorter than the minimum length a proof candidate may have**.
|
|
78
|
+
That is not formatting: it makes a collision **constructively impossible**. A candidate is a single
|
|
79
|
+
line of at least that minimum, and a single line can never match across a newline — so the request
|
|
80
|
+
itself can never reveal the very text it asks for, and the wrapper needs no second selection pass.
|
|
81
|
+
|
|
82
|
+
- **Any missing or non-matching echo is a FAILED review** — `exit 4`, **NO receipt**, and a message
|
|
83
|
+
naming the cause. Never a downgraded verdict, never a warning beside a kept receipt.
|
|
84
|
+
- **Cost is stated before it is spent** (D5): N parts cost N+1 subscription turns, announced on
|
|
85
|
+
stderr before the first dispatch. `AGY_REVIEW_MAX_TOTAL_BYTES` (default 240000) bounds the SUM of
|
|
86
|
+
all outgoing prompt bytes and refuses **before** turn 1 — an economy guard, not the correctness
|
|
87
|
+
guard.
|
|
88
|
+
- **The receipt self-declares delivery**: `inline` (the whole change set rode one prompt — proven by
|
|
89
|
+
construction) or `fed` (proven by echo). The kit's review-state gate requires the field present and
|
|
90
|
+
well-formed, never a particular value, so a receipt minted before this lane existed no longer
|
|
91
|
+
attests. The recovery is stated: re-run the review.
|
|
92
|
+
|
|
93
|
+
### Honest residuals (recorded, not engineered away)
|
|
94
|
+
|
|
95
|
+
- A model that genuinely received every part but **mis-transcribes** one echo produces a FALSE
|
|
96
|
+
refusal and its analysis is lost. Placing the proof FIRST bounds the truncation case, and the
|
|
97
|
+
comparison tolerates surrounding whitespace only — never content. The rest is the accepted price of
|
|
98
|
+
failing closed: **re-run the review**, do not distrust the lane.
|
|
99
|
+
- A change set whose parts carry **no unique interior line** in the 24..200-byte window (a single
|
|
100
|
+
huge minified line, for instance) cannot be proven delivered, so the wrapper **refuses** rather
|
|
101
|
+
than reviewing unprovably. Split the review, or exclude the blob.
|
|
102
|
+
- The conversation id is parsed from `agy`'s own run log, whose format is `agy`'s to change. An
|
|
103
|
+
unparseable log **degrades loudly** to `--continue`; correctness still rests on the echo proof,
|
|
104
|
+
which fails closed when the wrong conversation answers.
|
|
105
|
+
|
|
106
|
+
## agy's own permission ask — surfaced, never applied
|
|
107
|
+
|
|
108
|
+
When `agy` denies `read_file` it names the permission rule it wants. The kit **never writes it**:
|
|
109
|
+
granting it would widen a boundary for ALL `agy` use on the machine, and it would buy nothing this
|
|
110
|
+
design needs — the fed lane delivers content inline and reads no file. `--dangerously-skip-permissions`
|
|
111
|
+
is strictly worse (it auto-approves writes during a read-only review) and is not offered.
|
|
112
|
+
|
|
50
113
|
## Why no "read the repo's AGENTS.md" instruction
|
|
51
114
|
|
|
52
115
|
Earlier versions told `agy` to *read the repo's root `AGENTS.md` (your cwd)*. That was the documented
|
|
@@ -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.
|
|
5
|
+
version: '3.2.0'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# codex-cli-bridge
|
|
@@ -121,7 +121,7 @@ aw_settings_file() {
|
|
|
121
121
|
printf '%s/agent-workflow/bridge-settings.conf' "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
122
122
|
}
|
|
123
123
|
aw_settings_known() {
|
|
124
|
-
case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR " in
|
|
124
|
+
case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR AGY_REVIEW_MAX_TOTAL_BYTES " in
|
|
125
125
|
*" $1 "*) return 0 ;;
|
|
126
126
|
*) return 1 ;;
|
|
127
127
|
esac
|
|
@@ -144,6 +144,7 @@ aw_settings_valid() {
|
|
|
144
144
|
CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
|
|
145
145
|
AGY_HARD_TIMEOUT) [[ "$v" =~ $dur_re && ! "$v" =~ $zero_re ]] ;;
|
|
146
146
|
AGY_REVIEW_ALLOW_ADDDIR) [[ "$v" == "0" || "$v" == "1" ]] ;;
|
|
147
|
+
AGY_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
|
|
147
148
|
*) return 1 ;;
|
|
148
149
|
esac
|
|
149
150
|
}
|
|
@@ -124,7 +124,7 @@ aw_settings_file() {
|
|
|
124
124
|
printf '%s/agent-workflow/bridge-settings.conf' "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
125
125
|
}
|
|
126
126
|
aw_settings_known() {
|
|
127
|
-
case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR " in
|
|
127
|
+
case " CODEX_SERVICE_TIER CODEX_HARD_TIMEOUT CODEX_REVIEW_MAX_TOTAL_BYTES AGY_HARD_TIMEOUT AGY_REVIEW_ALLOW_ADDDIR AGY_REVIEW_MAX_TOTAL_BYTES " in
|
|
128
128
|
*" $1 "*) return 0 ;;
|
|
129
129
|
*) return 1 ;;
|
|
130
130
|
esac
|
|
@@ -147,6 +147,7 @@ aw_settings_valid() {
|
|
|
147
147
|
CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
|
|
148
148
|
AGY_HARD_TIMEOUT) [[ "$v" =~ $dur_re && ! "$v" =~ $zero_re ]] ;;
|
|
149
149
|
AGY_REVIEW_ALLOW_ADDDIR) [[ "$v" == "0" || "$v" == "1" ]] ;;
|
|
150
|
+
AGY_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
|
|
150
151
|
*) return 1 ;;
|
|
151
152
|
esac
|
|
152
153
|
}
|
|
@@ -265,7 +266,7 @@ DEFAULT_CODEX_EFFORT="xhigh"
|
|
|
265
266
|
# Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
|
|
266
267
|
# version (drift-guarded by codex-review.test.mjs against capability.json).
|
|
267
268
|
AW_RECEIPT_BACKEND="codex"
|
|
268
|
-
AW_BRIDGE_VERSION="3.
|
|
269
|
+
AW_BRIDGE_VERSION="3.2.0"
|
|
269
270
|
CODEX_MODEL="${CODEX_MODEL:-$DEFAULT_CODEX_MODEL}"
|
|
270
271
|
CODEX_EFFORT="${CODEX_EFFORT:-$DEFAULT_CODEX_EFFORT}"
|
|
271
272
|
# Generous hard cap for a slow xhigh review (subscription latency varies).
|
|
@@ -273,6 +274,12 @@ CODEX_HARD_TIMEOUT="${CODEX_HARD_TIMEOUT:-1800}"
|
|
|
273
274
|
# Above this assembled-payload size (bytes), the diff goes via a git-dir-local temp
|
|
274
275
|
# file instead of inline — never truncated.
|
|
275
276
|
CODEX_REVIEW_MAX_TOTAL_BYTES="${CODEX_REVIEW_MAX_TOTAL_BYTES:-1500000}"
|
|
277
|
+
# The repo file map's share of the assembled payload (see emit_repo_file_map). A PINNED constant,
|
|
278
|
+
# not a knob: a plain assignment, so an inherited environment value can never move it. codex has no
|
|
279
|
+
# single-argv ceiling (the payload rides stdin, and past CODEX_REVIEW_MAX_TOTAL_BYTES a git-dir temp
|
|
280
|
+
# file), so the budget is pinned at the DEFAULT inline-payload cap — the map can never outgrow the
|
|
281
|
+
# whole payload, and every realistic repo's map assembles byte-unchanged.
|
|
282
|
+
AW_REVIEW_MAP_BUDGET_BYTES=1500000
|
|
276
283
|
# Codex service tier (quality-neutral speed knob; live-probed 2026-07-05): default EMPTY ⇒ no
|
|
277
284
|
# service_tier flag (standard tier) — enabling Fast is a consented per-host SPEND act, never a
|
|
278
285
|
# silent default. The only server-catalog tier id on this subscription is 'priority' (catalog
|
|
@@ -544,7 +551,7 @@ posture_json() {
|
|
|
544
551
|
# itself instead of inferring it from this wrapper's version (which bumps in a different release
|
|
545
552
|
# phase). Silence is not a declaration — an unmarked receipt is untrustworthy and the gate rejects it.
|
|
546
553
|
write_review_receipt() {
|
|
547
|
-
local artifact="$1" fresh="$2" fingerprint="$3" verdict="$4" grounded="$5" facts_hash="$6" probe="${7:-false}"
|
|
554
|
+
local artifact="$1" fresh="$2" fingerprint="$3" verdict="$4" grounded="$5" facts_hash="$6" probe="${7:-false}" delivery="${8:-}"
|
|
548
555
|
local receipts="${AW_REVIEW_RECEIPTS:-}"
|
|
549
556
|
if [[ -z "$receipts" ]]; then
|
|
550
557
|
local receipt_git_dir
|
|
@@ -554,27 +561,70 @@ write_review_receipt() {
|
|
|
554
561
|
fi
|
|
555
562
|
receipts="$receipt_git_dir/agent-workflow-review-receipts.jsonl"
|
|
556
563
|
fi
|
|
557
|
-
local line probe_field=',"probe":false'
|
|
564
|
+
local line probe_field=',"probe":false' delivery_field=""
|
|
558
565
|
if [[ "$probe" == "true" ]]; then probe_field=',"probe":true'; fi
|
|
559
|
-
|
|
566
|
+
if [[ -n "$delivery" ]]; then delivery_field=",\"delivery\":\"$delivery\""; fi
|
|
567
|
+
line="$(printf '{"schema":1,"artifact":%s,"fresh":%s,"fingerprint":%s,"backend":"%s","verdict":"%s","grounded":%s,"factsHash":%s,"wrapperVersion":"%s","timestamp":"%s"%s,"posture":%s%s}' \
|
|
560
568
|
"$(receipt_json_scalar "$artifact")" "$fresh" "$(receipt_json_scalar "$fingerprint")" \
|
|
561
569
|
"$AW_RECEIPT_BACKEND" "$verdict" "$grounded" "$(receipt_json_scalar "$facts_hash")" \
|
|
562
|
-
"$AW_BRIDGE_VERSION" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$probe_field" "$(posture_json)")"
|
|
570
|
+
"$AW_BRIDGE_VERSION" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$probe_field" "$(posture_json)" "$delivery_field")"
|
|
563
571
|
if ! printf '%s\n' "$line" >>"$receipts" 2>/dev/null; then
|
|
564
572
|
echo "warning: could not append the review receipt to $receipts — the review itself succeeded;" >&2
|
|
565
573
|
echo " the review-state gate will read the current tree as un-receipted." >&2
|
|
566
574
|
fi
|
|
567
575
|
}
|
|
568
576
|
|
|
569
|
-
#
|
|
570
|
-
#
|
|
571
|
-
#
|
|
572
|
-
#
|
|
573
|
-
#
|
|
574
|
-
#
|
|
577
|
+
# The repo file map is a FIXED cost that scales with REPO SIZE, not change size (measured 28,735
|
|
578
|
+
# bytes in the home repo — 24% of agy's 120000-byte single-argv ceiling), so an unbounded map taxes
|
|
579
|
+
# the change budget of every review. AW_REVIEW_MAP_BUDGET_BYTES bounds it; the value is set by each
|
|
580
|
+
# wrapper so THIS BODY stays byte-identical across both (review-fingerprint-parity.test.mjs
|
|
581
|
+
# lockstep). Unset/0 = unbounded. Past the budget the map degrades to the CHANGED-path subset — cut
|
|
582
|
+
# at the SAME budget, so a change touching very many long paths cannot re-breach the bound — plus a
|
|
583
|
+
# stated omitted count; a truncation-with-count, never a silent cut. The map was never part of the
|
|
584
|
+
# fingerprint domain (emit_fingerprint_payload does not contain it), so bounding it moves no receipt.
|
|
585
|
+
emit_repo_file_map() {
|
|
586
|
+
local budget="${AW_REVIEW_MAP_BUDGET_BYTES:-0}" total shown omitted subset tracked
|
|
587
|
+
# ONE deduplicated tracked-path SNAPSHOT, captured once and reused for all four uses — the
|
|
588
|
+
# byte-budget predicate, the printed map, `total`, and the index intersection. Re-running the query
|
|
589
|
+
# per use let a concurrent index change make the budget decision, the map and the counts describe
|
|
590
|
+
# DIFFERENT snapshots. Dedupe: an UNMERGED index lists a path once per stage, so a predicate
|
|
591
|
+
# counting duplicates against a map printing unique paths would push a map that fits into the
|
|
592
|
+
# truncated arm. `ls-files` output is sorted by path, so one path's stages are adjacent and `uniq`
|
|
593
|
+
# is exact — no git version floor needed.
|
|
594
|
+
tracked="$(git ls-files | LC_ALL=C uniq)"
|
|
595
|
+
if (( budget <= 0 )) || (( $(printf '%s\n' "$tracked" | wc -c) <= budget )); then
|
|
596
|
+
if [[ -n "$tracked" ]]; then printf '%s\n' "$tracked"; fi
|
|
597
|
+
return 0
|
|
598
|
+
fi
|
|
599
|
+
total=$(( $(printf '%s\n' "$tracked" | wc -l) ))
|
|
600
|
+
# The subset is INTERSECTED with the index before budgeting, so `shown` and `total` live in ONE
|
|
601
|
+
# domain and `shown + omitted == total` holds exactly: a STAGED DELETION is a changed path that is
|
|
602
|
+
# no longer in `git ls-files`, and counting it as shown would make the stated arithmetic a lie.
|
|
603
|
+
# (The NR==FNR reader is safe here: an empty index returns through the in-budget arm above.)
|
|
604
|
+
# awk never `exit`s early: a closed pipe would SIGPIPE `sort` and pipefail would abort the run.
|
|
605
|
+
subset="$(LC_ALL=C awk 'NR == FNR { known[$0] = 1; next } ($0 in known)' <(printf '%s\n' "$tracked") <(git diff --name-only --no-ext-diff; git diff --cached --name-only --no-ext-diff) |
|
|
606
|
+
LC_ALL=C sort -u |
|
|
607
|
+
LC_ALL=C awk -v cap="$budget" '{ n = length($0) + 1; if (!over && used + n <= cap) { used += n; print } else over = 1 }')"
|
|
608
|
+
shown=0
|
|
609
|
+
if [[ -n "$subset" ]]; then
|
|
610
|
+
printf '%s\n' "$subset"
|
|
611
|
+
shown=$(( $(printf '%s\n' "$subset" | wc -l) ))
|
|
612
|
+
fi
|
|
613
|
+
omitted=$(( total - shown ))
|
|
614
|
+
if (( omitted < 0 )); then omitted=0; fi
|
|
615
|
+
printf '=== repo file map TRUNCATED to the changed-path subset: %s of %s tracked paths shown, %s omitted (map budget %s bytes) ===\n' \
|
|
616
|
+
"$shown" "$total" "$omitted" "$budget"
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
# Emit the full review surface to stdout: repo map (bounded, see emit_repo_file_map), status
|
|
620
|
+
# (never-committable untracked records filtered), staged + unstaged diffs, and the CONTENTS of every
|
|
621
|
+
# untracked REGULAR file (NUL-safe iteration over the SAME filtered walk as the fingerprint — the
|
|
622
|
+
# payload is byte-identical with and without a device mask). Symlinks are shown as their target
|
|
623
|
+
# (never followed — no out-of-repo leak); directories/vanished paths are noted, never read (a `cat`
|
|
624
|
+
# on a FIFO would hang BEFORE the hard timeout applies — that class never reaches this loop).
|
|
575
625
|
assemble_code_diff() {
|
|
576
626
|
echo "=== repo file map (git ls-files) ==="
|
|
577
|
-
|
|
627
|
+
emit_repo_file_map
|
|
578
628
|
echo
|
|
579
629
|
echo "=== git status (porcelain) ==="
|
|
580
630
|
emit_status_porcelain_filtered
|
|
@@ -765,6 +765,44 @@ describe('codex-review.sh — source-level reverse guard (parser arms ⟷ manife
|
|
|
765
765
|
});
|
|
766
766
|
});
|
|
767
767
|
|
|
768
|
+
// ── the repo file map budget (Phase 2) ────────────────────────────────────────────
|
|
769
|
+
// The shared emit_repo_file_map bounds the map in BOTH wrappers (byte-identical, kit parity test).
|
|
770
|
+
// codex has no single-argv ceiling — its payload rides stdin, and past CODEX_REVIEW_MAX_TOTAL_BYTES
|
|
771
|
+
// a git-dir temp file — so its budget is set at the default inline cap: the map can never outgrow
|
|
772
|
+
// the whole payload, and every realistic repo's map assembles byte-UNCHANGED. Behaviour alone
|
|
773
|
+
// cannot tell "a huge budget" from "no budget at all", so the pinned value is asserted at source.
|
|
774
|
+
describe('codex-review.sh — repo file map budget (Phase 2)', () => {
|
|
775
|
+
const MAP_DIR = 'deeply/nested/fixture/directory/for/the/repo/file/map/budget';
|
|
776
|
+
|
|
777
|
+
it("codex-review's assembled payload is byte-unchanged by the map budget", () => {
|
|
778
|
+
const sb = makeSandbox();
|
|
779
|
+
const g = (...a) => spawnSync('git', a, { cwd: sb.repo, encoding: 'utf8' });
|
|
780
|
+
mkdirSync(join(sb.repo, MAP_DIR), { recursive: true });
|
|
781
|
+
for (let i = 0; i < 100; i += 1) {
|
|
782
|
+
writeFileSync(join(sb.repo, `${MAP_DIR}/aa-untouched-file-${String(i).padStart(3, '0')}.txt`), `untouched ${i}\n`);
|
|
783
|
+
writeFileSync(join(sb.repo, `${MAP_DIR}/zz-modified-file-${String(i).padStart(3, '0')}.txt`), `body ${i} v1\n`);
|
|
784
|
+
}
|
|
785
|
+
g('add', '-A');
|
|
786
|
+
g('commit', '-qm', 'map fixture');
|
|
787
|
+
for (let i = 0; i < 100; i += 1) writeFileSync(join(sb.repo, `${MAP_DIR}/zz-modified-file-${String(i).padStart(3, '0')}.txt`), `body ${i} v2 — changed\n`);
|
|
788
|
+
const r = run(sb, { args: ['code'] });
|
|
789
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
790
|
+
assert.equal(r.status, 0, r.stderr);
|
|
791
|
+
assert.doesNotMatch(r.capStdin, /TRUNCATED/, 'a 17 KB map is far inside the budget — no degradation');
|
|
792
|
+
assert.ok(r.capStdin.includes(`${MAP_DIR}/aa-untouched-file-000.txt`), 'the whole map is still listed');
|
|
793
|
+
assert.ok(r.capStdin.includes(`${MAP_DIR}/aa-untouched-file-099.txt`), 'including its last entry');
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
it('the wrapper pins a map budget no smaller than its default inline-payload cap', () => {
|
|
797
|
+
const source = readFileSync(WRAPPER, 'utf8');
|
|
798
|
+
const pinned = source.match(/^AW_REVIEW_MAP_BUDGET_BYTES=(\d+)$/m);
|
|
799
|
+
assert.ok(pinned, 'codex-review.sh must PIN AW_REVIEW_MAP_BUDGET_BYTES (a plain assignment, never an env knob)');
|
|
800
|
+
const inlineCap = source.match(/^CODEX_REVIEW_MAX_TOTAL_BYTES="\$\{CODEX_REVIEW_MAX_TOTAL_BYTES:-(\d+)\}"$/m);
|
|
801
|
+
assert.ok(inlineCap, 'the default inline-payload cap is readable at source');
|
|
802
|
+
assert.ok(Number(pinned[1]) >= Number(inlineCap[1]), `map budget ${pinned[1]} must not be smaller than the inline cap ${inlineCap[1]}`);
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
|
|
768
806
|
// ── mode catalog ⟷ wrapper reality (BRIDGE-MODES-CATALOG) ─────────────────────────
|
|
769
807
|
// The kit validator owns the catalog's INTERNAL shape; these arms pin what only the wrapper source
|
|
770
808
|
// can settle — the catalog documents THIS wrapper's real modes and real escape hatches, and every
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.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",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-lens
|
|
3
|
+
description: Read-only ADDITIONAL review lens — an extra independent opinion on code the orchestrator already has, when the configured review backends have run and you want another angle. Grants no shell, so it can never turn a review into a wave of approval prompts. Never for writing code, running gates, or replacing the configured review recipe.
|
|
4
|
+
model: sonnet
|
|
5
|
+
effort: high
|
|
6
|
+
tools: Read, Grep, Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are an ADDITIONAL, INDEPENDENT review lens. Something has already been reviewed by the project's
|
|
10
|
+
configured backends; your job is to find what they MISSED, not to restate what they found.
|
|
11
|
+
|
|
12
|
+
You have `Read`, `Grep` and `Glob` and **no `Bash`**. That is deliberate and it is the whole point of
|
|
13
|
+
this vehicle: a read-only fan-out that can reach for a shell turns one review into a wave of approval
|
|
14
|
+
prompts for the maintainer, so this lens structurally cannot.
|
|
15
|
+
If a harness omits `Grep`/`Glob`, fall back to the `Read` tool (whole-file reads) — never a
|
|
16
|
+
shelled-out command. Should a harness
|
|
17
|
+
nonetheless route your reads through `Bash`, keep each one a **plain single read-only command**
|
|
18
|
+
(`grep …`, `ls …`, `cat …`) — never a `;`/`&&`/`|` chain, never `node -e`; where the maintainer
|
|
19
|
+
enabled the opt-in **read-lane** (`docs/ai/lanes.json`), the gate hook keeps those seeded-read-only
|
|
20
|
+
Bash reads promptless (subagent Bash included, where the host fires hooks on subagent Bash).
|
|
21
|
+
|
|
22
|
+
How to review:
|
|
23
|
+
|
|
24
|
+
- **Read the code before judging it.** Every finding cites `file:line` and names the concrete input
|
|
25
|
+
or state that triggers it. A finding you cannot anchor in the code does not go in the output.
|
|
26
|
+
- **Say what BREAKS, not what could be nicer.** For each finding: the defect in one sentence, then
|
|
27
|
+
the failure scenario — the input, the resulting wrong behaviour. No style preferences, no
|
|
28
|
+
restatement of design intent back to the orchestrator.
|
|
29
|
+
- **Respect what is already decided.** The prompt will name findings already folded and decisions
|
|
30
|
+
already locked. Re-raising them is churn; checking whether the FIX is correct is real work.
|
|
31
|
+
- **Accuracy over volume.** A wrong finding costs the orchestrator more than a missed one — it
|
|
32
|
+
spends a verification cycle and erodes trust in the whole list. If an angle turns up nothing, say
|
|
33
|
+
so in one line and move on. Never pad.
|
|
34
|
+
- **You are advisory.** You never edit files, never run gates, never propose a commit. The
|
|
35
|
+
orchestrator verifies every finding and owns every change.
|
|
36
|
+
|
|
37
|
+
Output: a numbered list of findings, most severe first, each as
|
|
38
|
+
`[severity] — file:line — the defect — the failure scenario — the fix direction`.
|
|
39
|
+
Then one line: `no further findings` or the angles you deliberately did not cover.
|
|
@@ -42,6 +42,21 @@
|
|
|
42
42
|
// (d) everything else → NO decision: exit 0, no output — the normal permission flow proceeds
|
|
43
43
|
// unchanged. The hook NEVER emits `deny`.
|
|
44
44
|
//
|
|
45
|
+
// WHY THERE IS NO DENY RUNG (kit 4.0.0, three council rounds, AD-078). One was built and REMOVED
|
|
46
|
+
// before release. It refused only a seeded read-only command that provably DISCARDS its output
|
|
47
|
+
// (`2>/dev/null`), on the argument that such a refusal cannot destroy anything the caller wanted.
|
|
48
|
+
// The argument was sound; the byte-level PROOF of "this command discards" was not, and could not be
|
|
49
|
+
// made so here. Five constructs defeated it in three rounds — `1<&2` (an fd dup routes stdout back
|
|
50
|
+
// out of /dev/null AFTER the approved `>`), a quoted literal `>/dev/null ` in an argument, a
|
|
51
|
+
// leading-token-only segment match (`… && npm test`), a bare `&` (backgrounds the read, runs the
|
|
52
|
+
// rest), and a `#` comment (bash never executes the redirect at all). Each was a FALSE REFUSAL.
|
|
53
|
+
// The lesson, which any future deny rung must start from: on an ASK rung an incomplete scan merely
|
|
54
|
+
// over-asks, which is safe; on a DENY rung the SAME incompleteness refuses real work. Deciding
|
|
55
|
+
// whether a `>` is an operator or text requires lexing the shell, which this dependency-free hook
|
|
56
|
+
// deliberately does not do. A deny rung therefore needs a justification that does not rest on
|
|
57
|
+
// parsing command bytes. Design record + all five counterexamples: docs/plans/queue.md,
|
|
58
|
+
// BARE-LANE-DENY-RUNG.
|
|
59
|
+
//
|
|
45
60
|
// Fail-safe invariant, decoupled per function: a DECLARATION anomaly (missing / unreadable /
|
|
46
61
|
// malformed / schema-invalid gates.json) disables ONLY exact-gate approval (a) — the residual
|
|
47
62
|
// guard (b) needs no declaration and keeps running (a broken gates.json must not silently
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
### Mode: agents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- opt-in-capability: agents -->
|
|
4
|
+
|
|
5
|
+
The opt-in **read-only subagent writer** — the family's second `.claude/` writer, on the velocity discipline. It places the bundled subagent definitions (`references/agents/*.md`) into the project's `.claude/agents/`. **Claude-Code-specific** (like velocity): other agent hosts ignore `.claude/agents/`.
|
|
6
|
+
|
|
7
|
+
**Every vehicle grants READ-ONLY tools and NO `Bash`** — that is the load-bearing property, not a detail. A read-only fan-out on a full-tool vehicle shells out for facts it could have read, and each shelled command is an approval prompt the maintainer never needed to see; a vehicle with no shell structurally cannot do that. Two lanes ride on it:
|
|
8
|
+
|
|
9
|
+
- **cheap lane** (`model: haiku`, `effort: low`) — `mechanical-sweep`, `changelog-skeleton`, `gate-triage`: extraction sweeps, changelog fact-skeletons, gate-failure triage. Extraction/drafting only; the orchestrator applies judgment and verifies the output.
|
|
10
|
+
- **review lens** (`review-lens`, review-capable model) — an ADDITIONAL independent read-only opinion on code the configured review backends have already seen. It exists because a third lens otherwise has **no vehicle at all**: the cheap vehicles are scoped away from judgment, and a review-capable full-tool subagent is the prompt-flood shape. It never replaces the configured review recipe, and it is advisory like every other review.
|
|
11
|
+
|
|
12
|
+
Writing code, running gates, and user-facing copy never move to these vehicles.
|
|
4
13
|
|
|
5
14
|
Run `node ${CLAUDE_SKILL_DIR}/tools/cheap-agents.mjs [--dry-run | --apply] [--cwd <dir>]`:
|
|
6
15
|
|
|
@@ -8,4 +17,4 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/cheap-agents.mjs [--dry-run | --apply] [--cw
|
|
|
8
17
|
2. **Only on an explicit yes**, re-run with `--apply`. It writes **only** under `.claude/agents/` — never `settings.json` / `settings.local.json`, never a commit. `--apply` is deployment-gated (the stamp must be at the lineage head) and symlink-safe (a symlinked `.claude` / `.claude/agents` / target file is a STOP).
|
|
9
18
|
3. **Hidden-mode deployments:** after apply, run the hide-footprint reconcile (`node ${CLAUDE_SKILL_DIR}/tools/hide-footprint.mjs --dir <project> --reconcile`) so the placed files stay invisible to `git status` — `/.claude/agents/` is in the known-footprint registry; the apply report reminds you.
|
|
10
19
|
|
|
11
|
-
**Invariants:** writer (writes only `.claude/agents/`) · preview by default · a diverged existing file is reported and preserved, never clobbered · never touches settings · never commits · vehicles are pinned to `model: haiku` + `effort: low
|
|
20
|
+
**Invariants:** writer (writes only `.claude/agents/`) · preview by default · a diverged existing file is reported and preserved, never clobbered · never touches settings · never commits · **no vehicle grants `Bash`** · the cheap-lane vehicles are pinned to `model: haiku` + `effort: low`, and the review lens is pinned OFF the cheap model (all content-tested).
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
### Mode: autonomy-doctor
|
|
2
2
|
|
|
3
|
+
<!-- opt-in-capability: sandbox-provision -->
|
|
4
|
+
|
|
3
5
|
The **sandbox provisioner "doctor"** — the answer to *"can this machine run the Claude sandbox, and can you fix it?"* (AD-044: macOS Seatbelt built-in / Linux+WSL2 `bwrap`+`socat` / native Windows → WSL2). **Division of labor:** YOU narrate the diagnosis and relay the consent question; the KIT does the deterministic detect → consent-gated install → verify. It is **guarded**: the privileged lane runs ONLY with the per-run consent tuple, always faces the harness permission prompt (the mode sits outside every velocity auto-approve tier), **never auto-runs, never writes repo files, and never commits**.
|
|
4
6
|
|
|
5
7
|
Run **`node ${CLAUDE_SKILL_DIR}/tools/autonomy-doctor.mjs [--verify | --apply <pm>:<pkg[,pkg...]>]`**:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
### Mode: backends
|
|
2
2
|
|
|
3
|
+
<!-- opt-in-capability: none — an inspection surface that configures nothing -->
|
|
4
|
+
|
|
3
5
|
Read-only. Answers *"which optional execution-backends are set up vs missing, and what's the next step?"* — for the family's subscription-CLI bridges (`codex-cli-bridge` → `codex`, `antigravity-cli-bridge` → `agy`). It **never writes, never commits, and never runs a subscription CLI**.
|
|
4
6
|
|
|
5
7
|
1. Run `node ${CLAUDE_SKILL_DIR}/tools/detect-backends.mjs` and present its table verbatim. Each row reports two **decoupled** axes: `manifestState` (health of the bridge *skill* — `not-installed | unsupported-schema | invalid-manifest | foreign | stub | ok`) and the readiness signals `cli` / `credentials` / `wrappers`, probed independently — so a CLI that is installed and signed in but whose bridge *skill* is absent reads `needs-skill`, not "missing".
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
### Mode: bootstrap
|
|
2
2
|
|
|
3
|
+
<!-- opt-in-capability: none — the deployment action itself; the advisor only renders inside an existing deployment -->
|
|
4
|
+
|
|
3
5
|
Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKILL_DIR}/references/shared/composition-handoff.md · ${CLAUDE_SKILL_DIR}/references/shared/deploy-tail.md · ${CLAUDE_SKILL_DIR}/references/shared/command-shapes.md
|
|
4
6
|
|
|
5
7
|
> Bundled sources below (templates, scripts) live in **this skill's own directory** — `${CLAUDE_SKILL_DIR}/` in Claude Code, or the folder containing this `SKILL.md` in Codex / other agents. Use that as the copy/read source; the working directory is the **target project**, not the skill.
|