feat: /retro global — cross-project retro using discovery engine

Adds Global Retrospective Mode to the /retro skill. When invoked as
`/retro global`, skips the repo-scoped retro and instead uses
gstack-global-discover to find all AI coding sessions across all tools,
then runs git log on each discovered repo for a unified cross-project
retrospective with global shipping streak and context-switching metrics.
This commit is contained in:
Garry Tan
2026-03-22 02:04:25 -07:00
parent 9f2d6273c1
commit 4000ac0a36
4 changed files with 624 additions and 6 deletions
+207 -2
View File
@@ -258,6 +258,8 @@ When the user types `/retro`, run this skill.
- `/retro 30d` — last 30 days
- `/retro compare` — compare current window vs prior same-length window
- `/retro compare 14d` — compare with explicit window
- `/retro global` — cross-project retro across all AI coding tools (7d default)
- `/retro global 14d` — cross-project retro with explicit window
## Instructions
@@ -265,17 +267,21 @@ Parse the argument to determine the time window. Default to 7 days if no argumen
**Midnight-aligned windows:** For day (`d`) and week (`w`) units, compute an absolute start date at local midnight, not a relative string. For example, if today is 2026-03-18 and the window is 7 days: the start date is 2026-03-11. Use `--since="2026-03-11T00:00:00"` for git log queries — the explicit `T00:00:00` suffix ensures git starts from midnight. Without it, git uses the current wall-clock time (e.g., `--since="2026-03-11"` at 11pm means 11pm, not midnight). For week units, multiply by 7 to get days (e.g., `2w` = 14 days back). For hour (`h`) units, use `--since="N hours ago"` since midnight alignment does not apply to sub-day windows.
**Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare`, or `compare` followed by a number and `d`/`h`/`w`, show this usage and stop:
**Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare` (optionally followed by a window), or the word `global` (optionally followed by a window), show this usage and stop:
```
Usage: /retro [window]
Usage: /retro [window | compare | global]
/retro — last 7 days (default)
/retro 24h — last 24 hours
/retro 14d — last 14 days
/retro 30d — last 30 days
/retro compare — compare this period vs prior period
/retro compare 14d — compare with explicit window
/retro global — cross-project retro across all AI tools (7d default)
/retro global 14d — cross-project retro with explicit window
```
**If the first argument is `global`:** Skip the normal repo-scoped retro (Steps 1-14). Instead, follow the **Global Retrospective** flow at the end of this document. The optional second argument is the time window (default 7d). This mode does NOT require being inside a git repo.
### Step 1: Gather Raw Data
First, fetch origin and identify the current user:
@@ -721,6 +727,204 @@ Small, practical, realistic. Each must be something that takes <5 minutes to ado
---
## Global Retrospective Mode
When the user runs `/retro global` (or `/retro global 14d`), follow this flow instead of the repo-scoped Steps 1-14. This mode works from any directory — it does NOT require being inside a git repo.
### Global Step 1: Compute time window
Same midnight-aligned logic as the regular retro. Default 7d. The second argument after `global` is the window (e.g., `14d`, `30d`, `24h`).
### Global Step 2: Run discovery
Locate and run the discovery script using this fallback chain:
```bash
DISCOVER_BIN=""
[ -x ~/.codex/skills/gstack/bin/gstack-global-discover ] && DISCOVER_BIN=~/.codex/skills/gstack/bin/gstack-global-discover
[ -z "$DISCOVER_BIN" ] && [ -x .agents/skills/gstack/bin/gstack-global-discover ] && DISCOVER_BIN=.agents/skills/gstack/bin/gstack-global-discover
[ -z "$DISCOVER_BIN" ] && which gstack-global-discover >/dev/null 2>&1 && DISCOVER_BIN=$(which gstack-global-discover)
[ -z "$DISCOVER_BIN" ] && [ -f bin/gstack-global-discover.ts ] && DISCOVER_BIN="bun run bin/gstack-global-discover.ts"
echo "DISCOVER_BIN: $DISCOVER_BIN"
```
If no binary is found, tell the user: "Discovery script not found. Run `bun run build` in the gstack directory to compile it." and stop.
Run the discovery:
```bash
$DISCOVER_BIN --since "<window>" --format json 2>/tmp/gstack-discover-stderr
```
Read the stderr output from `/tmp/gstack-discover-stderr` for diagnostic info. Parse the JSON output from stdout.
If `total_sessions` is 0, say: "No AI coding sessions found in the last <window>. Try a longer window: `/retro global 30d`" and stop.
### Global Step 3: Run git log on each discovered repo
For each repo in the discovery JSON's `repos` array, find the first valid path in `paths[]` (directory exists with `.git/`). If no valid path exists, skip the repo and note it.
**For local-only repos** (where `remote` starts with `local:`): skip `git fetch` and use the local default branch. Use `git log HEAD` instead of `git log origin/$DEFAULT`.
**For repos with remotes:**
```bash
git -C <path> fetch origin --quiet 2>/dev/null
```
Detect the default branch for each repo: first try `git symbolic-ref refs/remotes/origin/HEAD`, then check common branch names (`main`, `master`), then fall back to `git rev-parse --abbrev-ref HEAD`. Use the detected branch as `<default>` in the commands below.
```bash
# Commits with stats
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%H|%aN|%ai|%s" --shortstat
# Commit timestamps for session detection, streak, and context switching
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%at|%aN|%ai|%s" | sort -n
# Per-author commit counts
git -C <path> shortlog origin/$DEFAULT --since="<start_date>T00:00:00" -sn --no-merges
# PR numbers from commit messages
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%s" | grep -oE '#[0-9]+' | sort -n | uniq
```
For repos that fail (deleted paths, network errors): skip and note "N repos could not be reached."
### Global Step 4: Compute global shipping streak
For each repo, get commit dates (capped at 365 days):
```bash
git -C <path> log origin/$DEFAULT --since="365 days ago" --format="%ad" --date=format:"%Y-%m-%d" | sort -u
```
Union all dates across all repos. Count backward from today — how many consecutive days have at least one commit to ANY repo? If the streak hits 365 days, display as "365+ days".
### Global Step 5: Compute context switching metric
From the commit timestamps gathered in Step 3, group by date. For each date, count how many distinct repos had commits that day. Report:
- Average repos/day
- Maximum repos/day
- Which days were focused (1 repo) vs. fragmented (3+ repos)
### Global Step 6: Per-tool productivity patterns
From the discovery JSON, analyze tool usage patterns:
- Which AI tool is used for which repos (exclusive vs. shared)
- Session count per tool
- Behavioral patterns (e.g., "Codex used exclusively for myapp, Claude Code for everything else")
### Global Step 7: Aggregate and generate narrative
Structure the output as:
---
**Tweetable summary** (first line, before everything else):
```
Week of Mar 14: 5 projects, 182 commits, 15.3k LOC | CC: 48, Codex: 8, Gemini: 3 | Focus: gstack (58%) | Streak: 52d
```
## Global Engineering Retro: [date range]
### Overview
| Metric | Value |
|--------|-------|
| Projects active | N |
| Total commits (all repos) | N |
| Total LOC | +N / -N |
| AI coding sessions | N (CC: X, Codex: Y, Gemini: Z) |
| Active days | N |
| Global shipping streak | N consecutive days |
| Context switches/day | N avg (max: M) |
### Per-Project Breakdown
For each repo (sorted by commits descending):
- Repo name (with % of total commits)
- Commits, LOC, PRs merged, top contributor
- Key work (inferred from commit messages)
- AI sessions by tool
### Cross-Project Patterns
- Time allocation across projects (% breakdown)
- Peak productivity hours aggregated across all repos
- Focused vs. fragmented days
- Context switching trends
### Tool Usage Analysis
Per-tool breakdown with behavioral patterns:
- Claude Code: N sessions across M repos — patterns observed
- Codex: N sessions across M repos — patterns observed
- Gemini: N sessions across M repos — patterns observed
### Ship of the Week (Global)
Highest-impact PR across ALL projects. Identify by LOC and commit messages.
### 3 Cross-Project Insights
What the global view reveals that no single-repo retro could show.
### 3 Habits for Next Week
Considering the full cross-project picture.
---
### Global Step 8: Load history & compare
```bash
ls -t ~/.gstack/retros/global-*.json 2>/dev/null | head -5
```
**Only compare against a prior retro with the same `window` value** (e.g., 7d vs 7d). If the most recent prior retro has a different window, skip comparison and note: "Prior global retro used a different window — skipping comparison."
If a matching prior retro exists, load it with the Read tool. Show a **Trends vs Last Global Retro** table with deltas for key metrics: total commits, LOC, sessions, streak, context switches/day.
If no prior global retros exist, append: "First global retro recorded — run again next week to see trends."
### Global Step 9: Save snapshot
```bash
mkdir -p ~/.gstack/retros
```
Determine the next sequence number for today:
```bash
today=$(date +%Y-%m-%d)
existing=$(ls ~/.gstack/retros/global-${today}-*.json 2>/dev/null | wc -l | tr -d ' ')
next=$((existing + 1))
```
Use the Write tool to save JSON to `~/.gstack/retros/global-${today}-${next}.json`:
```json
{
"type": "global",
"date": "2026-03-21",
"window": "7d",
"projects": [
{
"name": "gstack",
"remote": "https://github.com/garrytan/gstack",
"commits": 47,
"insertions": 3200,
"deletions": 800,
"sessions": { "claude_code": 15, "codex": 3, "gemini": 0 }
}
],
"totals": {
"commits": 182,
"insertions": 15300,
"deletions": 4200,
"projects": 5,
"active_days": 6,
"sessions": { "claude_code": 48, "codex": 8, "gemini": 3 },
"global_streak_days": 52,
"avg_context_switches_per_day": 2.1
},
"tweetable": "Week of Mar 14: 5 projects, 182 commits, 15.3k LOC | CC: 48, Codex: 8, Gemini: 3 | Focus: gstack (58%) | Streak: 52d"
}
```
---
## Compare Mode
When the user runs `/retro compare` (or `/retro compare 14d`):
@@ -754,3 +958,4 @@ When the user runs `/retro compare` (or `/retro compare 14d`):
- Treat merge commits as PR boundaries
- Do not read CLAUDE.md or other docs — this skill is self-contained
- On first run (no prior retros), skip comparison sections gracefully
- **Global mode:** Does NOT require being inside a git repo. Saves snapshots to `~/.gstack/retros/` (not `.context/retros/`). Gracefully skip AI tools that aren't installed. Only compare against prior global retros with the same window value. If streak hits 365d cap, display as "365+ days".
+207 -2
View File
@@ -265,6 +265,8 @@ When the user types `/retro`, run this skill.
- `/retro 30d` — last 30 days
- `/retro compare` — compare current window vs prior same-length window
- `/retro compare 14d` — compare with explicit window
- `/retro global` — cross-project retro across all AI coding tools (7d default)
- `/retro global 14d` — cross-project retro with explicit window
## Instructions
@@ -272,17 +274,21 @@ Parse the argument to determine the time window. Default to 7 days if no argumen
**Midnight-aligned windows:** For day (`d`) and week (`w`) units, compute an absolute start date at local midnight, not a relative string. For example, if today is 2026-03-18 and the window is 7 days: the start date is 2026-03-11. Use `--since="2026-03-11T00:00:00"` for git log queries — the explicit `T00:00:00` suffix ensures git starts from midnight. Without it, git uses the current wall-clock time (e.g., `--since="2026-03-11"` at 11pm means 11pm, not midnight). For week units, multiply by 7 to get days (e.g., `2w` = 14 days back). For hour (`h`) units, use `--since="N hours ago"` since midnight alignment does not apply to sub-day windows.
**Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare`, or `compare` followed by a number and `d`/`h`/`w`, show this usage and stop:
**Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare` (optionally followed by a window), or the word `global` (optionally followed by a window), show this usage and stop:
```
Usage: /retro [window]
Usage: /retro [window | compare | global]
/retro — last 7 days (default)
/retro 24h — last 24 hours
/retro 14d — last 14 days
/retro 30d — last 30 days
/retro compare — compare this period vs prior period
/retro compare 14d — compare with explicit window
/retro global — cross-project retro across all AI tools (7d default)
/retro global 14d — cross-project retro with explicit window
```
**If the first argument is `global`:** Skip the normal repo-scoped retro (Steps 1-14). Instead, follow the **Global Retrospective** flow at the end of this document. The optional second argument is the time window (default 7d). This mode does NOT require being inside a git repo.
### Step 1: Gather Raw Data
First, fetch origin and identify the current user:
@@ -728,6 +734,204 @@ Small, practical, realistic. Each must be something that takes <5 minutes to ado
---
## Global Retrospective Mode
When the user runs `/retro global` (or `/retro global 14d`), follow this flow instead of the repo-scoped Steps 1-14. This mode works from any directory — it does NOT require being inside a git repo.
### Global Step 1: Compute time window
Same midnight-aligned logic as the regular retro. Default 7d. The second argument after `global` is the window (e.g., `14d`, `30d`, `24h`).
### Global Step 2: Run discovery
Locate and run the discovery script using this fallback chain:
```bash
DISCOVER_BIN=""
[ -x ~/.claude/skills/gstack/bin/gstack-global-discover ] && DISCOVER_BIN=~/.claude/skills/gstack/bin/gstack-global-discover
[ -z "$DISCOVER_BIN" ] && [ -x .claude/skills/gstack/bin/gstack-global-discover ] && DISCOVER_BIN=.claude/skills/gstack/bin/gstack-global-discover
[ -z "$DISCOVER_BIN" ] && which gstack-global-discover >/dev/null 2>&1 && DISCOVER_BIN=$(which gstack-global-discover)
[ -z "$DISCOVER_BIN" ] && [ -f bin/gstack-global-discover.ts ] && DISCOVER_BIN="bun run bin/gstack-global-discover.ts"
echo "DISCOVER_BIN: $DISCOVER_BIN"
```
If no binary is found, tell the user: "Discovery script not found. Run `bun run build` in the gstack directory to compile it." and stop.
Run the discovery:
```bash
$DISCOVER_BIN --since "<window>" --format json 2>/tmp/gstack-discover-stderr
```
Read the stderr output from `/tmp/gstack-discover-stderr` for diagnostic info. Parse the JSON output from stdout.
If `total_sessions` is 0, say: "No AI coding sessions found in the last <window>. Try a longer window: `/retro global 30d`" and stop.
### Global Step 3: Run git log on each discovered repo
For each repo in the discovery JSON's `repos` array, find the first valid path in `paths[]` (directory exists with `.git/`). If no valid path exists, skip the repo and note it.
**For local-only repos** (where `remote` starts with `local:`): skip `git fetch` and use the local default branch. Use `git log HEAD` instead of `git log origin/$DEFAULT`.
**For repos with remotes:**
```bash
git -C <path> fetch origin --quiet 2>/dev/null
```
Detect the default branch for each repo: first try `git symbolic-ref refs/remotes/origin/HEAD`, then check common branch names (`main`, `master`), then fall back to `git rev-parse --abbrev-ref HEAD`. Use the detected branch as `<default>` in the commands below.
```bash
# Commits with stats
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%H|%aN|%ai|%s" --shortstat
# Commit timestamps for session detection, streak, and context switching
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%at|%aN|%ai|%s" | sort -n
# Per-author commit counts
git -C <path> shortlog origin/$DEFAULT --since="<start_date>T00:00:00" -sn --no-merges
# PR numbers from commit messages
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%s" | grep -oE '#[0-9]+' | sort -n | uniq
```
For repos that fail (deleted paths, network errors): skip and note "N repos could not be reached."
### Global Step 4: Compute global shipping streak
For each repo, get commit dates (capped at 365 days):
```bash
git -C <path> log origin/$DEFAULT --since="365 days ago" --format="%ad" --date=format:"%Y-%m-%d" | sort -u
```
Union all dates across all repos. Count backward from today — how many consecutive days have at least one commit to ANY repo? If the streak hits 365 days, display as "365+ days".
### Global Step 5: Compute context switching metric
From the commit timestamps gathered in Step 3, group by date. For each date, count how many distinct repos had commits that day. Report:
- Average repos/day
- Maximum repos/day
- Which days were focused (1 repo) vs. fragmented (3+ repos)
### Global Step 6: Per-tool productivity patterns
From the discovery JSON, analyze tool usage patterns:
- Which AI tool is used for which repos (exclusive vs. shared)
- Session count per tool
- Behavioral patterns (e.g., "Codex used exclusively for myapp, Claude Code for everything else")
### Global Step 7: Aggregate and generate narrative
Structure the output as:
---
**Tweetable summary** (first line, before everything else):
```
Week of Mar 14: 5 projects, 182 commits, 15.3k LOC | CC: 48, Codex: 8, Gemini: 3 | Focus: gstack (58%) | Streak: 52d
```
## Global Engineering Retro: [date range]
### Overview
| Metric | Value |
|--------|-------|
| Projects active | N |
| Total commits (all repos) | N |
| Total LOC | +N / -N |
| AI coding sessions | N (CC: X, Codex: Y, Gemini: Z) |
| Active days | N |
| Global shipping streak | N consecutive days |
| Context switches/day | N avg (max: M) |
### Per-Project Breakdown
For each repo (sorted by commits descending):
- Repo name (with % of total commits)
- Commits, LOC, PRs merged, top contributor
- Key work (inferred from commit messages)
- AI sessions by tool
### Cross-Project Patterns
- Time allocation across projects (% breakdown)
- Peak productivity hours aggregated across all repos
- Focused vs. fragmented days
- Context switching trends
### Tool Usage Analysis
Per-tool breakdown with behavioral patterns:
- Claude Code: N sessions across M repos — patterns observed
- Codex: N sessions across M repos — patterns observed
- Gemini: N sessions across M repos — patterns observed
### Ship of the Week (Global)
Highest-impact PR across ALL projects. Identify by LOC and commit messages.
### 3 Cross-Project Insights
What the global view reveals that no single-repo retro could show.
### 3 Habits for Next Week
Considering the full cross-project picture.
---
### Global Step 8: Load history & compare
```bash
ls -t ~/.gstack/retros/global-*.json 2>/dev/null | head -5
```
**Only compare against a prior retro with the same `window` value** (e.g., 7d vs 7d). If the most recent prior retro has a different window, skip comparison and note: "Prior global retro used a different window — skipping comparison."
If a matching prior retro exists, load it with the Read tool. Show a **Trends vs Last Global Retro** table with deltas for key metrics: total commits, LOC, sessions, streak, context switches/day.
If no prior global retros exist, append: "First global retro recorded — run again next week to see trends."
### Global Step 9: Save snapshot
```bash
mkdir -p ~/.gstack/retros
```
Determine the next sequence number for today:
```bash
today=$(date +%Y-%m-%d)
existing=$(ls ~/.gstack/retros/global-${today}-*.json 2>/dev/null | wc -l | tr -d ' ')
next=$((existing + 1))
```
Use the Write tool to save JSON to `~/.gstack/retros/global-${today}-${next}.json`:
```json
{
"type": "global",
"date": "2026-03-21",
"window": "7d",
"projects": [
{
"name": "gstack",
"remote": "https://github.com/garrytan/gstack",
"commits": 47,
"insertions": 3200,
"deletions": 800,
"sessions": { "claude_code": 15, "codex": 3, "gemini": 0 }
}
],
"totals": {
"commits": 182,
"insertions": 15300,
"deletions": 4200,
"projects": 5,
"active_days": 6,
"sessions": { "claude_code": 48, "codex": 8, "gemini": 3 },
"global_streak_days": 52,
"avg_context_switches_per_day": 2.1
},
"tweetable": "Week of Mar 14: 5 projects, 182 commits, 15.3k LOC | CC: 48, Codex: 8, Gemini: 3 | Focus: gstack (58%) | Streak: 52d"
}
```
---
## Compare Mode
When the user runs `/retro compare` (or `/retro compare 14d`):
@@ -761,3 +965,4 @@ When the user runs `/retro compare` (or `/retro compare 14d`):
- Treat merge commits as PR boundaries
- Do not read CLAUDE.md or other docs — this skill is self-contained
- On first run (no prior retros), skip comparison sections gracefully
- **Global mode:** Does NOT require being inside a git repo. Saves snapshots to `~/.gstack/retros/` (not `.context/retros/`). Gracefully skip AI tools that aren't installed. Only compare against prior global retros with the same window value. If streak hits 365d cap, display as "365+ days".
+207 -2
View File
@@ -41,6 +41,8 @@ When the user types `/retro`, run this skill.
- `/retro 30d` — last 30 days
- `/retro compare` — compare current window vs prior same-length window
- `/retro compare 14d` — compare with explicit window
- `/retro global` — cross-project retro across all AI coding tools (7d default)
- `/retro global 14d` — cross-project retro with explicit window
## Instructions
@@ -48,17 +50,21 @@ Parse the argument to determine the time window. Default to 7 days if no argumen
**Midnight-aligned windows:** For day (`d`) and week (`w`) units, compute an absolute start date at local midnight, not a relative string. For example, if today is 2026-03-18 and the window is 7 days: the start date is 2026-03-11. Use `--since="2026-03-11T00:00:00"` for git log queries — the explicit `T00:00:00` suffix ensures git starts from midnight. Without it, git uses the current wall-clock time (e.g., `--since="2026-03-11"` at 11pm means 11pm, not midnight). For week units, multiply by 7 to get days (e.g., `2w` = 14 days back). For hour (`h`) units, use `--since="N hours ago"` since midnight alignment does not apply to sub-day windows.
**Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare`, or `compare` followed by a number and `d`/`h`/`w`, show this usage and stop:
**Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare` (optionally followed by a window), or the word `global` (optionally followed by a window), show this usage and stop:
```
Usage: /retro [window]
Usage: /retro [window | compare | global]
/retro — last 7 days (default)
/retro 24h — last 24 hours
/retro 14d — last 14 days
/retro 30d — last 30 days
/retro compare — compare this period vs prior period
/retro compare 14d — compare with explicit window
/retro global — cross-project retro across all AI tools (7d default)
/retro global 14d — cross-project retro with explicit window
```
**If the first argument is `global`:** Skip the normal repo-scoped retro (Steps 1-14). Instead, follow the **Global Retrospective** flow at the end of this document. The optional second argument is the time window (default 7d). This mode does NOT require being inside a git repo.
### Step 1: Gather Raw Data
First, fetch origin and identify the current user:
@@ -504,6 +510,204 @@ Small, practical, realistic. Each must be something that takes <5 minutes to ado
---
## Global Retrospective Mode
When the user runs `/retro global` (or `/retro global 14d`), follow this flow instead of the repo-scoped Steps 1-14. This mode works from any directory — it does NOT require being inside a git repo.
### Global Step 1: Compute time window
Same midnight-aligned logic as the regular retro. Default 7d. The second argument after `global` is the window (e.g., `14d`, `30d`, `24h`).
### Global Step 2: Run discovery
Locate and run the discovery script using this fallback chain:
```bash
DISCOVER_BIN=""
[ -x ~/.claude/skills/gstack/bin/gstack-global-discover ] && DISCOVER_BIN=~/.claude/skills/gstack/bin/gstack-global-discover
[ -z "$DISCOVER_BIN" ] && [ -x .claude/skills/gstack/bin/gstack-global-discover ] && DISCOVER_BIN=.claude/skills/gstack/bin/gstack-global-discover
[ -z "$DISCOVER_BIN" ] && which gstack-global-discover >/dev/null 2>&1 && DISCOVER_BIN=$(which gstack-global-discover)
[ -z "$DISCOVER_BIN" ] && [ -f bin/gstack-global-discover.ts ] && DISCOVER_BIN="bun run bin/gstack-global-discover.ts"
echo "DISCOVER_BIN: $DISCOVER_BIN"
```
If no binary is found, tell the user: "Discovery script not found. Run `bun run build` in the gstack directory to compile it." and stop.
Run the discovery:
```bash
$DISCOVER_BIN --since "<window>" --format json 2>/tmp/gstack-discover-stderr
```
Read the stderr output from `/tmp/gstack-discover-stderr` for diagnostic info. Parse the JSON output from stdout.
If `total_sessions` is 0, say: "No AI coding sessions found in the last <window>. Try a longer window: `/retro global 30d`" and stop.
### Global Step 3: Run git log on each discovered repo
For each repo in the discovery JSON's `repos` array, find the first valid path in `paths[]` (directory exists with `.git/`). If no valid path exists, skip the repo and note it.
**For local-only repos** (where `remote` starts with `local:`): skip `git fetch` and use the local default branch. Use `git log HEAD` instead of `git log origin/$DEFAULT`.
**For repos with remotes:**
```bash
git -C <path> fetch origin --quiet 2>/dev/null
```
Detect the default branch for each repo: first try `git symbolic-ref refs/remotes/origin/HEAD`, then check common branch names (`main`, `master`), then fall back to `git rev-parse --abbrev-ref HEAD`. Use the detected branch as `<default>` in the commands below.
```bash
# Commits with stats
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%H|%aN|%ai|%s" --shortstat
# Commit timestamps for session detection, streak, and context switching
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%at|%aN|%ai|%s" | sort -n
# Per-author commit counts
git -C <path> shortlog origin/$DEFAULT --since="<start_date>T00:00:00" -sn --no-merges
# PR numbers from commit messages
git -C <path> log origin/$DEFAULT --since="<start_date>T00:00:00" --format="%s" | grep -oE '#[0-9]+' | sort -n | uniq
```
For repos that fail (deleted paths, network errors): skip and note "N repos could not be reached."
### Global Step 4: Compute global shipping streak
For each repo, get commit dates (capped at 365 days):
```bash
git -C <path> log origin/$DEFAULT --since="365 days ago" --format="%ad" --date=format:"%Y-%m-%d" | sort -u
```
Union all dates across all repos. Count backward from today — how many consecutive days have at least one commit to ANY repo? If the streak hits 365 days, display as "365+ days".
### Global Step 5: Compute context switching metric
From the commit timestamps gathered in Step 3, group by date. For each date, count how many distinct repos had commits that day. Report:
- Average repos/day
- Maximum repos/day
- Which days were focused (1 repo) vs. fragmented (3+ repos)
### Global Step 6: Per-tool productivity patterns
From the discovery JSON, analyze tool usage patterns:
- Which AI tool is used for which repos (exclusive vs. shared)
- Session count per tool
- Behavioral patterns (e.g., "Codex used exclusively for myapp, Claude Code for everything else")
### Global Step 7: Aggregate and generate narrative
Structure the output as:
---
**Tweetable summary** (first line, before everything else):
```
Week of Mar 14: 5 projects, 182 commits, 15.3k LOC | CC: 48, Codex: 8, Gemini: 3 | Focus: gstack (58%) | Streak: 52d
```
## Global Engineering Retro: [date range]
### Overview
| Metric | Value |
|--------|-------|
| Projects active | N |
| Total commits (all repos) | N |
| Total LOC | +N / -N |
| AI coding sessions | N (CC: X, Codex: Y, Gemini: Z) |
| Active days | N |
| Global shipping streak | N consecutive days |
| Context switches/day | N avg (max: M) |
### Per-Project Breakdown
For each repo (sorted by commits descending):
- Repo name (with % of total commits)
- Commits, LOC, PRs merged, top contributor
- Key work (inferred from commit messages)
- AI sessions by tool
### Cross-Project Patterns
- Time allocation across projects (% breakdown)
- Peak productivity hours aggregated across all repos
- Focused vs. fragmented days
- Context switching trends
### Tool Usage Analysis
Per-tool breakdown with behavioral patterns:
- Claude Code: N sessions across M repos — patterns observed
- Codex: N sessions across M repos — patterns observed
- Gemini: N sessions across M repos — patterns observed
### Ship of the Week (Global)
Highest-impact PR across ALL projects. Identify by LOC and commit messages.
### 3 Cross-Project Insights
What the global view reveals that no single-repo retro could show.
### 3 Habits for Next Week
Considering the full cross-project picture.
---
### Global Step 8: Load history & compare
```bash
ls -t ~/.gstack/retros/global-*.json 2>/dev/null | head -5
```
**Only compare against a prior retro with the same `window` value** (e.g., 7d vs 7d). If the most recent prior retro has a different window, skip comparison and note: "Prior global retro used a different window — skipping comparison."
If a matching prior retro exists, load it with the Read tool. Show a **Trends vs Last Global Retro** table with deltas for key metrics: total commits, LOC, sessions, streak, context switches/day.
If no prior global retros exist, append: "First global retro recorded — run again next week to see trends."
### Global Step 9: Save snapshot
```bash
mkdir -p ~/.gstack/retros
```
Determine the next sequence number for today:
```bash
today=$(date +%Y-%m-%d)
existing=$(ls ~/.gstack/retros/global-${today}-*.json 2>/dev/null | wc -l | tr -d ' ')
next=$((existing + 1))
```
Use the Write tool to save JSON to `~/.gstack/retros/global-${today}-${next}.json`:
```json
{
"type": "global",
"date": "2026-03-21",
"window": "7d",
"projects": [
{
"name": "gstack",
"remote": "https://github.com/garrytan/gstack",
"commits": 47,
"insertions": 3200,
"deletions": 800,
"sessions": { "claude_code": 15, "codex": 3, "gemini": 0 }
}
],
"totals": {
"commits": 182,
"insertions": 15300,
"deletions": 4200,
"projects": 5,
"active_days": 6,
"sessions": { "claude_code": 48, "codex": 8, "gemini": 3 },
"global_streak_days": 52,
"avg_context_switches_per_day": 2.1
},
"tweetable": "Week of Mar 14: 5 projects, 182 commits, 15.3k LOC | CC: 48, Codex: 8, Gemini: 3 | Focus: gstack (58%) | Streak: 52d"
}
```
---
## Compare Mode
When the user runs `/retro compare` (or `/retro compare 14d`):
@@ -537,3 +741,4 @@ When the user runs `/retro compare` (or `/retro compare 14d`):
- Treat merge commits as PR boundaries
- Do not read CLAUDE.md or other docs — this skill is self-contained
- On first run (no prior retros), skip comparison sections gracefully
- **Global mode:** Does NOT require being inside a git repo. Saves snapshots to `~/.gstack/retros/` (not `.context/retros/`). Gracefully skip AI tools that aren't installed. Only compare against prior global retros with the same window value. If streak hits 365d cap, display as "365+ days".
+3
View File
@@ -80,6 +80,9 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'retro': ['retro/**'],
'retro-base-branch': ['retro/**'],
// Global discover
'global-discover': ['bin/gstack-global-discover.ts', 'test/global-discover.test.ts'],
// Document-release
'document-release': ['document-release/**'],