PR Creator
Creates a GitHub PR from committed changes with proper description, labels, and Notion integration.
Configuration
Uses the production API by default. No configuration needed for read operations.
Defaults (no setup required):
- API URL:
https://api-gateway-856475788601.us-central1.run.app - Read-only endpoints at
/public/*require no authentication
For write operations (PR registration, state transitions), set:
export PIPELINE_API_KEY="..." # Get from GCP Secret Manager or ask admin
Optional (for local working artifacts like plan.md):
PIPELINE_DIR="${PIPELINE_DIR:-$HOME/repos/ticket-to-pr-pipeline}"
Prerequisites
- Branch is not
main - All changes committed
- Branch pushed to remote
Workflow
0. Verify Pipeline Ticket Exists
Before proceeding, confirm a ticket exists in the pipeline API. If not, run ticket-intake first.
const ticket = await client.getTicket(ticketId)
if (!ticket) {
throw new Error('❌ No pipeline ticket found. Run ticket-intake first to register this ticket in the pipeline API.')
}
If no ticketId is available, search by Notion page ID or list recent tickets:
const ticket = await client.findByNotionId(notionPageId)
if (!ticket) {
console.error('❌ No pipeline ticket found for this Notion page. Run ticket-intake first.')
process.exit(1)
}
const ticketId = ticket.id
1. Verify Ready
# Confirm not on main
git branch --show-current | grep -v '^main$'
# Confirm clean working tree
git status --porcelain
# Check for conflicts with main
git fetch origin main
git merge-base --is-ancestor origin/main HEAD || echo "CONFLICTS_POSSIBLE"
1b. Register Branch
Register the working branch with the pipeline API for automatic PR detection:
// Get branch and repo info
const branch = execSync('git branch --show-current').toString().trim()
const remoteUrl = execSync('git remote get-url origin').toString().trim()
const repoMatch = remoteUrl.match(/github\.com[/:]([^/]+\/[^/.]+)/)
const repo = repoMatch ? repoMatch[1] : null
if (repo) {
await client.registerBranch(ticketId, branch, repo)
}
This enables the reconciler to detect your PR even if subsequent API calls fail.
2. Handle Conflicts
If conflicts detected, present options:
⚠️ Branch may have conflicts with main.
Options:
A) Rebase onto main now
B) Continue anyway (resolve later)
C) Stop and investigate
Choice:
If rebase selected: git rebase origin/main
3. Determine Commit Prefix
From changes, select one:
- New feature →
feat: - Bug fix →
fix: - Tests only →
test: - Refactor →
refactor: - Docs →
docs:
4. Generate PR Title
Format: {prefix}: {concise description}
- Max ~60 characters
- No period at end
- Lowercase after prefix
5. Generate PR Body
Use this template:
## Summary
{One sentence from ticket description}
## Changes
- **What**: {Core functionality from plan.md}
## Review Focus
{Key decisions or edge cases from plan.md}
Fixes #{issue_number}
<!-- Pipeline-Ticket: {ticket_id} -->
Important: Always include the Pipeline-Ticket: {ticket_id} HTML comment. This enables automatic state reconciliation even if the API call to register the PR fails.
Remove Breaking/Dependencies sections if not applicable. Keep it SHORT.
6. Determine Labels
Get changed files:
git diff --name-only origin/main...HEAD
Map to area:* labels:
src/components/→area:componentssrc/stores/→area:storessrc/composables/→area:composablessrc/api/→area:apisrc/scripts/→area:litegraphbrowser_tests/→area:testing
Multiple labels are fine.
7. Push Branch
git push -u origin $(git branch --show-current)
8. Create PR
# Save body to temp file first
cat > /tmp/pr-body.md << 'EOF'
{generated body}
EOF
gh pr create \
--title "{title}" \
--body-file /tmp/pr-body.md \
--label "{labels}" \
--assignee "@me"
9. Register PR with Pipeline API
After creating the PR, register it with the pipeline API:
import { PipelineClient, PipelineAPIError } from '@pipeline/client'
const client = new PipelineClient({
apiUrl: process.env.PIPELINE_API_URL || 'https://api-gateway-856475788601.us-central1.run.app',
agentId: process.env.AGENT_ID!,
})
const prUrl = 'https://github.com/org/repo/pull/123'
// Register PR - automatically transitions state and queues Notion sync
await client.setPRCreated(ticketId, prUrl)
This call:
- Updates the ticket state to
PR_CREATED - Stores the PR URL
- Queues automatic Notion sync (Status → "In Review", PR URL added)
- Records the event timestamp for metrics
10. Output
✅ PR Created
URL: https://github.com/Comfy-Org/ComfyUI_frontend/pull/{number}
Title: {title}
Labels: {labels}
Notion updated: Status → "In Review", PR linked
11. Auto-Trigger CI Checker
After PR creation, automatically initiate CI monitoring:
# Wait briefly for GitHub to register the PR
sleep 5
# Check initial CI status
gh pr checks $(git branch --show-current) --watch --fail-fast &
CI_PID=$!
# Don't block - just start monitoring
echo "CI monitoring started. Use 'skill ci-checker' for detailed status."
Prompt user:
CI checks are running. Options:
1. Wait for CI to complete (I'll monitor)
2. Continue working while CI runs in background
3. Skip CI monitoring
Your choice:
If user chooses to wait, invoke ci-checker skill automatically.
Guidelines
- Keep description SHORT - no essays
- One sentence summary is key
- Only include Breaking/Dependencies if actually applicable
- Don't add reviewers - let maintainers assign
- Assignee should always be
@me
API Client Reference
Available Methods
| Method | Purpose |
|---|---|
getTicket(id) | Fetch ticket context |
setPRCreated(id, prUrl) | Record PR URL, transition state, queue Notion sync |
queueSync(id, action, payload) | Manually queue a sync action (usually not needed) |
transitionState(id, state, reason) | Manually transition ticket state |
registerBranch(id, branch, repo) | Register working branch for automatic PR detection |
Error Handling
try {
await client.setPRCreated(ticketId, prUrl)
} catch (error) {
if (error instanceof PipelineAPIError) {
console.error(`API error: ${error.message} (status: ${error.status})`)
}
throw error
}
