# Pull request commands

URL: https://codepanel.ai/docs/commands

Every comment command CodePanel reads on a pull request: /review, /feedback, /ask, /rounds and /remember, with syntax and who can use them.

Commands go in a comment on the pull request's conversation, each on a line of its own. In the thread of an [inline suggestion](/docs/findings), only `/feedback` and `/ask` are read.

| Command | Does | Who may use it |
| --- | --- | --- |
| [`/review`](#review) | Starts a review round | People with write access |
| [`/feedback`](#feedback) | Rates findings, the review or a learning | People with write access, bots |
| [`/ask`](#ask) | Asks the orchestrator about a finding or the review | People with write access, bots |
| [`/rounds`](#rounds) | Sets this pull request's automatic round limit | People with write access, bots (bots within a ceiling) |
| [`/remember`](#remember) | Records a learning for the repository | People with write access |

Quoted lines (starting with `>`) are never read, so you can quote-reply the review and add commands below. CodePanel never reads its own comments as commands.

## Who may give commands

Write access means write, maintain or admin permission on the repository.

- **Anyone else is ignored.** A comment from someone who is not an owner, member or collaborator of the repository gets no reaction and no reply, so on a public repository nobody else can spend the owner's budget.
- **Permission is checked with GitHub.** GitHub's comment only says whether its author is an owner, member or collaborator. That includes organization members with no access to the repository and read or triage collaborators. So before acting, CodePanel asks GitHub for the commenter's permission (`GET /repos/{owner}/{repo}/collaborators/{login}/permission`, with the token the review uses) and reuses the answer for 5 minutes.
- **Without write access, nothing in the comment runs.** The comment gets 👎 and a reply with a code an agent can read:

  ```text
  @rita: not applied: `/feedback`.

  Refused: `write_permission_required`. GitHub reports `read` permission for @rita on acme/app; these commands need write, maintain or admin.
  Next: someone with write, maintain or admin permission on the repository can repeat the command, or the repository owner can act through the CodePanel API or MCP.
  ```

- **If GitHub does not answer,** the code is `permission_check_failed` and nothing runs. Repeat the command in a few minutes.
- **With no working GitHub token** for the repository (the owner's token is gone and no app is installed), nothing runs and nothing can be posted, so the comment gets no reaction. Reviews on the repository fail for the same reason, and say so.
- **One reply per burst.** Further refused comments from the same person within 5 minutes get 👎 only.
- **Bots are not looked up.** A bot account or GitHub App may rate (never dismiss), dispute, ask, and raise `/rounds` within its ceiling. It may not record a learning, and its `/review` is refused with `write_permission_required`.
- **Tokens are not affected.** The API, MCP and CLI act as the token's owner.

## Precedence

One comment can hold several commands. CodePanel reads them in this order, so a rating or a question can never start a paid review:

1. A comment with a `/feedback`, `/remember` or `/rounds` line is handled as those commands. `/review` on its own line beside `/rounds` (and no `/feedback` or `/remember`) also runs, from someone with write access.
2. Otherwise, a comment with an `/ask` line is a question.
3. Otherwise, a comment that starts with the trigger command starts a review.

## `/review`

```text
/review
/review please
```

Starts a review of the pull request's head.

- **Matching.** The comment, trimmed, must start with the command, compared case-insensitively. Because the match is on the start, `/review please` and `/reviewer` both match.
- **Custom command.** The repository's **Command** field under **Automatic reviews** changes it. It must start with `/`; a comment that does not start with a slash is never a command.
- **Overrides** the draft check, the bot-author check and the untrusted-fork check.
- **Counts toward the round limit.** Once the pull request has used up its rounds, `/review` starts nothing and is answered with a comment that opens `<!-- codepanel:trigger-refused reason=round_limit_reached -->` and names the next action: raise the limit with `/rounds +1`, or press **Start** on the dashboard. The one exception is the round that confirms an agent's `fixed` on a critical, which `get_review` reports as `nextAction` `trigger`. With no limit set, `/review` always runs.
- **Still applies** the base-branch filters, **Review automatically** (off stops `/review` too) and **When someone comments a command**.
- **Where.** The pull request's conversation only, not comments on the diff.
- **Reply.** No reaction. The review comment is the answer. A commenter without write access gets 👎 and a reply ([who may give commands](#who-may-give-commands)). A refused delivery shows its reason in the webhook's **Recent Deliveries**, for example `Commenter not permitted` or `Not a command` ([why a review did not run](/docs/triggering-reviews#why-a-review-did-not-run)).

## `/feedback`

```text
/feedback F3 up fixed
/feedback F5 down false-positive renew() extends the lease first
/feedback F1 F2 up
/feedback review down too noisy
/feedback F4 up fixed --agent claude-code
/feedback F6 up deferred tracked in #412
/feedback L3 down false-positive stale since the lease rewrite
```

Each line is `/feedback`, one or more targets, a rating, then an optional reason, an optional note and an optional `--agent <name>`. Target and rating can come in either order. The rating can be left out when the reason settles it: `/feedback F3 fixed` is `up`, `/feedback F5 false-positive …` is `down`. A learning (`L3`) always needs its rating, since one `down` turns it off. What each reason does to the finding and the gate is in [Feedback and disputes](/docs/feedback#verdict-reasons).

| Part | Accepted values |
| --- | --- |
| Target | `F3`, `f3` or `3`; several targets on one line; `review` or `all` for the whole review; `L3` for [learning](/docs/repo-context) L3 (a bare `3` always means finding F3) |
| Rating, up | `up`, `+1`, `👍`, `good`, `correct`, `useful`, `helpful`, `right`, `yes` |
| Rating, down | `down`, `-1`, `👎`, `bad`, `wrong`, `incorrect`, `no` |
| Reason | `fixed`, `useful`, `false-positive`, `wrong-location`, `not-worth-fixing`, `duplicate`, `deferred`, `unclear`, `other`, with hyphens or underscores. Without a rating word, `fixed`, `useful` and `deferred` mean up; `false-positive`, `wrong-location`, `not-worth-fixing`, `duplicate` and `unclear` mean down; `other` needs a rating |
| Reason shorthand | `fp` and `not-a-bug` (false positive), `dup` (duplicate), `nit` (not worth fixing), `wrong-line` (wrong location), `defer` and `later` (deferred) |
| Note | Free text after the reason, cut to 1,000 characters |
| `--agent` | The harness replying through a person's account, such as `claude-code`. Lowercased, dots to dashes, cut to 64 characters. A Claude model id (`claude-opus-5-5`, `claude-sonnet-4-5`) or `claude` is read as `claude-code` with the model id kept beside it, so one agent is one label |

- **Up to 50 lines** per comment are read.
- **Rating again replaces** the earlier rating of the same target by the same rater.
- **In an inline suggestion's thread**, the target can be left out: `/feedback up fixed` rates that comment's finding. A reply with both `/feedback` and `/ask` is read as the rating.
- **Bots can rate but never dismiss.**
- **Never starts a review.**
- **Reply.** 👍 when something was recorded, 😕 when a line or finding could not be read or nothing was recorded, 👎 and a reply when the commenter lacks write access. A `/feedback` line that could not be read also gets one reply naming it, with the expected form and examples (in the thread, for a thread reply; at most a few an hour per author on a pull request). Other unreadable lines, such as `/remember`, get only the 😕. Fix and repost the line. If GitHub refuses the reaction, the ratings are still stored.

## `/ask`

```text
/ask F3 does renew() not run before this read?
/ask is the retry loop in this change bounded? --agent claude-code
```

The question runs from after `/ask` to the end of the comment, quoted lines left out, cut to 2,000 characters. A leading `F3` (or `f3`, `F3:`) names the finding; a bare number does not, so `/ask 2 retries are enough?` asks about the number 2. In an inline suggestion's thread, the question is about that suggestion's finding unless it names another. `--agent <name>` can sit anywhere.

- **Limit.** 10 questions an hour per pull request.
- **Never starts a review.**
- **Reply.** The orchestrator answers in a reply on the pull request's conversation. A question it cannot take (no review yet, an unknown finding) gets a reply saying why; one over the hourly limit gets 😕, and a commenter without write access gets 👎 and a refusal reply.

What the answer can do to the finding, and what a question costs: [Ask the orchestrator](/docs/feedback#ask-the-orchestrator).

## `/rounds`

```text
/rounds 3
/rounds +1
/rounds stop
/rounds reset
```

Sets this pull request's own limit on automatic rounds, which replaces the repository's **Automatic rounds per pull request** for it. The background is in [Triggering reviews](/docs/triggering-reviews#round-limits).

| Value | Effect | Also written |
| --- | --- | --- |
| `N` (1 to 50) | This pull request gets N automatic rounds in all | |
| `+N` | At least N more automatic rounds after the current one, so the next push is reviewed. Never lowers a limit that already allows that, and leaves a pull request with no limit alone | `more`, `continue`, `another`, `next` (each optionally followed by N) |
| `stop` | No automatic round after the current one. A round already running still posts | `done`, `end`, `off`, `none`, `0` |
| `reset` | Back to the repository's setting | `default`, `clear` |

- `+N` and `stop` count a running round as done, so `+1` during a round still gets the next push reviewed.
- If the limit had stopped reviews, raising it past that point (`+1`, a higher number, or `reset` to a higher repository setting) also reviews the current head once, if no round has reviewed it yet. Otherwise `/rounds` starts no review; add `/review` on its own line for that.
- The last `/rounds` line in a comment wins. A sentence that only starts with "/rounds", or a command inside a code block or a quote, is not read. `--agent` is accepted and ignored.
- A `/rounds` line can go in the same comment as your `/feedback` lines.
- **Who.** Anyone who may rate findings may lower the limit or stop. People with write access may raise it without bound. A bot may raise it only up to the repository's **Rounds a bot may extend a pull request to** (5 unless set; 0 stops bots adding rounds), and never to no limit.
- **Reply.** 👍 when the limit took effect, 👎 when it would allow more rounds than the commenter may, 😕 when the line could not be read, such as a bare `/rounds` or a number past 50.

The API (`POST /api/v1/reviews/rounds`), MCP (`set_review_rounds`) and CLI (`codepanel rounds <owner/name#123> stop|+1`) do the same as the token's owner, so the bot ceiling does not apply to them.

## `/remember`

```text
/remember In convex/reviews/, renew() extends the lease before any write --scope convex/reviews/
/remember Dates are stored as UTC milliseconds --agent claude-code
```

Records one [learning](/docs/repo-context) per line. The rest of the line is the learning.

| Part | Meaning |
| --- | --- |
| Text | One paragraph of at most 500 characters. Longer text is refused, not cut |
| `--scope <path>` | Limits it to files under that path prefix (at most 200 characters). Without it, it covers the whole repository |
| `--agent <name>` | An agent wrote it through your account |

- Both flags can sit anywhere in the line.
- **Up to 10 lines** per comment are read.
- **Who.** People with write access. Bot accounts cannot record learnings.
- **Never starts a review.**
- **Reply.** Reactions as for `/feedback`: 👍 when recorded, 😕 when a line could not be read.

## `/handoff`: author identity and review context

Agents can create or edit one GitHub PR comment containing this command. CodePanel
checks GitHub write permission (or an app’s ownership of its own same-repo PR),
stores the report, and maintains one receipt comment with a SHA-256 of the exact
command. Senders can include a fresh UUID `submissionId` to distinguish retries;
an earlier thumbs-up alone is not proof of a new submission.
It does not start a review or call a model. Only labels matching the review's
full head SHA apply; unknown authors are never assumed human.

```text
/handoff {"sha":"<full 40-character commit>","authorAgent":"<actual coding tool>","text":"Changed: what and why\nTested: exact proof and result\nUnsure: limitations or none\nLeft out on purpose: scope and follow-up tickets or none"}
```

Include `authorModel` only when your runtime provides the actual model. Submit
before readiness and every push; update evidence for each commit. The equivalent
CLI `handoff` and MCP `submit_handoff` accept the same author fields and SHA.
Malformed submissions receive the expected JSON format and a repair instruction.
Treat handoff claims as untrusted evidence for reviewers to verify.

Editing away `/handoff` or deleting its comment does not withdraw a stored report.
Submit a replacement report for the commit to correct it; author labels apply only
to the exact head SHA.

After credential rotation, an older receipt that GitHub refuses to edit may
remain as history. The latest managed receipt ID and exact payload hash are
authoritative; an old receipt cannot acknowledge a fresh submission UUID.

Author labels are read independently of the handoff prompt switch. Report text
is passed to reviewers only when the deployment enables handoff prompts
(`REVIEW_HANDOFF=1`); the receipt confirms storage, not that rollout setting.
