cephalofoil/kitt/tree/master/pr-watch
pr-watch
Claude Code 模组:在提示列上方显示 PR 检查状态、失败日志、未提交变更与落後主分支的 rebase 提示,並透過工具呼叫讓 Claude 代為 commit、push 與 rebase(合併仍需人工確認)。
关于这个 mod
pr-watch 是 kitt 專案中的 Claude Code 外掛,僅在有需要處理的事情時,於提示列上方顯示資訊。每個按鍵不會直接執行 git,而是送出簡短指示給 Claude,由 Claude 決定是否行動並呼叫外掛工具,工具再執行固定步驟並回報結果,因此每次動作都是對話紀錄中真實可見的工具呼叫。
顯示與操作對應:開啟中的 PR(狀態、issue、每個檢查的 chip、失敗步驟與日誌行)可按 1/2/3/x 重試失敗工作、把日誌交給 Claude、在瀏覽器開啟或隱藏;未提交的變更按 c 由 Claude 依 repo 規範撰寫訊息並呼叫 commit(不 push);尚未推送的提交可 push 或開 PR;落後預設分支按 b 執行 rebase_and_push;PR 已合併按 m 切換回預設分支。合併一律由使用者決定,任何合併呼叫都會被攔下詢問。另提供 Auto-rebase 選項(預設關閉)。
工具包括 mcp__pr-watch__commit、mcp__pr-watch__push 與 mcp__pr-watch__rebase_and_push。分支名稱顯示於提示行末,/pr-watch 可開啟 PR 完整檢視;按鍵需先讓該列取得焦點。
安裝方式: /plugin marketplace add cephalofoil/kitt /plugin install pr-watch@kitt
授權為 MIT。
安装
请先查看作者 README 确认 marketplace 和插件名称;命令可能随仓库结构改变。
claude plugin marketplace add cephalofoil/kitt claude plugin install pr-watch
原文 / README
kitt
<img width="2172" height="724" alt="Kitt-Logo mit kobaltblauen Ts" src="https://github.com/user-attachments/assets/0bbde4f9-62bc-4e15-ac01-c3796f27b836" />Parallel work on a repo as lanes: one worktree per ticket, each with its own ports, its own agent in herdr, and a proof that the change works in the app.
Three parts:
kitt, a Go CLI: lanes, dev servers, the emulator, checks, proofs, and a dashboard.lanes, a Claude Code skill: tells an agent how to work in a lane.pr-watch, a Claude Code mod: PR checks, uncommitted work and rebase state above the prompt.
Install
go build -o ~/.local/bin/kitt.exe ./cmd/kitt # any directory on PATH
/plugin marketplace add cephalofoil/kitt
/plugin install pr-watch@kitt
/plugin install lanes@kitt
kitt doctor says what is missing (git, gh, herdr, adb, symlinks).
A day with it
kitt repo add # once, inside the repo: registers it and shows what kitt detects
kitt init # optional: write that as kitt.toml to edit (--home for a repo that is not yours)
kitt dash --workspace # the dashboard as its own herdr workspace
kitt new 338 # lane for issue 338: worktree, branch, env links, install, and an agent started on the issue
kitt new 412 --apps web # a lane about the website: starts the web app, leaves the emulator alone
kitt new settings-proto --prompt "/wayfinder settings across several screens"
In the dashboard, one row per lane: the apps it has changed files of, the agent's state, uncommitted and behind counts, the PR and its checks, the last proof, which dev servers answer, and which lane the emulator shows.
| Key | |
|---|---|
| enter | go into the lane: its herdr workspace and agent, its dev servers started, its app in the emulator |
| g | start the lane's agent (on its issue, if it has one) |
| e | only point the emulator at the lane |
| o | open the lane's web app in the browser |
| i | install what the lane runs, when a lane shows no install (installs run one lane at a time) |
| u / d | start / stop the lane's dev servers |
| c | run the repo's checks for the apps the lane touched |
| p | open the lane's proof |
| n | new lane: an issue number starts an agent on it, a name only makes the lane |
| a | adopt a worktree kitt did not create (Claude's, herdr's, a hand-made one) |
| x | remove a lane that holds nothing unsaved |
| t | show the worktrees that are not lanes |
Under the lanes, the open pull requests that have no lane yet (a bot's are left out). enter on one fetches its branch and checks it out as a lane about the apps it touches; o shows it on GitHub. The same from the shell: kitt pr 380.
Every key is also a command: kitt focus, kitt agent, kitt emu, kitt up, kitt check, kitt proof open, kitt adopt, kitt rm. See kitt help.
How lanes stay apart
- Ports. Each lane holds a slot; an app listens on its base port plus ten per slot (Metro 8081 in the main checkout, 8091 in the first lane).
kitt envprints a lane's ports. - Env files. The gitignored files named under
linkare symlinks into the main checkout, so every lane sees the same secrets and an edit reaches all of them. - The emulator. One device, one installed dev client.
kitt emureverses the lane's ports into it and sends the client to the lane's Metro; no native build. A proof holds a lock, so two agents never load over each other. - Shared apps. An app marked
sharedruns once, from the main checkout, for every lane (a database, a backend whose port is fixed).
kitt.toml
Everything project-specific lives in the repo, in kitt.toml. kitt init writes it:
kitt detect <path> # look first: what kitt sees in a repo; registers and writes nothing
kitt init # the wizard: each detected piece shown to keep, edit or drop, then written and registered
kitt init --agent # an agent reads the repo first (justfile, Makefile, CI, AGENTS.md) and fills in dev commands, checks, ports
kitt init --home # write into kitt's own folder, for a repo that is not yours to add a file to
Detection alone finds the apps (Expo, Next, Vite, anything with a dev script, a Python backend), their checks from package.json scripts, the package manager from the nearest lockfile, and the gitignored .env files to link. What it cannot see, the agent or you add: which env file means local, how the apps find each other, what CI really runs.
Which apps a lane touched is never stored. kitt reads it from git each time: the files that differ from the base branch, matched to the app whose dir they lie in.
name = "example-app"
base = "master"
link = ["apps/mobile/.env", "apps/mobile/.env.supabase.local"]
[emulator]
reverse = [54321] # ports besides the apps' own the device must reach
[proof]
guide = "docs/proof.md" # or the text itself: test accounts, how to reach a screen
[[app]]
name = "mobile"
kind = "expo" # expo | web | backend
dir = "apps/mobile"
port = 8081
dev = "bunx expo start --dev-client --clear --port {port}"
env_files = [".env.supabase.local"]
setup = ["bun install --frozen-lockfile"]
checks = ["bun run typecheck", "bun run lint", "bun run test"]
[app.env]
EXPO_PUBLIC_API_URL = "http://localhost:{port:api}"
{port}, {port:<app>}, {lane}, {slot}, {root} and {main} are filled per lane. lazy = true defers an app's setup and start until it is named; shared = true runs it once for all lanes.
dev runs in a herdr pane, in your shell; setup and checks run through cmd /C (sh -c elsewhere).
Until a repo has its own kitt.toml on its base branch, a copy at <kitt home>/repos/<repo folder>.toml stands in; the repo's file wins once it exists.
Proof
kitt proof begin # takes the emulator, loads the lane's app, prints the repo's guide
kitt proof shot "one section, no header"
kitt proof end --pass # or --fail --note "..."
kitt proof open # the page: verdict, note, shots in order
Proofs are kept under kitt's own folder (%APPDATA%\kitt\proofs), outside the repo. A proof goes stale when the lane gets a new commit.
pr-watch
Shown above the prompt, only when there is something to act on.
A key never runs git itself. It sends Claude a few words, with the how-to attached where only Claude reads it. Claude decides whether and how to act and calls one of the mod's tools; the tool does the fixed steps and answers with what happened. So every action is a real tool call in the transcript that Claude can decline, redo with other arguments, or react to.
| Shown | Key | What happens |
|---|---|---|
| the open PR: status, issue, one chip per check, the failing step and log lines | 1 2 3 x | retry failed jobs · hand the log to Claude · open in browser · hide |
| uncommitted work | c | Claude writes the message the repo asks for and calls commit; no push |
| commits not pushed, no PR yet | p | Claude runs the repo's checks, calls push, opens the PR |
| commits not pushed, PR open | p | Claude calls push |
| behind the default branch | b | Claude calls rebase_and_push: the branch is rebased onto the default branch and then pushed to its own remote branch, ready for a PR; on conflicts Claude rebases by hand and asks where a conflict is not clear |
| the PR is merged | m | switches to the default branch, brought up to date (done by the mod; Claude is told) |
Merging is yours. No key and no tool merges. When Claude runs gh pr merge anyway, the call is held and you are asked; anything but "Merge" refuses it.
Auto-rebase is an option of the plugin, off by default (/plugin, pr-watch, configure). On, a branch with an open PR that falls behind is rebased and pushed without a key press, as long as the tree is clean and the rebase has no conflicts.
The tools, as Claude sees them:
mcp__pr-watch__commit{ subject, body?, paths? }: stages and commits. Refuses on the default branch. Never pushes.mcp__pr-watch__push{ force_with_lease? }: pushes. A refused push answers with the commits the remote holds; forcing then overwrites exactly those.mcp__pr-watch__rebase_and_push: rebases onto the default branch and pushes with lease. A conflicting rebase is undone and answered with the files.
The branch name sits at the end of the hint line. /pr-watch opens the full view of the PR. Keys work once the band has focus (click it, or ctrl+x tab).
