From 66c09644a70a849447291cd8e6286b64203933c1 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sun, 29 Mar 2026 23:35:17 -0600 Subject: [PATCH] =?UTF-8?q?feat:=20composable=20skills=20=E2=80=94=20INVOK?= =?UTF-8?q?E=5FSKILL=20resolver=20+=20factoring=20infrastructure=20(v0.13.?= =?UTF-8?q?7.0)=20(#644)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add parameterized resolver support to gen-skill-docs Extend the placeholder regex from {{WORD}} to {{WORD:arg1:arg2}}, enabling parameterized resolvers like {{INVOKE_SKILL:plan-ceo-review}}. - Widen ResolverFn type to accept optional args?: string[] - Update RESOLVERS record to use ResolverFn type - Both replacement and unresolved-check regexes updated - Fully backward compatible: existing {{WORD}} patterns unchanged Co-Authored-By: Claude Opus 4.6 (1M context) * feat: add INVOKE_SKILL resolver for composable skill loading New composition.ts resolver module that emits prose instructing Claude to read another skill's SKILL.md and follow it, skipping preamble sections. Supports optional skip= parameter for additional sections. Usage: {{INVOKE_SKILL:plan-ceo-review}} or {{INVOKE_SKILL:plan-ceo-review:skip=Outside Voice}} Co-Authored-By: Claude Opus 4.6 (1M context) * feat: use frontmatter name: for skill symlinks and Codex paths Patch all 3 name-derivation paths to read name: from SKILL.md frontmatter instead of relying solely on directory basenames. This enables directory names that differ from invocation names (e.g., run-tests/ directory with name: test). - setup: link_claude_skill_dirs reads name: via grep, falls back to basename - gen-skill-docs.ts: codexSkillName uses frontmatter name for Codex output paths - gen-skill-docs.ts: moved frontmatter extraction before Codex path logic Co-Authored-By: Claude Opus 4.6 (1M context) * feat: extract CHANGELOG_WORKFLOW resolver from /ship Move changelog generation logic into a reusable resolver. The resolver is changelog-only (no version bump per Codex review recommendation). Adds voice rules inline. /ship Step 5 now uses {{CHANGELOG_WORKFLOW}}. Co-Authored-By: Claude Opus 4.6 (1M context) * refactor: use INVOKE_SKILL resolver for plan-ceo-review office-hours fallback Replace inline skill loading prose (read file, skip sections) with {{INVOKE_SKILL:office-hours}} in the mid-session detection path. The BENEFITS_FROM prerequisite offer is unchanged (separate use case). Co-Authored-By: Claude Opus 4.6 (1M context) * refactor: BENEFITS_FROM resolver delegates to INVOKE_SKILL Eliminate duplicated skip-list logic by having generateBenefitsFrom call generateInvokeSkill internally. The wrapper (AskUserQuestion, design doc re-check) stays in BENEFITS_FROM. The loading instructions (read file, skip sections, error handling) come from INVOKE_SKILL. Co-Authored-By: Claude Opus 4.6 (1M context) * test: add resolver tests for INVOKE_SKILL, CHANGELOG_WORKFLOW, parameterized args 12 new tests covering: - INVOKE_SKILL: template placeholder, default skip list, error handling, BENEFITS_FROM delegation - CHANGELOG_WORKFLOW: content, cross-check, voice guidance, format - Parameterized resolver infra: colon-separated args processing, no unresolved placeholders across all generated SKILL.md files Co-Authored-By: Claude Opus 4.6 (1M context) * chore: bump version and changelog (v0.13.7.0) Co-Authored-By: Claude Opus 4.6 * fix: journey routing tests — CLAUDE.md routing rules + stronger descriptions Three journey E2E tests (ideation, ship, debug) were failing because Claude answered directly instead of invoking the Skill tool. Root cause: skill descriptions in system-reminder are too weak to override Claude's default behavior for tasks it can handle natively. Fix has two parts: 1. CLAUDE.md routing rules in test workdir — Claude weighs project-level instructions higher than skill description metadata 2. "Proactively invoke" (not "suggest") in office-hours, investigate, ship descriptions — reinforces the routing signal 10/10 journey tests now pass (was 7/10). Co-Authored-By: Claude Opus 4.6 (1M context) * feat: one-time CLAUDE.md routing injection prompt Add a preamble section that checks if the project's CLAUDE.md has skill routing rules. If not (and user hasn't declined), asks once via AskUserQuestion to inject a "## Skill routing" section. Root cause: skill descriptions in system-reminder metadata are too weak to reliably trigger proactive Skill tool invocation. CLAUDE.md project instructions carry higher weight in Claude's decision making. - Preamble bash checks for "## Skill routing" in CLAUDE.md - Stores decline in gstack-config (routing_declined=true) - Only asks once per project (HAS_ROUTING check + config check) Co-Authored-By: Claude Opus 4.6 (1M context) * feat: annotated config file + routing injection tests gstack-config now writes a documented header on first config creation with every supported key explained (proactive, telemetry, auto_upgrade, skill_prefix, routing_declined, codex_reviews, skip_eng_review, etc.). Users can edit ~/.gstack/config.yaml directly, anytime. Also fixes grep to use ^KEY: anchoring so commented header lines don't shadow real config values. Tests added: - 7 new gstack-config tests (annotated header, no duplication, comment safety, routing_declined get/set/reset) - 6 new gen-skill-docs tests (preamble routing injection: bash checks, config reads, AskUserQuestion, decline persistence, routing rules) Co-Authored-By: Claude Opus 4.6 (1M context) * chore: bump to v0.13.9.0, separate CHANGELOG from main's releases Split our branch's changes into a new 0.13.9.0 entry instead of jamming them into 0.13.7.0 which already landed on main as "Community Wave." Co-Authored-By: Claude Opus 4.6 (1M context) * docs: clarify branch-scoped VERSION/CHANGELOG after merging main Add explicit rules: merging main doesn't mean adopting main's version. Branch always gets its own entry on top with a higher version number. Three-point checklist after every merge. Co-Authored-By: Claude Opus 4.6 (1M context) * fix: put our 0.13.9.0 entry on top of CHANGELOG Newest version goes on top. Our branch lands next, so our entry must be above main's 0.13.8.0. Co-Authored-By: Claude Opus 4.6 (1M context) * fix: restore missing 0.13.7.0 Community Wave entry Accidentally dropped the 0.13.7.0 entry when reordering. All entries now present: 0.13.9.0 > 0.13.8.0 > 0.13.7.0 > 0.13.6.0. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: add CHANGELOG integrity check rule After any edit that moves/adds/removes entries, grep for version headers and verify no gaps or duplicates before committing. Prevents accidentally dropping entries during reordering. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 23 +++++ CLAUDE.md | 17 ++++ SKILL.md | 104 ++++++++++++++++++----- SKILL.md.tmpl | 53 +++++++----- VERSION | 2 +- autoplan/SKILL.md | 66 ++++++++++++-- benchmark/SKILL.md | 51 +++++++++++ bin/gstack-config | 42 ++++++++- browse/SKILL.md | 51 +++++++++++ browse/test/gstack-config.test.ts | 58 +++++++++++++ canary/SKILL.md | 51 +++++++++++ codex/SKILL.md | 51 +++++++++++ connect-chrome/SKILL.md | 51 +++++++++++ cso/SKILL.md | 51 +++++++++++ design-consultation/SKILL.md | 51 +++++++++++ design-review/SKILL.md | 51 +++++++++++ design-shotgun/SKILL.md | 51 +++++++++++ document-release/SKILL.md | 51 +++++++++++ investigate/SKILL.md | 56 +++++++++++- investigate/SKILL.md.tmpl | 5 +- land-and-deploy/SKILL.md | 51 +++++++++++ learn/SKILL.md | 51 +++++++++++ office-hours/SKILL.md | 57 ++++++++++++- office-hours/SKILL.md.tmpl | 6 +- package.json | 2 +- plan-ceo-review/SKILL.md | 91 +++++++++++++++++--- plan-ceo-review/SKILL.md.tmpl | 7 +- plan-design-review/SKILL.md | 51 +++++++++++ plan-eng-review/SKILL.md | 66 ++++++++++++-- qa-only/SKILL.md | 51 +++++++++++ qa/SKILL.md | 51 +++++++++++ retro/SKILL.md | 51 +++++++++++ review/SKILL.md | 51 +++++++++++ scripts/gen-skill-docs.ts | 35 +++++--- scripts/resolvers/composition.ts | 48 +++++++++++ scripts/resolvers/index.ts | 9 +- scripts/resolvers/preamble.ts | 54 ++++++++++++ scripts/resolvers/review.ts | 19 ++--- scripts/resolvers/types.ts | 3 + scripts/resolvers/utility.ts | 44 ++++++++++ setup | 9 +- setup-browser-cookies/SKILL.md | 51 +++++++++++ setup-deploy/SKILL.md | 51 +++++++++++ ship/SKILL.md | 59 ++++++++++++- ship/SKILL.md.tmpl | 46 +--------- test/gen-skill-docs.test.ts | 137 +++++++++++++++++++++++++++++- test/skill-routing-e2e.test.ts | 29 +++++-- test/skill-validation.test.ts | 4 +- 48 files changed, 1952 insertions(+), 168 deletions(-) create mode 100644 scripts/resolvers/composition.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b1c40875d26e41475c53d04428b86069665f0e54..e61d3f02b5bd286b38df50d7c0ccb159878a37ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [0.13.9.0] - 2026-03-29 — Composable Skills + +Skills can now load other skills inline. Write `{{INVOKE_SKILL:office-hours}}` in a template and the generator emits the right "read file, skip preamble, follow instructions" prose automatically. Handles host-aware paths and customizable skip lists. + +### Added + +- **`{{INVOKE_SKILL:skill-name}}` resolver.** Composable skill loading as a first-class resolver. Emits host-aware prose that tells Claude or Codex to read another skill's SKILL.md and follow it inline, skipping preamble sections. Supports optional `skip=` parameter for additional sections to skip. +- **Parameterized resolver support.** The placeholder regex now handles `{{NAME:arg1:arg2}}`, enabling resolvers that take arguments at generation time. Fully backward compatible with existing `{{NAME}}` patterns. +- **`{{CHANGELOG_WORKFLOW}}` resolver.** Changelog generation logic extracted from /ship into a reusable resolver. Includes voice guidance ("lead with what the user can now do") inline. +- **Frontmatter `name:` for skill registration.** Setup script and gen-skill-docs now read `name:` from SKILL.md frontmatter for symlink naming. Enables directory names that differ from invocation names (e.g., `run-tests/` directory registered as `/test`). +- **Proactive skill routing.** Skills now ask once to add routing rules to your project's CLAUDE.md. This makes Claude invoke the right skill automatically instead of answering directly. Your choice is remembered in `~/.gstack/config.yaml`. +- **Annotated config file.** `~/.gstack/config.yaml` now gets a documented header on first creation explaining every setting. Edit it anytime. + +### Changed + +- **BENEFITS_FROM now delegates to INVOKE_SKILL.** Eliminated duplicated skip-list logic. The prerequisite offer wrapper stays in BENEFITS_FROM, but the actual "read and follow" instructions come from INVOKE_SKILL. +- **/plan-ceo-review mid-session fallback uses INVOKE_SKILL.** The "user can't articulate the problem, offer /office-hours" path now uses the composable resolver instead of inline prose. +- **Stronger routing language.** office-hours, investigate, and ship descriptions now say "Proactively invoke" instead of "Proactively suggest" for more reliable automatic skill invocation. + +### Fixed + +- **Config grep anchored to line start.** Commented header lines no longer shadow real config values. + ## [0.13.8.0] - 2026-03-29 — Security Audit Round 2 Browse output is now wrapped in trust boundary markers so agents can tell page content from tool output. Markers are escape-proof. The Chrome extension validates message senders. CDP binds to localhost only. Bun installs use checksum verification. diff --git a/CLAUDE.md b/CLAUDE.md index 0ea420c755c052251307b4341c201e617cdd49ad..33741f868a738c2b5382cb681eb06933c1c7d2d9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -258,6 +258,23 @@ not what was already on main. 3. Does an existing entry on this branch already cover earlier work? (If yes, replace it with one unified entry for the final version.) +**Merging main does NOT mean adopting main's version.** When you merge origin/main into +a feature branch, main may bring new CHANGELOG entries and a higher VERSION. Your branch +still needs its OWN version bump on top. If main is at v0.13.8.0 and your branch adds +features, bump to v0.13.9.0 with a new entry. Never jam your changes into an entry that +already landed on main. Your entry goes on top because your branch lands next. + +**After merging main, always check:** +- Does CHANGELOG have your branch's own entry separate from main's entries? +- Is VERSION higher than main's VERSION? +- Is your entry the topmost entry in CHANGELOG (above main's latest)? +If any answer is no, fix it before continuing. + +**After any CHANGELOG edit that moves, adds, or removes entries,** immediately run +`grep "^## \[" CHANGELOG.md` and verify the full version sequence is contiguous +with no gaps or duplicates before committing. If a version is missing, the edit +broke something. Fix it before moving on. + CHANGELOG.md is **for users**, not contributors. Write it like product release notes: - Lead with what the user can now **do** that they couldn't before. Sell the feature. diff --git a/SKILL.md b/SKILL.md index cb5942526b4fc2e487016ccf3463b0a431c7d45e..e0e6ccca73fb57f1ba7ce083004abc093ce7d84a 100644 --- a/SKILL.md +++ b/SKILL.md @@ -68,6 +68,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -149,6 +157,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice **Tone:** direct, concrete, sharp, never corporate, never academic. Sound like a builder, not a consultant. Name the file, the function, the command. No filler, no throat-clearing. @@ -271,28 +322,37 @@ Then write a `## GSTACK REVIEW REPORT` section to the end of the plan file: file you are allowed to edit in plan mode. The plan file review report is part of the plan's living status. -If `PROACTIVE` is `false`: do NOT proactively suggest other gstack skills during this session. -Only run skills the user explicitly invokes. This preference persists across sessions via -`gstack-config`. - -If `PROACTIVE` is `true` (default): suggest adjacent gstack skills when relevant to the -user's workflow stage: -- Brainstorming → /office-hours -- Strategy → /plan-ceo-review -- Architecture → /plan-eng-review -- Design → /plan-design-review or /design-consultation -- Auto-review → /autoplan -- Debugging → /investigate -- QA → /qa -- Code review → /review -- Visual audit → /design-review -- Shipping → /ship -- Docs → /document-release -- Retro → /retro -- Second opinion → /codex -- Prod safety → /careful or /guard -- Scoped edits → /freeze or /unfreeze -- Upgrades → /gstack-upgrade +If `PROACTIVE` is `false`: do NOT proactively invoke or suggest other gstack skills during +this session. Only run skills the user explicitly invokes. This preference persists across +sessions via `gstack-config`. + +If `PROACTIVE` is `true` (default): **invoke the Skill tool** when the user's request +matches a skill's purpose. Do NOT answer directly when a skill exists for the task. +Use the Skill tool to invoke it. The skill has specialized workflows, checklists, and +quality gates that produce better results than answering inline. + +**Routing rules — when you see these patterns, INVOKE the skill via the Skill tool:** +- User describes a new idea, asks "is this worth building", wants to brainstorm → invoke `/office-hours` +- User asks about strategy, scope, ambition, "think bigger" → invoke `/plan-ceo-review` +- User asks to review architecture, lock in the plan → invoke `/plan-eng-review` +- User asks about design system, brand, visual identity → invoke `/design-consultation` +- User asks to review design of a plan → invoke `/plan-design-review` +- User wants all reviews done automatically → invoke `/autoplan` +- User reports a bug, error, broken behavior, asks "why is this broken" → invoke `/investigate` +- User asks to test the site, find bugs, QA → invoke `/qa` +- User asks to review code, check the diff, pre-landing review → invoke `/review` +- User asks about visual polish, design audit of a live site → invoke `/design-review` +- User asks to ship, deploy, push, create a PR → invoke `/ship` +- User asks to update docs after shipping → invoke `/document-release` +- User asks for a weekly retro, what did we ship → invoke `/retro` +- User asks for a second opinion, codex review → invoke `/codex` +- User asks for safety mode, careful mode → invoke `/careful` or `/guard` +- User asks to restrict edits to a directory → invoke `/freeze` or `/unfreeze` +- User asks to upgrade gstack → invoke `/gstack-upgrade` + +**Do NOT answer the user's question directly when a matching skill exists.** The skill +provides a structured, multi-step workflow that is always better than an ad-hoc answer. +Invoke the skill first. If no skill matches, answer directly as usual. If the user opts out of suggestions, run `gstack-config set proactive false`. If they opt back in, run `gstack-config set proactive true`. diff --git a/SKILL.md.tmpl b/SKILL.md.tmpl index fcc0900b0a1afd5c4f55839a1ffb38dcf8561e41..1c8f12a86c672f3fdb7d600b4f57981744eedf55 100644 --- a/SKILL.md.tmpl +++ b/SKILL.md.tmpl @@ -16,28 +16,37 @@ allowed-tools: {{PREAMBLE}} -If `PROACTIVE` is `false`: do NOT proactively suggest other gstack skills during this session. -Only run skills the user explicitly invokes. This preference persists across sessions via -`gstack-config`. - -If `PROACTIVE` is `true` (default): suggest adjacent gstack skills when relevant to the -user's workflow stage: -- Brainstorming → /office-hours -- Strategy → /plan-ceo-review -- Architecture → /plan-eng-review -- Design → /plan-design-review or /design-consultation -- Auto-review → /autoplan -- Debugging → /investigate -- QA → /qa -- Code review → /review -- Visual audit → /design-review -- Shipping → /ship -- Docs → /document-release -- Retro → /retro -- Second opinion → /codex -- Prod safety → /careful or /guard -- Scoped edits → /freeze or /unfreeze -- Upgrades → /gstack-upgrade +If `PROACTIVE` is `false`: do NOT proactively invoke or suggest other gstack skills during +this session. Only run skills the user explicitly invokes. This preference persists across +sessions via `gstack-config`. + +If `PROACTIVE` is `true` (default): **invoke the Skill tool** when the user's request +matches a skill's purpose. Do NOT answer directly when a skill exists for the task. +Use the Skill tool to invoke it. The skill has specialized workflows, checklists, and +quality gates that produce better results than answering inline. + +**Routing rules — when you see these patterns, INVOKE the skill via the Skill tool:** +- User describes a new idea, asks "is this worth building", wants to brainstorm → invoke `/office-hours` +- User asks about strategy, scope, ambition, "think bigger" → invoke `/plan-ceo-review` +- User asks to review architecture, lock in the plan → invoke `/plan-eng-review` +- User asks about design system, brand, visual identity → invoke `/design-consultation` +- User asks to review design of a plan → invoke `/plan-design-review` +- User wants all reviews done automatically → invoke `/autoplan` +- User reports a bug, error, broken behavior, asks "why is this broken" → invoke `/investigate` +- User asks to test the site, find bugs, QA → invoke `/qa` +- User asks to review code, check the diff, pre-landing review → invoke `/review` +- User asks about visual polish, design audit of a live site → invoke `/design-review` +- User asks to ship, deploy, push, create a PR → invoke `/ship` +- User asks to update docs after shipping → invoke `/document-release` +- User asks for a weekly retro, what did we ship → invoke `/retro` +- User asks for a second opinion, codex review → invoke `/codex` +- User asks for safety mode, careful mode → invoke `/careful` or `/guard` +- User asks to restrict edits to a directory → invoke `/freeze` or `/unfreeze` +- User asks to upgrade gstack → invoke `/gstack-upgrade` + +**Do NOT answer the user's question directly when a matching skill exists.** The skill +provides a structured, multi-step workflow that is always better than an ad-hoc answer. +Invoke the skill first. If no skill matches, answer directly as usual. If the user opts out of suggestions, run `gstack-config set proactive false`. If they opt back in, run `gstack-config set proactive true`. diff --git a/VERSION b/VERSION index f4040e84c85add60c82cb3087e4b3255a5167e3f..1ef377f37719b0a4b93db043b1e3bc2dad114320 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.13.8.0 +0.13.9.0 diff --git a/autoplan/SKILL.md b/autoplan/SKILL.md index f827fcba80d5290df420d23fc650f31bd59568c9..2754cef0759efc54851ce18435ad331ca2d8ab2f 100644 --- a/autoplan/SKILL.md +++ b/autoplan/SKILL.md @@ -77,6 +77,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -158,6 +166,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. @@ -426,10 +477,11 @@ If they choose A: Say: "Running /office-hours inline. Once the design doc is ready, I'll pick up the review right where we left off." -Read the office-hours skill file from disk using the Read tool: -`~/.claude/skills/gstack/office-hours/SKILL.md` +Read the `/office-hours` skill file at `~/.claude/skills/gstack/office-hours/SKILL.md` using the Read tool. + +**If unreadable:** Skip with "Could not load /office-hours — skipping." and continue. -Follow it inline, **skipping these sections** (already handled by the parent skill): +Follow its instructions from top to bottom, **skipping these sections** (already handled by the parent skill): - Preamble (run first) - AskUserQuestion Format - Completeness Principle — Boil the Lake @@ -437,9 +489,13 @@ Follow it inline, **skipping these sections** (already handled by the parent ski - Contributor Mode - Completion Status Protocol - Telemetry (run last) +- Step 0: Detect platform and base branch +- Review Readiness Dashboard +- Plan File Review Report +- Prerequisite Skill Offer +- Plan Status Footer -If the Read fails (file not found), say: -"Could not load /office-hours — proceeding with standard review." +Execute every other section at full depth. When the loaded skill's instructions are complete, continue with the next step below. After /office-hours completes, re-run the design doc check: ```bash diff --git a/benchmark/SKILL.md b/benchmark/SKILL.md index d2c7b4f78f412b8ce1da56d9d443863079088b3f..8fe4bc94cdb5af1a8a52474bea7376b0f3aa8976 100644 --- a/benchmark/SKILL.md +++ b/benchmark/SKILL.md @@ -70,6 +70,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -151,6 +159,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice **Tone:** direct, concrete, sharp, never corporate, never academic. Sound like a builder, not a consultant. Name the file, the function, the command. No filler, no throat-clearing. diff --git a/bin/gstack-config b/bin/gstack-config index 08549a29d946dfae4ac885219274edcc6357055a..c118a322a6f59a1528821b2d78e6f220d5b045ec 100755 --- a/bin/gstack-config +++ b/bin/gstack-config @@ -13,6 +13,38 @@ set -euo pipefail STATE_DIR="${GSTACK_STATE_DIR:-$HOME/.gstack}" CONFIG_FILE="$STATE_DIR/config.yaml" +# Annotated header for new config files. Written once on first `set`. +CONFIG_HEADER='# gstack configuration — edit freely, changes take effect on next skill run. +# Docs: https://github.com/garrytan/gstack +# +# ─── Behavior ──────────────────────────────────────────────────────── +# proactive: true # Auto-invoke skills when your request matches one. +# # Set to false to only run skills you type explicitly. +# +# routing_declined: false # Set to true to skip the CLAUDE.md routing injection +# # prompt. Set back to false to be asked again. +# +# ─── Telemetry ─────────────────────────────────────────────────────── +# telemetry: anonymous # off | anonymous | community +# # off — no data sent, no local analytics +# # anonymous — counter only, no device ID +# # community — usage data + stable device ID +# +# ─── Updates ───────────────────────────────────────────────────────── +# auto_upgrade: false # true = silently upgrade on session start +# update_check: true # false = suppress version check notifications +# +# ─── Skill naming ──────────────────────────────────────────────────── +# skill_prefix: false # true = namespace skills as /gstack-qa, /gstack-ship +# # false = short names /qa, /ship +# +# ─── Advanced ──────────────────────────────────────────────────────── +# codex_reviews: enabled # disabled = skip Codex adversarial reviews in /ship +# gstack_contributor: false # true = file field reports when gstack misbehaves +# skip_eng_review: false # true = skip eng review gate in /ship (not recommended) +# +' + case "${1:-}" in get) KEY="${2:?Usage: gstack-config get }" @@ -21,7 +53,7 @@ case "${1:-}" in echo "Error: key must contain only alphanumeric characters and underscores" >&2 exit 1 fi - grep -F "${KEY}:" "$CONFIG_FILE" 2>/dev/null | tail -1 | awk '{print $2}' | tr -d '[:space:]' || true + grep -E "^${KEY}:" "$CONFIG_FILE" 2>/dev/null | tail -1 | awk '{print $2}' | tr -d '[:space:]' || true ;; set) KEY="${2:?Usage: gstack-config set }" @@ -32,12 +64,16 @@ case "${1:-}" in exit 1 fi mkdir -p "$STATE_DIR" + # Write annotated header on first creation + if [ ! -f "$CONFIG_FILE" ]; then + printf '%s' "$CONFIG_HEADER" > "$CONFIG_FILE" + fi # Escape sed special chars in value and drop embedded newlines ESC_VALUE="$(printf '%s' "$VALUE" | head -1 | sed 's/[&/\]/\\&/g')" - if grep -qF "${KEY}:" "$CONFIG_FILE" 2>/dev/null; then + if grep -qE "^${KEY}:" "$CONFIG_FILE" 2>/dev/null; then # Portable in-place edit (BSD sed uses -i '', GNU sed uses -i without arg) _tmpfile="$(mktemp "${CONFIG_FILE}.XXXXXX")" - sed "s/^${KEY}:.*/${KEY}: ${ESC_VALUE}/" "$CONFIG_FILE" > "$_tmpfile" && mv "$_tmpfile" "$CONFIG_FILE" + sed "/^${KEY}:/s/.*/${KEY}: ${ESC_VALUE}/" "$CONFIG_FILE" > "$_tmpfile" && mv "$_tmpfile" "$CONFIG_FILE" else echo "${KEY}: ${VALUE}" >> "$CONFIG_FILE" fi diff --git a/browse/SKILL.md b/browse/SKILL.md index c9a4e4a356c41a5bd3610e1efc8b5aaa3aeef3f3..6cec51b74727e63aaeb6435e981a7325acec750a 100644 --- a/browse/SKILL.md +++ b/browse/SKILL.md @@ -70,6 +70,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -151,6 +159,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice **Tone:** direct, concrete, sharp, never corporate, never academic. Sound like a builder, not a consultant. Name the file, the function, the command. No filler, no throat-clearing. diff --git a/browse/test/gstack-config.test.ts b/browse/test/gstack-config.test.ts index d3efc1ce76289b7790b398e2ecae35908f33fd10..a00af609613817dab3f93ebc8ca9072bf9405316 100644 --- a/browse/test/gstack-config.test.ts +++ b/browse/test/gstack-config.test.ts @@ -135,4 +135,62 @@ describe('gstack-config', () => { const { stdout } = run(['get', 'test_special']); expect(stdout).toBe('a/b&c\\d'); }); + + // ─── annotated header ────────────────────────────────────── + test('first set writes annotated header with docs', () => { + run(['set', 'telemetry', 'off']); + const content = readFileSync(join(stateDir, 'config.yaml'), 'utf-8'); + expect(content).toContain('# gstack configuration'); + expect(content).toContain('edit freely'); + expect(content).toContain('proactive:'); + expect(content).toContain('telemetry:'); + expect(content).toContain('auto_upgrade:'); + expect(content).toContain('skill_prefix:'); + expect(content).toContain('routing_declined:'); + expect(content).toContain('codex_reviews:'); + expect(content).toContain('skip_eng_review:'); + }); + + test('header written only once, not duplicated on second set', () => { + run(['set', 'foo', 'bar']); + run(['set', 'baz', 'qux']); + const content = readFileSync(join(stateDir, 'config.yaml'), 'utf-8'); + const headerCount = (content.match(/# gstack configuration/g) || []).length; + expect(headerCount).toBe(1); + }); + + test('header does not break get on commented-out keys', () => { + run(['set', 'telemetry', 'community']); + // Header contains "# telemetry: anonymous" as a comment example. + // get should return the real value, not the comment. + const { stdout } = run(['get', 'telemetry']); + expect(stdout).toBe('community'); + }); + + test('existing config file is not overwritten with header', () => { + writeFileSync(join(stateDir, 'config.yaml'), 'existing: value\n'); + run(['set', 'new_key', 'new_value']); + const content = readFileSync(join(stateDir, 'config.yaml'), 'utf-8'); + expect(content).toContain('existing: value'); + expect(content).not.toContain('# gstack configuration'); + }); + + // ─── routing_declined ────────────────────────────────────── + test('routing_declined defaults to empty (not set)', () => { + const { stdout } = run(['get', 'routing_declined']); + expect(stdout).toBe(''); + }); + + test('routing_declined can be set and read', () => { + run(['set', 'routing_declined', 'true']); + const { stdout } = run(['get', 'routing_declined']); + expect(stdout).toBe('true'); + }); + + test('routing_declined can be reset to false', () => { + run(['set', 'routing_declined', 'true']); + run(['set', 'routing_declined', 'false']); + const { stdout } = run(['get', 'routing_declined']); + expect(stdout).toBe('false'); + }); }); diff --git a/canary/SKILL.md b/canary/SKILL.md index 59987e3034954fdaaafe4233d4b564f5507a005a..6197b3c42a9ab2ed9464a9510ce80d555c867cda 100644 --- a/canary/SKILL.md +++ b/canary/SKILL.md @@ -70,6 +70,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -151,6 +159,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/codex/SKILL.md b/codex/SKILL.md index a3c826212b68ec66839bbf004edca5f4b39e0bb6..a3eb12cf3aaacba13e8a53fcf74c3b1290a5d1d4 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -71,6 +71,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -152,6 +160,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/connect-chrome/SKILL.md b/connect-chrome/SKILL.md index 49abe50280ffe3589b1fd2f99234e68dc32fc685..c863b171fd96f962668c1bb1369638a355d4eabd 100644 --- a/connect-chrome/SKILL.md +++ b/connect-chrome/SKILL.md @@ -68,6 +68,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -149,6 +157,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/cso/SKILL.md b/cso/SKILL.md index 783a5ee0119ad2f355ac080b99bc5897679f786f..3945884cffd73c437f968d8974de43fa0196e02f 100644 --- a/cso/SKILL.md +++ b/cso/SKILL.md @@ -74,6 +74,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -155,6 +163,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index 25ab6fbdc25862f09ab5724f71c7ac9a5e1003fa..3901ada1d8909ec0477498cfeb3303485117824d 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -75,6 +75,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -156,6 +164,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/design-review/SKILL.md b/design-review/SKILL.md index 515efb30936adc043c513854c41708ae7df45146..c152835c7ec9e4daac2a1adc45b1290ab02bdfae 100644 --- a/design-review/SKILL.md +++ b/design-review/SKILL.md @@ -75,6 +75,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -156,6 +164,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/design-shotgun/SKILL.md b/design-shotgun/SKILL.md index ac30aa5fa5f8479bed16379ac371be3604fe5ba4..609907d607dc8c0da38ffda974fd044d3695f7ba 100644 --- a/design-shotgun/SKILL.md +++ b/design-shotgun/SKILL.md @@ -72,6 +72,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -153,6 +161,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/document-release/SKILL.md b/document-release/SKILL.md index e7f80c9e7b8b60c11c7b6eb60844d2a39e20e894..a1c6ede925043442b7b79fb355505513e596a72d 100644 --- a/document-release/SKILL.md +++ b/document-release/SKILL.md @@ -72,6 +72,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -153,6 +161,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/investigate/SKILL.md b/investigate/SKILL.md index 565cc64048d2be2fd75bf84816ab4e9ea4da8cb0..ab940d17535639b1f901e0fc2357fd1041b933fc 100644 --- a/investigate/SKILL.md +++ b/investigate/SKILL.md @@ -7,8 +7,9 @@ description: | analyze, hypothesize, implement. Iron Law: no fixes without root cause. Use when asked to "debug this", "fix this bug", "why is this broken", "investigate this error", or "root cause analysis". - Proactively suggest when the user reports errors, unexpected behavior, or - is troubleshooting why something stopped working. (gstack) + Proactively invoke this skill (do NOT debug directly) when the user reports + errors, 500 errors, stack traces, unexpected behavior, "it was working + yesterday", or is troubleshooting why something stopped working. (gstack) allowed-tools: - Bash - Read @@ -86,6 +87,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -167,6 +176,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/investigate/SKILL.md.tmpl b/investigate/SKILL.md.tmpl index 4da2a708f06b78d2851cdaec662ccb7b7a400d15..3004300e2025d401e6f10bffb69580f6730596a2 100644 --- a/investigate/SKILL.md.tmpl +++ b/investigate/SKILL.md.tmpl @@ -7,8 +7,9 @@ description: | analyze, hypothesize, implement. Iron Law: no fixes without root cause. Use when asked to "debug this", "fix this bug", "why is this broken", "investigate this error", or "root cause analysis". - Proactively suggest when the user reports errors, unexpected behavior, or - is troubleshooting why something stopped working. (gstack) + Proactively invoke this skill (do NOT debug directly) when the user reports + errors, 500 errors, stack traces, unexpected behavior, "it was working + yesterday", or is troubleshooting why something stopped working. (gstack) allowed-tools: - Bash - Read diff --git a/land-and-deploy/SKILL.md b/land-and-deploy/SKILL.md index 1276abeca077852f37ec4c27fd2c4c20ba452c72..6311ecfc7a4f795376334da1facc4489bc24b123 100644 --- a/land-and-deploy/SKILL.md +++ b/land-and-deploy/SKILL.md @@ -69,6 +69,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -150,6 +158,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/learn/SKILL.md b/learn/SKILL.md index 67fa311e7fc2acf99d2720bc56d9a39a9c0d7cce..324b4a38781ad85ebc9acd5dafe47ece744d7b80 100644 --- a/learn/SKILL.md +++ b/learn/SKILL.md @@ -72,6 +72,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -153,6 +161,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 2c6458ce86ce1f0bc146f2b78d9e3d161f30875d..75beef32c949c29bf2e6a8cd2a7eae742b26a0dd 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -9,8 +9,10 @@ description: | hackathons, learning, and open source. Saves a design doc. Use when asked to "brainstorm this", "I have an idea", "help me think through this", "office hours", or "is this worth building". - Proactively suggest when the user describes a new product idea or is exploring - whether something is worth building — before any code is written. + Proactively invoke this skill (do NOT answer directly) when the user describes + a new product idea, asks whether something is worth building, wants to think + through design decisions for something that doesn't exist yet, or is exploring + a concept before any code is written. Use before /plan-ceo-review or /plan-eng-review. (gstack) allowed-tools: - Bash @@ -77,6 +79,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -158,6 +168,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/office-hours/SKILL.md.tmpl b/office-hours/SKILL.md.tmpl index 1e340cf97ca94d67a92bb3e692e24d944a294987..ba7c3c1e5756a0c603d79759e90a3c278202098f 100644 --- a/office-hours/SKILL.md.tmpl +++ b/office-hours/SKILL.md.tmpl @@ -9,8 +9,10 @@ description: | hackathons, learning, and open source. Saves a design doc. Use when asked to "brainstorm this", "I have an idea", "help me think through this", "office hours", or "is this worth building". - Proactively suggest when the user describes a new product idea or is exploring - whether something is worth building — before any code is written. + Proactively invoke this skill (do NOT answer directly) when the user describes + a new product idea, asks whether something is worth building, wants to think + through design decisions for something that doesn't exist yet, or is exploring + a concept before any code is written. Use before /plan-ceo-review or /plan-eng-review. (gstack) allowed-tools: - Bash diff --git a/package.json b/package.json index 13b85f965b7b151015946f0ece4f54eadd43a5c8..f34218c079bd2919dd174e3fcbc4854d1fe715a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "0.13.8.0", + "version": "0.13.9.0", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index 40d03ef6ed3dbd3f741c4bfc992ad8ba4d5a0839..c7631669357915244188dd940525715502773e7c 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -75,6 +75,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -156,6 +164,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. @@ -529,10 +580,11 @@ If they choose A: Say: "Running /office-hours inline. Once the design doc is ready, I'll pick up the review right where we left off." -Read the office-hours skill file from disk using the Read tool: -`~/.claude/skills/gstack/office-hours/SKILL.md` +Read the `/office-hours` skill file at `~/.claude/skills/gstack/office-hours/SKILL.md` using the Read tool. + +**If unreadable:** Skip with "Could not load /office-hours — skipping." and continue. -Follow it inline, **skipping these sections** (already handled by the parent skill): +Follow its instructions from top to bottom, **skipping these sections** (already handled by the parent skill): - Preamble (run first) - AskUserQuestion Format - Completeness Principle — Boil the Lake @@ -540,9 +592,13 @@ Follow it inline, **skipping these sections** (already handled by the parent ski - Contributor Mode - Completion Status Protocol - Telemetry (run last) +- Step 0: Detect platform and base branch +- Review Readiness Dashboard +- Plan File Review Report +- Prerequisite Skill Offer +- Plan Status Footer -If the Read fails (file not found), say: -"Could not load /office-hours — proceeding with standard review." +Execute every other section at full depth. When the loaded skill's instructions are complete, continue with the next step below. After /office-hours completes, re-run the design doc check: ```bash @@ -568,12 +624,27 @@ sure," or is clearly exploring rather than reviewing — offer `/office-hours`: Options: A) Yes, run /office-hours now. B) No, keep going. If they keep going, proceed normally — no guilt, no re-asking. -If they choose A: Read the office-hours skill file from disk: -`~/.claude/skills/gstack/office-hours/SKILL.md` +If they choose A: + +Read the `/office-hours` skill file at `~/.claude/skills/gstack/office-hours/SKILL.md` using the Read tool. + +**If unreadable:** Skip with "Could not load /office-hours — skipping." and continue. + +Follow its instructions from top to bottom, **skipping these sections** (already handled by the parent skill): +- Preamble (run first) +- AskUserQuestion Format +- Completeness Principle — Boil the Lake +- Search Before Building +- Contributor Mode +- Completion Status Protocol +- Telemetry (run last) +- Step 0: Detect platform and base branch +- Review Readiness Dashboard +- Plan File Review Report +- Prerequisite Skill Offer +- Plan Status Footer -Follow it inline, skipping these sections (already handled by parent skill): -Preamble, AskUserQuestion Format, Completeness Principle, Search Before Building, -Contributor Mode, Completion Status Protocol, Telemetry. +Execute every other section at full depth. When the loaded skill's instructions are complete, continue with the next step below. Note current Step 0A progress so you don't re-ask questions already answered. After completion, re-run the design doc check and resume the review. diff --git a/plan-ceo-review/SKILL.md.tmpl b/plan-ceo-review/SKILL.md.tmpl index d0f7476428aee743c9efc6242b1c6e5549fc20b1..b33aaa30c5c258b051bcb0981d297590893d56d2 100644 --- a/plan-ceo-review/SKILL.md.tmpl +++ b/plan-ceo-review/SKILL.md.tmpl @@ -143,12 +143,9 @@ sure," or is clearly exploring rather than reviewing — offer `/office-hours`: Options: A) Yes, run /office-hours now. B) No, keep going. If they keep going, proceed normally — no guilt, no re-asking. -If they choose A: Read the office-hours skill file from disk: -`~/.claude/skills/gstack/office-hours/SKILL.md` +If they choose A: -Follow it inline, skipping these sections (already handled by parent skill): -Preamble, AskUserQuestion Format, Completeness Principle, Search Before Building, -Contributor Mode, Completion Status Protocol, Telemetry. +{{INVOKE_SKILL:office-hours}} Note current Step 0A progress so you don't re-ask questions already answered. After completion, re-run the design doc check and resume the review. diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md index 452537cbed756775b8a00a0ce66e5e56a03ab06e..86a950a849e468a26328b6d74b0530eac88638cc 100644 --- a/plan-design-review/SKILL.md +++ b/plan-design-review/SKILL.md @@ -73,6 +73,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -154,6 +162,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index 109f6b2be1ca68ef936401e7f3e099949f852530..1dad9fc0b95ee377d00827413e8c5f9cf540211d 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -74,6 +74,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -155,6 +163,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. @@ -439,10 +490,11 @@ If they choose A: Say: "Running /office-hours inline. Once the design doc is ready, I'll pick up the review right where we left off." -Read the office-hours skill file from disk using the Read tool: -`~/.claude/skills/gstack/office-hours/SKILL.md` +Read the `/office-hours` skill file at `~/.claude/skills/gstack/office-hours/SKILL.md` using the Read tool. + +**If unreadable:** Skip with "Could not load /office-hours — skipping." and continue. -Follow it inline, **skipping these sections** (already handled by the parent skill): +Follow its instructions from top to bottom, **skipping these sections** (already handled by the parent skill): - Preamble (run first) - AskUserQuestion Format - Completeness Principle — Boil the Lake @@ -450,9 +502,13 @@ Follow it inline, **skipping these sections** (already handled by the parent ski - Contributor Mode - Completion Status Protocol - Telemetry (run last) +- Step 0: Detect platform and base branch +- Review Readiness Dashboard +- Plan File Review Report +- Prerequisite Skill Offer +- Plan Status Footer -If the Read fails (file not found), say: -"Could not load /office-hours — proceeding with standard review." +Execute every other section at full depth. When the loaded skill's instructions are complete, continue with the next step below. After /office-hours completes, re-run the design doc check: ```bash diff --git a/qa-only/SKILL.md b/qa-only/SKILL.md index 19acfe92e8577daed7218db8056328a1e260f0cb..2beb599a57c63e10783555351339db9db1d931ad 100644 --- a/qa-only/SKILL.md +++ b/qa-only/SKILL.md @@ -70,6 +70,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -151,6 +159,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/qa/SKILL.md b/qa/SKILL.md index 319ee4dfef91743975ab233fdd28e5152cbd8067..94081f20e77a807e466f6e42f6052ec32bdf5a48 100644 --- a/qa/SKILL.md +++ b/qa/SKILL.md @@ -76,6 +76,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -157,6 +165,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/retro/SKILL.md b/retro/SKILL.md index 7f4511586c235e2fc01b5ea2a335699d0e6d4cd4..5a84039b140189f0e1893cb3d301ecc410df522e 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -70,6 +70,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -151,6 +159,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/review/SKILL.md b/review/SKILL.md index 462123a66194572d2924128757517746fcf4c8b1..3f492d21fffaf4c53c59a82af12cc2182612f462 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -73,6 +73,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -154,6 +162,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/scripts/gen-skill-docs.ts b/scripts/gen-skill-docs.ts index 1c2a3fee2d67cc3c4a086797eecacec4224e9bf2..94f39101c14c85d305cdd1f6de54eb0812068522 100644 --- a/scripts/gen-skill-docs.ts +++ b/scripts/gen-skill-docs.ts @@ -83,11 +83,15 @@ const OPENAI_LITMUS_CHECKS = [ // ─── External Host Helpers ─────────────────────────────────── // Re-export local copy for use in this file (matches codex-helpers.ts) -function externalSkillName(skillDir: string): string { +// Accepts optional frontmatter name to support directory/invocation name divergence +function externalSkillName(skillDir: string, frontmatterName?: string): string { + // Root skill (skillDir === '' or '.') always maps to 'gstack' regardless of frontmatter if (skillDir === '.' || skillDir === '') return 'gstack'; + // Use frontmatter name when it differs from directory name (e.g., run-tests/ with name: test) + const baseName = frontmatterName && frontmatterName !== skillDir ? frontmatterName : skillDir; // Don't double-prefix: gstack-upgrade → gstack-upgrade (not gstack-gstack-upgrade) - if (skillDir.startsWith('gstack-')) return skillDir; - return `gstack-${skillDir}`; + if (baseName.startsWith('gstack-')) return baseName; + return `gstack-${baseName}`; } function extractNameAndDescription(content: string): { name: string; description: string } { @@ -255,11 +259,12 @@ function processExternalHost( skillDir: string, extractedDescription: string, ctx: TemplateContext, + frontmatterName?: string, ): { content: string; outputPath: string; outputDir: string; symlinkLoop: boolean } { const config = EXTERNAL_HOST_CONFIG[host]; if (!config) throw new Error(`No external host config for: ${host}`); - const name = externalSkillName(skillDir === '.' ? '' : skillDir); + const name = externalSkillName(skillDir === '.' ? '' : skillDir, frontmatterName); const outputDir = path.join(ROOT, config.hostSubdir, 'skills', name); fs.mkdirSync(outputDir, { recursive: true }); const outputPath = path.join(outputDir, 'SKILL.md'); @@ -324,10 +329,13 @@ function processTemplate(tmplPath: string, host: Host = 'claude'): { outputPath: // Determine skill directory relative to ROOT const skillDir = path.relative(ROOT, path.dirname(tmplPath)); - // Extract skill name from frontmatter for TemplateContext + // Extract skill name from frontmatter early — needed for both TemplateContext and external host output paths. + // When frontmatter name: differs from directory name (e.g., run-tests/ with name: test), + // the frontmatter name is used for external skill naming and setup script symlinks. const { name: extractedName, description: extractedDescription } = extractNameAndDescription(tmplContent); const skillName = extractedName || path.basename(path.dirname(tmplPath)); + // Extract benefits-from list from frontmatter (inline YAML: benefits-from: [a, b]) const benefitsMatch = tmplContent.match(/^benefits-from:\s*\[([^\]]*)\]/m); const benefitsFrom = benefitsMatch @@ -340,15 +348,18 @@ function processTemplate(tmplPath: string, host: Host = 'claude'): { outputPath: const ctx: TemplateContext = { skillName, tmplPath, benefitsFrom, host, paths: HOST_PATHS[host], preambleTier }; - // Replace placeholders - let content = tmplContent.replace(/\{\{(\w+)\}\}/g, (match, name) => { - const resolver = RESOLVERS[name]; - if (!resolver) throw new Error(`Unknown placeholder {{${name}}} in ${relTmplPath}`); - return resolver(ctx); + // Replace placeholders (supports parameterized: {{NAME:arg1:arg2}}) + let content = tmplContent.replace(/\{\{(\w+(?::[^}]+)?)\}\}/g, (match, fullKey) => { + const parts = fullKey.split(':'); + const resolverName = parts[0]; + const args = parts.slice(1); + const resolver = RESOLVERS[resolverName]; + if (!resolver) throw new Error(`Unknown placeholder {{${resolverName}}} in ${relTmplPath}`); + return args.length > 0 ? resolver(ctx, args) : resolver(ctx); }); // Check for any remaining unresolved placeholders - const remaining = content.match(/\{\{(\w+)\}\}/g); + const remaining = content.match(/\{\{(\w+(?::[^}]+)?)\}\}/g); if (remaining) { throw new Error(`Unresolved placeholders in ${relTmplPath}: ${remaining.join(', ')}`); } @@ -359,7 +370,7 @@ function processTemplate(tmplPath: string, host: Host = 'claude'): { outputPath: if (host === 'claude') { content = transformFrontmatter(content, host); } else { - const result = processExternalHost(content, tmplContent, host, skillDir, extractedDescription, ctx); + const result = processExternalHost(content, tmplContent, host, skillDir, extractedDescription, ctx, extractedName || undefined); content = result.content; outputPath = result.outputPath; symlinkLoop = result.symlinkLoop; diff --git a/scripts/resolvers/composition.ts b/scripts/resolvers/composition.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf9812f44833a644abd8a6150bdffa1cd59084bb --- /dev/null +++ b/scripts/resolvers/composition.ts @@ -0,0 +1,48 @@ +import type { TemplateContext } from './types'; + +/** + * {{INVOKE_SKILL:skill-name}} — emits prose instructing Claude to read + * another skill's SKILL.md and follow it, skipping preamble sections. + * + * Supports optional skip= parameter for additional sections to skip: + * {{INVOKE_SKILL:plan-ceo-review:skip=Outside Voice,Design Outside Voices}} + */ +export function generateInvokeSkill(ctx: TemplateContext, args?: string[]): string { + const skillName = args?.[0]; + if (!skillName || skillName === '') { + throw new Error('{{INVOKE_SKILL}} requires a skill name, e.g. {{INVOKE_SKILL:plan-ceo-review}}'); + } + + // Parse optional skip= parameter from args[1+] + const extraSkips = (args?.slice(1) || []) + .filter(a => a.startsWith('skip=')) + .flatMap(a => a.slice(5).split(',')) + .map(s => s.trim()) + .filter(Boolean); + + const DEFAULT_SKIPS = [ + 'Preamble (run first)', + 'AskUserQuestion Format', + 'Completeness Principle — Boil the Lake', + 'Search Before Building', + 'Contributor Mode', + 'Completion Status Protocol', + 'Telemetry (run last)', + 'Step 0: Detect platform and base branch', + 'Review Readiness Dashboard', + 'Plan File Review Report', + 'Prerequisite Skill Offer', + 'Plan Status Footer', + ]; + + const allSkips = [...DEFAULT_SKIPS, ...extraSkips]; + + return `Read the \`/${skillName}\` skill file at \`${ctx.paths.skillRoot}/${skillName}/SKILL.md\` using the Read tool. + +**If unreadable:** Skip with "Could not load /${skillName} — skipping." and continue. + +Follow its instructions from top to bottom, **skipping these sections** (already handled by the parent skill): +${allSkips.map(s => `- ${s}`).join('\n')} + +Execute every other section at full depth. When the loaded skill's instructions are complete, continue with the next step below.`; +} diff --git a/scripts/resolvers/index.ts b/scripts/resolvers/index.ts index 6b5a9e4e32c032b196d881201adc9b5883120ce0..7ac7f1a25f5ba544c2c27c057e9bb6d90b1ed4e1 100644 --- a/scripts/resolvers/index.ts +++ b/scripts/resolvers/index.ts @@ -3,7 +3,7 @@ * Each resolver takes a TemplateContext and returns the replacement string. */ -import type { TemplateContext } from './types'; +import type { TemplateContext, ResolverFn } from './types'; // Domain modules import { generatePreamble } from './preamble'; @@ -12,11 +12,12 @@ import { generateCommandReference, generateSnapshotFlags, generateBrowseSetup } import { generateDesignMethodology, generateDesignHardRules, generateDesignOutsideVoices, generateDesignReviewLite, generateDesignSketch, generateDesignSetup, generateDesignMockup, generateDesignShotgunLoop } from './design'; import { generateTestBootstrap, generateTestCoverageAuditPlan, generateTestCoverageAuditShip, generateTestCoverageAuditReview } from './testing'; import { generateReviewDashboard, generatePlanFileReviewReport, generateSpecReviewLoop, generateBenefitsFrom, generateCodexSecondOpinion, generateAdversarialStep, generateCodexPlanReview, generatePlanCompletionAuditShip, generatePlanCompletionAuditReview, generatePlanVerificationExec } from './review'; -import { generateSlugEval, generateSlugSetup, generateBaseBranchDetect, generateDeployBootstrap, generateQAMethodology, generateCoAuthorTrailer } from './utility'; +import { generateSlugEval, generateSlugSetup, generateBaseBranchDetect, generateDeployBootstrap, generateQAMethodology, generateCoAuthorTrailer, generateChangelogWorkflow } from './utility'; import { generateLearningsSearch, generateLearningsLog } from './learnings'; import { generateConfidenceCalibration } from './confidence'; +import { generateInvokeSkill } from './composition'; -export const RESOLVERS: Record string> = { +export const RESOLVERS: Record = { SLUG_EVAL: generateSlugEval, SLUG_SETUP: generateSlugSetup, COMMAND_REFERENCE: generateCommandReference, @@ -53,4 +54,6 @@ export const RESOLVERS: Record string> = { LEARNINGS_SEARCH: generateLearningsSearch, LEARNINGS_LOG: generateLearningsLog, CONFIDENCE_CALIBRATION: generateConfidenceCalibration, + INVOKE_SKILL: generateInvokeSkill, + CHANGELOG_WORKFLOW: generateChangelogWorkflow, }; diff --git a/scripts/resolvers/preamble.ts b/scripts/resolvers/preamble.ts index cf88325a3b52e152f20040df202da18f8c50ffa5..8cd1b5572b4055237aed640a47006fce0d6af95e 100644 --- a/scripts/resolvers/preamble.ts +++ b/scripts/resolvers/preamble.ts @@ -77,6 +77,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +fi +_ROUTING_DECLINED=$(${ctx.paths.binDir}/gstack-config get routing_declined 2>/dev/null || echo "false") +echo "HAS_ROUTING: $_HAS_ROUTING" +echo "ROUTING_DECLINED: $_ROUTING_DECLINED" \`\`\``; } @@ -167,6 +175,51 @@ touch ~/.gstack/.proactive-prompted This only happens once. If \`PROACTIVE_PROMPTED\` is \`yes\`, skip this entirely.`; } +function generateRoutingInjection(ctx: TemplateContext): string { + return `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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +\`\`\` + +Then commit the change: \`git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"\` + +If B: run \`${ctx.paths.binDir}/gstack-config set routing_declined true\` +Say "No problem. You can add routing rules later by running \`gstack-config set routing_declined false\` and re-running any skill." + +This only happens once per project. If \`HAS_ROUTING\` is \`yes\` or \`ROUTING_DECLINED\` is \`true\`, skip this entirely.`; +} + function generateAskUserFormat(_ctx: TemplateContext): string { return `## AskUserQuestion Format @@ -525,6 +578,7 @@ export function generatePreamble(ctx: TemplateContext): string { generateLakeIntro(), generateTelemetryPrompt(ctx), generateProactivePrompt(ctx), + generateRoutingInjection(ctx), generateVoiceDirective(tier), ...(tier >= 2 ? [generateAskUserFormat(ctx), generateCompletenessSection()] : []), ...(tier >= 3 ? [generateRepoModeSection(), generateSearchBeforeBuildingSection(ctx)] : []), diff --git a/scripts/resolvers/review.ts b/scripts/resolvers/review.ts index 02fd7765964058d65a4188cce4f918c353f1e690..5db226444885ff927075dcc6a7e18af9cc7b8583 100644 --- a/scripts/resolvers/review.ts +++ b/scripts/resolvers/review.ts @@ -13,6 +13,7 @@ * Codex CLI prompts are written to temp files to prevent shell injection. */ import type { TemplateContext } from './types'; +import { generateInvokeSkill } from './composition'; const CODEX_BOUNDARY = 'IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\\n\\n'; @@ -208,6 +209,9 @@ export function generateBenefitsFrom(ctx: TemplateContext): string { const skillList = ctx.benefitsFrom.map(s => `\`/${s}\``).join(' or '); const first = ctx.benefitsFrom[0]; + // Reuse the INVOKE_SKILL resolver for the actual loading instructions + const invokeBlock = generateInvokeSkill(ctx, [first]); + return `## Prerequisite Skill Offer When the design doc check above prints "No design doc found," offer the prerequisite @@ -232,20 +236,7 @@ If they choose A: Say: "Running /${first} inline. Once the design doc is ready, I'll pick up the review right where we left off." -Read the ${first} skill file from disk using the Read tool: -\`~/.claude/skills/gstack/${first}/SKILL.md\` - -Follow it inline, **skipping these sections** (already handled by the parent skill): -- Preamble (run first) -- AskUserQuestion Format -- Completeness Principle — Boil the Lake -- Search Before Building -- Contributor Mode -- Completion Status Protocol -- Telemetry (run last) - -If the Read fails (file not found), say: -"Could not load /${first} — proceeding with standard review." +${invokeBlock} After /${first} completes, re-run the design doc check: \`\`\`bash diff --git a/scripts/resolvers/types.ts b/scripts/resolvers/types.ts index 891ea0cd1d14296354c79778e5fc125cd06bdee9..785f5a3a816cc24ddbe1a53551b530d976ff26f8 100644 --- a/scripts/resolvers/types.ts +++ b/scripts/resolvers/types.ts @@ -40,3 +40,6 @@ export interface TemplateContext { paths: HostPaths; preambleTier?: number; // 1-4, controls which preamble sections are included } + +/** Resolver function signature. args is populated for parameterized placeholders like {{INVOKE_SKILL:name}}. */ +export type ResolverFn = (ctx: TemplateContext, args?: string[]) => string; diff --git a/scripts/resolvers/utility.ts b/scripts/resolvers/utility.ts index 660e4ec556b671166d192353e8be5a42fff044af..e6167d02f72acec571984398c51ae43245dd533d 100644 --- a/scripts/resolvers/utility.ts +++ b/scripts/resolvers/utility.ts @@ -375,3 +375,47 @@ export function generateCoAuthorTrailer(ctx: TemplateContext): string { } return 'Co-Authored-By: Claude Opus 4.6 '; } + +export function generateChangelogWorkflow(_ctx: TemplateContext): string { + return `## CHANGELOG (auto-generate) + +1. Read \`CHANGELOG.md\` header to know the format. + +2. **First, enumerate every commit on the branch:** + \`\`\`bash + git log ..HEAD --oneline + \`\`\` + Copy the full list. Count the commits. You will use this as a checklist. + +3. **Read the full diff** to understand what each commit actually changed: + \`\`\`bash + git diff ...HEAD + \`\`\` + +4. **Group commits by theme** before writing anything. Common themes: + - New features / capabilities + - Performance improvements + - Bug fixes + - Dead code removal / cleanup + - Infrastructure / tooling / tests + - Refactoring + +5. **Write the CHANGELOG entry** covering ALL groups: + - If existing CHANGELOG entries on the branch already cover some commits, replace them with one unified entry for the new version + - Categorize changes into applicable sections: + - \`### Added\` — new features + - \`### Changed\` — changes to existing functionality + - \`### Fixed\` — bug fixes + - \`### Removed\` — removed features + - Write concise, descriptive bullet points + - Insert after the file header (line 5), dated today + - Format: \`## [X.Y.Z.W] - YYYY-MM-DD\` + - **Voice:** Lead with what the user can now **do** that they couldn't before. Use plain language, not implementation details. Never mention TODOS.md, internal tracking, or contributor-facing details. + +6. **Cross-check:** Compare your CHANGELOG entry against the commit list from step 2. + Every commit must map to at least one bullet point. If any commit is unrepresented, + add it now. If the branch has N commits spanning K themes, the CHANGELOG must + reflect all K themes. + +**Do NOT ask the user to describe changes.** Infer from the diff and commit history.`; +} diff --git a/setup b/setup index bfe39bb466c9e8afdd13ef97a734592f05e5dac1..d2836245b8f532dd765f566ff73e05cc1c9eaad0 100755 --- a/setup +++ b/setup @@ -272,9 +272,12 @@ link_claude_skill_dirs() { local linked=() for skill_dir in "$gstack_dir"/*/; do if [ -f "$skill_dir/SKILL.md" ]; then - skill_name="$(basename "$skill_dir")" + dir_name="$(basename "$skill_dir")" # Skip node_modules - [ "$skill_name" = "node_modules" ] && continue + [ "$dir_name" = "node_modules" ] && continue + # Use frontmatter name: if present (e.g., run-tests/ with name: test → symlink as "test") + skill_name=$(grep -m1 '^name:' "$skill_dir/SKILL.md" 2>/dev/null | sed 's/^name:[[:space:]]*//' | tr -d '[:space:]') + [ -z "$skill_name" ] && skill_name="$dir_name" # Apply gstack- prefix unless --no-prefix or already prefixed if [ "$SKILL_PREFIX" -eq 1 ]; then case "$skill_name" in @@ -287,7 +290,7 @@ link_claude_skill_dirs() { target="$skills_dir/$link_name" # Create or update symlink; skip if a real file/directory exists if [ -L "$target" ] || [ ! -e "$target" ]; then - ln -snf "gstack/$skill_name" "$target" + ln -snf "gstack/$dir_name" "$target" linked+=("$link_name") fi fi diff --git a/setup-browser-cookies/SKILL.md b/setup-browser-cookies/SKILL.md index edf0fa9febc8ff4d1b8a91165bbe69dd757f7add..67657a6ba653a87bee426bf2756056f47dd1166f 100644 --- a/setup-browser-cookies/SKILL.md +++ b/setup-browser-cookies/SKILL.md @@ -67,6 +67,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -148,6 +156,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice **Tone:** direct, concrete, sharp, never corporate, never academic. Sound like a builder, not a consultant. Name the file, the function, the command. No filler, no throat-clearing. diff --git a/setup-deploy/SKILL.md b/setup-deploy/SKILL.md index f0879c9667fb3c08b43d2b1f724929d8b8c03ba6..9abfb9754b6b42eb42400bd904d7bb2f4691b293 100644 --- a/setup-deploy/SKILL.md +++ b/setup-deploy/SKILL.md @@ -73,6 +73,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -154,6 +162,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. diff --git a/ship/SKILL.md b/ship/SKILL.md index 4ce665fb050d639674d6f4b1f4e3c10b3b241209..4519b6e2d58d6965630825f04906ed3a7c29f2bd 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -5,8 +5,9 @@ version: 1.0.0 description: | Ship workflow: detect + merge base branch, run tests, review diff, bump VERSION, update CHANGELOG, commit, push, create PR. Use when asked to "ship", "deploy", - "push to main", "create a PR", or "merge and push". - Proactively suggest when the user says code is ready or asks about deploying. (gstack) + "push to main", "create a PR", "merge and push", or "get it deployed". + Proactively invoke this skill (do NOT push/PR directly) when the user says code + is ready, asks about deploying, wants to push code up, or asks to create a PR. (gstack) allowed-tools: - Bash - Read @@ -73,6 +74,14 @@ if [ -f "$_LEARN_FILE" ]; then else echo "LEARNINGS: 0" fi +# Check if CLAUDE.md has routing rules +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +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" ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills AND do not @@ -154,6 +163,49 @@ touch ~/.gstack/.proactive-prompted This only happens once. If `PROACTIVE_PROMPTED` is `yes`, skip this entirely. +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. +> This tells Claude to use specialized workflows (like /ship, /investigate, /qa) +> instead of answering directly. It's a one-time addition, about 15 lines. + +Options: +- A) Add routing rules to CLAUDE.md (recommended) +- 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, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +``` + +Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` + +If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` +Say "No problem. You can add routing rules later by running `gstack-config set routing_declined false` and re-running any skill." + +This only happens once per project. If `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`, skip this entirely. + ## Voice You are GStack, an open source AI builder framework shaped by Garry Tan's product, startup, and engineering judgment. Encode how he thinks, not his biography. @@ -1721,7 +1773,7 @@ already knows. A good test: would this insight save time in a future session? If --- -## Step 5: CHANGELOG (auto-generate) +## CHANGELOG (auto-generate) 1. Read `CHANGELOG.md` header to know the format. @@ -1754,6 +1806,7 @@ already knows. A good test: would this insight save time in a future session? If - Write concise, descriptive bullet points - Insert after the file header (line 5), dated today - Format: `## [X.Y.Z.W] - YYYY-MM-DD` + - **Voice:** Lead with what the user can now **do** that they couldn't before. Use plain language, not implementation details. Never mention TODOS.md, internal tracking, or contributor-facing details. 6. **Cross-check:** Compare your CHANGELOG entry against the commit list from step 2. Every commit must map to at least one bullet point. If any commit is unrepresented, diff --git a/ship/SKILL.md.tmpl b/ship/SKILL.md.tmpl index 7c7f1b2b1ecdd21f0569b90b8c1c237a48a42245..993a67a59711ea58abd94dcace66d606f130e834 100644 --- a/ship/SKILL.md.tmpl +++ b/ship/SKILL.md.tmpl @@ -5,8 +5,9 @@ version: 1.0.0 description: | Ship workflow: detect + merge base branch, run tests, review diff, bump VERSION, update CHANGELOG, commit, push, create PR. Use when asked to "ship", "deploy", - "push to main", "create a PR", or "merge and push". - Proactively suggest when the user says code is ready or asks about deploying. (gstack) + "push to main", "create a PR", "merge and push", or "get it deployed". + Proactively invoke this skill (do NOT push/PR directly) when the user says code + is ready, asks about deploying, wants to push code up, or asks to create a PR. (gstack) allowed-tools: - Bash - Read @@ -345,46 +346,7 @@ For each classified comment: --- -## Step 5: CHANGELOG (auto-generate) - -1. Read `CHANGELOG.md` header to know the format. - -2. **First, enumerate every commit on the branch:** - ```bash - git log ..HEAD --oneline - ``` - Copy the full list. Count the commits. You will use this as a checklist. - -3. **Read the full diff** to understand what each commit actually changed: - ```bash - git diff ...HEAD - ``` - -4. **Group commits by theme** before writing anything. Common themes: - - New features / capabilities - - Performance improvements - - Bug fixes - - Dead code removal / cleanup - - Infrastructure / tooling / tests - - Refactoring - -5. **Write the CHANGELOG entry** covering ALL groups: - - If existing CHANGELOG entries on the branch already cover some commits, replace them with one unified entry for the new version - - Categorize changes into applicable sections: - - `### Added` — new features - - `### Changed` — changes to existing functionality - - `### Fixed` — bug fixes - - `### Removed` — removed features - - Write concise, descriptive bullet points - - Insert after the file header (line 5), dated today - - Format: `## [X.Y.Z.W] - YYYY-MM-DD` - -6. **Cross-check:** Compare your CHANGELOG entry against the commit list from step 2. - Every commit must map to at least one bullet point. If any commit is unrepresented, - add it now. If the branch has N commits spanning K themes, the CHANGELOG must - reflect all K themes. - -**Do NOT ask the user to describe changes.** Infer from the diff and commit history. +{{CHANGELOG_WORKFLOW}} --- diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index 21aebb2785f88ffd99183823175c3f5e9f55fb2a..d7272a01da8b4819c607cea8d887eb0590926c1d 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -1153,6 +1153,138 @@ describe('BENEFITS_FROM resolver', () => { expect(ceoContent).toContain('office-hours/SKILL.md'); expect(engContent).toContain('office-hours/SKILL.md'); }); + + test('BENEFITS_FROM delegates to INVOKE_SKILL pattern', () => { + // Should contain the INVOKE_SKILL-style loading prose (not the old manual skip list) + expect(engContent).toContain('Follow its instructions from top to bottom'); + expect(engContent).toContain('skipping these sections'); + expect(ceoContent).toContain('Follow its instructions from top to bottom'); + }); +}); + +// --- {{INVOKE_SKILL}} resolver tests --- + +describe('INVOKE_SKILL resolver', () => { + const ceoContent = fs.readFileSync(path.join(ROOT, 'plan-ceo-review', 'SKILL.md'), 'utf-8'); + + test('plan-ceo-review uses INVOKE_SKILL for mid-session office-hours fallback', () => { + // The mid-session detection path should use INVOKE_SKILL-generated prose + expect(ceoContent).toContain('office-hours/SKILL.md'); + expect(ceoContent).toContain('Follow its instructions from top to bottom'); + }); + + test('INVOKE_SKILL output includes default skip list', () => { + expect(ceoContent).toContain('Preamble (run first)'); + expect(ceoContent).toContain('Telemetry (run last)'); + expect(ceoContent).toContain('AskUserQuestion Format'); + }); + + test('INVOKE_SKILL output includes error handling', () => { + expect(ceoContent).toContain('If unreadable'); + expect(ceoContent).toContain('Could not load'); + }); + + test('template uses {{INVOKE_SKILL:office-hours}} placeholder', () => { + const tmpl = fs.readFileSync(path.join(ROOT, 'plan-ceo-review', 'SKILL.md.tmpl'), 'utf-8'); + expect(tmpl).toContain('{{INVOKE_SKILL:office-hours}}'); + }); +}); + +// --- {{CHANGELOG_WORKFLOW}} resolver tests --- + +describe('CHANGELOG_WORKFLOW resolver', () => { + const shipContent = fs.readFileSync(path.join(ROOT, 'ship', 'SKILL.md'), 'utf-8'); + + test('ship SKILL.md contains changelog workflow', () => { + expect(shipContent).toContain('CHANGELOG (auto-generate)'); + expect(shipContent).toContain('git log ..HEAD --oneline'); + }); + + test('changelog workflow includes cross-check step', () => { + expect(shipContent).toContain('Cross-check'); + expect(shipContent).toContain('Every commit must map to at least one bullet point'); + }); + + test('changelog workflow includes voice guidance', () => { + expect(shipContent).toContain('Lead with what the user can now **do**'); + }); + + test('template uses {{CHANGELOG_WORKFLOW}} placeholder', () => { + const tmpl = fs.readFileSync(path.join(ROOT, 'ship', 'SKILL.md.tmpl'), 'utf-8'); + expect(tmpl).toContain('{{CHANGELOG_WORKFLOW}}'); + // Should NOT contain the old inline changelog content + expect(tmpl).not.toContain('Group commits by theme'); + }); + + test('changelog workflow includes keep-changelog format', () => { + expect(shipContent).toContain('### Added'); + expect(shipContent).toContain('### Fixed'); + }); +}); + +// --- Parameterized resolver infrastructure tests --- + +describe('parameterized resolver support', () => { + test('gen-skill-docs regex handles colon-separated args', () => { + // Verify the template containing {{INVOKE_SKILL:office-hours}} was processed + // without leaving unresolved placeholders + const ceoContent = fs.readFileSync(path.join(ROOT, 'plan-ceo-review', 'SKILL.md'), 'utf-8'); + expect(ceoContent).not.toMatch(/\{\{INVOKE_SKILL:[^}]+\}\}/); + }); + + test('templates with parameterized resolvers pass unresolved check', () => { + // All generated SKILL.md files should have no unresolved {{...}} placeholders + const skillDirs = fs.readdirSync(ROOT).filter(d => + fs.existsSync(path.join(ROOT, d, 'SKILL.md')) + ); + for (const dir of skillDirs) { + const content = fs.readFileSync(path.join(ROOT, dir, 'SKILL.md'), 'utf-8'); + const unresolved = content.match(/\{\{[A-Z_]+(?::[^}]*)?\}\}/g); + if (unresolved) { + throw new Error(`${dir}/SKILL.md has unresolved placeholders: ${unresolved.join(', ')}`); + } + } + }); +}); + +// --- Preamble routing injection tests --- + +describe('preamble routing injection', () => { + const shipContent = fs.readFileSync(path.join(ROOT, 'ship', 'SKILL.md'), 'utf-8'); + + test('preamble bash checks for routing section in CLAUDE.md', () => { + expect(shipContent).toContain('grep -q "## Skill routing" CLAUDE.md'); + expect(shipContent).toContain('HAS_ROUTING'); + }); + + test('preamble bash reads routing_declined config', () => { + expect(shipContent).toContain('routing_declined'); + expect(shipContent).toContain('ROUTING_DECLINED'); + }); + + test('preamble includes routing injection AskUserQuestion', () => { + expect(shipContent).toContain('Add routing rules to CLAUDE.md'); + expect(shipContent).toContain("I'll invoke skills manually"); + }); + + test('routing injection respects prior decline', () => { + expect(shipContent).toContain('ROUTING_DECLINED'); + expect(shipContent).toMatch(/routing_declined.*true/); + }); + + test('routing injection only fires when all conditions met', () => { + // Must be: HAS_ROUTING=no AND ROUTING_DECLINED=false AND PROACTIVE_PROMPTED=yes + expect(shipContent).toContain('HAS_ROUTING'); + expect(shipContent).toContain('ROUTING_DECLINED'); + expect(shipContent).toContain('PROACTIVE_PROMPTED'); + }); + + test('routing section content includes key routing rules', () => { + expect(shipContent).toContain('invoke office-hours'); + expect(shipContent).toContain('invoke investigate'); + expect(shipContent).toContain('invoke ship'); + expect(shipContent).toContain('invoke qa'); + }); }); // --- {{DESIGN_OUTSIDE_VOICES}} resolver tests --- @@ -1793,11 +1925,12 @@ describe('setup script validation', () => { }); test('link_claude_skill_dirs creates relative symlinks', () => { - // Claude links should be relative: ln -snf "gstack/skill_name" + // Claude links should be relative: ln -snf "gstack/$dir_name" + // Uses dir_name (not skill_name) because symlink target must point to the physical directory const fnStart = setupContent.indexOf('link_claude_skill_dirs()'); const fnEnd = setupContent.indexOf('}', setupContent.indexOf('linked[@]}', fnStart)); const fnBody = setupContent.slice(fnStart, fnEnd); - expect(fnBody).toContain('ln -snf "gstack/$skill_name"'); + expect(fnBody).toContain('ln -snf "gstack/$dir_name"'); }); test('setup supports --host auto|claude|codex|kiro', () => { diff --git a/test/skill-routing-e2e.test.ts b/test/skill-routing-e2e.test.ts index b865efb7c66d57b6d7428b4d807c0266990a5bd9..d5a48499ba93eefbc01c30b0d4420f259b8f999c 100644 --- a/test/skill-routing-e2e.test.ts +++ b/test/skill-routing-e2e.test.ts @@ -93,11 +93,30 @@ function installSkills(tmpDir: string) { } } - // Copy CLAUDE.md so Claude has project context for skill routing. - const claudeMdSrc = path.join(ROOT, 'CLAUDE.md'); - if (fs.existsSync(claudeMdSrc)) { - fs.copyFileSync(claudeMdSrc, path.join(tmpDir, 'CLAUDE.md')); - } + // Write a CLAUDE.md with explicit routing instructions. + // The skill descriptions in system-reminder aren't strong enough to override + // Claude's default behavior of answering directly. A CLAUDE.md instruction + // puts routing rules in project context which Claude weighs more heavily. + fs.writeFileSync(path.join(tmpDir, 'CLAUDE.md'), `# Project Instructions + +## Skill routing + +When the user's request matches an available skill, ALWAYS invoke it using the Skill +tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. +The skill has specialized workflows that produce better results than ad-hoc answers. + +Key routing rules: +- Product ideas, "is this worth building", brainstorming → invoke office-hours +- Bugs, errors, "why is this broken", 500 errors → invoke investigate +- Ship, deploy, push, create PR → invoke ship +- QA, test the site, find bugs → invoke qa +- Code review, check my diff → invoke review +- Update docs after shipping → invoke document-release +- Weekly retro → invoke retro +- Design system, brand → invoke design-consultation +- Visual audit, design polish → invoke design-review +- Architecture review → invoke plan-eng-review +`); } /** Init a git repo with config */ diff --git a/test/skill-validation.test.ts b/test/skill-validation.test.ts index 46398d5aca11deedd0afbd92ae4ab0eac918fb18..50beaa907a1bb8d6577b7a650a71d52aa2a881f0 100644 --- a/test/skill-validation.test.ts +++ b/test/skill-validation.test.ts @@ -1409,13 +1409,13 @@ describe('Skill trigger phrases', () => { ]; for (const skill of SKILLS_REQUIRING_PROACTIVE) { - test(`${skill}/SKILL.md has "Proactively suggest" phrase`, () => { + test(`${skill}/SKILL.md has proactive routing phrase`, () => { const skillPath = path.join(ROOT, skill, 'SKILL.md'); if (!fs.existsSync(skillPath)) return; const content = fs.readFileSync(skillPath, 'utf-8'); const frontmatterEnd = content.indexOf('---', 4); const frontmatter = content.slice(0, frontmatterEnd); - expect(frontmatter).toMatch(/Proactively suggest/i); + expect(frontmatter).toMatch(/Proactively (suggest|invoke)/i); }); } });