@sabaiway/agent-workflow-kit 1.15.2 → 1.17.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.
@@ -10,13 +10,22 @@ judgment.
10
10
 
11
11
  1. Decide the mode: `codex-exec` to *do* (edit the repo under the sandbox), `codex-review` to *judge*
12
12
  (advisory findings, no edits).
13
- 2. Run the wrapper from the **target project root** so codex auto-reads its `AGENTS.md` (the wrappers
14
- also preflight that a root `AGENTS.md` and a git work tree exist).
13
+ 2. Run the wrapper from the **target project root** so codex auto-merges its `AGENTS.md` (the wrappers
14
+ also preflight that a root `AGENTS.md` and a git work tree exist, and fail fast before spending a run).
15
15
  3. For an ad-hoc instruction, make it self-contained: codex cannot see your conversation — embed the
16
- goal, the relevant paths, the non-goals, and the expected result. The project's rules come from
17
- `AGENTS.md`.
16
+ goal, the relevant paths, the non-goals, and the expected result. The project's rules come from the
17
+ already-merged `AGENTS.md`.
18
18
  4. Let codex run; then **review its diff yourself** and re-run the project's gates.
19
- 5. **Commit yourself** — codex never commits.
19
+ 5. **Commit yourself** — codex never commits (a git-write shim enforces it; see below).
20
+
21
+ ## Quality-first: model & effort are pinned
22
+
23
+ Delegated codex work ALWAYS runs on the frontier model at max effort: `gpt-5.5` / `xhigh` are **pinned**
24
+ and a non-default `CODEX_MODEL`/`CODEX_EFFORT` is **refused** (exit 2). Do not try to "tune down" the
25
+ model or effort for a real run — the wrapper will stop you. Quota is metered in **messages** (rolling
26
+ 5h + weekly), so economy comes from removing waste (clean capture, the precomputed review diff, resume),
27
+ never from a downgrade. The only opt-out is a throwaway, effort-independent probe: `CODEX_PROBE=1`
28
+ (loud) — never use its output as real work.
20
29
 
21
30
  ## Exec vs review
22
31
 
@@ -27,34 +36,74 @@ can review the resulting diff.
27
36
  Use **`codex-review plan`** for a cold second opinion on a plan before executing it (risks, missing or
28
37
  mis-ordered steps, scope creep, missing gates).
29
38
 
30
- Use **`codex-review code`** for advisory, severity-tagged findings on uncommitted changes including
31
- when **untracked** files matter: the wrapper prompt tells codex to run `git status --short` and read
32
- the contents of `??` files, because plain `git diff` omits them.
39
+ Use **`codex-review code`** for advisory, severity-tagged findings on uncommitted changes. The wrapper
40
+ **precomputes the whole change set** repo map, `git status`, staged + unstaged diff, and the
41
+ **contents of untracked files** (binaries noted but skipped, symlinks shown as targets, other
42
+ non-regular paths skipped) — and feeds it in, so codex does not burn a run roaming the filesystem to
43
+ rediscover it. A clean tree exits 0 *before* a run is spent. An oversized payload (over
44
+ `CODEX_REVIEW_MAX_TOTAL_BYTES`, default 1.5 MB) is written to a git-dir temp file and referenced by
45
+ path — never silently truncated. Set `CODEX_REVIEW_SCHEMA=1` to get findings back as a validated JSON
46
+ object (raw-text fallback on failure).
33
47
 
34
48
  ## Usage
35
49
 
36
50
  ```bash
37
51
  codex-exec docs/plans/<slug>.md # drive a plan file
38
52
  echo "apply review fix: tighten the guard in X, keep tests green" | codex-exec -
39
- CODEX_MODEL=<slug> CODEX_EFFORT=high codex-exec <file> # tune model/effort
40
- codex-exec <file|-> -- --add-dir ../shared # passthrough codex flags after `--`
53
+ codex-exec <file|-> -- <unguarded codex flags> # passthrough AFTER `--` (policy/model/capture flags are rejected)
54
+
55
+ codex-exec --resume-last docs/plans/<slug>.md # continue the last session, no re-send
56
+ echo "now do step 2" | codex-exec --resume <id> -
41
57
 
42
58
  codex-review plan docs/plans/<slug>.md # critique a plan before executing it
43
- codex-review code # review the current working-tree diff
59
+ codex-review code # review the current working-tree diff (precomputed)
44
60
  codex-review code "focus on the reducer and its tests"
45
61
  ```
46
62
 
47
63
  `codex-exec` prepends an **orchestrator execution contract**: work in the current tree, never
48
- git-write, obey the target `AGENTS.md`, self-review the diff (incl. untracked files), run the
49
- project's declared gates (STOP if none are declared), don't commit, report blockers.
64
+ git-write, *obey* the already-merged `AGENTS.md` (Hard Constraints + declared gates), self-review the
65
+ diff (incl. untracked files), run the project's declared gates (STOP if none are declared), don't
66
+ commit, report blockers. It captures only codex's **final message** (`-o`; the JSON event stream +
67
+ reasoning are discarded to a trace) and, on a **non-resume** run, records the session id to
68
+ `${CODEX_SESSION_FILE:-./.codex-last-session}`.
50
69
 
51
- ## Prompt shapes (for ad-hoc `codex-exec -` instructions)
70
+ ## Resume iterate without re-sending context
71
+
72
+ ```bash
73
+ codex-exec --resume-last <plan-file|-> # session id read from the sidecar
74
+ codex-exec --resume <session-id> <file|-> # explicit session id
75
+ ```
76
+
77
+ Resume continues the SAME codex session, so you avoid re-sending the original context. It runs through
78
+ the wrapper, which **re-establishes every invariant** (subscription-only `*_API_KEY` scrub,
79
+ `--ignore-user-config`, the pinned `gpt-5.5`/`xhigh`) and **restates the full posture via `-c`** —
80
+ because `codex exec resume` resets the sandbox/approval/network posture and rejects `-s`/`--add-dir`/`-C`,
81
+ the wrapper passes `-c sandbox_mode=workspace-write -c approval_policy=never -c
82
+ sandbox_workspace_write.network_access=false` explicitly. A resume takes no passthrough flags and an
83
+ empty resumed instruction is rejected. Prefer resume over re-dispatching a fresh run when you are
84
+ iterating on the same task; start a fresh `codex-exec` when the task changes.
85
+
86
+ ## The commit boundary & the git-write shim
87
+
88
+ - **Repo edits** are codex's job *inside* `codex-exec`'s workspace-write sandbox — but you **review the
89
+ diff** before accepting/committing it. `codex-review` makes no edits at all (read-only sandbox).
90
+ - **Git writes** (branch/add/commit/stash/reset/checkout/tag/rewrite) are never delegated. Beyond the
91
+ prompt contract, `codex-exec` prepends a physical **git-write shim** to the codex subprocess's
92
+ `PATH`: a `git` wrapper file that passes read-only verbs through to the real git and **blocks every
93
+ write/unknown verb** (codex spawns `git` via `execve`, which bypasses shell functions, so the
94
+ boundary must be a real executable; the real git path is baked into the shim, not exposed as an env
95
+ var). `git config` is read-only too (blocked on a write flag or a `<name> <value>` set form). The
96
+ orchestrator commits after review.
97
+ - **New dependencies / network installs** are done by hand (exec has network OFF), then codex is
98
+ re-dispatched.
99
+ - **A hung run** is killed at `CODEX_HARD_TIMEOUT` (exec 3600s / review 1800s) and reported (exit
100
+ 124/137); raise it for a known-healthy slow run.
52
101
 
53
- Execution:
102
+ ## Prompt shapes (for ad-hoc `codex-exec -` instructions)
54
103
 
55
104
  ```text
56
105
  Implement the change below from the current project root.
57
- Respect root AGENTS.md, especially its Hard Constraints and declared gates.
106
+ Obey root AGENTS.md (already in your context), especially its Hard Constraints and declared gates.
58
107
  Do not run git write commands. Do not commit.
59
108
  If a dependency install, network call, missing gate set, or out-of-repo write is needed, STOP and report.
60
109
 
@@ -62,30 +111,8 @@ If a dependency install, network call, missing gate set, or out-of-repo write is
62
111
  ```
63
112
 
64
113
  The review prompt shapes are built into `codex-review` itself — you only pass `plan <file>` or
65
- `code [focus]`; the wrapper supplies the severity-tagged-findings + verdict directive.
66
-
67
- ## Re-dispatch vs. fresh run
68
-
69
- ```bash
70
- codex exec resume --last # run codex DIRECTLY — not through codex-exec
71
- ```
72
-
73
- Resume is **not** reachable through `codex-exec`: the wrapper's shape (fixed flags + a trailing `-`
74
- that reads the prompt from stdin) can't host the `resume` subcommand, and the wrapper rejects
75
- policy-affecting passthrough flags anyway. Run `codex exec resume` directly when you want to continue
76
- a session without re-sending context — but note it runs **outside** the wrapper, so it does not
77
- inherit the enforced sandbox/network/approval policy and **may not re-accept those flags**. Restate
78
- the policy in the resumed instruction, or just start a fresh `codex-exec` run when the posture must be
79
- guaranteed (see `sandbox-and-flags.md`).
80
-
81
- ## Escalation policy (edits, network, git)
82
-
83
- - **Repo edits** are codex's job *inside* `codex-exec`'s workspace-write sandbox — but you **review the
84
- diff** before accepting/committing it. `codex-review` makes no edits at all.
85
- - **New dependencies / network installs** are done by hand (exec has network OFF), then codex is
86
- re-dispatched.
87
- - **Git writes** (branch/add/commit/stash/reset/checkout/tag/rewrite) are never delegated — the
88
- orchestrator commits after review. The execution contract forbids them.
114
+ `code [focus]`; the wrapper supplies the assembled diff + the severity-tagged-findings + verdict
115
+ directive (or the JSON-schema directive when `CODEX_REVIEW_SCHEMA=1`).
89
116
 
90
117
  ## Handling output
91
118
 
@@ -1,7 +1,7 @@
1
1
  # `codex` sandbox, flags & policy (reference)
2
2
 
3
3
  The source of truth is the live binary: `codex --version`, `codex --help`, `codex exec --help`. The
4
- tables below were captured from **codex-cli 0.140.0**; if the binary disagrees, the binary wins. The
4
+ tables below were captured from **codex-cli 0.142.3**; if the binary disagrees, the binary wins. The
5
5
  wrapper commands are `codex-exec` and `codex-review`, backed by `bin/codex-exec.sh` /
6
6
  `bin/codex-review.sh`.
7
7
 
@@ -13,51 +13,140 @@ wrapper commands are `codex-exec` and `codex-review`, backed by `bin/codex-exec.
13
13
  | `workspace-write` | repo (cwd) only | OFF (we force it off) | `codex-exec` (codex edits the repo) |
14
14
  | `danger-full-access` | anywhere | yes | never used by this skill |
15
15
 
16
- `codex-exec` always passes:
16
+ **A sandbox bounds WRITES, not READS.** Even `read-only` can read any file on disk (it is what kept a
17
+ naive review roaming into `~/.claude/**` and producing multi-MB transcripts). Read-scoping is therefore
18
+ a **prompt + env** concern, not a sandbox one — see the review read-fence below. Under `read-only` codex
19
+ *structurally* cannot edit, create, delete, or git-write; it can only read and report.
17
20
 
18
- ```bash
19
- --sandbox workspace-write \
20
- -c approval_policy="never" \
21
- -c sandbox_workspace_write.network_access=false
22
- ```
21
+ ## Flags the wrappers always pass
23
22
 
24
- `codex-review` always passes:
23
+ `codex-exec`:
25
24
 
26
25
  ```bash
27
- --sandbox read-only \
28
- -c approval_policy="never"
26
+ codex exec --ignore-user-config \
27
+ --sandbox workspace-write \
28
+ -c approval_policy=never \
29
+ -c sandbox_workspace_write.network_access=false \
30
+ -c model_reasoning_effort="$CODEX_EFFORT" \
31
+ -c hide_agent_reasoning=true -c model_reasoning_summary=none \
32
+ --color never -o "$out" --json -m "$CODEX_MODEL" -
29
33
  ```
30
34
 
31
- Under `read-only`, codex *structurally* cannot edit, create, delete, or git-write it can only read
32
- and report. In v0.140.0 `read-only` also grants **no network**, so `codex-review` relies on that and
33
- passes no separate network flag — the `sandbox_workspace_write.*` config (including
35
+ `codex-review` is the same minus the write/network posture, plus `--sandbox read-only` and (optionally)
36
+ `--output-schema`. In v0.142.3 `read-only` also grants **no network**, so `codex-review` relies on that
37
+ and passes no separate network flag — the `sandbox_workspace_write.*` config (including
34
38
  `network_access`) applies **only** to `workspace-write`.
35
39
 
36
- ## Network-OFF invariant (exec)
40
+ ### Clean output capture
37
41
 
38
- `codex-exec` keeps network access OFF on purpose: **new dependencies and any network step are
39
- installed by a human**, not by codex. If a task needs a new package, codex must STOP and report it;
40
- the orchestrator installs it, then re-dispatches.
42
+ `-o`/`--output-last-message` writes ONLY codex's final message; `--json` streams the structured event
43
+ stream (incl. `thread.started`, which carries the session id) to a discarded trace; `--color never` +
44
+ `-c hide_agent_reasoning=true` + `-c model_reasoning_summary=none` strip colour and chain-of-thought.
45
+ Net effect: the wrapper prints just the final answer. **Reasoning still runs at `xhigh`** — quality is
46
+ unchanged; only the *noise* is dropped. On success `codex-exec` extracts the session id from the trace
47
+ and records it to `${CODEX_SESSION_FILE:-./.codex-last-session}` (so `--resume-last` can find it) and
48
+ echoes `session: <id>` to stderr. On a missing/empty final-message file it falls back to the trace tail
49
+ (loud, never silent).
41
50
 
42
- ## Escalation & approvals
51
+ ## Quality-first guard (pinned model & effort)
43
52
 
44
- There is **no TTY** in `codex exec`, so `approval_policy=never`: codex never pauses for an interactive
45
- approval. Any action that would need escalation (network, writes outside the repo, an ambiguous
46
- decision) is **refused and reported**, and the orchestrator handles it by hand. Codex must never run a
47
- git write command the orchestrator commits after reviewing the diff.
53
+ The wrappers default `CODEX_MODEL=gpt-5.5` and `CODEX_EFFORT=xhigh` and **refuse** (exit 2, loud) any
54
+ non-default delegated work always uses the frontier model at max effort; quality is never traded for
55
+ quota. `CODEX_PROBE=1` relaxes this for a throwaway, effort-independent probe only (echoed loudly), and
56
+ a probe still runs on the subscription, in the sandbox, with clean capture.
57
+
58
+ ## Passthrough guard (two tiers, after a literal `--`)
59
+
60
+ `codex-exec` owns the safety + quality policy, so it filters passthrough flags:
48
61
 
49
- ## Commit prohibition
62
+ - **Tier 1 — ALWAYS rejected, even under `CODEX_PROBE=1`:** anything that would defeat the policy or the
63
+ capture — `-c`/`--config`, `-s`/`--sandbox`, `--full-auto`, `--dangerously-bypass-*`, `--oss`,
64
+ `--local-provider`, `-p`/`--profile`, `-m`/`--model` (the model is pinned via `CODEX_MODEL`), and the
65
+ capture flags `-o`/`--output-last-message`/`--json`/`--color`/`--output-schema`/`--ephemeral`.
66
+ - **Tier 2 — context/discovery knobs, rejected for a real run but allowed under `CODEX_PROBE=1`:**
67
+ `--add-dir`, `-C`/`--cd`, `--skip-git-repo-check`, `--ignore-rules`, `--enable`/`--disable`.
50
68
 
51
- Delegated codex runs do not own repository history. The wrappers' contract prohibits every git write:
52
- no branch, add, commit, stash, reset, checkout, tag, or history rewrite. The orchestrator reviews the
53
- diff, runs final verification, and commits only when that is the desired next step.
69
+ Args passed WITHOUT the `--` separator are rejected (a likely mistake), never silently dropped. Need
70
+ more than the wrapper allows? Invoke `codex` directly outside the subscription/policy guarantees.
54
71
 
55
- ## `resume` caveat
72
+ Note that `--skip-git-repo-check` (tier 2) only relaxes **codex's own** git-repo check; the wrapper's
73
+ preflight still **requires a git work tree and a root `AGENTS.md`** and STOPs first if either is
74
+ missing — passing it does not let `codex-exec` run outside a repo.
75
+
76
+ ## Network-OFF invariant (exec)
56
77
 
57
- `codex exec resume` re-dispatches an existing session without re-sending context. **It may not
58
- re-accept `--sandbox` / `approval_policy` / network flags** do not assume the original posture
59
- carries over. Restate the policy in the resumed instruction, or start a fresh `codex-exec` run when a
60
- guaranteed sandbox/network posture matters.
78
+ `codex-exec` keeps network access OFF on purpose: **new dependencies and any network step are installed
79
+ by a human**, not by codex. If a task needs a new package, codex must STOP and report it; the
80
+ orchestrator installs it, then re-dispatches.
81
+
82
+ ## Escalation & approvals
83
+
84
+ There is **no TTY** in `codex exec`, so `approval_policy=never`: codex never pauses for an interactive
85
+ approval. Any action that would need escalation (network, writes outside the repo, an ambiguous
86
+ decision) is **refused and reported**, and the orchestrator handles it by hand.
87
+
88
+ ## Commit prohibition — enforced by a git-write shim
89
+
90
+ Delegated codex runs do not own repository history. Beyond the prompt contract (no branch/add/commit/
91
+ stash/reset/checkout/tag/rewrite), `codex-exec` **physically enforces** the boundary: it writes a `git`
92
+ shim into a temp dir and prepends that dir to the codex subprocess's `PATH`. codex spawns `git` via
93
+ `execve`, which bypasses exported shell functions, so the boundary must be a real executable file. The
94
+ shim:
95
+
96
+ - passes a **read-only allowlist** through to the real git (`status`, `diff`, `show`, `log`, `ls-files`,
97
+ `rev-parse`, `cat-file`, `for-each-ref`, …);
98
+ - treats `git config` as **read-only** — blocked on any write/action flag (`--add`/`--unset`/…) or a
99
+ `<name> <value>` set form (≥2 positionals);
100
+ - **blocks every other / unknown verb** (`add`, `commit`, `reset`, `checkout`, `merge`, `push`, `tag`,
101
+ `update-ref`, `symbolic-ref`, `reflog`, …) with exit 13;
102
+ - bakes the **real git path into the shim itself** (never exposed as an env var — that would be a
103
+ trivial bypass vector).
104
+
105
+ This is defence-in-depth beside the prompt contract; the orchestrator still reviews the diff and commits.
106
+
107
+ ## Precomputed review diff (`codex-review code`)
108
+
109
+ `code` mode does NOT make codex discover the diff. The wrapper assembles the full surface — repo file
110
+ map (`git ls-files`), `git status`, staged + unstaged diff, and the **contents** of every untracked
111
+ regular file (NUL-safe; binaries noted but skipped, symlinks shown as targets, other non-regular paths
112
+ skipped) — into a git-dir-local temp file (600 perms), then feeds it in. A **clean tree exits 0** before
113
+ a run is spent. If the assembled payload exceeds `CODEX_REVIEW_MAX_TOTAL_BYTES` (default `1500000`) it is
114
+ passed **by path** (read-fence carve-out) instead of inline — **never truncated**. `-s read-only` is
115
+ kept so codex may still read surrounding in-repo files for context.
116
+
117
+ ### Optional structured findings
118
+
119
+ `CODEX_REVIEW_SCHEMA=1` adds `--output-schema` with a flexible schema (`findings[]` of
120
+ `severity`/`location`/`issue`/`suggested_change`/optional `evidence`, plus `verdict` and free-text
121
+ `notes`). `--output-schema` *constrains* the output (a probe confirmed it does not silently emit
122
+ non-conforming text); a raw-text retry covers a rare validation/run failure. Default OFF.
123
+
124
+ ### Review read-fence (best-effort env hygiene)
125
+
126
+ `codex-review` runs under a throwaway `HOME` + `XDG_CONFIG_HOME`/`XDG_CACHE_HOME`/`XDG_DATA_HOME` with an
127
+ **absolute `CODEX_HOME`** so auth + history still resolve while codex's default config/cache/skill-scan
128
+ roots point at an empty dir (trims the roaming + skill-scan noise). This is **env hygiene, NOT a security
129
+ boundary** — absolute paths anywhere on disk remain readable under `read-only`; the real read-scoping is
130
+ the prompt fence ("do not read outside the working tree, except the precomputed-diff temp file").
131
+
132
+ ## `resume` — resets posture, restated via `-c`
133
+
134
+ `codex exec resume` re-dispatches an existing session without re-sending context. It **rejects the
135
+ posture flags** `-s`/`--add-dir`/`-C` and **resets** the sandbox/approval/network posture (it DOES
136
+ accept `-c`/`-m`/`--last`/`-o`/`--json` on 0.142.3 — the wrapper just doesn't need `-o`/`--json` here).
137
+ The `codex-exec --resume`/`--resume-last` entrypoint handles the reset: it restates the entire policy
138
+ via `-c` (`sandbox_mode=workspace-write`, `approval_policy=never`,
139
+ `sandbox_workspace_write.network_access=false`) plus the pinned `-m`/effort and `--ignore-user-config`,
140
+ reads the session id from the sidecar (or an argument), and captures codex's final message straight
141
+ from stdout (no `-o` needed). Only a *raw* `codex exec resume` outside the wrapper loses the posture.
142
+
143
+ ## Hard timeout
144
+
145
+ A backgrounded/hung run survives otherwise, so both wrappers wrap codex in `timeout`/`gtimeout`
146
+ (`--kill-after=15s`): `CODEX_HARD_TIMEOUT` defaults to **3600s (exec)** / **1800s (review)**, sized for a
147
+ slow `xhigh` run. Exit 124/137 ⇒ "exceeded the hard cap" (raise the cap or narrow the task). If neither
148
+ `timeout` nor `gtimeout` is on `PATH`, the wrapper **warns loudly and runs uncapped** — never a silent
149
+ no-op.
61
150
 
62
151
  ## Subscription / config invariant
63
152
 
@@ -70,27 +159,41 @@ Both wrappers, before invoking codex:
70
159
  - preflight `codex login status` and refuse unless it contains `Logged in using ChatGPT`;
71
160
  - preflight a git work tree and a root `AGENTS.md`, failing fast (before a run is spent) if missing.
72
161
 
73
- ## Verified commands & flags (v0.140.0)
162
+ ## Native `codex review` is out of scope (why)
163
+
164
+ `codex review` is the CLI's built-in review subcommand, but this skill does **not** ship it. Its flag
165
+ surface (0.142.3) is `-c`/`--strict-config`/`--enable`/`--disable`/`--uncommitted`/`--base`/`--commit`/
166
+ `--title` — crucially it **rejects** `--ignore-user-config`, `-s`, `-m`, `-o`, `--json`,
167
+ `--output-schema`. Without `--ignore-user-config` a
168
+ personal `~/.codex/config.toml` loads (a live run forced `sandbox: workspace-write`), which breaks the
169
+ subscription/config-isolation invariant, and it has no clean-capture flag. `codex-review` runs `codex
170
+ exec` over the precomputed diff instead, keeping every invariant intact.
171
+
172
+ ## Verified commands & flags (v0.142.3)
74
173
 
75
174
  | Command / flag | Verified behaviour |
76
175
  |---|---|
77
176
  | `codex exec` | non-interactive run from stdin / a prompt arg (headless, no TTY) |
78
- | `codex exec resume` | resume an exec session (see the resume caveat) |
79
- | `codex exec review` | review path reachable under `exec` |
80
- | `codex review` | repository review path; supports reviewing uncommitted changes |
177
+ | `codex exec resume --last` / `resume <id>` | resume a session; **resets posture & rejects the `-s`/`--add-dir`/`-C` posture flags** (accepts `-c`/`-m`/`--last`/`-o`/`--json`) — restate posture via `-c` |
178
+ | `codex review` | built-in review subcommand **NOT used** (rejects `--ignore-user-config`; see above) |
81
179
  | `codex login` / `codex login status` | subscription auth flow + status check |
82
- | `codex sandbox` / `codex apply` / `codex resume` | sandbox / apply / resume helper subcommands |
83
- | `-c key=value` | override a config value (dotted path, TOML-parsed) — how policy is set deterministically |
180
+ | `-c key=value` | override a config value (dotted, TOML-parsed) how policy is set deterministically |
84
181
  | `--sandbox <mode>` | `read-only` \| `workspace-write` \| `danger-full-access` (this skill uses the first two) |
85
182
  | `-c approval_policy=never` | never pause for interactive approval (required: exec has no TTY) |
86
183
  | `-c sandbox_workspace_write.network_access=false` | network OFF under workspace-write (the exec invariant) |
87
- | `-m <model>` | model to use (wrapper default `gpt-5.5` via `CODEX_MODEL`) |
88
- | `-c model_reasoning_effort=<effort>` | reasoning effort (wrapper default `xhigh` via `CODEX_EFFORT`) |
184
+ | `-c hide_agent_reasoning=true` / `-c model_reasoning_summary=none` | drop chain-of-thought from output (reasoning still runs) |
185
+ | `-o, --output-last-message <f>` | write ONLY the final message (clean capture) |
186
+ | `--json` | structured event stream (`thread.started` ⇒ session id) |
187
+ | `--output-schema <f>` | constrain output to a JSON schema (`CODEX_REVIEW_SCHEMA=1`) |
188
+ | `-m <model>` | model (wrapper default `gpt-5.5`, pinned via `CODEX_MODEL`) |
189
+ | `-c model_reasoning_effort=<effort>` | reasoning effort (wrapper default `xhigh`, pinned via `CODEX_EFFORT`) |
89
190
  | `--ignore-user-config` | do NOT load `$CODEX_HOME/config.toml`; auth still uses `CODEX_HOME` |
90
- | `--add-dir <dir>` | extra writable dir alongside the workspace |
91
- | `-C, --cd <dir>` | use `<dir>` as the working root |
92
- | `--skip-git-repo-check` | allow running outside a git repo (exec normally requires one) |
93
- | `--ephemeral` | do not persist session files |
191
+ | `--color never` | disable ANSI colour in output |
192
+
193
+ ## Environment variables
194
+
195
+ `CODEX_MODEL`, `CODEX_EFFORT`, `CODEX_HARD_TIMEOUT`, `CODEX_SESSION_FILE`, `CODEX_REVIEW_MAX_TOTAL_BYTES`,
196
+ `CODEX_REVIEW_SCHEMA`, `CODEX_PROBE` — see the knob table in [`../SKILL.md`](../SKILL.md#environment-knobs).
94
197
 
95
198
  ## Troubleshooting
96
199
 
@@ -101,5 +204,7 @@ Both wrappers, before invoking codex:
101
204
  `codex login status` → `Logged in using ChatGPT`.
102
205
  - **`must run inside a git working tree` / `no root AGENTS.md`** (wrapper preflight): run the wrapper
103
206
  from the target project root.
207
+ - **`exceeded the hard cap`** (exit 124/137): the run hit `CODEX_HARD_TIMEOUT` — raise it for a
208
+ known-healthy slow run, or narrow the task, then re-dispatch.
104
209
  - **codex wants to install a dependency**: it can't (network OFF in exec) — install it by hand, then
105
210
  re-dispatch.
@@ -11,7 +11,7 @@ confirm it is on `PATH`:
11
11
 
12
12
  ```bash
13
13
  npm install -g @openai/codex # or: brew install codex (use the current official channel)
14
- codex --version # this skill was verified with codex-cli 0.140.0 or newer
14
+ codex --version # this skill was verified with codex-cli 0.142.3 or newer
15
15
  ```
16
16
 
17
17
  The binary is **`codex`**. If `codex --version` works but the wrappers can't find it, fix your
@@ -70,7 +70,11 @@ if it reports a missing git work tree or root `AGENTS.md`, run it from a project
70
70
 
71
71
  - The wrappers are **subscription-only** by design and will not use api-key billing.
72
72
  - `codex-exec` runs a **workspace-write** sandbox with **network OFF**; `codex-review` runs
73
- **read-only**. See [`../references/sandbox-and-flags.md`](../references/sandbox-and-flags.md).
73
+ **read-only**. They also pin the frontier model/effort (refusing a downgrade), enforce a hard
74
+ timeout, capture only codex's final message, and block codex from writing git via a shim — see
75
+ [`../references/sandbox-and-flags.md`](../references/sandbox-and-flags.md) and the knob table in
76
+ [`../SKILL.md`](../SKILL.md#environment-knobs). No setup is needed to enable these — they are on by
77
+ default.
74
78
  - `codex exec` requires a git repository, and the wrappers also require a root `AGENTS.md`. The
75
79
  orchestrator commits, not codex. Re-run `codex login` only when the cached login expires or the
76
80
  account changes.
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "1.15.2",
6
+ "version": "1.17.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "1.15.2",
3
+ "version": "1.17.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,206 @@
1
+ #!/usr/bin/env node
2
+ // commands.mjs — the kit's canonical command catalog + the pure invocation router behind the
3
+ // `/agent-workflow-kit help` index and the safe unknown-invocation routing rule.
4
+ //
5
+ // Until now the modes existed only as `### Mode:` headers in SKILL.md, never enumerated for the user:
6
+ // there was no discoverable command surface and no executable answer to "what did the user actually
7
+ // invoke?". This module is the SINGLE source of truth for both — one frozen catalog (one entry per
8
+ // mode, grouped + tagged read-only/writer/guarded with a plain-language one-liner) that the `help`
9
+ // mode renders and the report footers point at, plus `routeInvocation(token)` that maps a raw
10
+ // subcommand token to its mode.
11
+ //
12
+ // Safety invariant (pinned by the tests): `bootstrap` is a writer and the BARE/EMPTY invocation maps
13
+ // to it — that is the ONE acknowledged exception, itself guarded downstream by the existing
14
+ // "docs/ai/ exists → ask upgrade-vs-bootstrap" check (SKILL.md Mode: bootstrap). The invariant is
15
+ // therefore: NO unrecognized/garbage token ever maps to a writer/guarded mode — every such token
16
+ // routes to `help`, which is read-only.
17
+ //
18
+ // Source of truth = the COMMANDS table below; a drift-guard test (commands.test.mjs) pins its keys to
19
+ // the `### Mode:` headers in SKILL.md, so the catalog cannot silently drift from the documented modes.
20
+ // Pure, dependency-free, Node >= 18. No side effects on import (the isDirectRun idiom).
21
+
22
+ import { pathToFileURL } from 'node:url';
23
+
24
+ const SKILL_NAME = 'agent-workflow-kit';
25
+ const BARE_INVOCATION = `/${SKILL_NAME}`;
26
+ const invocationOf = (token) => `${BARE_INVOCATION}${token ? ` ${token}` : ''}`;
27
+
28
+ // ── kinds ────────────────────────────────────────────────────────────────────────
29
+ // read-only — never writes, never commits, never runs a subscription CLI.
30
+ // writer — writes files (a project deployment or a settings/skill placement).
31
+ // guarded — a destructive teardown gated behind a mandatory dry-run-first + explicit consent.
32
+ // `writer` and `guarded` are the "acts on the system" kinds; only an explicit known token may reach
33
+ // one (plus the bare bootstrap exception). Garbage routes to `help` (read-only) — see routeInvocation.
34
+ export const READ_ONLY = 'read-only';
35
+ export const WRITER = 'writer';
36
+ export const GUARDED = 'guarded';
37
+ const KINDS = new Set([READ_ONLY, WRITER, GUARDED]);
38
+
39
+ // ── groups (fixed render order) ────────────────────────────────────────────────────
40
+ export const GROUP_ORDER = Object.freeze(['Inspect', 'Configure', 'Orchestrate', 'Lifecycle']);
41
+
42
+ // ── the canonical catalog ──────────────────────────────────────────────────────────
43
+ // One entry per `### Mode:` in SKILL.md. `key` is the mode (and, for every non-bootstrap mode, the
44
+ // routable subcommand token — bootstrap is the bare invocation, so it has no token). `oneLine` is
45
+ // plain-language: NO internal terms (no reconcile/fence/stamp/manifest/anchor) a third-party user
46
+ // hasn't read SKILL.md for. The drift-guard test pins these keys to the SKILL.md headers.
47
+ const CATALOG = [
48
+ {
49
+ key: 'bootstrap',
50
+ invocation: BARE_INVOCATION,
51
+ group: 'Lifecycle',
52
+ kind: WRITER,
53
+ oneLine: 'Deploy the memory & workflow system into a new or empty project (asks visibility, language, and attribution first).',
54
+ },
55
+ {
56
+ key: 'upgrade',
57
+ invocation: invocationOf('upgrade'),
58
+ group: 'Lifecycle',
59
+ kind: WRITER,
60
+ oneLine: 'Bring an existing deployment up to the current version — your authored notes are preserved.',
61
+ },
62
+ {
63
+ key: 'uninstall',
64
+ invocation: invocationOf('uninstall'),
65
+ group: 'Lifecycle',
66
+ kind: GUARDED,
67
+ oneLine: 'Remove only what setup placed; it never deletes your notes and always previews before changing anything.',
68
+ },
69
+ {
70
+ key: 'status',
71
+ invocation: invocationOf('status'),
72
+ group: 'Inspect',
73
+ kind: READ_ONLY,
74
+ oneLine: 'Show what is installed and at what version, your settings and backends, and what is deployed in this project.',
75
+ },
76
+ {
77
+ key: 'backends',
78
+ invocation: invocationOf('backends'),
79
+ group: 'Inspect',
80
+ kind: READ_ONLY,
81
+ oneLine: 'Check which optional review/execute backends (codex, agy) are set up versus missing, and the next step.',
82
+ },
83
+ {
84
+ key: 'help',
85
+ invocation: invocationOf('help'),
86
+ group: 'Inspect',
87
+ kind: READ_ONLY,
88
+ oneLine: 'List every command, grouped, marking each as read-only or as one that makes changes.',
89
+ },
90
+ {
91
+ key: 'setup',
92
+ invocation: invocationOf('setup'),
93
+ group: 'Configure',
94
+ kind: WRITER,
95
+ oneLine: 'Set up an optional backend — place its helper and link its commands onto your PATH (opt-in; preview first).',
96
+ },
97
+ {
98
+ key: 'velocity',
99
+ invocation: invocationOf('velocity'),
100
+ group: 'Configure',
101
+ kind: WRITER,
102
+ oneLine: 'Seed a read-only command allowlist so routine read-only commands stop prompting (Claude Code; opt-in; preview first).',
103
+ },
104
+ {
105
+ key: 'recipes',
106
+ invocation: invocationOf('recipes'),
107
+ group: 'Orchestrate',
108
+ kind: READ_ONLY,
109
+ oneLine: 'See the orchestration recipes (Solo / Reviewed / Council / Delegated) and which one fits this environment.',
110
+ },
111
+ {
112
+ key: 'procedures',
113
+ invocation: invocationOf('procedures'),
114
+ group: 'Orchestrate',
115
+ kind: READ_ONLY,
116
+ oneLine: 'Show a named activity’s steps and which recipe applies at each stage here.',
117
+ },
118
+ ];
119
+
120
+ // Deep-freeze: freeze the array AND every entry, so the catalog is genuinely immutable at runtime
121
+ // (Object.freeze on the array alone leaves the entry objects writable).
122
+ export const COMMANDS = Object.freeze(CATALOG.map((c) => Object.freeze(c)));
123
+
124
+ // The mode every garbage/unrecognized token routes to. Read-only by contract (see routeInvocation).
125
+ export const UNKNOWN_INVOCATION_MODE = 'help';
126
+ // The mode the bare/empty invocation maps to — the one writer reachable without an explicit token,
127
+ // guarded downstream by the docs/ai upgrade-vs-bootstrap check.
128
+ export const BARE_INVOCATION_MODE = 'bootstrap';
129
+
130
+ const byKey = new Map(COMMANDS.map((c) => [c.key, c]));
131
+ // Routable subcommand tokens = every mode except bootstrap (whose invocation is the bare default).
132
+ const ROUTABLE_TOKENS = new Set(COMMANDS.filter((c) => c.key !== BARE_INVOCATION_MODE).map((c) => c.key));
133
+
134
+ export const commandFor = (key) => byKey.get(key) ?? null;
135
+ export const kindOf = (key) => byKey.get(key)?.kind ?? null;
136
+
137
+ // ── the pure router ────────────────────────────────────────────────────────────────
138
+ // routeInvocation(token) → a mode key. `token` is the subcommand the user typed — either the raw word
139
+ // (`upgrade`) OR the full slash form (`/agent-workflow-kit upgrade`); the first word is significant
140
+ // and trailing args are ignored. Precise semantics:
141
+ // undefined / null / '' / whitespace-only / the exact bare invocation → 'bootstrap'
142
+ // a known first token (upgrade/status/setup/backends/recipes/procedures/velocity/uninstall/help)
143
+ // → that mode
144
+ // anything else (unrecognized / ambiguous) → 'help' (read-only — NEVER a writer/guarded mode)
145
+ export const routeInvocation = (token) => {
146
+ if (token == null) return BARE_INVOCATION_MODE;
147
+ const trimmed = String(token).trim();
148
+ if (trimmed === '' || trimmed === BARE_INVOCATION) return BARE_INVOCATION_MODE;
149
+ // Accept either the raw subcommand token OR the full slash invocation the user types — strip a
150
+ // leading `/agent-workflow-kit ` prefix so `/agent-workflow-kit upgrade` routes like `upgrade`.
151
+ const rest = trimmed.startsWith(`${BARE_INVOCATION} `)
152
+ ? trimmed.slice(BARE_INVOCATION.length).trim()
153
+ : trimmed;
154
+ if (rest === '') return BARE_INVOCATION_MODE;
155
+ const first = rest.split(/\s+/)[0];
156
+ return ROUTABLE_TOKENS.has(first) ? first : UNKNOWN_INVOCATION_MODE;
157
+ };
158
+
159
+ // ── render ──────────────────────────────────────────────────────────────────────────
160
+
161
+ const KIND_TAG = { [READ_ONLY]: '[read-only]', [WRITER]: '[writer] ', [GUARDED]: '[guarded] ' };
162
+ const pad = (s, n) => (s.length >= n ? s : s + ' '.repeat(n - s.length));
163
+
164
+ // formatHelp() → the grouped, kind-tagged human index. Deterministic; groups in GROUP_ORDER, modes in
165
+ // catalog order within each group. The header states the index itself is read-only.
166
+ export const formatHelp = () => {
167
+ const invocWidth = Math.max(...COMMANDS.map((c) => c.invocation.length));
168
+ const lines = [
169
+ `${SKILL_NAME} — command index (this list is read-only)`,
170
+ '',
171
+ 'Each command is tagged read-only · writer (makes changes) · guarded (destructive, previews first).',
172
+ ];
173
+ for (const group of GROUP_ORDER) {
174
+ const inGroup = COMMANDS.filter((c) => c.group === group);
175
+ if (!inGroup.length) continue;
176
+ lines.push('', group);
177
+ for (const c of inGroup) {
178
+ lines.push(` ${pad(c.invocation, invocWidth)} ${KIND_TAG[c.kind] ?? c.kind} ${c.oneLine}`);
179
+ }
180
+ }
181
+ return lines.join('\n');
182
+ };
183
+
184
+ // The machine form behind `--json`: the flat catalog (machines group by `group` themselves) plus the
185
+ // two routing anchors, so a consumer can reproduce routeInvocation without re-deriving the rules.
186
+ export const buildJson = () => ({
187
+ skill: SKILL_NAME,
188
+ groupOrder: [...GROUP_ORDER],
189
+ unknownInvocationMode: UNKNOWN_INVOCATION_MODE,
190
+ bareInvocationMode: BARE_INVOCATION_MODE,
191
+ commands: COMMANDS.map(({ key, invocation, group, kind, oneLine }) => ({ key, invocation, group, kind, oneLine })),
192
+ });
193
+
194
+ // ── CLI ──────────────────────────────────────────────────────────────────────────────
195
+ const main = (argv) => {
196
+ if (argv.includes('--json')) {
197
+ console.log(JSON.stringify(buildJson(), null, 2));
198
+ return;
199
+ }
200
+ console.log(formatHelp());
201
+ };
202
+
203
+ const isDirectRun = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
204
+ if (isDirectRun) main(process.argv.slice(2));
205
+
206
+ export { KINDS, SKILL_NAME, BARE_INVOCATION };