Github Pr Workflow — GitHub PR lifecycle: branch, commit, open, CI, merge
Github Pr Workflow
Section titled “Github Pr Workflow”GitHub PR lifecycle: branch, commit, open, CI, merge.
Skill metadata
Section titled “Skill metadata”| Source | Bundled (installed by default) |
| Path | skills/github/github-pr-workflow |
| Version | 1.1.0 |
| Author | Hermes Agent |
| License | MIT |
| Tags | GitHub, Pull-Requests, CI/CD, Git, Automation, Merge |
| Related skills | github-auth, github-code-review |
Reference: full SKILL.md
Section titled “Reference: full SKILL.md”The following is the complete skill definition that Hermes loads when this skill is triggered. This is what the agent sees as instructions when the skill is active.
GitHub Pull Request Workflow
Section titled “GitHub Pull Request Workflow”Complete guide for managing the PR lifecycle. Each section shows the gh way first, then the git + curl fallback for machines without gh.
Prerequisites
Section titled “Prerequisites”- Authenticated with GitHub (see
github-authskill) - Inside a git repository with a GitHub remote
Quick Auth Detection
Section titled “Quick Auth Detection”# Determine which method to use throughout this workflowif command -v gh &>/dev/null && gh auth status &>/dev/null; then AUTH="gh"else AUTH="git" # Ensure we have a token for API calls if [ -z "$GITHUB_TOKEN" ]; then if [ -f ~/.hermes/.env ] && grep -q "^GITHUB_TOKEN=" ~/.hermes/.env; then GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" ~/.hermes/.env | head -1 | cut -d= -f2 | tr -d '\n\r') elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then GITHUB_TOKEN=$(grep "github.com" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]*:\([^@]*\)@.*|\1|') fi fifiecho "Using: $AUTH"Extracting Owner/Repo from the Git Remote
Section titled “Extracting Owner/Repo from the Git Remote”Many curl commands need owner/repo. Extract it from the git remote:
# Works for both HTTPS and SSH remote URLsREMOTE_URL=$(git remote get-url origin)OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's|.*github\.com[:/]||; s|\.git$||')OWNER=$(echo "$OWNER_REPO" | cut -d/ -f1)REPO=$(echo "$OWNER_REPO" | cut -d/ -f2)echo "Owner: $OWNER, Repo: $REPO"1. Branch Creation
Section titled “1. Branch Creation”This part is pure git — identical either way:
# Make sure you're up to dategit fetch origingit checkout main && git pull origin main
# Create and switch to a new branchgit checkout -b feat/add-user-authenticationBranch naming conventions:
feat/description— new featuresfix/description— bug fixesrefactor/description— code restructuringdocs/description— documentationci/description— CI/CD changes
2. Making Commits
Section titled “2. Making Commits”Use the agent’s file tools (write_file, patch) to make changes, then commit:
# Stage specific filesgit add src/auth.py src/models/user.py tests/test_auth.py
# Commit with a conventional commit messagegit commit -m "feat: add JWT-based user authentication
- Add login/register endpoints- Add User model with password hashing- Add auth middleware for protected routes- Add unit tests for auth flow"Commit message format (Conventional Commits):
type(scope): short description
Longer explanation if needed. Wrap at 72 characters.Types: feat, fix, refactor, docs, test, ci, chore, perf
3. Pushing and Creating a PR
Section titled “3. Pushing and Creating a PR”Push the Branch (same either way)
Section titled “Push the Branch (same either way)”git push -u origin HEADCreate the PR
Section titled “Create the PR”With gh:
gh pr create \ --title "feat: add JWT-based user authentication" \ --body "## Summary- Adds login and register API endpoints- JWT token generation and validation
## Test Plan- [ ] Unit tests pass
Closes #42"Options: --draft, --reviewer user1,user2, --label "enhancement", --base develop
With git + curl:
BRANCH=$(git branch --show-current)
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/$OWNER/$REPO/pulls \ -d "{ \"title\": \"feat: add JWT-based user authentication\", \"body\": \"## Summary\nAdds login and register API endpoints.\n\nCloses #42\", \"head\": \"$BRANCH\", \"base\": \"main\" }"The response JSON includes the PR number — save it for later commands.
To create as a draft, add "draft": true to the JSON body.
4. Monitoring CI Status
Section titled “4. Monitoring CI Status”Check CI Status
Section titled “Check CI Status”With gh:
# One-shot checkgh pr checks
# Watch until all checks finish (polls every 10s)gh pr checks --watchWith git + curl:
# Get the latest commit SHA on the current branchSHA=$(git rev-parse HEAD)
# Query the combined statuscurl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status \ | python3 -c "import sys, jsondata = json.load(sys.stdin)print(f\"Overall: {data['state']}\")for s in data.get('statuses', []): print(f\" {s['context']}: {s['state']} - {s.get('description', '')}\")"
# Also check GitHub Actions check runs (separate endpoint)curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/check-runs \ | python3 -c "import sys, jsondata = json.load(sys.stdin)for cr in data.get('check_runs', []): print(f\" {cr['name']}: {cr['status']} / {cr['conclusion'] or 'pending'}\")"Poll Until Complete (git + curl)
Section titled “Poll Until Complete (git + curl)”# Simple polling loop — check every 30 seconds, up to 10 minutesSHA=$(git rev-parse HEAD)for i in $(seq 1 20); do STATUS=$(curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status \ | python3 -c "import sys,json; print(json.load(sys.stdin)['state'])") echo "Check $i: $STATUS" if [ "$STATUS" = "success" ] || [ "$STATUS" = "failure" ] || [ "$STATUS" = "error" ]; then break fi sleep 30done5. Auto-Fixing CI Failures
Section titled “5. Auto-Fixing CI Failures”When CI fails, diagnose and fix. This loop works with either auth method.
Step 1: Get Failure Details
Section titled “Step 1: Get Failure Details”With gh:
# List recent workflow runs on this branchgh run list --branch $(git branch --show-current) --limit 5
# View failed logsgh run view <RUN_ID> --log-failedWith git + curl:
BRANCH=$(git branch --show-current)
# List workflow runs on this branchcurl -s \ -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/repos/$OWNER/$REPO/actions/runs?branch=$BRANCH&per_page=5" \ | python3 -c "import sys, jsonruns = json.load(sys.stdin)['workflow_runs']for r in runs: print(f\"Run {r['id']}: {r['name']} - {r['conclusion'] or r['status']}\")"
# Get failed job logs (download as zip, extract, read)RUN_ID=<run_id>curl -s -L \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/logs \ -o /tmp/ci-logs.zipcd /tmp && unzip -o ci-logs.zip -d ci-logs && cat ci-logs/*.txtStep 2: Fix and Push
Section titled “Step 2: Fix and Push”After identifying the issue, use file tools (patch, write_file) to fix it:
git add <fixed_files>git commit -m "fix: resolve CI failure in <check_name>"git pushStep 3: Verify
Section titled “Step 3: Verify”Re-check CI status using the commands from Section 4 above.
Auto-Fix Loop Pattern
Section titled “Auto-Fix Loop Pattern”When asked to auto-fix CI, follow this loop:
- Check CI status → identify failures
- Read failure logs → understand the error
- Use
read_file+patch/write_file→ fix the code git add . && git commit -m "fix: ..." && git push- Wait for CI → re-check status
- Repeat if still failing (up to 3 attempts, then ask the user)
6. Merging
Section titled “6. Merging”With gh:
# Squash merge + delete branch (cleanest for feature branches)gh pr merge --squash --delete-branch
# Enable auto-merge (merges when all checks pass)gh pr merge --auto --squash --delete-branchWith git + curl:
PR_NUMBER=<number>
# Merge the PR via API (squash)curl -s -X PUT \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/merge \ -d "{ \"merge_method\": \"squash\", \"commit_title\": \"feat: add user authentication (#$PR_NUMBER)\" }"
# Delete the remote branch after mergeBRANCH=$(git branch --show-current)git push origin --delete $BRANCH
# Switch back to main locallygit checkout main && git pull origin maingit branch -d $BRANCHMerge methods: "merge" (merge commit), "squash", "rebase"
Enable Auto-Merge (curl)
Section titled “Enable Auto-Merge (curl)”# Auto-merge requires the repo to have it enabled in settings.# This uses the GraphQL API since REST doesn't support auto-merge.PR_NODE_ID=$(curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \ | python3 -c "import sys,json; print(json.load(sys.stdin)['node_id'])")
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/graphql \ -d "{\"query\": \"mutation { enablePullRequestAutoMerge(input: {pullRequestId: \\\"$PR_NODE_ID\\\", mergeMethod: SQUASH}) { clientMutationId } }\"}"7. Complete Workflow Example
Section titled “7. Complete Workflow Example”# 1. Start from clean maingit checkout main && git pull origin main
# 2. Branchgit checkout -b fix/login-redirect-bug
# 3. (Agent makes code changes with file tools)
# 4. Commitgit add src/auth/login.py tests/test_login.pygit commit -m "fix: correct redirect URL after login
Preserves the ?next= parameter instead of always redirecting to /dashboard."
# 5. Pushgit push -u origin HEAD
# 6. Create PR (picks gh or curl based on what's available)# ... (see Section 3)
# 7. Monitor CI (see Section 4)
# 8. Merge when green (see Section 6)Useful PR Commands Reference
Section titled “Useful PR Commands Reference”| Action | gh | git + curl |
|---|---|---|
| List my PRs | gh pr list --author @me | curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$OWNER/$REPO/pulls?state=open" |
| View PR diff | gh pr diff | git diff main...HEAD (local) or curl -H "Accept: application/vnd.github.diff" ... |
| Add comment | gh pr comment N --body "..." | curl -X POST .../issues/N/comments -d '{"body":"..."}' |
| Request review | gh pr edit N --add-reviewer user | curl -X POST .../pulls/N/requested_reviewers -d '{"reviewers":["user"]}' |
| Close PR | gh pr close N | curl -X PATCH .../pulls/N -d '{"state":"closed"}' |
| Check out someone’s PR | gh pr checkout N | git fetch origin pull/N/head:pr-N && git checkout pr-N |