Update an existing pull request's title and description following project conventions.
-
Identify the PR
The PR number is provided in the chain context (the text after /update-pr). If no PR number is provided, report an error and stop — this skill requires a specific PR to update.
Determine the target repository dynamically from the git remote. Never hardcode a repo name:
GIT_REMOTE=$(git remote get-url origin 2>/dev/null)
if echo "$GIT_REMOTE" | grep -q '^git@'; then
GH_REPO=$(echo "$GIT_REMOTE" | sed 's/.*@[^:]*:\(.*\).git$/\1/')
elif echo "$GIT_REMOTE" | grep -q 'github\.com'; then
GH_REPO=$(echo "$GIT_REMOTE" | sed 's/.*github\.com[/:]\(.*\).git$/\1/')
else
echo "ERROR: Could not parse repository from remote '$GIT_REMOTE'."
exit 1
fi
Confirm the PR exists:
gh pr view <PR_NUMBER> --json title,state,url --repo "$GH_REPO"
-
Scan Project Rules
Scan the project root and any specified paths for a .agent rules file and read its contents:
# Scan the project root for AGENTS.md or similar rules file
Extract:
- Commit style (Conventional Commits format from section 5.1)
- PR template requirements from section 5.4 (and
.github/PULL_REQUEST_TEMPLATE.md if it exists)
- Any project-specific rules that affect the PR description
-
Read the PR template
cat .github/PULL_REQUEST_TEMPLATE.md
If the file doesn't exist, construct a reasonable description with: Description, Type of Change, Testing, Coverage, Checklist.
-
Gather the full delta
You must collect the complete picture — every commit and every file change between the branch and its target. Do not rely on the most recent commit alone.
BASE_REF=$(gh pr view <PR_NUMBER> --json baseRefName --jq '.baseRefName' --repo "$GH_REPO")
HEAD_REF=$(gh pr view <PR_NUMBER> --json headRefName --jq '.headRefName' --repo "$GH_REPO")
From this data, identify:
- All files changed and what kind of change each represents
- All commits and their messages (these are your primary signal for the title)
- The nature of changes: code, docs, tests, config, etc.
git log --reverse "${BASE_REF}..${HEAD_REF}" --oneline --no-decorate
git diff "${BASE_REF}..${HEAD_REF}" --stat
git diff "${BASE_REF}..${HEAD_REF}"
-
Draft the title
Synthesize the title from the complete delta — all commits and all file changes. Follow Conventional Commits format: <type>: <short description>
Type selection priority (use the highest-priority type present in the delta):
fix: — if any commit fixes a bug
feat: — if any commit adds a feature
docs: — if only documentation/spec changes
test: — if only test changes
refactor: — if only refactoring with no behavior change
chore: — if only maintenance tasks
Description selection:
- If all commits share a common theme, use that as the description.
- If commits span multiple themes, use the primary theme (the one with the most commits or the most impactful change).
- Keep it under 72 characters. Be specific — avoid vague phrases like "update" or "changes."
Examples:
fix: resolve agent stalling on empty conversation history
feat: add cron-based auto-reflection scheduling
docs: add compliance framework and borderline escalation rules to safety guidelines
Assign the synthesized title:
DRAFTED_TITLE="<type>: <short description>"
echo "DRAFTED_TITLE=$DRAFTED_TITLE"
-
Draft the description
Synthesize the description from the complete delta — all commits and all file changes. Fill out every section of the PR template. Never leave a section blank — use N/A if not applicable.
Description body:
- Write a concise 1-3 sentence summary of what changed across the entire branch, not just the last commit.
- Reference all files changed and the nature of each change.
- If the branch has multiple commits, mention the scope: e.g., "This change adds X and also updates Y to align with Z."
Template sections:
- Type of Change: Check the box that matches the highest-priority type (same priority as title: fix > feat > docs > test > refactor > chore). If multiple types apply, check the highest-priority one.
- Testing: Describe tests written/run and their coverage. Use "N/A" for doc-only or config-only changes.
- Coverage: Confirm 100% line coverage maintained (check the box if no code changes or if coverage is maintained).
- Checklist: Check all boxes if no violations. Uncheck any that don't apply.
-
Apply via gh api
Never use gh pr edit — it fails in this repo. Use the GitHub API instead. Continue using the $GH_REPO variable extracted in Step 1:
gh api "repos/$GH_REPO/pulls/$PR_NUMBER" \
-f title="$DRAFTED_TITLE" \
-f body="$DRAFTED_BODY"
VERIFY_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title' --repo "$GH_REPO" 2>/dev/null || true)
if [ "$VERIFY_TITLE" != "$DRAFTED_TITLE" ]; then
echo "ERROR: PR title update verification failed. Expected '$DRAFTED_TITLE', got '$VERIFY_TITLE'."
exit 1
fi
echo "PR title verified: $VERIFY_TITLE"
Handle API errors: If the API call returns a non-200 status, report the error and stop. Common errors:
- 403 Forbidden: Check authentication and permissions
- 404 Not Found: Verify PR number and repo
- 422 Unprocessable Entity: Check title/body format (title under 72 chars, body not empty)
Coverage verification: The skill instructs to "Confirm 100% line coverage maintained" but there's no way to verify this without running tests. If code changes were made, run npm run coverage and check the output. If no code changes were made (docs-only, config-only), note "No code changes — coverage N/A."
-
Confirm
Show the user the updated PR URL and a summary of what changed.