From cff65f7229a7a0149d53adb05c484c34edaea302 Mon Sep 17 00:00:00 2001 From: garrytan Date: Mon, 19 Oct 2026 19:06:05 +0000 Subject: [PATCH] feat(config): plan_mode_preamble key wires --plan-mode=off into setup and every installed render gstack-config plan_mode_preamble (on|off, default on) makes ./setup pass --plan-mode=off to every gen:skill-docs render, gbrain-refresh and the gstack-relink router render. The default Claude install, which otherwise serves the committed SKILL.md files, gets a plain render with the key off; the activation record notes plan_mode=off so switching back on removes the render, including on the gbrain=unknown keep branch. With the key on or unset every path and record is byte-for-byte unchanged. Fixes #3168. Finishes #3213 by @xingzihai. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 13 +++ README.md | 2 + bin/gstack-config | 27 ++++- bin/gstack-relink | 12 ++- bin/gstack-render-claude.sh | 30 ++++-- setup | 37 ++++--- test/plan-mode-off-generation.test.ts | 83 +++++++++++++++ test/plan-mode-preamble-config.test.ts | 74 ++++++++++++++ test/plan-mode-preamble-render.test.ts | 134 +++++++++++++++++++++++++ test/plan-mode-preamble-setup.test.ts | 54 ++++++++++ 10 files changed, 433 insertions(+), 33 deletions(-) create mode 100644 test/plan-mode-off-generation.test.ts create mode 100644 test/plan-mode-preamble-config.test.ts create mode 100644 test/plan-mode-preamble-render.test.ts create mode 100644 test/plan-mode-preamble-setup.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b30aaaf..8c94e80dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [Unreleased] + +**`gstack-config set plan_mode_preamble off` leaves the plan-mode preamble out of every installed skill, for people who never use plan mode.** The "Plan Mode Safe Operations" and "Skill Invocation During Plan Mode" sections add about 1.6 KB to each of 50 Claude skills. With the key off, the next `./setup` renders every host's skills with `gen-skill-docs --plan-mode=off`, and the default Claude install serves that render instead of the committed files. The default is on, and with it on every render and the committed SKILL.md files are byte-for-byte unchanged. + +### Added +- **`gen-skill-docs --plan-mode=off`** drops the two sections at generation time. Commands marked "PLAN MODE EXCEPTION — ALWAYS RUN" keep their marker. Hosts whose capabilities declare no plan mode already render the sections empty, so in practice the flag matters for Claude, Copilot and OpenCode. Fixes #3168. From #3213 by @xingzihai, finished with the config wiring. +- **The `plan_mode_preamble` config key** (`on` | `off`, default `on`). It is a closed domain like `explain_level`: an unknown value warns and stores `on`. Setting it outside `./setup` says it applies on the next setup run and prints the `./setup --refresh-registered` command that applies it now. +- **Every installed render carries the choice:** all 16 `gen:skill-docs` call sites in `setup`, the Claude render helper, `gstack-config gbrain-refresh`, and the router that `gstack-relink` re-renders in place (as it already does for `disabled_skills`). +- **The default Claude install gets a render when the key is off.** `gstack_claude_render_action` returns `plain` whatever gbrain detection says, and the activation record (`~/.gstack/render/claude.overlay`) gains `plan_mode=off`. Turning the key back on removes that render on the next setup, including when the gbrain detector fails, which otherwise keeps a render. Records written with the key on are unchanged. + +### Changed +- **Gate integrity:** new tests `test/plan-mode-off-build.test.ts` (from #3213, unchanged), `test/plan-mode-off-generation.test.ts`, `test/plan-mode-preamble-config.test.ts`, `test/plan-mode-preamble-render.test.ts` and `test/plan-mode-preamble-setup.test.ts`. No existing test was edited, and no threshold, trial count, case kind or judge changed. + ## [1.91.149.0] - 2026-10-19 **Paid eval cases can now run on the Codex host, and the Monday census runs two arms: Claude Opus 5.5 and Codex gpt-6.1-sol.** `EVALS_HOST=codex` runs the 52 adapter-only gate cases through a full Codex runtime per case. On its first pilot gpt-6.1-sol passed 48 of 52 with no retries, at $4.63 for the 52 cases, against $28.93 for the same cases on Fable (0.16×). Claude-only cases are skipped on Codex with a recorded reason and never count as failed. GSTA-49 TM2. diff --git a/README.md b/README.md index 18c21f8d7..97031c8a9 100644 --- a/README.md +++ b/README.md @@ -796,6 +796,8 @@ types into that element; bare `browse type ` types into whatever has focus **Don't use some skills?** `gstack-config set disabled_skills make-pdf,pair-agent` stops registering them on every host, so their descriptions stop loading into each session. Claude Code updates right away; other hosts on their next `./setup --host ` or `/gstack-upgrade`. Their files stay installed, so a skill that calls a disabled one still works (you get a warning). Typos are rejected with the closest skill name, `gstack-upgrade` can't be disabled, and `gstack-config set disabled_skills ""` re-enables everything. +**Never use plan mode?** `gstack-config set plan_mode_preamble off` leaves the "Plan Mode Safe Operations" and "Skill Invocation During Plan Mode" sections (about 1.6 KB per skill) out of every installed skill on the next `./setup` run; the command prints the exact `./setup --refresh-registered` line that applies it. Claude Code then serves a render under `~/.gstack/render/claude` instead of the committed files. Commands marked "PLAN MODE EXCEPTION — ALWAYS RUN" keep their marker. `gstack-config set plan_mode_preamble on` (the default) and another `./setup` bring the sections back. It matters for Claude Code, Copilot and OpenCode: hosts without plan mode (Codex and others) never carry these sections. + **Want namespaced commands?** `cd ~/.claude/skills/gstack && ./setup --prefix` — switches from `/qa` to `/gstack-qa`. Useful if you run other skill packs alongside gstack. **Codex says "Skipped loading skill(s) due to invalid SKILL.md"?** Your Codex skill descriptions are stale. `${CODEX_HOME:-~/.codex}/skills/gstack` is a runtime directory, not the checkout: `./setup --status` shows the Codex row's source checkout. Fix: `cd && git pull && ./setup --host codex` — for a repo-local install, run it from inside the project. diff --git a/bin/gstack-config b/bin/gstack-config index 8e33aeb9a..163b1b4dd 100755 --- a/bin/gstack-config +++ b/bin/gstack-config @@ -94,6 +94,13 @@ CONFIG_HEADER='# gstack configuration — edit freely, changes take effect on ne # # (for power users who know the terms) # # Unknown values default to "default" with a warning. # # See docs/designs/PLAN_TUNING_V1.md for rationale. +# plan_mode_preamble: on # on = every skill carries the plan-mode preamble +# # off = rendered skills omit the "Plan Mode Safe +# # Operations" and "Skill Invocation During +# # Plan Mode" sections (~1.8 KB each), for +# # users who never enter plan mode +# # Applies on the next ./setup run. Unknown values +# # default to "on" with a warning. # # ─── Artifacts sync (renamed from gbrain_sync_mode in v1.27.0.0) ───── # artifacts_sync_mode: off # off | artifacts-only | full @@ -279,6 +286,7 @@ lookup_default() { update_check) echo "true" ;; skill_prefix) echo "false" ;; explain_level) echo "default" ;; + plan_mode_preamble) echo "on" ;; # on | off — off drops the plan-mode preamble on the next ./setup (#3168) codex_reviews) echo "enabled" ;; design_detector) echo "auto" ;; # auto | off — impeccable engine pre-pass in the design skills design_detector_install_prompted) echo "false" ;; # true once the user answered the one-time engine install offer with "never ask again" @@ -734,6 +742,10 @@ $_gstack_legacy_root" echo "Warning: explain_level '$VALUE' not recognized. Valid values: default, terse. Using default." >&2 VALUE="default" fi + if [ "$KEY" = "plan_mode_preamble" ] && [ "$VALUE" != "on" ] && [ "$VALUE" != "off" ]; then + echo "Warning: plan_mode_preamble '$VALUE' not recognized. Valid values: on, off. Using on." >&2 + VALUE="on" + fi if [ "$KEY" = "artifacts_sync_mode" ] && [ "$VALUE" != "off" ] && [ "$VALUE" != "artifacts-only" ] && [ "$VALUE" != "full" ]; then echo "Warning: artifacts_sync_mode '$VALUE' not recognized. Valid values: off, artifacts-only, full. Using off." >&2 VALUE="off" @@ -985,6 +997,11 @@ $_gstack_legacy_root" gstack_install_registry_rows | awk -F '\t' '$1 != "claude" { print " apply to " $1 " (" $4 "): cd " $6 " && ./setup --host " $1 }' ) fi fi + # Installed skills are rendered by ./setup, so the preamble choice lands + # on its next run (every registered host). + if [ "$KEY" = "plan_mode_preamble" ] && [ -z "${GSTACK_SETUP_RUNNING:-}" ]; then + printf 'gstack-config: plan_mode_preamble=%s applies on the next ./setup run. Apply now: cd %q && ./setup --refresh-registered\n' "$VALUE" "$(cd "$(dirname "$0")/.." && pwd)" + fi ;; unset) KEY="${2:?Usage: gstack-config unset }" @@ -1009,7 +1026,7 @@ $_gstack_legacy_root" echo "# ─── Active values (including defaults for unset keys) ───" report_root_disagreement for KEY in proactive routing_declined telemetry auto_upgrade update_check \ - skill_prefix explain_level \ + skill_prefix explain_level plan_mode_preamble \ codex_reviews gstack_contributor skip_eng_review workspace_root \ artifacts_sync_mode artifacts_sync_mode_prompted artifacts_sync_removals plan_tune_hooks \ timeline_stop_hook design_detector design_detector_install_prompted memorable_recall \ @@ -1034,7 +1051,7 @@ $_gstack_legacy_root" defaults) echo "# gstack-config defaults" for KEY in proactive routing_declined telemetry auto_upgrade update_check \ - skill_prefix explain_level \ + skill_prefix explain_level plan_mode_preamble \ codex_reviews gstack_contributor skip_eng_review workspace_root \ artifacts_sync_mode artifacts_sync_mode_prompted artifacts_sync_removals plan_tune_hooks \ timeline_stop_hook design_detector design_detector_install_prompted memorable_recall \ @@ -1065,6 +1082,8 @@ $_gstack_legacy_root" # generated SKILL.md files match your installation state. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" . "$SCRIPT_DIR/gstack-render-claude.sh" 2>/dev/null || { echo "$0: $SCRIPT_DIR/gstack-render-claude.sh is missing. fix: reinstall with ./setup or /gstack-upgrade" >&2; exit 1; } + _PLAN_MODE_ARG="" + [ "$("$0" get plan_mode_preamble 2>/dev/null || true)" != off ] || _PLAN_MODE_ARG="--plan-mode=off" DETECT_BIN="$SCRIPT_DIR/gstack-gbrain-detect" DETECTION_FILE="$STATE_DIR/gbrain-detection.json" mkdir -p "$STATE_DIR" @@ -1133,7 +1152,7 @@ $_gstack_legacy_root" gstack_claude_overlay "$INSTALL_DIR" "$0" RENDER_TMP="$RENDER_DIR.tmp.$$" rm -rf "$RENDER_TMP" - if ( cd "$INSTALL_DIR" && bun run gen:skill-docs:user --host claude --out-dir "$RENDER_TMP" --link-root "$RENDER_DIR" --model "$_GSTACK_OVERLAY" >/dev/null 2>&1 ); then + if ( cd "$INSTALL_DIR" && bun run gen:skill-docs:user --host claude --out-dir "$RENDER_TMP" --link-root "$RENDER_DIR" --model "$_GSTACK_OVERLAY" ${_PLAN_MODE_ARG:+"$_PLAN_MODE_ARG"} >/dev/null 2>&1 ); then gstack_render_lock "$RENDER_DIR" _swap_in_render "$RENDER_DIR" "$RENDER_TMP" gstack_render_unlock "$RENDER_DIR" @@ -1159,7 +1178,7 @@ $_gstack_legacy_root" # brain blocks, so removing gbrain keeps the chosen overlay. INSTALL_DIR="$HOME/.claude/skills/gstack" RENDER_DIR="${GSTACK_USER_RENDER_DIR:-$STATE_DIR/render/claude}" - if { [ -d "$RENDER_DIR" ] || "$0" has claude_overlay_model; } \ + if { [ -d "$RENDER_DIR" ] || "$0" has claude_overlay_model || [ -n "$_PLAN_MODE_ARG" ]; } \ && [ -d "$INSTALL_DIR" ] && [ ! -L "$INSTALL_DIR" ] && [ -f "$INSTALL_DIR/VERSION" ] && [ -f "$INSTALL_DIR/package.json" ]; then if ! command -v bun >/dev/null 2>&1; then echo "Skip: bun not on PATH — the Claude render at $RENDER_DIR was not refreshed. Install bun, then re-run 'gstack-config gbrain-refresh'." diff --git a/bin/gstack-relink b/bin/gstack-relink index 40ff055dc..f572e6a86 100755 --- a/bin/gstack-relink +++ b/bin/gstack-relink @@ -461,19 +461,25 @@ done # (in place, like gstack-patch-names). Clearing the list restores the committed # bytes. Only a generated router is rewritten, and only from a checkout that # carries the generator; a failed render keeps the current router. +# plan_mode_preamble=off (#3168) renders it without the plan-mode preamble the +# same way, and turning it back on restores the committed bytes. _ROUTER="$INSTALL_DIR/SKILL.md" _GEN_SRC="$(cd "$SCRIPT_DIR/.." && pwd)" -if { [ "$DISABLED" != " " ] || grep -q '^Disabled on this install' "$_ROUTER" 2>/dev/null; } \ +_PLAN_MODE_ARG="" +[ "$("$GSTACK_CONFIG" get plan_mode_preamble 2>/dev/null || true)" != off ] || _PLAN_MODE_ARG="--plan-mode=off" +if { [ "$DISABLED" != " " ] || grep -q '^Disabled on this install' "$_ROUTER" 2>/dev/null \ + || [ -n "$_PLAN_MODE_ARG" ] \ + || { grep -q 'PLAN MODE EXCEPTION' "$_ROUTER" 2>/dev/null && ! grep -q '^## Plan Mode Safe Operations' "$_ROUTER" 2>/dev/null; }; } \ && grep -q '