From data-science
Creates draft PR from current branch, pushes if needed, waits for CI checks to pass then marks ready for review; auto-triggers /fix-pr if fails.
npx claudepluginhub policyengine/policyengine-claude --plugin data-science# Creating PR with CI Verification **IMPORTANT:** This command solves the common problem where Claude creates a PR, says "I'll wait for CI", then gives up. This command ACTUALLY waits for CI completion. ## Workflow This command will: 1. ✅ Create PR as draft 2. ✅ Wait for CI checks to complete (actually wait, not give up) 3. ✅ Mark as ready for review if CI passes 4. ✅ **Automatically trigger /fix-pr if CI fails** (new!) ## Step 1: Determine Current Branch and Changes ## Step 2: Gather PR Context Run in parallel to gather information: **If PR already exists:** ## Step 3: Create ...
/create-prCreates GitHub pull requests after user-selected validation (feature: security/quality/tests; bugfix/refactor: targeted checks; quick: direct), with incremental status updates.
/prp-prCreates GitHub PR from current branch with unpushed commits. Discovers templates, analyzes changes/files, pushes branch, fills body. Optional base-branch (default: main).
/pr-shepherdMonitors specified PR (or current branch) until merge-ready by polling CI/CD every 60s, auto-fixing simple issues, handling reviews, and resolving threads.
/prp-prCreates a GitHub pull request from current branch's unpushed commits to specified or auto-detected base branch, validating prerequisites and using repo PR templates.
/SKILLCreates a GitHub pull request with automated quality validation, security scanning, issue linking, and compliance checks. Accepts optional description or issue reference.
Share bugs, ideas, or general feedback.
IMPORTANT: This command solves the common problem where Claude creates a PR, says "I'll wait for CI", then gives up. This command ACTUALLY waits for CI completion.
This command will:
# Get current branch
CURRENT_BRANCH=$(git branch --show-current)
# Get base branch (usually main or master)
BASE_BRANCH=$(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5)
# Verify we're not on main/master
if [[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]]; then
echo "ERROR: Cannot create PR from main/master branch"
echo "Create a feature branch first: git checkout -b feature-name"
exit 1
fi
# Check if branch is pushed
git rev-parse --verify origin/$CURRENT_BRANCH > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Branch not pushed yet. Pushing now..."
git push -u origin $CURRENT_BRANCH
fi
Run in parallel to gather information:
# 1. Git status
git status
# 2. Diff since divergence from base
git diff ${BASE_BRANCH}...HEAD
# 3. Commit history for this branch
git log ${BASE_BRANCH}..HEAD --oneline
# 4. Check if PR already exists
gh pr view --json number,state,isDraft 2>/dev/null
If PR already exists:
EXISTING_PR=$(gh pr view --json number --jq '.number')
echo "PR #$EXISTING_PR already exists for this branch"
echo "Use /review-program $EXISTING_PR or /fix-pr $EXISTING_PR instead"
exit 0
Based on the changes (read from git diff and commit history):
Title: Concise summary of changes (50 chars max)
Body format:
## Summary
- Bullet point 1
- Bullet point 2
## Changes
- Specific change 1
- Specific change 2
## Testing
- Test approach
- Verification steps
## Checklist
- [ ] Tests pass locally
- [ ] Code formatted (make format)
- [ ] Changelog entry created (if applicable)
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL: Always create as draft initially.
# Create PR as draft
# CRITICAL: Use --repo flag to create PR in upstream repo from fork
# This creates cross-fork PR: your-fork:branch → PolicyEngine:master
gh pr create --repo PolicyEngine/policyengine-us \
--title "PR Title Here" \
--body "$(cat <<'EOF'
PR body here
EOF
)" \
--draft
# Get PR number
PR_NUMBER=$(gh pr view --json number --jq '.number')
echo "Created draft PR #$PR_NUMBER"
echo "URL: $(gh pr view --json url --jq '.url')"
This is where Claude usually fails. DO NOT say "I'll check back later".
Instead, ACTUALLY wait using a polling loop with NO timeout:
echo "Waiting for CI checks to complete..."
echo "Typical CI times by repository:"
echo " - policyengine-app: 3-6 minutes"
echo " - policyengine-uk: 9-12 minutes"
echo " - policyengine-api: 30 minutes"
echo " - policyengine-us: 60-75 minutes (longest)"
echo ""
echo "I will poll every 15 seconds until all checks complete. No time limit."
POLL_INTERVAL=15 # Check every 15 seconds
ELAPSED=0
while true; do
# Get check status
CHECKS_JSON=$(gh pr checks $PR_NUMBER --json name,status,conclusion)
# Count checks
TOTAL=$(echo "$CHECKS_JSON" | jq '. | length')
if [ "$TOTAL" -eq 0 ]; then
echo "No CI checks found yet. Waiting for checks to start..."
sleep $POLL_INTERVAL
ELAPSED=$((ELAPSED + POLL_INTERVAL))
continue
fi
# Count by status
COMPLETED=$(echo "$CHECKS_JSON" | jq '[.[] | select(.status == "COMPLETED")] | length')
FAILED=$(echo "$CHECKS_JSON" | jq '[.[] | select(.conclusion == "FAILURE")] | length')
echo "[$ELAPSED s] CI Checks: $COMPLETED/$TOTAL completed, $FAILED failed"
# If all completed
if [ "$COMPLETED" -eq "$TOTAL" ]; then
if [ "$FAILED" -eq 0 ]; then
echo "✅ All CI checks passed after $ELAPSED seconds!"
break
else
echo "❌ Some CI checks failed after $ELAPSED seconds."
# Show failures
gh pr checks $PR_NUMBER
break
fi
fi
# Continue waiting (no timeout!)
sleep $POLL_INTERVAL
ELAPSED=$((ELAPSED + POLL_INTERVAL))
done
Important: No timeout means we actually wait as long as needed. Population simulations can take 30+ minutes.
if [ "$FAILED" -eq 0 ] && [ "$COMPLETED" -eq "$TOTAL" ]; then
echo "Marking PR as ready for review..."
gh pr ready $PR_NUMBER
echo ""
echo "✅ PR #$PR_NUMBER is ready for review!"
echo "URL: $(gh pr view $PR_NUMBER --json url --jq '.url')"
echo ""
echo "All CI checks passed:"
gh pr checks $PR_NUMBER
else
echo ""
echo "❌ CI checks failed. PR remains as draft."
echo "URL: $(gh pr view $PR_NUMBER --json url --jq '.url')"
echo ""
echo "Failed checks:"
gh pr checks $PR_NUMBER
echo ""
echo "🔧 Automatically triggering /fix-pr to address CI failures..."
echo ""
fi
If CI failed, automatically trigger fix-pr command:
After detecting CI failures, invoke the /fix-pr command to automatically attempt to fix the issues. This ensures the PR doesn't stay broken and saves user intervention.
The /fix-pr command will:
Old way (Claude gives up):
Claude: "I've created the PR. CI will take a while, I'll check back later..."
[Chat ends, Claude never checks back]
User: Has to manually check CI and mark ready
New way (this command waits and auto-fixes):
Claude: "I've created the PR as draft. Now waiting for CI..."
[Actually polls CI status every 15 seconds]
Scenario A - CI passes:
Claude: "CI passed! Marking as ready for review."
[PR is ready, user doesn't have to do anything]
Scenario B - CI fails:
Claude: "CI failed. Automatically triggering /fix-pr..."
[Analyzes failures, applies fixes, pushes changes]
[Waits for CI again, marks ready when passes]
[User doesn't have to do anything]
If CI fails:
The command automatically triggers /fix-pr to handle failures. No manual intervention needed in most cases.
The auto-fix will handle:
make format && git pushisortIf no CI configured:
if [ "$TOTAL" -eq 0 ] && [ $ELAPSED -gt 60 ]; then
echo "⚠️ No CI checks detected after 60 seconds."
echo "Repository may not have CI configured."
echo "Marking PR as ready for manual review."
gh pr ready $PR_NUMBER
fi
Basic:
# Make changes, commit
git add .
git commit -m "Add feature"
# Create PR (command waits for CI)
/create-pr
With custom title:
# Command can accept optional arguments
/create-pr "Add California EITC implementation"
Checking existing PR:
# If PR exists, command tells you and suggests alternatives
/create-pr
# Output: "PR #123 exists. Use /review-program 123 or /fix-pr 123"
After /encode-policy or /fix-pr:
# These commands might push code
# Use /create-pr to create PR and wait for CI
/create-pr
After fixing CI issues:
# Fix issues locally
make format
git add .
git commit -m "Fix linting"
git push
# Command will detect existing PR and re-check CI
/create-pr # "PR #123 exists, checking CI status..."
By repository (based on actual data):
The command has no timeout - it will wait as long as needed, even for policyengine-us's 75-minute CI runs.
Problem: Claude's internal timeout or context leads it to give up
Solution:
Key insight: By having the command contain the waiting logic in bash, Claude executes it and actually waits instead of just saying "I'll wait."
This command is essential for:
Use this instead of:
gh pr create followed by manual CI checking