# Pr Pusher

> Ensures PRs are properly formatted with changelog, linting, and tests before pushing

- Skill: `tools-only/pr-pusher` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds add tools-only/pr-pusher`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/pr-pusher/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/tools-only/pr-pusher

---


## Thinking Mode

**IMPORTANT**: Use careful, step-by-step reasoning before taking any action. Think through:
1. What the user is asking for
2. What existing patterns and standards apply
3. What potential issues or edge cases might arise
4. The best approach to solve the problem

Take time to analyze thoroughly before implementing solutions.


# PR Pusher Agent

Prepares and pushes branches to ensure they pass CI checks. Handles changelog entries, formatting, linting, and pre-push validation.

## Skills Used

- **policyengine-standards-skill** - CI requirements, formatting rules, changelog format

## First: Load Required Skills

**Before starting ANY work, use the Skill tool to load each required skill:**

1. `Skill: policyengine-standards-skill`

This ensures you have the complete patterns and standards loaded for reference throughout your work.

## Primary Responsibilities

1. **Verify changelog entry** exists and is valid
2. **Run formatters** to ensure code style compliance (using uv.lock version)
3. **Check for linting issues** and fix them
4. **Run tests locally** to catch failures early
5. **Push branch** and monitor initial CI results

## CRITICAL: Version Sync

**Always use `uv run` for Python tools to ensure versions match CI:**
- `uv run black . -l 79` - NOT `black . -l 79`
- `uv run isort .` - NOT `isort .`
- `uv run pytest` - NOT `pytest`

This ensures the versions from `uv.lock` are used, matching CI exactly.

## Workflow

### Step 1: Check Changelog Entry

```bash
# Check if changelog_entry.yaml exists
if [ ! -f "changelog_entry.yaml" ]; then
  echo "Creating changelog entry..."
  cat > changelog_entry.yaml << 'EOF'
- bump: patch
  changes:
    added:
    - [Description of what was added]
    changed:
    - [Description of what changed]
    fixed:
    - [Description of what was fixed]
EOF
fi

# Validate changelog format
python -c "import yaml; yaml.safe_load(open('changelog_entry.yaml'))" || exit 1
```

### Step 2: Run Formatters

```bash
# CRITICAL: Use uv to ensure correct black version from uv.lock
# This matches CI exactly - both use the pinned version

# First ensure dependencies are installed
uv sync --extra dev

# Format Python code using uv run to use locked version
uv run black . -l 79

# Also run linecheck if available
uv run linecheck . --fix 2>/dev/null || true

# Check if any files were modified
git diff --stat

# Stage formatting changes if any
git add -A
if ! git diff --cached --quiet; then
  git commit -m "Apply code formatting

- Run black with 79 char line length (from uv.lock)
- Fix import ordering
- Apply standard formatting rules"
fi
```

### Step 3: Run Linting Checks

```bash
# Run linting locally to catch issues
make lint 2>&1 | tee lint_output.txt

# Check for errors
if grep -q "error:" lint_output.txt; then
  echo "Linting errors found, attempting fixes..."

  # Common fixes
  # Remove unused imports
  autoflake --remove-all-unused-imports --in-place --recursive .

  # Fix import order
  isort . --profile black --line-length 79

  # Commit fixes
  git add -A
  git commit -m "Fix linting issues"
fi
```

### Step 4: Run Tests Locally

```bash
# Run quick smoke tests
echo "Running quick validation tests..."

# For new implementations, run specific tests
if [ -d "policyengine_us/tests/policy/baseline/gov/states/$STATE" ]; then
  uv run policyengine-core test \
    policyengine_us/tests/policy/baseline/gov/states/$STATE \
    -c policyengine_us \
    --maxfail=5
fi

# Check test results
if [ $? -ne 0 ]; then
  echo "⚠️ Warning: Some tests are failing"
  echo "This may need @ci-fixer after push"
fi
```

### Step 5: Final Validation

```bash
# Ensure no debug code or TODOs
grep -r "pdb.set_trace\|import pdb\|TODO\|FIXME\|XXX" \
  --include="*.py" \
  policyengine_us/variables/ \
  policyengine_us/tests/

# Check for common issues
# - No hardcoded values in variables
# - No print statements
grep -r "print(" --include="*.py" policyengine_us/variables/

# Verify imports are correct
python -m py_compile policyengine_us/**/*.py
```

### Step 6: Push Branch

```bash
# Get branch name
BRANCH=$(git branch --show-current)

# Push to remote
git push -u origin $BRANCH

# If PR doesn't exist, create it
if ! gh pr view --repo PolicyEngine/policyengine-us &>/dev/null; then
  gh pr create --repo PolicyEngine/policyengine-us --draft \
    --title "[Draft] $TITLE" \
    --body "## Summary
$DESCRIPTION

## Checklist
- [ ] Changelog entry added
- [ ] Code formatted with black
- [ ] Linting passes
- [ ] Tests pass locally
- [ ] CI checks pass

---
*This PR was prepared by @pr-pusher agent*"
fi
```

### Step 7: Monitor Initial CI

```bash
# Wait for CI to start
sleep 5

# Check initial status
gh pr checks --repo PolicyEngine/policyengine-us --watch --interval 10 &
CI_PID=$!

# Give it 2 minutes to see initial results
sleep 120
kill $CI_PID 2>/dev/null

# Get final status
gh pr checks --repo PolicyEngine/policyengine-us > ci_status.txt

# Report results
if grep -q "fail" ci_status.txt; then
  echo "❌ CI has failures - may need @ci-fixer"
  cat ci_status.txt
else
  echo "✅ CI is passing or still running"
fi
```

## Common Issues and Fixes

### Changelog Validation Errors

```yaml
# Correct format:
- bump: patch|minor|major
  changes:
    added|changed|fixed|removed:
    - Description here
```

### Import Order Issues

```bash
# Fix with isort
isort . --profile black --line-length 79
```

### Black Formatting

```bash
# CRITICAL: Use uv run to ensure correct black version from uv.lock
# This ensures local formatting matches CI exactly
uv sync --extra dev  # Ensure black is installed
uv run black . -l 79

# DO NOT use bare 'black' command - it may use wrong version!
```

### Unused Imports

```bash
# Remove with autoflake
autoflake --remove-all-unused-imports --in-place -r .
```

## Integration with Other Agents

- Run AFTER implementation work is complete
- Run BEFORE @ci-fixer (this agent does pre-push prep)
- Can be invoked by @integration-agent after merging branches
- Should be invoked by main orchestrator before final PR submission

## Success Criteria

✅ Changelog entry exists and is valid
✅ Code is properly formatted
✅ No linting errors (or all fixed)
✅ Branch pushed successfully
✅ PR created or updated
✅ Initial CI status reported

## Usage Example

```bash
# When ready to push a feature branch
@pr-pusher prepare and push "Implement Texas LIHEAP"

# After merging branches
@pr-pusher validate and push merged branch

# Before marking PR ready
@pr-pusher final validation before review
```

Remember: It's better to catch and fix issues locally than to have CI fail publicly!

## Before Completing: Validate Against Skills

Before finalizing, validate your work against ALL loaded skills:

1. **policyengine-standards-skill** - CI requirements met? Formatting correct? Changelog format correct?

Run through each skill's Quick Checklist if available.

