Claude Code Plugins

Community-maintained marketplace

Feedback

pr-lifecycle

@codekiln/langstar
1
0

Enforce project hygiene throughout the PR lifecycle. Use before creating PRs to validate worktrees, branch naming, and issue linking. Use when creating PRs to ensure proper "Fixes #XYZ" keywords, conventional commit titles, and complete PR bodies. Use after PR merge for cleanup guidance and issue closure verification.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name pr-lifecycle
description Enforce project hygiene throughout the PR lifecycle. Use before creating PRs to validate worktrees, branch naming, and issue linking. Use when creating PRs to ensure proper "Fixes

PR Lifecycle Management

Enforce project hygiene throughout the pull request lifecycle. This skill provides checklists, validation commands, and templates to ensure PRs properly close issues and follow project conventions.

Critical Constraints - Session Statelessness

IMPORTANT: You are operating in a stateless session. Each Claude Code session is isolated.

You CANNOT:

  • Track issues across sessions
  • Remember to do something later
  • Follow up on tasks in the future
  • Promise to handle something "in a follow-up"

You MUST NOT say things like:

  • "I'll track this in a follow-up issue"
  • "I'll remember to fix this later"
  • "I'll handle this in a subsequent PR"

PR Comment Response Decision Framework

When addressing review comments, choose ONE of these options:

Option 1: Implement Now (Preferred)

When: Change is small-ish and worth doing. Action: Implement fix, commit, reply with: "Fixed in commit {sha}: {description}"

Option 2: Defer with Issue (Expensive - use sparingly)

When: Change is large AND worth doing AND not critical to PR. Action:

  1. Create GitHub issue NOW using gh issue create
  2. Add to same milestone as PR's issue
  3. Add as sub-issue using gh sub-issue add
  4. Reply: "Created #XYZ to track this. Not addressing in this PR because {reason}."

Option 3: Disagree / Won't Fix

When: Suggestion is nitpicky, negligible, or you disagree. Action: Reply explaining why not addressing. Be professional. NEVER use for: Test failures, errors, security concerns.

Overview

Project Hygiene Invariant: Each PR should:

  1. Close exactly one GitHub issue
  2. Include "Fixes #XYZ" (or similar keyword) in PR body
  3. Be created from a proper worktree using the .claude/skills/git-worktrees skill (you should not be in /workspace, which should always be kept up to date with origin main - instead you should be in wip/<feature branch>)
  4. Follow branch naming convention: m<milestone_id>-p<parent_issue_id>-i<issue_num>-<slug> (with appropriate variations)
  5. Use Conventional Emoji Commits for PR title

Why This Matters: PRs #221 and #222 didn't include "Fixes #XYZ" keywords, causing issues to remain open after merge. This skill prevents such "orphan PRs."

Tmux Window Naming Convention

When working in a tmux session, window names reflect the current PR lifecycle phase for quick visual reference.

Format: <emoji><prefix><number>

Prefix Conventions:

  • i = Issue number (e.g., ๐Ÿ’ปi483 = coding on issue #483)
  • pr = Pull request number (e.g., ๐Ÿ”งpr485 = maintaining PR #485)

Examples:

  • ๐Ÿ’ปi483 - Coding on issue #483
  • ๐Ÿš€i483 - Submitting PR for issue #483
  • ๐Ÿ”งpr485 - Maintaining PR #485
  • โณpr485 - Waiting for tests on PR #485

Phase Emojis:

Phase Emoji When Used Format Example Command
1. Gathering information ๐Ÿ” Research/discovery ๐Ÿ”i483 Manual
2. Coding ๐Ÿ’ป Active development ๐Ÿ’ปi483 /gh-start-issue
3. Waiting for tests โณ CI/CD checks running โณpr485 /pr-workflow
4. Waiting for user โ“ Needs input/clarification โ“i483 or โ“pr485 Manual
5. Submitting PR ๐Ÿš€ Creating/pushing PR ๐Ÿš€i483 /pr-workflow
6. PR maintenance ๐Ÿ”ง Addressing feedback/fixes ๐Ÿ”งpr485 /pr-workflow
7. Cleanup ๐Ÿงน Post-merge cleanup ๐Ÿงนpr485 Manual

Automatic Updates:

  • /gh-start-issue sets tmux to ๐Ÿ’ปi<issue_num> (coding phase on issue)
  • /pr-workflow updates tmux through phases:
    • ๐Ÿš€i<issue_num> โ†’ (PR created) โ†’ ๐Ÿ”งpr<pr_num> โ†’ โณpr<pr_num> โ†’ ๐Ÿ”งpr<pr_num>
    • Note: Transitions from issue number to PR number after PR is created

Manual Updates:

# Update tmux window name manually for issue work
ISSUE_NUM=<your_issue_number>
tmux rename-window "๐Ÿ”i${ISSUE_NUM}"  # Research phase on issue

# Update tmux window name manually for PR work
PR_NUM=<your_pr_number>
tmux rename-window "๐Ÿ”งpr${PR_NUM}"  # PR maintenance

Why This Convention:

  • Information density: Maximizes useful info in limited tmux window title space (5-7 chars vs 50+)
  • Clear distinction: Instantly know if you're working on issue or PR
  • Visual status: Emoji provides at-a-glance phase indication
  • WCAG compliance: Window title colors meet AAA accessibility standards (see .devcontainer/.tmux.conf)

Phase 1: Before Creating PR

Pre-PR Checklist

Run these validations before creating a PR:

# 1. Verify you're in a worktree (not main)
pwd | grep -q "wip/" && echo "In worktree" || echo "WARNING: Not in wip/ worktree"

# 2. Check branch name follows convention
BRANCH=$(git branch --show-current)
echo "Current branch: $BRANCH"
# Should match: m<id>-p<id>-i<num>-<slug> or variants (p<id>-i<num>-<slug>, i<num>-<slug>)

# 3. Extract issue number from branch (look for i<num> pattern)
ISSUE_NUM=$(echo "$BRANCH" | grep -oP 'i\K[0-9]+' || echo "$BRANCH" | grep -oE '[0-9]+' | head -1)
echo "Issue number: $ISSUE_NUM"

# 4. Verify issue exists and is open
gh issue view "$ISSUE_NUM" --json state,title

# 5. Check commits for "Fixes #" keyword
git log origin/main..HEAD --oneline | grep -i "fixes #\|closes #\|resolves #" || echo "WARNING: No 'Fixes #' keyword found in commits"

Validation Details

Worktree Verification

Why: Feature work should happen in worktrees, not the main worktree.

# List all worktrees
git worktree list

# Verify current directory is in wip/
pwd | grep -q "wip/" && echo "In worktree" || echo "WARNING: Not in wip/ worktree"

Expected: You should be in a wip/<branch-name>/ directory.

Branch Naming Convention

Format variations:

  • With milestone & parent: m<milestone_id>-p<parent_id>-i<issue_num>-<issue_slug>
  • With parent only: p<parent_id>-i<issue_num>-<issue_slug>
  • With milestone only: m<milestone_id>-i<issue_num>-<issue_slug>
  • Standalone: i<issue_num>-<issue_slug>

Examples:

  • m8-p123-i234-add-authentication
  • p123-i234-add-authentication
  • i42-add-authentication

Validation:

BRANCH=$(git branch --show-current)

# Check format: must contain i<number> pattern
if [[ "$BRANCH" =~ i[0-9]+ ]]; then
  echo "Branch name follows convention"
else
  echo "WARNING: Branch name '$BRANCH' doesn't follow convention (missing i<number>)"
fi

Issue Verification

Check issue exists and is open:

ISSUE_NUM=$(git branch --show-current | grep -oE '[0-9]+' | head -1)

# View issue details
gh issue view "$ISSUE_NUM" --json number,title,state,labels

# Verify it's open
STATE=$(gh issue view "$ISSUE_NUM" --json state -q '.state')
if [ "$STATE" = "OPEN" ]; then
  echo "Issue #$ISSUE_NUM is open"
else
  echo "WARNING: Issue #$ISSUE_NUM is $STATE"
fi

Commit Message Check

Verify commits reference the issue:

# Check for GitHub closing keywords in commits
git log origin/main..HEAD --pretty=format:"%s" | \
  grep -iE "(fix(es)?|close[sd]?|resolve[sd]?)\s*#\d+" || \
  echo "WARNING: No GitHub closing keywords found in commit messages"

GitHub closing keywords: close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved

Phase 2: Creating PR

PR Title Convention

Format: <emoji> <type>[scope]: <description>

Common Types:

Type Emoji Use For
feat โœจ New features
fix ๐Ÿฉน Bug fixes
docs ๐Ÿ“š Documentation
refactor โ™ป๏ธ Code refactoring
test ๐Ÿงช Tests
build ๐Ÿ”ง Build system
perf โšก๏ธ Performance
release ๐Ÿ”– Releases

Examples:

  • โœจ feat(cli): add deployment management commands
  • ๐Ÿฉน fix: resolve race condition in thread handler
  • ๐Ÿ“š docs: add PR lifecycle skill

PR Body Template

Always include "Fixes #XYZ" to auto-close the issue:

## Summary
<1-3 bullet points describing the changes>

## Changes
- <specific change 1>
- <specific change 2>

## Related Issues
Fixes #<issue_number>

## Test Plan
- [ ] <test item 1>
- [ ] <test item 2>

---
Generated with [Claude Code](https://claude.com/claude-code)

Adding PR to Milestone

If the issue that the PR fixes is part of a milestone, add the PR to that milestone.

Create PR Command

Using gh CLI with proper body:

ISSUE_NUM=$(git branch --show-current | grep -oE '[0-9]+' | head -1)

gh pr create \
  --title "โœจ feat: <description>" \
  --body "$(cat <<EOF
## Summary
- <summary point>

## Changes
- <change 1>
- <change 2>

## Related Issues
Fixes #$ISSUE_NUM

## Test Plan
- [ ] <test item>

---
Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"

Verify PR Will Close Issue

After creating PR, verify the link:

# Get PR number
PR_NUM=$(gh pr view --json number -q '.number')

# Check closing issues
gh pr view "$PR_NUM" --json closingIssuesReferences -q '.closingIssuesReferences[].number'

# Should output the issue number

Phase 3: After PR Creation

Monitor for Automated Reviews

Copilot and other automated reviewers may add comments. Monitor and address them:

PR_NUM=$(gh pr view --json number -q '.number')

# Get owner/repo dynamically from current repository
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)

# Check for Copilot comments (use --paginate to get ALL comments)
gh api repos/$REPO/pulls/$PR_NUM/comments --paginate \
  --jq '.[] | select(.user.login == "copilot") | {id, body, path, line}'

# Check for all review comments (use --paginate to get ALL comments)
gh api repos/$REPO/pulls/$PR_NUM/comments --paginate \
  --jq '.[] | {id, user: .user.login, body: .body[0:100]}'

Reply to Review Comments

After addressing feedback, reply with commit reference:

Note: Do not at-mention copilot in your reply, otherwise copilot will try to implement something.

PR_NUM=$(gh pr view --json number -q '.number')
COMMENT_ID=<comment_id>
COMMIT_SHA=$(git rev-parse --short HEAD)
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)

gh api repos/$REPO/pulls/$PR_NUM/comments/$COMMENT_ID/replies \
  -f body="Fixed in commit $COMMIT_SHA: <brief description>"

Check PR Status

PR_NUM=$(gh pr view --json number -q '.number')

# View PR checks
gh pr checks "$PR_NUM"

# View PR status
gh pr view "$PR_NUM" --json state,mergeable,reviewDecision

Phase 4: After PR Merge

Verify Issue Closure

Check if the issue was auto-closed:

ISSUE_NUM=<issue_number>

# Check issue state
STATE=$(gh issue view "$ISSUE_NUM" --json state -q '.state')
echo "Issue #$ISSUE_NUM state: $STATE"

if [ "$STATE" = "CLOSED" ]; then
  echo "Issue #$ISSUE_NUM was auto-closed"
else
  echo "WARNING: Issue #$ISSUE_NUM is still OPEN"
  echo "Manually close with: gh issue close $ISSUE_NUM"
fi

Manual Issue Closure (If Needed)

If the issue wasn't auto-closed:

Ask the user first before doing this:

ISSUE_NUM=<issue_number>
PR_NUM=<pr_number>

# Close with reference to PR
gh issue close "$ISSUE_NUM" --comment "Closed via PR #$PR_NUM"

Cleanup: Remove Worktree

After PR merge, clean up the worktree:

# Switch to main worktree first
cd /workspace

# Remove the worktree
WORKTREE_PATH="wip/<branch-name>"  # e.g., wip/i42-add-auth or wip/m8-p123-i234-add-auth
git worktree remove "$WORKTREE_PATH"

# Prune stale references
git worktree prune --verbose

Cleanup: Delete Branch

Delete local and remote branches:

BRANCH="<branch_name>"  # e.g., i42-add-auth or m8-p123-i234-add-auth

# Delete local branch
git branch -d "$BRANCH"

# If not fully merged, force delete
# git branch -D "$BRANCH"

# Delete remote branch (GitHub usually does this automatically)
git push origin --delete "$BRANCH" 2>/dev/null || echo "Remote branch already deleted"

Cleanup: Ensure /workspace is up to date

  • /workspace should be kept up to date with origin main
  • after merging, cd /workspace then ensure workspace is refreshed from origin main
    • in the unlikely case that another agent has put WIP in /workspace (instead of wip/<feature branch>) that would be affected by this action, ask user what to do

Complete Cleanup Workflow

# Variables
ISSUE_NUM=225
BRANCH="claude/225-pr-lifecycle-skill"
WORKTREE_PATH="wip/claude-225-pr-lifecycle-skill"

# 1. Verify issue closed
gh issue view "$ISSUE_NUM" --json state -q '.state'

# 2. Switch to main worktree
cd /workspace

# 3. Pull latest changes
git checkout main
git pull origin main

# 4. Remove worktree
git worktree remove "$WORKTREE_PATH"

# 5. Delete local branch
git branch -d "$BRANCH"

# 6. Prune
git worktree prune --verbose

# 7. Verify cleanup - should only show main worktree
git worktree list

# Show only non-main branches (should be empty after cleanup)
git branch | grep -v "^\*" | grep -v "main\|master"

Quick Reference

Pre-PR Checklist

Check Command Expected
In worktree pwd | grep wip/ In wip/ directory
Branch format git branch --show-current user/num-slug
Issue open gh issue view N --json state OPEN
Has "Fixes #" git log | grep -i "fixes #" Found keyword

GitHub Closing Keywords

Any of these in PR body will auto-close the linked issue:

  • close, closes, closed
  • fix, fixes, fixed
  • resolve, resolves, resolved

Format: Fixes #123 or Fixes owner/repo#123

PR Title Emojis

Emoji Type Triggers
โœจ feat MINOR bump
๐Ÿฉน fix PATCH bump
๐Ÿšจ BREAKING MAJOR bump
๐Ÿ“š docs No bump
โ™ป๏ธ refactor No bump
๐Ÿงช test No bump
๐Ÿ”ง build No bump
๐Ÿ”– release N/A

Common API Commands

# Get owner/repo for API calls
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)

# View issue
gh issue view <num> --json number,title,state

# View PR
gh pr view --json number,title,state,closingIssuesReferences

# PR comments (for reviews) - use --paginate to get ALL comments
gh api repos/$REPO/pulls/<num>/comments --paginate

# Reply to comment
gh api repos/$REPO/pulls/<num>/comments/<id>/replies -f body="message"

# Close issue manually
gh issue close <num> --comment "Closed via PR #N"

Integration with Other Skills

With git-worktrees Skill

Use git-worktrees skill to create proper worktrees before starting work:

# Create worktree for new issue
git worktree add -b alice/42-new-feature wip/alice-42-new-feature main

With gh-sub-issue Skill

For issues with parent-child relationships, verify PR targets:

# Check if issue has parent
gh sub-issue list 42 --relation parent

# If parent exists, PR should target parent branch, not main

Troubleshooting

"Issue not closed after merge"

Cause: Missing "Fixes #N" keyword in PR body.

Solution:

# Close manually
gh issue close <num> --comment "Closed via PR #<pr_num>"

# Prevent future issues: always include "Fixes #N" in PR body

"Branch name doesn't match issue"

Cause: Branch created without following convention.

Solution: Rename branch before PR:

git branch -m old-name i42-proper-name
git push origin -u i42-proper-name
git push origin --delete old-name

"Can't determine issue number"

Cause: Branch name doesn't contain issue number.

Solution: Check branch name, rename if needed:

git branch --show-current
# If no number, rename branch to include issue number

"PR shows wrong closing issues"

Cause: Wrong issue number in PR body.

Solution: Edit PR body on GitHub or:

gh pr edit <num> --body "$(cat updated-body.md)"

See Also