Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"name": "pr-flow",
"source": "./plugins/pr-flow",
"description": "PR review feedback loop for Claude Code. Create PRs with readiness checks, commit + push + trigger @claude review, inspect status, and work through review issues interactively.",
"version": "1.2.0"
"version": "1.2.1"
}
]
}
2 changes: 1 addition & 1 deletion plugins/pr-flow/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "pr-flow",
"description": "PR review feedback loop for Claude Code. Create PRs with readiness checks, commit + push + trigger @claude review, inspect status, and work through review issues interactively.",
"version": "1.2.0",
"version": "1.2.1",
"author": {
"name": "gering"
},
Expand Down
2 changes: 1 addition & 1 deletion plugins/pr-flow/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ If a clear pattern emerges (e.g. 18 of 20 last PRs were squashed), `/merge` sugg

### Pre-merge documentation check

**What it does.** Before executing a merge, `/merge` runs a readiness pass: checks the README for staleness, verifies a version bump happened if the branch mentions version changes, checks for a changelog entry, checks knowledge-system entries for new patterns. On warnings, it asks: `[f]ix / [m]erge anyway / [a]bort`.
**What it does.** Before executing a merge, `/merge` runs a readiness pass: checks the README for staleness, verifies a version bump happened if the branch mentions version changes, checks for a changelog entry, checks knowledge-system entries for new patterns. On warnings, it asks: `[f]ix / [m]erge anyway / [a]bort`. The same four checks run pre-PR in `/open` — both skills read their definitions from a **single shared spec** (`docs/READINESS-CHECKS.md`), so the heuristics can't drift apart. Only the stage behavior differs: `/open` auto-resolves fixes in place, `/merge` inspects read-only and defers the fix to the `[f]` choice.

**Why it matters.** The right moment to update docs is at merge time, not "later." The three-way prompt keeps you in the loop without being paternalistic.

Expand Down
133 changes: 133 additions & 0 deletions plugins/pr-flow/docs/READINESS-CHECKS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Shared Documentation-Readiness Checks

> Canonical definitions for the four documentation-readiness checks shared by
> `/open` (pre-PR, step 3c–3f) and `/merge` (pre-merge, step 8): README
> freshness, version bump, changelog, knowledge/conventions. Defines the
> detection signals, the ✅/⚠️/❌/➖ semantics, and the auto-fixable vs. manual
> split. Consumers add only their stage-specific behavior — they do not
> redefine the checks here.

## Status semantics

Every check resolves to exactly one of:

- ✅ **pass** — requirement met, or correctly not applicable to *these* changes
- ⚠️ **warning** — a gap that needs a decision (auto-fix or accept). These
doc checks emit ⚠️, never ❌ — a stale doc never hard-blocks.
- ➖ **N/A** — the project doesn't use this convention; nothing to check
- ❌ **blocker** — reserved; the documentation checks do not produce blockers

## Shared inputs

All four checks read the branch diff against the base:

git diff origin/<BASE_BRANCH>...HEAD --name-only

- **User-facing changes** — the diff touches user-visible code (`src/`,
`lib/`, `plugins/`, `skills/`, public entry points), or commit messages
describe `feat` / `fix` / `breaking`.
- **Internal only** — tests, configs, refactors, comments. Internal-only
changes resolve every check below to ✅ ("no action needed").

## The checks

### 3c · README freshness — *manual*

- **Signal:** user-facing code changed, but `README.md` itself was not
touched. Other `*.md` files (CONTRIBUTING, CHANGELOG, …) do **not** count as
a README update.
- ✅ `README.md` was touched, or changes are internal only
- ⚠️ "Code changed but docs untouched — README may be stale"
- ➖ no `README.md` exists
- **Classification: manual** — prose can't be auto-written; needs human
judgment about what to document.

### 3d · Version bump — *auto-fixable*

- **First detect whether the project versions releases** (warn only if it
does). Any of:
- `package.json` / `plugin.json` / `Cargo.toml` / `pyproject.toml` /
`*.csproj` with a version field that changed in the last ~10 commits
- semver git tags: `git tag --sort=-v:refname | head -5`
- `.changeset/`, `release-please` config, or similar release automation
- **No versioning signal** → ➖ "N/A (project does not appear to version
releases)"
- **Versioned** — check the diff for a bump:
`git diff origin/<BASE_BRANCH>...HEAD -- '**/package.json' '**/plugin.json' '**/Cargo.toml' '**/pyproject.toml'`
- ✅ version was bumped — "Version bumped to <new>"
- ✅ not bumped, changes internal only — "No bump needed (internal)"
- ⚠️ not bumped, changes user-facing → "Version bump may be needed.
Detected: <feat|fix|breaking>. Suggest: <patch|minor|major>"
- **Monorepo / multi-package awareness:** if several version files exist
(e.g. each plugin's `plugin.json` + a root `marketplace.json`), check which
one(s) the diff affects and remind per package — keep them in sync.
- Respect repo-specific semver conventions from memory / CLAUDE.md (e.g.
"patch for small changes, minor for new features").
- **Classification: auto-fixable** — bump the detected field(s) per the
suggestion; update every in-sync file together.

### 3e · Changelog — *auto-fixable*

- **Detect presence:** `CHANGELOG.md`, `CHANGELOG`, `HISTORY.md`,
`RELEASES.md`, `docs/changelog/`, `.changeset/`
- **None** → ➖ "N/A (no changelog)"
- **Exists** — check whether it was updated on this branch:
`git diff origin/<BASE_BRANCH>...HEAD --name-only | grep -iE '(changelog|history|releases|\.changeset/)'`
- ✅ updated, or changes internal only
- ⚠️ not updated, changes user-facing → "Changelog unchanged — add an
entry for this PR". Suggest the section from the change type: `feat` →
Added, `fix` → Fixed, `breaking` → Changed/Removed.
- **Link to version bump (3d):** if the version bumped but the changelog
didn't (or vice versa), flag the inconsistency explicitly.
- **Classification: auto-fixable** — draft an entry under the unreleased /
next-version heading (use Keep-a-Changelog sections if that format is
detected from headings).

### 3f · Knowledge / conventions — *auto-fixable*

- **Detect a conventions/knowledge location** (system-agnostic — any of):
- `.claude/knowledge/`, `.claude/rules/` (gering `knowledge-system`)
- `.cursor/rules/`, `.cursorrules` (Cursor)
- `.github/copilot-instructions.md` (Copilot)
- `AGENTS.md`, `CONVENTIONS.md`, `CONTRIBUTING.md`
- `docs/adr/`, `docs/decisions/` (ADRs)
- `CLAUDE.md` with documented conventions beyond setup
- **None** → ➖ "N/A (no knowledge/convention system detected)"
- **Exists** — does the branch introduce **new patterns, conventions, or
generalizable fixes**? Heuristic: commit messages like "add <pattern>",
"refactor to <approach>", "fix <recurring bug>", or many similar files
changed the same way.
- ✅ knowledge location was touched — "Conventions documented"
- ✅ nothing generalizable — "No new patterns to capture"
- ⚠️ new patterns likely but knowledge location untouched → "Knowledge gap"
- **Auto-fix target:** if `knowledge-system` is detected, invoke `/curate`
with the detected pattern; otherwise append to the closest topical file
(fallback: the generic `AGENTS.md` / `CONVENTIONS.md`).
- **Classification: auto-fixable** — unless the new pattern *conflicts* with
an existing documented rule, which needs judgment (then it's a manual ⚠️).

## Auto-fixable vs. manual — summary

| Check | Classification | Auto-fix action |
|---|---|---|
| 3c README freshness | manual | — (human writes the prose) |
| 3d Version bump | auto-fixable | bump version field(s); keep multi-package in sync |
| 3e Changelog | auto-fixable | draft entry under unreleased / next-version heading |
| 3f Knowledge / conventions | auto-fixable | `/curate`, or append to closest knowledge file |

## How consumers apply this

The checks above are identical for both skills. **Only the stage behavior
differs** — that, and nothing else, lives in the skills:

- **`/open` step 3c–3f (pre-PR) — auto-resolve in place.** Per its
"auto-resolve warnings where feasible" principle, `/open` applies each
**auto-fixable** fix *immediately during the check phase* (bump the
version, draft the changelog entry, `/curate` the knowledge gap) so it
rarely surfaces as a warning. Only **manual** gaps (README) and fixes that
genuinely need judgment reach the step-4 decision as ⚠️.
- **`/merge` step 8 (pre-merge) — read-only.** `/merge` **never mutates
here.** It collects every ⚠️ into `DOC_WARNINGS` (tagged auto-fixable vs.
manual) and surfaces them in the final plan (step 13), where the user picks
`[f]` fix / `[m]` merge anyway / `[a]` abort. Auto-fix runs only after `[f]`
— and then commits locally + hands off to `/cycle`, never pushing directly.
20 changes: 11 additions & 9 deletions plugins/pr-flow/skills/merge/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,17 @@ user_invocable: true
- Count open blocking issues
- If > 0 → ⚠️ warn explicitly, require explicit confirmation before merging. **Do not silently ignore.**

8. **Documentation readiness** (read-only at this stage — mirrors `/open` checks 3c-3f):
- Compare branch diff against base: `git diff origin/<BASE_BRANCH>...HEAD --name-only`
- **README freshness**: user-visible code changed (`src/`, `lib/`, `plugins/`, `skills/`, public entry points) but `README.md` itself was not touched → ⚠️ "README may be stale" (manual — cannot auto-write). Changes to other `*.md` files (CONTRIBUTING, CHANGELOG, etc.) do not count as a README update.
- **Version bump**: if project versions releases (`package.json`/`plugin.json`/`Cargo.toml`/`pyproject.toml` with version field + git tags or recent bump commits) AND no version field bumped on this branch AND changes look user-facing (feat/fix/breaking from commit messages) → ⚠️ "Version not bumped" with suggestion (patch/minor/major). Auto-fixable.
- **Changelog**: if `CHANGELOG.md`/`HISTORY.md`/`.changeset/` exists AND not touched on this branch AND changes are user-facing → ⚠️ "Changelog missing entry". Auto-fixable (draft entry).
- **Knowledge/conventions**: detect any knowledge location (`.claude/knowledge/`, `.cursor/rules/`, `AGENTS.md`, `CONVENTIONS.md`, `docs/adr/`, etc.). If new patterns detected (via commit-message heuristic from `/open` step 3f) AND knowledge location not touched → ⚠️ "Knowledge gap". Auto-fixable.
- Categorize each finding as **auto-fixable** (version, changelog, knowledge) or **manual** (README).
- Collect warnings into `DOC_WARNINGS` — surface them in the final plan (step 13) and handle user decision there.
- **Do not mutate anything here** — this is read-only inspection.
8. **Documentation readiness** (read-only at this stage):
- Run the four documentation-readiness checks defined in the shared spec at
`${CLAUDE_PLUGIN_ROOT}/docs/READINESS-CHECKS.md` (README freshness, version
bump, changelog, knowledge/conventions) — **read that file** for the
detection signals, the ✅/⚠️/❌/➖ semantics, and the auto-fixable vs.
manual classification.
- **Merge-specific behavior — read-only.** **Do not mutate anything here.**
Collect each ⚠️ into `DOC_WARNINGS`, tagged with its classification
(auto-fixable vs. manual). These surface in the final plan (step 13),
where the user's `[f]` choice triggers the actual auto-fix — keeping this
step cheap if the user later picks `[m]` to skip it.

9. **Detect merge method** (priority order):
- **a) Repo allowed methods** — `gh api repos/:owner/:name --jq '{merge: .allow_merge_commit, squash: .allow_squash_merge, rebase: .allow_rebase_merge}'`
Expand Down
70 changes: 17 additions & 53 deletions plugins/pr-flow/skills/open/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,59 +52,23 @@ user_invocable: true
### 3b. Unpushed commits (for branch-existence check later)
- Run: `git log @{u}..HEAD --oneline 2>/dev/null` — fine if it errors (upstream may not exist yet)

### 3c. README freshness heuristic
- Run: `git diff origin/<BASE_BRANCH>...HEAD --name-only`
- If the diff touches user-visible code (`src/`, `lib/`, `plugins/`, `skills/`, public entry points) but NOT `README.md` or `*.md` → ⚠️ "Code changed but docs untouched — README may be stale"
- If `README.md` WAS touched → ✅
- If only internal changes (tests, configs, refactors) → ➖ "N/A"

### 3d. Version bump reminder (only if versioning is an established convention)
- **First detect whether this project versions releases** — do NOT warn on projects that don't. Signals:
- `package.json` has a `version` field AND git log shows prior version bumps (e.g. commits like "bump to 1.2.3", "v1.2.3", or version-field changes in recent history)
- `plugin.json` / `pyproject.toml` / `Cargo.toml` / `*.csproj` with a version field that has changed in the last ~10 commits
- Git tags following semver (`git tag --sort=-v:refname | head -5`)
- `.changeset/` directory, `release-please` config, or similar release-automation
- If **no** versioning signal → ➖ "N/A (project does not appear to version releases)"
- If versioning is used:
- Check whether any version field was bumped on this branch vs. base:
`git diff origin/<BASE_BRANCH>...HEAD -- '**/package.json' '**/plugin.json' '**/Cargo.toml' '**/pyproject.toml'`
- If version was bumped → ✅ "Version bumped to <new>"
- If NOT bumped AND the changes look user-facing (new feature, bug fix, breaking change — inferred from commit messages/diff) → ⚠️ "Version bump may be needed. Detected: <feat|fix|breaking>. Suggest: <patch|minor|major>"
- If NOT bumped AND changes are internal only (tests, docs, refactor) → ✅ "No bump needed (internal changes)"
- **Monorepo / multi-package awareness**: if multiple version files exist (e.g. this marketplace's `plugin.json` per plugin + root `marketplace.json`), check which one(s) are affected by the diff and remind per-package
- Respect any repo-specific semver conventions found in memory/CLAUDE.md (e.g. "patch for small changes, minor for new features")

### 3e. Release notes / changelog (only if the project maintains one)
- Detect presence: `CHANGELOG.md`, `CHANGELOG`, `HISTORY.md`, `RELEASES.md`, `docs/changelog/`, `.changeset/`
- If none exist → ➖ "N/A (no changelog)"
- If a changelog exists:
- Check whether it was updated on this branch: `git diff origin/<BASE_BRANCH>...HEAD --name-only | grep -iE '(changelog|history|releases|\.changeset/)'`
- If updated → ✅ "Changelog updated"
- If NOT updated AND changes look user-facing → ⚠️ "Changelog unchanged — add an entry for this PR"
- Also suggest the section: did the version bump (2d) indicate `feat` → Added, `fix` → Fixed, `breaking` → Changed/Removed?
- If the changelog follows Keep-a-Changelog format (detect by headings), offer: "Want me to draft an entry?"
- If internal only → ✅ "No changelog entry needed (internal changes)"
- Link 2d ↔ 2e: if version bumped but changelog not, or vice versa, flag the inconsistency explicitly

### 3f. Project knowledge / conventions (system-agnostic)
- Detect whether the project maintains a place for conventions, rules, or learnings. Any of:
- `.claude/knowledge/`, `.claude/rules/` (gering `knowledge-system`)
- `.cursor/rules/`, `.cursorrules` (Cursor)
- `.github/copilot-instructions.md` (Copilot)
- `AGENTS.md`, `CONVENTIONS.md`, `CONTRIBUTING.md`
- `docs/adr/`, `docs/decisions/` (ADRs)
- `CLAUDE.md` with documented conventions beyond setup
- If none detected → ➖ "N/A (no knowledge/convention system detected)"
- If detected:
- Check if this branch introduces **new patterns, new conventions, or generalizable fixes** (heuristic: commit messages like "add <new pattern>", "refactor to <new approach>", "fix <recurring bug>", or many similar files changed the same way)
- If knowledge location WAS touched → ✅ "Conventions documented"
- If nothing generalizable → ✅ "No new patterns to capture"
- If likely AND the knowledge location was NOT touched:
- **Auto-update the relevant file** — read the relevant knowledge file, draft the entry based on the branch changes, write the update
- If project uses `knowledge-system` specifically → invoke `/curate` automatically with the detected pattern as input
- Otherwise → directly edit the most relevant file (closest topical match, or the generic `AGENTS.md`/`CONVENTIONS.md` as fallback)
- Result: ✅ "Knowledge updated: `<file>` (added: <short-description>)"
- Only fall back to ⚠️ if the update genuinely requires judgment beyond mechanical doc-addition (e.g. the pattern conflicts with existing documented rules)
### 3c–3f. Documentation readiness (README, version, changelog, knowledge)
Run the four documentation-readiness checks defined in the shared spec at
`${CLAUDE_PLUGIN_ROOT}/docs/READINESS-CHECKS.md` — **read that file** for
the detection signals, the ✅/⚠️/❌/➖ semantics, and the auto-fixable vs.
manual classification. Do not re-derive the heuristics here; the spec is
canonical.

**Open-specific behavior — auto-resolve in place.** Per the "auto-resolve
warnings where feasible" principle (top of this skill), apply each
**auto-fixable** fix *immediately during this check phase* rather than
surfacing it as a warning:
- **Version** → bump the detected field(s) per the spec's suggestion
- **Changelog** → draft the entry under the unreleased / next-version heading
- **Knowledge** → invoke `/curate` (knowledge-system) or append to the closest knowledge file
After resolving, mark the check ✅ "<auto-fixed>". Only **manual** gaps
(README staleness) and fixes that genuinely need judgment remain as ⚠️ for
step 4.

### 3g. Tests
- Detect test command (check in order):
Expand Down
Loading