stage-chapters
stage-chapters
Generates a Stage chapter run for the current local git branch and opens it in a browser. Uses stagereview prep to compute the diff, then generates chapters and a prologue, and hands the result to stagereview show to launch the SPA.
Prerequisites
Run these checks before any other work. If either fails, stop with the error message — do not continue.
-
stagereviewis installed. Runwhich stagereview. If it exits non-zero, instruct the user:stagereview is not installed. Run: npm install -g stagereview Then retry /stage-chapters.Stop.
-
The current directory is a git repo. Run
git rev-parse --is-inside-work-tree. If it does not printtrue, stop with:/stage-chapters must be run inside a git repository.
Step 1 — Run prep
PREP_FILE=$(stagereview prep)
stagereview prep auto-detects the base ref (main/master), computes the merge-base, generates the diff (including uncommitted and untracked changes when present), filters out lockfiles/binaries, and formats hunks with line numbers for analysis. It writes a plain-text file and prints only the file path to stdout.
If the user specifies a base branch (e.g., "generate chapters against feature-a"), pass --base <ref> to both prep and show:
PREP_FILE=$(stagereview prep --base feature-a)
# ... later ...
stagereview show --base feature-a "$AGENT_OUTPUT"
If prep exits non-zero, relay its stderr to the user and stop.
Do not modify files in the working tree between running prep and running show. Both commands independently snapshot the git state. If the diff changes between them, show will reject the chapters with a hunk coverage error because the hunks no longer match.
Step 2 — Read prep output
Read $PREP_FILE via the Read tool (or equivalent). For large diffs, use the Read tool's offset and limit parameters to read in chunks.
The file has two sections separated by headers:
=== COMMIT MESSAGES ===—git log --onelineoutput for prologue context.=== HUNKS ===— formatted diff hunks with line numbers. Each hunk looks like:
=== File: src/app.ts (modified) | filePath: "src/app.ts", oldStart: 1 ===
=== Hunk @1: @@ -1,5 +1,6 @@ ===
1 1 | const a = 1;
2 |-const b = 2;
2 |+const b = 3;
3 |+const c = 4;
3 4 | const d = 5;
The two number columns are the old line number (left) and new line number (right). A blank column means the line doesn't exist on that side — additions have no old line number, deletions have no new line number. These numbers are used directly for lineRefs in key changes (see Step 3d).
commits.txt contains git log --oneline output for prologue context.
Step 3 — Cluster + narrate
Using the hunks from hunks.txt, produce a chapters array. Each chapter groups related hunks into a coherent story beat, narrates them for a reviewer unfamiliar with this part of the codebase, and flags judgment calls that need human input.
3a — Clustering rules
Group hunks by causal relationship — changes that set up or enable later changes belong together.
- Spanning multiple files is expected and correct (e.g., schema + API + UI for one feature = one chapter).
- Moves and refactors are a single chapter — when code is removed from one file and added to another (or a file is deleted and a similar one created), group the deletion and addition hunks together as one "Move/Refactor" chapter, not separate "Remove" and "Add" chapters.
- Split only when changes are truly independent — a reviewer could understand one without knowing about the other.
- Tests belong with their implementation chapter.
- Config/dependency changes can be their own chapter if unrelated to a feature chapter.
Chapter ordering:
- Foundation first: types, interfaces, schemas, utilities that others depend on
- Core logic next: main implementation
- Integration last: wiring, configuration, tests
Consider symbol dependencies between chapters — a chapter that introduces a type another chapter uses must come first.
Hunk ordering within a chapter:
- Group all hunks from the same file together — do not interleave hunks from different files.
- Within the same file, list hunks in ascending
oldStartorder (matching file layout).
3b — Self-validation rules
Every hunk in the formatted diff must appear in exactly one chapter. No hunk may be omitted and no hunk may appear in more than one chapter.
Each hunk header in the prep output has the format:
=== File: <path> (<status>) | filePath: "<path>", oldStart: <N> ===
Use the filePath and oldStart values from these headers to build hunkRefs.
stagereview show validates hunk coverage automatically — it will error with a list of missing or extra hunks if the chapters don't account for every hunk in the diff. If this happens, fix the chapters and retry.
3c — Narration rules
Write each chapter as a story beat — a meaningful step that moves the branch forward, not a summary of files changed.
- Title: action-oriented verb phrase, max 8 words (e.g., "Wire org ID through the API layer"). No filler like "Add support for".
- Summary: 2–3 sentences covering what this chapter enables and why. Lead with impact, then connect to the broader purpose. When a chapter builds on a previous one, open with that causal link explicitly (e.g., "Now that X is in place…").
- Keep paragraphs short. Prefer splitting distinct points into separate short paragraphs (separated by a blank line) rather than writing one long dense paragraph. Each paragraph should convey a single idea.
- Markdown allowed:
**bold**for emphasis,*italics*for nuance,`backticks`for inline code references, and fenced code blocks when a short snippet (≤ 6 lines) helps illustrate the change.
3d — Key change rules
Key changes are judgment calls only a human reviewer can make — things that require product context, team conventions, or knowledge of the author's intent. Linters, type checkers, and code-review bots already cover correctness and style; skip anything they can catch. Ignore auto-generated files.
Return an empty array when nothing needs human input — do not invent items to fill the list. When a chapter is a straightforward rename, type fix, or mechanical refactor with no judgment calls, keyChanges should be [].
Frame each item as a question.
Each key change includes lineRefs: one line range per distinct spot the question depends on. Most questions touch a single location, so use one range; only add more when the judgment genuinely spans related code in different places.
Reading line numbers from hunks.txt: Each diff line shows two number columns — old (left) and new (right). Use these numbers directly:
- For
side: "deletions"— use the old (left) column number asstartLine/endLine. - For
side: "additions"— use the new (right) column number asstartLine/endLine. - Do not count lines yourself — read the numbers from the formatted output.
Keep ranges tight — point to the specific lines the question is about, not the entire hunk. startLine and endLine must both be positive integers with endLine >= startLine.
Good examples:
- "Should
retryCountreset when the user switches orgs?" - "Is a 60-minute session timeout appropriate for this user base, or would 30 minutes be safer?"
- "Does this new index cover the query patterns the team actually uses in production?"
Bad examples:
- "Check that the auth logic is correct." — vague, verifiable by reading the code
- "The function now handles errors." — changelog item, not a question
- "Make sure the tests pass." — CI catches this, not a human judgment call
3e — Output format
Produce an array of chapter objects. Each chapter:
{
"id": "chapter-1", // unique within the run, e.g. "chapter-1", "chapter-2", …
"order": 1, // positive integer, 1-indexed
"title": "Short imperative title",
"summary": "Why this chapter matters to the reviewer.",
"hunkRefs": [
// one entry per hunk in the chapter
{ "filePath": "path/to/file.ts", "oldStart": 42 }
],
"keyChanges": [
// zero or more judgment-call questions
{
"content": "A judgment-call question for the reviewer.",
"lineRefs": [
{
"filePath": "path/to/file.ts",
"side": "additions",
"startLine": 50,
"endLine": 55
}
]
}
]
}
- Do not invent
hunkRefs— only use(filePath, oldStart)tuples that actually appear in the formatted hunks. keyChanges[].lineRefsmust have at least one entry per key change.
Step 4 — Generate prologue
After building the chapters, generate a prologue — a high-level overview of the entire change. The prologue helps reviewers orient themselves before diving into individual chapters.
Use commits.txt from the prep output for context.
Using the diff, chapters, and commit messages, produce a prologue object with the following fields:
motivation (string or null)
One sentence a non-engineer would understand. What was broken, annoying, or missing — from a person's perspective. If the commit messages are generic and the diff doesn't make the motivation obvious, use null.
Good: "Dashboards would break during deploys, so people had to keep refreshing until things came back." Bad: "The API client had no retry logic for 503 errors." (too technical — no one outside the team knows what that means)
outcome (string or null)
One sentence a non-engineer would understand. What's better now. Same null rule as motivation.
Good: "Dashboards stay up during deploys now." Bad: "Added exponential backoff with a base delay of 100ms." (implementation detail)
keyChanges (array of 2–5 objects)
Each object has:
summary: 6–10 words describing what's different now. Outcome-focused, not action-focused.description: Capitalized sentence, 10–15 words of additional context.
Good: summary: "Audit runs are now tracked in a database", description: "Uses new Drizzle ORM schema with full history retention"
Bad: summary: "Adds Drizzle ORM layer" (action-focused — describe what changed, not what you did)
focusAreas (array of 1–5 objects)
Always provide at least 1 focus area. Even clean changes have spots worth a reviewer's attention.
Each object has:
type: one ofsecurity,breaking-change,high-complexity,data-integrity,new-pattern,architecture,performance,testing-gapseverity: one ofcritical,high,medium(for problems) orinfo(for points of interest)title: 3–5 word noun phrase (e.g., "Unvalidated user input")description: WHY this was flagged + a declarative action for the reviewer. Use "confirm", "verify", or "check" to give the reviewer a specific task.locations: array of file paths where this applies
Good: type: "security", severity: "high", title: "Unvalidated user input", description: "User-provided ID passed directly to database query — confirm input is validated and parameterized"
Bad: description: "Worth understanding" (no action, vague)
complexity
Object with:
level: one oflow,medium,high,very-highreasoning: brief explanation (e.g., "New DB schema plus multiple service changes")
Style
Talk like a coworker, not a changelog. No jargon, no filler phrases, no "this change introduces/implements/adds". Just say what happened and why it matters.
Step 5 — Write agent output
Compute a unique temp path and write the JSON via a bash heredoc:
AGENT_OUTPUT=$(mktemp "${TMPDIR:-/tmp}/stage-agent-output.XXXXXX")
cat > "$AGENT_OUTPUT" << 'AGENT_EOF'
{
"chapters": [ ... ],
"prologue": { ... }
}
AGENT_EOF
The trailing XXXXXX (with no suffix after) is required by macOS BSD mktemp. Using cat with a heredoc avoids tool-specific file-writing issues.
Field rules:
| Field | Constraint |
|---|---|
chapters[].id |
Non-empty, unique within the run |
chapters[].order |
Positive integer (1-indexed) |
chapters[].hunkRefs[].oldStart |
Non-negative integer — the pre-image start line from the oldStart in the formatted hunk header (0 for new files) |
chapters[].keyChanges[].lineRefs |
Array with at least one entry |
lineRefs[].side |
"additions" (right side) or "deletions" (left side) |
lineRefs[].startLine / endLine |
Positive integers; endLine >= startLine |
prologue |
Optional object; omit entirely if not desired |
prologue.motivation |
String or null |
prologue.outcome |
String or null |
prologue.keyChanges |
Array of 2–5 objects with summary and description |
prologue.focusAreas |
Array of 1–5 objects |
prologue.focusAreas[].type |
One of: security, breaking-change, high-complexity, data-integrity, new-pattern, architecture, performance, testing-gap |
prologue.focusAreas[].severity |
One of: critical, high, medium, info |
prologue.complexity.level |
One of: low, medium, high, very-high |
Step 6 — Display generated chapters
Hand the file to stagereview:
stagereview show "$AGENT_OUTPUT"
stagereview show auto-detects the agent output format, independently computes the scope and "Other changes" chapter for filtered files, validates the JSON, inserts the run into the local SQLite database, boots a loopback HTTP server, and opens the browser.
The command blocks until the user presses Ctrl+C. If your harness requires non-blocking execution, run it in the background (e.g., run_in_background in Claude Code). Invoke it as the final command in the workflow.