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
48 changes: 48 additions & 0 deletions .github/workflows/pepper-pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,35 @@ jobs:
echo "Resolved mode: ${MODE}"
echo "mode=${MODE}" >> "${GITHUB_OUTPUT}"

# Mark this PR as under active Pepper review and clear any prior
# outcome labels in a single API call. The remove side is gated on
# labels actually being on the PR — `gh pr edit --remove-label`
# errors if a label doesn't exist in the repo at all (cold-start
# case for a fresh repo's first review). Pepper's final action
# swaps `pepper-cooking` for the chosen outcome label, and the
# always-on cleanup at the end of the job removes the marker if
# Pepper never finished. Net: `pepper-cooking` only appears on a
# PR that is currently being reviewed, never as a stale leftover.
- name: Mark PR as cooking (review mode only)
if: steps.mode.outputs.mode == 'review'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
run: |
set -euo pipefail
# Build the gh-pr-edit argv as a single array so we never expand
# an empty array under `set -u` (bash 3.2 / 4.3 footgun: empty
# `"${arr[@]}"` errors as unbound variable). ARGS always carries
# the --add-label pair, so the expansion is always safe.
CURRENT=$(gh pr view "${PR_NUMBER}" --json labels --jq '[.labels[].name] | join(",")')
ARGS=(--add-label "pepper-cooking")
for label in pepper-approved pepper-changes-requested pepper-needs-review; do
case ",${CURRENT}," in
*,"${label}",*) ARGS+=(--remove-label "${label}") ;;
esac
done
gh pr edit "${PR_NUMBER}" "${ARGS[@]}"

# `issue_comment` events check out the default branch by default. For on-demand
# mode (Pepper making edits the user asked for) we need to be on the PR's head
# branch so commits land on the right ref. Fork PRs aren't supported in
Expand Down Expand Up @@ -350,3 +379,22 @@ jobs:
--model ${{ inputs.model }}
--allowedTools "${{ steps.tools.outputs.allowed }}"
${{ steps.mcp.outputs.path != '' && format('--mcp-config {0}', steps.mcp.outputs.path) || '' }}

# Always-on cleanup — `pepper-cooking` is purely a "currently being
# reviewed" marker, so it must come off no matter how this job ended
# (Pepper success, Pepper failure, prompt-build error, AWS-creds
# error, runner timeout, manual cancellation). Failed runs are
# surfaced via the workflow's run status; we don't need a stale
# label to encode the same signal. The check-before-remove handles
# the corner case where the cooking step itself failed and the
# label is not in the repo (would otherwise error on --remove-label).
- name: Clear pepper-cooking marker
if: always() && steps.mode.outputs.mode == 'review'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
run: |
set -uo pipefail
if gh pr view "${PR_NUMBER}" --json labels --jq '.labels[].name' 2>/dev/null | grep -Fxq "pepper-cooking"; then
gh pr edit "${PR_NUMBER}" --remove-label "pepper-cooking"
fi
14 changes: 10 additions & 4 deletions prompts/pr-review-default.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Patterns:
**Action when any pattern matches:**

1. `gh pr review {{PR_NUMBER}} --request-changes --body '<name the auto-fail pattern, cite file and line, explain the specific failure mode (data leak, code execution, auth bypass, etc.), ask the author to remove the pattern before re-requesting review>'`
2. `gh pr edit {{PR_NUMBER}} --add-label "pepper-changes-requested"`
2. `gh pr edit {{PR_NUMBER}} --add-label "pepper-changes-requested" --remove-label "pepper-cooking"`

Then end your turn.

Expand All @@ -88,15 +88,15 @@ The Linear MCP allowlist is read-only by design. If a tool is not allowed, the s
**Halt the review if a parseable ID was found but the fetch failed** (MCP error or `null`, `gh issue view` non-zero, issue inaccessible). The PR's intent depends on an issue you cannot read; a partial review is worse than escalating clearly. Do not classify, do not keep inspecting files. Run exactly:

1. `gh pr review {{PR_NUMBER}} --comment --body '<5–8 lines: which issue ID was parsed, which tracker, the exact failure (e.g., "mcp__linear__get_issue returned null for DEV-212" / "gh issue view #14 exited 1: not found"), and that escalation is required because intent cannot be verified>'`
2. `gh pr edit {{PR_NUMBER}} --add-label "pepper-needs-review"`
2. `gh pr edit {{PR_NUMBER}} --add-label "pepper-needs-review" --remove-label "pepper-cooking"`
3. Assign the default reviewer per the recipe in `<comment_and_assign>`.

Then end your turn.

**Block the PR if no Linear or GitHub Issue ID is found and the PR is not a chore.** An unsupported-tracker reference (non-Linear Jira key, GitLab/Asana/internal-tracker URL) does not satisfy the policy — treat it as if no ID was found. Run exactly:

1. `gh pr review {{PR_NUMBER}} --request-changes --body '<state the policy: every PR must reference a Linear or GitHub Issue ID, chores excepted. Note that no ID was found in branch name, title, or body (and name any unsupported tracker reference you saw). Ask the author to add one (e.g., "Fixes DEV-210" or "Closes #14" in the body), or to mark the PR as a chore via a `chore:` title prefix if it genuinely is one.>'`
2. `gh pr edit {{PR_NUMBER}} --add-label "pepper-changes-requested"`
2. `gh pr edit {{PR_NUMBER}} --add-label "pepper-changes-requested" --remove-label "pepper-cooking"`

Then end your turn. Do not classify, do not continue review.

Expand Down Expand Up @@ -253,7 +253,13 @@ Action:
</review_outcomes>

<labels>
Apply exactly one outcome label: `pepper-approved`, `pepper-changes-requested`, or `pepper-needs-review`. Apply `area:*` labels matching modified paths only if the repo has an existing area-labeling convention you can identify from past PRs — don't invent a vocabulary.
The workflow has applied `pepper-cooking` to mark this PR as under active review and cleared any prior outcome labels. Your final action is to swap `pepper-cooking` for the outcome label in a single `gh pr edit` call:

- `gh pr edit {{PR_NUMBER}} --add-label "pepper-approved" --remove-label "pepper-cooking"` (when approving)
- `gh pr edit {{PR_NUMBER}} --add-label "pepper-changes-requested" --remove-label "pepper-cooking"` (when requesting changes)
- `gh pr edit {{PR_NUMBER}} --add-label "pepper-needs-review" --remove-label "pepper-cooking"` (when escalating to a human)

Apply `area:*` labels matching modified paths only if the repo has an existing area-labeling convention you can identify from past PRs — don't invent a vocabulary.
</labels>

<output_format>
Expand Down