@sabaiway/agent-workflow-kit 14.21.0 → 14.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +95 -0
- package/README.md +1 -1
- package/SKILL.md +1 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +16 -10
- package/bridges/antigravity-cli-bridge/bin/agy-jev.test.mjs +105 -0
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +20 -6
- package/bridges/antigravity-cli-bridge/bin/agy.sh +26 -11
- package/bridges/antigravity-cli-bridge/capability.json +3 -3
- package/bridges/antigravity-cli-bridge/references/models-and-flags.md +4 -3
- package/bridges/antigravity-cli-bridge/setup/README.md +2 -1
- package/bridges/codex-cli-bridge/SKILL.md +44 -24
- package/bridges/codex-cli-bridge/bin/codex-exec-jev.test.mjs +385 -0
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +262 -42
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +16 -18
- package/bridges/codex-cli-bridge/bin/codex-model-posture.test.mjs +16 -7
- package/bridges/codex-cli-bridge/bin/codex-review-honesty.test.mjs +1 -0
- package/bridges/codex-cli-bridge/bin/codex-review-jev.test.mjs +301 -0
- package/bridges/codex-cli-bridge/bin/codex-review.sh +240 -26
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +9 -9
- package/bridges/codex-cli-bridge/capability.json +10 -10
- package/bridges/codex-cli-bridge/references/driving-codex.md +18 -14
- package/bridges/codex-cli-bridge/references/sandbox-and-flags.md +61 -22
- package/bridges/codex-cli-bridge/setup/README.md +8 -5
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/authoring/TASK_TEMPLATE.md +11 -16
- package/references/modes/agents.md +2 -2
- package/references/modes/procedures.md +7 -7
- package/references/modes/recipes.md +1 -1
- package/references/modes/recommendations.md +1 -1
- package/references/modes/set-recipe.md +1 -1
- package/references/modes/tier.md +1 -1
- package/references/modes/velocity.md +2 -2
- package/references/reference-profile.json +1 -1
- package/references/templates/SPEC_TEMPLATE.md +2 -1
- package/references/templates/agent_rules.md +7 -7
- package/tools/carriers.mjs +6 -4
- package/tools/cheap-agents.mjs +1 -1
- package/tools/detect-backends.mjs +3 -3
- package/tools/held-session.mjs +1 -33
- package/tools/manifest/schema.md +2 -2
- package/tools/procedures.mjs +83 -113
- package/tools/rules-regions.mjs +2 -1
- package/tools/tier-guide-facts.mjs +145 -159
- package/tools/tier-guide.mjs +8 -14
|
@@ -9,8 +9,9 @@ wrapper commands are `codex-exec` and `codex-review`, backed by `bin/codex-exec.
|
|
|
9
9
|
|
|
10
10
|
| Level | Can write? | Network? | Wrapper that uses it |
|
|
11
11
|
|---|---|---|---|
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
12
|
+
| permissions profile `jev` | exec: the repository, `/tmp` and `$TMPDIR`; review: nothing | `api.typesafe.ai` and `docs.typesafe.ai` only | both wrappers on Linux with codex-cli 0.160.0 or newer (conditions below) |
|
|
13
|
+
| `read-only` | no | no | `codex-review`, the fallback (codex only reads + emits findings) |
|
|
14
|
+
| `workspace-write` | repository, `/tmp` and `$TMPDIR` | off (forced off) | `codex-exec`, the fallback (codex edits the repo) |
|
|
14
15
|
| `danger-full-access` | anywhere | yes | never used by this skill |
|
|
15
16
|
|
|
16
17
|
**A sandbox bounds WRITES, not READS.** Even `read-only` can read any file on disk (it is what kept a
|
|
@@ -20,7 +21,7 @@ a **prompt + env** concern, not a sandbox one — see the review read-fence belo
|
|
|
20
21
|
|
|
21
22
|
## Flags the wrappers always pass
|
|
22
23
|
|
|
23
|
-
`codex-exec
|
|
24
|
+
`codex-exec`, on today's flags:
|
|
24
25
|
|
|
25
26
|
```bash
|
|
26
27
|
codex exec --ignore-user-config \
|
|
@@ -32,10 +33,23 @@ codex exec --ignore-user-config \
|
|
|
32
33
|
--color never -o "$out" --json -m "$CODEX_MODEL" -
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`
|
|
36
|
+
On Linux with codex-cli 0.160.0 or newer, from a repository outside every temp root and off a codex
|
|
37
|
+
version and profile digest recorded as refused, the first two
|
|
38
|
+
posture flags (`--sandbox workspace-write` and the `network_access=false` override) give way to the
|
|
39
|
+
permissions profile `jev` — four overrides, never beside `--sandbox` or `sandbox_mode` (codex refuses
|
|
40
|
+
both together):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
-c default_permissions=jev -c permissions.jev.network.enabled=true \
|
|
44
|
+
-c 'permissions.jev.network.domains={"api.typesafe.ai"="allow","docs.typesafe.ai"="allow"}' \
|
|
45
|
+
-c 'permissions.jev.filesystem={":root"="read",":tmpdir"="write",":slash_tmp"="write",":workspace_roots"={"."="write"}}'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`codex-review` is the same minus the write/network posture, plus (optionally) `--output-schema`: on
|
|
49
|
+
today's flags `--sandbox read-only`, which in v0.142.3 also grants **no network** (the
|
|
50
|
+
`sandbox_workspace_write.*` config, `network_access` included, applies **only** to `workspace-write`);
|
|
51
|
+
under the profile `jev` the same four overrides with `permissions.jev.filesystem={":root"="read"}` —
|
|
52
|
+
no write entry at all, so a review still writes nothing. The banner's `jev=` field names the posture.
|
|
39
53
|
|
|
40
54
|
### Clean output capture
|
|
41
55
|
|
|
@@ -90,16 +104,30 @@ Note that `--skip-git-repo-check` (tier 2) only relaxes **codex's own** git-repo
|
|
|
90
104
|
preflight still **requires a git work tree and a root `AGENTS.md`** and STOPs first if either is
|
|
91
105
|
missing — passing it does not let `codex-exec` run outside a repo.
|
|
92
106
|
|
|
93
|
-
## Network
|
|
94
|
-
|
|
95
|
-
`
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
## Network: two hosts at most
|
|
108
|
+
|
|
109
|
+
A run reaches `api.typesafe.ai` and `docs.typesafe.ai` under the permissions profile `jev` and no other
|
|
110
|
+
host; on today's flags `codex-exec` keeps the network off. Either way **new dependencies and any other
|
|
111
|
+
network step are installed by a human**, not by codex: if a task needs a new package, codex must STOP
|
|
112
|
+
and report it; the orchestrator installs it, then re-dispatches. The profile runs on Linux with
|
|
113
|
+
codex-cli 0.160.0 or newer, off a codex version and profile digest recorded as refused and, for
|
|
114
|
+
`codex-exec`, from a repository whose root and git common dir sit outside `/tmp` and `$TMPDIR` (there
|
|
115
|
+
the profile would leave `.git` writable); every other run keeps today's flags and its banner says
|
|
116
|
+
`jev=unreachable (<reason>)`.
|
|
117
|
+
|
|
118
|
+
**The loud failure.** A run whose codex refuses the profile — a "Permissions profile `jev` …" or
|
|
119
|
+
"Configured filesystem path … is not recognized …" error item before the turn starts, or `bwrap: execvp`
|
|
120
|
+
in a command item whose failure is proven — exits **72** with the matched message and no success
|
|
121
|
+
receipt (a nonced exec run records `transport-failure`; a review writes no receipt). The error-item case
|
|
122
|
+
appends `<codex version> <sha256 of the profile overrides>` to
|
|
123
|
+
`${XDG_STATE_HOME:-~/.local/state}/agent-workflow/codex-jev-profile-refused`, so the next run on that
|
|
124
|
+
version and digest takes today's flags before any spend; if that file cannot be written the wrapper
|
|
125
|
+
says so on stderr and the next run tries the profile again.
|
|
98
126
|
|
|
99
127
|
## Escalation & approvals
|
|
100
128
|
|
|
101
129
|
There is **no TTY** in `codex exec`, so `approval_policy=never`: codex never pauses for an interactive
|
|
102
|
-
approval. Any action that would need escalation (network, writes outside the repo, an ambiguous
|
|
130
|
+
approval. Any action that would need escalation (network beyond the run's posture, writes outside the repo, an ambiguous
|
|
103
131
|
decision) is **refused and reported**, and the orchestrator handles it by hand.
|
|
104
132
|
|
|
105
133
|
## Commit prohibition — enforced by a git-write shim
|
|
@@ -142,10 +170,13 @@ non-conforming text); a raw-text retry covers a rare validation/run failure. Def
|
|
|
142
170
|
### Review read-fence (best-effort env hygiene)
|
|
143
171
|
|
|
144
172
|
`codex-review` runs under a throwaway `HOME` + `XDG_CONFIG_HOME`/`XDG_CACHE_HOME`/`XDG_DATA_HOME` with an
|
|
145
|
-
**absolute `CODEX_HOME`** so auth + history still resolve while codex's default config/cache
|
|
146
|
-
|
|
173
|
+
**absolute `CODEX_HOME`** so auth + history still resolve while codex's default config/cache roots point
|
|
174
|
+
at an empty dir (trims the roaming noise). When the user's real skill root `$HOME/.agents/skills`
|
|
175
|
+
exists, the throwaway home gets `.agents/skills` as a link to it (read-only on every posture), so a
|
|
176
|
+
review can load a skill, and the fence directives admit reading it. This is **env hygiene, NOT a security
|
|
147
177
|
boundary** — absolute paths anywhere on disk remain readable under `read-only`; the real read-scoping is
|
|
148
|
-
the prompt fence ("do not read outside the working tree, except the precomputed-diff temp file"
|
|
178
|
+
the prompt fence ("do not read outside the working tree, except the precomputed-diff temp file" and a
|
|
179
|
+
linked skill).
|
|
149
180
|
|
|
150
181
|
## `resume` — resets posture, restated via `-c`
|
|
151
182
|
|
|
@@ -157,7 +188,8 @@ the sandbox/approval/network posture, and — probed on codex-cli 0.147.0 — ac
|
|
|
157
188
|
run starts, so the failure is loud and costs no quota; the wrapper's own test pins the accepted set
|
|
158
189
|
(`RESUME_ACCEPTED_FLAGS`) precisely because the hermetic fake CLI accepts any argv and cannot answer
|
|
159
190
|
this question. The `codex-exec --resume`/`--resume-last` entrypoint handles the reset: it restates
|
|
160
|
-
the entire policy via `-c` (`
|
|
191
|
+
the entire policy via `-c` (`approval_policy=never` and the posture it chooses afresh for this run —
|
|
192
|
+
the profile `jev`'s four overrides, or `sandbox_mode=workspace-write` with
|
|
161
193
|
`sandbox_workspace_write.network_access=false`) plus the host posture's `-m`/effort and
|
|
162
194
|
`--ignore-user-config`, reads the session id from the sidecar (or an argument), and applies the same
|
|
163
195
|
EVIDENCE posture as a fresh run — `-o` for the final message, `--json` into the trace. Only a *raw*
|
|
@@ -175,8 +207,9 @@ no-op — while `codex-review` **refuses pre-spend** (the fail-closed hard-timeo
|
|
|
175
207
|
|
|
176
208
|
Both wrappers, before invoking codex:
|
|
177
209
|
|
|
178
|
-
- **unset** `
|
|
179
|
-
stray key can't switch to paid api-key billing;
|
|
210
|
+
- **unset** `OPENAI_BASE_URL` and every `*_API_KEY` except `TYPESAFE_API_KEY` (`OPENAI_API_KEY` and
|
|
211
|
+
`CODEX_API_KEY` included), so a stray key can't switch to paid api-key billing; `TYPESAFE_API_KEY`
|
|
212
|
+
passes as given (empty stays empty, unset stays unset) and changes no flag;
|
|
180
213
|
- pass **`--ignore-user-config`** so a personal `~/.codex/config.toml` cannot change behaviour. Auth
|
|
181
214
|
still works: codex reads the cached login from `CODEX_HOME` (`~/.codex`) regardless of that flag;
|
|
182
215
|
- preflight `codex login status` and refuse unless it contains `Logged in using ChatGPT`;
|
|
@@ -203,7 +236,8 @@ exec` over the precomputed diff instead, keeping every invariant intact.
|
|
|
203
236
|
| `-c key=value` | override a config value (dotted, TOML-parsed) — how policy is set deterministically |
|
|
204
237
|
| `--sandbox <mode>` | `read-only` \| `workspace-write` \| `danger-full-access` (this skill uses the first two) |
|
|
205
238
|
| `-c approval_policy=never` | never pause for interactive approval (required: exec has no TTY) |
|
|
206
|
-
| `-c sandbox_workspace_write.network_access=false` | network
|
|
239
|
+
| `-c sandbox_workspace_write.network_access=false` | network off under workspace-write (exec on today's flags) |
|
|
240
|
+
| `-c default_permissions=jev` + `-c permissions.jev.*` | the permissions profile `jev`: its filesystem part and a network limited to the listed domains (probed on 0.160.0; never beside `--sandbox`/`sandbox_mode`) |
|
|
207
241
|
| `-c hide_agent_reasoning=true` / `-c model_reasoning_summary=none` | drop chain-of-thought from output (reasoning still runs) |
|
|
208
242
|
| `-o, --output-last-message <f>` | write ONLY the final message (clean capture) |
|
|
209
243
|
| `--json` | structured event stream (`thread.started` ⇒ session id) |
|
|
@@ -230,5 +264,10 @@ exec` over the precomputed diff instead, keeping every invariant intact.
|
|
|
230
264
|
from the target project root.
|
|
231
265
|
- **`exceeded the hard cap`** (exit 124/137): the run hit `CODEX_HARD_TIMEOUT` — raise it for a
|
|
232
266
|
known-healthy slow run, or narrow the task, then re-dispatch.
|
|
233
|
-
- **codex wants to install a dependency**: it can't (
|
|
234
|
-
re-dispatch.
|
|
267
|
+
- **codex wants to install a dependency**: it can't (exec reaches at most `api.typesafe.ai` and
|
|
268
|
+
`docs.typesafe.ai`) — install it by hand, then re-dispatch.
|
|
269
|
+
- **exit 72**: codex refused the permissions profile `jev` (the message is on stderr). A refused profile
|
|
270
|
+
key, codex's error item before the first turn, is recorded for that wrapper's profile digest when the
|
|
271
|
+
state file can be written (otherwise the wrapper prints one warning naming the file), so that wrapper's
|
|
272
|
+
next run on that codex version takes today's flags — re-dispatch; a `bwrap: execvp` failure records
|
|
273
|
+
nothing and recurs on every run until its cause is fixed.
|
|
@@ -28,9 +28,10 @@ codex login status # expect: Logged in using ChatGPT
|
|
|
28
28
|
|
|
29
29
|
This caches credentials under `CODEX_HOME` (`~/.codex`, e.g. `~/.codex/auth.json`). That directory is
|
|
30
30
|
**personal** — never copy, commit, package, print, or share it. This skill needs **no API keys** and
|
|
31
|
-
must not be configured with api-key billing; both wrappers unset
|
|
32
|
-
`
|
|
33
|
-
pay-as-you-go and a personal
|
|
31
|
+
must not be configured with api-key billing; both wrappers unset `OPENAI_BASE_URL` and every
|
|
32
|
+
`*_API_KEY` except `TYPESAFE_API_KEY` (the one key a run passes, as given) and pass
|
|
33
|
+
`--ignore-user-config`, so billing can never silently fall back to pay-as-you-go and a personal
|
|
34
|
+
`~/.codex/config.toml` can never change behaviour.
|
|
34
35
|
|
|
35
36
|
## 3. Put the wrappers on `PATH`
|
|
36
37
|
|
|
@@ -69,8 +70,10 @@ if it reports a missing git work tree or root `AGENTS.md`, run it from a project
|
|
|
69
70
|
## Notes
|
|
70
71
|
|
|
71
72
|
- The wrappers are **subscription-only** by design and will not use api-key billing.
|
|
72
|
-
- `codex-exec` runs
|
|
73
|
-
|
|
73
|
+
- `codex-exec` runs **workspace-write**; `codex-review` runs **read-only**. On Linux with codex-cli
|
|
74
|
+
0.160.0 or newer, off a codex version and profile digest recorded as refused and, for `codex-exec`, from
|
|
75
|
+
a repository outside every temp root, both carry the permissions profile `jev`, whose network reaches `api.typesafe.ai`
|
|
76
|
+
and `docs.typesafe.ai` and no other host; elsewhere the network stays off. They also run on the host posture — `CODEX_MODEL` / `CODEX_EFFORT` from the
|
|
74
77
|
bridge settings file, else `gpt-6.1-sol` / `high` — checked against the installed CLI's catalog,
|
|
75
78
|
and refuse a one-off model or effort unless `CODEX_PROBE=1` (see `../SKILL.md`), enforce a hard
|
|
76
79
|
timeout, capture only codex's final message, and block codex from writing git via a shim — see
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.23.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",
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
# Task: {{TASK_NAME}}
|
|
2
|
-
Story: {{STORY_ID}} of {{EPIC_ID}}
|
|
3
|
-
|
|
4
|
-
## Slice
|
|
5
2
|
Plan: {{PLAN_PATH}}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
|
|
4
|
+
## Row
|
|
5
|
+
{{ROW_LINE}}
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
- {{FILE_PATH}}
|
|
11
9
|
|
|
12
10
|
## Reads
|
|
11
|
+
- {{SCENARIO_LINE}}
|
|
13
12
|
- {{PLAN_PATH}}
|
|
14
13
|
|
|
15
|
-
##
|
|
16
|
-
- {{
|
|
17
|
-
|
|
18
|
-
## Negative cases
|
|
19
|
-
- {{NEGATIVE_CASE}} :: {{NEGATIVE_OUTCOME}}
|
|
14
|
+
## Run
|
|
15
|
+
- {{RUN_COMMAND}}
|
|
20
16
|
|
|
21
|
-
##
|
|
22
|
-
- {{
|
|
23
|
-
- {{MODULE_PATH}} :: {{MODULE_MAX_LINES}}
|
|
17
|
+
## Do not run
|
|
18
|
+
- {{FORBIDDEN_COMMAND}}
|
|
@@ -8,11 +8,11 @@ The opt-in **subagent-vehicle writer** — the family's second `.claude/` writer
|
|
|
8
8
|
**Every READ-ONLY 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:
|
|
9
9
|
|
|
10
10
|
- **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.
|
|
11
|
-
- **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
|
+
- **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 of a plan or a diff — an epic's rendered brief is reviewed by the lens alone, whatever `epic.review` resolves to — and it is advisory like every other review.
|
|
12
12
|
|
|
13
13
|
Writing code, running gates, and user-facing copy never move to these four vehicles.
|
|
14
14
|
|
|
15
|
-
**The fifth vehicle, `executor`, is the ONE full-tool one** (model and effort from `docs/ai/vehicles.json` — `opus` / `high` by default — and every tool, a shell included). It is the instrument behind the **Subagent** recipe, dispatched ONLY for a **bounded, file-disjoint slice** the orchestrator verifies afterwards by running its suites: a slice of execution (`plan-execution.execute`), a plan/contract authoring brief (`plan-authoring.author`), an authoring-round fold (`plan-authoring.fold`), a bounded chore (`routine.carrier`), an epic brief (`epic.author`),
|
|
15
|
+
**The fifth vehicle, `executor`, is the ONE full-tool one** (model and effort from `docs/ai/vehicles.json` — `opus` / `high` by default — and every tool, a shell included). It is the instrument behind the **Subagent** recipe, dispatched ONLY for a **bounded, file-disjoint slice** the orchestrator verifies afterwards by running its suites: a slice of execution (`plan-execution.execute`), a plan/contract authoring brief (`plan-authoring.author`), an authoring-round fold (`plan-authoring.fold`), a bounded chore (`routine.carrier`), an epic brief (`epic.author`), or one prompt the orchestrator wrote from one ledger row, run inside its Files (`task.execute`); `task.author` dispatches no slice, since the orchestrator writes each row's prompt itself. It **never commits** (no git write at all), is **never a review backend**, is **never a bridge substitute**, and is **never dispatched for read-only work** — a sweep, an inventory or a review rides a read-only vehicle instead.
|
|
16
16
|
|
|
17
17
|
**Its readiness is the vehicle FILE.** `surveyExecutorVehicle` answers exactly one of four states: **`placed`** (bytes equal to the body derived from `docs/ai/vehicles.json` at `.claude/agents/executor.md`), **`customized`** (a readable regular file whose frontmatter names `executor` and whose tools are not read-only), **`unusable`** (a symlink, a non-regular or unreadable file, one failing that check, or an unreadable `docs/ai/vehicles.json` — with the reason), **`missing`**. `placed` and `customized` are dispatchable; on `unusable` or `missing` a `subagent` slot **degrades to Solo** with a reason naming this mode's apply command (and `docs/ai/vehicles.json` when that file is unreadable). `/agent-workflow-kit status` shows the state in its `agents` block and the deployment advisor raises it when a configured slot names `subagent` and the vehicle is `unusable` or `missing` — that item is **`executor-vehicle`** (attention-class: a configured declaration that is broken), a DIFFERENT capability from this mode's placement offer (`agents`), which converges the moment nothing is left to place and therefore can never observe a present-but-unusable vehicle. It is a claim about the FILE, never about the host: a Claude Code lane, like this mode itself.
|
|
18
18
|
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- opt-in-capability: none — an inspection surface that configures nothing -->
|
|
4
4
|
|
|
5
|
-
Read-only **activity-procedures advisor**. Answers *"what are the steps of this named activity, and which recipe applies at each slot here?"* It composes the orchestration recipes (`${CLAUDE_SKILL_DIR}/references/modes/recipes.md`) into **named activities** with **typed recipe slots**. It **never writes, never commits, never runs a subscription CLI** — the deterministic resolution lives in the kit; the orchestrator runs the resolved recipe via the bridge skills or the executor vehicle and **owns any commit when the activity has a commit boundary** (every other carrier never commits). Not every activity commits: `plan-authoring` ends at approval and produces no commit (plans are ephemeral, never committed); `plan-execution` commits
|
|
5
|
+
Read-only **activity-procedures advisor**. Answers *"what are the steps of this named activity, and which recipe applies at each slot here?"* It composes the orchestration recipes (`${CLAUDE_SKILL_DIR}/references/modes/recipes.md`) into **named activities** with **typed recipe slots**. It **never writes, never commits, never runs a subscription CLI** — the deterministic resolution lives in the kit; the orchestrator runs the resolved recipe via the bridge skills or the executor vehicle and **owns any commit when the activity has a commit boundary** (every other carrier never commits). Not every activity commits: `plan-authoring` ends at approval and produces no commit (plans are ephemeral, never committed); `plan-execution` commits the story once, after its diff review.
|
|
6
6
|
|
|
7
7
|
The six activities (canon in the **installed engine**, `references/procedures.md`; the registry is `tools/carriers.mjs`):
|
|
8
8
|
|
|
9
|
-
- **`plan-authoring`** (slots: `author`, `fold`, `review`) — research → draft (the resolved `author` carrier drafts: Solo writes it, Subagent drafts from the orchestrator's brief) → self-review with the readers sweep first → **review {recipe}** →
|
|
10
|
-
- **`plan-execution`** (slots: `execute`, `review`) — per ledger row: resolve the recipe → if Delegated, dispatch execution first; if Subagent, dispatch file-disjoint slices to the executor vehicle and verify each returned slice → implement → self-review
|
|
9
|
+
- **`plan-authoring`** (slots: `author`, `fold`, `review`) — research → draft (the resolved `author` carrier drafts: Solo writes it, Subagent drafts from the orchestrator's brief) → self-review with the readers sweep first → **review {recipe}** of the spec, every contract the story revises and the plan's ledger in the same rounds, at most two → one fold ask per member per round, then fold through the resolved `fold` carrier, a fold of the last round re-read by its raiser → present the plan folded with the spec for approval; enforce the mandatory Cleanup.
|
|
10
|
+
- **`plan-execution`** (slots: `execute`, `review`) — per ledger row: resolve the recipe → if Delegated, dispatch execution first; if Subagent, dispatch file-disjoint slices to the executor vehicle and verify each returned slice → implement → self-review; then once, on the story's staged diff with every committable output (the project-declared stages' included) staged first: **review {recipe}** with the fold ask, the raiser's re-read and the re-check of a moved staged tree → gates → the one commit; Phase: Cleanup runs after it and changes nothing the review judged.
|
|
11
11
|
- **`routine`** (slots: `carrier`, `parallel`) — name the chore and its file-disjoint slices → resolve → carry it (Solo, or Subagent: a read-only slice rides a placed read-only vehicle, a write-capable one rides the executor; `parallel` on → concurrently) → verify every returned slice; the commit boundary is unchanged.
|
|
12
12
|
- **`feedback-triage`** (slot: `review`) — record → verify every claim by code on the stamped HEAD → `feedback-record-cli --check` → **review {recipe}** over the record, the excerpts as agy's `--facts` payload → `--rows` renders the queue rows and the ratchet line → fold only a false statement in shipped copy.
|
|
13
|
-
- **`epic`** (slots: `author`, `review`) — brief → draft by the resolved `author` carrier → `epic-shape-cli --check` → **review {recipe}
|
|
14
|
-
- **`task`** (slots: `author`, `execute`) —
|
|
13
|
+
- **`epic`** (slots: `author`, `review`) — brief → draft by the resolved `author` carrier → `epic-shape-cli --check` → **review {recipe}**: one review-lens read over the rendered review brief, whatever `epic.review` resolves to (no bridge wrapper, driving contract or grounding pre-step renders under it) → fold through the fold ask and `--fold`, at most two rounds → land.
|
|
14
|
+
- **`task`** (slots: `author`, `execute`) — the orchestrator writes one prompt from one ledger row, whatever `author` resolves to → with the story's changes staged, the resolved `execute` carrier runs it inside its Files (Delegated: `codex-exec --nonce <n> <prompt file>`) → the read after the hand-out restores writes outside the Files from the index and the copied excluded paths from their copy, then the row's tests → return into the story's row, a fold resuming the run's session from its exec receipt; no commit boundary or review of its own.
|
|
15
15
|
|
|
16
16
|
Value sets per slot type: `review` accepts `solo | reviewed | council`; `execute` (including `task.author` and `task.execute`) accepts `solo | delegated | subagent`; a carrier slot (`plan-authoring.author`, `plan-authoring.fold`, `routine.carrier`, `epic.author`) accepts `solo | subagent`; `parallel` is a **switch**, `on | off`, resolved outside the recipe lattice. Defaults when the config is silent: `review` → Reviewed if a review-capable backend is ready, else Solo; `author`, `fold`, `execute`, `carrier` → Solo (a placed executor never flips a default); `parallel` → on. The orchestrator owns every commit; every other carrier — a bridge or a subagent — never commits.
|
|
17
17
|
|
|
@@ -21,9 +21,9 @@ Run **`node ${CLAUDE_SKILL_DIR}/tools/procedures.mjs <activity> [--override <slo
|
|
|
21
21
|
2. **Default resolution (config silent):** `review` → Reviewed if any review-capable backend is `ready`, else Solo (never Council by default); `execute`, `author`, `fold`, `carrier` → Solo (Delegated and Subagent are opt-in; a placed executor never flips a default); `parallel` → on. **Degradation:** a config/computed default degrades **gracefully with a stated reason** (Council → Reviewed → Solo; Delegated → Solo; Subagent → Solo when the executor vehicle is missing or unusable, the reason naming the apply command; a switch never degrades); a per-run **`--override <slot>=<value>`** that can't be satisfied degrades **loudly** (a flagged warning, so you tell the user) — but is **still exit 0** (a valid request that gracefully degraded).
|
|
22
22
|
3. **Exit codes:** `0` success; `2` usage (unknown `<activity>` / bad `--override` — a bare `--override <recipe>`, an unknown slot, a value outside the slot's list, or a duplicate slot); `1` config error (malformed / schema-invalid / unreadable `orchestration.json`) **or** engine error (the installed engine is absent / invalid / **too old** to ship `references/procedures.md` — upgrade it with `npx @sabaiway/agent-workflow-engine@latest init`). A `1`/`2` failure is loud (`path: reason`), never a silent fallback. **Lagging-kit honesty:** a kit predating the `"flow"` key that reads a config carrying one fails this config load loudly (exit `1`, reddening its full gate matrix); the `set-flow` arming path now enforces the declared `kitMinVersion` floor with a null-guarded comparison (an unparseable version never passes), while tolerate-first ordering remains the only protection for readers older than the `"flow"` key itself — no in-config floor can reach a kit that dies on the unknown key.
|
|
23
23
|
|
|
24
|
-
**The dispatch form (a slot resolved to `subagent`).** A carrier that is only NAMED is a name, not an instruction, so after such a slot's resolved-recipe line the advisor prints — indented under it, in place of the one-line vehicle mention — the form the dispatch must take, in five parts: (1) what a SLICE is for THIS slot — for `plan-execution.execute`, a set of file-disjoint ledger rows, wording copied verbatim where wording is a red line; for `plan-authoring.author`, a brief naming the goal, the governing spec(s) and the ledger constraints, whose returned draft the orchestrator reviews as its own; for `plan-authoring.fold`, the round's findings with their dispositions, whose edits the orchestrator follows with the self-consistency read; for `routine.carrier`, a bounded mechanical task, where a read-only chore (a sweep, gate triage) rides its placed read-only vehicle — or is carried solo with a stated reason when that vehicle is absent — a write-capable one (a regeneration, a fixture build) rides the executor, and the changelog stays the orchestrator's; for `epic.author`, a brief naming the intent, the value, the non-goals and the stories in order, from which the subagent drafts the epic file and the orchestrator runs the shape check on the draft as its own; for `task.author`,
|
|
24
|
+
**The dispatch form (a slot resolved to `subagent`).** A carrier that is only NAMED is a name, not an instruction, so after such a slot's resolved-recipe line the advisor prints — indented under it, in place of the one-line vehicle mention — the form the dispatch must take, in five parts: (1) what a SLICE is for THIS slot — for `plan-execution.execute`, a set of file-disjoint ledger rows, wording copied verbatim where wording is a red line; for `plan-authoring.author`, a brief naming the goal, the governing spec(s) and the ledger constraints, whose returned draft the orchestrator reviews as its own; for `plan-authoring.fold`, the round's findings with their dispositions, whose edits the orchestrator follows with the self-consistency read; for `routine.carrier`, a bounded mechanical task, where a read-only chore (a sweep, gate triage) rides its placed read-only vehicle — or is carried solo with a stated reason when that vehicle is absent — a write-capable one (a regeneration, a fixture build) rides the executor, and the changelog stays the orchestrator's; for `epic.author`, a brief naming the intent, the value, the non-goals and the stories in order, from which the subagent drafts the epic file and the orchestrator runs the shape check on the draft as its own; for `task.author`, no slice the flow dispatches, since the orchestrator writes each row's prompt itself whatever the slot resolves to — that sentence renders alone, with none of the parts below; for `task.execute`, one prompt the orchestrator wrote from one ledger row, run inside the Files the prompt names with the changed paths reported and the row's tests run by the orchestrator; (2) the vehicle and its surveyed state — `.claude/agents/executor.md` (`placed` / `customized` / `unusable` / `missing`, from the same survey `status` and the advisor read) — dispatched **in the background**; (3) that the orchestrator **verifies every returned slice by running its suites itself**; (4) that the subagent is **never told to commit, never a review backend, never a bridge substitute**; (5) the **honest limit** — a Claude Code lane: on a host that cannot dispatch the vehicle, follow this form BY HAND and say so, never report it as a subagent dispatch. The wording is the kit's own (`tools/carriers.mjs`) and is printed, never re-worded. The dispatch-form branch is unchanged for a slot resolved to `solo` or `delegated`.
|
|
25
25
|
|
|
26
|
-
**Fold lane (an execute slot the activity reads resolved to `delegated`).** `procedures plan-execution` reads `plan-execution.execute` and `task.execute`, `procedures task` reads `task.execute` alone, and `task.author` never counts; a per-run `--override` moves only the rendered activity's own slot. The lane renders once, immediately after the rendered activity's `execute` slot block (after its driving contract when that slot itself resolves to `delegated`), as
|
|
26
|
+
**Fold lane (an execute slot the activity reads resolved to `delegated`).** `procedures plan-execution` reads `plan-execution.execute` and `task.execute`, `procedures task` reads `task.execute` alone, and `task.author` never counts; a per-run `--override` moves only the rendered activity's own slot. The lane renders once, immediately after the rendered activity's `execute` slot block (after its driving contract when that slot itself resolves to `delegated`), as one line: a fold of code a bridge wrote resumes that run's session, `codex-exec --resume <session id> --nonce <n> <prompt file>`, the session id read from the `sessionId` of the run's exec receipt, with a new prompt and a fresh nonce. No delegation ledger and no HEAD are read, so the line is the same whatever a ledger holds. The block is advisory and never changes the exit code; `foldLane` carries the identical line under `--json`, and is `[]` for every other activity and whenever no slot the activity reads resolves to `delegated`.
|
|
27
27
|
|
|
28
28
|
**`routine`'s `parallel` switch renders against the EFFECTIVE carrier.** The flag always renders with its source (`parallel: on` / `parallel: off`); the concurrency claim — *file-disjoint slices dispatch concurrently* — renders **only** while the resolved `carrier` is `subagent`. Under a `solo` carrier the line states its own inertness instead, `(no effect while the carrier is solo)`: a switch never degrades, so the flag keeps the value you set and the render simply stops promising a concurrency nothing can perform. That makes four cells (`on`/`off` x `subagent`/`solo`), and only the `subagent`+`on` cell claims concurrency.
|
|
29
29
|
|
|
@@ -10,7 +10,7 @@ The five recipes (defined over each bridge's `provides` roles — `codex`: execu
|
|
|
10
10
|
- **Reviewed** — you execute; **one** backend reviews the result (advisory). Prefers `codex` when both are ready (`agy` carries a standing health caveat).
|
|
11
11
|
- **Council** — **both** backends review independently; you synthesize the two opinions.
|
|
12
12
|
- **Delegated** — you hand a **bounded** execution sub-task to a backend (`codex exec`), then review the returned diff and commit.
|
|
13
|
-
- **Subagent** — a **full-tool frontier subagent**, dispatched from the placed executor vehicle (`.claude/agents/executor.md`), carries a **bounded, file-disjoint** slice — of execution, of plan/contract authoring, of an authoring fold, of routine work, of an epic brief (`epic.author`), of
|
|
13
|
+
- **Subagent** — a **full-tool frontier subagent**, dispatched from the placed executor vehicle (`.claude/agents/executor.md`), carries a **bounded, file-disjoint** slice — of execution, of plan/contract authoring, of an authoring fold, of routine work, of an epic brief (`epic.author`), or of one prompt the orchestrator wrote from one ledger row, run inside its Files (`task.execute`; `task.author` dispatches no slice: the orchestrator writes each row's prompt itself); you verify the returned slice by running its suites yourself and you make the commit. It is **never a review backend**, **never a bridge substitute**, and is **never told to commit**; it **degrades to Solo** when the vehicle is `missing` or `unusable`, with the reason. Readiness here is the **vehicle FILE, never the host** — a **Claude Code lane**, like the `agents` writer itself: on a host that cannot dispatch the vehicle, the rendered dispatch form is an instruction you follow by hand and report as such, never as a subagent dispatch.
|
|
14
14
|
|
|
15
15
|
1. Run **`node ${CLAUDE_SKILL_DIR}/tools/recipes.mjs`** (the read-only planner; `--json` for the structured form). It runs the backend detector, lists the five recipes, and prints — for the current environment — a **per-recipe dispatch plan that degrades with a stated reason** when a carrier isn't `ready` (Council → Reviewed → Solo; Delegated → Solo; Subagent → Solo when the executor vehicle is `missing`/`unusable`), plus advisory **quota/health notes** (each bridge runs the host posture the user set — a weaker model is the user's bridge setting, never a per-call choice; Council spends two backends' quota; `agy` may stall on substantive prompts — Issue-001, prefer `codex`).
|
|
16
16
|
2. **Offer the choice** via **`AskUserQuestion` where your agent supports it** (`AskUserQuestion` in Claude Code) — one option per recipe, the `recommendRecipe` choice listed **first** — otherwise in prose. Then print `planRecipe(chosen, detection)` (the per-stage dispatch + degradation reasons + quota/health notes) so the user sees exactly what running it entails.
|
|
@@ -44,7 +44,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/recommendations.mjs --cwd <project-root> [--
|
|
|
44
44
|
|
|
45
45
|
**Sandbox lanes (what to DO with the `sandbox-lane` recipe, per host class):**
|
|
46
46
|
|
|
47
|
-
- **Settings-native sandbox** (the harness reads the `.claude/settings.json` sandbox keys):
|
|
47
|
+
- **Settings-native sandbox** (the harness reads the `.claude/settings.json` sandbox keys): where the harness honours the `--bridge-tier` wiring's `excludedCommands`, the wrappers run OUTSIDE the sandbox and never consult `allowedDomains`/`allowWrite` — nothing beyond the tier. A harness may not honour that entry (observed 2026-10-06: Claude Code 2.1.291 ran an agent's plain `codex-review` inside its sandbox with the project entry present, and that run still reached `chatgpt.com`, which only `allowedDomains` admitted); there a recipe host outside `allowedDomains` is refused by the harness proxy or held for a network prompt (a refusal reads `Tunnel connection failed: 403` or `CONNECT tunnel failed, response 403` in the run), and the lane is the hand-apply `allowedDomains` shape in (2) below, filled from this recipe — the agent does not add it, the kit never writes these keys. Record the ack (the ack-write one-liner) once the lane is confirmed.
|
|
48
48
|
- **Harness-managed sandbox** (an IDE/session-imposed sandbox that ignores the settings keys) — a NARROWEST-SCOPE ladder: (1) prefer wrapper/command-SCOPED sandbox rules where the harness offers them (only the review wrappers gain the egress + state-dir writes); (2) a SESSION-scoped allowance (the manifest hosts + the resolved state dirs for the whole session) is an INFORMED WIDENING — it carries the same blast-radius class the settings security keys were rejected for (every sandboxed command in the session gains that egress and those writable credential dirs), acceptable only as the maintainer's deliberate choice for a review-heavy session. Its **paste-ready hand-apply shape** (the kit never writes these keys) is, in `.claude/settings.json`, `"sandbox": { "network": { "allowedDomains": ["<egress host>", …] }, "filesystem": { "allowWrite": ["<writable state dir>", …] } }` — fill `<egress host>` / `<writable state dir>` from THIS recipe (the wired bridges' `capability.json` `networkHosts` ∪ resolved `writableDirs`); one consent then lands durably in config. (3) Else the per-run consented bypass. Record the ack (the ack-write one-liner) once a lane is chosen — choosing the bypass, or consciously declining, also counts.
|
|
49
49
|
- Either way the recipe is **observed-minimal, honestly incomplete** — a blocked host names itself at run time; extend by hand and re-ack (the fingerprint moves with the recipe, not with your extensions).
|
|
50
50
|
|
|
@@ -15,7 +15,7 @@ mapping their wording onto them is your job, not a shipped phrase list.
|
|
|
15
15
|
| "both review" | `--set <activity>.review=council` | **disambiguate**: which activity? If both, pass `--set plan-authoring.review=council --set plan-execution.review=council`. |
|
|
16
16
|
| "one reviewer" | `--set <activity>.review=reviewed` | per the named activity, else ask |
|
|
17
17
|
| "delegate execution" | `--set plan-execution.execute=delegated` | execution only (a **bridge** runs the change) |
|
|
18
|
-
| "let a subagent do it" | `--set <activity>.<slot>=subagent` | **disambiguate**: which work? `--set plan-execution.execute=subagent` (a slice of the change), `--set plan-authoring.author=subagent` (a plan/contract brief), `--set plan-authoring.fold=subagent` (the round's findings and dispositions), `--set routine.carrier=subagent` (a bounded chore), `--set epic.author=subagent` (an epic brief), `--set task.
|
|
18
|
+
| "let a subagent do it" | `--set <activity>.<slot>=subagent` | **disambiguate**: which work? `--set plan-execution.execute=subagent` (a slice of the change), `--set plan-authoring.author=subagent` (a plan/contract brief), `--set plan-authoring.fold=subagent` (the round's findings and dispositions), `--set routine.carrier=subagent` (a bounded chore), `--set epic.author=subagent` (an epic brief), `--set task.execute=subagent` (one row's prompt run inside its Files; `task.author` dispatches no slice) |
|
|
19
19
|
| "one slice at a time" | `--set routine.parallel=off` | `routine` only — `parallel` is a **flag**, not a recipe |
|
|
20
20
|
| "revert / do it myself" | `--unset <activity>.<slot>` | the named slot → its computed default |
|
|
21
21
|
|
package/references/modes/tier.md
CHANGED
|
@@ -8,7 +8,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/tier-guide.mjs --dir <project> --json`.
|
|
|
8
8
|
|
|
9
9
|
Render the returned envelope compactly in the user's conversational language. Never paste the JSON. Keep every path and every command verbatim, each command on its own line so it runs as printed; translate only the prose around them.
|
|
10
10
|
|
|
11
|
-
Keep this order: the tier text (what each level is, the
|
|
11
|
+
Keep this order: the tier text (what each level is, the four story sessions, the two templates, the glossary of their keys, the Recommendations pointer); then every rendered state with its reader, file, cause and next command; then per epic its stage, any placeholder left and the accepted check; then each story in hand with its stage, any placeholder left and its ordered actions; then the epic's own ordered actions (for example the check, the close, or the Cleanup a landed story left over). The first action printed is the next step. Several epics or stories each render; never pick one silently.
|
|
12
12
|
|
|
13
13
|
Exit codes:
|
|
14
14
|
|
|
@@ -35,7 +35,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/velocity-profile.mjs [--dry-run | --apply] [
|
|
|
35
35
|
- `node ${CLAUDE_SKILL_DIR}/tools/release-scan.mjs <path>` (wildcard)
|
|
36
36
|
- `node ${CLAUDE_SKILL_DIR}/tools/repo-search.mjs --pattern <literal> --path <p>` (wildcard — the LITERAL search lane; for a pattern carrying a shell-significant byte use `--pattern-file <p>` instead, and for a TARGET PATH carrying one use `--paths-file <p>` — either way the bytes never enter the command string. one of the TWO tier tools that carry hook residual coverage — see the honesty note below)
|
|
37
37
|
- `node ${CLAUDE_SKILL_DIR}/tools/path-inventory.mjs --path <p>` (wildcard — the read-only inventory lane: exists / type / size / `wc -l` lines / one-level listing / small-file contents for N paths in ONE call, so small path questions never need a composed shell. `--paths-file <p>` is its out-of-band target lane; hook residual coverage as with repo-search)
|
|
38
|
-
- `node ${CLAUDE_SKILL_DIR}/tools/review-rounds-cli.mjs --artifact <plan>` (wildcard — the read-only round table over the review receipts,
|
|
38
|
+
- `node ${CLAUDE_SKILL_DIR}/tools/review-rounds-cli.mjs --artifact <plan>` (wildcard — the read-only round table over the review receipts, which `procedures feedback-triage` renders over its record; the path argument is resolved and compared, never opened as a pattern, so it rides the settings-level posture like the rest)
|
|
39
39
|
- `node ${CLAUDE_SKILL_DIR}/tools/control-bytes.mjs --check` (wildcard — the read-only control-byte gate over the work tree: read-only git queries and descriptor-bound reads, no write API; the agent's own hand run before the declared gate runs it)
|
|
40
40
|
- `node ${CLAUDE_SKILL_DIR}/tools/robustness-brief.mjs --plan <plan>` (wildcard — the read-only executor-brief generator over a plan and the kit's shipped literal list; no write API and no process spawn)
|
|
41
41
|
- `node ${CLAUDE_SKILL_DIR}/tools/run-gates.mjs --cwd ${PROJECT_ROOT}` — **EXACT byte-string only**, and honestly **project-exec, not read-only**: it runs YOUR declared `docs/ai/gates.json` commands — the same trust boundary the opt-in hook grants byte-exact per-cmd. A wildcard would be BROADER than that boundary (`--cwd <dir>` executes another project's declared gates), so the bare cwd-defaulting form, any other `--cwd`, `--only`, and **`--final`** forms all still prompt (`--final` WRITES the final-run receipt into the core-evidence store — a recording run is never auto-approved).
|
|
@@ -50,7 +50,7 @@ Honesty notes: tier entries get **NO PreToolUse-hook residual coverage — with
|
|
|
50
50
|
|
|
51
51
|
**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.
|
|
52
52
|
|
|
53
|
-
**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
|
|
53
|
+
**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 a settings-native sandbox that honours the exclusion and simply prompts again elsewhere (fail-safe, never a silent widening). A harness that reads the settings sandbox keys may still drop this exclusion (observed 2026-10-06: Claude Code 2.1.291 ran an agent's plain `codex-review` inside its sandbox with the project entry present); its lane is the settings-native one in `${CLAUDE_SKILL_DIR}/references/modes/recommendations.md`. 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):
|
|
54
54
|
|
|
55
55
|
- `Bash(codex-review code:*)` — the code-mode prefix, args wildcard; plus `codex-review` in `sandbox.excludedCommands`
|
|
56
56
|
- `Bash(agy-review code:*)` — the code-mode prefix, args wildcard; plus `agy-review` in `sandbox.excludedCommands`
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"has": "The kit-owned checker gates are declared." },
|
|
27
27
|
{ "id": "session-close-rules",
|
|
28
28
|
"story": "S5",
|
|
29
|
-
"has": "The rules your project reads state the session-close value section and
|
|
29
|
+
"has": "The rules your project reads state the session-close value section and the four-session story flow." },
|
|
30
30
|
{ "id": "named-queue-row-seed",
|
|
31
31
|
"story": "S5",
|
|
32
32
|
"has": "A new work queue is seeded with the named row." },
|
|
@@ -21,7 +21,8 @@ revision: 1
|
|
|
21
21
|
## Contract
|
|
22
22
|
|
|
23
23
|
What the feature accepts and returns, stated as invariants a test can pin. A `draft` spec is authored
|
|
24
|
-
|
|
24
|
+
in the session that writes the plan landing the feature and exists at its spec review; approval of
|
|
25
|
+
that plan confirms the
|
|
25
26
|
contract (no separate stop). It becomes `live` on the plan's landing row; `revision` increments by one
|
|
26
27
|
per live contract change; `retired` on the removal row — never backwards.
|
|
27
28
|
|
|
@@ -38,8 +38,8 @@ Before claiming "done":
|
|
|
38
38
|
1. Run all quality gates (lint + type-check + tests) — all green.
|
|
39
39
|
2. Update docs: `current_state.md` (feature ready), `changelog.md` (entry), `handover.md` (**REPLACE** the last-session block — session delta, never append; older deltas live in `changelog.md` → `history/`), `pages/<page>.md` (matches implementation), the governing spec (its revision lands with the code: `draft` -> `live` on the landing row). Only bump "Last Updated" when content actually changed.
|
|
40
40
|
3. Run the docs cap-validator + index-freshness gate (the pre-commit hook also enforces it where installed). On failure: trim the offending file, or run the changelog rotation if the offender is `changelog.md`.
|
|
41
|
-
4.
|
|
42
|
-
5.
|
|
41
|
+
4. **Ask before committing** (§4): report lint / type-check / test counts + docs status, then wait for explicit approval. DO NOT auto-commit.
|
|
42
|
+
5. If the work executed a plan file — after the commit, run that plan's final **Phase: Cleanup** (see the planning skill / §5); it changes nothing the review judged. Without it the plan is not done.
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
@@ -78,15 +78,15 @@ Apply this as part of §2 before any user-facing summary:
|
|
|
78
78
|
### 2.6. Planning, review & process-fidelity invariants
|
|
79
79
|
Apply these when authoring a plan, reviewing, folding a finding, or editing code — the layer read **before any code change**. (Full canon: the project's planning / workflow-methodology + orchestration canon. This section is rendered from that canon and refreshed on upgrade; a custom edit is preserved verbatim, but flagged.)
|
|
80
80
|
- **Fold by code, not prose.** Before folding a code-touching finding into a plan or change, read the cited `file:line` and cite it — a prose fold drifts from the code and seeds the next bug.
|
|
81
|
-
- **Finding scope (plan-execution) — name the invariant BEFORE the edit.** During EXECUTION only — a plan under authoring
|
|
81
|
+
- **Finding scope (plan-execution) — name the invariant BEFORE the edit.** During EXECUTION only — a spec and its plan under authoring have no shipped behaviour to call a live defect in, so the spec review carries none of this. Every finding names the invariant its fix would enforce, and where that invariant already lives decides the disposition: already an acceptance criterion of the phase → **fold here**; it would have to be ADDED → ship the **narrow fix** for the found site (red first, then green) and queue ONLY the generalization — a deferral row carries the invariant, the origin `file:line`, the narrow fix, its proof and a residual exposure declared NOT live; no correct narrow fix → **blocking**: the phase does not close, and it is **never queued**. Two bars declared before each round: a finding counts only if it changes a **WRITE/REMOVE decision** or is a false statement in shipped text; a repeat finding in one subarea **routes to SUBTRACTION**, not a fourth patch.
|
|
82
82
|
- **Right altitude.** Pin intent + invariants + acceptance criteria (named tests); leave fine code-mechanics to Execute, where prose cannot diverge from reality.
|
|
83
|
-
- **Spec-first.** A plan names its GOVERNING spec(s) — zero, one or many, one per touched spec-covered slice (the feature spec under `docs/ai/specs/`; page-only coverage governs as an ADOPTION SHIM, with Out of scope + Revision stated inline in the plan). A ZERO names the adoption state it relies on — `not adopted` (no store) or `adopting` (a store with no live contract), either with a recorded decline, or `nothing spec-covered touched` (a store with live contracts) — a bare zero is never a licence; the store's own state is what `status` and the upgrade advisor report. Each cited spec's Out of scope bounds that slice's work and the plan's non-goals restate it per slice — no global union; a cross-spec conflict is resolved by a spec revision BEFORE approval, never by silent precedence. A NEW feature's draft spec exists AT
|
|
83
|
+
- **Spec-first.** A plan names its GOVERNING spec(s) — zero, one or many, one per touched spec-covered slice (the feature spec under `docs/ai/specs/`; page-only coverage governs as an ADOPTION SHIM, with Out of scope + Revision stated inline in the plan). A ZERO names the adoption state it relies on — `not adopted` (no store) or `adopting` (a store with no live contract), either with a recorded decline, or `nothing spec-covered touched` (a store with live contracts) — a bare zero is never a licence; the store's own state is what `status` and the upgrade advisor report. Each cited spec's Out of scope bounds that slice's work and the plan's non-goals restate it per slice — no global union; a cross-spec conflict is resolved by a spec revision BEFORE approval, never by silent precedence. A NEW feature's draft spec exists AT the spec review (a `create` row); a change to a governed contract rides the plan as its proposed revision (a `modify` row); approval confirms plan and contract atomically, and the revision lands with the code. Scenario bindings are per scenario: a new scenario is `unbound` until its test lands in the same plan, and a status never regresses for an extension.
|
|
84
84
|
- **No code-mechanics in the plan.** A ledger row carries its path and anchor, and Verification carries the exact commands (the plan-shape canon) — checked syntax: the plan's own Verification runs them against an explicit expected outcome or gate; the only other syntax a plan may carry is a literal fixture/schema fragment a named test copies or validates. Un-run, logic-bearing syntax — control-flow, a regex, a glob, a grammar, an algorithm body, a mini-DSL — never lives in plan prose, however plausible or shell-verified it looks: a fold or draft that wants one is the trigger to write the test instead.
|
|
85
85
|
- **Test-as-spec.** Fold a code-touching finding into a red→green TEST, not a prose paragraph — the gate is the only deterministic checker; a paragraph cannot self-check.
|
|
86
86
|
- **Characterize-first.** Before editing UNCOVERED code, pin its current behavior in a green test, then edit — any unintended change goes red. Never edit what has no checker; first give it one. Keep edits atomic/reversible; prefer SUBTRACTIVE folds.
|
|
87
87
|
- **State table BEFORE the guard — enumerate by PROOF, never by exclusion.** The subtraction rule above fires on a repeat finding, which is a LATE signal: by then the review has paid for each miss. The EARLY signal is structural — a decision whose input has **several independent state dimensions** (is it tracked? do the bytes still match the source? does the neighbouring file exist?). Write the table first, admit the write with **ONE conjunction of proven facts**, and funnel every other cell into a single refusal; the table is then the table-driven test. An exclusion list (`if (bad1) return; if (bad2) return;`) fails **OPEN** on the first state nobody enumerated — and "unreadable" is a state, distinct from "absent". A reviewer cannot save you here: it judges the patch in front of it and can only name the NEXT missing state, one round at a time.
|
|
88
|
-
- **Fold minimally — prose has no checker.**
|
|
89
|
-
- **Heavy review at the diff.**
|
|
88
|
+
- **Fold minimally — prose has no checker.** A spec under the spec review, like the ephemeral plan beside it, is prose with no executable checker; fold **minimally, in ONE place** and run a **self-consistency** read across the spec before every re-review — a fold that drifts several prose spots is what turns a 2-round review into churn.
|
|
89
|
+
- **Heavy review at the diff.** The spec review settles the contract and reads the plan's ledger in the same rounds (≤2 rounds, stop at the pre-existing→fold-induced crossover); the plan has no rounds of its own and is checked by its shape gate, that reading and the approval; the exhaustive review runs against the staged diff of real compiling code + the full suite, where a regression fails a gate immediately. **Backend divergence** (one backend grounded-ships while another keeps revising mechanics) IS that crossover — resolve at altitude, don't exhaust the strictest backend; route an all-mechanics/CI or prose-only artifact to a **thin plan + diff-review**.
|
|
90
90
|
- **Convergence bar.** A review loop is CLEAN only when one round returns **0 blockers + 0 majors** from EVERY backend the recipe names (nits + a ship verdict is the stop). Folding ≠ convergence — re-review after folding.
|
|
91
91
|
- **Per-round emission.** Every review round emits **{round N · finding-origin tally · per-backend verdict}** so the crossover is a computed, visible signal, not a remembered rule.
|
|
92
92
|
- **Recipe fidelity.** Council runs every backend the recipe names, **every round**; silently dropping a ready backend for quota/convenience is a forbidden downgrade — an unavailable backend is a LOUD, stated degrade, never a quiet drop.
|
|
@@ -94,7 +94,7 @@ Apply these when authoring a plan, reviewing, folding a finding, or editing code
|
|
|
94
94
|
- **Cost lanes.** Route every step to the **cheapest adequate executor** — L0 deterministic script (the batched gate matrix over `gates.json`, the rotation `--check`s) · L1 cheap subagent (extraction/drafting only; the orchestrator verifies) · L2 subscription bridge · L3 frontier judgment. A step with **no named guardrail does not move down** a lane, and the **red lines never move down** (council review models · real code · ADR/handover/changelog-entry wording · persuasive copy · go/no-go · the approval asks). Own-error repair: salvage recorded state first (L0/L1, batched), never frontier re-derivation. **Prompt economy:** read-only fan-out (research/sweeps/extraction) runs ONLY on restricted-tool vehicles — a full-tool subagent for read-only work is a forbidden lane downgrade (invisible prompt-flood + blast radius), and a subagent is never told to shell out for facts obtainable read-only; the orchestrator's own shell form is ONE plain pipeline per call (a `;`/`&&` chain or env-prefixed invocation never matches a prefix allow rule); a fan-out launcher that gates per call yields to the agent-spawn lane — capability-gated: without restricted-tool vehicles (generic full-tool spawning does not count), read-only research stays in the orchestrator's own context, never a vehicle mandate a host cannot satisfy. Judgment, code, synthesis stay at the frontier lane (a task that genuinely runs/writes keeps a full-tool subagent); honest limit: no deterministic gate classifies a dispatch — canon at the point of use + placed vehicles + the retro loop. **Writer economy:** a stage's repeated WRITER commands batch — evidence declarations ride consecutive plain invocations of ONE allow-listed tool, other stage writers combine via one launcher per stage; never an unbatched writer scatter (each gated write is its own prompt).
|
|
95
95
|
|
|
96
96
|
### 2.7. Story sessions
|
|
97
|
-
A story — one row of an epic's ledger, carried by one plan — runs as
|
|
97
|
+
A story — one row of an epic's ledger, carried by one plan — runs as four sessions, each step in them giving one checked result: **spec and plan** (every contract the story creates or revises and the plan's ledger beside them, checked by the spec gate, the plan-shape gate and one review of at most two rounds that reads both, then the plan's approval), **tests** (only tests, each new one failing for the reason its scenario or acceptance bullet states, or on the absence of a name the plan adds, imported inside the test; no code and no prototype), **code** (code until the tests and the pre-review gates pass; a wrong test is changed only back to what its scenario states), and **diff review, release and record** (every committable output, tracked records included, staged first, the review of the staged diff in at most two rounds, the final gates and the release where the story ships one, then the plan's Phase: Cleanup). Tests and code never share a session. A storyless plan runs the same four. **Exception — a split:** moving code and its existing cases into modules, with no new logic and no new case, is one session: a short spec (the Module list), the split, the diff review, the release, Cleanup. A bridge executor gets a task only when it writes new tests or code, from one prompt of the orchestrator; a file the orchestrator already wrote is laid down by the orchestrator, never relayed through a bridge.
|
|
98
98
|
|
|
99
99
|
---
|
|
100
100
|
|
package/tools/carriers.mjs
CHANGED
|
@@ -112,8 +112,8 @@ export const SLICE_BY_SLOT = {
|
|
|
112
112
|
'plan-execution.execute': 'a slice is a set of file-disjoint ledger rows; wording is copied verbatim where wording is a red line',
|
|
113
113
|
'routine.carrier': "a slice is a bounded mechanical task; a read-only one (a sweep, gate triage) rides its placed read-only vehicle, or is carried solo with a stated reason when that vehicle is absent; a write-capable one (a regeneration, a fixture build) rides the executor; the changelog stays the orchestrator's",
|
|
114
114
|
'epic.author': 'a slice is a brief naming the intent, the value, the non-goals and the stories in order; the subagent drafts the epic file from it, and the orchestrator runs the shape check on the draft as its own',
|
|
115
|
-
'task.author':
|
|
116
|
-
'task.execute':
|
|
115
|
+
'task.author': "no slice the flow dispatches: the orchestrator writes each row's prompt itself, whatever this slot resolves to",
|
|
116
|
+
'task.execute': "a slice is one prompt the orchestrator wrote from one ledger row; the subagent runs it inside the Files the prompt names and reports the paths it changed, and the orchestrator runs the row's tests itself",
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
export const VEHICLE_STATE_TOKEN = '<state>';
|
|
@@ -139,12 +139,14 @@ export const SUBAGENT_SLOT_TYPES = Object.entries(SLOT_RECIPES)
|
|
|
139
139
|
|
|
140
140
|
// dispatchForm({ activity, slot, state }) → the lines a `subagent`-resolved slot renders: the
|
|
141
141
|
// slot's slice sentence, then the four shared lines with the surveyed vehicle state filled in.
|
|
142
|
-
// A slot
|
|
142
|
+
// A slot type that cannot hold `subagent` (review) and an unknown activity render nothing; a slot
|
|
143
|
+
// whose slice the flow never dispatches renders its sentence alone.
|
|
144
|
+
const UNDISPATCHED_SLOTS = new Set(['task.author']);
|
|
143
145
|
export const dispatchForm = ({ activity, slot, state } = {}) => {
|
|
144
146
|
const slice = SLICE_BY_SLOT[`${activity}.${slot}`];
|
|
145
147
|
const slotType = ACTIVITIES[activity]?.slots?.[slot];
|
|
146
148
|
if (!slice || !SUBAGENT_SLOT_TYPES.includes(slotType)) return [];
|
|
147
|
-
return [slice, ...DISPATCH_LINES.map((line) => line.replace(VEHICLE_STATE_TOKEN, state ?? MISSING))];
|
|
149
|
+
return UNDISPATCHED_SLOTS.has(`${activity}.${slot}`) ? [slice] : [slice, ...DISPATCH_LINES.map((line) => line.replace(VEHICLE_STATE_TOKEN, state ?? MISSING))];
|
|
148
150
|
};
|
|
149
151
|
|
|
150
152
|
// parallelLine({ value, carrier }) → the `routine` switch line. The concurrency claim is TRUE only
|
package/tools/cheap-agents.mjs
CHANGED
|
@@ -94,7 +94,7 @@ const EXIT_USAGE = 2;
|
|
|
94
94
|
// the internal-attestation evaluation consumes this sentence — a lens set claiming a configured
|
|
95
95
|
// backend's slot without a then-active down-mark REFUSES, quoting it (substitution is recorded,
|
|
96
96
|
// never silent).
|
|
97
|
-
export const FALLBACK_LENS_ADDITIONAL_ONLY = 'review-lens is an ADDITIONAL read-only review opinion, not a replacement for your
|
|
97
|
+
export const FALLBACK_LENS_ADDITIONAL_ONLY = 'review-lens is an ADDITIONAL read-only review opinion, not a replacement for your plan or diff review recipe.';
|
|
98
98
|
|
|
99
99
|
const USAGE = `usage: cheap-agents [--dry-run | --apply] [--cwd <dir>] [--help]
|
|
100
100
|
|