From bdf7c03ff50a06c50a42befcfa164e750a5ee7cd Mon Sep 17 00:00:00 2001 From: Sergio Alexander Florez Galeano Date: Thu, 16 Jul 2026 19:53:58 +0000 Subject: [PATCH 1/4] chore(agents): upgrade DWP to 2.17.0 and add AI Diff Reviewer Flow B Re-vendor Deep Work Plan at v2.17.0 (adds the ai-diff-reviewer addon), install the AI Diff Reviewer skill v2.0.0 with a CLI-specific .review/extension.md, and wire dual-surface review: local Security Review augmentation plus CI gated on the Ready label via pr-review.yml. Co-authored-by: Cursor --- .agents/docs/COMMANDS_REFERENCE.md | 12 + .agents/docs/skills_agents_catalog.md | 15 +- .agents/skills/ai-diff-reviewer/SKILL.md | 569 +++++++ .../ai-diff-reviewer/apply-review/SKILL.md | 1347 +++++++++++++++++ .../generate-extension/SKILL.md | 349 +++++ .../generate-extension/examples.md | 185 +++ .../skills/ai-diff-reviewer/open-pr/SKILL.md | 925 +++++++++++ .agents/skills/ai-diff-reviewer/prompt.md | 120 ++ .../skills/ai-diff-reviewer/setup/SKILL.md | 463 ++++++ .../ai-diff-reviewer/setup/reference.md | 501 ++++++ .agents/skills/deepworkplan/SKILL.md | 2 +- .agents/skills/deepworkplan/addons/README.md | 9 +- .../addons/ai-diff-reviewer/SKILL.md | 324 ++++ .../addons/ai-diff-reviewer/SPEC.md | 437 ++++++ .../ai-diff-reviewer/templates/INTEGRATION.md | 323 ++++ .../deepworkplan/addons/dailybot/SKILL.md | 57 +- .../deepworkplan/addons/dailybot/SPEC.md | 43 +- .../addons/dailybot/templates/INTEGRATION.md | 22 +- .../addons/dependency-upgrade/SKILL.md | 2 +- .../addons/design-system/SKILL.md | 2 +- .../deepworkplan/addons/devcontainer/SKILL.md | 2 +- .../devcontainer/templates/Dockerfile.md | 46 +- .agents/skills/deepworkplan/author/SKILL.md | 2 +- .agents/skills/deepworkplan/create/SKILL.md | 36 +- .agents/skills/deepworkplan/execute/SKILL.md | 24 +- .agents/skills/deepworkplan/guide/GUIDE.md | 41 + .agents/skills/deepworkplan/onboard/SKILL.md | 37 +- .agents/skills/deepworkplan/refine/SKILL.md | 2 +- .agents/skills/deepworkplan/resume/SKILL.md | 2 +- .agents/skills/deepworkplan/spec/ADDONS.md | 56 +- .agents/skills/deepworkplan/status/SKILL.md | 2 +- .agents/skills/deepworkplan/verify/SKILL.md | 2 +- .github/workflows/pr-review.yml | 215 +++ .review/extension.md | 84 + AGENTS.md | 17 +- docs/PR_REVIEW_WORKFLOW.md | 21 +- skills-lock.json | 17 + 37 files changed, 6222 insertions(+), 91 deletions(-) create mode 100644 .agents/skills/ai-diff-reviewer/SKILL.md create mode 100644 .agents/skills/ai-diff-reviewer/apply-review/SKILL.md create mode 100644 .agents/skills/ai-diff-reviewer/generate-extension/SKILL.md create mode 100644 .agents/skills/ai-diff-reviewer/generate-extension/examples.md create mode 100644 .agents/skills/ai-diff-reviewer/open-pr/SKILL.md create mode 100644 .agents/skills/ai-diff-reviewer/prompt.md create mode 100644 .agents/skills/ai-diff-reviewer/setup/SKILL.md create mode 100644 .agents/skills/ai-diff-reviewer/setup/reference.md create mode 100644 .agents/skills/deepworkplan/addons/ai-diff-reviewer/SKILL.md create mode 100644 .agents/skills/deepworkplan/addons/ai-diff-reviewer/SPEC.md create mode 100644 .agents/skills/deepworkplan/addons/ai-diff-reviewer/templates/INTEGRATION.md create mode 100644 .github/workflows/pr-review.yml create mode 100644 .review/extension.md create mode 100644 skills-lock.json diff --git a/.agents/docs/COMMANDS_REFERENCE.md b/.agents/docs/COMMANDS_REFERENCE.md index 5d92829..aa57bce 100644 --- a/.agents/docs/COMMANDS_REFERENCE.md +++ b/.agents/docs/COMMANDS_REFERENCE.md @@ -23,6 +23,18 @@ The full plan-execute-verify loop, delegating to the vendored `deepworkplan` ski | `/agent-create` | `../skills/deepworkplan/author/SKILL.md` | Create a new agent persona in `.agents/agents/.md`. | "Create an agent persona for the CI investigator role" | | `/design-system` | `../skills/deepworkplan/addons/design-system/SKILL.md` | Refresh `docs/DESIGN.md` from the real design source (`display.py` + `DISPLAY_OUTPUT_BEST_PRACTICES.md`) via the DWP design-system addon. | "Re-sync DESIGN.md after refactoring `display.py`" | +## AI Diff Reviewer (Flow B) + +Vendored skill at [`../skills/ai-diff-reviewer/`](../skills/ai-diff-reviewer/) (**v2.0.0**). CI gate: apply the **`Ready`** label on a PR to `main` (see [`.github/workflows/pr-review.yml`](../../.github/workflows/pr-review.yml); requires `CURSOR_API_KEY`). Extension: [`.review/extension.md`](../../.review/extension.md). + +| Command / phrase | Routes to | What it does | Example trigger | +|------------------|-----------|--------------|-----------------| +| "Review my current branch" | `../skills/ai-diff-reviewer/SKILL.md` | Local review (verdict + findings); used by DWP Security Review when skill + extension are present | "Review my current branch" | +| `/ai-diff-reviewer-generate-extension` | `../skills/ai-diff-reviewer/generate-extension/SKILL.md` | Regenerate `.review/extension.md` from repo evidence | "Customize the review for this repo" | +| `/ai-diff-reviewer-setup` | `../skills/ai-diff-reviewer/setup/SKILL.md` | Re-run the CI workflow wizard | "Set up AI Diff Reviewer for this repo" | +| `/ai-diff-reviewer-open-pr` | `../skills/ai-diff-reviewer/open-pr/SKILL.md` | Draft PR title/body from the branch diff | "Open a PR for this branch" | +| `/ai-diff-reviewer-apply-review` | `../skills/ai-diff-reviewer/apply-review/SKILL.md` | Walk CI findings per-finding (apply / defer / skip); never commits | "Apply the CI review findings" | + Every plan ends with three mandatory final tasks (per the DWP spec): a **Security Review** of the plan's own changes (a critical finding blocks completion), a **Skills & Agents Discovery** pass, and an **Executive Report**. State persists in [`.dwp/`](../../.dwp/) which is gitignored — only the placeholders `.dwp/plans/.gitkeep` and `.dwp/drafts/.gitkeep` are tracked. diff --git a/.agents/docs/skills_agents_catalog.md b/.agents/docs/skills_agents_catalog.md index 09b9978..1ac4dc3 100644 --- a/.agents/docs/skills_agents_catalog.md +++ b/.agents/docs/skills_agents_catalog.md @@ -39,7 +39,7 @@ The full pack lives under [`.agents/skills/dailybot/`](../skills/dailybot/) (rou ### Deep Work Plan skill pack (vendored from [`DailybotHQ/deepworkplan-skill`](https://github.com/DailybotHQ/deepworkplan-skill)) -The full pack lives under [`.agents/skills/deepworkplan/`](../skills/deepworkplan/) (router + 9 sub-skills + addons). Vendored at **v2.16.0**. The router auto-routes by intent — read [`skills/deepworkplan/SKILL.md`](../skills/deepworkplan/SKILL.md) and let it pick the right sub-skill. Each sub-skill is independently invocable, and each has a short `dwp-*` alias in [`.agents/commands/`](../commands/) for ergonomic typing. +The full pack lives under [`.agents/skills/deepworkplan/`](../skills/deepworkplan/) (router + 8 sub-skills + addons). Vendored at **v2.17.0**. The router auto-routes by intent — read [`skills/deepworkplan/SKILL.md`](../skills/deepworkplan/SKILL.md) and let it pick the right sub-skill. Each sub-skill is independently invocable, and each has a short `dwp-*` alias in [`.agents/commands/`](../commands/) for ergonomic typing. | Slug | Procedure | Use when | |------|-----------|----------| @@ -53,6 +53,19 @@ The full pack lives under [`.agents/skills/deepworkplan/`](../skills/deepworkpla | `skill-create` | [`skills/deepworkplan/author/SKILL.md`](../skills/deepworkplan/author/SKILL.md) | Creating a new skill in `.agents/skills//` | | `agent-create` | [`skills/deepworkplan/author/SKILL.md`](../skills/deepworkplan/author/SKILL.md) | Creating a new agent persona in `.agents/agents/.md` | | `design-system` | [`skills/deepworkplan/addons/design-system/SKILL.md`](../skills/deepworkplan/addons/design-system/SKILL.md) | Refreshing [`docs/DESIGN.md`](../../docs/DESIGN.md) from the real design source (`display.py` + `DISPLAY_OUTPUT_BEST_PRACTICES.md`) — the `cli-output` profile of the DWP design-system addon | +| `ai-diff-reviewer` (addon) | [`skills/deepworkplan/addons/ai-diff-reviewer/SKILL.md`](../skills/deepworkplan/addons/ai-diff-reviewer/SKILL.md) | Opt-in DWP addon — wires Security Review to the vendored AI Diff Reviewer (Flow B: local + CI). See also the installed skill below. | + +### AI Diff Reviewer (vendored from [`DailybotHQ/ai-diff-reviewer`](https://github.com/DailybotHQ/ai-diff-reviewer)) + +Vendored at **v2.0.0** under [`.agents/skills/ai-diff-reviewer/`](../skills/ai-diff-reviewer/). Flow B is enabled: local Security Review augmentation + CI gate via [`.github/workflows/pr-review.yml`](../../.github/workflows/pr-review.yml) (trigger label **`Ready`**; secret `CURSOR_API_KEY`; extension [`.review/extension.md`](../../.review/extension.md)). + +| Slug | Procedure | Use when | +|------|-----------|----------| +| `ai-diff-reviewer` | [`skills/ai-diff-reviewer/SKILL.md`](../skills/ai-diff-reviewer/SKILL.md) | Running a local review on the current branch ("Review my current branch") | +| `ai-diff-reviewer-generate-extension` | [`skills/ai-diff-reviewer/generate-extension/SKILL.md`](../skills/ai-diff-reviewer/generate-extension/SKILL.md) | Regenerating [`.review/extension.md`](../../.review/extension.md) from repo evidence | +| `ai-diff-reviewer-setup` | [`skills/ai-diff-reviewer/setup/SKILL.md`](../skills/ai-diff-reviewer/setup/SKILL.md) | Re-running the CI workflow wizard | +| `ai-diff-reviewer-open-pr` | [`skills/ai-diff-reviewer/open-pr/SKILL.md`](../skills/ai-diff-reviewer/open-pr/SKILL.md) | Drafting a PR title/body from the branch diff | +| `ai-diff-reviewer-apply-review` | [`skills/ai-diff-reviewer/apply-review/SKILL.md`](../skills/ai-diff-reviewer/apply-review/SKILL.md) | Walking CI-posted findings per-finding (apply / defer / skip) | Plans and drafts persist under [`.dwp/`](../../.dwp/) which is gitignored — only the `plans/.gitkeep` and `drafts/.gitkeep` placeholders are tracked. Full command catalog in [`COMMANDS_REFERENCE.md`](COMMANDS_REFERENCE.md), and the rationale in [`../../AGENTS.md`](../../AGENTS.md) "Working with Deep Work Plans". diff --git a/.agents/skills/ai-diff-reviewer/SKILL.md b/.agents/skills/ai-diff-reviewer/SKILL.md new file mode 100644 index 0000000..d66c790 --- /dev/null +++ b/.agents/skills/ai-diff-reviewer/SKILL.md @@ -0,0 +1,569 @@ +--- +name: ai-diff-reviewer +description: Local & CI companion to the AI Diff Reviewer GitHub Action (DailybotHQ/ai-diff-reviewer on GitHub, "AI Diff Reviewer" on the Marketplace). Router for five capabilities — (1) run a local review of the current branch's diff using the SAME methodology as the CI action, (2) generate a repo-tailored `.review/extension.md` via the `generate-extension` sub-skill, (3) install and configure the GitHub Action itself in a repo that doesn't have it yet via the `setup` sub-skill (also doubles as the reference manual for every `action.yml` input), (4) author a well-documented pull request from the current branch's diff (Conventional-Commits title inference, structured body, PR-template merge, `gh pr create`/`edit`) via the `open-pr` sub-skill, (5) read the AI review the CI Action posted back on the current branch's open PR, present findings in the same format as the local review, and optionally walk the developer through each finding to apply/defer/skip (multi-leg-aware, per-finding consent, no commits/pushes) via the `apply-review` sub-skill. Auto-detects `.review/extension.md` (or `.github/ai-diff-reviewer/extension.md` as fallback) and layers it on top of the shipped default prompt for full local↔CI parity. Use when the developer wants a local pre-flight review before pushing, asks "run a code review on my current changes", wants to customize the reviewer to this repo, asks "how do I set up ai diff reviewer?", asks a reference-style question about any of the action's inputs, asks to "open a PR", "create the pull request", or "write the PR body" for the current branch, or asks "what did the CI review say?", "apply the AI review's fixes", or "walk me through the review findings". +version: "2.0.0" +documentation_url: https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/skills/ai-diff-reviewer/SKILL.md +user-invocable: true +metadata: {"openclaw":{"emoji":"🔍","homepage":"https://github.com/DailybotHQ/ai-diff-reviewer","requires":{"anyBins":["git"]}}} +allowed-tools: Bash, Read, Grep, Glob +--- + +# AI Diff Reviewer — Local & CI Companion Skill + +The [**AI Diff Reviewer**](https://github.com/marketplace/actions/ai-diff-reviewer) +is a GitHub Action that runs an LLM review on every pull request in +CI. **This skill is its local counterpart** — the same reviewer, +driven by your coding agent (Cursor, Claude Code, Codex, Gemini, +Copilot, Cline, Windsurf), on the branch you're editing right now. It +also installs and configures the CI Action itself when your repo +doesn't have it yet. + +**Two audiences, same skill.** + +- If your repo **already runs the Action in CI** → use the skill + locally to catch what CI would catch, seconds before pushing. When + CI is wired to the same extension file + (`prompt-extension-file: .review/extension.md`), local and CI + reviews match — same base prompt, same overrides. See the "Parity + guarantee (Flow B)" section below for the wiring details. +- If your repo **doesn't have the Action yet** (or you don't want it) + → the skill still gives you the full review locally, AND — when + you're ready — helps you install the Action in CI with sensible + defaults for strictness, triggers, and external-contributor policy. + +**Five coordinated capabilities**, routed by intent: + +| # | Capability | Sub-skill | Surface | +|---|---|---|---| +| 1 | Run the review on the current branch | *(default flow — this file)* | 🖥️ Local | +| 2 | Author repo-specific overrides (`.review/extension.md`) | [`generate-extension`](generate-extension/SKILL.md) | 🖥️ Local **+** ☁️ CI (shared file) | +| 3 | Install the GitHub Action + write `pr-review.yml` | [`setup`](setup/SKILL.md) | ☁️ CI | +| 4 | Draft the PR title + body from the diff | [`open-pr`](open-pr/SKILL.md) | 🖥️ Local → GitHub | +| 5 | Read the CI review on the PR + walk through findings to apply/defer/skip | [`apply-review`](apply-review/SKILL.md) | ☁️ CI → 🖥️ Local | + +Sub-skill 3 (`setup`) also doubles as the **reference manual** for +every `action.yml` input via [`setup/reference.md`](setup/reference.md) +— any agent can answer *"what does `strictness` do?"* without opening +the action source. + +**Version parity.** The [`prompt.md`](prompt.md) in this skill is +byte-identical to the one the Action ships in the same tagged release +(enforced by CI's `Skills — prompt-sync invariant` job). Pinning +`@v2.0.0` on both surfaces guarantees the same methodology and severity +model (CI may additionally dedupe on round 2+ via Iteration-Aware +Review; local reviews stay a full pass). + +Source: · License: MIT + +--- + +## Two supported flows: local-only or dual-surface + +The five sub-skills are **independent**. There is no ordering +requirement, and installing the CI GitHub Action is **NOT** a +prerequisite for using this skill locally. Every consumer repo falls +into one of two flows — pick the one that matches the repo's use case: + +| Flow | Use when | Sub-skills to run | Sub-skills to skip | +|---|---|---|---| +| **A. Local-only** | You want your coding agent to run the same review methodology on the branch you're working on right now, but you do NOT want the review to fire in CI on every PR. Common for personal repos, experimental repos, repos where the team hasn't opted into automated PR review yet. | **Optional but recommended:** `generate-extension` (once, to tailor `.review/extension.md`). Then the parent `run a local review` flow on every branch — works with or without an extension file (falls back to the shipped base prompt if Step 2.5 is declined). Optionally `open-pr` at the end. | `setup` — do NOT run it. It writes `.github/workflows/pr-review.yml`, which activates the CI Action. `apply-review` — nothing to apply (no CI review posts back to the PR without the Action installed). | +| **B. Dual-surface** | You want both: pre-flight local review before pushing AND a full CI review on every PR, sharing the same methodology and severity model on both surfaces (CI may additionally dedup on round 2+ via IAR — see below). Recommended for team repos and anything production-facing. | `setup` (once, installs the CI Action + accepts the Step 5 handoff to `generate-extension`), then the parent `run a local review` flow on every branch. `open-pr` when the PR is ready. After push, once CI has posted its review, `apply-review` closes the loop (read the CI findings, walk through them, apply fixes). | Nothing — all five capabilities are used across the lifecycle. | + +**Parity guarantee (Flow B).** When `setup` writes the workflow with +`prompt-extension-file: .review/extension.md` wired in (default when +you accept the Step 5 handoff to `generate-extension`), the CI Action +reads the same file your local agent uses. Same base prompt + same +extension file = same review methodology and severity model, locally +and in CI. CI may still post a *shorter* finding set on round 2+ of a +generation because Iteration-Aware Review dedups there (local reviews +never do — see below). If the Step 5 handoff is declined, `setup` +omits `prompt-extension-file` and you get base-prompt parity only — +you can add the input manually later, or re-run `setup` and accept +the handoff. + +**CI-only surfaces (not mirrored locally).** Two Action capabilities +run only in GitHub Actions, not in this skill's local review flow: + +1. **Iteration-Aware Review (IAR)** — content-anchored dedup across + rounds, four convergence policies (default + `first-pass-exhaustive`), escape label (`full-review-please`), + and user-forced reset (remove `applied-label` then re-trigger). + A local review is always a **full pass** against the current + diff — it may surface findings CI has already deduped on + round 2+ of the same generation. Spec: + [`docs/ITERATION_AWARENESS.md`](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/ITERATION_AWARENESS.md). + Tuning example: + [`examples/iteration-aware.yml`](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/examples/iteration-aware.yml). +2. **`skip-review-label` emergency bypass** — when the configured + label is on the PR, CI short-circuits to success with no LLM + call. Hotfixes / rollbacks only; protect the label with a + ruleset. Spec: + [`docs/TRIGGER_MODES.md` § Emergency-bypass](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/TRIGGER_MODES.md). + Example: + [`examples/skip-review-label.yml`](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/examples/skip-review-label.yml). + +The full input reference (including every IAR knob and +`skip-review-label`) lives in +[`setup/reference.md`](setup/reference.md). + +**Signalling the flow to your agent.** If the ambiguous request "set +up the reviewer" could mean either flow, the agent will ask. To skip +that question, be explicit the first time in each repo: + +- Flow A: *"Set up ai-diff-reviewer for local-only use — do NOT install the GitHub Action."* +- Flow B: *"Full ai-diff-reviewer setup — install the Action workflow AND generate the extension file."* + +Every subsequent request in the repo (`"review my branch"`, +`"open the PR"`, etc.) works identically across both flows — the flow +distinction only matters at first-time setup. + +--- + +## Install + +```bash +# Latest v2.x +npx skills add DailybotHQ/ai-diff-reviewer --skill ai-diff-reviewer + +# Or pin to a specific tag for reproducibility +npx skills add DailybotHQ/ai-diff-reviewer@v2.0.0 --skill ai-diff-reviewer +``` + +This vendors the skill into `.agents/skills/ai-diff-reviewer/` in the +consumer repo and records source + content hash in `skills-lock.json` so +any teammate can restore identical bytes with `npx skills experimental_install`. +Bump to the latest with `npx skills update ai-diff-reviewer`. + +> **Note on the git repo slug.** The repo path stays at +> `DailybotHQ/ai-diff-reviewer` (historical — published tags from v1.0.0 +> onward, current major `@v2`). The `--skill ai-diff-reviewer` flag +> matches the Marketplace listing name; both refer to the same product. + +--- + +## Activation + +**Default flow (run a review) — triggers:** + +- "Review my current branch" +- "Run a code review on my changes" +- "Do a pre-flight review before I push" +- "Code review the diff against `main`" +- "What would CI say about my current commits?" + +**Generate-extension flow — triggers:** + +- "Generate a `.review/extension.md` for this repo" +- "Customize the code review for our project" +- "Help me write repo-specific review rules" +- "Tailor the reviewer to our stack" + +**Setup flow (install the GitHub Action) — triggers:** + +- "Set up AI Diff Reviewer for this repo" +- "Configure the reviewer action" +- "Install the AI Diff Reviewer GitHub Action" +- "Help me create the pr-review workflow" +- "How do I add AI Diff Reviewer to this project?" +- Also fires as the answer to reference-style questions about the + action — *"what does `strictness` do?"*, *"how do I use + `label-gate`?"* — via [`setup/reference.md`](setup/reference.md). + +**Open-PR flow (author the pull request) — triggers:** + +- "Open the PR", "create a pull request for this branch" +- "Draft the PR title and description" +- "Write the PR body" +- "Update the PR description", "rewrite the PR body in the proper format" +- "Make a draft PR" (adds `--draft`) + +**Apply-review flow (read + apply the CI review on the PR) — triggers:** + +- "What did the CI review say?" +- "Read the review on this PR", "show me the review findings" +- "Apply the AI review's fixes", "walk me through the findings" +- "Help me address the critical findings", "critical only" +- "Which findings blocked the merge?" +- "The bot posted a review — help me address it" + +If the trigger is ambiguous (e.g. developer says "help me with the +review" on a repo that has no `.review/extension.md` yet, or says +"handle the PR" on a repo where a PR both needs a review AND has a +one-line body), ask ONE clarifying question before routing. Heuristics +that help disambiguate: + +- Repo already has `.github/workflows/pr-review.yml` (or similar) → + probably NOT the setup flow. +- Repo has no `.github/workflows/pr-review.yml` (or similarly-named + AI Diff Reviewer workflow — grep the `.github/workflows/` tree for + `DailybotHQ/ai-diff-reviewer` or `ai-diff-reviewer` action refs) + AND no `.review/extension.md`, and the developer just installed the + skill → **ask** which of the two flows they want ("Flow A + local-only" vs "Flow B dual-surface"; see the "Two supported flows" + section above). Do NOT default to `setup` — Flow A (local-only) is + a first-class use case, and running `setup` unrequested would + write `.github/workflows/pr-review.yml` and force the CI Action + into a repo where the developer may not want it. The presence of + unrelated workflows (CI tests, deploy pipelines, dependency bots) + is NOT evidence of Flow B; only an ai-diff-reviewer workflow is. +- Developer just finished a session of code changes and hasn't asked for + a review yet → default review flow (local). +- The word *"review"* is ambiguous when a PR already exists for the + current branch AND has live `` comments + from a recent CI run. In that case, *"read the review"* usually means + the CI review on the PR (apply-review flow), not a fresh local one. + Ask once: *"Read the CI review that just landed on PR #N, or run a + new local review on your working tree?"* +- Developer just accepted a local review's findings and applied fixes + → probably the open-pr flow (natural next step, first PR of the + session). +- Developer just applied fixes from the CI review → probably `open-pr` + in edit mode (to refresh the PR body if the scope changed), then + `git commit + git push` (they'll do it themselves). + +Some harnesses (Claude Code, Cursor) also expose these as slash +commands (`/ai-diff-reviewer`, `/ai-diff-reviewer-generate-extension`, +`/ai-diff-reviewer-setup`, `/ai-diff-reviewer-open-pr`, +`/ai-diff-reviewer-apply-review`); check the harness's +skill-invocation docs. + +--- + +## Default flow: how the local review works + +Everything below (Steps 0 through 5) describes **only capability #1** +from the table above — running the review on the current branch. The +four sibling sub-skills have their own procedures in their respective +`SKILL.md` files: + +- [`generate-extension/SKILL.md`](generate-extension/SKILL.md) — author `.review/extension.md` +- [`setup/SKILL.md`](setup/SKILL.md) — install the GitHub Action +- [`open-pr/SKILL.md`](open-pr/SKILL.md) — author the PR title + body +- [`apply-review/SKILL.md`](apply-review/SKILL.md) — read + apply the CI review posted on the PR + +--- + +## Step 0 — Trust boundary + +This skill is **near read-only** on the working tree and does **not** +call any remote API. It: + +- Reads files from the current git checkout (`Read`, `Grep`, `Glob`). +- Runs `git diff` and `git log` locally (no push, no fetch). +- Composes the review prompt in the agent's context and produces the + review as terminal output. + +The **only** writes it may perform, and only with explicit developer +consent in Step 2.5: + +- Create `.review/` and write `.review/extension.md` — if the developer + answers **yes** to the bootstrap offer (invokes the + `generate-extension` sub-skill). +- Create `.review/` and touch `.review/.skip-bootstrap` (0 bytes) — if + the developer answers **never** to the bootstrap offer. + +It does **not**: + +- Post inline comments to GitHub (that's the CI action's job). +- Modify any source file, workflow, or config file in the working tree. +- Call the LLM provider directly — it uses the coding agent that's + already running you. +- Send any data off your machine. + +If the coding agent has broader powers (e.g. can write files or run +arbitrary bash), those come from the harness, not this skill. + +--- + +## Step 1 — Detect context + +Run these to establish the review's inputs. Emit the JSON to your working +context; do not print it to the user unless they ask. + +```bash +# Base branch: prefer the tracked upstream's short name, fall back to `main`. +BASE=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null | sed 's|.*/||') +BASE="${BASE:-main}" + +# Current branch + head SHA +HEAD_BRANCH=$(git branch --show-current) +HEAD_SHA=$(git rev-parse --short HEAD) + +# The three artifacts the review needs +git diff --stat "origin/${BASE}...HEAD" # summary of what changed +git diff "origin/${BASE}...HEAD" # the actual diff +git log "origin/${BASE}..HEAD" --oneline # the commit trail +``` + +If the diff is empty, tell the developer "no changes vs `` — nothing +to review" and stop. If `origin/${BASE}` doesn't exist (fresh clone, +missing remote), fall back to `git merge-base main HEAD` and diff against +that; note the fallback in the summary. + +--- + +## Step 2 — Compose the prompt (base + extension) + +The review methodology lives in [`prompt.md`](prompt.md) — the exact same +prompt the CI action ships. Read it into your context as the base. + +Then check for a **repo-specific extension** in this order of precedence +(first match wins; the rest are ignored): + +1. `.review/extension.md` (recommended convention — runtime-agnostic) +2. `.github/ai-diff-reviewer/extension.md` (fallback for teams that + prefer `.github/` sibling to workflow files; + `.github/ai-pr-reviewer/extension.md` also accepted for back-compat + with the pre-v1.5 skill name) + +**If a match is found** — read it, append its content to the base prompt +verbatim, and skip to Step 3. + +**If no match is found**: + +- If `.review/.skip-bootstrap` exists → the developer opted out of the + bootstrap offer previously. Use the base prompt alone (no announcement), + skip to Step 3. +- Otherwise → go to **Step 2.5** (first-time bootstrap offer). + +Announce the composed configuration in one line, e.g. +`Reviewing feat/foo (a1b2c3d) against main. Base prompt + .review/extension.md.` + +The final composed prompt is what governs the review — the severity +definitions, the "what NOT to comment on" rules, the output shape. + +--- + +## Step 2.5 — Offer to bootstrap the extension (first-time only) + +This step fires only when Step 2 found no extension file **and** no +`.review/.skip-bootstrap` marker exists. It's the one moment the skill +educates the developer about the extension convention. After the answer +is recorded (either as generated content or an opt-out marker), the +skill never asks again in this repo unless the developer removes the +marker. + +Ask the developer ONE question: + +> **No `.review/extension.md` found for this repo.** +> +> I can run the review right now with the shipped default prompt — that +> catches ~90% of general-purpose issues (SQL injection, unhandled +> promises, missing input validation, obvious perf regressions, etc.). +> +> But it will miss the **repo-specific** stuff: your money-handling +> conventions, the modules where `console.log` is banned, the RFC-014 +> pattern, the always-critical SQL patterns tied to YOUR schema. That's +> what a `.review/extension.md` gives you — file-anchored severity +> overrides written against THIS codebase. +> +> Want to bootstrap one now? (~30 seconds of Discovery + a ~100-line +> file of concrete overrides.) +> +> - **yes** — I'll route to the `generate-extension` sub-skill, then +> come back and run the review with the fresh extension layered on. +> - **no** — run the review this once with the base prompt only. I'll +> ask again the next time the skill activates. +> - **never** — never ask again in this repo. I'll create +> `.review/.skip-bootstrap` (a tracked 0-byte marker). Commit it so +> your whole team inherits the same preference. To re-enable the +> offer later, delete the marker. + +Handle the response: + +- **yes** → invoke the `generate-extension` sub-skill in extension mode + (see [`generate-extension/SKILL.md`](generate-extension/SKILL.md)). + When the sub-skill finishes writing `.review/extension.md`, re-enter + Step 2 from the top — the freshly-written file will be picked up and + layered onto the base prompt. Do NOT skip the sub-skill's Discovery + phase (12+ tool calls); that's where the value is. +- **no** → skip to Step 3 with the base prompt alone. Do NOT persist + anything. The offer fires again next time. +- **never** → run: + ```bash + mkdir -p .review + touch .review/.skip-bootstrap + ``` + Then skip to Step 3 with the base prompt alone. Suggest the developer + commit the marker: `git add .review/.skip-bootstrap && git commit -m + "chore(review): opt out of AI Diff Reviewer bootstrap offer"`. + +If the developer's response is ambiguous, default to **no** (the +minimally-disruptive choice) — do not silently opt them out. + +--- + +## Step 3 — Execute the review + +Apply the composed prompt to the diff **using the coding agent's own +tools** (Read, Grep, Glob): + +- The prompt tells you to `read_file` / `grep` / `glob` — translate those + to whatever primitives the harness gives you. Read the changed files in + full; the diff alone is rarely enough context. +- The prompt tells you to `post_inline_comment(path, line, body, severity)` + — since you are running locally without GitHub write access, instead + **collect** each finding into an internal list of + `{path, line, severity, body}` records and print them as a table in + Step 4. +- The prompt tells you to `submit_review(summary)` **exactly once** — this + is your cue that the review is complete. When you reach this point, + print the final summary and stop. + +**Cost discipline:** cap yourself at the same number of turns the CI +action does (~25) and the same inline-comment cap (default 20). Don't +grep the whole world; grep the files you're commenting on plus their +imports. + +--- + +## Step 4 — Print the review + +Emit the review to the terminal in the **same format** the CI bot would +post on a PR — this is the parity contract: + +```markdown +## Verdict + + +## Findings + +| # | Severity | File | Summary | +|---|----------|------|---------| +| 1 | 🚨 critical | `src/auth.ts:55` | SQL injection in raw-string login query | +| 2 | ⚠️ warning | `src/cache.ts:120` | Unbounded cache key cardinality | +| 3 | ℹ️ info | `tests/utils.ts:12` | Helper could be reused from existing fixture | + +### 1. `src/auth.ts:55` — 🚨 critical + + +### 2. `src/cache.ts:120` — ⚠️ warning +<...> + +### 3. `tests/utils.ts:12` — ℹ️ info +<...> + +## Notes (no inline anchor) +- + +**Recommendation:** approve / request-changes / comment-only +``` + +Reproducing this exact shape (verdict → findings table → per-finding +body → notes → recommendation) is what lets a developer trust the +same methodology and severity model on both surfaces. On CI round 2+ +of a generation, Iteration-Aware Review may additionally dedupe +findings that a local full pass would still list — that difference is +expected, not a parity bug (see **CI-only surfaces** above). + +**Optional next-step hint.** When the review is clean (no 🚨 critical or +⚠️ warning findings) OR when the developer explicitly signals they're +ready to push, close the output with a one-line pointer to the sibling +sub-skill: + +```text +Next step: want me to open the PR? — I can draft the title + body from +this same diff (see the `open-pr` sub-skill). Or run `gh pr create` +yourself. +``` + +Do not print this hint when the review found blocking issues — fix +first, ship second. + +--- + +## Step 5 — Extension file convention (for consumers) + +Three ways to end up with an extension file, all valid: + +1. **Automated bootstrap** — say "review my branch" on a fresh repo, + answer **yes** at the Step 2.5 prompt. The `generate-extension` + sub-skill runs its 12+ tool-call Discovery and writes + `.review/extension.md` for you. Simplest path — recommended for the + first setup. +2. **Explicit sub-skill invocation** — say "generate a + `.review/extension.md` for this repo" (or one of the other triggers + listed in Activation). Same result as (1) but skips the bootstrap + prompt. Use this to regenerate or refine an existing file. +3. **Hand-written** — create the file yourself, using the schema and + examples below. Best when you know exactly what overrides you want + and don't need the Discovery walkthrough. + +Whichever path you take, the layout options are the same: + +**Option A — `.review/extension.md`** (recommended): + +``` +my-repo/ +├── .review/ +│ └── extension.md ← auto-detected by this skill +└── .github/ + └── workflows/ + └── pr-review.yml ← CI workflow uses the same file +``` + +**Option B — `.github/ai-diff-reviewer/extension.md`** (fallback if you +prefer keeping the file next to your workflows). The pre-v1.5 path +`.github/ai-pr-reviewer/extension.md` is still recognised for +back-compat. + +The **same file** should be referenced from your CI workflow's +`prompt-extension-file:` input so local and CI stay in perfect sync: + +```yaml +# .github/workflows/pr-review.yml +- uses: DailybotHQ/ai-diff-reviewer@v2 + with: + api-key: ${{ secrets.ANTHROPIC_API_KEY }} + github-token: ${{ secrets.GITHUB_TOKEN }} + prompt-extension-file: .review/extension.md # same file the skill auto-detects +``` + +Example `.review/extension.md`: + +```markdown +## Severity overrides for our codebase + +- Any `SELECT * FROM users` in a request path is **critical** (PII exposure). +- Missing `AbortController` on a `fetch()` in `apps/frontend/` is **warning** + (React 18 pattern we standardized on in RFC-014). + +## Don't comment on + +- Formatting in `apps/legacy/*` — that module is scheduled for a rewrite. +- Missing tests in `experiments/` — that folder is intentionally exploratory. +``` + +Full authoring guide (structure, tips, worked examples): +[`docs/PROMPTS.md`](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/PROMPTS.md). + +--- + +## Notes + +- **The skill runs your local agent — it doesn't invoke a separate + LLM.** If your harness is Cursor and you're on `auto`, the review costs + are billed to your Cursor Pro subscription. If your harness is Claude + Code with an API key, it's Anthropic tokens. Either way the local + review is a "free bonus" if you were going to use the agent anyway. +- **When paired with the CI Action (Flow B), this skill does not + replace it.** The CI Action still runs on every PR and posts the + authoritative review (inline comments, severity gating, + merge-blocking); the skill is for the "before pushing" moment. In + Flow A (local-only), the local skill IS the entire reviewer — no CI + leg, no post-push authority; findings live only in your terminal + and you decide what to act on before opening the PR. +- **Extension parity is guaranteed on your side, not enforced by + tooling.** If your `.review/extension.md` says something different + from what your CI workflow's `prompt-extension-file:` points at, you + get drift. Keep them at the same path. +- **Opt-out marker (`.review/.skip-bootstrap`).** A 0-byte tracked + marker file that tells the skill "don't offer to bootstrap the + extension anymore in this repo — the team knows the option exists + and chose to stick with the base prompt." Created by answering + **never** at the Step 2.5 prompt. Delete the file to re-enable the + offer. Committing it is the intended behaviour so the whole team + inherits the same UX. +- **Bugs, feature requests, and extension patterns to add to the + starter templates:** + [`github.com/DailybotHQ/ai-diff-reviewer/issues`](https://github.com/DailybotHQ/ai-diff-reviewer/issues). diff --git a/.agents/skills/ai-diff-reviewer/apply-review/SKILL.md b/.agents/skills/ai-diff-reviewer/apply-review/SKILL.md new file mode 100644 index 0000000..2d7db89 --- /dev/null +++ b/.agents/skills/ai-diff-reviewer/apply-review/SKILL.md @@ -0,0 +1,1347 @@ +--- +name: ai-diff-reviewer-apply-review +description: Read the most recent AI Diff Reviewer review from the current branch's open PR, present the findings in the same format as the parent skill's local review flow (verdict → findings table → per-finding body → recommendation), and — with explicit consent — walk the developer through each finding to apply, defer, or skip. Multi-provider aware — when the repo runs a matrix of legs (anthropic, cursor, codex, claude-code), attributes each finding to its self-reviewed provider label and surfaces cross-leg consensus. Anchors on the latest ai-pr-reviewer-marker tracking comment and filters minimized (collapsed / outdated) comments per the repo's documented PR-review workflow. Read-only by default; edits to source files require an explicit yes per finding, never commits, never pushes. Use when the developer says "what did the CI review say?", "read the review on this PR", "apply the AI review's fixes", "walk me through the findings", "which findings blocked the merge?", "show me only the critical findings", or "the bot posted a review — help me address it". +version: "2.0.0" +documentation_url: https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/skills/ai-diff-reviewer/apply-review/SKILL.md +user-invocable: true +metadata: {"openclaw":{"emoji":"🔎","homepage":"https://github.com/DailybotHQ/ai-diff-reviewer","requires":{"anyBins":["git","gh"]}}} +allowed-tools: Bash, Read, Grep, Glob, Edit +--- + +# AI Diff Reviewer — Apply Review (sub-skill) + +Companion to the [`ai-diff-reviewer`](../SKILL.md) skill. Where the +parent **runs** the review locally and [`open-pr`](../open-pr/SKILL.md) +**writes** the pull request, this sub-skill closes the loop: it +**reads** the review the CI Action posted back on the PR, presents +the findings in the same format the local review uses, and — with +explicit consent — walks the developer through each finding to +apply, defer, or skip. + +The design philosophy mirrors the family's: + +- **Parity of shape.** The output uses the same + `verdict → findings table → per-finding body → notes → recommendation` + structure the parent skill emits. A developer who has seen one of + the two knows how to read the other. When the CI leg found *"SQL + injection in `src/auth.ts:55`"*, the summary looks identical whether + it was your local agent or CI that surfaced it. +- **Read-only by default.** Fetching + presenting the review never + writes anything. Only when the developer explicitly asks to *"walk + through"* or *"apply the fixes"* does the sub-skill open source + files, and each individual apply still requires a yes. +- **Multi-provider aware.** This repo (and any consumer that opts + into the 4-leg matrix) posts up to four independent reviews per PR, + distinguished by `self-reviewed:` labels. The sub-skill + reads all live legs, attributes each finding to its leg, and + surfaces cross-leg consensus (*"agreed by 3/3 legs → strong signal; + called by 1/3 → could be leg-specific"*). +- **Never commits, never pushes.** Applied fixes stay unstaged in the + working tree. Commit + push is the developer's judgment call, + matching [`open-pr`](../open-pr/SKILL.md)'s trust boundary. + +The single source of truth for the workflow this sub-skill implements +is [`docs/PR_REVIEW_WORKFLOW.md`](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/PR_REVIEW_WORKFLOW.md). +This sub-skill is that doc, executable. + +--- + +## When it fires + +**Read + present the review (default flow) — triggers:** + +- "What did the CI review say?" +- "Read the review on this PR" +- "Show me the review findings" +- "Did the bot approve or request changes?" +- "Which findings blocked the merge?" +- "The AI review just landed — summarize it" + +**Walkthrough mode (apply/defer/skip per finding) — triggers:** + +- "Apply the AI review's fixes" +- "Walk me through the findings" +- "Go through the review one finding at a time" +- "Help me address the critical findings" +- "Fix the review comments the bot left" + +**Scope filters — triggers:** + +- "Critical only" / "show me only the critical findings" +- "Warnings only" / "info-level only" +- "Just the ones from the `cursor` leg" (multi-leg attribution) +- "The findings we all three legs agreed on" + +**Fall through** to a sibling skill when the developer: + +- Wants a **local review** on uncommitted changes → parent + [`ai-diff-reviewer`](../SKILL.md) skill (default review flow). This + sub-skill reads reviews that already exist on the PR; the parent + produces a new one locally. +- Wants to **install the CI action** → [`setup`](../setup/SKILL.md). +- Wants to **customize the reviewer** → [`generate-extension`](../generate-extension/SKILL.md). +- Wants to **author or refresh the PR body** → [`open-pr`](../open-pr/SKILL.md). +- Wants to read **human** reviewer comments (not the bot's) → defer; + this skill filters to bot artefacts by design. `gh pr view --comments` + covers human threads. + +If the intent is ambiguous ("show me the review" on a repo where the +Action posted 4 legs, or on a PR with both bot findings and human +comments), ask ONE clarifying question before acting. + +--- + +## Step 0 — Trust boundary + +This sub-skill's reads and writes are enumerated below. **Nothing else +happens.** + +**Reads (always allowed, no consent needed):** + +- `git`: `git branch --show-current`, `git rev-parse HEAD`, + `git status`, and `git show :` — the latter is + Step 6b's **primary** pre-image source (used on every `apply`, not + just the empty-`diffHunk` case) and is safe by construction: + write-free, streamed to stdout, never touches the working tree, + never creates or modifies a ref. Use it whenever the sub-skill + needs SHA-pinned file content. +- `gh`: `gh pr view` for PR metadata, `gh api graphql` for reviews + + comments. **Not** `gh pr diff` — it always emits current tip vs + base with no way to pin a historical SHA, so it can't be used for + pre-image or freshness checks (Step 6b covers this in detail); if + the sub-skill needs SHA-pinned file content, use `git show` + instead. +- Local files under the current git checkout, via `Read` / `Grep` / + `Glob` — only for files a finding references. + +**Writes (only under the per-finding consent contract in Step 6):** + +- **Edit source files** — when the developer answers *"apply"* on a + finding that has a `\`\`\`suggestion` block, the sub-skill reads the + target file, replaces the exact lines the suggestion covers, and + writes the file back. Never touches lines outside the suggestion's + range. +- **Create `.review/deferred.md`** (0-byte if empty, otherwise a + single-line-per-deferral list) — only when the developer answers + *"defer"* on any finding AND is prompted-and-agrees to persist. If + the developer prefers ephemeral deferrals, the file is not created. +- **Append `.review/deferred.md` to `.gitignore`** — only as a + one-time follow-up the very first time `.review/deferred.md` is + created in this repo, AND only when the developer accepts the + separate consent prompt in Step 6c. Never modifies existing + `.gitignore` rules; only appends one line (plus a labeled comment + identifying this sub-skill as the source) after the existing + content. + +**It does not:** + +- `git add`, `git commit`, `git push`, `git checkout`, or any + history-rewriting operation. +- Post replies, resolve conversations, dismiss reviews, approve, or + request changes on the PR — the sub-skill is read-only against + the GitHub PR-review surface. Replies to individual threads are a + separate concern (a future `respond-to-review` sub-skill). +- Call the LLM provider directly — it uses the coding agent that's + already running you. +- Fabricate suggestions, expand suggestion blocks beyond what the bot + wrote, or reason about "what the bot probably meant" when a + suggestion is absent. If a finding has no suggestion, *"apply"* is + not offered; the developer implements the fix themselves. +- Change any file outside the finding's `path:line` scope on + *"apply"*. If a suggestion is malformed (e.g. the file no longer + matches the expected context), the sub-skill refuses and surfaces + the finding for manual application. + +If the coding agent has broader powers (e.g. can run arbitrary bash), +those come from the harness, not this sub-skill. + +--- + +## Step 1 — Detect context + +Establish the mode (present vs. walkthrough vs. refuse) before +fetching anything from GitHub. + +```bash +# Current branch + head SHA +HEAD_BRANCH="$(git branch --show-current)" +HEAD_SHA="$(git rev-parse HEAD)" +HEAD_SHORT="$(git rev-parse --short HEAD)" + +# Repo slug (owner/repo) +REPO="$(gh repo view --json nameWithOwner --jq .nameWithOwner 2>/dev/null || echo '')" + +# PR for the current branch (if any) +PR_JSON="$(gh pr view --json number,url,state,headRefOid,labels,isDraft 2>/dev/null || true)" +PR_NUMBER="$(gh pr view --json number --jq '.number // empty' 2>/dev/null || true)" +``` + +`PR_NUMBER` is consumed by every subsequent `gh` / `gh api graphql` +invocation (Steps 2b, 3, 7). Extracted via `gh pr view --json … +--jq …` (not standalone `jq`) so the sub-skill's dependency set +stays `git` + `gh` — the two bins already declared in +`metadata.requires.anyBins`, matching sibling sub-skills. If the +`gh pr view` call fails (no open PR on this branch), `PR_NUMBER` is +empty and the mode table below routes to `refuse-soft`. + +Decide the mode from the state: + +| State | Mode | Skill behavior | +|---|---|---| +| On `main` / `master` / `develop` / `trunk` with no PR | **refuse** | Ask the developer to switch to a feature branch that has an open PR. | +| Detached HEAD | **refuse** | Ask the developer to check out a branch first. | +| `PR_JSON` empty (no PR for this branch) | **refuse-soft** | Point at [`open-pr`](../open-pr/SKILL.md): *"No open PR for ``. Open one first with the `open-pr` sub-skill, wait for CI to review, then re-run me."* | +| `PR_JSON` state is CLOSED or MERGED | **warn** | The review artefacts still exist and are readable — offer to read anyway ("this PR is closed / merged; want the historical review or should I stop?"). Do not proceed silently. | +| `PR_JSON` state is OPEN | **read** | Go to Step 2. | + +**On `gh` missing or unauthenticated:** surface the exact remediation +(`brew install gh` or `gh auth login`) and stop. Do not attempt to +scrape the PR page via a browser — the sub-skill is designed for +`gh` + GraphQL and there is no fallback path. + +--- + +## Step 2 — Fetch the review + +This is the mechanical heart of the sub-skill. The GraphQL query below +is **adapted from** [`docs/PR_REVIEW_WORKFLOW.md`](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/PR_REVIEW_WORKFLOW.md#ready-to-copy-graphql-query) +— the selection set is extended (`createdAt`, `submittedAt`, +`startLine` for multi-line-suggestion apply) but the **filter rules +are the shared contract**: if the doc says *"skip `isMinimized == +true`"*, this sub-skill does. If it says *"anchor on the most recent +marker"*, this sub-skill does. Divergence in the selection set is +allowed and expected as this sub-skill's needs evolve; divergence in +the filter rules is a bug — fix the doc, then re-sync here. + +### 2a. Identify the bot login + +The Action collapses prior artefacts belonging to the user its +`github-token` authenticates as. For consumers using +`secrets.GITHUB_TOKEN` (default), that's `github-actions[bot]`; for +consumers using a PAT / automation account, it's the PAT owner's +login. Hardcoding `github-actions[bot]` silently mis-filters every +PAT consumer — Step 2c drops the real review author and Step 2d +then fires the *"Missing (no marker found)"* branch even though a +live review exists on the PR. + +Resolve the login in this order (first non-empty wins): + +1. **`AIPRR_BOT_LOGIN` env var** — explicit override; always respected. +2. **The most recent non-minimized `` + comment's `author.login`** — authoritative and self-configuring + across `github-actions[bot]`, PATs, and automation accounts. Read + it from the `comments` collection you already fetch in Step 2b; + pick the newest comment whose body starts with + ``. +3. **`gh api user --jq .login`** — a last-resort fallback only when + no marker exists on the PR (a first-run install where CI hasn't + posted anything yet). +4. **The literal string `github-actions[bot]`** — final default when + even step 3 fails; a warning should be surfaced to the developer + since this is almost always wrong for PAT consumers. + +The Step 2b query already returns the top-level `comments` nodes +with `author.login`. To keep the sub-skill's runtime deps aligned +with `metadata.requires.anyBins` (`git` + `gh` only — **no** +standalone `jq`), issue a small dedicated `gh api graphql` call for +the marker-author read, using `gh`'s built-in `--jq` filter to +extract the login without shelling out to `jq`: + +```bash +BOT_LOGIN="${AIPRR_BOT_LOGIN:-}" + +if [ -z "$BOT_LOGIN" ]; then + # Preferred: derive from the most recent non-minimized marker comment. + # Uses gh's built-in --jq (no standalone jq dependency). + BOT_LOGIN="$(gh api graphql \ + -F owner="${REPO%%/*}" -F repo="${REPO##*/}" -F number="$PR_NUMBER" \ + -f query=' + query($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $number) { + comments(first: 100) { + nodes { body isMinimized createdAt author { login } } + } + } + } + }' \ + --jq '[.data.repository.pullRequest.comments.nodes[] + | select((.isMinimized | not) + and (.body | startswith("")))] + | sort_by(.createdAt) | reverse | .[0].author.login // empty' \ + 2>/dev/null)" +fi + +if [ -z "$BOT_LOGIN" ]; then + # Fallback: current authenticated user (only accurate on first-run repos + # where no marker exists yet). Warn the developer that this is a guess. + BOT_LOGIN="$(gh api user --jq .login 2>/dev/null || echo 'github-actions[bot]')" +fi +``` + +`gh api graphql --jq` runs the filter inside `gh` itself — it does +not shell out to standalone `jq`, so this snippet stays inside the +`git` + `gh`-only dep constraint declared in `metadata.requires`. +Do NOT reintroduce a standalone `jq | ...` pipe here — the moment +you do, the primary marker-author path breaks on vanilla macOS / +minimal agents and the fallback (`gh api user`) mis-filters live +reviews for every PAT / automation-account consumer. + +### 2b. Run the GraphQL query + +```bash +gh api graphql -F owner="${REPO%%/*}" -F repo="${REPO##*/}" \ + -F number="$PR_NUMBER" -f query=' +query($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $number) { + comments(first: 100) { + nodes { + id + body + isMinimized + createdAt + author { login } + } + } + reviews(first: 100) { + nodes { + id + body + state + isMinimized + submittedAt + author { login } + commit { oid } + comments(first: 100) { + nodes { + id + body + path + line + startLine + diffHunk + isMinimized + } + } + } + } + } + } +}' +``` + +`startLine` is `null` for single-line inline comments and non-null for +multi-line ones (e.g. a `\`\`\`suggestion\`\`\` block covering several +lines). When you later need the apply range for Step 6b, derive it as +`start = startLine or line`, `end = line` — the reviewer's `line` +field is the range end for multi-line comments and the anchor for +single-line ones. `originalLine` is the outdated-position field +(diff-relative for reviews that no longer point at the current file +state) and is **not** the multi-line-range start — do not use it here. + +**`line: null` is a distinct case.** GitHub returns `line: null` (and +`startLine: null`) when the comment is anchored on a hunk that is no +longer present in the diff — the review was posted, the developer +force-pushed or rebased, and the anchor became orphaned. This shows +up precisely on the stale-review paths Step 2d allows after +acknowledgement. Because `[startLine or line, line]` would collapse +to `[null, null]` and every downstream comparison would either crash +or produce a bogus apply range, treat `line: null` as a **read-only** +finding: + +- Include the finding in Step 4's presentation with a marker like + `[⚠️ outdated anchor — apply disabled]`. +- In Step 6a's walkthrough, present the body normally. +- In Step 6's menu, **never offer `apply`** — only `defer`, `skip`, + `discuss`, `stop`. Do not attempt to reconstruct a range from + `originalLine` (it's diff-relative to a hunk that no longer + exists; the numbers won't map cleanly onto today's file). +- In Step 3a's consensus scoring, group `line: null` findings only + with other `line: null` findings on the same `path` — the range- + overlap predicate is undefined for null ranges. + +The `diffHunk` field carries the raw diff hunk the comment was +anchored on (the `-`, `+`, and context lines around the anchor). It +is used to render the surrounding patch when the developer needs +context — that display belongs in **Step 4's presentation table** +(next to the file/line) and/or **Step 6a's walkthrough banner** for +the current finding, NOT in Step 5 (which is only the top-level +routing menu: `done` / `walk through` / `critical only` / `warnings +and up` / `filter by leg` / `cancel`). `diffHunk` also serves as an +optional +consistency check inside Step 6b — but it is **not** the primary +source of the expected pre-image; that role belongs to +`git show :` (see Step 6b for the full +derivation). Note the GraphQL schema does **not** expose a `side` +field on `PullRequestReviewComment` — side-of-diff lives on +`PullRequestReviewThread.diffSide`. Step 6b sidesteps this by +reading the reviewed-commit file content directly, which is +independent of hunk sides. In practice this is safe because +`findings_to_gh_inline_comments()` in `scripts/reviewer.py` posts +anchors with `side: RIGHT` by default (the `"side": f.side or +"RIGHT"` line inside that function is the authoritative reference — +cite the function name, not a raw line number that will drift on +the next edit), so `line` / `startLine` refer to post-image file +positions that resolve cleanly +via `git show`. A rare `side: LEFT` anchor (removed-line comment) +will fail the `git show`-slice consistency check in Step 6b and +route to `skip / discuss`. + +`BOT_LOGIN` is **not** a GraphQL variable — it's applied client-side +in Step 2c's filter. GitHub's GraphQL API rejects unused declared +variables (`variableNotUsed`), so declaring `$bot: String!` while only +using it in a follow-up `jq` filter fails the query outright. Keep +the login filter in Step 2c and the GraphQL selection set variable-free. + +### 2c. Filter to live bot artefacts + +Two collections come back — `comments` (top-level, includes tracking +markers) and `reviews` (with nested inline `comments`). Apply the +mandatory rules from [`docs/PR_REVIEW_WORKFLOW.md` § Mandatory rules](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/PR_REVIEW_WORKFLOW.md#mandatory-rules): + +1. **Filter out `isMinimized == true`** at every level (top-level + comments, review bodies, inline review comments). +2. **Filter authors** to `$BOT_LOGIN` only. +3. **Anchor on the latest `` comments** — + plural when multiple legs ran. Each marker's body starts with the + marker string; each carries the SHA its leg reviewed. + +**IAR note.** The marker may contain an HTML-comment `IterationState` +JSON block and a short gen/round/policy annotation — ignore both when +collecting findings (they are telemetry, not review comments). The +inline comments you present are already post-IAR-dedup. If the +developer expected a finding that appeared in a local review but not +in CI, suggest applying `full-review-please` (the +`iteration-escape-label`, one-shot full review with state preserved) +or removing the `applied-label` then re-triggering for a full state +reset — see +[`docs/ITERATION_AWARENESS.md` § 8](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/ITERATION_AWARENESS.md). + +Emit the filtered set to your working context as a list of +`{leg_label, sha, review_body, inline_comments[]}` records. + +### 2d. Anchor + freshness check + +Tracking markers are top-level **issue comments** — they have no +`commit.oid`. The SHA source depends on the marker state (the H3 tells +you which one: `_Working…_` vs. `✅ done` / `🚫 done` vs. `❌ failed`): + +- **Working markers** (`render_tracking_body_working()` in + `scripts/reviewer.py`) — include a `Full SHA: \`\`` line in + the body. Parse it. This is the in-flight case; a Working marker + means the review is still running or its terminal transition + failed. +- **Done and failed markers** (`render_tracking_body_done()` / + `render_tracking_body_failed()`) — do NOT render `Full SHA:`; they + only carry the 7-char short SHA in the H3 (`AI review for + \`<7chars>\``). Resolve the full SHA by joining the marker to its + matching non-minimized review via the provider marker (both carry + ``), then read the joined + review's `commit.oid` — that is the **primary** SHA source for + completed reviews (which is the common case). The 7-char prefix in + the H3 is a useful cross-check but is ambiguous by itself. + +If the joined review is missing when the marker says `done` or +`failed` (rare — the mid-flight transition raced), fall back to the +7-char H3 prefix and warn the developer that the review body could +not be paired. + +Compare the resolved SHA against `HEAD_SHA`: + +| Marker SHA | HEAD SHA | Interpretation | +|---|---|---| +| Matches HEAD | Matches | Review is for the current commit — proceed normally. | +| Matches HEAD's parent (marker == `HEAD~1`) | Matches | The developer has made **one commit locally** since the review; HEAD itself is a commit CI never saw. Warn: *"The review is for ``, but you've committed `` since then. Findings may already be resolved by your local commit; CI will re-review once you push. Continue anyway?"* — proceed only after ack. Pre-image checks in Step 6b will still refuse silently-clobbering an already-edited line. | +| Older than HEAD's parent | New commits landed since the review | Warn: *"The review is for ``, but HEAD is ``. Reading anyway, but the findings may be stale — CI will likely re-review. Continue?"* | +| Newer than HEAD | Local branch is behind origin | Warn: *"Origin has ``, your local HEAD is ``. Consider `git pull` before applying."* — proceed only after ack. | +| Missing (no marker found) | — | CI hasn't run yet OR the label-gate is missing OR all matrix legs' secrets are unset. See [`docs/PR_REVIEW_WORKFLOW.md` § "I don't see any live review"](https://github.com/DailybotHQ/ai-diff-reviewer/blob/main/docs/PR_REVIEW_WORKFLOW.md#i-dont-see-any-live-review) for the diagnosis table. Stop; do not proceed with an empty review. | + +Only exact-HEAD is fully authoritative; every other row above +(including `marker == HEAD~1`) requires an explicit developer +acknowledgement before Step 4 presents findings or Step 6b applies +anything. This closes the "silent green light" case where a single +uncommitted-since-CI commit would otherwise be treated as +authoritative. + +Never fabricate findings when the review is missing or stale. + +### 2e. Extract per-finding severity + +GitHub inline review comments carry `body` only — +`findings_to_gh_inline_comments()` in `scripts/reviewer.py` does +**not** prefix severity into the comment body, so severity is **not** +recoverable from the inline comment itself. The authoritative +per-finding severity lives in the **review summary body's findings +table**: + +```markdown +### 2. Findings table + +| # | Severity | File | Summary | +|---|------------|---------------------|----------------| +| 1 | 🚨 critical | `src/auth.ts:55` | SQL injection… | +| 2 | ⚠️ warning | `src/cache.ts:120` | Unbounded key… | +``` + +For each inline comment produced by the leg, join to the summary +table by matching on `path:line`: + +1. **Locate the findings table heading-agnostically.** Scan + `review_body` for a Markdown table whose header row contains all + of `Severity`, `File`, and `Summary` (case-insensitive, in any + column order). The heading right above the table varies — + `prompts/default.md` instructs models to emit it under + `### 2. Findings table`, while the local review flow uses + `## Findings`, and consumers with custom prompts may use anything — + so anchoring on the header row (not the heading text) is the only + reliable strategy. +2. Parse each row into `{severity, path, line, summary}`. The severity + cell is `