Skip to content
Back to skills

Draft Pr

ASecurity

Draft or update a pull request using a disciplined PR schema (Summary, Review Claim, Review Lane, Review Unit, Safety Invariant, Slice Rationale, Non-goals, Measured, Test Plan, Revert Plan), a diff-atomicity gate, and visual-proof rules for UI-impacting changes. Always on after catstack install.sh via Cursor ~/.cursor/rules/draft-pr-precedence.mdc, Claude CLAUDE.md, Codex AGENTS.md, and slash commands /pr-skill, /draft-pr, /make-pr. Trigger when asked to make a PR, draft or update a PR body,...

  • 4 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsgobashnodetestinggit

Works with

  • claude code
  • cursor
  • cli
  • mcp

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 8 files and shows the line behind each finding

Scanned October 5, 2026

npx -y skills add EdbertChan/catstack --skill draft-pr --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Draft Pr?

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

Security grade badge for Draft Pr
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/edbertchan-draft-pr/badge)](https://www.skillsdirectory.com/skills/edbertchan-draft-pr)

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: draft-pr
description: >
  Draft or update a pull request using a disciplined PR schema (Summary,
  Review Claim, Review Lane, Review Unit, Safety Invariant, Slice Rationale,
  Non-goals, Measured, Test Plan, Revert Plan), a diff-atomicity gate, and visual-proof
  rules for UI-impacting changes. Always on after catstack install.sh via
  Cursor ~/.cursor/rules/draft-pr-precedence.mdc, Claude CLAUDE.md, Codex
  AGENTS.md, and slash commands /pr-skill, /draft-pr, /make-pr. Trigger when
  asked to make a PR, draft or update a PR body, prepare PR text, run gh pr
  create, or whenever a branch/PR change means the PR's title/body may now be
  stale.
---

# draft-pr

Use this skill when the work is already done and the user wants a PR created,
updated, rewritten, split, or republished, and whenever a branch or diff
change could leave a PR's title/body out of date with the actual code.

After `./install.sh`, this is always on for Cursor, Claude Code, and Codex
(the Cursor precedence rule, Claude `CLAUDE.md`, Codex `AGENTS.md`, plus
`/pr-skill`, `/draft-pr`, and `/make-pr`). If the current repo has
`skills/make-pr/SKILL.md`, use that overlay for publication. Do not substitute
a generic `gh pr create` Summary / Test plan template.

Apply `split-scope` (this bundle's companion skill) before writing titles or
PR bodies for a stack: if one branch mixes more than one local review claim,
split the stack first.

When the current repo has `skills/make-pr/SKILL.md` (or
`engine/skills/make-pr/SKILL.md`), that overlay owns publication gates.
**Run its preflight classification before drafting any PR body** — dry-run
with commit-scoped paths is enough to learn the review unit. Draft the body
only after preflight declares one unit. Choose Mergify vs `gh` once from
that overlay before the first push, and keep that path for the slice.

## Scope & Ambiguity Confirmation

Before drafting a PR body, resolve scope and ambiguity with the user in
conversation. Do not draft through unresolved ambiguity.

Ask a concise, concrete question — instead of drafting speculatively — when,
after looking at the actual diff/changed files:

- The review lane cannot be inferred with confidence: no single lane's
  compatible unit set covers the large majority of changed, non-neutral files.
- The changed files plausibly span more than one review unit under the
  active `drafter.config.json` taxonomy, and grouping them isn't covered by an
  explicit Boundary/Grouping rule (see `split-scope`'s Grouping Rules).
- The slice boundary is undecided: the diff could reasonably ship as one PR or
  a multi-PR stack, and each framing changes what a reviewer is being asked to
  approve.
- A configured pairing ban (see `drafter.config.json`) is half-triggered — one
  of its two paths changed, not the other.

If none of these hold, proceed and record the resolved choice under an
`Assumptions:` note rather than asking. Do not ask about a choice that has
exactly one non-arbitrary answer.

**Safety Invariant Confirmation is a standing rule, independent of the above:**
always propose the `## Safety Invariant` text and ask the user to confirm or
correct it before finalizing a PR body — even when scope was completely
unambiguous. Mechanical slices may use a terse invariant; confirmation is
still required. Nothing in this skill or its validator enforces that a human
actually answered — this is a conversational convention you must actually
follow, not a check you can skip because the tooling would let you.

**Headless / non-interactive mode:** when invoked under a directive that
forbids clarifying questions (a benchmark prompt, an explicit non-interactive
flag), skip all asking above, resolve every open point to your best-effort
default, and record each one under `Assumptions:` instead — including the
Safety Invariant, marked as unconfirmed in the output.

## Stack ordering

Order slices so a reviewer reads the evidence before the change it justifies:

- **Repro/proof comes before the fix.** Land the repro or regression proof as
  the earlier slice and the behavior fix as the later slice, so the bug is
  demonstrated before the change is approved.
- Foundation (types, helpers, migrations, flags) precedes behavior; cleanup
  and docs come last.

## Preferred PR schema

Default to this structure (validated by `validatePrBody()` in
`@neko-catpital-labs/drafter-core`):

```md
## Summary

The reader is a busy director who has never seen the code. Teach them from
zero.

The first paragraph says what the part is and what it does for a person.
Then one short paragraph each for the problem, the cause, and the fix.
Paragraphs, not bullets, under 30 words each (configurable via
`drafter.config.json`'s `prBody.summaryWordLimit`). Short sentences,
everyday words; explain or cut every term coined while working.

The whole Summary is 150 words or fewer. Write it with the `diu` skill:
lead with what changed for a person, then the problem and the fix, and
nothing else. Detail goes in the sections below it.

No code names in Summary or Review Claim: no backticked text, no snake_case
or camelCase words, no file paths, and no word that is the name of a changed
file or folder. Say what the part does instead. Names and output belong in
later sections: Test Plan, Revert Plan, Architecture.

Before: "When diu-stop or prove-it-ship-gate block a reply and the agent
rewrites it, the rewrite is still checked for evidence. Before, both hooks
returned on `stop_hook_active` before running any check."

After: "Before Claude sends a reply, small checker scripts read it. One
checks length. Others check that every claim comes with proof. If a check
fails, Claude must rewrite. The problem: when Claude rewrote, both checkers
stepped aside completely."

`scripts/validate-pr-body.mjs` fails a Summary or Review Claim that holds a
code name and lists each one. It also blocks a Summary above reading grade 11,
with more than 25% words of three or more syllables, or over 150 words. CI
runs the same check on every PR's live text, so a body edited on GitHub is
checked too.

## Review Claim

State the one thing the reviewer is being asked to approve, in everyday
words with no code names (same rule as Summary).

## Review Lane

Choose exactly one from your `drafter.config.json` taxonomy (default:
`behavior`, `refactor`, `proof`, `cleanup`, `policy`, `docs`).

## Review Unit

Choose exactly one matching review unit from your configured taxonomy. The
unit must match the changed files — the validator rejects a declared unit
that ships files assigned to another unit.

## Safety Invariant

Explain why this slice is safe to review locally. Propose it and get the
user's confirmation before publishing (see Scope & Ambiguity Confirmation
above).

## Slice Rationale

Explain why this work is split here instead of bundled elsewhere.

## Non-goals

List what this slice explicitly does not change. For a `refactor` lane,
include one of: `no behavior change`, `behavior unchanged`, `unchanged
behavior`, or `pass unchanged`.

## Architecture

Only include this section when the change modifies component interactions,
control flow, state flow, or data flow. Quote Mermaid labels that contain
prose, punctuation, or code-ish text.

### Before

\`\`\`mermaid
graph TD
    A["old flow"]
\`\`\`

### After

\`\`\`mermaid
graph TD
    A["new flow"]
\`\`\`

## Measured

Command: `exact repro command`

- base: `the command's real output on the base, pasted`
- head: `the command's real output on this branch, pasted`

A slice with nothing to measure says so and says why: one line,
`none: <reason>`, takes the place of the rows.

## Test Plan

<details>
<summary>Test Plan</summary>

- [ ] exact command
- [ ] exact command
- Not run: the check that was skipped. Blocker: what stops it

</details>

## Visual Proof

Required when the diff changes UI-impacting files. Include before/after
screenshots or a video link.

## Revert Plan

<details>
<summary>Revert Plan</summary>

- Safe to revert? Yes/No
- Revert command: `git revert <sha>` or equivalent
- Post-revert steps: None / concrete steps
- Data migration? No / concrete steps

</details>
```

If the change is small and has no architectural impact, omit `## Architecture`
rather than forcing filler.

Use visible markdown sections for review metadata. Do not hide `Review
Claim`, `Review Lane`, `Review Unit`, `Safety Invariant`, or `Slice Rationale`
inside `<details>` or other HTML disclosure blocks — they must render
directly in the PR body. Test Plan and Revert Plan are the opposite: keep
their headings visible, but their content must sit inside a collapsed
`<details>` block with `<summary>Test Plan</summary>` /
`<summary>Revert Plan</summary>`.

`## Measured` is required and stays visible. A repro command in a PR body
comes with the output it printed. Give a `base:` row and a `head:` row, each
with that output pasted inline in backticks or in a code block under the row.
A slice whose claim is about speed, size, or cost shows the measured number on
both rows. A slice with nothing to measure writes `none: <reason>` instead.
`scripts/validate-pr-body.mjs` reads the shape only: the heading is there, it
is outside `<details>`, and either both rows carry pasted output or the
`none:` line has a reason. It does not read what the words mean, so a number
in another section never counts, and nothing judges whether a `none:` reason
is true; the validator prints that reason as not checked. `none:` is not a way
around a slice that claims a number.

A check the Test Plan names but that was not run gets its own row that starts
`Not run:`, and that row names what stops it: `Blocker: <what stops it>` on
the same line or on the next non-empty line. A check that nothing stops is
run, and its result is pasted, before the PR is published. The validator
rejects a `Not run:` row with no blocker. It reads the shape of that one
labelled row only: the row starts with `Not run:` and `Blocker:` is followed
by text. It does not hunt the rest of the body for other ways of saying a
check was skipped, and nothing judges whether a blocker is real or could have
been removed; the validator prints each blocker as not checked. Drop the row
from the example above when every check ran.

Do not default to a lightweight `## Summary / ## Testing / ## Notes` PR body.
Use the schema above as the floor.

## Visual proof rules

If the change is UI-impacting, capture before/after screenshots or a video
first. UI-impacting means the user-visible experience changes, even when no
file under a conventional UI directory changes.

- Visual proof must show the changed behavior itself, not just the changed
  screen area. Open every screenshot or video and verify the user-visible
  target is present and identifiable.
- If the changed behavior spans multiple states or a state transition —
  restart persistence, before/after transitions, progress animations, opening
  then dismissing overlays — use animated proof (gif/mp4/webm/walkthrough
  video). Static screenshots alone are not enough.
- When the claim is that a state persists across an action (navigation,
  restart, refresh, resize), each screenshot must also show the action
  happened, with an on-screen cue distinguishing each step.
- Caption each visual proof item with the concrete thing the reviewer should
  see.
- Before/after proof images must use distinct local filenames before upload
  (a shared upload prefix keyed by basename can otherwise collapse two
  different images into one URL).

## Diff atomicity gate

Run `lintDiffAtomicity()` (or the CLI at `scripts/lint-diff-atomicity.mjs`)
before publishing. Fatal findings — generated files mixed with hand-written
source, an orphaned lockfile change, a debugger statement, a focused
(`.only`) test — are hard failures; split the PR to clear them. Warnings
(readability findings like file count or unrelated-area spread) are
advisories — confirm the spread is intentional rather than silently ignoring
them.

If one branch mixes behavior, refactor, cleanup, or proof/test-harness work,
split the work into separate PRs. Do not relabel the lane or weaken the
checker to make a mixed branch pass.

## Command surface

The scripts below import `@neko-catpital-labs/drafter-core`. Install it once
in the repo you're drafting PRs for (`npm install --save-dev
@neko-catpital-labs/drafter-core`) so Node can resolve the import — a globally
installed skill copy can't resolve a bare import on its own.

1. Branch from your canonical base remote (see `references/branching-workflow.md`).
2. If the repo has a make-pr overlay, run its **commit-scoped preflight**
   (dry-run) and learn the Review Unit **before** writing the body.
3. Choose one publish path before the first push: Mergify stack tooling when
   the repo uses it (for example `.mergify.yml`), otherwise `gh pr create` /
   `gh pr edit`. Do not switch mid-slice.
4. Draft from the canonical template and validate it:

```bash
npx @neko-catpital-labs/drafter-mcp --help  # or call validate_pr_body via MCP
node scripts/validate-pr-body.mjs --body-file /tmp/my-pr.md --base main
```

5. Push the working branch and create or update the PR only via the path
   chosen in step 3, once this skill's schema and validation pass. The
   command is not a license to skip the schema for a Summary / Test plan
   template.

After any branch update, rebase, or force-push, refresh the PR title and body
so they still match the live diff. Re-check `## Summary`, test commands,
revert guidance, and any visual proof section; old copy is stale the moment
the branch meaning changes.

## Upstream-first workflow

Use the canonical repository as the PR target and an explicit publish remote
for branch publication. Create branches from `<baseRemote>/<base>`; open PRs
against the canonical repository's base branch. See
`references/branching-workflow.md`.

## Merge-queue tools (Mergify, etc.)

If this repo uses a merge-queue or stacked-PR tool, choose that path once
before the first push and follow that tool's publish workflow after this
skill produces a validated body/branch. Do not also open the same slice with
a separate `gh pr create` unless the make-pr overlay says to refresh
title/body on an already-pushed stack.

## Validation

- Ensure the PR title still matches the current slice after any branch update
  or force-push.
- Ensure the `## Summary` section still describes the current diff.
- Ensure the branch is pushed.
- Ensure body sections are present and concrete; test commands are real
  commands that were actually run when possible; revert guidance is honest.
- Keep Test Plan and Revert Plan content inside their collapsed `<details>`
  blocks.
- Give every `Not run:` row in the Test Plan a `Blocker:` that says what
  stops the check, or run the check and replace the row with its result.
- Keep measured proof in plain view: the output a repro command printed on
  the base and on the head sits under `## Measured`, outside any collapsed
  block, or that section says `none: <reason>`.
- Do not create or update a PR when the branch has no file changes against
  its selected base, or contains an empty commit slice.
- For UI-impacting diffs, include `## Visual Proof` before publishing;
  classify by user-visible behavior, not by path alone.

## References

- `references/branching-workflow.md`
- `scripts/validate-pr-body.mjs`
- `scripts/lint-diff-atomicity.mjs`
- `scripts/pr-body-template.mjs`
- `scripts/measured-section.mjs`

Files in this skill

  • SKILL.md12.2 KB
  • references/branching-workflow.md830 B
  • scripts/lint-diff-atomicity.mjs2.6 KB
  • scripts/pr-body-targets.mjs2.4 KB
  • scripts/pr-body-template.mjs325 B
  • scripts/summary-reading-grade.mjs6.3 KB
  • scripts/validate-pr-body.mjs3.3 KB
  • tests/test_draft_pr_scripts.py13.2 KB

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.