diff --git a/AGENTS.md b/AGENTS.md index 4df7eec35..4c8ea80f4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,6 +43,7 @@ Invoke them by name (e.g., `/office-hours`). | Skill | What it does | |-------|-------------| +| `/pr-prep` | Pre-PR upstream duplicate audit. Scores each commit against upstream issues + PRs; blocks on exact duplicates. Hooks into `/ship` as Step 0. | | `/ship` | Run tests, review, push, open PR. Workspace-aware version queue. | | `/land-and-deploy` | Merge the PR, wait for CI and deploy, verify production health. | | `/canary` | Post-deploy monitoring loop using the browse daemon. | diff --git a/PREAMBLE-BLOAT-NOTES.md b/PREAMBLE-BLOAT-NOTES.md new file mode 100644 index 000000000..0077ebab3 --- /dev/null +++ b/PREAMBLE-BLOAT-NOTES.md @@ -0,0 +1,199 @@ +# Preamble Bloat — Findings & Safe Trim Strategy + +Date: 2026-07-05. Investigated on branch `feat/pr-prep-skill` +(merge-base with `upstream/main` = `11de390b`, v1.58.5.0). + +**Verdict: do NOT trim locally.** The bloat is upstream-owned, generated +content, churned in every upstream release. Any fork-side edit to the +source (resolvers or templates) or to the committed generated files +guarantees rebase conflicts on every `/gstack-upgrade` (this fork is +maintained by rebasing onto `upstream/main`). The safe path is an +upstream PR that extends the repo's own `sections/` carving mechanism +to the preamble. Details below. + +--- + +## 1. Where the bytes come from + +Every `~/.claude/skills//SKILL.md` is a **symlink** into this repo. +Each `SKILL.md` here is **generated** by `scripts/gen-skill-docs.ts` from +`/SKILL.md.tmpl`: placeholders (`{{PREAMBLE}}`, `{{SLUG_SETUP}}`, +`{{QA_METHODOLOGY}}`, …) are resolved from `scripts/resolvers/**`. + +The dominant placeholder is `{{PREAMBLE}}`, composed in +`scripts/resolvers/preamble.ts` from ~24 generator files under +`scripts/resolvers/preamble/`, gated by `preamble-tier: 1-4` in each +template's frontmatter (missing tier defaults to 4). + +Rendered preamble size (measured by invoking `generatePreamble()` +directly; host=claude, model=claude, interactive): + +| Tier | Bytes | ~Tokens (4 B/tok) | Skills at this tier | +|------|-------|-------------------|---------------------| +| 1 | 25,690 | ~6.4k | 6 | +| 2 | 45,295 | ~11.3k | 16 | +| 3 | 46,336 | ~11.6k | 15 | +| 4 | 46,336 | ~11.6k | 7 (+ untiered, e.g. `spec`) | + +So a tier-2 skill like `context-save` (54,971 B total) is **84% preamble** +(46,112 B before the first body heading). Across the whole install, +~1.9 MB of the 3.57 MB of installed SKILL.md bytes is the same preamble +duplicated ~44 times (~53%). + +Per-section breakdown of the tier-4 preamble (rendered bytes): + +| Section | Bytes | Nature | +|---|---|---| +| ask-user-format | 10,546 | prose — interaction framework | +| preamble-bash | 6,169 | **functional** — session/telemetry bootstrap | +| brain-sync-block | 5,785 | **functional** — gbrain sync bash | +| plan-mode-info | 2,888 | prose + env contract | +| question-tuning | 2,494 | prose | +| context-recovery | 2,378 | prose | +| first-run-guidance | 1,715 | one-time onboarding gate | +| routing-injection | 1,624 | one-time onboarding gate | +| voice-directive | 1,350 | prose | +| upgrade-check | 1,186 | **functional** — bash | +| writing-style | 1,113 | prose | +| vendoring-deprecation | 975 | one-time gate | +| model-overlay | 947 | behavioural patch | +| continuous-checkpoint | 922 | prose | +| telemetry-prompt | 829 | one-time gate | +| 9 further sections | ~4,182 | mixed, ≤700 B each | +| **Total** | **~45.1k** | | + +## 2. Ten largest installed SKILL.md files (symlink-resolved bytes) + +```txt +126,959 spec (untiered -> T4) +105,796 review (T4) +105,734 design-review (T4) +101,167 land-and-deploy (T4) +100,590 autoplan (T3) + 97,744 office-hours (T3) + 93,248 retro (T2) + 90,397 setup-gbrain + 90,000 codex (T3) + 89,827 plan-ceo-review (T3) +``` + +(Also notable: `qa` 83,941; `context-save` 54,971; `browse` 54,983.) +Non-gstack skills are far smaller: `graphify` 37,070, `impeccable` +19,981, `undercover-agent` 12,653 — the bloat is specifically the +gstack preamble plus a handful of intentionally large bodies. + +## 3. Why fork-side trimming is unsafe (the evidence) + +1. **Upstream owns and churns every layer.** The last three upstream + releases (v1.57.5.0 `45cc95d5`, v1.58.1.0 `c7ae6320`, v1.58.5.0 + `11de390b`) each modified `scripts/resolvers/preamble/` AND the + committed generated `SKILL.md` files (e.g. `context-save/SKILL.md` + changed in all three). A single release delta + (`upstream/main~1..upstream/main`) touched **51 files / 1,469 + insertions** across `*/SKILL.md`, `*/SKILL.md.tmpl`, and + `scripts/resolvers/`. A local diff in those paths conflicts on + every rebase. +2. **CI freshness gate pins generated output to default flags.** + `gen-skill-docs.ts --dry-run` (used by `skill:check` / CI) exits 1 + if committed SKILL.md ≠ generator output. A committed trim therefore + cannot live only in the generated files — it must be sourced in the + resolvers/templates, which are exactly the upstream-churned files. +3. **This fork's own discipline confirms the pain.** The 12 local + commits ahead of upstream confine themselves to a new fork-owned + skill (`pr-prep/`) plus a ~50-line `ship/SKILL.md.tmpl` addition; + none touch `scripts/resolvers/`. That boundary is what keeps + rebases cheap today. +4. **Preamble composition is behaviour-sensitive upstream territory.** + `preamble.ts` documents ordering constraints in-line (e.g. + AskUserQuestion Format must render before the model overlay; + "reversing this order regresses plan-review cadence (v1.6.4.0 + bug)"). Relocating sections is not a mechanical move. +5. **Upstream's stated stance tolerates the size.** The generator's + token-ceiling guardrail (gen-skill-docs.ts, ~line 1013) warns only + above 160 KB/file and explicitly defends 25-35k-token skills as + intentional. A quiet local fork of that philosophy would fight + upstream on every release. + +## 4. The safe trim strategy + +**A. Upstream PR (recommended, durable).** The machinery already +exists: carved skills render on-demand `sections/*.md` for the Claude +host (`discoverSectionTemplates` in `scripts/discover-skills.ts`, +section generation in `gen-skill-docs.ts`; live examples: +`plan-eng-review/sections/`, `qa/references/`, `qa/templates/`). +Extend it to the preamble: + +- Move the tier-2+ interaction-framework prose — ask-user-format, + question-tuning, context-recovery, writing-style, completeness, + confusion-protocol, continuous-checkpoint, context-health, plus the + tier-3 repo-mode and search-before-building blocks (~20.5 KB + rendered) — into a generated shared section file (e.g. + `/sections/interaction-framework.md`), leaving a 2-3 line + pointer in the inline preamble ("Read + `~/.claude/skills/gstack//sections/interaction-framework.md` + before your first AskUserQuestion / when the framework applies"). +- Keep byte-identical inline: the functional bash bootstrap + (preamble-bash, upgrade-check, brain-sync-block, telemetry), the + one-time onboarding gates, model overlay, and frontmatter/triggers. +- Non-Claude hosts already inline sections via `{{SECTION:id}}`, so + the change is Claude-host-only, mirroring the existing carve. + +Run `/pr-prep` first (built in this fork for exactly this) to check +upstream for an existing issue/PR on preamble slimming before opening. + +**B. Zero-conflict local interim (nothing committed).** Render a +user-local variant to an untracked directory with the existing +`--out-dir` flag and re-point the `~/.claude/skills//SKILL.md` +symlinks there. Supported knob today: `--explain-level=terse` +compresses four prose sections to pointer lines — but it saves only +~2.2 KB (46,336 → 44,179 B), which is why A is the real fix. Note the +working tree already carries expected uncommitted SKILL.md dirt from +`gen:skill-docs:user` (gbrain detection); an out-dir render avoids +adding to it. + +**C. Not recommended.** Fork-local edits to +`scripts/resolvers/preamble/**` or committing regenerated SKILL.md +files: recurring semantic conflicts against ~50 files/1.5k lines of +upstream churn per release. + +## 5. Estimated savings (strategy A) + +- Per invocation, tier 2-4 skill: ~20.5 KB relocated ≈ **~5.1k tokens + saved** (at the generator's own 4-chars/token heuristic), i.e. the + preamble drops ~44% (46.3 KB → ~25.8 KB) and e.g. `context-save` + goes 55 KB → ~34 KB, `qa` 84 KB → ~63 KB. +- Applies to 38 tier-2+ skills; tier-1 skills (browse, benchmark, …) + are unaffected by design. +- Install-wide: ~0.8 MB less duplicated preamble on disk; every + gstack skill invocation on this machine starts ~5k tokens lighter. +- Getting the top offenders under ~15 KB would additionally require + carving their bodies (spec 95 KB body, review ~60 KB body) — that is + upstream-owned, intentionally-tuned behaviour per the token-ceiling + comment, so propose it upstream per-skill via the same `sections/` + mechanism rather than forking it. + +--- + +## 6. Upstream duplicate check (2026-07-05, Opus session) + +Ran the check the strategy said to do first. Findings on garrytan/gstack: + +- **#1572 (open) — "skill: cache preamble bash output within session to + reduce duplication"** is the closest existing issue: same preamble-duplication + concern, no PR carving the interaction-framework prose yet. Our proposal is + complementary, not a duplicate. +- Active adjacent preamble work (do NOT collide): #2001/#2022 gate + upgrade-handling prose; #1150/#1188 gate telemetry session tracking; #1982 + surface failed update-checks; #1972 shrink skill descriptions (codex budget). +- No open PR implements a `sections/` carve of the preamble prose. + +Verification blockers confirming proposal-first: +- `bun run skill:check` is **red on a clean `11de390b` checkout** — unrelated + cause: `.gbrain/skills/gstack-*/SKILL.md` stale under `gen:skill-docs --host + gbrain` detection. A fork can't cleanly prove Claude-host freshness in + isolation against that baseline. +- Real behaviour gate is `test:evals` (EVALS=1, live model calls) — API-gated. + +Deliverable: `~/worktrees/gstack-preamble-trim/PR-PROPOSAL.md` — maintainer-ready +text to post on #1572 for buy-in before implementing. Branch `pr/preamble-trim` +sits on clean upstream; no code committed (proposal-first, per above). diff --git a/autoplan/SKILL.md b/autoplan/SKILL.md index 5346f1d43..f8ca34a42 100644 --- a/autoplan/SKILL.md +++ b/autoplan/SKILL.md @@ -399,6 +399,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -450,6 +452,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/benchmark-models/SKILL.md b/benchmark-models/SKILL.md index 6a9d62616..0b11d8cae 100644 --- a/benchmark-models/SKILL.md +++ b/benchmark-models/SKILL.md @@ -12,6 +12,7 @@ allowed-tools: - Bash - Read - AskUserQuestion +disable-model-invocation: true --- diff --git a/benchmark-models/SKILL.md.tmpl b/benchmark-models/SKILL.md.tmpl index 034cda182..1060f3bf8 100644 --- a/benchmark-models/SKILL.md.tmpl +++ b/benchmark-models/SKILL.md.tmpl @@ -22,6 +22,7 @@ allowed-tools: - Bash - Read - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/benchmark/SKILL.md b/benchmark/SKILL.md index 9451d2d4f..c9273988d 100644 --- a/benchmark/SKILL.md +++ b/benchmark/SKILL.md @@ -13,6 +13,7 @@ allowed-tools: - Write - Glob - AskUserQuestion +disable-model-invocation: true --- diff --git a/benchmark/SKILL.md.tmpl b/benchmark/SKILL.md.tmpl index 038f16f5f..1e028e191 100644 --- a/benchmark/SKILL.md.tmpl +++ b/benchmark/SKILL.md.tmpl @@ -21,6 +21,7 @@ allowed-tools: - Write - Glob - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/bin/gstack-artifacts-init b/bin/gstack-artifacts-init index b8bfe830c..2a308fc87 100755 --- a/bin/gstack-artifacts-init +++ b/bin/gstack-artifacts-init @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-artifacts-init — set up ~/.gstack/ as a git repo synced to a private # git host (GitHub or GitLab) so a remote gbrain can ingest your artifacts # (CEO plans, designs, /investigate reports) as a federated source. @@ -48,7 +49,7 @@ while [ $# -gt 0 ]; do --remote) REMOTE_URL="$2"; shift 2 ;; --host) HOST_PREF="$2"; shift 2 ;; --url-form-supported) URL_FORM_SUPPORTED="$2"; shift 2 ;; - --help|-h) sed -n '2,32p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; + --help|-h) sed -n '3,33p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) echo "Unknown flag: $1" >&2; exit 1 ;; esac done diff --git a/bin/gstack-brain-consumer b/bin/gstack-brain-consumer index 12403ae58..5fb320051 100755 --- a/bin/gstack-brain-consumer +++ b/bin/gstack-brain-consumer @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-brain-consumer — manage the consumer (reader) registry. # # DEPRECATED in v1.17.0.0. This binary targets a gbrain HTTP /ingest-repo @@ -196,6 +197,6 @@ case "${1:-}" in list) sub_list ;; remove) shift; sub_remove "$@" ;; test) shift; sub_test "$@" ;; - --help|-h|"") sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//' ;; + --help|-h|"") sed -n '3,21p' "$0" | sed 's/^# \{0,1\}//' ;; *) echo "Unknown subcommand: $1" >&2; exit 1 ;; esac diff --git a/bin/gstack-brain-restore b/bin/gstack-brain-restore index 21f7c1134..8b4fad6fd 100755 --- a/bin/gstack-brain-restore +++ b/bin/gstack-brain-restore @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-brain-restore — bootstrap a new machine from an existing brain repo. # # Usage: diff --git a/bin/gstack-brain-sync b/bin/gstack-brain-sync index 2ad0fe773..4a932a071 100755 --- a/bin/gstack-brain-sync +++ b/bin/gstack-brain-sync @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-brain-sync — drain queue, commit allowlisted paths, push to remote. # # Usage: @@ -487,7 +488,7 @@ case "${1:-}" in --drop-queue) shift; subcmd_drop_queue "${1:-}" ;; --discover-new) subcmd_discover_new ;; --help|-h) - sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//' + sed -n '3,19p' "$0" | sed 's/^# \{0,1\}//' ;; *) echo "Unknown subcommand: $1" >&2 diff --git a/bin/gstack-distill-free-text b/bin/gstack-distill-free-text index 4f0688dcb..d930b4d63 100755 --- a/bin/gstack-distill-free-text +++ b/bin/gstack-distill-free-text @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-distill-free-text — Layer 8 "dream cycle" batch distiller. # # Reads auq-other free-text events from this project's question-log.jsonl, @@ -37,7 +38,7 @@ case "${1:-}" in --dry-run) MODE="dry-run" ;; --status) MODE="status" ;; --help|-h) - sed -n '1,/^set -euo/p' "$0" | sed 's|^# \?||' + sed -n '3,/^set -euo/p' "$0" | sed 's|^# \?||' exit 0 ;; '') ;; diff --git a/bin/gstack-jsonl-merge b/bin/gstack-jsonl-merge index d2fa5744c..8878db3c6 100755 --- a/bin/gstack-jsonl-merge +++ b/bin/gstack-jsonl-merge @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-jsonl-merge — git merge driver for append-only JSONL files. # # Usage (called by git, not by users): diff --git a/bin/gstack-pr-prep-score b/bin/gstack-pr-prep-score new file mode 100755 index 000000000..030bfcb83 --- /dev/null +++ b/bin/gstack-pr-prep-score @@ -0,0 +1,153 @@ +#!/usr/bin/env bun +/** + * gstack-pr-prep-score — pure collision scorer for the /pr-prep audit. + * + * Extracts the Step 4 bucketing rules from pr-prep/SKILL.md into one + * deterministic, unit-tested place (the v0.2.0 seed the skill flags). The + * skill's inline bash remains the spec; this is the canonical implementation + * it points to. No network, no git — pure function of its JSON input. + * + * Input (stdin or --file ), one commit's candidate set: + * { + * "commitKeywords": ["reindex", "cli", "fix"], + * "changedFiles": ["src/reindex.ts"], + * "candidates": [ + * { "state": "open_pr", "titleKeywords": [...], "changedFiles": [...] }, + * { "state": "open_issue", "titleKeywords": [...] }, + * { "state": "merged_recent", "titleKeywords": [...] }, + * { "state": "closed_issue", "titleKeywords": [...] } + * ] + * } + * + * Output (stdout): { "bucket", "topScore", "openIssueCount", "reasons": [...] } + * Buckets: EXACT_DUP | OVERLAP | SIBLING | CLEAN (precedence in that order). + * Exit 0 always; the bucket is the signal (the skill maps EXACT_DUP -> exit 1). + */ + +export type CandidateState = 'open_pr' | 'open_issue' | 'merged_recent' | 'closed_issue'; + +export interface Candidate { + state: CandidateState; + titleKeywords?: string[]; + changedFiles?: string[]; + ref?: string; // e.g. "#1358" — passed through into reasons +} + +export interface ScoreInput { + commitKeywords?: string[]; + changedFiles?: string[]; + candidates?: Candidate[]; +} + +export type Bucket = 'EXACT_DUP' | 'OVERLAP' | 'SIBLING' | 'CLEAN'; + +export interface ScoreResult { + bucket: Bucket; + topScore: number; + openIssueCount: number; + reasons: string[]; +} + +// State weighting from SKILL.md Step 4. +const STATE_WEIGHT: Record = { + open_pr: 1.0, + open_issue: 0.7, + merged_recent: 0.6, + closed_issue: 0.2, +}; + +function norm(tokens: string[] | undefined): Set { + return new Set((tokens ?? []).map((t) => t.toLowerCase().trim()).filter(Boolean)); +} + +export function jaccard(a: string[] | undefined, b: string[] | undefined): number { + const sa = norm(a); + const sb = norm(b); + if (sa.size === 0 || sb.size === 0) return 0; + let inter = 0; + for (const x of sa) if (sb.has(x)) inter++; + const union = sa.size + sb.size - inter; + return union === 0 ? 0 : inter / union; +} + +export function score(input: ScoreInput): ScoreResult { + const candidates = input.candidates ?? []; + const reasons: string[] = []; + let topScore = 0; + let exactDup = false; + let overlap = false; + let sibling = false; + let openIssueCount = 0; + let hasOpenPr = false; + let onlyClosed = candidates.length > 0; + + for (const c of candidates) { + const titleJ = jaccard(input.commitKeywords, c.titleKeywords); + // File overlap only meaningful for open PRs (we can read their diff). + const fileJ = + c.state === 'open_pr' ? jaccard(input.changedFiles, c.changedFiles) : 0; + const overlapJ = Math.max(titleJ, fileJ); + const s = overlapJ * STATE_WEIGHT[c.state]; + if (s > topScore) topScore = s; + if (c.state !== 'closed_issue') onlyClosed = false; + if (c.state === 'open_issue') openIssueCount++; + if (c.state === 'open_pr') hasOpenPr = true; + + const ref = c.ref ? `${c.ref} ` : ''; + // EXACT_DUP: any OPEN PR with title Jaccard >=0.6 OR file overlap >=0.6. + if (c.state === 'open_pr' && (titleJ >= 0.6 || fileJ >= 0.6)) { + exactDup = true; + reasons.push( + `${ref}EXACT_DUP: open PR titleJ=${titleJ.toFixed(2)} fileJ=${fileJ.toFixed(2)}`, + ); + continue; + } + // OVERLAP: any OPEN PR/issue with score >=0.3. + if ((c.state === 'open_pr' || c.state === 'open_issue') && s >= 0.3) { + overlap = true; + reasons.push(`${ref}OVERLAP: open ${c.state} score=${s.toFixed(2)}`); + continue; + } + // SIBLING: merged-recently with any overlap. + if (c.state === 'merged_recent' && overlapJ > 0) { + sibling = true; + reasons.push(`${ref}SIBLING: merged-recent overlap=${overlapJ.toFixed(2)}`); + } + } + + // OVERLAP also triggers on >=3 OPEN issues even when none individually scores high. + if (openIssueCount >= 3) { + overlap = true; + reasons.push(`OVERLAP: ${openIssueCount} open issues`); + } + // SIBLING: OPEN issues present but no OPEN PR (and not already EXACT_DUP/OVERLAP). + if (openIssueCount > 0 && !hasOpenPr) sibling = true; + + let bucket: Bucket; + if (exactDup) bucket = 'EXACT_DUP'; + else if (overlap) bucket = 'OVERLAP'; + else if (sibling) bucket = 'SIBLING'; + else bucket = 'CLEAN'; + + if (bucket === 'CLEAN' && reasons.length === 0) { + reasons.push(onlyClosed ? 'only closed issues' : 'no hits above threshold'); + } + return { bucket, topScore: Number(topScore.toFixed(4)), openIssueCount, reasons }; +} + +// CLI entry — skip when imported by the test. +if (import.meta.main) { + const fileArg = process.argv.indexOf('--file'); + const raw = + fileArg !== -1 + ? await Bun.file(process.argv[fileArg + 1]).text() + : await Bun.stdin.text(); + let input: ScoreInput; + try { + input = JSON.parse(raw || '{}'); + } catch { + console.error('gstack-pr-prep-score: input is not valid JSON'); + process.exit(2); + } + process.stdout.write(JSON.stringify(score(input)) + '\n'); +} diff --git a/bin/gstack-settings-hook b/bin/gstack-settings-hook index 6d663b23f..aa02e6b37 100755 --- a/bin/gstack-settings-hook +++ b/bin/gstack-settings-hook @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-settings-hook — manage Claude Code hooks in ~/.claude/settings.json # # Two shapes: diff --git a/bin/gstack-team-init b/bin/gstack-team-init index 256735f8b..da97173b5 100755 --- a/bin/gstack-team-init +++ b/bin/gstack-team-init @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +#!/bin/bash +# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ) # gstack-team-init — generate repo-level bootstrap files for team mode # # Usage: diff --git a/canary/SKILL.md b/canary/SKILL.md index 08d4d7369..ff79e0309 100644 --- a/canary/SKILL.md +++ b/canary/SKILL.md @@ -13,6 +13,7 @@ triggers: - monitor after deploy - canary check - watch for errors post-deploy +disable-model-invocation: true --- @@ -391,6 +392,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -442,6 +445,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/canary/SKILL.md.tmpl b/canary/SKILL.md.tmpl index d1eb2950a..e7f2a779c 100644 --- a/canary/SKILL.md.tmpl +++ b/canary/SKILL.md.tmpl @@ -18,6 +18,7 @@ triggers: - monitor after deploy - canary check - watch for errors post-deploy +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/careful/SKILL.md b/careful/SKILL.md index c646c8b60..f1b46651a 100644 --- a/careful/SKILL.md +++ b/careful/SKILL.md @@ -16,6 +16,7 @@ hooks: - type: command command: "bash $HOME/.claude/skills/gstack/careful/bin/check-careful.sh" statusMessage: "Checking for destructive commands..." +disable-model-invocation: true --- diff --git a/careful/SKILL.md.tmpl b/careful/SKILL.md.tmpl index 5c128a00e..b45f42639 100644 --- a/careful/SKILL.md.tmpl +++ b/careful/SKILL.md.tmpl @@ -22,6 +22,7 @@ hooks: command: "bash $HOME/.claude/skills/gstack/careful/bin/check-careful.sh" statusMessage: "Checking for destructive commands..." sensitive: true +disable-model-invocation: true --- # /careful — Destructive Command Guardrails diff --git a/codex/SKILL.md b/codex/SKILL.md index 33228ff9b..8db868546 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -14,6 +14,7 @@ allowed-tools: - Glob - Grep - AskUserQuestion +disable-model-invocation: true --- @@ -394,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -445,6 +448,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/codex/SKILL.md.tmpl b/codex/SKILL.md.tmpl index 333de7d8d..535b4bb39 100644 --- a/codex/SKILL.md.tmpl +++ b/codex/SKILL.md.tmpl @@ -23,6 +23,7 @@ allowed-tools: - Glob - Grep - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/context-restore/SKILL.md b/context-restore/SKILL.md index 59b40e82c..ea8acef61 100644 --- a/context-restore/SKILL.md +++ b/context-restore/SKILL.md @@ -395,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -446,6 +448,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/context-save/SKILL.md b/context-save/SKILL.md index a1eb24595..dc95fcb80 100644 --- a/context-save/SKILL.md +++ b/context-save/SKILL.md @@ -394,6 +394,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -445,6 +447,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/cso/SKILL.md b/cso/SKILL.md index a08d7e9fe..5e3638087 100644 --- a/cso/SKILL.md +++ b/cso/SKILL.md @@ -16,6 +16,7 @@ triggers: - security audit - check for vulnerabilities - owasp review +disable-model-invocation: true --- @@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/cso/SKILL.md.tmpl b/cso/SKILL.md.tmpl index 413fb0995..73b9db410 100644 --- a/cso/SKILL.md.tmpl +++ b/cso/SKILL.md.tmpl @@ -29,6 +29,7 @@ triggers: - security audit - check for vulnerabilities - owasp review +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index 83eed0a2d..bf4fbf168 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -417,6 +417,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -468,6 +470,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/design-html/SKILL.md b/design-html/SKILL.md index a480bd62c..5b8944d2c 100644 --- a/design-html/SKILL.md +++ b/design-html/SKILL.md @@ -16,6 +16,7 @@ allowed-tools: - Grep - Agent - AskUserQuestion +disable-model-invocation: true --- @@ -398,6 +399,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -449,6 +452,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/design-html/SKILL.md.tmpl b/design-html/SKILL.md.tmpl index 3cdec9a14..c2eb022db 100644 --- a/design-html/SKILL.md.tmpl +++ b/design-html/SKILL.md.tmpl @@ -28,6 +28,7 @@ allowed-tools: - Grep - Agent - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/design-review/SKILL.md b/design-review/SKILL.md index 645453162..93d425389 100644 --- a/design-review/SKILL.md +++ b/design-review/SKILL.md @@ -395,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -446,6 +448,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/design-shotgun/SKILL.md b/design-shotgun/SKILL.md index 3386d18fa..50ecbd92d 100644 --- a/design-shotgun/SKILL.md +++ b/design-shotgun/SKILL.md @@ -34,6 +34,7 @@ gbrain: sort: mtime_desc limit: 3 render_as: "## Recent design docs" +disable-model-invocation: true --- @@ -412,6 +413,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -463,6 +466,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/design-shotgun/SKILL.md.tmpl b/design-shotgun/SKILL.md.tmpl index 230dbc292..17ab20348 100644 --- a/design-shotgun/SKILL.md.tmpl +++ b/design-shotgun/SKILL.md.tmpl @@ -40,6 +40,7 @@ gbrain: sort: mtime_desc limit: 3 render_as: "## Recent design docs" +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/devex-review/SKILL.md b/devex-review/SKILL.md index 7ef324b3e..813223eb3 100644 --- a/devex-review/SKILL.md +++ b/devex-review/SKILL.md @@ -15,6 +15,7 @@ allowed-tools: - Bash - AskUserQuestion - WebSearch +disable-model-invocation: true --- @@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/devex-review/SKILL.md.tmpl b/devex-review/SKILL.md.tmpl index 081d4f35b..1a2482b8c 100644 --- a/devex-review/SKILL.md.tmpl +++ b/devex-review/SKILL.md.tmpl @@ -27,6 +27,7 @@ allowed-tools: - Bash - AskUserQuestion - WebSearch +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/diagram/SKILL.md b/diagram/SKILL.md index 9e5a41066..abd64af2b 100644 --- a/diagram/SKILL.md +++ b/diagram/SKILL.md @@ -14,6 +14,7 @@ triggers: - diagram this - visualize this flow - architecture diagram +disable-model-invocation: true --- @@ -392,6 +393,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -443,6 +446,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/diagram/SKILL.md.tmpl b/diagram/SKILL.md.tmpl index 9e19a52c6..fd8ac0a4c 100644 --- a/diagram/SKILL.md.tmpl +++ b/diagram/SKILL.md.tmpl @@ -20,6 +20,7 @@ triggers: - diagram this - visualize this flow - architecture diagram +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/docs/skills.md b/docs/skills.md index 8e8cb7adc..5fa5a561a 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -19,6 +19,7 @@ Detailed guides for every gstack skill — philosophy, workflow, and examples. | [`/qa-only`](#qa) | **QA Reporter** | Same methodology as /qa but report only. Use when you want a pure bug report without code changes. | | [`/scrape`](#scrape) | **Browser Data Extractor** | Pull data from a web page. First call prototypes via `$B`; subsequent calls on a matching intent run a codified browser-skill in ~200ms. | | [`/skillify`](#skillify) | **Skill Codifier** | Walks back through your conversation, finds the last `/scrape` prototype, synthesizes script + test + fixture, runs the test, asks before committing. | +| [`/pr-prep`](#pr-prep) | **PR Auditor** | Pre-PR upstream duplicate audit. Walks `git log base..HEAD`, queries upstream issues + PRs, scores each commit (EXACT_DUP / OVERLAP / SIBLING / CLEAN), and refuses to proceed on exact duplicates. Hooks into `/ship` as Step 0. | | [`/ship`](#ship) | **Release Engineer** | Sync main, run tests, audit coverage, push, open PR. Bootstraps test frameworks if you don't have one. One command. | | [`/land-and-deploy`](#land-and-deploy) | **Release Engineer** | Merge the PR, wait for CI and deploy, verify production health. One command from "approved" to "verified in production." | | [`/canary`](#canary) | **SRE** | Post-deploy monitoring loop. Watches for console errors, performance regressions, and page failures using the browse daemon. | diff --git a/document-generate/SKILL.md b/document-generate/SKILL.md index 30846fc4d..24576aa76 100644 --- a/document-generate/SKILL.md +++ b/document-generate/SKILL.md @@ -19,6 +19,7 @@ triggers: - write a how-to - explain this module - docs for this project +disable-model-invocation: true --- @@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/document-generate/SKILL.md.tmpl b/document-generate/SKILL.md.tmpl index d3ef0cbc3..046103514 100644 --- a/document-generate/SKILL.md.tmpl +++ b/document-generate/SKILL.md.tmpl @@ -25,6 +25,7 @@ triggers: - write a how-to - explain this module - docs for this project +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/document-release/SKILL.md b/document-release/SKILL.md index b95873625..c302ed149 100644 --- a/document-release/SKILL.md +++ b/document-release/SKILL.md @@ -15,6 +15,7 @@ triggers: - update docs after ship - document what changed - post-ship docs +disable-model-invocation: true --- @@ -395,6 +396,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -446,6 +449,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/document-release/SKILL.md.tmpl b/document-release/SKILL.md.tmpl index 7621cb312..12977565c 100644 --- a/document-release/SKILL.md.tmpl +++ b/document-release/SKILL.md.tmpl @@ -22,6 +22,7 @@ triggers: - update docs after ship - document what changed - post-ship docs +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/freeze/SKILL.md b/freeze/SKILL.md index d6ba29b24..0e13d2a91 100644 --- a/freeze/SKILL.md +++ b/freeze/SKILL.md @@ -22,6 +22,7 @@ hooks: - type: command command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh" statusMessage: "Checking freeze boundary..." +disable-model-invocation: true --- diff --git a/freeze/SKILL.md.tmpl b/freeze/SKILL.md.tmpl index c0b31aa7f..e7b02e726 100644 --- a/freeze/SKILL.md.tmpl +++ b/freeze/SKILL.md.tmpl @@ -28,6 +28,7 @@ hooks: command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh" statusMessage: "Checking freeze boundary..." sensitive: true +disable-model-invocation: true --- # /freeze — Restrict Edits to a Directory diff --git a/gstack-upgrade/SKILL.md b/gstack-upgrade/SKILL.md index 9f0f2f7ea..6fb64d5e7 100644 --- a/gstack-upgrade/SKILL.md +++ b/gstack-upgrade/SKILL.md @@ -11,6 +11,7 @@ allowed-tools: - Read - Write - AskUserQuestion +disable-model-invocation: true --- diff --git a/gstack-upgrade/SKILL.md.tmpl b/gstack-upgrade/SKILL.md.tmpl index 5402a1da3..0fb5ed6d5 100644 --- a/gstack-upgrade/SKILL.md.tmpl +++ b/gstack-upgrade/SKILL.md.tmpl @@ -19,6 +19,7 @@ allowed-tools: - Read - Write - AskUserQuestion +disable-model-invocation: true --- # /gstack-upgrade diff --git a/gstack-upgrade/migrations/v1.27.0.0.sh b/gstack-upgrade/migrations/v1.27.0.0.sh index fb1ce73ce..b90d4c7dd 100755 --- a/gstack-upgrade/migrations/v1.27.0.0.sh +++ b/gstack-upgrade/migrations/v1.27.0.0.sh @@ -97,23 +97,24 @@ fi # Ask once (idempotent: if journal exists from a prior partial run, skip ask). if [ ! -f "$JOURNAL" ]; then - cat >&2 <512B deadlock on macOS when the + # kernel grants 512-byte pipe buffers (pipe-KVA pressure; no F_GETPIPE_SZ). + printf '%s\n' \ + '' \ + ' [v1.27.0.0] gstack-brain has been renamed to gstack-artifacts.' \ + ' This is a clearer name for what it actually holds: CEO plans, designs,' \ + ' /investigate reports, retros (i.e. artifacts, not behavioral memory).' \ + '' \ + ' This migration will:' \ + " 1. Rename your private GitHub/GitLab repo \"$OLD_REPO_NAME\" → \"$NEW_REPO_NAME\"" \ + ' 2. mv ~/.gstack-brain-remote.txt → ~/.gstack-artifacts-remote.txt' \ + ' 3. Rename gbrain_sync_mode → artifacts_sync_mode in ~/.gstack/config.yaml' \ + ' 4. Update any "## GBrain Configuration" block in CLAUDE.md' \ + ' 5. Update gbrain federated source registration (local CLI mode)' \ + ' OR print commands for your brain admin (remote MCP mode)' \ + '' \ + ' Each step is journaled so a Ctrl-C mid-flight is safe to re-run.' \ + '' >&2 if [ -t 0 ]; then printf " Proceed? [Y/n/skip-for-now]: " >&2 read -r REPLY || REPLY="" diff --git a/gstack-upgrade/migrations/v1.37.0.0.sh b/gstack-upgrade/migrations/v1.37.0.0.sh index b173f5844..5bc5a3f30 100755 --- a/gstack-upgrade/migrations/v1.37.0.0.sh +++ b/gstack-upgrade/migrations/v1.37.0.0.sh @@ -70,22 +70,23 @@ is_local_engine_missing() { } if is_remote_http_mcp && is_local_engine_missing; then - cat <<'NOTICE' - - ┌──────────────────────────────────────────────────────────────────┐ - │ gstack v1.37.0.0 — split-engine gbrain │ - │ │ - │ Symbol-aware code search is now available on this machine. │ - │ Your remote brain at gbrain MCP keeps working as today; you can │ - │ add a tiny local PGLite (~30s, no accounts) for `gbrain │ - │ code-def` / `code-refs` / `code-callers` queries per worktree. │ - │ │ - │ Run /setup-gbrain to opt in at Step 4.5. Or skip this notice │ - │ permanently: │ - │ gstack-config set local_code_index_offered true │ - └──────────────────────────────────────────────────────────────────┘ - -NOTICE + # printf, not a heredoc: bash 5.3 heredocs >512B deadlock on macOS when the + # kernel grants 512-byte pipe buffers (pipe-KVA pressure; no F_GETPIPE_SZ). + printf '%s\n' \ + '' \ + ' ┌──────────────────────────────────────────────────────────────────┐' \ + ' │ gstack v1.37.0.0 — split-engine gbrain │' \ + ' │ │' \ + ' │ Symbol-aware code search is now available on this machine. │' \ + ' │ Your remote brain at gbrain MCP keeps working as today; you can │' \ + ' │ add a tiny local PGLite (~30s, no accounts) for `gbrain │' \ + ' │ code-def` / `code-refs` / `code-callers` queries per worktree. │' \ + ' │ │' \ + ' │ Run /setup-gbrain to opt in at Step 4.5. Or skip this notice │' \ + ' │ permanently: │' \ + ' │ gstack-config set local_code_index_offered true │' \ + ' └──────────────────────────────────────────────────────────────────┘' \ + '' fi # Always touch done so we don't print again, regardless of state-match outcome. diff --git a/gstack/llms.txt b/gstack/llms.txt index efe522f90..3d87c4b04 100644 --- a/gstack/llms.txt +++ b/gstack/llms.txt @@ -52,6 +52,7 @@ Conventions: - [/plan-devex-review](plan-devex-review/SKILL.md): Interactive developer experience plan review. - [/plan-eng-review](plan-eng-review/SKILL.md): Eng manager-mode plan review. - [/plan-tune](plan-tune/SKILL.md): Self-tuning question sensitivity + developer psychographic for gstack (v1: observational). +- [/pr-prep](pr-prep/SKILL.md): Pre-PR upstream duplicate audit. - [/qa](qa/SKILL.md): Systematically QA test a web application and fix bugs found. - [/qa-only](qa-only/SKILL.md): Report-only QA testing. - [/retro](retro/SKILL.md): Weekly engineering retrospective. diff --git a/guard/SKILL.md b/guard/SKILL.md index d9ae63de8..1b9e3d1a7 100644 --- a/guard/SKILL.md +++ b/guard/SKILL.md @@ -27,6 +27,7 @@ hooks: - type: command command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh" statusMessage: "Checking freeze boundary..." +disable-model-invocation: true --- diff --git a/guard/SKILL.md.tmpl b/guard/SKILL.md.tmpl index 3d34ee0c1..a88478c48 100644 --- a/guard/SKILL.md.tmpl +++ b/guard/SKILL.md.tmpl @@ -33,6 +33,7 @@ hooks: command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh" statusMessage: "Checking freeze boundary..." sensitive: true +disable-model-invocation: true --- # /guard — Full Safety Mode diff --git a/health/SKILL.md b/health/SKILL.md index e68199dec..cc15dd069 100644 --- a/health/SKILL.md +++ b/health/SKILL.md @@ -15,6 +15,7 @@ allowed-tools: - Glob - Grep - AskUserQuestion +disable-model-invocation: true --- @@ -393,6 +394,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -444,6 +447,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/health/SKILL.md.tmpl b/health/SKILL.md.tmpl index f92eb7347..4ee7e197d 100644 --- a/health/SKILL.md.tmpl +++ b/health/SKILL.md.tmpl @@ -20,6 +20,7 @@ allowed-tools: - Glob - Grep - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/investigate/SKILL.md b/investigate/SKILL.md index 5d54b4256..6b53b6a93 100644 --- a/investigate/SKILL.md +++ b/investigate/SKILL.md @@ -432,6 +432,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -483,6 +485,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/ios-clean/SKILL.md b/ios-clean/SKILL.md index 6c466896b..b984f04b8 100644 --- a/ios-clean/SKILL.md +++ b/ios-clean/SKILL.md @@ -14,6 +14,7 @@ triggers: - clean the ios debug bridge - remove debugbridge - strip the gstack ios instrumentation +disable-model-invocation: true --- @@ -395,6 +396,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -446,6 +449,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/ios-clean/SKILL.md.tmpl b/ios-clean/SKILL.md.tmpl index 21a1d5495..8ca35d0fc 100644 --- a/ios-clean/SKILL.md.tmpl +++ b/ios-clean/SKILL.md.tmpl @@ -25,6 +25,7 @@ triggers: - clean the ios debug bridge - remove debugbridge - strip the gstack ios instrumentation +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/ios-design-review/SKILL.md b/ios-design-review/SKILL.md index 904da7589..adfccd514 100644 --- a/ios-design-review/SKILL.md +++ b/ios-design-review/SKILL.md @@ -13,6 +13,7 @@ triggers: - review the ios design - audit the iphone app visuals - design qa the ios app +disable-model-invocation: true --- @@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/ios-design-review/SKILL.md.tmpl b/ios-design-review/SKILL.md.tmpl index dd9e2518f..302ea7259 100644 --- a/ios-design-review/SKILL.md.tmpl +++ b/ios-design-review/SKILL.md.tmpl @@ -26,6 +26,7 @@ triggers: - review the ios design - audit the iphone app visuals - design qa the ios app +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/ios-fix/SKILL.md b/ios-fix/SKILL.md index 3ddae1ac0..e983b89a5 100644 --- a/ios-fix/SKILL.md +++ b/ios-fix/SKILL.md @@ -15,6 +15,7 @@ triggers: - fix this ios bug - patch the iphone app - auto-fix the ios issue +disable-model-invocation: true --- @@ -398,6 +399,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -449,6 +452,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/ios-fix/SKILL.md.tmpl b/ios-fix/SKILL.md.tmpl index 94655e282..f8376a46d 100644 --- a/ios-fix/SKILL.md.tmpl +++ b/ios-fix/SKILL.md.tmpl @@ -27,6 +27,7 @@ triggers: - fix this ios bug - patch the iphone app - auto-fix the ios issue +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/ios-qa/SKILL.md b/ios-qa/SKILL.md index 24624be5f..568e7c442 100644 --- a/ios-qa/SKILL.md +++ b/ios-qa/SKILL.md @@ -17,6 +17,7 @@ triggers: - test my ios app - find bugs on the device - qa the ios app +disable-model-invocation: true --- @@ -401,6 +402,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -452,6 +455,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/ios-qa/SKILL.md.tmpl b/ios-qa/SKILL.md.tmpl index 78f9454b1..ddb32f72f 100644 --- a/ios-qa/SKILL.md.tmpl +++ b/ios-qa/SKILL.md.tmpl @@ -30,6 +30,7 @@ triggers: - test my ios app - find bugs on the device - qa the ios app +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/ios-sync/SKILL.md b/ios-sync/SKILL.md index 95e0bca0a..a019dee7c 100644 --- a/ios-sync/SKILL.md +++ b/ios-sync/SKILL.md @@ -15,6 +15,7 @@ triggers: - resync the ios debug bridge - regenerate ios accessors - update the gstack ios instrumentation +disable-model-invocation: true --- @@ -395,6 +396,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -446,6 +449,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/ios-sync/SKILL.md.tmpl b/ios-sync/SKILL.md.tmpl index add54c3d8..4f6364768 100644 --- a/ios-sync/SKILL.md.tmpl +++ b/ios-sync/SKILL.md.tmpl @@ -25,6 +25,7 @@ triggers: - resync the ios debug bridge - regenerate ios accessors - update the gstack ios instrumentation +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/land-and-deploy/SKILL.md b/land-and-deploy/SKILL.md index 54ebf52c0..09f9584d5 100644 --- a/land-and-deploy/SKILL.md +++ b/land-and-deploy/SKILL.md @@ -390,6 +390,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -441,6 +443,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/landing-report/SKILL.md b/landing-report/SKILL.md index 8f7e6e210..c1fa184f6 100644 --- a/landing-report/SKILL.md +++ b/landing-report/SKILL.md @@ -11,6 +11,7 @@ triggers: allowed-tools: - Bash - Read +disable-model-invocation: true --- @@ -391,6 +392,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -442,6 +445,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/landing-report/SKILL.md.tmpl b/landing-report/SKILL.md.tmpl index 32a8cc1ab..a437a54f1 100644 --- a/landing-report/SKILL.md.tmpl +++ b/landing-report/SKILL.md.tmpl @@ -17,6 +17,7 @@ allowed-tools: - Bash - Read sensitive: false +disable-model-invocation: true --- # /landing-report — Version Queue Dashboard diff --git a/learn/SKILL.md b/learn/SKILL.md index a0c6ae053..cc5f030cf 100644 --- a/learn/SKILL.md +++ b/learn/SKILL.md @@ -393,6 +393,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -444,6 +446,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/make-pdf/SKILL.md b/make-pdf/SKILL.md index 600eb47ca..045a710fd 100644 --- a/make-pdf/SKILL.md +++ b/make-pdf/SKILL.md @@ -12,6 +12,7 @@ allowed-tools: - Bash - Read - AskUserQuestion +disable-model-invocation: true --- diff --git a/make-pdf/SKILL.md.tmpl b/make-pdf/SKILL.md.tmpl index 9133a711d..e2aee6466 100644 --- a/make-pdf/SKILL.md.tmpl +++ b/make-pdf/SKILL.md.tmpl @@ -26,6 +26,7 @@ allowed-tools: - Bash - Read - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 83161b8ca..5b23b1d8a 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -428,6 +428,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -479,6 +481,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/open-gstack-browser/SKILL.md b/open-gstack-browser/SKILL.md index 28fb1ddb2..aa53e538f 100644 --- a/open-gstack-browser/SKILL.md +++ b/open-gstack-browser/SKILL.md @@ -11,6 +11,7 @@ allowed-tools: - Read - AskUserQuestion +disable-model-invocation: true --- @@ -390,6 +391,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -441,6 +444,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/open-gstack-browser/SKILL.md.tmpl b/open-gstack-browser/SKILL.md.tmpl index ef91a5278..aebc8b3e7 100644 --- a/open-gstack-browser/SKILL.md.tmpl +++ b/open-gstack-browser/SKILL.md.tmpl @@ -18,6 +18,7 @@ allowed-tools: - Read - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/pair-agent/SKILL.md b/pair-agent/SKILL.md index eed9d171a..e3493d776 100644 --- a/pair-agent/SKILL.md +++ b/pair-agent/SKILL.md @@ -11,6 +11,7 @@ allowed-tools: - Read - AskUserQuestion +disable-model-invocation: true --- @@ -392,6 +393,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -443,6 +446,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/pair-agent/SKILL.md.tmpl b/pair-agent/SKILL.md.tmpl index 75ed42d59..5619fcda5 100644 --- a/pair-agent/SKILL.md.tmpl +++ b/pair-agent/SKILL.md.tmpl @@ -22,6 +22,7 @@ allowed-tools: - Read - AskUserQuestion +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index 3d3208bee..939b3734f 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -422,6 +422,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -473,6 +475,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md index e81f7f12a..c2a8ad692 100644 --- a/plan-design-review/SKILL.md +++ b/plan-design-review/SKILL.md @@ -394,6 +394,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -445,6 +447,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/plan-devex-review/SKILL.md b/plan-devex-review/SKILL.md index 20a32da8b..f889634c4 100644 --- a/plan-devex-review/SKILL.md +++ b/plan-devex-review/SKILL.md @@ -17,6 +17,7 @@ triggers: - developer experience review - dx plan review - check developer onboarding +disable-model-invocation: true --- @@ -400,6 +401,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -451,6 +454,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/plan-devex-review/SKILL.md.tmpl b/plan-devex-review/SKILL.md.tmpl index 1ef723c10..8d0266334 100644 --- a/plan-devex-review/SKILL.md.tmpl +++ b/plan-devex-review/SKILL.md.tmpl @@ -32,6 +32,7 @@ triggers: - developer experience review - dx plan review - check developer onboarding +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index 5557a33fa..d0de97b77 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -398,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -449,6 +451,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/plan-tune/SKILL.md b/plan-tune/SKILL.md index f49b66fac..2e1c0e660 100644 --- a/plan-tune/SKILL.md +++ b/plan-tune/SKILL.md @@ -19,6 +19,7 @@ allowed-tools: - AskUserQuestion - Glob - Grep +disable-model-invocation: true --- @@ -403,6 +404,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.` +Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: =X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect. + Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`. Neutral posture: `Recommendation: — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE. @@ -454,6 +457,7 @@ Before calling AskUserQuestion, verify: - [ ] ELI10 paragraph present (stakes line too) - [ ] Recommendation line present with concrete reason - [ ] Completeness scored (coverage) OR kind-note present (kind) +- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select) - [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape) - [ ] (recommended) label on one option (even for neutral-posture) - [ ] Dual-scale effort labels on effort-bearing options (human / CC) diff --git a/plan-tune/SKILL.md.tmpl b/plan-tune/SKILL.md.tmpl index dc1214d4c..d4f1bd5da 100644 --- a/plan-tune/SKILL.md.tmpl +++ b/plan-tune/SKILL.md.tmpl @@ -31,6 +31,7 @@ allowed-tools: - AskUserQuestion - Glob - Grep +disable-model-invocation: true --- {{PREAMBLE}} diff --git a/pr-prep/SKILL.md b/pr-prep/SKILL.md new file mode 100644 index 000000000..2daf768e5 --- /dev/null +++ b/pr-prep/SKILL.md @@ -0,0 +1,1262 @@ +--- +name: pr-prep +preamble-tier: 4 +version: 0.1.0 +description: Pre-PR upstream duplicate audit. (gstack) +allowed-tools: + - Bash + - Read + - Grep + - Glob + - AskUserQuestion +triggers: + - pr-prep + - audit my PR + - check for duplicates + - upstream check + - pre-PR audit + - is this already filed + - dup PR check +disable-model-invocation: true +--- + + + + +## When to invoke this skill + +Walks `git log base..HEAD`, derives +search keywords from commit subjects + changed file paths, queries +upstream issues + PRs via `gh`, scores each commit against upstream +collisions (EXACT_DUP / OVERLAP / SIBLING / CLEAN), and refuses to +proceed when EXACT_DUP found. Use when asked to "audit my PR", +"check for duplicates", "pr-prep", "is this already filed", +"upstream check before PR", or "pre-PR audit". +Proactively invoke this skill (do NOT skip the audit) before any +`gh pr create` against a tracked upstream repo. Hooks into /ship +as Step 0. + +## Preamble (run first) + +```bash +_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +[ -n "$_UPD" ] && echo "$_UPD" || true +mkdir -p ~/.gstack/sessions +touch ~/.gstack/sessions/"$PPID" +_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') +find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true +_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") +_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") +echo "BRANCH: $_BRANCH" +_SKILL_PREFIX=$(~/.claude/skills/gstack/bin/gstack-config get skill_prefix 2>/dev/null || echo "false") +echo "PROACTIVE: $_PROACTIVE" +echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED" +echo "SKILL_PREFIX: $_SKILL_PREFIX" +source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true +REPO_MODE=${REPO_MODE:-unknown} +echo "REPO_MODE: $REPO_MODE" +_SESSION_KIND=$(~/.claude/skills/gstack/bin/gstack-session-kind 2>/dev/null || echo "interactive") +case "$_SESSION_KIND" in spawned|headless|interactive) ;; *) _SESSION_KIND="interactive" ;; esac +echo "SESSION_KIND: $_SESSION_KIND" +# Conductor host: AskUserQuestion is unreliable here (native disabled, MCP +# variant flaky), so skills render decisions as prose instead of calling the +# tool. Gated on !headless so an eval/CI run INSIDE Conductor (GSTACK_HEADLESS) +# still BLOCKs rather than rendering prose to nobody. +if [ "$_SESSION_KIND" != "headless" ] && { [ -n "${CONDUCTOR_WORKSPACE_PATH:-}" ] || [ -n "${CONDUCTOR_PORT:-}" ]; }; then + echo "CONDUCTOR_SESSION: true" +fi +_ACTIVATED=$([ -f ~/.gstack/.activated ] && echo "yes" || echo "no") +_FIRST_LOOP_SHOWN=$([ -f ~/.gstack/.first-loop-tip-shown ] && echo "yes" || echo "no") +echo "ACTIVATED: $_ACTIVATED" +echo "FIRST_LOOP_SHOWN: $_FIRST_LOOP_SHOWN" +# First-run project detection: run the detector ONLY on the first-ever skill run +# (ACTIVATED=no, interactive) so it stays off the hot path for every run after. +_FIRST_TASK="" +if [ "$_ACTIVATED" = "no" ] && [ "$_SESSION_KIND" != "headless" ]; then + _FIRST_TASK=$(~/.claude/skills/gstack/bin/gstack-first-task-detect 2>/dev/null || true) +fi +echo "FIRST_TASK: $_FIRST_TASK" +_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") +echo "LAKE_INTRO: $_LAKE_SEEN" +_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") +_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":"pr-prep","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(_repo=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null | tr -cd 'a-zA-Z0-9._-'); echo "${_repo:-unknown}")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true +fi +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 + ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true + fi + rm -f "$_PF" 2>/dev/null || true + fi + break +done +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 + _LEARN_COUNT=$(wc -l < "$_LEARN_FILE" 2>/dev/null | tr -d ' ') + echo "LEARNINGS: $_LEARN_COUNT entries loaded" + if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then + ~/.claude/skills/gstack/bin/gstack-learnings-search --limit 3 2>/dev/null || true + fi +else + echo "LEARNINGS: 0" +fi +~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"pr-prep","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null & +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" +_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" +# Plan-mode hint for skills like /spec that branch behavior on plan-mode state. +# Claude Code exposes plan mode via system reminders; we detect best-effort +# from CLAUDE_PLAN_FILE (set by the harness when plan mode is active) and +# fall back to "inactive". Codex hosts and Claude execution mode both end up +# inactive, which is the safe default (defaults to file+execute pipeline). +if [ -n "${CLAUDE_PLAN_FILE:-}${GSTACK_PLAN_MODE_FORCE:-}" ]; then + export GSTACK_PLAN_MODE="active" +elif [ "${GSTACK_PLAN_MODE:-}" = "active" ]; then + export GSTACK_PLAN_MODE="active" +else + export GSTACK_PLAN_MODE="inactive" +fi +echo "GSTACK_PLAN_MODE: $GSTACK_PLAN_MODE" +[ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true +``` + +## 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 (any variant — `mcp__*__AskUserQuestion` or native; see "AskUserQuestion Format → Tool resolution") satisfies plan mode's end-of-turn requirement. If AskUserQuestion is unavailable or a call fails, follow the AskUserQuestion Format failure fallback: `headless` → BLOCKED; `interactive` → the prose fallback (also satisfies end-of-turn). 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 `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 `SKILL_PREFIX` is `"true"`, suggest/invoke `/gstack-*` names. Disk paths stay `~/.claude/skills/gstack/[skill-name]/SKILL.md`. + +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 Ocean** 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 yes. Always run `touch`. + +If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: ask telemetry once via AskUserQuestion: + +> Help gstack get better. Share usage data only: skill, duration, crashes, stable device ID. No code or file paths. Your repo name is recorded locally only and stripped before any upload. + +Options: +- A) Help gstack get better! (recommended) +- B) No thanks + +If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` + +If B: ask follow-up: + +> Anonymous mode sends only aggregate usage, no unique ID. + +Options: +- A) Sure, anonymous is fine +- B) No thanks, fully off + +If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` + +Always run: +```bash +touch ~/.gstack/.telemetry-prompted +``` + +Skip if `TEL_PROMPTED` is `yes`. + +If `PROACTIVE_PROMPTED` is `no` AND `TEL_PROMPTED` is `yes`: ask once: + +> Let gstack proactively suggest skills, like /qa for "does this work?" or /investigate for bugs? + +Options: +- A) Keep it on (recommended) +- B) Turn it off — I'll type /commands myself + +If A: run `~/.claude/skills/gstack/bin/gstack-config set proactive true` +If B: run `~/.claude/skills/gstack/bin/gstack-config set proactive false` + +Always run: +```bash +touch ~/.gstack/.proactive-prompted +``` + +Skip if `PROACTIVE_PROMPTED` is `yes`. + +## First-run guidance (one-time) + +If `ACTIVATED` is `no` (first skill run on this machine) AND the preamble printed a non-empty `FIRST_TASK:` value that is NOT `nongit`: show ONE short, project-specific line mapped from the token, as a heads-up, then CONTINUE with whatever the user actually asked — do NOT halt their task. Map the token: `greenfield` → "Fresh repo — shape it first with `/spec` or `/office-hours`." `code_node`/`code_python`/`code_rust`/`code_go`/`code_ruby`/`code_ios` → "There's code here — `/qa` to see it work, or `/investigate` if something's off." `branch_ahead` → "Unshipped work on this branch — `/review` then `/ship`." `dirty_default` → "Uncommitted changes — `/review` before committing." `clean_default` → "Pick one: `/spec`, `/investigate`, or `/qa`." Then substitute the token you saw for TASK_TOKEN and run (best-effort), and mark activated: +```bash +~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type first_task_scaffold_shown --skill "TASK_TOKEN" --outcome shown 2>/dev/null || true +touch ~/.gstack/.activated 2>/dev/null || true +``` + +If `ACTIVATED` is `no` but `FIRST_TASK:` is empty or `nongit` (headless, non-git, or nothing actionable): show nothing, just run `touch ~/.gstack/.activated 2>/dev/null || true`. + +Else if `ACTIVATED` is `yes` AND `FIRST_LOOP_SHOWN` is `no`: say once as a heads-up (then continue): + +> Tip: gstack pays off when you complete one loop — **plan → review → ship**. A common first loop: `/office-hours` or `/spec` to shape it, `/plan-eng-review` to lock it, then `/ship`. + +Then run `touch ~/.gstack/.first-loop-tip-shown 2>/dev/null || true`. + +Skip this section if `ACTIVATED` and `FIRST_LOOP_SHOWN` are both `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. + +Use AskUserQuestion: + +> gstack works best when your project's CLAUDE.md includes skill routing rules. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- B) No thanks, I'll invoke skills manually + +If A: Append this section to the end of CLAUDE.md: + +```markdown + +## Skill routing + +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/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 +- Author a backlog-ready spec/issue → invoke /spec +``` + +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` 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." + +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: +- Do NOT use AskUserQuestion for interactive prompts. Auto-choose the recommended option. +- Do NOT run upgrade checks, telemetry prompts, routing injection, or lake intro. +- Focus on completing the task and reporting results via prose output. +- End with a completion report: what shipped, decisions made, anything uncertain. + +## AskUserQuestion Format + +### Tool resolution (read first) + +"AskUserQuestion" can resolve to two tools at runtime: the **host MCP variant** (e.g. `mcp__conductor__AskUserQuestion` — appears in your tool list when the host registers it) or the **native** Claude Code tool. + +**Conductor rule (read before the MCP rule):** if `CONDUCTOR_SESSION: true` was echoed by the preamble, do NOT call AskUserQuestion at all — neither native nor any `mcp__*__AskUserQuestion` variant. Render EVERY decision brief as the **prose form** below and STOP. This is proactive, not a reaction to a failure: Conductor disables native AUQ and its MCP variant is flaky (it returns `[Tool result missing due to internal error]`), so prose is the reliable path. **Auto-decide preferences still apply first:** if a `[plan-tune auto-decide]