Created
March 17, 2026 11:48
-
-
Save myobie/375b399ca505cf8cdcf03527f4264276 to your computer and use it in GitHub Desktop.
Revisions
-
myobie created this gist
Mar 17, 2026 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,236 @@ --- name: literate-review description: "Use when the user wants to review code changes interactively. Uses literate markdown documents served in a local web app. Works with one repo or many. Triggers on: 'review PR', 'review branch', 'review changes', 'literate review', 'set up a review', 'create review docs', 'review these branches'. Generates topic-organized markdown files with inline diffs and surrounding context, serves them with syntax highlighting and inline commenting, and watches for reviewer comments that the current Claude Code session can respond to." --- # Literate PR Review Generate a topic-organized code review experience for changes in one or more git repositories. The output is a set of `.diff` and literate markdown files served in a local web app where reviewers can leave inline comments that Claude watches and responds to. Works equally well for a single branch in one repo or coordinated changes across many repos. ## Overview 1. **Produce raw diffs** — save to `docs/` as `.diff` files (source of truth) 2. **Plan topics** — group hunks by functional area, not by repo 3. **Write literate markdown** — diffs are the primary content, prose explains them, context in `<details>` 4. **Build the web server** — Express + marked + highlight.js + WebSocket live-reload + selection based commenting UI 5. **Run Playwright tests** — verify everything works before presenting, never ask a user to test something you haven’t already tested 6. **Launch** — server + CronCreate for comment monitoring ## Step 1: Gather Information Ask the user for: - **Repo(s) and branch(es)** to compare (e.g., `main...feature-branch`) - **Output directory** (suggest a sibling directory like `../review-name/`) - **Topics** — learn from reading the diffs. The user can optionally tell you some of the topics they are interested in. If the user has already provided this, proceed directly. ## Step 2: Produce the Raw Diffs For each repo, get a full diff and save into `docs/` as `00-<repo-name>.diff`. These files: - Appear in the sidebar for quick reference - Are the **source of truth** — every hunk must appear in at least one literate doc - Are commentable by the reviewer, just like the markdown docs ## Step 3: Plan Topics Read the diff files. Group hunks into topics by functional area (not by repo or file). Each topic should tell a coherent story. Propose topics to the user, or let them define them. ## Step 4: Write Literate Markdown Docs **The diffs are the primary content.** For each topic file: 1. **Prose intro** — what this topic covers and why the changes were made 2. **For each relevant hunk**, create a section: - Brief prose explaining the change - The actual `diff` code block (copied verbatim from the `.diff` files) - If the diff is too short to understand alone, either increase the surrounding context of the diff a small amount or add a **collapsed** `<details>` block with the full function/class/etc for context 3. **Cross-reference** between topics using relative markdown links 4. **Add visualizations** where they help (ASCII diagrams, tables, sequence annotations). Be creative. Be helpful. ### Example Structure ```markdown # Topic Title Prose explaining what this topic covers and why. ## Section Name (repo-name/path/to/file.ext) Prose explaining this specific change. \`\`\`diff context line -removed line +added line \`\`\` <details> <summary>Full function for context</summary> \`\`\`language function example() { ... } \`\`\` </details> See also [Other Topic](XX-other-topic.md) for related changes. ``` ### Rules - **Every section MUST have a diff block.** No exceptions. The reviewer came to see the diffs. - **Diffs are verbatim from `git diff`.** Never fabricate or rephrase. Copy actual `+`/`-`/` ` lines. - **Context goes in `<details>`.** Collapsed by default, available on demand. - **For new files**, show key hunks as diffs with `+` lines. Short files (< 50 lines) get the whole diff. Long files get the important hunks plus a “see full diff” details which expands to show the entire diff for the new file. - **Don't duplicate.** Include a hunk in one doc, cross-reference from others. - **Lead with prose.** Explain *why* before showing *what*. - **Justify the changes.** Why is this necessary? Why is this worth submitting for review? - **Number the files** (01-, 02-, ...) to suggest reading order. - **Be creative with visualizations** — ASCII diagrams, tables, sequence annotations. Think whiteboard. ## Step 5: Build the Web Server Create `server.mjs` in the project root. Dependencies: `express`, `marked`, `marked-highlight`, `highlight.js`, `chokidar`, `ws`, etc. ```bash npm init -y # Set "type": "module" for ESM npm install express marked marked-highlight highlight.js chokidar ws # etc ``` ### Endpoints - **GET `/`** — Sidebar with all docs (`.md` and `.diff`), renders first `.md` by default - **GET `/docs/:name`** — For `.md`: renders markdown with syntax highlighting. For `.diff`: renders with highlight.js diff highlighting, splitting on embedded `> ` blockquote lines to render inline comments. Returns HTML fragment when `X-Requested-With: fetch` header present. - **POST `/api/request`** — Accepts `{ file, selectedText, comment }`. Generates a 7-char hex short-id. Creates `requests/<short-id>.md` with frontmatter AND inserts `> **Reviewer** (<short-id>): comment` into the doc. Returns `{ ok: true, id }`. - **WebSocket `/ws`** — Pushes `{ type: "reload", file }` on file changes in `docs/` ### UI Requirements - **Dark theme** (GitHub-dark): `#0d1117` background, `#e6edf3` text - **Sidebar** (280px fixed) with doc links, active state highlighting. `.diff` files shown in italics. - **Content layout**: Full-width scrollable `<main>` with max-width inner wrapper. Scroll works anywhere in the right pane, not just over the text column. - **SPA navigation** using fetch + pushState. Target the inner wrapper, not the scroll container. Make sure the back/forward buttons work. - **Blockquote styling**: Red border for Reviewer, blue border for Claude. Anchor IDs (`comment-<short-id>`) on each. - **Comment nav**: Sticky bar at top with "Comments (N)" dropdown. Lists all blockquotes, click to scroll-and-highlight. Rebuild on navigation and live-reload. - **Split diff toggle**: "Split diffs" button parses diff code blocks into side-by-side old/new panes. Widens content to ~1400px. Persists across live-reloads and navigation. - **Commenting**: mouseup on selection > 3 chars shows fixed-position "Comment" button. Popover flips above when near viewport bottom. Works on `.md` and `.diff` files. Server strips `> ` prefixes and `**Reviewer/Claude** (id):` markers when matching selected text. - **WebSocket auto-reconnect** on close (2s delay) ### Request File Format ```markdown --- file: 05-subscription-changes.md selectedText: "..." status: pending created: 2026-03-17T22:14:03Z --- The reviewer's comment text. ``` ## Step 6: Comment Monitoring The `requests/` directory is the queue. Set up a recurring cron after the server is running: ``` CronCreate: "*/1 * * * *", recurring: true ``` The cron prompt should instruct Claude to: 1. List `requests/` for pending files 2. For each, read the comment and surrounding doc context 3. Determine type (ask or change) and process accordingly 4. Delete the request file after processing (audit trail is in the doc blockquotes) ### Two Types of Comments Claude infers the type — no explicit label needed. **Ask** — reviewer wants an explanation or has a question. Claude reads the context, reads source files if needed, inserts a `> **Claude** (<id>): response` blockquote after the reviewer's comment. **Change** — reviewer wants code modified. Claude makes the change in the actual repo, regenerates the diff section in the doc (collecting old comments into a collapsed `<details>` archive), and responds with `> **Claude** (<id>): Done — description`. ### Diff Regeneration (for change comments) 1. Collect existing blockquote pairs from the section 2. Re-read the source with `git diff main -- path/to/file` (includes working tree changes) and update the `.diff` file that is our source of truth 3. Rewrite the diff/context blocks across all .md files 4. Archive old comments in `<details><summary>Previous review comments (N)</summary>...</details>` ## Step 7: Playwright Tests Create `test.mjs` using `playwright` (not `@playwright/test`). The test starts its own server, runs checks, then kills it. **Required coverage:** 1. Server responds with 200 2. Sidebar has correct number of links (`.md` + `.diff`) 3. Each doc renders with headings and code blocks 4. Syntax highlighting present (`.hljs` classes) 5. Diff code blocks present 6. Text selection shows comment button 7. Comment submission creates request file + blockquote with short-id 8. Live reload shows comment without manual refresh 9. Commenting on blockquotes works 10. Commenting on `.diff` files works (via API) 11. Screenshots at each stage ```bash npm install playwright && npx playwright install chromium node test.mjs ``` ## Step 8: Launch After all tests pass: 1. Start server: `nohup node server.mjs &` 2. Set up CronCreate for comment monitoring 3. Tell the user the URL and cron job ID ## File Structure ``` review-project/ ├── package.json ├── server.mjs ├── test.mjs ├── docs/ │ ├── 00-repo-name.diff (raw diffs, one per repo) │ ├── 01-topic-name.md │ ├── 02-topic-name.md │ └── ... ├── requests/ (transient queue, files deleted after processing) └── screenshots/ ``` ## Important Reminders - **Test before presenting — every time.** Run `node test.mjs` after every change to the server, UI, or docs. Never tell the user to reload until all tests pass. Non-negotiable. - **Audit after generating docs.** Run `grep -c '````diff' docs/*.md` — every doc must have diffs. Cross-check every hunk in the `.diff` files against the docs. No fabricated lines. - **UI preferences go in this SKILL file.** If the reviewer asks for different styling or layout, implement it AND update this file so future sessions produce the same UI. - **The cron is session-only.** Remind the user it dies when Claude exits (3-day auto-expiry). ## Lessons Learned These went wrong during real usage. Follow them to avoid repeating. ### Validation - **Escape `\n` in template literals.** Inside backtick HTML templates, `\n` becomes a real newline — use `\\n`. This is the #1 cause of browser SyntaxErrors. Playwright catches them. ### CSS / Layout - **The scroll container is `#content`, not `window`.** `window.scrollY` is always 0. Comment button/popover use `position: fixed` with raw `getBoundingClientRect()` values. Clamp to viewport bounds with `Math.max(8, ...)`. - **Sticky nav needs `padding-top: 0` on `#content`.** Put top padding on `#content-inner` instead. ### Comment System - **Comments can land inside code blocks.** The server's line search finds text inside fenced code regions. Prefer matches outside triple-backtick regions. - **Selected text from rendered blockquotes won't match raw markdown.** Strip `> ` prefixes and `**Reviewer/Claude** (id):` markers when searching. - **Popover must flip above when near viewport bottom.** Check `window.innerHeight - rect.bottom` before positioning. ### Diff Regeneration - **Use `git diff main -- path/to/file`** (not `main...HEAD`) to include unstaged changes. - **Blank line required between `<details>` tag and blockquote content**, otherwise marked won't parse the blockquotes. ### Content - **Context goes in `<details>`, not as the main content.** The diff is what the reviewer is here to see. - **Don't duplicate hunks across docs.** Include once, cross-reference elsewhere.