GH PR
Overview
Create or update GitHub Pull Requests with the gh CLI using a detailed body template and strict same-branch rules.
Decision rules (must follow)
- Do not create or switch branches. Always use the current branch as the PR head.
- Check local working tree state before push/PR operations.
git status --porcelain
- If output is non-empty (tracked or untracked changes), pause and ask the user what to do.
- Present 3 options: continue as-is, abort, or manual cleanup then rerun.
- Do not run
git stash, git commit, or git clean automatically unless explicitly requested.
- Check for an existing PR for the current head branch.
gh pr list --head <head> --state all --json number,state,mergedAt,updatedAt,url,title,mergeCommit
- If no PR exists → create a new PR.
- If any PR exists and is NOT merged (
mergedAt is null) → push only and finish (do not create a new PR).
- This applies to OPEN or CLOSED (unmerged) PRs.
- Only update title/body/labels if the user explicitly requests changes.
- If all PRs for the head are merged → check for post-merge commits (see below).
- If multiple PRs exist for the head → use the most recently updated PR for reporting, but the create vs push decision is based on
mergedAt.
Post-merge commit check (critical)
When all PRs for the head branch are merged, you must check whether there are new commits after the merge:
- Get the merge commit SHA of the most recent merged PR.
- Count commits after the merge:
git rev-list --count <merge_commit>..HEAD
- Decision:
- If new commits exist → create a new PR (these changes are not in the base branch)
- If no new commits → report "No changes since last merge" and finish (do not create an empty PR)
Why this matters
- Scenario A: PR merged → user makes local changes → pushes → changes are NOT in the merged PR
- Without this check, the changes would be lost or require manual intervention
- Scenario B: PR merged → user says "create PR" without new changes → would create empty/duplicate PR
- This check prevents unnecessary PR creation
PR title rules (must follow)
- Format:
<type>(<scope>): <subject> — Conventional Commits 形式に準拠する。
- type:
feat / fix / docs / chore / refactor / test / ci / perf のいずれか。
- scope: 省略可。変更の影響範囲を端的に示す(例:
gui, core, pty)。
- subject: 70文字以内。命令形(imperative mood)で書く(例: "add …" / "fix …")。先頭大文字禁止、末尾ピリオド禁止。
- ブランチ名にプレフィックス(
feat/, fix/ など)がある場合、タイトルの type と一致させる。
PR body rules (must follow)
Section classification
| Section |
Required |
Notes |
| Summary |
YES |
1-3 bullet points。"what" と "why" を両方含める |
| Changes |
YES |
ファイル/モジュール単位で変更内容を列挙 |
| Testing |
YES |
実行したコマンドまたは手動テスト手順を具体的に記載 |
| Closing Issues |
YES |
Closes #N または None のみ。gwt-spec issues may appear in Closing Issues for release PRs |
| Related Issues / Links |
YES |
参照用の Issue番号、SPEC、または "None" を明記 |
| Checklist |
YES |
全項目を確認してチェック/N-A を付ける |
| Context |
Conditional |
3ファイル以上の変更、または非自明な変更理由がある場合は必須 |
| Risk / Impact |
Conditional |
破壊的変更・パフォーマンス影響・ロールバック手順がある場合は必須 |
| Screenshots |
Conditional |
UI 変更がある場合のみ必須 |
| Deployment |
Optional |
デプロイ手順がある場合のみ記載 |
| Notes |
Optional |
レビュアーへの補足がある場合のみ記載 |
Validation (agent must check before creating PR)
- Required セクションに
TODO が残っていたら PR を作成してはならない。
- Conditional セクションが該当しない場合は、セクション自体を削除する(空の TODO を残さない)。
- Summary の各 bullet は 1文で完結 させる。曖昧な表現("いくつかの変更", "various fixes")を禁止する。
- Changes は 変更ファイルまたはモジュール名を含む 具体的な記述にする。
- Testing は 再現可能な手順 を書く("テスト済み" のような曖昧な記述を禁止)。
- Closing Issues は
Closes #123 または None のみを許可する。bare #123 は禁止する。
- gwt-spec issues may appear in Closing Issues for release PRs when they should auto-close on release. develop PR で
Related Issues / Links にだけ置かれた gwt-spec も release tooling が release PR の Closing Issues に昇格する。通常 Issue は Related Issues / Links にだけ置いた場合、参照専用として扱う。
- Checklist の未チェック項目には理由コメントを付ける(例:
- [ ] Docs updated — N/A: no user-facing change)。
- Related Issues は
#123 形式または URL で記載する。該当なしの場合は "None" と明記する。
Issue/PR Comment Formatting (must follow)
- Final comment text must not contain escaped newline literals such as
\n.
- Use real line breaks in comment bodies. Do not rely on escaped sequences for formatting.
- Before posting, verify the final body does not accidentally include escaped control sequences (
\n, \t).
- If a raw escape sequence must be shown for explanation, include it only inside a fenced code block and clarify it is intentional.
Issue Progress Comment Template (required for issue-based work)
When work is tracked in GitHub Issues, progress updates must use this template:
Progress
- ...
Done
- ...
Next
- ...
- Post updates at least when starting work, after meaningful progress, and when blocked/unblocked.
- In
Next, explicitly state blockers or the immediate next action.
Workflow (recommended)
Confirm repo + branches
- Repo root:
git rev-parse --show-toplevel
- Current branch (head):
git rev-parse --abbrev-ref HEAD
- Base branch defaults to
develop unless user specifies.
Check local working tree state (preflight)
- Run
git status --porcelain.
- If empty, continue.
- If non-empty, show detected files and ask the user to choose:
- Continue as-is
- Abort
- Manual cleanup first (
git commit / git stash / git clean) and rerun
- Proceed only when the user explicitly chooses continue.
Fetch latest remote state
git fetch origin to ensure accurate comparison
Check existing PR for head branch
- Use decision rules above to pick action.
- Treat
mergedAt as the source of truth for "merged".
If all PRs are merged, perform post-merge commit check
- Get merge commit:
gh pr list --head <head> --state merged --json mergeCommit -q '.[0].mergeCommit.oid'
- Count new commits:
git rev-list --count <merge_commit>..HEAD
- If 0 → finish with message "No new changes since merge"
- If >0 → proceed to create new PR
Ensure the head branch is pushed
- If no upstream:
git push -u origin <head>
- Otherwise:
git push
Collect PR inputs (for new PR or explicit update)
- Title, Summary, Context, Changes, Testing, Closing Issues, Risk/Impact, Deployment, Screenshots, Related Links, Notes
- Optional: labels, reviewers, assignees, draft
Build PR body from template
- Read the template from the gh-pr skill path (not the current project path):
GH_PR_SKILL_DIR="${GH_PR_SKILL_DIR:-$HOME/.codex/skills/gh-pr}"
PR_BODY_TEMPLATE="${GH_PR_SKILL_DIR}/references/pr-body-template.md"
- Read
${PR_BODY_TEMPLATE} and fill all required placeholders.
- Conditional セクションが該当しない場合はセクションごと削除する。
- テンプレート内の
<!-- GUIDE: ... --> コメントは最終出力から削除する。
- Required セクションに TODO が残っている場合は PR を作成せず、ユーザーに不足情報を確認する。
- Closing Issues は
Closes #N か None のみを許可する。release PR で auto-close したい gwt-spec は Closing Issues に記載する。develop PR の Related Issues にある gwt-spec は release tooling で Closing Issues に昇格される。
Create or update the PR
- Create:
gh pr create -B <base> -H <head> --title "<title>" --body-file <file>
- Update (only if user asked):
gh pr edit <number> --title "<title>" --body-file <file>
Return PR URL
gh pr view <number> --json url -q .url
- Post-PR CI/merge check (automatic).
- After PR creation or push, load
github/skills/gh-fix-ci/SKILL.md and
follow its workflow to inspect CI status, merge state, and review feedback.
- If all CI checks are still pending, poll (30s interval) until complete.
- If conflicts, review issues, or CI failures are detected, proceed with
the gh-fix-ci workflow to diagnose and fix.
Command snippets (bash)
head=$(git rev-parse --abbrev-ref HEAD)
base=develop
GH_PR_SKILL_DIR="${GH_PR_SKILL_DIR:-$HOME/.codex/skills/gh-pr}"
PR_BODY_TEMPLATE="${GH_PR_SKILL_DIR}/references/pr-body-template.md"
if [ ! -f "$PR_BODY_TEMPLATE" ]; then
echo "PR template not found: $PR_BODY_TEMPLATE" >&2
exit 1
fi
# Preflight: local working tree state
status_lines=$(git status --porcelain)
if [ -n "$status_lines" ] && [ "${ALLOW_DIRTY_WORKTREE:-0}" != "1" ]; then
echo "Detected local uncommitted/untracked changes:" >&2
echo "$status_lines" >&2
echo "Choose one before continuing: continue as-is, abort, or manual cleanup then rerun." >&2
echo "Set ALLOW_DIRTY_WORKTREE=1 only after explicit user confirmation to continue." >&2
exit 1
fi
# Fetch latest remote state
git fetch origin
# Check existing PRs for the head branch
pr_json=$(gh pr list --head "$head" --state all --json number,state,mergedAt,mergeCommit)
pr_count=$(echo "$pr_json" | jq 'length')
unmerged_count=$(echo "$pr_json" | jq 'map(select(.mergedAt == null)) | length')
if [ "$pr_count" -eq 0 ]; then
action=create
elif [ "$unmerged_count" -gt 0 ]; then
action=push_only
else
# All PRs are merged - check for post-merge commits
merge_commit=$(echo "$pr_json" | jq -r 'sort_by(.mergedAt) | last | .mergeCommit.oid')
if [ -n "$merge_commit" ] && [ "$merge_commit" != "null" ]; then
new_commits=$(git rev-list --count "$merge_commit"..HEAD 2>/dev/null || echo "0")
if [ "$new_commits" -gt 0 ]; then
echo "Found $new_commits commit(s) after merge - creating new PR"
action=create
else
echo "No new commits since merge - nothing to do"
action=none
fi
else
# Fallback: check against base branch
new_commits=$(git rev-list --count "origin/$base"..HEAD 2>/dev/null || echo "0")
if [ "$new_commits" -gt 0 ]; then
action=create
else
action=none
fi
fi
fi
# Execute action
case "$action" in
create)
cp "$PR_BODY_TEMPLATE" /tmp/pr-body.md
git push -u origin "$head"
gh pr create -B "$base" -H "$head" --title "..." --body-file /tmp/pr-body.md
;;
push_only)
echo "Existing unmerged PR found - pushing changes only"
git push
gh pr list --head "$head" --state open --json url -q '.[0].url'
;;
none)
echo "No action needed - no new changes since last merge"
;;
esac
References
${GH_PR_SKILL_DIR}/references/pr-body-template.md: PR body template
1---2name: gh-pr3description: Create or update GitHub Pull Requests with the gh CLI, including deciding whether to create a new PR or only push based on existing PR merge status. Use when the user asks to open/create/edit a PR, generate a PR body/template, or says 'PRを出して/PR作成/gh pr'. Defaults: base=develop, head=current branch (same-branch only; never create/switch branches).4---56# GH PR78## Overview910Create or update GitHub Pull Requests with the gh CLI using a detailed body template and strict same-branch rules.1112## Decision rules (must follow)13141. **Do not create or switch branches.** Always use the current branch as the PR head.152. **Check local working tree state before push/PR operations.**16 - `git status --porcelain`17 - If output is non-empty (tracked or untracked changes), pause and ask the user what to do.18 - Present 3 options: continue as-is, abort, or manual cleanup then rerun.19 - **Do not** run `git stash`, `git commit`, or `git clean` automatically unless explicitly requested.203. **Check for an existing PR for the current head branch.**21 - `gh pr list --head <head> --state all --json number,state,mergedAt,updatedAt,url,title,mergeCommit`224. **If no PR exists** → create a new PR.235. **If any PR exists and is NOT merged** (`mergedAt` is null) → push only and finish (do **not** create a new PR).24 - This applies to OPEN or CLOSED (unmerged) PRs.25 - Only update title/body/labels if the user explicitly requests changes.266. **If all PRs for the head are merged** → check for post-merge commits (see below).277. **If multiple PRs exist for the head** → use the most recently updated PR for reporting, but the create vs push decision is based on `mergedAt`.2829## Post-merge commit check (critical)3031When all PRs for the head branch are merged, you **must** check whether there are new commits after the merge:32331. **Get the merge commit SHA** of the most recent merged PR.342. **Count commits after the merge**: `git rev-list --count <merge_commit>..HEAD`353. **Decision**:36 - If new commits exist → create a new PR (these changes are not in the base branch)37 - If no new commits → report "No changes since last merge" and finish (do **not** create an empty PR)3839### Why this matters4041- **Scenario A**: PR merged → user makes local changes → pushes → changes are NOT in the merged PR42 - Without this check, the changes would be lost or require manual intervention43- **Scenario B**: PR merged → user says "create PR" without new changes → would create empty/duplicate PR44 - This check prevents unnecessary PR creation4546## PR title rules (must follow)47481. **Format**: `<type>(<scope>): <subject>` — Conventional Commits 形式に準拠する。492. **type**: `feat` / `fix` / `docs` / `chore` / `refactor` / `test` / `ci` / `perf` のいずれか。503. **scope**: 省略可。変更の影響範囲を端的に示す(例: `gui`, `core`, `pty`)。514. **subject**: 70文字以内。命令形(imperative mood)で書く(例: "add …" / "fix …")。先頭大文字禁止、末尾ピリオド禁止。525. ブランチ名にプレフィックス(`feat/`, `fix/` など)がある場合、**タイトルの type と一致させる**。5354## PR body rules (must follow)5556### Section classification5758| Section | Required | Notes |59|---------|----------|-------|60| Summary | **YES** | 1-3 bullet points。"what" と "why" を両方含める |61| Changes | **YES** | ファイル/モジュール単位で変更内容を列挙 |62| Testing | **YES** | 実行したコマンドまたは手動テスト手順を具体的に記載 |63| Closing Issues | **YES** | `Closes #N` または `None` のみ。gwt-spec issues may appear in Closing Issues for release PRs |64| Related Issues / Links | **YES** | 参照用の Issue番号、SPEC、または "None" を明記 |65| Checklist | **YES** | 全項目を確認してチェック/N-A を付ける |66| Context | Conditional | 3ファイル以上の変更、または非自明な変更理由がある場合は必須 |67| Risk / Impact | Conditional | 破壊的変更・パフォーマンス影響・ロールバック手順がある場合は必須 |68| Screenshots | Conditional | UI 変更がある場合のみ必須 |69| Deployment | Optional | デプロイ手順がある場合のみ記載 |70| Notes | Optional | レビュアーへの補足がある場合のみ記載 |7172### Validation (agent must check before creating PR)73741. **Required セクションに `TODO` が残っていたら PR を作成してはならない。**752. Conditional セクションが該当しない場合は、セクション自体を削除する(空の TODO を残さない)。763. Summary の各 bullet は **1文で完結** させる。曖昧な表現("いくつかの変更", "various fixes")を禁止する。774. Changes は **変更ファイルまたはモジュール名を含む** 具体的な記述にする。785. Testing は **再現可能な手順** を書く("テスト済み" のような曖昧な記述を禁止)。796. Closing Issues は `Closes #123` または `None` のみを許可する。bare `#123` は禁止する。807. gwt-spec issues may appear in Closing Issues for release PRs when they should auto-close on release. develop PR で `Related Issues / Links` にだけ置かれた gwt-spec も release tooling が release PR の Closing Issues に昇格する。通常 Issue は `Related Issues / Links` にだけ置いた場合、参照専用として扱う。818. Checklist の未チェック項目には理由コメントを付ける(例: `- [ ] Docs updated — N/A: no user-facing change`)。829. Related Issues は `#123` 形式または URL で記載する。該当なしの場合は "None" と明記する。8384## Issue/PR Comment Formatting (must follow)8586- Final comment text must not contain escaped newline literals such as `\n`.87- Use real line breaks in comment bodies. Do not rely on escaped sequences for formatting.88- Before posting, verify the final body does not accidentally include escaped control sequences (`\n`, `\t`).89- If a raw escape sequence must be shown for explanation, include it only inside a fenced code block and clarify it is intentional.9091## Issue Progress Comment Template (required for issue-based work)9293When work is tracked in GitHub Issues, progress updates must use this template:9495```markdown96Progress97- ...9899Done100- ...101102Next103- ...104```105106- Post updates at least when starting work, after meaningful progress, and when blocked/unblocked.107- In `Next`, explicitly state blockers or the immediate next action.108109## Workflow (recommended)1101111. **Confirm repo + branches**112 - Repo root: `git rev-parse --show-toplevel`113 - Current branch (head): `git rev-parse --abbrev-ref HEAD`114 - Base branch defaults to `develop` unless user specifies.1151162. **Check local working tree state (preflight)**117 - Run `git status --porcelain`.118 - If empty, continue.119 - If non-empty, show detected files and ask the user to choose:120 - Continue as-is121 - Abort122 - Manual cleanup first (`git commit` / `git stash` / `git clean`) and rerun123 - Proceed only when the user explicitly chooses continue.1241253. **Fetch latest remote state**126 - `git fetch origin` to ensure accurate comparison1271284. **Check existing PR for head branch**129 - Use decision rules above to pick action.130 - Treat `mergedAt` as the source of truth for "merged".1311325. **If all PRs are merged, perform post-merge commit check**133 - Get merge commit: `gh pr list --head <head> --state merged --json mergeCommit -q '.[0].mergeCommit.oid'`134 - Count new commits: `git rev-list --count <merge_commit>..HEAD`135 - If 0 → finish with message "No new changes since merge"136 - If >0 → proceed to create new PR1371386. **Ensure the head branch is pushed**139 - If no upstream: `git push -u origin <head>`140 - Otherwise: `git push`1411427. **Collect PR inputs (for new PR or explicit update)**143 - Title, Summary, Context, Changes, Testing, Closing Issues, Risk/Impact, Deployment, Screenshots, Related Links, Notes144 - Optional: labels, reviewers, assignees, draft1451468. **Build PR body from template**147 - Read the template from the gh-pr skill path (not the current project path):148 - `GH_PR_SKILL_DIR="${GH_PR_SKILL_DIR:-$HOME/.codex/skills/gh-pr}"`149 - `PR_BODY_TEMPLATE="${GH_PR_SKILL_DIR}/references/pr-body-template.md"`150 - Read `${PR_BODY_TEMPLATE}` and fill all required placeholders.151 - **Conditional セクションが該当しない場合はセクションごと削除する。**152 - **テンプレート内の `<!-- GUIDE: ... -->` コメントは最終出力から削除する。**153 - **Required セクションに TODO が残っている場合は PR を作成せず、ユーザーに不足情報を確認する。**154 - **Closing Issues は `Closes #N` か `None` のみを許可する。release PR で auto-close したい gwt-spec は Closing Issues に記載する。develop PR の Related Issues にある gwt-spec は release tooling で Closing Issues に昇格される。**1551569. **Create or update the PR**157 - Create: `gh pr create -B <base> -H <head> --title "<title>" --body-file <file>`158 - Update (only if user asked): `gh pr edit <number> --title "<title>" --body-file <file>`15916010. **Return PR URL**161 - `gh pr view <number> --json url -q .url`16216311. **Post-PR CI/merge check (automatic).**164 - After PR creation or push, load `github/skills/gh-fix-ci/SKILL.md` and165 follow its workflow to inspect CI status, merge state, and review feedback.166 - If all CI checks are still pending, poll (30s interval) until complete.167 - If conflicts, review issues, or CI failures are detected, proceed with168 the gh-fix-ci workflow to diagnose and fix.169170## Command snippets (bash)171172```bash173head=$(git rev-parse --abbrev-ref HEAD)174base=develop175GH_PR_SKILL_DIR="${GH_PR_SKILL_DIR:-$HOME/.codex/skills/gh-pr}"176PR_BODY_TEMPLATE="${GH_PR_SKILL_DIR}/references/pr-body-template.md"177178if [ ! -f "$PR_BODY_TEMPLATE" ]; then179 echo "PR template not found: $PR_BODY_TEMPLATE" >&2180 exit 1181fi182183# Preflight: local working tree state184status_lines=$(git status --porcelain)185if [ -n "$status_lines" ] && [ "${ALLOW_DIRTY_WORKTREE:-0}" != "1" ]; then186 echo "Detected local uncommitted/untracked changes:" >&2187 echo "$status_lines" >&2188 echo "Choose one before continuing: continue as-is, abort, or manual cleanup then rerun." >&2189 echo "Set ALLOW_DIRTY_WORKTREE=1 only after explicit user confirmation to continue." >&2190 exit 1191fi192193# Fetch latest remote state194git fetch origin195196# Check existing PRs for the head branch197pr_json=$(gh pr list --head "$head" --state all --json number,state,mergedAt,mergeCommit)198pr_count=$(echo "$pr_json" | jq 'length')199unmerged_count=$(echo "$pr_json" | jq 'map(select(.mergedAt == null)) | length')200201if [ "$pr_count" -eq 0 ]; then202 action=create203elif [ "$unmerged_count" -gt 0 ]; then204 action=push_only205else206 # All PRs are merged - check for post-merge commits207 merge_commit=$(echo "$pr_json" | jq -r 'sort_by(.mergedAt) | last | .mergeCommit.oid')208209 if [ -n "$merge_commit" ] && [ "$merge_commit" != "null" ]; then210 new_commits=$(git rev-list --count "$merge_commit"..HEAD 2>/dev/null || echo "0")211212 if [ "$new_commits" -gt 0 ]; then213 echo "Found $new_commits commit(s) after merge - creating new PR"214 action=create215 else216 echo "No new commits since merge - nothing to do"217 action=none218 fi219 else220 # Fallback: check against base branch221 new_commits=$(git rev-list --count "origin/$base"..HEAD 2>/dev/null || echo "0")222223 if [ "$new_commits" -gt 0 ]; then224 action=create225 else226 action=none227 fi228 fi229fi230231# Execute action232case "$action" in233 create)234 cp "$PR_BODY_TEMPLATE" /tmp/pr-body.md235236 git push -u origin "$head"237 gh pr create -B "$base" -H "$head" --title "..." --body-file /tmp/pr-body.md238 ;;239 push_only)240 echo "Existing unmerged PR found - pushing changes only"241 git push242 gh pr list --head "$head" --state open --json url -q '.[0].url'243 ;;244 none)245 echo "No action needed - no new changes since last merge"246 ;;247esac248```249250## References251252- `${GH_PR_SKILL_DIR}/references/pr-body-template.md`: PR body template