From cc9a4f5d8970742f293840461c0b76177862d7c6 Mon Sep 17 00:00:00 2001 From: gujishh Date: Tue, 12 May 2026 16:17:32 +0900 Subject: [PATCH] fix(codex): avoid prompt and --base conflict in review mode --- codex/SKILL.md | 33 +- codex/SKILL.md.tmpl | 33 +- review/SKILL.md | 2 +- scripts/resolvers/review.ts | 2 +- ship/SKILL.md | 2 +- test/fixtures/golden-ship-claude.md | 1183 +++++++++++++------- test/fixtures/golden/claude-ship-SKILL.md | 2 +- test/fixtures/golden/factory-ship-SKILL.md | 2 +- test/gen-skill-docs.test.ts | 8 + test/skill-validation.test.ts | 7 + 10 files changed, 851 insertions(+), 423 deletions(-) diff --git a/codex/SKILL.md b/codex/SKILL.md index e90ec7e89e..7cc141b503 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -821,8 +821,9 @@ All prompts sent to Codex MUST be prefixed with this boundary instruction: > IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only. -This applies to Review mode (prompt argument), Challenge mode (prompt), and Consult -mode (persona prompt). Reference this section as "the filesystem boundary" below. +This applies to Challenge mode (prompt), Consult mode (persona prompt), and Review +mode when custom instructions require the `codex exec` fallback. Reference this +section as "the filesystem boundary" below. --- @@ -835,15 +836,17 @@ Run Codex code review against the current branch diff. TMPERR=$(mktemp /tmp/codex-err-XXXXXX.txt) ``` -2. Run the review (5-minute timeout). **Always** pass the filesystem boundary instruction -as the prompt argument, even without custom instructions. If the user provided custom -instructions, append them after the boundary separated by a newline: +2. Run the review (5-minute timeout). + +If the user did **not** provide custom instructions, use bare `codex review --base`. +Codex CLI `0.130.0+` rejects `[PROMPT]` combined with `--base`, so the default path +must not pass a positional prompt: ```bash _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" # Fix 1: wrap with timeout. 330s (5.5min) is slightly longer than the Bash 300s # so the shell wrapper only fires if Bash's own timeout doesn't. -_gstack_codex_timeout_wrapper 330 codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. Do NOT modify agents/openai.yaml. Stay focused on repository code only." --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +_gstack_codex_timeout_wrapper 330 codex review --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" _CODEX_EXIT=$? if [ "$_CODEX_EXIT" = "124" ]; then _gstack_codex_log_event "codex_timeout" "330" @@ -854,14 +857,22 @@ fi If the user passed `--xhigh`, use `"xhigh"` instead of `"high"`. -Use `timeout: 300000` on the Bash call. If the user provided custom instructions -(e.g., `/codex review focus on security`), append them after the boundary: +Use `timeout: 300000` on the Bash call. + +If the user **did** provide custom instructions (e.g., `/codex review focus on security`), +route the review through `codex exec` instead. Include the filesystem boundary in the +prompt and tell Codex to inspect `git diff origin/` itself: ```bash _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } -cd "$_REPO_ROOT" -codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. Do NOT modify agents/openai.yaml. Stay focused on repository code only. +_gstack_codex_timeout_wrapper 330 codex exec "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the changes on this branch against the base branch. Run git diff origin/ to inspect the diff. Use the user's extra review instructions below if they narrow the focus. -focus on security" --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +focus on security" -C "$_REPO_ROOT" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +_CODEX_EXIT=$? +if [ "$_CODEX_EXIT" = "124" ]; then + _gstack_codex_log_event "codex_timeout" "330" + _gstack_codex_log_hang "review" "$(wc -c < "$TMPERR" 2>/dev/null || echo 0)" + echo "Codex stalled past 5.5 minutes. Common causes: model API stall, long prompt, network issue. Try re-running. If persistent, split the prompt or check ~/.codex/logs/." +fi ``` 3. Capture the output. Then parse cost from stderr: diff --git a/codex/SKILL.md.tmpl b/codex/SKILL.md.tmpl index c311fc80b7..0e86f195be 100644 --- a/codex/SKILL.md.tmpl +++ b/codex/SKILL.md.tmpl @@ -130,8 +130,9 @@ All prompts sent to Codex MUST be prefixed with this boundary instruction: > IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only. -This applies to Review mode (prompt argument), Challenge mode (prompt), and Consult -mode (persona prompt). Reference this section as "the filesystem boundary" below. +This applies to Challenge mode (prompt), Consult mode (persona prompt), and Review +mode when custom instructions require the `codex exec` fallback. Reference this +section as "the filesystem boundary" below. --- @@ -144,15 +145,17 @@ Run Codex code review against the current branch diff. TMPERR=$(mktemp /tmp/codex-err-XXXXXX.txt) ``` -2. Run the review (5-minute timeout). **Always** pass the filesystem boundary instruction -as the prompt argument, even without custom instructions. If the user provided custom -instructions, append them after the boundary separated by a newline: +2. Run the review (5-minute timeout). + +If the user did **not** provide custom instructions, use bare `codex review --base`. +Codex CLI `0.130.0+` rejects `[PROMPT]` combined with `--base`, so the default path +must not pass a positional prompt: ```bash _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" # Fix 1: wrap with timeout. 330s (5.5min) is slightly longer than the Bash 300s # so the shell wrapper only fires if Bash's own timeout doesn't. -_gstack_codex_timeout_wrapper 330 codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. Do NOT modify agents/openai.yaml. Stay focused on repository code only." --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +_gstack_codex_timeout_wrapper 330 codex review --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" _CODEX_EXIT=$? if [ "$_CODEX_EXIT" = "124" ]; then _gstack_codex_log_event "codex_timeout" "330" @@ -163,14 +166,22 @@ fi If the user passed `--xhigh`, use `"xhigh"` instead of `"high"`. -Use `timeout: 300000` on the Bash call. If the user provided custom instructions -(e.g., `/codex review focus on security`), append them after the boundary: +Use `timeout: 300000` on the Bash call. + +If the user **did** provide custom instructions (e.g., `/codex review focus on security`), +route the review through `codex exec` instead. Include the filesystem boundary in the +prompt and tell Codex to inspect `git diff origin/` itself: ```bash _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } -cd "$_REPO_ROOT" -codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. Do NOT modify agents/openai.yaml. Stay focused on repository code only. +_gstack_codex_timeout_wrapper 330 codex exec "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the changes on this branch against the base branch. Run git diff origin/ to inspect the diff. Use the user's extra review instructions below if they narrow the focus. -focus on security" --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +focus on security" -C "$_REPO_ROOT" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +_CODEX_EXIT=$? +if [ "$_CODEX_EXIT" = "124" ]; then + _gstack_codex_log_event "codex_timeout" "330" + _gstack_codex_log_hang "review" "$(wc -c < "$TMPERR" 2>/dev/null || echo 0)" + echo "Codex stalled past 5.5 minutes. Common causes: model API stall, long prompt, network issue. Try re-running. If persistent, split the prompt or check ~/.codex/logs/." +fi ``` 3. Capture the output. Then parse cost from stderr: diff --git a/review/SKILL.md b/review/SKILL.md index f21a401213..c9b61506d5 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -1521,7 +1521,7 @@ If `DIFF_TOTAL >= 200` AND Codex is available AND `OLD_CFG` is NOT `disabled`: TMPERR=$(mktemp /tmp/codex-review-XXXXXXXX) _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" -codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the diff against the base branch." --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +codex review --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" ``` Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. Present output under `CODEX SAYS (code review):` header. diff --git a/scripts/resolvers/review.ts b/scripts/resolvers/review.ts index a0f29e1746..2bc87e35b0 100644 --- a/scripts/resolvers/review.ts +++ b/scripts/resolvers/review.ts @@ -487,7 +487,7 @@ If \`DIFF_TOTAL >= 200\` AND Codex is available AND \`OLD_CFG\` is NOT \`disable TMPERR=$(mktemp /tmp/codex-review-XXXXXXXX) _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" -codex review "${CODEX_BOUNDARY}Review the diff against the base branch." --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +codex review --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" \`\`\` Set the Bash tool's \`timeout\` parameter to \`300000\` (5 minutes). Do NOT use the \`timeout\` shell command — it doesn't exist on macOS. Present output under \`CODEX SAYS (code review):\` header. diff --git a/ship/SKILL.md b/ship/SKILL.md index 1030ef9938..0444cb475d 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -2247,7 +2247,7 @@ If `DIFF_TOTAL >= 200` AND Codex is available AND `OLD_CFG` is NOT `disabled`: TMPERR=$(mktemp /tmp/codex-review-XXXXXXXX) _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" -codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the diff against the base branch." --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" +codex review --base -c 'model_reasoning_effort="high"' --enable web_search_cached < /dev/null 2>"$TMPERR" ``` Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. Present output under `CODEX SAYS (code review):` header. diff --git a/test/fixtures/golden-ship-claude.md b/test/fixtures/golden-ship-claude.md index 05fff9871b..0444cb475d 100644 --- a/test/fixtures/golden-ship-claude.md +++ b/test/fixtures/golden-ship-claude.md @@ -18,6 +18,11 @@ allowed-tools: - Agent - AskUserQuestion - WebSearch +triggers: + - ship it + - create a pr + - push to main + - deploy this --- @@ -50,11 +55,15 @@ _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +_EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") +if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi +echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL" +_QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo "false") +echo "QUESTION_TUNING: $_QUESTION_TUNING" mkdir -p ~/.gstack/analytics if [ "$_TEL" != "off" ]; then echo '{"skill":"ship","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true fi -# zsh-compatible: use find instead of glob to avoid NOMATCH error for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do if [ -f "$_PF" ]; then if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then @@ -64,7 +73,6 @@ for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null fi break done -# Learnings count eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true _LEARN_FILE="${GSTACK_HOME:-$HOME/.gstack}/projects/${SLUG:-unknown}/learnings.jsonl" if [ -f "$_LEARN_FILE" ]; then @@ -76,9 +84,7 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi -# Session timeline: record skill start (local-only, never sent anywhere) ~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"ship","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null & -# Check if CLAUDE.md has routing rules _HAS_ROUTING="no" if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then _HAS_ROUTING="yes" @@ -86,42 +92,74 @@ fi _ROUTING_DECLINED=$(~/.claude/skills/gstack/bin/gstack-config get routing_declined 2>/dev/null || echo "false") echo "HAS_ROUTING: $_HAS_ROUTING" echo "ROUTING_DECLINED: $_ROUTING_DECLINED" -# Detect spawned session (OpenClaw or other orchestrator) +_VENDORED="no" +if [ -d ".claude/skills/gstack" ] && [ ! -L ".claude/skills/gstack" ]; then + if [ -f ".claude/skills/gstack/VERSION" ] || [ -d ".claude/skills/gstack/.git" ]; then + _VENDORED="yes" + fi +fi +echo "VENDORED_GSTACK: $_VENDORED" +echo "MODEL_OVERLAY: claude" +_CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit") +_CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo "false") +echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE" +echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH" [ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true ``` -If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not -auto-invoke skills based on conversation context. Only run skills the user explicitly -types (e.g., /qa, /ship). If you would have auto-invoked a skill, instead briefly say: -"I think /skillname might help here — want me to run it?" and wait for confirmation. -The user opted out of proactive behavior. +## Plan Mode Safe Operations + +In plan mode, allowed because they inform the plan: `$B`, `$D`, `codex exec`/`codex review`, writes to `~/.gstack/`, writes to the plan file, and `open` for generated artifacts. + +## Skill Invocation During Plan Mode + +If the user invokes a skill in plan mode, the skill takes precedence over generic plan mode behavior. **Treat the skill file as executable instructions, not reference.** Follow it step by step starting from Step 0; the first AskUserQuestion is the workflow entering plan mode, not a violation of it. AskUserQuestion satisfies plan mode's end-of-turn requirement. At a STOP point, stop immediately. Do not continue the workflow or call ExitPlanMode there. Commands marked "PLAN MODE EXCEPTION — ALWAYS RUN" execute. Call ExitPlanMode only after the skill workflow completes, or if the user tells you to cancel the skill or leave plan mode. -If `SKILL_PREFIX` is `"true"`, the user has namespaced skill names. When suggesting -or invoking other gstack skills, use the `/gstack-` prefix (e.g., `/gstack-qa` instead -of `/qa`, `/gstack-ship` instead of `/ship`). Disk paths are unaffected — always use -`~/.claude/skills/gstack/[skill-name]/SKILL.md` for reading skill files. +If `PROACTIVE` is `"false"`, do not auto-invoke or proactively suggest skills. If a skill seems useful, ask: "I think /skillname might help here — want me to run it?" -If output shows `UPGRADE_AVAILABLE `: read `~/.claude/skills/gstack/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED `: tell user "Running gstack v{to} (just updated!)" and continue. +If `SKILL_PREFIX` is `"true"`, suggest/invoke `/gstack-*` names. Disk paths stay `~/.claude/skills/gstack/[skill-name]/SKILL.md`. -If `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. -Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete -thing when AI makes the marginal cost near-zero. Read more: https://garryslist.org/posts/boil-the-ocean" -Then offer to open the essay in their default browser: +If output shows `UPGRADE_AVAILABLE `: read `~/.claude/skills/gstack/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). + +If output shows `JUST_UPGRADED `: print "Running gstack v{to} (just updated!)". If `SPAWNED_SESSION` is true, skip feature discovery. + +Feature discovery, max one prompt per session: +- Missing `~/.claude/skills/gstack/.feature-prompted-continuous-checkpoint`: AskUserQuestion for Continuous checkpoint auto-commits. If accepted, run `~/.claude/skills/gstack/bin/gstack-config set checkpoint_mode continuous`. Always touch marker. +- Missing `~/.claude/skills/gstack/.feature-prompted-model-overlay`: inform "Model overlays are active. MODEL_OVERLAY shows the patch." Always touch marker. + +After upgrade prompts, continue workflow. + +If `WRITING_STYLE_PENDING` is `yes`: ask once about writing style: + +> v1 prompts are simpler: first-use jargon glosses, outcome-framed questions, shorter prose. Keep default or restore terse? + +Options: +- A) Keep the new default (recommended — good writing helps everyone) +- B) Restore V0 prose — set `explain_level: terse` + +If A: leave `explain_level` unset (defaults to `default`). +If B: run `~/.claude/skills/gstack/bin/gstack-config set explain_level terse`. + +Always run (regardless of choice): +```bash +rm -f ~/.gstack/.writing-style-prompt-pending +touch ~/.gstack/.writing-style-prompted +``` + +Skip if `WRITING_STYLE_PENDING` is `no`. + +If `LAKE_INTRO` is `no`: say "gstack follows the **Boil the Lake** principle — do the complete thing when AI makes marginal cost near-zero. Read more: https://garryslist.org/posts/boil-the-ocean" Offer to open: ```bash open https://garryslist.org/posts/boil-the-ocean touch ~/.gstack/.completeness-intro-seen ``` -Only run `open` if the user says yes. Always run `touch` to mark as seen. This only happens once. +Only run `open` if yes. Always run `touch`. -If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, -ask the user about telemetry. Use AskUserQuestion: +If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: ask telemetry once via AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. -> Change anytime with `gstack-config set telemetry off`. +> Help gstack get better. Share usage data only: skill, duration, crashes, stable device ID. No code, file paths, or repo names. Options: - A) Help gstack get better! (recommended) @@ -129,10 +167,9 @@ Options: If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` -If B: ask a follow-up AskUserQuestion: +If B: ask follow-up: -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. +> Anonymous mode sends only aggregate usage, no unique ID. Options: - A) Sure, anonymous is fine @@ -146,14 +183,11 @@ Always run: touch ~/.gstack/.telemetry-prompted ``` -This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +Skip if `TEL_PROMPTED` is `yes`. -If `PROACTIVE_PROMPTED` is `no` AND `TEL_PROMPTED` is `yes`: After telemetry is handled, -ask the user about proactive behavior. Use AskUserQuestion: +If `PROACTIVE_PROMPTED` is `no` AND `TEL_PROMPTED` is `yes`: ask once: -> gstack can proactively figure out when you might need a skill while you work — -> like suggesting /qa when you say "does this work?" or /investigate when you hit -> a bug. We recommend keeping this on — it speeds up every part of your workflow. +> Let gstack proactively suggest skills, like /qa for "does this work?" or /investigate for bugs? Options: - A) Keep it on (recommended) @@ -167,7 +201,7 @@ Always run: touch ~/.gstack/.proactive-prompted ``` -This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +Skip if `PROACTIVE_PROMPTED` is `yes`. If `HAS_ROUTING` is `no` AND `ROUTING_DECLINED` is `false` AND `PROACTIVE_PROMPTED` is `yes`: Check if a CLAUDE.md file exists in the project root. If it does not exist, create it. @@ -175,8 +209,6 @@ Check if a CLAUDE.md file exists in the project root. If it does not exist, crea Use AskUserQuestion: > gstack works best when your project's CLAUDE.md includes skill routing rules. -> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) -> instead of answering directly. It's a one-time addition, about 15 lines. Options: - A) Add routing rules to CLAUDE.md (recommended) @@ -188,31 +220,54 @@ If A: Append this section to the end of CLAUDE.md: ## Skill routing -When the user's request matches an available skill, ALWAYS invoke it using the Skill -tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. -The skill has specialized workflows that produce better results than ad-hoc answers. +When the user's request matches an available skill, invoke it via the Skill tool. When in doubt, invoke the skill. Key routing rules: -- Product ideas, "is this worth building", brainstorming → invoke office-hours -- Bugs, errors, "why is this broken", 500 errors → invoke investigate -- Ship, deploy, push, create PR → invoke ship -- QA, test the site, find bugs → invoke qa -- Code review, check my diff → invoke review -- Update docs after shipping → invoke document-release -- Weekly retro → invoke retro -- Design system, brand → invoke design-consultation -- Visual audit, design polish → invoke design-review -- Architecture review → invoke plan-eng-review -- Save progress, checkpoint, resume → invoke checkpoint -- Code quality, health check → invoke health +- Product ideas/brainstorming → invoke /office-hours +- Strategy/scope → invoke /plan-ceo-review +- Architecture → invoke /plan-eng-review +- Design system/plan review → invoke /design-consultation or /plan-design-review +- Full review pipeline → invoke /autoplan +- Bugs/errors → invoke /investigate +- QA/testing site behavior → invoke /qa or /qa-only +- Code review/diff check → invoke /review +- Visual polish → invoke /design-review +- Ship/deploy/PR → invoke /ship or /land-and-deploy +- Save progress → invoke /context-save +- Resume context → invoke /context-restore ``` Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` -If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` -Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` and say they can re-enable with `gstack-config set routing_declined false`. + +This only happens once per project. Skip if `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`. + +If `VENDORED_GSTACK` is `yes`, warn once via AskUserQuestion unless `~/.gstack/.vendoring-warned-$SLUG` exists: + +> This project has gstack vendored in `.claude/skills/gstack/`. Vendoring is deprecated. +> Migrate to team mode? + +Options: +- A) Yes, migrate to team mode now +- B) No, I'll handle it myself + +If A: +1. Run `git rm -r .claude/skills/gstack/` +2. Run `echo '.claude/skills/gstack/' >> .gitignore` +3. Run `~/.claude/skills/gstack/bin/gstack-team-init required` (or `optional`) +4. Run `git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"` +5. Tell the user: "Done. Each developer now runs: `cd ~/.claude/skills/gstack && ./setup --team`" + +If B: say "OK, you're on your own to keep the vendored copy up to date." -This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. +Always run (regardless of choice): +```bash +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true +touch ~/.gstack/.vendoring-warned-${SLUG:-unknown} +``` + +If marker exists, skip. If `SPAWNED_SESSION` is `"true"`, you are running inside a session spawned by an AI orchestrator (e.g., OpenClaw). In spawned sessions: @@ -221,73 +276,178 @@ AI orchestrator (e.g., OpenClaw). In spawned sessions: - Focus on completing the task and reporting results via prose output. - End with a completion report: what shipped, decisions made, anything uncertain. -## Voice +## AskUserQuestion Format + +Every AskUserQuestion is a decision brief and must be sent as tool_use, not prose. + +``` +D +Project/branch/task: <1 short grounding sentence using _BRANCH> +ELI10: +Stakes if we pick wrong: +Recommendation: because +Completeness: A=X/10, B=Y/10 (or: Note: options differ in kind, not coverage — no completeness score) +Pros / cons: +A)