Watch GitHub PRs from a Claude Code session: merge state, review and required checks above the prompt, with alerts when they change
翻译准备中
插件TypeScript · ShellGitHub @sezaakgun自行安装运营者未确认
试用过了吗? 点一下就好,无需登录。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
安装型项目无需部署域名也可验证。个人仓库可通过 GitHub 登录验证,组织仓库可使用上方的仓库验证文件。
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Watch GitHub pull requests without leaving your Claude Code session.
Paste a PR URL, or let Claude open one, and it gets one line above the prompt: merge state, review decision and required checks, refreshed every minute by default. When a check flips or the merge state moves you get a toast, a one-second flash and a sound, and Claude gets a note with the failing check's log link. You keep working; the PR tells you when it needs you.
Claude can also ask for a PR's status itself, the list survives restarts, and /config controls what alerts, which checks count, and how often PRs are polled. Where no line can be drawn (claude.ai/code on the web, the Claude mobile app), /prs prints the PRs and every alert is a line in the transcript.
One PR is always one line; hovering it shows its buttons and the details panel names the checks. Reading the line explains each part.
The plugin is a Claude Code mod: a plugin whose TypeScript hooks run inside Claude Code's own process, instead of shell-command hooks. Mods are on by default from Claude Code 2.1.287.
claude --version; mods load by default from 2.1.287). Older builds still watch and alert, but keep the list in memory only, send Claude no note and cannot copy. Before 2.1.287, function hooks were in early access and load only with CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 set; 2.1.287 and later ignore that variable, so remove it if you set it.gh), logged in with access to the repos you watch. Check with gh auth status. In a claude.ai/code cloud session gh comes set up for the repos the session was given, and since that session refuses GraphQL, polls go over the REST API there (see How it works).afplay with the system sounds) and open. On Linux, xdg-open is tried when open is absent, and there is no sound.Install from GitHub. The repo is its own marketplace:
claude plugin marketplace add sezaakgun/cc-pr-tracker
claude plugin install cc-pr-tracker@cc-pr-tracker
Start claude, paste a PR URL as the whole prompt and press Enter. No model turn runs; Claude Code shows Prompt dropped by a hook: watching owner/repo#N. Several URLs at once, separated by spaces or newlines, are all watched.
The line appears above the prompt and fills in within a few seconds.
Paste the same URL again to stop watching. Run /plugin to confirm the mod loaded: a dim line under the tabs reads N mods active · cc-pr-tracker.
If the line shows gh failed: … instead, see Troubleshooting.
To try it without installing, or to hack on it, clone and load it for one session:
git clone https://github.com/sezaakgun/cc-pr-tracker
cd cc-pr-tracker
claude --plugin-dir .
The repo's own .claude/settings.json still sets CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 for builds before 2.1.287; newer ones ignore it.
On Claude Code 2.1.289 or later the list comes back when you resume a session, Claude is told about changes, and the copy buttons work. Older builds watch and alert as before, in memory only.
Watch a PR: paste its URL as the whole prompt, several at once if you like. Or mention URLs in a normal prompt: the prompt runs as usual and the PRs are watched too.
Watch a PR Claude creates or talks about: nothing to do. Any open PR whose URL appears in Claude's answer is watched, and so is the URL gh pr create prints when it runs through the Bash tool. Subagent answers are not scanned.
Use the line's buttons: hover a line and five buttons appear at its end: open, copy, mute (or unmute), details and ×. They need a terminal that reports the mouse.
Open a PR: Cmd+click its repo#number (needs a terminal that renders hyperlinks), or hover the line and press open.
Copy a PR's URL: hover the line and press copy, or press copy URL in the details panel. Over SSH the terminal's clipboard is reached through OSC 52.
Ask Claude about a PR: Claude has a pr_status tool for the PRs you watch. It polls them when called and answers with the state, merge state, review decision, every required check with its log link and any failing optional check (every optional one with Count all checks on), so "why is my PR red?" needs no gh call. Claude passes a URL or owner/repo#number for one PR, or nothing for all of them; a PR that is not watched gets the list of those that are.
See every check: hover the line and press details. A side panel shows the title, the state, merge state and review, four buttons (open in browser, copy URL, stop watching, close), then every required check and every failing optional one (every optional one with Count all checks on), linked to its run when the run has an https link. Its last line counts the optional checks and says when the PR was last polled. Esc or close closes the panel and the PR stays watched.
Silence a PR: hover the line and press mute. The line keeps updating but that PR no longer toasts, flashes, plays a sound, notifies cmux or tells Claude; the line ends in · muted. Press unmute to turn alerts back on.
Several PRs stack, one line each, in the order you added them.
The line above the prompt is drawn by the terminal and the Claude Code desktop app only. When a session is followed from claude.ai/code in a browser or from the Claude mobile app, and no surface the session draws on has drawn the line, the PRs come to the transcript instead:
cc-pr-tracker: repo#7 · blocked · review required · ✓1 ✗1 · Fix itPRs: repo#7 blocked ✗1 · repo#8 clean/prs prints the full list whenever you want itThe toast and the note to Claude work as everywhere else. Show PRs in the transcript in /config turns this on everywhere (always) or off (never).
The list is kept with the session. Resuming it (claude --resume, --continue) watches the same PRs again, minus any merged or closed since; a new session starts empty. Set Remember watched PRs to this project to have every new session in the directory pick the list up instead. /clear drops the PRs Claude brought in and keeps the ones you pasted.
repo#number, then draft, merged or closed when the PR is not simply open. A merged or closed PR keeps its line until you stop it, shortened to its label, its state in magenta (merged) or gray (closed) and its title, all struck through. With Stop watching merged or closed PRs on, the line goes away instead.clean, has_hooks) means mergeable now. Yellow (behind, unstable) means update the branch or an optional check failed. Red (blocked, dirty) means a required check or review is missing, or there are conflicts. Gray (draft, unknown) needs no action; unknown usually resolves on the next poll.approved in green, changes requested in red, review required in yellow, or no review in gray when the repo has no review rules.✓N passed, ✗N failed or cancelled, ●N pending. Skipped checks are not counted and show as ○ only in the details panel. Failing optional checks are summarised as (+N optional ✗) and listed there too. With Count all checks on, the counts cover every check, so there is no optional summary, and the details panel lists every optional check.· refresh failed in red means the last poll errored and the line shows the previous values.· muted, dimmed, means the PR does not alert, because you muted it or Mute all PR alerts is on.Every poll is compared with the previous one. A required check changing bucket (for example pending → fail, or a new check appearing) or the merge state moving (for example blocked → clean) triggers the list below. With Count all checks on, optional checks count too; with Alert on review changes on, so does the review decision moving (for example review required → approved).
my-service#42 lint: pending → fail● PR checks changed[cc-pr-tracker: automated status notice, …] org/my-service#42 (…) changed: "lint: pending → fail". Newly failing required checks: "lint" https://…Alert on, Alert sound, Flash strip and Tell Claude about changes in /config (see Settings) narrow this. A muted PR gets none of these, the note included. Two things never alert: the first load of a PR, and a move into or out of GitHub's temporary unknown merge state.
Open /config; the rows are under cc-pr-tracker. Each also takes /config cc-pr-tracker.<field>=<value>. A change applies at once, without a restart.
| Row | Field | Default | What it does |
|---|---|---|---|
| Mute all PR alerts | muteAll | off | Lines keep updating; nothing toasts, flashes, sounds, notifies cmux or tells Claude. Its help text says how many PRs are watched and muted. |
| Alert on | alertOn | every change | every change, failures and ready to merge (a required check newly failing, or the merge state turning green), or failures only. |
| Tell Claude about changes | notifyClaude | on | The note Claude reads after an alert. |
| Alert sound | sound | on | The macOS sounds; the toast, strip and cmux notification stay. |
| Poll every (seconds) | pollSeconds | 60 | 30 to 3600; a value outside is held to the nearer end. One GraphQL call per PR per poll. |
| Auto-watch PRs | autoWatch | answers and gh pr create | answers and gh pr create, gh pr create only, or off. Pasted URLs are always watched. |
| Remember watched PRs | remember | this session | this session: resuming it brings the list back, a new session starts empty. this project: every new session in the directory watches the list. |
| Stop watching merged or closed PRs | stopWhenDone | off | A PR's line goes away once it merges or closes, with a toast saying so. Turning it on drops the lines already done. A PR you paste that is already merged stays until you stop it or turn this on. |
| Count all checks | allChecks | off | The line counts and alerts on every check, not only the required ones; the details panel and pr_status list every optional check. |
| Alert on review changes | alertOnReview | off | The review decision moving (for example to approved or changes requested) alerts too, whatever Alert on is set to. |
| Flash strip | flash |
/plugin: the dim mods active line should name cc-pr-tracker. If not, check claude --version is 2.1.287 or later, the plugin is enabled in the Installed tab, the session was not started with --safe-mode, and disableAllHooks is not true in your settings. On a build before 2.1.287, set CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1.gh failed: … on the line. Run gh pr view <url> in a terminal. Usually gh is not logged in or has no access to that repo. In a claude.ai/code cloud session, GitHub access to this repository is not enabled for this session means the repo was not added to the session./prs. If it answers but no transcript lines appear after a change, check Show PRs in the transcript in /config is not never.Required checks: none reported in details. The repo has no branch protection with required checks. The line still shows the merge state and review./System/Library/Sounds present plays sounds.open./config; a muted PR, Mute all, or Alert on set narrower than the change sends none. Claude reads the note on its next turn, so ask after the toast.this project. A /clear drops the PRs Claude brought in. Paste the URLs again.pollSeconds in /config) through gh, one GraphQL call per PR per poll.remember: this project ($.store); a hot reload keeps the lines as drawn ($.state). A session's list not polled for 30 days is deleted.claude -p run never draws; /prs still answers there, so claude -p "/prs <PR URL>" prints a PR's status./prs, transcript lines and the status line (see On the web and on your phone).approved shows even on a repo with no review rules.gh pr create output.github.com URLs are recognised; GitHub Enterprise hosts are not.refresh failed and the next one retries.The plugin is one hooks module, hooks/register.tsx. It hooks these events:
prompt.submit reads PR URLs from your prompt and starts or stops watching.turn.complete reads PR URLs from Claude's final answer, and tool.call on Bash reads the URL gh pr create prints.ui.render on AbovePrompt draws the lines; on Pane it draws the details panel.session.start reads the settings, restores the list, registers the pr_status tool and the /prs command, and sets up the timer that polls every watched PR.command.run on prs prints the list, toggling any PR URLs given.session.attach and session.detach re-check whether any surface draws the line, which decides the transcript lines and the status line.config.set applies a settings change at once; config.describe adds the watched and muted counts to the Mute all row.tool.call on mcp__cc-pr-tracker__pr_status polls the asked PRs and answers that tool.session.end with reason clear drops the PRs Claude brought in.An alert also calls $.session.append to add a user-role note Claude reads but you do not see. Because check names come from the PR's own workflows, the note says it is an automated notice and quotes every name GitHub supplies, capped at 100 characters.
The calls that arrived after 2.1.269 ($.session.root, $.state, $.session.append, $.ui.copy, the session.end event) are each guarded: on an older build the call fails, is logged once, and the plugin carries on in memory as 0.2 did.
Each poll is one read-only GraphQL call through gh api graphql: the PR's title, state, merge state and review decision, plus every check on its head commit with GitHub's own isRequired flag. Like gh pr checks, only the latest run of each check is kept: runs are grouped by app, workflow, event and name, so a re-run replaces the run it superseded while same-named checks from another workflow or event stay separate. The plugin maps check states to the same pass / fail / pending / cancel / skipping buckets that gh pr checks uses. When GitHub refuses GraphQL (a claude.ai/code cloud session says GraphQL is not available, or any HTTP 403), the session switches to the REST API for good: the PR, its head commit's check runs and statuses, its reviews, and the base branch's protection and rulesets, four to six calls per PR per poll. A failed poll keeps the previous values and marks the line refresh failed, so a network blip is not reported as a change. Every call has a 30-second timeout.
claude plugin test . # register.test.ts (pure helpers) and hooks.test.ts (every hook against the engine, gh faked)
bunx @biomejs/[email protected] lint --error-on-warnings # lint only (biome.jsonc); the code keeps its own style
claude plugin validate . # the manifests, and the events and $ calls the module uses
The tests need no login: nothing calls a model, and gh is answered by the tests. GitHub Actions (.github/workflows/test.yml) runs the validate and test steps on Claude Code 2.1.289 and the latest release, and the lint step, on every push to main and every pull request.
For type checking, load the plugin once (claude --plugin-dir .). Claude Code then writes this build's API types to .claude-plugin/types/, which is git-ignored and which tsconfig.json reads; tsc fails with a missing claude-code module until it exists. Then:
bunx -p typescript tsc -p .
Edits hot-reload into a running session. If a reload fails partway, the transcript says so; restart the session.
MIT. See LICENSE.
Silence every PR: open /config and turn on Mute all PR alerts. It applies at once, is saved across sessions, and every line ends in · muted while it is on. Turn it off to get alerts back; PRs you muted one by one stay muted.
Stop watching: hover the line and press ×, or paste the same URL again as the whole prompt. A paste of several URLs toggles each one; a URL inside a normal prompt never stops anything.
Print the PRs in the transcript: run /prs. Each PR gets its line, its URL and every required check that is not passing, with its log link; failing optional checks are listed too. /prs <PR URL>… starts or stops watching those PRs first, like a paste. It polls before it answers and runs even while Claude is working.
| on |
The one-second ● PR checks changed strip above the prompt. The toast, sound, cmux pane flash and notification stay. |
| Show PRs in the transcript | transcript | when no band is drawn | when no band is drawn (claude.ai/code on the web, the mobile app), always, or never: each PR's first status and every alert as a transcript line, and a summary in the status line. /prs works either way. |