Skip to content
Back to skills

Auto Draft Review

ASecurity

Use when running a PR review in --auto mode, to post analyzer findings as a pending GitHub review without an interactive walkthrough. Not user-facing — invoked by the orchestrator only.

  • 3 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 26, 2026
developmentpythonrustgobashgitapi

Works with

  • api

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add ahardin13/review-assistant --skill auto-draft-review --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Auto Draft Review?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Auto Draft Review
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ahardin13-auto-draft-review/badge)](https://www.skillsdirectory.com/skills/ahardin13-auto-draft-review)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: auto-draft-review
description: Use when running a PR review in --auto mode, to post analyzer findings as a pending GitHub review without an interactive walkthrough. Not user-facing — invoked by the orchestrator only.
---

# Auto Draft Review

Post analyzer findings as a pending GitHub review so the user can finalize on github.com. No walkthrough, no per-finding prompts. The user's first line ("Running auto review — ...") was already announced by the orchestrator; do not re-announce.

**File I/O:** Use `Bash` with heredocs or `>>` for session/temp files — not Write, Read, or Edit tools.

## Inputs

- `pr_number`: the PR number
- `repo`: owner/repo
- `session_file`: path to the session file (contains Why, Findings, etc.)

## Step 1: Fetch the diff

```bash
gh pr diff <PR_NUMBER> --repo <REPO> > $HOME/.local/state/review-assistant/pr-<PR_NUMBER>-diff.txt
```

Read the session file separately for metadata (Why summary, `review_sha`, `threshold`, skipped files). Findings themselves flow through the classifier in the next step — do not re-parse them by hand.

## Step 2: Classify and verify findings

Run the shared classifier against the `## Findings` section:

```bash
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/classify-and-verify.py" \
  --diff "$HOME/.local/state/review-assistant/pr-<PR_NUMBER>-diff.txt" \
  --session "<session_file>" \
  --section findings \
  > $HOME/.local/state/review-assistant/pr-<PR_NUMBER>-classified.json
```

The script emits `{ inline, fallback, suspect, stats }` where each bucket means:

- **inline** — safe to post as an inline review comment. `line` and `side` have been verified (or re-anchored within ±3 lines) against the finding's recorded `code` text. Use these verbatim. Each entry's `body` is the finding's description as written by the analyzer (paragraph breaks preserved). Severity, confidence, and source live on `source_finding` for the review-body summary, **not** in the inline body — keep it that way; meta-prefixes like `**high** (confidence 87, source: bug-scan)` add noise to anyone reading the PR on github.com.
- **fallback** — the line is outside every hunk for that file, or the finding was recorded with `in_diff: false`. Put these in the review body, not in `comments[]`.
- **suspect** — the line IS inside a hunk, but the finding's `code` anchor didn't match the diff line or any of its ±3 neighbors. Also goes in the review body, with an explicit "line anchor uncertain" flag so the reviewer knows not to trust the number.

**Never** invent inline comments that bypass the classifier. If the classifier says fallback or suspect, respect it.

## Step 3: Build the review payload

**Body** (heredoc into the `gh api` call):

```
<Why summary from session file>

---

This is a pending review with <inline_count> findings pre-annotated inline. Open the PR on github.com, review the inline comments, edit or dismiss as needed, and submit when ready.

<If fallback entries exist:>
## Findings outside the current diff

- `<file>` line <N> (<severity>, confidence <C>): <description>
...

<If suspect entries exist:>
## Findings with uncertain line anchors

The analyzer reported these inside the diff, but the recorded line text didn't match the diff's version — the line number may be stale. Check the file on github.com before acting.

- `<file>` line <N> (<severity>, confidence <C>): <description>
...
```

**Inline comments** come from the classifier's `inline` bucket — use each entry's `path`, `line`, `side`, and `body` directly.

## Step 4: Post as a pending review

Call the shared helper. It detects an existing pending review by the current user, **silently merges** with it (preserving any user-edited bodies the user already touched on github.com), backs up the pre-DELETE state, and POSTs the combined review. Omitting the `event` field — which the helper does — is what keeps the new review pending so the user finalizes on github.com.

Write the body to a scratch file first, then assemble the JSON spec with `jq -n` so multi-paragraph content (which contains literal newlines) is JSON-encoded reliably. Do **not** try to interpolate `$(jq -Rs . <<<"$BODY")` inside an outer heredoc — bash's here-string handling chokes on multi-line content and you'll get `Invalid control character` from the helper.

```bash
cat > $HOME/.local/state/review-assistant/pr-<PR_NUMBER>-body.txt <<'EOF'
<body text — Why summary, separator, "pending review with N findings..." line, then any "Findings outside the diff" / "uncertain anchor" sections>
EOF

INLINE_COMMENTS=$(jq '.inline | map({path, line, side, body})' \
  $HOME/.local/state/review-assistant/pr-<PR_NUMBER>-classified.json)

jq -n \
  --arg repo "<OWNER>/<REPO>" \
  --argjson pr <PR_NUMBER> \
  --arg commit "<review_sha>" \
  --rawfile body $HOME/.local/state/review-assistant/pr-<PR_NUMBER>-body.txt \
  --argjson comments "$INLINE_COMMENTS" \
  --arg ip "merge" \
  '{repo: $repo, pr: $pr, commit_id: $commit, body: $body, comments: $comments, if_pending: $ip}' \
  | python3 "${CLAUDE_PLUGIN_ROOT}/scripts/post-pending-review.py"
```

The helper exits non-zero with `gh ... failed: <reason>` on any GitHub error — surface that verbatim to the user and stop. Do not retry silently. The helper output (stdout) is JSON: `{ review_id, review_url, comment_count, replaced_existing, merged_comments, backup_path }`. Keep the `review_url` for the final summary; if `replaced_existing` is true, mention it ("Merged with previous pending review (N comments)") so the user isn't surprised.

After a successful post, append to the session file:

```
last_reviewed_sha: <review_sha>
posted_mode: auto
```

## Step 5: Final summary (user-facing)

Print exactly this shape. "Not posted" lists every finding that did NOT end up as an inline comment, grouped by reason. Omit groups with zero entries. If the helper reported `replaced_existing: true`, prepend the merge line below the URL.

```
Pending review posted: https://github.com/<OWNER>/<REPO>/pull/<N>
[Merged with previous pending review (<merged_comments> comments).]

Posted inline: <inline_count>
Posted in review body (outside diff hunks): <fallback_count>
Posted in review body (uncertain line anchor): <suspect_count>

Not posted:
  Below confidence threshold (<threshold>): <count>
    - <file>:<line> — <description>
  In skipped files: <count>
    - <file> — <reason>

Open the PR on github.com to review, edit, and submit. Nothing has been submitted yet.
```

If `inline + fallback + suspect` equals the total non-skipped findings and there are no below-threshold or skipped records, replace the "Not posted" block with:

```
Not posted: none — every finding made it onto the pending review.
```

To list below-threshold findings, re-run the classifier with `--section below` (emits the same bucket shape; you only need the `source_finding` details for display, not the classification).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.