From 3a57a3f59e70a8e9ae7af3696a2d0eff365cd221 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 16 Mar 2026 00:15:36 -0500 Subject: [PATCH] feat: add /setup-team-sync skill, auto-push transcript hooks in skills - setup-team-sync/SKILL.md.tmpl: idempotent guided setup (create config, OAuth, verify connectivity, configure settings, summary) - ship/retro/qa SKILL.md.tmpl: add push-transcript hook after existing push-ship/push-retro/push-qa hooks (silent, non-fatal) - scripts/gen-skill-docs.ts: add setup-team-sync to template list - Regenerated all SKILL.md files Co-Authored-By: Claude Opus 4.6 (1M context) --- qa/SKILL.md | 1 + qa/SKILL.md.tmpl | 1 + retro/SKILL.md | 1 + retro/SKILL.md.tmpl | 1 + scripts/gen-skill-docs.ts | 1 + setup-team-sync/SKILL.md | 139 ++++++++++++++++++++++++++++++++++ setup-team-sync/SKILL.md.tmpl | 130 +++++++++++++++++++++++++++++++ ship/SKILL.md | 1 + ship/SKILL.md.tmpl | 1 + 9 files changed, 276 insertions(+) create mode 100644 setup-team-sync/SKILL.md create mode 100644 setup-team-sync/SKILL.md.tmpl diff --git a/qa/SKILL.md b/qa/SKILL.md index 618157d5..1cc33011 100644 --- a/qa/SKILL.md +++ b/qa/SKILL.md @@ -271,6 +271,7 @@ $B snapshot -i -a -o "$REPORT_DIR/screenshots/issue-002.png" } QAEOF ~/.claude/skills/gstack/bin/gstack-sync push-qa .gstack/qa-reports/qa-sync.json 2>/dev/null && echo "Synced to team ✓" || true + ~/.claude/skills/gstack/bin/gstack-sync push-transcript 2>/dev/null || true ``` Substitute actual values. Uses snake_case keys matching the Supabase schema. diff --git a/qa/SKILL.md.tmpl b/qa/SKILL.md.tmpl index 8ca52f9f..5396ba0c 100644 --- a/qa/SKILL.md.tmpl +++ b/qa/SKILL.md.tmpl @@ -245,6 +245,7 @@ $B snapshot -i -a -o "$REPORT_DIR/screenshots/issue-002.png" } QAEOF ~/.claude/skills/gstack/bin/gstack-sync push-qa .gstack/qa-reports/qa-sync.json 2>/dev/null && echo "Synced to team ✓" || true + ~/.claude/skills/gstack/bin/gstack-sync push-transcript 2>/dev/null || true ``` Substitute actual values. Uses snake_case keys matching the Supabase schema. diff --git a/retro/SKILL.md b/retro/SKILL.md index 37acba7b..7d7b8eb5 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -358,6 +358,7 @@ Include backlog data in the JSON when TODOS.md exists: After writing the JSON snapshot, sync to the team store (non-fatal, silent if not configured): ```bash ~/.claude/skills/gstack/bin/gstack-sync push-retro ".context/retros/${today}-${next}.json" 2>/dev/null && echo "Synced to team ✓" || true +~/.claude/skills/gstack/bin/gstack-sync push-transcript 2>/dev/null || true ``` ### Step 14: Write the Narrative diff --git a/retro/SKILL.md.tmpl b/retro/SKILL.md.tmpl index 07a4e328..de3588be 100644 --- a/retro/SKILL.md.tmpl +++ b/retro/SKILL.md.tmpl @@ -349,6 +349,7 @@ Include backlog data in the JSON when TODOS.md exists: After writing the JSON snapshot, sync to the team store (non-fatal, silent if not configured): ```bash ~/.claude/skills/gstack/bin/gstack-sync push-retro ".context/retros/${today}-${next}.json" 2>/dev/null && echo "Synced to team ✓" || true +~/.claude/skills/gstack/bin/gstack-sync push-transcript 2>/dev/null || true ``` ### Step 14: Write the Narrative diff --git a/scripts/gen-skill-docs.ts b/scripts/gen-skill-docs.ts index 7f6bd249..69d6e978 100644 --- a/scripts/gen-skill-docs.ts +++ b/scripts/gen-skill-docs.ts @@ -183,6 +183,7 @@ function findTemplates(): string[] { path.join(ROOT, 'plan-eng-review', 'SKILL.md.tmpl'), path.join(ROOT, 'retro', 'SKILL.md.tmpl'), path.join(ROOT, 'gstack-upgrade', 'SKILL.md.tmpl'), + path.join(ROOT, 'setup-team-sync', 'SKILL.md.tmpl'), ]; for (const p of candidates) { if (fs.existsSync(p)) templates.push(p); diff --git a/setup-team-sync/SKILL.md b/setup-team-sync/SKILL.md new file mode 100644 index 00000000..63435527 --- /dev/null +++ b/setup-team-sync/SKILL.md @@ -0,0 +1,139 @@ +--- +name: setup-team-sync +version: 1.0.0 +description: | + Set up team sync with Supabase. Creates .gstack-sync.json if missing, + authenticates via OAuth, verifies connectivity, and configures sync settings. + Idempotent — safe to run multiple times. Use before first /ship, /retro, or /qa + to enable team data sharing. +allowed-tools: + - Bash + - Read + - Write + - AskUserQuestion +--- + + + +## Update Check (run first) + +```bash +_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +[ -n "$_UPD" ] && echo "$_UPD" || true +``` + +If output shows `UPGRADE_AVAILABLE `: read `~/.claude/skills/gstack/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED `: tell user "Running gstack v{to} (just updated!)" and continue. + +# Setup Team Sync + +Set up gstack team sync with Supabase. This skill is idempotent — safe to run anytime. + +## Steps + +### Step 1: Check project config + +```bash +cat .gstack-sync.json 2>/dev/null || echo "NOT_FOUND" +``` + +- If the file exists and has `supabase_url`, `supabase_anon_key`, and `team_slug`: print "Team config found: {team_slug} at {supabase_url}" and skip to Step 3. +- If NOT_FOUND: proceed to Step 2. + +### Step 2: Create .gstack-sync.json + +Ask the user for three values using AskUserQuestion: + +1. **Supabase URL** — e.g., `https://xyzcompany.supabase.co` + - Found in Supabase Dashboard → Project Settings → API → Project URL +2. **Anon Key** — the public `anon` key (NOT the `service_role` key) + - Found in Supabase Dashboard → Project Settings → API → Project API keys → `anon` `public` + - This key is safe to commit — it's public by design (like a Firebase API key). RLS enforces real access control. +3. **Team slug** — a short identifier like `my-team` or `yc-internal` + +Then write `.gstack-sync.json`: + +```bash +cat > .gstack-sync.json << 'ENDCONFIG' +{ + "supabase_url": "USER_PROVIDED_URL", + "supabase_anon_key": "USER_PROVIDED_KEY", + "team_slug": "USER_PROVIDED_SLUG" +} +ENDCONFIG +echo "Created .gstack-sync.json" +``` + +Tell the user: "Commit this file to your repo so team members get it automatically. The anon key is public by Supabase design — RLS enforces real access control." + +### Step 3: Check authentication + +```bash +~/.claude/skills/gstack/bin/gstack-sync status 2>&1 +``` + +Look at the output: +- If `Authenticated: yes` → skip to Step 5 +- If `Authenticated: no` → proceed to Step 4 + +### Step 4: Authenticate + +```bash +~/.claude/skills/gstack/bin/gstack-sync setup 2>&1 +``` + +This opens a browser for OAuth. Tell the user to complete authentication in their browser. Wait for the output to show "Authenticated as ..." or an error. + +If it fails with "Port 54321 is in use", ask the user to close the other process and retry. + +### Step 5: Test connectivity + +```bash +~/.claude/skills/gstack/bin/gstack-sync test 2>&1 +``` + +This runs a full push + pull test. All 4 steps should show `ok`: +1. Config: ok +2. Auth: ok +3. Push: ok (with latency) +4. Pull: ok (with row count) + +If Step 3 (Push) fails, tell the user: "The Supabase migrations may not be applied yet. Copy the SQL files from `supabase/migrations/` and run them in your Supabase SQL editor, in order (001 through 006)." + +### Step 6: Configure sync settings + +```bash +~/.claude/skills/gstack/bin/gstack-config get sync_enabled 2>/dev/null +~/.claude/skills/gstack/bin/gstack-config get sync_transcripts 2>/dev/null +``` + +Ask the user if they want to enable transcript sync (opt-in, shares Claude session data with the team): + +- If they say yes: + ```bash + ~/.claude/skills/gstack/bin/gstack-config set sync_enabled true + ~/.claude/skills/gstack/bin/gstack-config set sync_transcripts true + ``` + +- If they say no (or just want basic sync without transcripts): + ```bash + ~/.claude/skills/gstack/bin/gstack-config set sync_enabled true + ``` + +### Step 7: Summary + +Print a summary: + +``` +Team sync setup complete! + + Project config: .gstack-sync.json ✓ (commit to repo) + Authentication: {email} ✓ + Connectivity: {supabase_url} ✓ + Sync enabled: yes + Transcripts: {yes/no} + +Next steps: + • Run /ship, /retro, or /qa — data syncs automatically + • View team data: gstack-sync show + • Check status anytime: gstack-sync status +``` diff --git a/setup-team-sync/SKILL.md.tmpl b/setup-team-sync/SKILL.md.tmpl new file mode 100644 index 00000000..672a6738 --- /dev/null +++ b/setup-team-sync/SKILL.md.tmpl @@ -0,0 +1,130 @@ +--- +name: setup-team-sync +version: 1.0.0 +description: | + Set up team sync with Supabase. Creates .gstack-sync.json if missing, + authenticates via OAuth, verifies connectivity, and configures sync settings. + Idempotent — safe to run multiple times. Use before first /ship, /retro, or /qa + to enable team data sharing. +allowed-tools: + - Bash + - Read + - Write + - AskUserQuestion +--- + +{{UPDATE_CHECK}} + +# Setup Team Sync + +Set up gstack team sync with Supabase. This skill is idempotent — safe to run anytime. + +## Steps + +### Step 1: Check project config + +```bash +cat .gstack-sync.json 2>/dev/null || echo "NOT_FOUND" +``` + +- If the file exists and has `supabase_url`, `supabase_anon_key`, and `team_slug`: print "Team config found: {team_slug} at {supabase_url}" and skip to Step 3. +- If NOT_FOUND: proceed to Step 2. + +### Step 2: Create .gstack-sync.json + +Ask the user for three values using AskUserQuestion: + +1. **Supabase URL** — e.g., `https://xyzcompany.supabase.co` + - Found in Supabase Dashboard → Project Settings → API → Project URL +2. **Anon Key** — the public `anon` key (NOT the `service_role` key) + - Found in Supabase Dashboard → Project Settings → API → Project API keys → `anon` `public` + - This key is safe to commit — it's public by design (like a Firebase API key). RLS enforces real access control. +3. **Team slug** — a short identifier like `my-team` or `yc-internal` + +Then write `.gstack-sync.json`: + +```bash +cat > .gstack-sync.json << 'ENDCONFIG' +{ + "supabase_url": "USER_PROVIDED_URL", + "supabase_anon_key": "USER_PROVIDED_KEY", + "team_slug": "USER_PROVIDED_SLUG" +} +ENDCONFIG +echo "Created .gstack-sync.json" +``` + +Tell the user: "Commit this file to your repo so team members get it automatically. The anon key is public by Supabase design — RLS enforces real access control." + +### Step 3: Check authentication + +```bash +~/.claude/skills/gstack/bin/gstack-sync status 2>&1 +``` + +Look at the output: +- If `Authenticated: yes` → skip to Step 5 +- If `Authenticated: no` → proceed to Step 4 + +### Step 4: Authenticate + +```bash +~/.claude/skills/gstack/bin/gstack-sync setup 2>&1 +``` + +This opens a browser for OAuth. Tell the user to complete authentication in their browser. Wait for the output to show "Authenticated as ..." or an error. + +If it fails with "Port 54321 is in use", ask the user to close the other process and retry. + +### Step 5: Test connectivity + +```bash +~/.claude/skills/gstack/bin/gstack-sync test 2>&1 +``` + +This runs a full push + pull test. All 4 steps should show `ok`: +1. Config: ok +2. Auth: ok +3. Push: ok (with latency) +4. Pull: ok (with row count) + +If Step 3 (Push) fails, tell the user: "The Supabase migrations may not be applied yet. Copy the SQL files from `supabase/migrations/` and run them in your Supabase SQL editor, in order (001 through 006)." + +### Step 6: Configure sync settings + +```bash +~/.claude/skills/gstack/bin/gstack-config get sync_enabled 2>/dev/null +~/.claude/skills/gstack/bin/gstack-config get sync_transcripts 2>/dev/null +``` + +Ask the user if they want to enable transcript sync (opt-in, shares Claude session data with the team): + +- If they say yes: + ```bash + ~/.claude/skills/gstack/bin/gstack-config set sync_enabled true + ~/.claude/skills/gstack/bin/gstack-config set sync_transcripts true + ``` + +- If they say no (or just want basic sync without transcripts): + ```bash + ~/.claude/skills/gstack/bin/gstack-config set sync_enabled true + ``` + +### Step 7: Summary + +Print a summary: + +``` +Team sync setup complete! + + Project config: .gstack-sync.json ✓ (commit to repo) + Authentication: {email} ✓ + Connectivity: {supabase_url} ✓ + Sync enabled: yes + Transcripts: {yes/no} + +Next steps: + • Run /ship, /retro, or /qa — data syncs automatically + • View team data: gstack-sync show + • Check status anytime: gstack-sync status +``` diff --git a/ship/SKILL.md b/ship/SKILL.md index 1acb99cb..3dfbae07 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -431,6 +431,7 @@ Substitute actual values from the preceding steps. Use `0` for Greptile fields i 2. Push (non-fatal): ```bash ~/.claude/skills/gstack/bin/gstack-sync push-ship /tmp/gstack-ship-log.json 2>/dev/null && echo "Synced to team ✓" || true +~/.claude/skills/gstack/bin/gstack-sync push-transcript 2>/dev/null || true ``` --- diff --git a/ship/SKILL.md.tmpl b/ship/SKILL.md.tmpl index 32883263..7ebf12f2 100644 --- a/ship/SKILL.md.tmpl +++ b/ship/SKILL.md.tmpl @@ -422,6 +422,7 @@ Substitute actual values from the preceding steps. Use `0` for Greptile fields i 2. Push (non-fatal): ```bash ~/.claude/skills/gstack/bin/gstack-sync push-ship /tmp/gstack-ship-log.json 2>/dev/null && echo "Synced to team ✓" || true +~/.claude/skills/gstack/bin/gstack-sync push-transcript 2>/dev/null || true ``` ---