Awesome-omni-skill creating-pull-request
Create a high-quality PR end-to-end with automated lifecycle loop (pre-checks, branch/commit, PR metadata, review handling, CI fixes) based on TileOPs workflow
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data-ai/creating-pull-request" ~/.claude/skills/diegosouzapw-awesome-omni-skill-creating-pull-request && rm -rf "$T"
skills/data-ai/creating-pull-request/SKILL.mdWhen to use
- You need to turn local changes into a clean PR that follows TileOPs conventions.
- You want the full lifecycle automated: create PR → wait for CI/review → fix → done.
Workflow
- Phase 0–2: Create PR — subagent (sonnet) runs Phase 0 → 1 → 2
- Phase 0: Pre-checks (lint, tests)
- Phase 1: Branch + commit + push
- Phase 2: Create PR + labeling
- Phase 3–5: Poll & Handle — main agent loops until done (max 3 rounds)
- Phase 3: Launch poll script (background, zero tokens)
- Phase 4: Handle CI failures + review comments
- Phase 5: Verify done (CI green + reviews handled → DONE, notify user)
Phase 0–2: Create PR
Dispatch a subagent (sonnet-level or equivalent) to execute Phase 0 → 1 → 2. The subagent handles all pre-checks, branching, committing, pushing, and PR creation.
Subagent spec
Spawn a general-purpose subagent with model=sonnet and the following prompt:
You are creating a PR for
.{owner}/{repo}Background: {issue_description_or_task_context}
Steps: Execute Phase 0 → 1 → 2 from the skill below. Read
first for naming conventions.docs/CONTRIBUTING.mdReturn format (report exactly):
PR_NUMBER: <number>PR_URL: <url>BRANCH: <branch-name>SUMMARY: <one-line summary of changes>
Phase 0: Pre-checks
Goal: avoid opening a PR that immediately fails formatting/tests.
- If it's not clear what the PR is fixing/adding, ask the user what issue/task this PR is for (link or short description).
- Read
to confirm the latest branch naming, commit message, and PR title conventions. Do NOT rely on other files (workflow configs, CI scripts) for naming rules —docs/CONTRIBUTING.md
is the single source of truth.CONTRIBUTING.md - Confirm repository root and current git state:
git statusgit diff --stat
- Confirm Python environment is active (TileOPs example):
conda activate top
- Run formatting/lint checks and tests following
→Claude.md
.DEVELOPMENT.md
Notes:
- Keep runs reproducible (fixed seed where applicable).
- Don't fix unrelated failures in this PR; report them.
Pre-Checklist
-
passespre-commit run --all-files - Tests pass (see
for exact commands)Claude.md - docs examples use portable env vars (prefer
, avoid backticks likePYTHONPATH="$PWD"
)`pwd`
Phase 1: Branch + commit
Goal: keep history clean and easy to review.
- Sync
first:main
git fetch origin git switch main git pull --ff-only
- Create a new branch:
git switch -c <branch-name>
- Stage changes intentionally (list specific files, avoid
):git add .
git add <file1> <file2> ...
- Create a focused commit:
git commit -m "[<Area>] <short summary>"
- Push branch (always pull before push to incorporate any remote changes):
git pull origin <branch-name> --rebase git push -u origin <branch-name>
Branch naming + commit conventions:
- Branch name:
(e.g.type/scope/description
,feat/flash-attn/fwd-kernel
)fix/mla/parsing-error - Commit/PR title: bracket format
or[Type] Description[Type][Scope] Description - Common types:
,[Feat]
,[BugFix]
,[Refactor]
,[Enhancement]
,[Doc]
,[Chore][Bench] - Follow
as the single source of truth.docs/CONTRIBUTING.md
Phase 2: Create PR + labeling
Goal: PR is self-contained and matches project expectations.
- Create PR using the GitHub MCP tool (
) or GitHub CLI:create_pull_request
gh pr create --base main --head <owner>:<branch> --title "<title>"
MCP pitfall: When using the GitHub MCP
orcreate_pull_requesttools, theupdate_pull_requestparameter must use actual newlines (multi-line string), NOTbodyescape sequences.\n
- PR title guidelines:
- Must use bracket format from
:docs/CONTRIBUTING.md
or[Type] Description
.[Type][Scope] Description - Examples:
,[Feat][GEMV] Add forward kernel
.[CI] Add pr-validation workflow - Keep it under ~80 chars, describe the user-facing change.
- PR body template (fill in, or leave for user to edit after creation):
Closes #<issue-number> ## Summary - <what was migrated/added/fixed> - <what was removed/replaced> - <other notable changes> ## Test plan - [x] pre-commit passed - [x] pytest <N> passed
- Add labels (if your repo uses them):
- docs / bug / benchmark / ci
If the PR was fully AI-driven (no user discussion, no user code edits — e.g., selfplay mode), add the
All AI powered label:
gh pr edit <PR_NUMBER> --add-label "All AI powered"
Phase 3–5: Poll & Handle
After the subagent returns
PR_NUMBER, the main agent enters a poll-handle loop:
do { Phase 3 → Phase 4 → Phase 5 } while PR is not done
Exit conditions: CI green + all reviews handled, OR timeout, OR max 3 rounds.
Critical: Every re-poll (Phase 3) must check both CI status and review comments. Never check only one. Review bots may post comments at any time — especially after the first CI run completes.
Phase 3: Poll
Dependencies: The poll script requires
gh (GitHub CLI, authenticated) and jq. If either is missing, the script returns a JSON error to stdout — proceed to Phase 4a (do NOT silently work around it).
Launch the poll script in background (zero token cost during the wait):
.claude/scripts/poll-pr-status.sh {owner}/{repo} {pr_number} # Run this via your tool's background/async execution mode.
The script polls CI checks and review comments every 30 seconds for up to 10 minutes, then returns structured JSON:
{ "status": "ready | timeout | error", "ci": { "state": "success | failure | pending", "failed_checks": [{"name": "...", "conclusion": "failure", "url": "..."}] }, "reviews": { "new_inline_comments": [{"id": ..., "author": "...", "body": "...", "path": "...", "line": ...}], "new_review_bodies": [{"id": ..., "author": "...", "body": "...", "state": "..."}], "unresolved_count": 3 } }
Phase 4: Handle polling result
Parse the JSON and follow this decision tree in order (first matching branch wins):
4a. Timeout / error → STOP and ask user
If
status == "error" or status == "timeout":
"PR #{pr_number} — poll returned
: {message}. You can retry later:{status}Or ask me to continue monitoring.".claude/scripts/poll-pr-status.sh {owner}/{repo} {pr_number}
You MUST stop and ask the user. Do NOT silently fall back to manual polling or alternative approaches. The user decides how to proceed.
Exit the loop.
4b. CI failure → auto fix
If
ci.state == "failure", handle CI first (reviews will be re-checked after fix via re-poll).
-
Identify failing checks from
ci.failed_checks -
Reproduce locally when possible:
- Run the same command CI runs (format/test)
- Use the same Python environment
-
Fix by severity:
-
Lint/format failures (pre-commit, ruff, black, isort):
- Dispatch a haiku subagent:
, commit, pushpre-commit run --all-files - → re-poll (back to Phase 3)
- Dispatch a haiku subagent:
-
Test/build failures:
- Main agent analyzes the failure logs (
→ get log URL)gh pr checks - Simple fix → fix, commit, push → re-poll
- Complex/unclear → report to user with log summary, ask for guidance
- Main agent analyzes the failure logs (
-
-
Common CI issues:
- Non-portable commands in docs (use
instead of backticks)"$PWD" - Tool missing from PATH (use
)python -m <tool> - Formatting drift (run
)pre-commit run --all-files
- Non-portable commands in docs (use
4c. New reviews → auto handle
If
reviews.new_inline_comments or reviews.new_review_bodies are non-empty:
Every review comment MUST be replied to individually in its original thread. Do NOT post a summary comment.
For each comment, classify and handle:
-
Simple/format (typos, naming, imports, docstring style):
- Dispatch a haiku subagent to fix and reply in thread
- → re-poll (back to Phase 3)
-
Logic/architecture:
- Main agent analyzes the suggestion against the codebase
- Accept: fix + reply with commit hash
- Decline: reply with specific technical reason
- Uncertain: ask the user
-
Invalid/incorrect:
- Reply with a specific technical reason why the suggestion is unnecessary or incorrect
How to reply to a review comment:
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \ -f body="<reply>"
After replying, resolve the thread via GraphQL (use the thread's
PRRT_* node ID, not the comment ID):
gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "<thread_node_id>"}) { thread { isResolved } } }'
To get thread IDs, query
repository.pullRequest.reviewThreads. Every replied-to thread must be resolved — an unresolved thread means the PR is not done.
Reply content rules:
- Accepting:
"Accepted. Fixed X. See {commit_hash}." - Declining (future work):
— also create a GitHub issue."Declined for this PR — scope is limited to X. Tracked in #{issue}." - Declining (invalid):
"Declined. {specific technical reason}." - If accepting reveals a novel pattern (broadly applicable, not a duplicate, actionable): document it in
.docs/CONTRIBUTING.md
Phase 5: Verify done
All of these must be true to declare done:
— not "pending". If any check is still pending (e.g. waiting for a GPU runner), you must keep waiting. Print periodic "waiting for CI: {check_name} still pending…" messages so the user sees progress, and continue polling. Do NOT skip pending checks or declare done early.ci.state == "success"
is empty (or all replied to and resolved)reviews.new_inline_comments
is empty (or all replied to)reviews.new_review_bodies
If done:
"PR #{pr_number} is ready for human review:
- CI: all checks passed
- Automated review comments: all addressed and resolved
- URL: {pr_url}"
Exit the loop.
If
ci.state == "pending" and no failures/reviews to handle → keep polling (back to Phase 3). Print a waiting message each cycle. There is no max-rounds limit for passive waiting — only fix-push cycles count toward the 3-round limit.
Note on
: The poll script counts all non-author inline comments (REST API lacks thread resolution state). The agent should verify it has replied to every comment in bothunresolved_countandnew_inline_commentsbefore considering the PR done.new_review_bodies
Loop constraints
- Max 3 rounds. After 3 fix-poll cycles still failing → escalate to user with status summary.
- Each "round" = one poll + one fix + one push. Re-poll counts as the next round.
Done criteria
A PR is "done" when:
- CI is green (all checks passed, none pending)
- All automated review comments have been replied to and resolved
- User is notified that PR is ready for human review