Engineering retrospective from git metrics. Reports deployment frequency, release cycle span, churn hotspots, backlog health. Outputs narrative report with 3+ actionable items. Flags: --since, --path, explicit range argument.
Scanned 5/28/2026
Install via CLI
openskills install greglas75/zuvo---
name: retro
description: >
Engineering retrospective from git metrics. Reports deployment frequency,
release cycle span, churn hotspots, backlog health. Outputs narrative report
with 3+ actionable items. Flags: --since, --path, explicit range argument.
codesift_tools:
always:
- analyze_project
- index_status
- index_folder
- index_file
- plan_turn
- analyze_hotspots # KEY — git churn × complexity for retrospective
- changed_symbols # what changed in the period
- diff_outline
- get_file_tree
- search_text
by_stack: {} # narrative report — no framework-specific tools needed
---
# zuvo:retro
Generate an engineering retrospective from git history, backlog state, and skill usage trends. Produces a narrative report with actionable items.
**Scope:** Post-release or periodic retrospective covering shipping velocity, code churn, backlog health, and quality trends.
**Out of scope:** Actually fixing issues (use the suggested zuvo commands in the Actionable Items section).
## Argument Parsing
| Input | Action |
|-------|--------|
| _(empty)_ | Auto-detect window from `memory/last-ship.json` or last two git tags |
| `<range>` | Explicit git range, e.g., `v1.0.0..v1.2.0` |
| `--since <tag>` | Start of retrospective window (open-ended, through HEAD) |
| `--path <dir>` | Scope git analysis to a subdirectory (required for monorepos) |
---
## Environment Compatibility
Read `../../shared/includes/env-compat.md` for agent dispatch patterns, path resolution, and progress tracking across Claude Code, Codex, and Cursor.
## Mandatory File Loading
```
CORE FILES LOADED:
1. ../../shared/includes/env-compat.md -- READ
2. ../../shared/includes/run-logger.md -- READ
```
Both files must be read before proceeding. If either is missing, note "DEGRADED -- [file] unavailable" in the report and continue with reduced capability.
---
## Phase 0: Window Detection
Determine the retrospective window in this priority order:
1. **Explicit argument** — if `<range>` was provided (e.g., `v1.0.0..v1.2.0`), use it directly.
2. **`--since <tag>`** — if provided, window is `<tag>..HEAD`. No `--until` flag is defined.
3. **`memory/last-ship.json`** — read the file if it exists. Use the `range` field (SHA-based, e.g., `"abc1234..def5678"`). If the artifact uses a legacy version-based range, fall back to it.
4. **Last two git tags** — run `git describe --tags --abbrev=0` twice (with `--exclude` on first result) to derive `<prev-tag>..<latest-tag>`.
5. **Fallback** — if fewer than two tags exist, use the last 30 commits: derive range as `HEAD~30..HEAD`.
**Count commits in window:**
```bash
git log --oneline <range> | wc -l
```
### Edge Case E13 — Insufficient History
If commit count is **< 10**: output "Insufficient history for statistical metrics" and produce a qualitative-only report. Skip Phases 1 and 3 (no git metrics, no skill trends to aggregate). Use Phase 2 (backlog health) as the sole data source. Still produce Phase 4 actionable items and Phase 5 report.
### Edge Case E14 — Monorepo Detection
Check for monorepo signals in the project root:
- `turbo.json`
- `nx.json`
- `pnpm-workspace.yaml`
If any of these files exist AND no `--path` argument was provided:
1. First, try auto-detection: run `git diff --name-only <range>` and extract unique top-level directories matching workspace package paths.
2. If only ONE package was touched: auto-scope to that package with `[AUTO-DECISION]: scoped to <package>`.
3. If multiple packages were touched:
- **Interactive:** list the affected packages and ask the user to pick one or confirm full-repo analysis.
- **Non-interactive:** `[AUTO-DECISION]: monorepo detected, analyzing all affected packages. Results may be noisy — re-run with --path for focused analysis.` Proceed with full-repo analysis.
If `--path` was provided: scope all `git log` commands with `-- <path>` and note the scope in the report.
---
## Phase 1: Git Metrics
Run these commands against the resolved `<range>` (append `-- <path>` if `--path` was provided).
### Deployment Frequency
Count **release tags** within the window, not arbitrary tags.
**Counting method:**
```bash
git tag --sort=creatordate --merged HEAD | grep -E '^v[0-9]' | while read tag; do
TAG_DATE=$(git log -1 --format="%ai" "$tag")
# keep only tags whose date falls within the window
done
```
Priority for identifying release tags:
1. Tags matching a semver-like pattern (`v*.*.*`, `v[0-9]*`)
2. Tags referenced by `memory/last-ship.json` (`newTag`, `previousTag`) — cross-reference, not sole source
3. If no release tag pattern can be identified, report:
`Deployment frequency unavailable — no reliable release tag pattern detected`
Ignore unrelated tags (experimental, package-local, scratch tags). `memory/last-ship.json` covers only the most recent release; for multi-release windows, the git tag scan is the primary data source.
### Release Cycle Span
Estimate the time span covered by the release window:
```bash
git log --format="%ai %H" <range>
```
Use the earliest commit date in the window as the start and the latest tag date as the end. Report as: N days (earliest commit → latest tag). Note: this is the window span, not per-PR lead time — exact branch-to-merge lead time requires per-PR analysis with `gh pr list`.
### Churn Hotspots
Find the top 5 most-changed files in the window:
```bash
git log --name-only --pretty=format: <range> | sort | uniq -c | sort -rn | head -5
```
Filter out empty lines. Report as a ranked list: filename (N changes).
---
## Phase 2: Backlog Health
Read `memory/backlog.md` if it exists.
If the file **does not exist**: note "No backlog tracked. Run `zuvo:review` or `zuvo:code-audit` to populate." Skip all backlog metrics.
If the file **exists**, count:
- **Open items** — rows where Status = `OPEN`
- **Critical items** — OPEN rows where Severity = `CRITICAL`
- **Resolved in window** — rows where Status = `RESOLVED` and the Resolved/Updated date (not Added date) falls within the window. If backlog.md has no Resolved date column, skip this metric and note: "Resolved-in-window metric unavailable — backlog lacks Resolved date column."
- **Added in window** — rows where Added date falls within the retrospective window
Also identify the oldest unresolved item (earliest Added date among OPEN rows) and report its ID and age in days.
---
## Phase 3: Skill Usage Trends
Read the skill usage log using the environment-aware path from `run-logger.md` (primary: `~/.zuvo/runs.log`, Codex App fallback: `memory/zuvo-runs.log`).
If the file **does not exist** at either path: note "No skill usage history found." Skip this section.
If the file **exists**, parse each line by splitting on tab characters (`\t`):
- **Lines with 10 tab characters (11 fields):** populate all fields:
```
DATE SKILL PROJECT CQ_SCORE Q_SCORE VERDICT TASKS DURATION NOTES BRANCH HEAD_SHA7
```
- **Lines with 8 tab characters (9 fields):** populate the first 9 fields as above, treat BRANCH and HEAD_SHA7 as `-`
- **Lines that match neither pattern** (e.g., pipe-delimited legacy entries like `2026-03-31T05:20:44Z | SKILL: brainstorm | ...`): skip silently
**DATE parsing:** handle both `T...Z` (with Z suffix) and `T...` (without Z) formats as UTC.
Filter to entries where:
- `PROJECT` matches the current project directory basename
- `DATE` falls within the retrospective window
From the filtered entries, aggregate:
- **Most-used skills** — rank by frequency
- **Average CQ score** — parse `CQ_SCORE` field, skip `-` entries, average the numerator/denominator separately
- **Average Q score** — same approach as CQ
- **Pass/fail ratio** — count PASS vs FAIL vs WARN verdicts
- **Branch distribution:** [branch: N runs, ...] (e.g., `main: 8, feature/x: 2`) — only display when at least one 11-field entry exists in the filtered window
---
## Phase 4: Actionable Items
Generate **at least 3** specific, actionable items. Each item must:
- Reference a **specific file, directory, or backlog item** (not generic advice)
- Include a **specific zuvo command**
- State the **reason** derived from the data
### Derivation rules (priority order):
1. **High-churn files** — for each file in the churn hotspot list with N ≥ 5 changes: check whether a corresponding test file exists. If no test file found: `zuvo:write-tests <file>` with reason "high-churn, N changes, no test coverage found".
2. **Churn instability** — for files with N ≥ 5 changes that already have tests: `zuvo:refactor <file>` with reason "N changes suggest instability or unclear responsibilities".
3. **Critical backlog items** — for each OPEN CRITICAL item: `zuvo:backlog fix <ID>` with reason "critical debt item open N days".
4. **Old open items** — if oldest open item is > 14 days: `zuvo:backlog prioritize` with reason "oldest item open N days, prioritization overdue".
5. **Low CQ scores** — if average CQ score < 23/29: `zuvo:code-audit <top-churn-directory>` with reason "CQ average N/29 below threshold".
6. **Low Q scores** — if average Q score < 14/19: `zuvo:write-tests <top-churn-directory>` with reason "Q average N/19 suggests test quality gaps".
If fewer than 3 items can be derived from the data, supplement with: "Run `zuvo:code-audit .` to establish a quality baseline" or "Run `zuvo:test-audit .` to identify test gaps."
---
## Phase 5: Report and Output
### Write Report File
Create the report using a readable suffix:
- Prefer tag-based names when `previousTag` / `newTag` are known:
`audit-results/retro-YYYY-MM-DD-<previousTag>_<newTag>.md`
- Otherwise fall back to a shortened SHA-based suffix (first 7 chars of `baseSha` and `releaseCommitSha` from `last-ship.json`):
`audit-results/retro-YYYY-MM-DD-<baseSha7>_<releaseCommitSha7>.md`
This prevents collisions and keeps filenames readable. If `audit-results/` does not exist, create it.
Use this exact structure:
```markdown
# Engineering Retrospective — YYYY-MM-DD
## Summary
[Tweetable one-liner: period, commits, releases, key metric]
## Shipping Velocity
- **Window:** <range> (<N> days, <N> commits)
- **Deployment frequency:** N releases in period (frequency: 1 per X days)
- **Release cycle span:** N days (earliest commit → latest tag)
- **Commits:** N total, N/day average
## Churn Hotspots
[Top 5 most-changed files with change count. Note if test file was found for each.]
| Rank | File | Changes | Has Tests |
|------|------|---------|-----------|
| 1 | src/orders/service.ts | 12 | No |
| 2 | src/auth/guard.ts | 8 | Yes |
## Backlog Health
- **Open items:** N (N critical, N high)
- **Added this period:** N
- **Resolved this period:** N
- **Oldest unresolved:** [item ID] — open N days
## Quality Trends
- **CQ scores:** avg N/29 ([N runs in period], or "no runs.log data")
- **Q scores:** avg N/19 ([N runs in period], or "no runs.log data")
- **Most-used skills:** [skill1 (N runs), skill2 (N runs)]
- **Pass/fail ratio:** N PASS, N WARN, N FAIL
## Actionable Items
1. `zuvo:write-tests src/orders/` — high-churn (12 changes), no test file found
2. `zuvo:refactor src/auth/guard.ts` — 8 changes suggest instability
3. `zuvo:backlog fix BD-007` — critical debt item open 21 days
## Comparison vs Prior Retro
[Delta table or "First retro — run again next period for trends"]
```
### Prior Retro Comparison
Check for existing `audit-results/retro-*.md` files. If one or more exist, compare with the most recent:
| Metric | Prior | Current | Delta |
|--------|-------|---------|-------|
| Deployment frequency | N/period | N/period | +/-N |
| Release cycle span | N days | N days | +/-N days |
| Open backlog items | N | N | +/-N |
| Avg CQ score | N/29 | N/29 | +/-N |
| Avg Q score | N/19 | N/19 | +/-N |
If no prior retro exists: note "First retro — run again next period for trends."
### Terminal Output Block
Print the RETRO COMPLETE block after writing the report:
```
RETRO COMPLETE
Window: v1.1.0..v1.2.0 (14 days, 47 commits)
Releases: 2 in period (frequency: 1 per week)
Cycle span: 14 days (earliest commit → latest tag)
Hotspots: src/orders/service.ts (12 changes), src/auth/guard.ts (8 changes)
Backlog: +5 added, -3 resolved, 12 open (2 critical)
Report: audit-results/retro-2026-03-28-v1.1.0_v1.2.0.md
Actions:
1. zuvo:write-tests src/orders/ — high-churn, low coverage
2. zuvo:refactor src/auth/guard.ts — 8 changes suggest instability
3. zuvo:backlog fix BD-007 — critical debt item open 21 days
Run: <ISO-8601-Z> retro <project> - - <VERDICT> - 6-phase <NOTES> <BRANCH> <SHA7>
After printing this block, append the `Run:` line value (without the `Run: ` prefix) to the log file path resolved per `run-logger.md`.
```
If E13 (insufficient history) was triggered, show:
```
RETRO COMPLETE [QUALITATIVE ONLY — <10 commits in window]
Window: HEAD~30..HEAD (fallback — fewer than 10 commits found)
Backlog: +N added, -N resolved, N open (N critical)
Report: audit-results/retro-YYYY-MM-DD-<suffix>.md
Actions:
1. [derived from backlog only]
Run: <ISO-8601-Z> retro <project> - - <VERDICT> - qualitative <NOTES> <BRANCH> <SHA7>
After printing this block, append the `Run:` line value (without the `Run: ` prefix) to the log file path resolved per `run-logger.md`.
```
No comments yet. Be the first to comment!