--- name: retro preamble-tier: 2 version: 2.0.0 description: | Weekly engineering retrospective. Analyzes commit history, work patterns, and code quality metrics with persistent history and trend tracking. Team-aware: breaks down per-person contributions with praise and growth areas. Use when asked to "weekly retro", "what did we ship", or "engineering retrospective". Proactively suggest at the end of a work week or sprint. (gstack) allowed-tools: - Bash - Read - Write - Glob - AskUserQuestion triggers: - weekly retro - what did we ship - engineering retrospective gbrain: schema: 1 context_queries: - id: prior-retros kind: filesystem # #2552: /retro writes .context/retros/*.json (repo-local; see the save # step below) — the old ~/.gstack/.../retros/*.md glob matched a # directory and extension nothing ever writes, so this query was dead. glob: ".context/retros/*.json" sort: mtime_desc limit: 5 render_as: "## Prior retros for this project" - id: recent-timeline kind: filesystem glob: "~/.gstack/projects/{repo_slug}/timeline.jsonl" tail: 30 render_as: "## Recent timeline events" - id: recent-learnings kind: filesystem glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl" tail: 10 render_as: "## Recent learnings" --- {{PREAMBLE}} {{BASE_BRANCH_DETECT}} # /retro — Weekly Engineering Retrospective Generates a comprehensive engineering retrospective analyzing commit history, work patterns, and code quality metrics. Team-aware: identifies the user running the command, then analyzes every contributor with per-person praise and growth opportunities. Designed for a senior IC/CTO-level builder using Claude Code as a force multiplier. ## User-invocable When the user types `/retro`, run this skill. ## Arguments - `/retro` — default: last 7 days - `/retro 24h` — last 24 hours - `/retro 14d` — last 14 days - `/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 {{GBRAIN_CONTEXT_LOAD}} {{SECTION_INDEX:retro}} ## Instructions Parse the argument to determine the time window. Default to 7 days if no argument given. All times should be reported in the user's **local timezone** (use the system default — do NOT set `TZ`). **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"` — 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. Compute "today" from the user-visible `## currentDate` tag in the session reminder — NEVER from `date` (the system clock can be hours off in containerized harnesses). If you cannot reliably compute "today", stop and ask the user via AskUserQuestion rather than proceeding. **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 | 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. {{LEARNINGS_SEARCH}} ### Step 0.5: Freshness pre-flight (fetch) Refresh `origin/` so the retro doesn't misreport against a stale local ref. If the repo has no `origin` remote this fails harmlessly — the metrics script (Step 1) falls back to the local branch and its guard lines disclose it: ```bash git fetch origin --quiet 2>/dev/null \ || echo "RETRO_FETCH: failed (offline or no remote) — proceeding against last-known refs" ``` Remember whether the fetch succeeded — the stale-base guard in Step 1 only BLOCKs when it did. ### Step 1: Gather Metrics (one command) All raw data gathering and metric computation runs through `gstack-retro-metrics` — one command instead of a dozen git pipelines. Substitute the base branch detected in Step 0 and the midnight-aligned start computed above: ```bash _RM="$HOME/.claude/skills/gstack/bin/gstack-retro-metrics" [ -x "$_RM" ] || _RM=".claude/skills/gstack/bin/gstack-retro-metrics" "$_RM" --base "" --since "" \ || echo "RETRO_METRICS: unavailable — stale install (compute metrics manually from the steps below)" ``` Read the labeled `METRIC_NAME: value` lines — they feed every step below. **Degraded mode:** if `RETRO_METRICS_PROTO: 1` is missing from the output, the install is stale; compute each metric manually with git commands, using the metric definitions in Steps 2-11 as the spec. **Identity:** `USER_NAME` is **"you"** — the person reading this retro. All other authors are teammates. Orient the narrative around this: "your" commits vs teammate contributions. **Stale-base + bad-today-anchor guard.** The script echoes `GUARD_LATEST_COMMIT: ` (newest commit on the analyzed ref). If "today" drifts (model session-context error) or the local `origin/` is materially behind the remote, the window returns zero or near-zero commits and the retro would fabricate a coherent-looking narrative from nothing. Evaluate in this order: 1. If `GUARD_REMOTE: none` or `GUARD_HEAD: detached` or the Step 0.5 fetch failed: proceed, but carry the disclosure into the narrative ("offline run, window not freshness-verified") rather than silently misreporting. 2. If the Step 0.5 fetch succeeded AND the `GUARD_LATEST_COMMIT` date is **older than (today − window-days)**: BLOCK with: "Retro window is stale. Latest commit on `origin/` was ``, but the window covers `` to ``. This usually means either (a) today's date is wrong in this session or (b) `origin/` is materially behind the remote. Confirm today's date via the session reminder; if today is correct, run `git fetch origin ` manually and re-run /retro." Stop the skill until the user resolves. 3. Otherwise, write: "RETRO_GUARD: latest commit `` within window — proceeding." Also check `RETRO_REF`: if it is not `origin/` (local-only repo, missing remote branch), disclose which ref the retro analyzed. **Metric line reference** (what the script emits): | Line | Meaning | |------|---------| | `COMMIT: hash\|author\|datetime\|+ins/-del\|subject` | One per commit, newest first (capped at 300) — the raw material for narrative anchoring | | `COMMITS` / `MERGE_COMMITS` / `CONTRIBUTORS` | Window totals on the analyzed ref | | `INSERTIONS` / `DELETIONS` / `NET_LOC` | Raw LOC | | `LOGICAL_SLOC_ADDED` | Non-blank, non-comment added lines — the primary code-volume metric | | `TEST_INSERTIONS` / `TEST_RATIO` | Test LOC (test/spec paths + .test./.spec. suffixes) and its share of insertions | | `WEIGHTED_COMMITS` | Commits × files-touched, capped at 20 per commit | | `ACTIVE_DAYS` | Distinct local dates with commits | | `SESSIONS` / `DEEP_SESSIONS` / `MEDIUM_SESSIONS` / `MICRO_SESSIONS` | 45-minute-gap session detection: deep 50+ min, medium 20-50, micro <20 | | `TOTAL_ACTIVE_MINUTES` / `AVG_SESSION_MINUTES` / `LOC_PER_SESSION_HOUR` | Session time aggregates (LOC/hour pre-rounded to nearest 50) | | `COMMIT_TYPES` / `FIX_RATIO` | Conventional-commit prefix mix | | `COMMIT_SIZE_BUCKETS` | small <100 / medium 100-500 / large 500-1500 / xl 1500+ LOC per commit | | `HOURS` / `PEAK_HOUR` | Hourly commit histogram (local time), nonzero hours only | | `FOCUS_SCORE` | % of file changes in the single busiest top-level directory | | `BIGGEST_COMMIT` | Highest-LOC commit in the window (ship-of-the-week candidate) | | `HOTSPOT: count file` | Top 10 most-changed files | | `AUTHOR: name\|commits\|ins\|del\|test_ratio\|top_areas\|types\|peak_hour` | Per-contributor rollup, sorted by commits desc | | `AUTHOR_BIGGEST: name\|hash\|loc\|subject` | Each contributor's biggest ship | | `COAUTHOR: hash\|name` / `AI_ASSISTED_COMMITS` | Human co-author credit lines; count of commits with AI trailers | | `WEEK: wN\|commits\|ins\|del\|test_ratio` | Weekly buckets, w0 = newest (for Step 10 trends) | | `PR_REFS` / `PRS_REFERENCED` | PR/MR numbers from commit subjects (GitHub #NNN, GitLab !NNN) | | `TEST_FILES_TOTAL` / `TEST_FILES_CHANGED` / `REGRESSION_TEST_COMMITS` / `REGRESSION_COMMIT` | Test health: repo-wide test file count, test files changed in window, `test(qa):` / `test(design):` / `test: coverage` commits | | `VERSION_RANGE` | First → last VERSION file value in the window (when tracked) | | `TEAM_STREAK` / `USER_STREAK` | Consecutive commit days with anchor date (Step 11) | | `RETRO_CONTEXT` / `GREPTILE_HISTORY` / `TODOS_FILE` / `SKILL_USAGE_LOG` / `EUREKA_LOG` | Presence of optional inputs — Read the ones marked present | **Optional inputs** (Read each file the script marks `present`): - `RETRO_CONTEXT: present` → Read `~/.gstack/retro-context.md`. It is user-authored and may contain meeting notes, calendar events, decisions, and other context that doesn't appear in git history. Incorporate it into the retro narrative where relevant. - `GREPTILE_HISTORY: present` → Read `~/.gstack/greptile-history.md`. Filter entries to the retro window by date. Count by type: `fix`, `fp`, `already-fixed`. Signal ratio = `(fix + already-fixed) / (fix + already-fixed + fp)`. Skip unparseable lines silently; if no entries fall in the window, skip the Greptile metric row. - `TODOS_FILE: present` → Read `TODOS.md`. Compute: total open TODOs (exclude the `## Completed` section), P0/P1 count, P2 count, items completed this period (Completed entries dated within the window), items added this period (cross-reference `COMMIT:` lines that touched TODOS.md). - `SKILL_USAGE_LOG: present` → Read `~/.gstack/analytics/skill-usage.jsonl`. Filter to the window by `ts`. Separate skill activations (no `event` field) from hook fires (`event: "hook_fire"`). Aggregate by skill name. - `EUREKA_LOG: present` → Read `~/.gstack/analytics/eureka.jsonl`. Filter to the window by `ts`. For each eureka moment note the skill that flagged it, the branch, and a one-line summary of the insight. ### Step 2: Compute Metrics Present these metrics in a summary table, straight from the metric lines: | Metric | Value | |--------|-------| | **Features shipped** (from CHANGELOG + merged PR titles) | N | | Commits to main | N | | Weighted commits (`WEIGHTED_COMMITS`) | N | | Contributors | N | | PRs merged | N | | **Logical SLOC added** (`LOGICAL_SLOC_ADDED` — primary code-volume metric) | N | | Raw LOC: insertions | N | | Raw LOC: deletions | N | | Raw LOC: net | N | | Test LOC (insertions) | N | | Test LOC ratio | N% | | Version range | vX.Y.Z.W → vX.Y.Z.W | | Active days | N | | Detected sessions | N | | Avg raw LOC/session-hour | N | | Greptile signal | N% (Y catches, Z FPs) | | Test Health | N total tests · M added this period · K regression tests | **Metric order rationale (V1):** features shipped leads — what users got. Commits and weighted commits reflect intent-to-ship. Logical SLOC added reflects real new functionality. Raw LOC is demoted to context because AI inflates it; ten lines of a good fix is not less shipping than ten thousand lines of scaffold. See docs/designs/PLAN_TUNING_V1.md §Workstream C. Then show a **per-author leaderboard** immediately below, from the `AUTHOR:` lines: ``` Contributor Commits +/- Top area You (garry) 32 +2400/-300 browse/ alice 12 +800/-150 app/services/ bob 3 +120/-40 tests/ ``` Sort by commits descending. The current user (`USER_NAME`) always appears first, labeled "You (name)". Conditional rows (skip each when its input is absent or empty in the window): ``` | Backlog Health | N open (X P0/P1, Y P2) · Z completed this period | | Skill Usage | /ship(12) /qa(8) /review(5) · 3 safety hook fires | | Eureka Moments | 2 this period | ``` If eureka moments exist, list them: ``` EUREKA /office-hours (branch: garrytan/auth-rethink): "Session tokens don't need server storage — browser crypto API makes client-side JWT validation viable" EUREKA /plan-eng-review (branch: garrytan/cache-layer): "Redis isn't needed here — Bun's built-in LRU cache handles this workload" ``` ### Step 3: Commit Time Distribution Render the `HOURS` line as an hourly histogram in local time: ``` Hour Commits ████████████████ 00: 4 ████ 07: 5 █████ ... ``` Identify and call out: - Peak hours - Dead zones - Whether pattern is bimodal (morning/evening) or continuous - Late-night coding clusters (after 10pm) ### Step 4: Work Session Detection Sessions are pre-computed with a **45-minute gap** threshold between consecutive commits (`SESSIONS`, `DEEP_SESSIONS` 50+ min, `MEDIUM_SESSIONS` 20-50 min, `MICRO_SESSIONS` <20 min — typically single-commit fire-and-forget). Report: - Session count and the deep/medium/micro split - Total active coding time (`TOTAL_ACTIVE_MINUTES`) and average session length - LOC per hour of active time (`LOC_PER_SESSION_HOUR`) ### Step 5: Commit Type Breakdown Render `COMMIT_TYPES` (feat/fix/refactor/test/chore/docs) as a percentage bar: ``` feat: 20 (40%) ████████████████████ fix: 27 (54%) ███████████████████████████ refactor: 2 ( 4%) ██ ``` Flag if `FIX_RATIO` exceeds 50% — this signals a "ship fast, fix fast" pattern that may indicate review gaps. ### Step 6: Hotspot Analysis Show the `HOTSPOT` lines (top 10 most-changed files). Flag: - Files changed 5+ times (churn hotspots) - Test files vs production files in the hotspot list - VERSION/CHANGELOG frequency (version discipline indicator) ### Step 7: PR Size Distribution Report `COMMIT_SIZE_BUCKETS`: - **Small** (<100 LOC) - **Medium** (100-500 LOC) - **Large** (500-1500 LOC) - **XL** (1500+ LOC) ### Step 8: Focus Score + Ship of the Week **Focus score:** `FOCUS_SCORE` is the percentage of file changes touching the single most-changed top-level directory (e.g., `app/services/`). Higher score = deeper focused work. Lower score = scattered context-switching. Report as: "Focus score: 62% (app/services/)" **Ship of the week:** `BIGGEST_COMMIT` is the highest-LOC change in the window. Highlight it: - PR number (match against `PR_REFS` / the subject) and title - LOC changed - Why it matters (infer from commit messages and files touched) ### Step 9: Team Member Analysis For each contributor (including the current user), the `AUTHOR:` line carries commits, insertions, deletions, test ratio, top areas, commit type mix, and peak hour; `AUTHOR_BIGGEST:` carries their single highest-impact commit. Use the `COMMIT:` lines to anchor everything in actual work. **For the current user ("You"):** This section gets the deepest treatment. Include all the detail from the solo retro — session analysis, time patterns, focus score. Frame it in first person: "Your peak hours...", "Your biggest ship..." **For each teammate:** Write 2-3 sentences covering what they worked on and their pattern. Then: - **Praise** (1-2 specific things): Anchor in actual commits. Not "great work" — say exactly what was good. Examples: "Shipped the entire auth middleware rewrite in 3 focused sessions with 45% test coverage", "Every PR under 200 LOC — disciplined decomposition." - **Opportunity for growth** (1 specific thing): Frame as a leveling-up suggestion, not criticism. Anchor in actual data. Examples: "Test ratio was 12% this week — adding test coverage to the payment module before it gets more complex would pay off", "5 fix commits on the same file suggest the original PR could have used a review pass." **If only one contributor (solo repo):** Skip the team breakdown and proceed as before — the retro is personal. **Co-author credit:** `COAUTHOR:` lines carry human `Co-Authored-By:` trailers — credit those authors for the commit alongside the primary author. AI co-authors (e.g., `noreply@anthropic.com`) are counted in `AI_ASSISTED_COMMITS` instead — track "AI-assisted commits" as a separate metric, never as a team member. {{LEARNINGS_LOG}} {{GBRAIN_SAVE_RESULTS}} ### Step 10: Week-over-Week Trends (if window >= 14d) If the time window is 14 days or more, use the `WEEK:` lines (w0 = the week containing the newest commit) to show trends: - Commits per week (total; per-author from the `COMMIT:` lines) - LOC per week - Test ratio per week - Fix ratio per week ### Step 11: Streak Tracking `TEAM_STREAK` and `USER_STREAK` count consecutive days with at least 1 commit (full history, no cutoff), anchored at the **newest commit date** — not at today, because the script never trusts the system clock. Interpret against today from the session reminder: - If the anchor date is today or yesterday, the streak is live: "Team shipping streak: 47 consecutive days" / "Your shipping streak: 32 consecutive days" - If the anchor is older, the streak is broken: report 0 days and note the last shipping day. ### Step 12: Load History & Compare Before saving the new snapshot, check for prior retro history: ```bash setopt +o nomatch 2>/dev/null || true # zsh compat ls -t .context/retros/*.json 2>/dev/null ``` **If prior retros exist:** Load the most recent one using the Read tool. Calculate deltas for key metrics and include a **Trends vs Last Retro** section: ``` Last Now Delta Test ratio: 22% → 41% ↑19pp Sessions: 10 → 14 ↑4 LOC/hour: 200 → 350 ↑75% Fix ratio: 54% → 30% ↓24pp (improving) Commits: 32 → 47 ↑47% Deep sessions: 3 → 5 ↑2 ``` **If no prior retros exist:** Skip the comparison section and append: "First retro recorded — run again next week to see trends." ### Step 13: Save Retro History After computing all metrics (including streak) and loading any prior history for comparison, save a JSON snapshot: ```bash mkdir -p .context/retros ``` Determine the next sequence number for today (substitute the actual date for `$(date +%Y-%m-%d)`): ```bash setopt +o nomatch 2>/dev/null || true # zsh compat # Count existing retros for today to get next sequence number today=$(date +%Y-%m-%d) existing=$(ls .context/retros/${today}-*.json 2>/dev/null | wc -l | tr -d ' ') next=$((existing + 1)) # Save as .context/retros/${today}-${next}.json ``` Use the Write tool to save the JSON file with this schema: ```json { "date": "2026-03-08", "window": "7d", "metrics": { "commits": 47, "contributors": 3, "prs_merged": 12, "insertions": 3200, "deletions": 800, "net_loc": 2400, "test_loc": 1300, "test_ratio": 0.41, "active_days": 6, "sessions": 14, "deep_sessions": 5, "avg_session_minutes": 42, "loc_per_session_hour": 350, "feat_pct": 0.40, "fix_pct": 0.30, "peak_hour": 22, "ai_assisted_commits": 32 }, "authors": { "Garry Tan": { "commits": 32, "insertions": 2400, "deletions": 300, "test_ratio": 0.41, "top_area": "browse/" }, "Alice": { "commits": 12, "insertions": 800, "deletions": 150, "test_ratio": 0.35, "top_area": "app/services/" } }, "version_range": ["1.16.0.0", "1.16.1.0"], "streak_days": 47, "tweetable": "Week of Mar 1: 47 commits (3 contributors), 3.2k LOC, 38% tests, 12 PRs, peak: 10pm", "greptile": { "fixes": 3, "fps": 1, "already_fixed": 2, "signal_pct": 83 } } ``` **Note:** Only include the `greptile` field if `~/.gstack/greptile-history.md` exists and has entries within the time window. Only include the `backlog` field if `TODOS.md` exists. Only include the `test_health` field if test files were found (`TEST_FILES_TOTAL` > 0). If any has no data, omit the field entirely. Include test health data in the JSON when test files exist: ```json "test_health": { "total_test_files": 47, "tests_added_this_period": 5, "regression_test_commits": 3, "test_files_changed": 8 } ``` Include backlog data in the JSON when TODOS.md exists: ```json "backlog": { "total_open": 28, "p0_p1": 2, "p2": 8, "completed_this_period": 3, "added_this_period": 1 } ``` ### Step 14: Write the Narrative {{SECTION:report-format}} --- ## 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 "" --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 . 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 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 `` in the commands below. ```bash # Commits with stats git -C log origin/$DEFAULT --since="T00:00:00" --format="%H|%aN|%ai|%s" --shortstat # Commit timestamps for session detection, streak, and context switching git -C log origin/$DEFAULT --since="T00:00:00" --format="%at|%aN|%ai|%s" | sort -n # Per-author commit counts git -C shortlog origin/$DEFAULT --since="T00:00:00" -sn --no-merges # PR/MR numbers from commit messages (GitHub #NNN, GitLab !NNN) git -C log origin/$DEFAULT --since="T00:00:00" --format="%s" | grep -oE '[#!][0-9]+' | sort -t'#' -k1 | 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 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 with the **shareable personal card first**, then the full team/project breakdown below. The personal card is designed to be screenshot-friendly — everything someone would want to share on X/Twitter in one clean block. --- **Tweetable summary** (first line, before everything else): ``` Week of Mar 14: 5 projects, 138 commits, 250k LOC across 5 repos | 48 AI sessions | Streak: 52d 🔥 ``` ## 🚀 Your Week: [user name] — [date range] This section is the **shareable personal card**. It contains ONLY the current user's stats — no team data, no project breakdowns. Designed to screenshot and post. Use the user identity from `git config user.name` to filter all per-repo git data. Aggregate across all repos to compute personal totals. Render as a single visually clean block. Left border only — no right border (LLMs can't align right borders reliably). Pad repo names to the longest name so columns align cleanly. Never truncate project names. ``` ╔═══════════════════════════════════════════════════════════════ ║ [USER NAME] — Week of [date] ╠═══════════════════════════════════════════════════════════════ ║ ║ [N] commits across [M] projects ║ +[X]k LOC added · [Y]k LOC deleted · [Z]k net ║ [N] AI coding sessions (CC: X, Codex: Y, Gemini: Z) ║ [N]-day shipping streak 🔥 ║ ║ PROJECTS ║ ───────────────────────────────────────────────────────── ║ [repo_name_full] [N] commits +[X]k LOC [solo/team] ║ [repo_name_full] [N] commits +[X]k LOC [solo/team] ║ [repo_name_full] [N] commits +[X]k LOC [solo/team] ║ ║ SHIP OF THE WEEK ║ [PR title] — [LOC] lines across [N] files ║ ║ TOP WORK ║ • [1-line description of biggest theme] ║ • [1-line description of second theme] ║ • [1-line description of third theme] ║ ║ Powered by gstack ╚═══════════════════════════════════════════════════════════════ ``` **Rules for the personal card:** - Only show repos where the user has commits. Skip repos with 0 commits. - Sort repos by user's commit count descending. - **Never truncate repo names.** Use the full repo name (e.g., `analyze_transcripts` not `analyze_trans`). Pad the name column to the longest repo name so all columns align. If names are long, widen the box — the box width adapts to content. - For LOC, use "k" formatting for thousands (e.g., "+64.0k" not "+64010"). - Role: "solo" if user is the only contributor, "team" if others contributed. - Ship of the Week: the user's single highest-LOC PR across ALL repos. - Top Work: 3 bullet points summarizing the user's major themes, inferred from commit messages. Not individual commits — synthesize into themes. E.g., "Built /retro global — cross-project retrospective with AI session discovery" not "feat: gstack-global-discover" + "feat: /retro global template". - The card must be self-contained. Someone seeing ONLY this block should understand the user's week without any surrounding context. - Do NOT include team members, project totals, or context switching data here. **Personal streak:** Use the user's own commits across all repos (filtered by `--author`) to compute a personal streak, separate from the team streak. --- ## Global Engineering Retro: [date range] Everything below is the full analysis — team data, project breakdowns, patterns. This is the "deep dive" that follows the shareable card. ### All Projects Overview | Metric | Value | |--------|-------| | Projects active | N | | Total commits (all repos, all contributors) | N | | Total LOC | +N / -N | | AI coding sessions | N (CC: X, Codex: Y, Gemini: Z) | | Active days | N | | Global shipping streak (any contributor, any repo) | 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 **Your Contributions** (sub-section within each project): For each project, add a "Your contributions" block showing the current user's personal stats within that repo. Use the user identity from `git config user.name` to filter. Include: - Your commits / total commits (with %) - Your LOC (+insertions / -deletions) - Your key work (inferred from YOUR commit messages only) - Your commit type mix (feat/fix/refactor/chore/docs breakdown) - Your biggest ship in this repo (highest-LOC commit or PR) If the user is the only contributor, say "Solo project — all commits are yours." If the user has 0 commits in a repo (team project they didn't touch this period), say "No commits this period — [N] AI sessions only." and skip the breakdown. Format: ``` **Your contributions:** 47/244 commits (19%), +4.2k/-0.3k LOC Key work: Writer Chat, email blocking, security hardening Biggest ship: PR #605 — Writer Chat eats the admin bar (2,457 ins, 46 files) Mix: feat(3) fix(2) chore(1) ``` ### Cross-Project Patterns - Time allocation across projects (% breakdown, use YOUR commits not total) - 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 setopt +o nomatch 2>/dev/null || true # zsh compat 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 setopt +o nomatch 2>/dev/null || true # zsh compat 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": "", "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`): 1. Run Steps 0.5-1 for the current window (default 7d) using the midnight-aligned start date (same logic as the main retro — e.g., if today is 2026-03-18 and window is 7d, `--since "2026-03-11T00:00:00"`) 2. Run `gstack-retro-metrics` a second time for the immediately prior same-length window, using both `--since` and `--until` with midnight-aligned dates to avoid overlap (e.g., for a 7d window starting 2026-03-11: `--since "2026-03-04T00:00:00" --until "2026-03-11T00:00:00"`) 3. Show a side-by-side comparison table with deltas and arrows 4. Write a brief narrative highlighting the biggest improvements and regressions 5. Save only the current-window snapshot to `.context/retros/` (same as a normal retro run); do **not** persist the prior-window metrics. ## Tone - Encouraging but candid, no coddling - Specific and concrete — always anchor in actual commits/code - Skip generic praise ("great job!") — say exactly what was good and why - Frame improvements as leveling up, not criticism - **Praise should feel like something you'd actually say in a 1:1** — specific, earned, genuine - **Growth suggestions should feel like investment advice** — "this is worth your time because..." not "you failed at..." - Never compare teammates against each other negatively. Each person's section stands on its own. - Keep total output around 3000-4500 words (slightly longer to accommodate team sections) - Use markdown tables and code blocks for data, prose for narrative - Output directly to the conversation — do NOT write to filesystem (except the `.context/retros/` JSON snapshot) ## Important Rules - ALL narrative output goes directly to the user in the conversation. The ONLY file written is the `.context/retros/` JSON snapshot. - The metrics script analyzes `origin/` (not local main which may be stale); when `RETRO_REF` says otherwise, disclose it - Display all timestamps in the user's local timezone (do not override `TZ`) - If `COMMITS: 0`, say so and suggest a different window - Round LOC/hour to nearest 50 (the script pre-rounds `LOC_PER_SESSION_HOUR`) - 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".