check-pr
Skill761 starsChanged todayMITView on GitHub
Review one or more contributor pull requests to claude-desktop-extra the way the maintainer wants it - read, classify (category, switch, cost, Linux exposure), build the branch locally, audit the upstream code paths around every patched site in the pristine bundle, run the harnesses, decide with the maintainer, fix gaps with our own commits on top instead of review ping-pong, merge to master, release, and thank the author. Self-improving - every run ends by folding what it learned back into this file. Invoke as "/check-pr <PR numbers or URLs>".
- Reads credentials
- Deletes or force-pushes
- Commits and pushes
12 other projects use a version of this.
Adopted by
Most recently taken up by
- danielcherubini/skillstheir own version, first seen Nov 11, 2026
- storybookjs/storybooktheir own version, first seen Nov 8, 2026
- blamechris/chroxytheir own version, first seen Nov 8, 2026
- kellykampen/agent-skillstheir own version, first seen Nov 1, 2026
- greptileai/skillstheir own version, first seen Oct 25, 2026
- ever-works/skillstheir own version, first seen Oct 9, 2026
Other versions12 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 12
- paperclipai/paperclip★ 114ksame name
- storybookjs/storybook★ 92ksame name
- greptileai/skills★ 433same name
- basementstudio/website-2k25★ 266same name
- haseeb-heaven/gworkspace-agent★ 82same name
- danielcherubini/skills★ 14same name
- blamechris/chroxy★ 8same name
- Bboyfarouk/skills★ 2same name
- kellykampen/agent-skills★ 2same name
- ever-works/skills★ 1same name
2 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository12 other files it gives its agents.
- AGENTS.mdAGENTS.md
- 3pSkill
- architectureSkill
- auditSkill
- check-issueSkill
- commentSkill
- debugSkill
- deploySkill
- fresh-upstreamSkill
- linuxSkill
- test-nativeSkill
- updateSkill
The file
We split this skill into the rules it gives an agent
6 rules. 0 are common, 5 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 11 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 21
No review ping-pong: When a PR has a gap, fix it with our own commit on top of the author's commits and merge, instead of a "request …
- Distinctive: line 26
Gates: Ask before each of these, and treat each approval as covering only its own step:
- Distinctive: line 31
every public PR comment
- Very specific: line 44
Docs-only PR: no build, no workers. Grep each corrected claim against the code, and check AGENTS.md/CLAUDE.md for bare @path lines: they …
- Distinctive: line 69
Check for absorption: does upstream already ship part of the behavior (same strings, same event)?
- Distinctive: line 77
Request changes: only when the design itself is wrong and the fix would be a rewrite.
“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Check PR - from contributor branch to released feature
PRs: $ARGUMENTS
Open PRs right now: !gh -R patrickjaja/claude-desktop-extra pr list --state open --limit 10 2>/dev/null || echo "(gh not ready)"
Latest release: !gh -R patrickjaja/claude-desktop-extra release list --limit 1 2>/dev/null || echo "(gh not ready)"
Upstream version patches target: !cat .upstream-version 2>/dev/null
Local master vs origin: !git fetch -q origin master 2>/dev/null; git rev-list --left-right --count master...origin/master 2>/dev/null | awk '{print "ahead " $(1) ", behind " $(2)}'
The main thread orchestrates and reads; audits, implementation and reviews run in dispatched workers. Follow the global subagent tier rules: name the tier and the reason in every dispatch.
How the maintainer works with contributor PRs (these are the rules the rest of this file serves):
- Assume good faith and say thanks, but verify everything. A green CI and a long "Validation" section in the PR body prove the patch applied, not that the feature works.
- No review ping-pong. When a PR has a gap, fix it with our own commit on top of the author's commits and merge, instead of a "request changes" round-trip. The author's commits stay intact and are credited.
- The author is credited in
CHANGELOG.md, in the section heading:### <What now works> (thanks @login, #N). Nothing in README or docs prose. - A live end-to-end test is wanted when the host can do it. When it needs something the maintainer does not have (a second GitHub account, a GitHub App, another plan), say so in the PR comment, ship it anyway behind its switch, and ask the author to test after the release. A feature behind a Community switch that turns out broken gets a follow-up PR or is removed; that is acceptable.
- The maintainer installs packages themselves: build, hand over the
sudo pacman -U ...line, wait.
Gates. Ask before each of these, and treat each approval as covering only its own step:
- building (ask once, up front, together with the review questions)
- the decision per PR (merge as is / fix on top / request changes)
- commit, push, merge
- the release
- every public PR comment
Phase 1 - read everything
gh pr view <n> --json title,author,body,headRefName,headRepositoryOwner,baseRefName,files,commits,mergeable,statusCheckRollup
git fetch origin master && git fetch origin pull/<n>/head:pr-<n>
git merge-base origin/master pr-<n>; git diff --stat origin/master...pr-<n>
git diff origin/master...pr-<n> -- . ':!scripts/tests' ':!docs' # code first, tests and docs second- Diff against
origin/master, never localmaster: the release job commits README versions and the Nix hash, so local master is often behind and the diff would show unrelated noise. - Read the PR's own tests last, and read them for what they assume: a fixture that starts in a state upstream never produces (e.g.
own: trueon a binding upstream refuses to mark as own) makes every assertion green and the feature dead. The PR body's test counts are not evidence. - Docs-only PR: no build, no workers. Grep each corrected claim against the code, and check AGENTS.md/CLAUDE.md for bare
@pathlines: they are imports loaded into every agent session, so they become plain links (on-top fix). No release needed; the CHANGELOG credit rides along. - Several PRs from the same author off the same base each bump
EXPECTED_PATCH_COUNTandEXPECTED_TEST_HARNESSESby one from the same number; merging both means re-bumping in the integration commit. Same for the per-directory counts in README anddocs/patches.md. When sibling PRs touch overlapping CSS or DOM selectors (for example one for backdrop mode and one for standalone opt-in mode), diff their property sets side by side so fixes like::before/::afterbox-shadow: noneland in both.
Phase 2 - classify
Answer these in the first reply, because the maintainer asks them every time:
- Category and switch - a judgement per patch, not a reflex. The maintainer wants the project to be "for everyone": a contributor's Linux fix belongs in
patches/linux/always on, infrastructure incore/always on, and only a feature that changes behavior or cost for every user goes behind a Community switch. The switch's default is a judgement too: ON when the feature is a plain improvement most people want and costs nothing (the theme picker and the Computer Use consent switch ship on), OFF when it spends model turns or API budget or replaces an upstream surface. Say which in the review and in the thank-you.patches/linux/is always on and must be a Linux fix.patches/community/is an opt-in feature with a row in Settings -> Extra -> Community Features (a toggle, or a list/editor whose empty state equals upstream behavior).patches/core/is always-on infrastructure that other patches build on. A new feature incore/with no switch is misplaced: it goes tocommunity/behind a switch, default off, as an on-top commit. Switch check (mandatory, the maintainer's first concern): most contributions are features, and every feature must sit behind a Community switch, either its own or the switch of the feature it extends. Name the switch, then verify that switching it off preserves upstream: the off state renders upstream's output, and the injected code starts no timers, polling, IPC or network reads before it has read the switch. Code that renames or wraps upstream functions runs whatever the setting is, so read what it does while off. A patch that targetsresources/ion-distonly reaches 3P mode (app://localhost); in 1P the UI is remote claude.ai code. Say so in the review, and in the docs if the PR leaves it out. - Cost and blast radius. Does it call GitHub/claude.ai APIs on a sweep (rate budget shared with upstream's own reads)? Does it inject messages into a running session (spends model turns)? Does it persist state (per-profile path via
app.getPath("userData"), never a fixed home path)? Default off unless the maintainer says otherwise. - Linux compatibility - always, for every PR. Read
.claude/skills/linux/SKILL.mdand go through each axis of its matrix: distro/package format (Arch, deb, rpm incl. RHEL 9, Nix, AppImage), glibc floor, x86_64 + aarch64, X11/Wayland/XWayland, the desktop environments and compositors, input/screenshot backend, and profile isolation. Give a one-line verdict per axis in the review, "not touched" included. Touching the launcher, a bridge, packaging, session-type or compositor paths means checking every row in depth. Pure main-process or renderer JS still gets the per-axis lines, plus the 1P/3P mode split. - Windows branch. Custom models and the Extra settings page also load on win32 for the downstream fork; a new Extra row needs both the
win32IPC handler refusal injs/extra_settings_main.jsand the!IS_WIN32UI gate injs/extra_settings_page.js(covered by DOM and status tests), and must not change Linux behavior.
Phase 3 - build and audit in parallel
Worktree and build (ask first, then run in the background):
git worktree add .claude/worktrees/pr-<n> pr-<n>
cd .claude/worktrees/pr-<n> && ./scripts/build-local.sh # downloads the current official .deb into build/work/Never git add -A in a PR worktree that holds a tmp symlink to another checkout's extract: tmp/ is gitignored as a directory, the symlink is not, and it ends up in the commit (happened on #310; amend it out). Use git add -u plus explicit new paths. The build does not leave a pristine extract behind. For the audit, extract one into the worktree's tmp/: ar x + tar xf the .deb from build/work/ into tmp/extract/, then npx @electron/asar extract tmp/extract/usr/lib/claude-desktop/resources/app.asar tmp/app.asar.contents. A second PR worktree can symlink that tmp/. Workers read the bundle with python3 -I or grep -a; rg silently finds nothing in it.
Audit the upstream code around every patched site - this is the step that finds the real bugs, and the main thread does the key read itself:
- For each regex site, dump the enclosing method and its callers and gates upstream of it. A patch that relaxes a check deep in a method is a no-op when an earlier gate (ownership, platform, feature flag, state machine) already refused. #308 patched two
not_authorchecks that sat behind anown/notOwnReadownership gate decided at bind time; the feature could never fire for its own use case. - List every runtime anchor the injected JS assumes (property names, method arities, return shapes, option objects, message formats, Map key formats) and have an opus worker verify each one against the pristine bundle with a HOLDS / BROKEN / PARTIAL verdict and a quote. The build only checks the regex anchors.
- Check for absorption: does upstream already ship part of the behavior (same strings, same event)? Then that part is dropped, not duplicated.
- Harnesses:
bash scripts/run-feature-tests.sh <category>for the touched category pluscore, the PR's own harness withtmp/present (its "real release" branch must run, not SKIP), the absorption probe,node --checkon a patched copy,nph --check+nim checkon new Nim.
Phase 4 - decide with the maintainer
One AskUserQuestion with one question per PR, recommended option first:
- Fix on top (recommended when a gap is real and bounded): our commit after the author's, then merge.
- Merge as is: nothing to fix; credit and ship.
- Request changes: only when the design itself is wrong and the fix would be a rewrite.
Also ask up front which identity or environment a live test needs, so "skip live, ask the author to test" is a conscious choice.
Phase 5 - fix on top
Dispatch an implementer (opus for ownership/consent/state semantics, sonnet for contained plumbing) into the PR worktree with: the exact sites and host/scope variables you already found, the AGENTS.md strictness rules, "extend the PR's harness against the real extract", "do not commit, do not build", and the docs/CHANGELOG wording (regular - dashes, -> not arrows, no em-dashes, author credited in the heading). Review per Phase 4 of /check-issue. Rebuild and rerun the category harnesses afterwards; the implementer's make is not a package build.
A feature moved from core/ to community/ gets: git mv of the patch, a globalThis.__cdb... predicate in js/extra_settings_main.js read by the patch (pattern: fix_tray_icon_theme.nim / __cdbTrayAlwaysWhite), a bridge channel pair in js/extra_settings_bridge.js, a row in FEATURE_ROWS of js/extra_settings_page.js, the win32 refusal, the DOM and bridge harness lines, and the docs/patches.md table move with both directory counts (README too).
Phase 6 - ship
- Build in the PR worktree, hand over
sudo pacman -U <worktree>/build/<pkg>, wait for the maintainer to install and restart the app. - Live check what the host can check: the new Settings row (read, save, reload, JSONC lock), the
[...]lines in~/.config/Claude/logs/claude-patches.log, and the feature path when an identity for it exists. A test PR in this repo viaghis fine for GitHub-side features; delete it afterwards. Run the feature path BEFORE pushing: a harness built from the shape the author believes upstream sends can be green while the real app never takes that path. When the live path silently falls back to upstream, the on-top fix adds oneclaude-patches.logline naming the check that refused, then retest. A desktop-driving worker re-activates the app window before every typed chunk and click; the maintainer typing elsewhere steals focus. On an X11 host the main thread can drive the app itself without the maintainer:xdotool mousemove --window <id> x y click 1+xdotool type, screenshots withimport -window <id>(the Electron window, found viawmctrl -lx | grep anthropic.Claude) andimport -window root -crop WxH+X+Yfor GTK portal dialogs, whose--windowcoordinates are off by the frame height - use absolute root coordinates there, navigate the folder picker through its sidebar bookmark and click the row, then Select. A Code session on a test branch: Code tab -> folder dropdown -> Open folder..., untick Worktree, send a one-word prompt; the PR binding lands in~/.config/Claude/claude-code-sessions/<org>/<account>/local_<id>.json(prs,autoArchiveOnPrClose). Delete the test PR's file from master afterwards: merging it puts the file on master. - Re-fetch every PR head right before merging, and before dispatching an implementer (
git fetch origin pull/<n>/head:refs/remotes/pr/<n>and compare with the SHA you reviewed; never compare via FETCH_HEAD, the next fetch overwrites it): an on-top fix written against a stale head has to be ported when the author has rewritten the same files. contributors push while you review, and a head that is not reachable from master leaves the PR open even after its earlier commits landed. A late commit is cherry-picked under the author's name (--author), thengit merge -s ours pr-<n>makes the head reachable so GitHub marks the PR merged. Merge onmaster, directly, no feature branch:git merge --no-ff pr-<n>(or merge both PRs in sequence), then the integration commit (count re-bumps, CHANGELOG with credit, docs), thengit push origin master. The PR shows as merged once its head commit is reachable from master. - Release:
gh workflow run build-and-release.yml --ref master -f force_rebuild=true(or/deploy force), watch withgh run watch <id> --exit-status, confirmgh release view. - Clean up:
git worktree remove .claude/worktrees/pr-<n>, delete the localpr-<n>branches.
Phase 7 - thank the author
One comment per PR, in the /comment voice: thanks, what shipped (and its menu path), the release in bold, what we changed on top in one sentence and why (no blame, no internals), and - when the live test needed something we lack - one friendly sentence saying so and asking whether they can confirm it on the release. No bullet lists, no edge cases, no invitation to send more PRs.
For a PR with a UI change, attach two or three screenshots from the live check to the comment itself, each with a one-line caption saying what it shows: not only where the new row is, but what was tested (a refused input with its message, a saved state, the evidence behind any "could not reach X here" sentence). The maintainer takes the time to test and wants the thread to show it. Crop to the row or dialog in question (about 800 px wide): two full-window shots that differ in one value look identical on a phone, which is where the maintainer reads the thread. Draw a rectangle around what is new, and personal data blurred (name, org, sidebar recents, the config path line under the rows, project names in a session header, other windows); crop and view every blur strip before uploading, the path line moves when a row wraps. gh cannot upload attachments, so a worker uses claude-in-chrome with the maintainer's GitHub session and drags the PNGs into the comment editor (the same recipe as /check-issue Phase 7); check every PNG before uploading. The comment editor's own file input ignores the extension's file_upload: upload through the page's bottom "Add a comment" box instead, read the user-attachments/assets/<uuid> URL GitHub inserts there, clear that draft without submitting, and type the  line at the end of the edited comment. Verify afterwards with gh pr view <n> --json comments that each comment body references its asset and that no extra comment was posted.
Phase 8 - self-improve (always, last step)
Before reporting done, update this file. Fold lessons into the phase they belong to; keep dated one-liners under "Lessons" only when they have no home; never write minified names or versions into the phases; keep this file under ~150 lines; tell the maintainer in one line what changed.
Lessons
- 2026-11-04 (#308): a PR's harness can be green with the feature unreachable. Always trace the gates before the patched site in the pristine bundle, and read the fixtures' starting state.
- 2026-11-04 (#309): a contributor may put a new feature in
patches/core/because the infrastructure patches live there; the category question is the first thing the maintainer asks. - 2026-11-05 (#312): when two PRs append a
{ ... }block at the same spot of a harness, git keeps the shared closing braces as common text and a keep-both resolution leaves the first block unclosed;node --checkstill passes when the block lives inside a driver string. Re-run the harness after every merge resolution and gate the commit on it. - 2026-11-05 (#316): an ion-dist patch reaches 3P mode only, and React-compiler cache calls (
<alias>(<slot count>),$[<n>]) plus vendor export names are minified anchors too; demand[\w$]+/\d+and stable strings. The author force-pushed a rework mid-review (the on-top fix was ported onto it). - 2026-11-06 (#316): the author's UI half patched ion-dist, which only 3P loads; the maintainer wanted it for everyone, so the port to the claude.ai page (runtime injection like panel tabs) was our follow-up, live-verified with the recipe in Phase 6. Ask "does this reach 1P users?" for every renderer patch.
- 2026-11-04:
run-feature-tests.shprints its Summary on the second-to-last line (a===rule follows); gate ontail -2 | grep ' 0 failed', nottail -1. - 2026-11-05 (#313): the patch keyed on the first-use folder sentence in the ask reason; live, upstream asked with its ordinary card (no reason) and the dialog never fired, although a 48-test harness incl. the real broker passed. Found only by the live run; fixed on top with a
card kept: <reason>diag line. - 2026-11-10 (#321, #322): a Nix module can be evaluated and its generated scripts built on a host without Nix through Docker (
nixos/nix, a named volume for/nix,path:flake refs, stub packages instead of the app and the browser); say in the comment what only a real NixOS run can show. The PR's own CI step had never run (fork PRs get no CI). - 2026-11-10 (#321, #322): our fix on top gets its own independent review before the merge. Both had a regression of ours (a bare-name spawn with a wide PATH; a transient failure turned into a permanent stop). A PR's CHANGELOG hunk conflicts with ours: take ours in the merge and write the credited entries in the integration commit.
- 2026-11-10 (#321): upstream narrows
process.env.PATHto root-owned system folders at startup and keeps the launch PATH in an env variable. A wide PATH goes only to what the user named (the app to open); tools we choose are resolved on the narrowed PATH plus root-managed folders and spawned by absolute path. - 2026-11-13 (#333): a contributor may push (and rebase onto a new upstream) while you review: re-fetch the head right after every pause and before the worktree build,
git reset --hardthe PR worktree to the new head, and re-read the incremental diff. A "wait for build" loop that greps the log for "Build complete" fires early (the tarball stage prints it); wait on the build process itself.pkill -fon a pattern in your own command line kills your own shell; kill by PID. - 2026-11-13 (#333): for a feature whose first message is built from untrusted remote text (Jira, issues), the consent question is the exact text shown in a native confirm dialog before every send, not only a folder picker. Credentials must be bound to the host they were saved for (clear the token when the site changes), and per-site caches must be cleared on credential change and switch-off.
- 2026-11-13 (#333): when workers report harness counts, check the labels yourself (
ls scripts/tests/<category>); one worker swapped community and core.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

