From ea66b4d2f5f9fca3ebf64c0ab0830864d154a4d4 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 23 Mar 2026 15:48:30 -0700 Subject: [PATCH] chore: regenerate SKILL.md files after preamble/epilogue changes Regenerated via bun run gen:skill-docs. Preamble now persists TEL_START and SESSION_ID to $PPID files + echoes them. Epilogue reads from files and passes --source flag. Co-Authored-By: Claude Opus 4.6 (1M context) --- SKILL.md | 96 +++++++++++++++++++++++++++------- autoplan/SKILL.md | 96 +++++++++++++++++++++++++++------- benchmark/SKILL.md | 96 +++++++++++++++++++++++++++------- browse/SKILL.md | 96 +++++++++++++++++++++++++++------- canary/SKILL.md | 96 +++++++++++++++++++++++++++------- codex/SKILL.md | 96 +++++++++++++++++++++++++++------- cso/SKILL.md | 96 +++++++++++++++++++++++++++------- design-consultation/SKILL.md | 96 +++++++++++++++++++++++++++------- design-review/SKILL.md | 96 +++++++++++++++++++++++++++------- document-release/SKILL.md | 96 +++++++++++++++++++++++++++------- investigate/SKILL.md | 96 +++++++++++++++++++++++++++------- land-and-deploy/SKILL.md | 96 +++++++++++++++++++++++++++------- office-hours/SKILL.md | 96 +++++++++++++++++++++++++++------- plan-ceo-review/SKILL.md | 96 +++++++++++++++++++++++++++------- plan-design-review/SKILL.md | 96 +++++++++++++++++++++++++++------- plan-eng-review/SKILL.md | 96 +++++++++++++++++++++++++++------- qa-only/SKILL.md | 96 +++++++++++++++++++++++++++------- qa/SKILL.md | 96 +++++++++++++++++++++++++++------- retro/SKILL.md | 96 +++++++++++++++++++++++++++------- review/SKILL.md | 96 +++++++++++++++++++++++++++------- setup-browser-cookies/SKILL.md | 96 +++++++++++++++++++++++++++------- setup-deploy/SKILL.md | 96 +++++++++++++++++++++++++++------- ship/SKILL.md | 96 +++++++++++++++++++++++++++------- 23 files changed, 1771 insertions(+), 437 deletions(-) diff --git a/SKILL.md b/SKILL.md index af9ef7b0..d3d28038 100644 --- a/SKILL.md +++ b/SKILL.md @@ -46,8 +46,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"gstack","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -74,28 +84,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -104,6 +117,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -242,6 +282,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -250,17 +300,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/autoplan/SKILL.md b/autoplan/SKILL.md index ec75c550..cb9c76fe 100644 --- a/autoplan/SKILL.md +++ b/autoplan/SKILL.md @@ -47,8 +47,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"autoplan","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -75,28 +85,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -105,6 +118,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -243,6 +283,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -251,17 +301,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/benchmark/SKILL.md b/benchmark/SKILL.md index 7a3e7432..94d6f8bc 100644 --- a/benchmark/SKILL.md +++ b/benchmark/SKILL.md @@ -40,8 +40,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"benchmark","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -68,28 +78,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -98,6 +111,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -236,6 +276,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -244,17 +294,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/browse/SKILL.md b/browse/SKILL.md index 123dcbe8..c90e851d 100644 --- a/browse/SKILL.md +++ b/browse/SKILL.md @@ -40,8 +40,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"browse","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -68,28 +78,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -98,6 +111,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -236,6 +276,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -244,17 +294,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/canary/SKILL.md b/canary/SKILL.md index 56646a9b..ad5253c8 100644 --- a/canary/SKILL.md +++ b/canary/SKILL.md @@ -40,8 +40,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"canary","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -68,28 +78,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -98,6 +111,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -236,6 +276,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -244,17 +294,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/codex/SKILL.md b/codex/SKILL.md index 226e5163..a9148117 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -41,8 +41,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"codex","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -69,28 +79,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -99,6 +112,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -237,6 +277,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -245,17 +295,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/cso/SKILL.md b/cso/SKILL.md index 26971fde..5ff3f14b 100644 --- a/cso/SKILL.md +++ b/cso/SKILL.md @@ -44,8 +44,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"cso","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -72,28 +82,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -102,6 +115,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -240,6 +280,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -248,17 +298,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index fc265f9e..03c9afb2 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -45,8 +45,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"design-consultation","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -73,28 +83,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -103,6 +116,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -241,6 +281,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -249,17 +299,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/design-review/SKILL.md b/design-review/SKILL.md index 94330822..4aec7c62 100644 --- a/design-review/SKILL.md +++ b/design-review/SKILL.md @@ -45,8 +45,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"design-review","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -73,28 +83,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -103,6 +116,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -241,6 +281,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -249,17 +299,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/document-release/SKILL.md b/document-release/SKILL.md index 82c613d4..c0cfb6f0 100644 --- a/document-release/SKILL.md +++ b/document-release/SKILL.md @@ -42,8 +42,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"document-release","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -70,28 +80,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -100,6 +113,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -238,6 +278,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -246,17 +296,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/investigate/SKILL.md b/investigate/SKILL.md index ddfcf308..78882ddf 100644 --- a/investigate/SKILL.md +++ b/investigate/SKILL.md @@ -56,8 +56,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"investigate","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -84,28 +94,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -114,6 +127,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -252,6 +292,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -260,17 +310,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/land-and-deploy/SKILL.md b/land-and-deploy/SKILL.md index 0ea57930..599a5106 100644 --- a/land-and-deploy/SKILL.md +++ b/land-and-deploy/SKILL.md @@ -39,8 +39,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"land-and-deploy","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -67,28 +77,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -97,6 +110,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -235,6 +275,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -243,17 +293,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 998fd3f2..1c89b0c0 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -47,8 +47,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"office-hours","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -75,28 +85,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -105,6 +118,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -243,6 +283,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -251,17 +301,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index a6365fca..d3912f0d 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -45,8 +45,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-ceo-review","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -73,28 +83,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -103,6 +116,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -241,6 +281,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -249,17 +299,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md index e8d9fbbe..c1a3ae8d 100644 --- a/plan-design-review/SKILL.md +++ b/plan-design-review/SKILL.md @@ -43,8 +43,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-design-review","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -71,28 +81,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -101,6 +114,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -239,6 +279,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -247,17 +297,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index 54d68fcc..c8f2ca33 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -44,8 +44,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-eng-review","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -72,28 +82,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -102,6 +115,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -240,6 +280,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -248,17 +298,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/qa-only/SKILL.md b/qa-only/SKILL.md index cd1767bb..d55b506b 100644 --- a/qa-only/SKILL.md +++ b/qa-only/SKILL.md @@ -40,8 +40,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"qa-only","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -68,28 +78,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -98,6 +111,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -236,6 +276,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -244,17 +294,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/qa/SKILL.md b/qa/SKILL.md index 66e5829a..3adc56e5 100644 --- a/qa/SKILL.md +++ b/qa/SKILL.md @@ -46,8 +46,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"qa","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -74,28 +84,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -104,6 +117,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -242,6 +282,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -250,17 +300,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/retro/SKILL.md b/retro/SKILL.md index 80e1e42a..37468649 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -40,8 +40,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"retro","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -68,28 +78,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -98,6 +111,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -236,6 +276,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -244,17 +294,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/review/SKILL.md b/review/SKILL.md index c96f5ca5..ddc74798 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -43,8 +43,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"review","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -71,28 +81,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -101,6 +114,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -239,6 +279,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -247,17 +297,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/setup-browser-cookies/SKILL.md b/setup-browser-cookies/SKILL.md index c7ecffee..0b839758 100644 --- a/setup-browser-cookies/SKILL.md +++ b/setup-browser-cookies/SKILL.md @@ -37,8 +37,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"setup-browser-cookies","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -65,28 +75,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -95,6 +108,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -233,6 +273,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -241,17 +291,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/setup-deploy/SKILL.md b/setup-deploy/SKILL.md index 2c86d5df..57bcbef7 100644 --- a/setup-deploy/SKILL.md +++ b/setup-deploy/SKILL.md @@ -43,8 +43,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"setup-deploy","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 # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -71,28 +81,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -101,6 +114,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -239,6 +279,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -247,17 +297,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer diff --git a/ship/SKILL.md b/ship/SKILL.md index 0d984f09..63dac89e 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -41,8 +41,18 @@ _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || tr _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" +echo $_TEL_START > ~/.gstack/analytics/.tel-start-$PPID +echo $_SESSION_ID > ~/.gstack/analytics/.tel-session-$PPID echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" +echo "TEL_START: $_TEL_START" +echo "SESSION_ID: $_SESSION_ID" +_EMAIL=$(~/.claude/skills/gstack/bin/gstack-config get email 2>/dev/null || true) +_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no") +_AUTH_OK=$(~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no") +echo "EMAIL: ${_EMAIL:-none}" +echo "COMM_PROMPTED: $_COMM_PROMPTED" +echo "AUTH: $_AUTH_OK" mkdir -p ~/.gstack/analytics echo '{"skill":"ship","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true # zsh-compatible: use find instead of glob to avoid NOMATCH error @@ -69,28 +79,31 @@ Only run `open` if the user says yes. Always run `touch` to mark as seen. This o If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion: -> Help gstack get better! Community mode shares usage data (which skills you use, how long -> they take, crash info) with a stable device ID so we can track trends and fix bugs faster. -> No code, file paths, or repo names are ever sent. +> gstack can share usage data (which skills you use, how long they take, crash info) +> to help improve the project. No code, file paths, or repo names are ever sent. +> +> The **community tier** unlocks extra features: +> - **Cloud backup** of your gstack config + history (restore on new machines) +> - **Benchmarks**: see how your usage compares to other builders +> - **Skill recommendations** based on community patterns +> > Change anytime with `gstack-config set telemetry off`. Options: -- A) Help gstack get better! (recommended) -- B) No thanks +- A) Community — share data + email for backup, benchmarks & recommendations (recommended) +- B) Anonymous — share data only, no account +- C) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: ask for their email via a follow-up AskUserQuestion, then run: +```bash +~/.claude/skills/gstack/bin/gstack-config set telemetry community +~/.claude/skills/gstack/bin/gstack-auth +``` +The auth script will send a verification code to their email. Wait for them to enter the 6-digit code. +If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier. -If B: ask a follow-up AskUserQuestion: - -> How about anonymous mode? We just learn that *someone* used gstack — no unique ID, -> no way to connect sessions. Just a counter that helps us know if anyone's out there. - -Options: -- A) Sure, anonymous is fine -- B) No thanks, fully off - -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` +If C: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` Always run: ```bash @@ -99,6 +112,33 @@ touch ~/.gstack/.telemetry-prompted This only happens once. If `TEL_PROMPTED` is `yes`, skip this entirely. +If `TELEMETRY` is `anonymous` AND `COMM_PROMPTED` is `no`: After the main skill workflow +begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion: + +> You're already sharing anonymous usage data — nice! Want to unlock more? +> +> The **community tier** adds: +> - Cloud backup of your gstack config (restore on new machines) +> - Benchmarks: see how your /qa times compare to the community +> - Skill recommendations based on what other builders use +> +> Just needs your email (verified via a one-time code). + +Options: +- A) Yes, join community (enter email) +- B) Not now + +If A: ask for their email, then run `~/.claude/skills/gstack/bin/gstack-auth `. +Wait for the verification code. On success, run `~/.claude/skills/gstack/bin/gstack-config set telemetry community`. +If B: do nothing. + +Always run: +```bash +touch ~/.gstack/.community-prompted +``` + +This only happens once. If `COMM_PROMPTED` is `yes`, skip this entirely. + ## AskUserQuestion Format **ALWAYS follow this structure for every AskUserQuestion call:** @@ -237,6 +277,16 @@ Determine the skill name from the `name:` field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted). +**For errors:** Also determine: +- `ERROR_CLASS`: a short category — one of: `timeout`, `test_failure`, `build_failure`, + `git_error`, `auth_error`, `network_error`, `browse_error`, `lint_error`, + `merge_conflict`, `permission_error`, `unknown_error`. Pick the most specific match. +- `ERROR_MESSAGE`: a one-line summary of what went wrong (max 200 chars). Include the + command that failed and the key error text. Example: `"bun test: 3 tests failed in + auth.test.ts — expected 200 got 401"`. Never include file paths, secrets, or PII. +- `FAILED_STEP`: which step in the skill workflow failed. Example: `"run_tests"`, + `"create_pr"`, `"merge_base"`, `"build"`, `"qa_browse"`. Use snake_case, max 30 chars. + **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to `~/.gstack/analytics/` (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. @@ -245,17 +295,25 @@ Skipping this command loses session duration and outcome data. Run this bash: ```bash +_TEL_START=$(cat ~/.gstack/analytics/.tel-start-$PPID 2>/dev/null || echo 0) +_SESSION_ID=$(cat ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || echo "") _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.tel-start-$PPID ~/.gstack/analytics/.tel-session-$PPID 2>/dev/null || true rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true ~/.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 & + --source "${GSTACK_TELEMETRY_SOURCE:-live}" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \ + --error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \ + --failed-step "FAILED_STEP" 2>/dev/null & ``` 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". This runs in the background and +For `ERROR_CLASS`, `ERROR_MESSAGE`, and `FAILED_STEP`: use empty string `""` if the +outcome is not error. If the outcome is error but you cannot determine the details, +use `"unknown_error"`, `""`, and `""` respectively. This runs in the background and never blocks the user. ## Plan Status Footer