Present PR
SkillFiles & storagePresent a PR to the owner for validation as one self-contained artifact — composed context visuals, a review-history audit trail, an area→package→file sankey, a file tree, and importance-ordered diffs each carrying a one-line rationale. Use as the final step of every implementation PR, before requesting owner validation.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Present PR skill
What this skill tells your AI
The instructions your AI receives, as published by hachej/boring-ui in .agents/skills/present-pr/SKILL.md and read by ahel’s review.
This is the standard final step of every implementation PR: before requesting owner validation, generate the presentation (composed context visuals + summary + sankey + importance-ordered diffs) and publish/hand the artifact to the owner.
The review flow it encodes, in the owner's own order:
- What review already happened — was this deep-audited? thermo-reviewed? what failed and did it get fixed? Answerable yes/no without reading a single comment thread.
- What areas/packages are touched —
packages/vsapps/vs the rest. - Per-package scope check — a PR reaching into a package it has no business in is visible at a glance, with that package's ±line counts on the node.
- Why is each file in this PR at all — one line per file or group, readable by skimming headers without opening a single diff.
- Most important diffs first — not alphabetical, not whatever GitHub shows first.
A GitHub PR page answers none of these: it opens on a path-sorted file list with lockfiles and snapshots competing with the one file that decides the review.
When to use
- Any implementation PR that is CI-green and audited and needs a merge decision.
- A change spanning several packages, where "which seam does this touch?" comes first.
Do not use it as a substitute for the review itself. Present only what you have already reviewed, and state the open questions.
Steps
-
Understand the seam. Read the production files first and
../show-me/SKILL.md. Identify the flow the PR changes—entry point → policy/decision → effect—and compose the views that make that seam easiest to review. -
Write the context sidecar — one markdown file, per PR, at
<scratchpad>/pr-<n>-context.md:# PR <n> context ```text submitForm createSession + expandSkillMention launchAgent navigateToSession ``` ```ts type SubmitResult = + | { status: 'expanded'; skill: string } | { status: 'started'; sessionId: string } ``` Fenced blocks compose the context explanation in sidecar order. Follow the visual selection and composition rules in `../show-me/SKILL.md`; every view must explain the review seam and correspond to changed code. Follow with 3–6 sentences of context: the problem, which two or three mechanisms changed, what the PR explicitly does **not** do, and what to look at first. ## Key files - path/to/the/file/that/decides/the/review.ts - path/to/the/second/one.tsPR-specific rendering contract: Mermaid blocks become inline SVG; other fenced views become escaped preformatted shapes. Keep focused HTML mockups as companion artifacts—never inject arbitrary HTML into the presentation itself.
## Key filesis optional and pins the reading order explicitly, overriding the importance heuristic. Use it whenever you know which two or three diffs decide the review — you almost always do. -
Write the
## Whyblock — required, and deliberately cheap. One line per file group, matched by glob, budget ~10-15 lines for the whole PR:## Why - packages/boring-sandbox/src/providers/bwrap/** | emit --ro-bind-try per protected prefix after the writable mount - packages/boring-bash/src/server/routes/** | 403 mutations of protected paths at the HTTP edge - packages/agent/src/server/runtime/userFilesystemBinding.ts | intersect lexical path with realpath so symlinks cannot alias around the policy - **/__tests__/** | lock the deny/allow matrixGroup-first is the rule, not a shortcut. Reach for a per-file line only where the file carries a mechanism a group line cannot state — in practice, roughly the same files as
## Key files. Globs support*,**/and a trailing/**; the most specific match wins, so a per-file line always beats the group line covering it. Files matching nothing render nothing — that is fine, not an error, and cheaper than padding the block with filler.Each line answers "why is this file in this PR", in one clause. Not what the diff does line-by-line (the diff is right there), not a summary of the PR (section 1 has that).
-
Fill the review history — this is mandatory, not optional. Add a
## Review historyblock to the same sidecar, one bullet per event, fields separated by|:## Review history - 2026-08-08 | deep audit | FAIL -> fixed | Opus worker | 6 findings, 4 blocking: <one line each>. Closed by <commit>. - 2026-08-08 | thermo review | PASS with findings | Claude Fable 5 | Two buildBwrapArgs copies kept in sync rather than deduplicated; accepted with rationale. - 2026-08-09 | CI re-verify | PASS | GitHub Actions | Full matrix green on the merge commit.date | type | verdict | who ran it | 1-line summary with resolution state. Trailing fields may be omitted. Recognised types colour their badge: deep audit, security audit, thermo review, pi/code review, fix round, re-verify, UI review, merge. Verdicts are free text, tone-matched onPASS/PASS with findings/FAIL/FAIL -> fixed.Reconstruct it from the PR's actual audit trail, and reconstruct it from all four sources — never from memory or optimism:
gh pr view <n> --json commits,reviews,comments,mergedAt,mergedBy gh run list --branch <head-branch> --limit 30 \ --json databaseId,name,conclusion,createdAt,headSha # ← the one agents skip gh run view <failing-run-id> --json jobs --jq '.jobs[]|select(.conclusion=="failure")|.name' gh run view --job <job-id> --log-failedThe run history is mandatory, not optional. Reviews and comments alone will make you miss the most valuable events on the page: a gate that failed, got diagnosed, and was fixed. Those are precisely what the owner wants preserved — a PR whose CI went green on the first try and one that went green after a hard gate caught a real regression are very different objects, and only the run history tells them apart. Walk the runs on the head branch, find every
conclusion: failure, open the failing job's log, and record what failed, what the diagnosis was, and which commit fixed it. Note reruns too: a failure that reproduces on rerun is a real defect, not a flake, and that distinction belongs in the summary. Cite run ids and fix commit shas so the claim is checkable.Do not write
SKIPPEDfor a job you did not actually look up. A job that was skipped because a path filter excluded it and a job that failed twice then passed after a fix look identical from the reviews-and-comments view — and opposite from the run history. Every finding gets its resolution state: closed, deferred with stated risk, or open. If a review did not happen, record that as an event with verdictNOT RECORDEDand say so; the header badge reads "thermo review: NOT recorded" and will not count aNOT RECORDED/SKIPPEDthermo entry as evidence of review. Recording an absence honestly is the point of the section.Omitting the block entirely does not hide the gap: the artifact renders a red "No review history recorded — treat as unreviewed" panel in its place.
-
Generate the page — into the lane worktree, not a scratchpad. Mermaid pre-render uses Playwright Chromium. If the lane has no browser binary yet, provision it from that lane (never the canonical checkout or live hub) with
pnpm exec playwright install chromium.Resolve
<present-pr-skill-dir>as the directory containing thisSKILL.md; skill-relative support files belong to the skill and never to the current repository. Omit--reposoghresolves the repository from the current workspace. Pass it only when the PR intentionally belongs to a different repository.mkdir -p .handoff node <present-pr-skill-dir>/../../../scripts/present-pr.mjs <pr-number> \ --context <scratchpad>/pr-<n>-context.md \ --audit "deep audit <date>: N findings closed, M deferred" \ --out .handoff/pr-<n>-presentation.html.handoff/is gitignored and lives inside the workspace root, which is what makes the next step possible: the workspace file API is relative-only, so a page written to a scratchpad outside the worktree cannot be opened as a pane.The script pulls metadata, checks, and the combined diff via
ghand renders one HTML file with no external requests — safe for the artifact viewer's strict CSP. Mermaid is pre-rendered at generation time to inline SVG on a fixed dark diagram surface. This deliberately avoids runtime Mermaid, external scripts, and CDN requests because the workspace HTML viewer does not execute or fetch them reliably; the resulting single file also renders in a plain browser.pnpm test:present-pr-mermaidexercises the browser-backed multi-diagram ID isolation separately from the browser-free lint suite. -
Hand it over as two panes — the standard handoff. Working inside a workspace session, the artifact is not a link, it is a pane:
// the review artifact { "kind": "openFile", "params": { "path": ".handoff/pr-<n>-presentation.html" } } // the live demo, if the change has a running surface { "kind": "openPanel", "params": { "id": "demo:br-<id>", "component": "url-pane.panel", "params": { "url": "http://127.0.0.1:<port>/", "title": "br-<id> demo" } } }Both via
exec_ui. The.htmlpath resolves to the sandboxed HTML viewer;url-pane.panelembeds the running server (loopback origins are allowed by default — seepackages/workspace/docs/URL_PANE.md). Then send the owner card throughask_user, naming both panes, with the decision you want and the open questions.Outside a workspace session, fall back to publishing the page as an artifact and handing over the URL.
What the page gives the reviewer
- Header — the linked issue number, exact title, and clickable URL plus the bead ID appear first; when the PR body has no semantic issue reference, the header says no linked issue explicitly. PR title, author, branch pair, churn, live CI check tally, and audit status follow.
- Section 1 — what this touches. The composed context visuals and summary.
- Section 2 — review history. A chronological audit trail with type badges, per-event verdict, who ran it, and a 1-line finding summary with resolution state. A headline badge answers "thermo review: recorded / NOT recorded" at a glance. Absent history renders as an explicit warning, never as an omitted section.
- Section 3 — changes. A file tree on the left (directories nested with
single-child chains collapsed, counts rolled up, a category dot per file, group
rationale on directory rows) linked to the diff panel on the right: clicking a tree row
scrolls to and expands that diff. The tree is the spatial view; the panel keeps
importance order.
Within that:
- Sankey navigation (inline SVG, hand-rolled, no libraries): area → package → file. Ribbon width is changed lines, colour is the dominant file category, node bars split green/red by additions/deletions. Package nodes carry their own ±counts. Hovering isolates a branch; clicking any node jumps to the most important diff beneath it. Tests and docs are excluded from the default diagram and available through an explicit Show tests + docs control; every file still remains in the diff list. The file level is optional and defaults off above 24 files. Below 4 changed files the sankey is skipped entirely.
- Category chips toggle production / test / docs / config / generated, with per-category counts. Generated files start off.
- Diffs in importance order. The top file is marked
start hereand the top two are pre-expanded; every header shows its rank. Apathtoggle restores tree order. - One line of rationale inside every file header, visible while the diff is collapsed — skimming the headers is skimming the rationale. The same line is the tree row's hover title.
Importance heuristic
score = log2(changed lines + 1) × category weight × surface boost × new-file bonus
- Category weight: prod 1.0, test 0.45, config 0.4, docs 0.3, generated 0.08.
- Surface boost:
src/shared/**×1.6;types|schema|contract|error-codes×1.4;routes|api|server×1.25; barrelindex.*×1.2. - Churn is damped logarithmically so a 900-line snapshot cannot outrank a 12-line policy change.
## Key filesin the sidecar overrides all of it, in the order given.
Tune the weights in importance() / surfaceBoost() if a repo convention is mis-ranked;
tune categorize() (first-match-wins) if a file is mis-bucketed.
Notes
gh pr diff --patchemits one patch per commit and would duplicate files — the script deliberately uses the plain combined diff.- Syntax highlighting is a deliberately small regex tokenizer (comments, strings, numbers, keywords). It is legibility, not correctness; no external highlighter is bundled because the CSP forbids one.
Signals
- GitHub stars
- 46
- Forks
- 2
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
present-pr- Source
- github.com/hachej/boring-ui