diff --git a/design-html/SKILL.md b/design-html/SKILL.md
index d77d0465..d21750a5 100644
--- a/design-html/SKILL.md
+++ b/design-html/SKILL.md
@@ -9,7 +9,7 @@ description: |
Smart API routing: picks the right Pretext patterns for each design type.
Use when: "finalize this design", "turn this mockup into HTML", "implement
this design", or after /design-shotgun approves a direction.
- Proactively suggest when user has approved a design in /design-shotgun.
+ Proactively suggest when user has approved a design in /design-shotgun. (gstack)
allowed-tools:
- Bash
- Read
@@ -31,7 +31,7 @@ _UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/sk
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
-find ~/.gstack/sessions -mmin +120 -type f -delete 2>/dev/null || true
+find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true
_CONTRIB=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true)
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no")
@@ -53,7 +53,9 @@ _SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
mkdir -p ~/.gstack/analytics
-echo '{"skill":"design-html","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
+if [ "${_TEL:-off}" != "off" ]; then
+ echo '{"skill":"design-html","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
+fi
# zsh-compatible: use find instead of glob to avoid NOMATCH error
for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do
if [ -f "$_PF" ]; then
@@ -73,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
@@ -154,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.
@@ -288,20 +341,22 @@ Run this bash:
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
-# Local analytics (always available, no binary needed)
-echo '{"skill":"SKILL_NAME","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
-# Remote telemetry (opt-in, requires binary)
-if [ "$_TEL" != "off" ] && [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then
- ~/.claude/skills/gstack/bin/gstack-telemetry-log \
- --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \
- --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
+# Local + remote telemetry (both gated by _TEL setting)
+if [ "$_TEL" != "off" ]; then
+ echo '{"skill":"SKILL_NAME","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
+ if [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then
+ ~/.claude/skills/gstack/bin/gstack-telemetry-log \
+ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \
+ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
+ fi
fi
```
Replace `SKILL_NAME` with the actual skill name from frontmatter, `OUTCOME` with
success/error/abort, and `USED_BROWSE` with true/false based on whether `$B` was used.
-If you cannot determine the outcome, use "unknown". The local JSONL always logs. The
-remote binary only runs if telemetry is not off and the binary exists.
+If you cannot determine the outcome, use "unknown". Both local JSONL and remote
+telemetry only run if telemetry is not off. The remote binary additionally requires
+the binary to exist.
## Plan Status Footer
@@ -409,7 +464,19 @@ If `NEEDS_SETUP`:
3. If `bun` is not installed:
```bash
if ! command -v bun >/dev/null 2>&1; then
- curl -fsSL https://bun.sh/install | BUN_VERSION=1.3.10 bash
+ BUN_VERSION="1.3.10"
+ BUN_INSTALL_SHA="bab8acfb046aac8c72407bdcce903957665d655d7acaa3e11c7c4616beae68dd"
+ tmpfile=$(mktemp)
+ curl -fsSL "https://bun.sh/install" -o "$tmpfile"
+ actual_sha=$(shasum -a 256 "$tmpfile" | awk '{print $1}')
+ if [ "$actual_sha" != "$BUN_INSTALL_SHA" ]; then
+ echo "ERROR: bun install script checksum mismatch" >&2
+ echo " expected: $BUN_INSTALL_SHA" >&2
+ echo " got: $actual_sha" >&2
+ rm "$tmpfile"; exit 1
+ fi
+ BUN_VERSION="$BUN_VERSION" bash "$tmpfile"
+ rm "$tmpfile"
fi
```
diff --git a/design-html/SKILL.md.tmpl b/design-html/SKILL.md.tmpl
index 90572f6f..2ef73a70 100644
--- a/design-html/SKILL.md.tmpl
+++ b/design-html/SKILL.md.tmpl
@@ -9,7 +9,7 @@ description: |
Smart API routing: picks the right Pretext patterns for each design type.
Use when: "finalize this design", "turn this mockup into HTML", "implement
this design", or after /design-shotgun approves a direction.
- Proactively suggest when user has approved a design in /design-shotgun.
+ Proactively suggest when user has approved a design in /design-shotgun. (gstack)
allowed-tools:
- Bash
- Read