Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@

# Local agent config (not shared)
.claude/settings.local.json

# skill-creator eval scratch (not part of the skill)
*-workspace/
32 changes: 32 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# CLAUDE.md — reply-pr

Guidance for Claude Code when working in this repo.

## What this repo is

`reply-pr` is a cross-tool **Agent Skill** (`SKILL.md`) that triages and replies to
a pull request's unresolved review comments (reply-only; it never edits code). The
skill lives at **`skills/reply-pr/`** (`SKILL.md` + `scripts/`); the repo root holds
the README and config. It installs via `npx skills add deployhq/reply-pr` — which
requires the `skills/<name>/SKILL.md` layout, so keep that structure.

## Repo hygiene — do NOT commit scratch or generated artifacts

Only the skill, README, and repo config belong in git. Never commit local scratch,
eval output, or tool-generated working directories:

- `*-workspace/` (e.g. skill-creator's `reply-pr-workspace/` eval runs), `.idea/`,
`.vscode/`, `.claude/settings.local.json` — all gitignored; keep it that way.
- **Do not run `git add -A` / `git add .` blindly** — it sweeps in whatever untracked
scratch happens to be in the working tree. Stage specific paths (`git add <path>`),
or run `git status` and confirm exactly what's staged **before** committing.

Why this rule exists: an earlier `git add -A` accidentally committed a skill-creator
eval workspace into this public repo. Verifying the staged set prevents persisting
things we don't need.

## Testing the skill

- `bash skills/reply-pr/scripts/gather.sh <PR> [owner/repo]` — read-only; safe to run.
- `scripts/post-reply.sh` **posts and resolves** on real PRs — don't run it against a
live PR while testing.
128 changes: 64 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,82 @@
# reply-pr

**Answer a PR's review comments the right way — without re-explaining the etiquette every time.**

Reviewers — Codex, Claude, CodeRabbit, and humans — pile comments onto a pull
request, and replying *well* is fiddly: each reviewer wants a different channel
and a different `@`-ping, every comment deserves a reply (what you **tackled**
*and* what you **skipped**, with a reason), pre-existing code shouldn't be
re-litigated, and you're meant to end with **zero unresolved threads**. Doing all
that by hand is tedious and easy to get subtly wrong.

`reply-pr` turns a wall of review comments into a clean, decided set of replies.
It knows the per-reviewer conventions, critically assesses each comment (it does
**not** blindly accept bot suggestions), and **never posts without your OK**.

## Why use it

- **Stop re-explaining the rules.** It already knows them: Codex → inline + `@codex`,
Claude → top-level + `@claude`, CodeRabbit → inline, no ping, nitpicks dropped,
humans first. Any other bot works too — it replies *in kind*.
- **You stay in control.** It is **reply-only — it never edits code**, and it
**always stops at a deliberation gate** with a tackle/skip proposal before
posting anything.
- **No silent skips.** Every comment gets a reply — what you did (with the commit
SHA) or why you skipped it — in your voice.
- **Cuts the noise.** Drops CodeRabbit nitpicks and flags findings that look
pre-existing (a bot re-flagging code this PR didn't change).
- **Ends clean.** Resolves threads once they're settled, so the PR lands at zero
unresolved.
- **Cross-tool.** Runs in Claude Code, Cursor, Codex — any tool that reads Agent
Skills.
<h1 align="center">reply-pr</h1>

<p align="center">
Triage and reply to a pull request's unresolved review comments —<br/>
reply-only, on each reviewer's channel, with you approving every reply.
</p>

<p align="center">
<img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg">
<img alt="Agent Skill" src="https://img.shields.io/badge/Agent%20Skill-SKILL.md-black">
<img alt="Works with Claude Code, Cursor, Codex" src="https://img.shields.io/badge/works%20with-Claude%20Code%20%C2%B7%20Cursor%20%C2%B7%20Codex-5B4FE9">
</p>

`reply-pr` reads the unresolved comments on a pull request, helps you decide what
to address and what to skip, and posts a reply on the right channel for each
reviewer — in your voice. It doesn't edit your code, and it doesn't post anything
you haven't approved.

## Why it exists

A PR usually gathers comments from several reviewers at once — CodeRabbit, Codex,
Claude, and people. Replying to them properly is more fiddly than it looks:

- each reviewer expects a different channel and `@`-ping (Codex inline with
`@codex`, Claude a top-level comment with `@claude`, CodeRabbit inline, no ping);
- every comment wants a reply — including the ones you skip, with a reason;
- bots re-flag pre-existing code and add nitpicks that aren't worth re-litigating;
- and you're meant to leave no unresolved threads behind.

`reply-pr` keeps track of all that, so the replies stay yours and nothing slips.

## How it works

```mermaid
flowchart TD
A["reply-pr on your PR"] --> B["Gather UNRESOLVED comments<br/>bots + humans, inline + top-level"]
B --> C["Classify + critically assess<br/>humans first, dedup,<br/>drop CodeRabbit nitpicks,<br/>flag likely pre-existing"]
C --> G{"Deliberation gate:<br/>tackle / skip + rationale<br/>you decide"}
B --> C["Classify + assess<br/>humans first, dedup,<br/>drop CodeRabbit nitpicks,<br/>flag likely pre-existing"]
C --> G{"You decide:<br/>tackle / skip + rationale"}
G -->|you steer| R["Reply on each reviewer's channel<br/>item by item, in your voice"]
R --> Z["Resolve settled threads<br/>zero unresolved"]
R --> Z["Resolve settled threads"]
```

Nothing is posted, no code is touched, and no thread is resolved **before the
gate** — the skill only acts on what you approve.
It gathers the unresolved comments, assesses each (humans first, CodeRabbit
nitpicks dropped, likely-pre-existing findings flagged), and shows you a
tackle/skip list to steer. Once you approve, it posts each reply on the reviewer's
channel — noting the commit that fixed things where relevant — and resolves the
settled threads. It is reply-only, and it never posts before you approve.

## Install

With the [`skills`](https://github.com/vercel-labs/skills) CLI — cross-tool (Claude
Code, Cursor, Codex, …):

```bash
npx skills add deployhq/reply-pr # this project only (./.claude/skills)
npx skills add deployhq/reply-pr -g # all your projects (~/.claude/skills)
npx skills add deployhq/reply-pr -g # all your repos (~/.claude/skills)
npx skills add deployhq/reply-pr # this project only (./.claude/skills)
```

`skills add` **defaults to project scope** (committed with the repo, shared with
your team). `reply-pr` is a personal, cross-repo tool, so you probably want
**`-g` / `--global`** instead. Scope is set by the flag — the CLI doesn't prompt
for it.

Inside saas.group it's also listed on [lookmi](https://lookmi.saas.group/skills) —
install it with the command shown on its skill page.
`skills add` defaults to project scope; since `reply-pr` is a personal, cross-repo
tool, you probably want **`-g` / `--global`**. (Scope is set by the flag — the CLI
doesn't prompt for it.) Inside saas.group it's also on
[lookmi](https://lookmi.saas.group/skills).

## Use

```
/reply-pr # unresolved comments on the current branch's open PR
```bash
/reply-pr # the current branch's open PR
/reply-pr 1016 # a specific PR
/reply-pr analyse # analysis only — never posts
```

Or just ask naturally: *"reply to the review comments on this PR"* — the skill
triggers from its description. Either way it stops at the **deliberation gate**
(a tackle/skip proposal, humans first) and only posts after you steer it.
Or just say *"reply to the review comments on this PR."* Either way it stops at the
approval gate — a tackle/skip proposal, humans first — and only posts what you
approve.

## Reviewer routing
## Who gets replied to, and how

The general rule works for **any** reviewer: reply *in kind* (where they
commented) and ping only reviewers known to want it.
The rule works for any reviewer: reply in kind (where they commented) and ping only
reviewers known to want it.

```mermaid
flowchart LR
Expand All @@ -88,26 +87,27 @@ flowchart LR
O["Any other bot"] --> OR["reply in kind, no ping<br/>flagged for you to confirm"]
```

## What it will and won't do
## What it does and doesn't

- **Will:** fetch unresolved comments, propose tackle/skip (you decide), post the
replies you approve on the right channel, and resolve settled threads.
- **Won't:** edit code, post anything before you approve it, or quietly skip a
comment or re-litigate pre-existing code without flagging it.
| Does | Doesn't |
|---|---|
| Fetch unresolved comments | Edit your code |
| Propose tackle / skip (you decide) | Post anything before you approve it |
| Post replies on the right channel, in your voice | Silently skip a comment |
| Resolve settled threads | Re-litigate pre-existing code without flagging it |

## Requirements

- `gh` CLI (authenticated), `jq`.
- [`gh`](https://cli.github.com/) CLI (authenticated), `jq`.

## Structure
## Under the hood

```
```text
skills/reply-pr/
SKILL.md — the skill (workflow, reply rules, voice)
scripts/gather.sh — fetch unresolved threads (GraphQL) + top-level comments
scripts/post-reply.sh — post inline / top-level replies, resolve threads
README.md
```

(The `skills/reply-pr/` layout is what the `skills` CLI expects when installing
from a repo.)
The scripts are deterministic plumbing (`gh` + `jq`); the judgement — what to
tackle, how to word it, when to resolve — stays in the skill, gated on your call.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading