kramme-cc-workflow/skills/kramme:pr:verify-description/SKILL.md
Compare an existing PR's title and body against the actual branch diff and report drift — false claims, missing major changes, stale scope, missing risk callouts. Use after pushing changes to a branch with an open PR, or before requesting review. Read-only by default; add --fix to delegate to kramme:pr:generate-description for an updated description. Complements kramme:pr:code-review (which checks description accuracy as one signal among many code-quality checks) by being a fast, focused, single-purpose check that runs in seconds.
npx skillsauth add abildtoft/kramme-cc-workflow kramme:pr:verify-descriptionInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Parse $ARGUMENTS for flags:
--fix: After reporting drift, ask the user once whether to delegate to kramme:pr:generate-description --auto to regenerate and update the PR body. Default is report-only.--base <ref>: Use <ref> as the base branch for diff computation instead of auto-detecting.--strict: Tighten the accuracy bar. Flag every bullet in the description that cannot be tied to a diff hunk. Default mode is loose — only contradictions, material omissions, and missing risk callouts surface.Set FIX_MODE=true / BASE_BRANCH_OVERRIDE=<ref> / STRICT_MODE=true from the flags and remove each flag (and its value) from remaining arguments.
Use this skill when:
When NOT to use this skill:
kramme:pr:generate-description to draft one instead.kramme:pr:code-review (it includes description accuracy as one of many checks).kramme:pr:generate-description --auto directly.This skill is single-purpose: it answers "does the PR body honestly describe the current diff?" It does not review code quality, suggest implementation changes, or rewrite the description on its own.
Classify each potential drift point against the rubric below. Severity drives the verdict; mode controls which severities surface in the report.
| Drift type | Severity | Visible in loose mode |
| --- | --- | --- |
| Body contradicts diff (flag default flipped, "no migration" claim refuted, "no breaking changes" claim with a rename in the diff) | Critical | Yes |
| Undisclosed migration, breaking API rename, missing required migration note, or new required env var | Critical | Yes |
| Undisclosed SemVer-major implication, or body claims no breaking changes when a versioned artifact surface or durable public contract breaks | Critical | Yes |
| Undisclosed new endpoint, dependency, feature flag, or removed code path | Important | Yes |
| Versioned artifact or durable public contract change lacks release impact, SemVer, changelog, or migration story needed for release-note accuracy | Important | Yes |
| Potential concerns: None despite a migration, flag flip, partial coverage, or known follow-up | Important | Yes |
| Stale claim — body describes work that was removed or refactored away | Important | Yes |
| Things I didn't touch excludes adjacent work the diff did touch | Important | Yes |
| Title Conventional Commit type wrong for the dominant change (fix: for a feature addition) | Important | Yes |
| Title type defensible but not ideal for a mixed change (refactor: vs feat:) | Suggestion | Strict only |
| Per-area technical notes missing when 3+ areas changed | Suggestion | Strict only |
| Test Plan missing manual scenarios when reviewer-visible UI changed | Suggestion | Strict only |
| Body claim cannot be traced to a specific diff hunk | Suggestion | Strict only |
| Wording, tone, polish, bullet ordering, formatting | Not flagged | Never |
| Description shorter than the diff (concise but accurate) | Not flagged | Never |
| Missing Linear ID link | Side note in report header | Not a finding |
Severity definitions — apply to new drift types not enumerated above:
ALWAYS confirm the gh CLI is installed and authenticated before any other step:
if ! command -v gh > /dev/null; then
echo "MISSING REQUIREMENT: gh CLI not installed. Install from https://cli.github.com." >&2
exit 1
fi
if ! gh auth status > /dev/null 2>&1; then
echo "MISSING REQUIREMENT: gh CLI not authenticated. Run \`gh auth login\` first." >&2
exit 1
fi
Confirm the current branch:
git branch --show-current
Resolve the base branch with the shared plugin script. It uses the same 3-tier strategy: explicit --base override, PR target branch, then origin/HEAD/origin/main/origin/master. It runs in strict mode, so fetch failures stop the workflow with the script's stderr message instead of being silently swallowed:
RESOLVE_ARGS=(--strict)
[ -n "${BASE_BRANCH_OVERRIDE:-}" ] && RESOLVE_ARGS+=(--base "$BASE_BRANCH_OVERRIDE")
RESOLVED=$("${CLAUDE_PLUGIN_ROOT}/scripts/resolve-base.sh" "${RESOLVE_ARGS[@]}") || {
echo "Error: Could not resolve base branch; see the message above. Re-run with --base <ref>." >&2
exit 1
}
eval "$RESOLVED"
The script exports BASE_REF, BASE_BRANCH, and MERGE_BASE for the diff commands in Phase 2.
ALWAYS confirm a PR exists for the current branch and is in an open state:
gh pr view --json number,url,title,body,baseRefName,headRefName,state
If no PR exists, stop with:
MISSING REQUIREMENT: no PR found for the current branch.
Run `/kramme:pr:create` or `/kramme:pr:generate-description` first.
If state is not OPEN (i.e. MERGED or CLOSED), warn but continue — verifying a merged PR's drift is occasionally useful (e.g. when preparing a follow-up). Prepend a PR state: <STATE> (verification on non-open PR) line to the report header so the user notices.
Capture PR_NUMBER, PR_URL, PR_TITLE, PR_BODY, PR_STATE for downstream phases.
Get the branch diff against the base:
git diff origin/$BASE_BRANCH...HEAD
git diff origin/$BASE_BRANCH...HEAD --stat
git log origin/$BASE_BRANCH..HEAD --format="%h %s%n%b%n"
Include local uncommitted work in the diff scope (the PR body should match what will be on the branch after the next push):
git status --porcelain
git diff HEAD # staged + unstaged
If local changes exist, ALWAYS note this in the report header (Local uncommitted changes included in scope: <N> files). If they're substantial and the user is verifying "after pushing", warn them that the comparison includes work not yet on the remote.
Categorize changed files for the rubric:
Walk the description body section-by-section and the diff in parallel. Classify each potential drift point against the rubric in ## Scope and Rubric above. For each finding, record:
## Summary, ### Potential concerns, Title) or PR description if global.Contradiction, Material omission, Stale claim, Missing risk callout, Scope misrepresentation, Title drift).kramme:pr:generate-description --auto".For diffs that change a versioned artifact surface or durable public contract, verify that the body either states the release impact or explicitly explains why there is no versioned consumer contract. Flag undisclosed SemVer implications, missing migration/upgrade notes for breaking changes, missing curated changelog/release-note expectations, and release-impact claims that are not supported by the diff or gathered PR context.
In loose mode, suppress any finding whose rubric row says "Strict only" or "Never". In --strict mode, surface those too.
Present an inline report (do not write a separate file). Use this structure:
# PR Description Verification — #<PR_NUMBER>
**PR:** <PR_URL>
**Title:** <current title>
**Base:** <BASE_BRANCH> · **Head:** <current branch>
**Mode:** loose | strict
**PR state:** <STATE> (only show this line when state is not OPEN)
**Local uncommitted changes included in scope:** <N> files (only show when N > 0)
## Verdict
**VERDICT_TAG:** ACCURATE | MINOR_DRIFT | MATERIAL_DRIFT | INACCURATE
<prose verdict: "Accurate" | "Minor drift" | "Material drift" | "Inaccurate — do not merge as-is">
## Findings
### Critical
- **[Type]** *(Location)* — <one-sentence summary>
- Body says: "<quoted or paraphrased>"
- Diff shows: <evidence with file paths>
- Fix: <concrete recommendation>
### Important
(same structure)
### Suggestions
(only emitted in --strict mode)
## Not flagged (loose-mode skips)
- <one line per skipped potential issue with a brief reason, e.g. "Wording in summary is dry but accurate">
- <rank by closest-to-flagging; if list grows past ~8 entries, truncate the tail with "+<N> more low-signal skips">
## Next steps
- <if no findings: "Description matches the diff. Safe to request review.">
- <if findings: numbered list of fix options, ending with "Run `/kramme:pr:verify-description --fix` to regenerate via kramme:pr:generate-description --auto">
ALWAYS include both the VERDICT_TAG: line (for tooling) and the prose verdict line. Map findings to verdict like this:
| Highest finding severity | VERDICT_TAG | Prose verdict |
| --- | --- | --- |
| No findings | ACCURATE | Accurate |
| Only Suggestions | MINOR_DRIFT | Minor drift |
| Important (no Critical) | MATERIAL_DRIFT | Material drift |
| Any Critical | INACCURATE | Inaccurate — do not merge as-is |
Skip this phase if FIX_MODE is not set.
If FIX_MODE=true and at least one Important or Critical finding was reported, ask the user once:
Found <N> finding(s). Regenerate the PR description by running
`/kramme:pr:generate-description --auto`? [y/N]
y: invoke the kramme:pr:generate-description skill with --auto (it will detect the existing PR and update it directly). Then re-run Phase 1-4 of this skill to verify the regenerated body actually resolves the findings — if any Critical or Important finding persists, report it and stop.n or no response: stop. Print the report and exit.FIX_MODE=true but the verdict was Accurate, do not prompt — just confirm "Nothing to fix."kramme:pr:generate-description is not available in this environment, report the drift findings only, note MISSING REQUIREMENT: kramme:pr:generate-description not installed; --fix unavailable, and stop. Do not attempt to rewrite the PR body manually.NEVER invoke kramme:pr:generate-description automatically without the y/N confirmation, even in FIX_MODE. The user opted into fixing, not into a silent rewrite.
Use these uppercase markers in the report (and in conversation output around it) so the user can audit decisions:
UNVERIFIED: body says "matches behavior on staging" — cannot validate from diff.CONFUSION: body says "flag defaults OFF" but flag definition sets default=true.Not flagged line in the report). NOTICED BUT NOT TOUCHING: title says "fix" but change is small enough that "fix" is defensible.MISSING REQUIREMENT: no open PR for current branch.Watch for these — each one means a finding is about to be wrongly suppressed:
Potential concerns block is the contract; visible-in-diff does not equal disclosed.fix but it's basically a fix." → Conventional Commit type drives changelogs and release notes. If the dominant change is a feature, the title is wrong regardless of how the author thinks of it.Things I didn't touch: None is fine — the author probably considered it." → Only fine when nothing adjacent was changed. If the diff touches adjacent files, the block needs an entry.Pause and re-examine the diff if any of these are true while drafting the report:
Accurate but the diff contains a migration, feature-flag default, or breaking change.Accurate but the diff changes a versioned artifact surface or durable public contract such as a public API, package, CLI, integration contract, or schema, and the body has no release impact, SemVer, changelog, or migration story.Not flagged entries than Findings — that usually means the bar is set too low; reconsider whether several of the skipped items are actually material.kramme:pr:generate-description --auto without explicit user confirmation.Accurate and stop.Before presenting the report, self-check:
gh CLI was confirmed installed and authenticated; missing-tool exit was clean (MISSING REQUIREMENT), not an opaque stderr dump.MISSING REQUIREMENT message rather than improvising.origin/$BASE_BRANCH was fetched successfully.## Scope and Rubric — Critical is reserved for merge-blocking misinformation.--strict.VERDICT_TAG: and the prose verdict are present and match the highest finding severity.--fix flow asked for y/N confirmation before delegating to kramme:pr:generate-description, and stopped cleanly if the sibling skill is unavailable.kramme:pr:code-review's job.--fix delegation, which itself requires explicit user confirmation.kramme:pr:code-review, which checks description accuracy as one signal among many. Use this skill when you only need the description check and want it fast; use pr:code-review when you want a full quality pass.tools
Requires Linear MCP. Implements one Linear issue end to end, selects applicable code-review, convention, and PR-refactor gates, runs them to bounded convergence, verifies, and optionally opens the PR and iterates on CI and review feedback until green. Use when the user wants a single Linear issue taken from implementation through a clean Pull Request. Not for implementation-only work, SIW-tracked issues, stacked PRs, existing PR updates, or post-merge rollout.
development
Reviews PR and local changes for convention drift and overcaution against documented rules and mined peer-file practice. Use for new patterns, dependencies, abstractions, or defensive complexity that departs from established practice; every finding cites evidence. Supports --inline. Not for general code quality (use kramme:pr:code-review) or spec review (use kramme:siw:spec-audit --team).
testing
Charts huge or foggy initiatives into a local `.context` decision map and resolves one typed frontier ticket per session until the work is ready for SIW or another execution workflow. Use when the route to a destination cannot fit in one agent session or parallel workspaces need coordinated planning state. Not for clear specs, ordinary issue decomposition, implementation, or Linear-native tracking.
development
Investigates a question against primary sources and saves one cited Markdown artifact. Use for reading legwork: official docs/API facts, source-code or spec checks, standards, and first-party service behavior before planning or implementation. Not for making product or architecture decisions, implementing code, broad web search, secondary blog summaries, or uncited answers.