Gate PR bodies
Reject pull requests whose description is missing sections or still has placeholder text.
MON MOTHMA: "Many Bothans died to bring us these plans. The least the courier can do is fill in the briefing form."
The Rebel Alliance does not accept a mission briefing that's missing the objective, has no linked intel, and whose pre-flight checklist is half-empty. Neither should your repo. Here's a complete, runnable recipe: require every PR to carry a real Summary, a linked issue, and a checked-off checklist before it can dock.
The contract
<!-- mdv: document title.pattern=/^(feat|fix|docs|chore|refactor|perf|test|build|ci)(\(.+\))?!?:\s.+/ -->
<!-- mdv: block required minWords=20 noPlaceholder -->
## Description
Describe what changed, why, and the impact.
<!-- mdv: endblock -->
<!-- mdv: block required issueKeyword=Fixes,Closes,Resolves -->
## Related Issue
Fixes #
<!-- mdv: endblock -->
<!-- mdv: taskList required allChecked exactLabels -->
## Pre-Merge Checklist
- [ ] I reviewed the diff for unrelated changes.
- [ ] I updated docs, or this PR does not require docs.
<!-- mdv: endtaskList -->mediva validates the PR body against this template — the same file is both the contributor template and the contract. One form, every courier.
The GitHub Action
This is the sensor net guarding the exhaust port: every PR that arrives gets scanned before it can merge. Two details make it tamper-proof — it checks out the base branch's template (so a PR can't loosen the contract it must pass), and it validates the title as well as the body.
on:
pull_request:
types: [opened, edited, reopened, synchronize]
jobs:
validate-pr-body:
runs-on: ubuntu-latest
steps:
# Check out the BASE branch's template — the rules come from the branch you're merging
# INTO, so a PR that edits the template to weaken it is still judged by the old contract.
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.sha }}
- run: npm install -D mediva
- env:
TITLE: ${{ github.event.pull_request.title }}
BODY: ${{ github.event.pull_request.body }}
run: |
printf '%s' "$BODY" > /tmp/body.md
npx mediva check --schema .github/pull_request_template.md --title "$TITLE" /tmp/body.mdA PR with a placeholder Description (Fixes # and nothing else), a misformatted title, or an unchecked box exits 1 and fails the check with the exact rule and line — the proton torpedo finds the gap. Real content passes, and the plans get through.
First adoption: the check validates against the template on the base branch, so land
.github/pull_request_template.mdthere first. Until that file exists on base,mediva check --schemacan't read its contract and exits2— the step fails red, it does not pass silently. So merge the template to base before you turn the required check on.
Variations
-
Swap
allCheckedforminChecked=1if not every box is mandatory. -
Add
oneCheckedon achoiceblock for a single-select "Type of change" (feat / fix / docs — pick one, like choosing your starfighter). -
Require visual evidence for UI work with a
mediasection.requiredOrNAaccepts an image or video, or an explicitN/Awhen there's genuinely nothing to show — so a backend-only PR isn't forced to fake a screenshot:<!-- mdv: media requiredOrNA --> ## Screenshot  <!-- mdv: endmedia -->A section with prose but no image and no
N/Anote fails with[missing-media]— "tell me what changed on screen, or tell me honestly that nothing did."
Autofix
Repair a broken Markdown document so it satisfies a contract, with a model you provide — validator-in-the-loop, provider-agnostic, safe by construction.
Validate LLM output before persisting
Repair generated Markdown shape with autofix, then require human-owned state before saving or rendering.