Просмотр исходного кода

feat(github-ops): Add issue + PR operations with preview discipline

Extends github-ops past its previous "repo create / release / metadata"
scope to cover the issue and pull-request operations that were marked as
future work. PR create migrates from git-ops T2 (which keeps working but
github-ops is now the canonical home — anything talking to api.github.com
belongs here per the boundary rule on line 13).

New `## Operations` section in SKILL.md documenting:

- Issues: view/list (read), create/comment/edit (preview-gated), triage
  (mechanical), close/reopen (with optional closing-comment preview).
- PRs: view/list/diff/checks (read), create/comment/review/edit
  (preview-gated), labels/reviewers/ready (mechanical), merge (explicit
  approval + pre-merge gate + strategy decision), close.

Hard rule 8 added: every public post (issue/PR/release body, merge commit
subject) must be quoted verbatim in chat and approved before sending,
per ~/.claude/rules/public-posts.md. Mechanical actions (labels, assign,
close-without-message, ready) skip preview.

Pre-merge gate distilled from PR #11:
1. mergeable=MERGEABLE, mergeStateStatus=CLEAN
2. all checks pass (gh pr checks --watch during CI run)
3. diff reviewed, PR body still accurate
4. merge strategy decided (default --squash; ask if uncertain)
5. branch deletion stays a separate explicit step (not bundled)

Two new reference files (525 lines combined):

- references/issue-ops.md - per-op playbooks, preview-block format,
  tone defaults for maintainer responses, bug-report body template,
  closing-comment templates, common workflows.
- references/pr-ops.md - per-op playbooks, PR body shape (with
  Closes #N footer), review-flow templates, full pre-merge gate
  procedure, merge-strategy decision tree, branch-cleanup sequence.

No scripts yet (following the existing convention - extract when
patterns truly repeat across uses).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0xDarkMatter 2 недель назад
Родитель
Сommit
2ef6f40640

+ 59 - 4
skills/github-ops/SKILL.md

@@ -1,6 +1,6 @@
 ---
 name: github-ops
-description: "GitHub remote operations — repo creation, metadata (description/homepage/topics), releases, README 'Recent Updates' enforcement. Companion to git-ops (local) and push-gate (pre-push safety). Three modes: new (first publish), update (subsequent release), audit (read-only checklist). Triggers on: push to github, publish repo, ship release, cut release, gh release, set topics, repo description, github metadata, recent updates section, audit github repo, repo visibility, make repo public, gh repo create."
+description: "GitHub remote operations — repo creation, metadata (description/homepage/topics), releases, README 'Recent Updates' enforcement, and issue / PR management with preview-before-send discipline. Companion to git-ops (local) and push-gate (pre-push safety). Three modes: new (first publish), update (subsequent release), audit (read-only checklist), plus atomic operations for issues and PRs. Triggers on: push to github, publish repo, ship release, cut release, gh release, set topics, repo description, github metadata, recent updates section, audit github repo, repo visibility, make repo public, gh repo create, gh issue, gh pr, create issue, comment on issue, close issue, triage issue, create PR, review PR, merge PR, pre-merge check, pr checks."
 license: MIT
 allowed-tools: "Read Write Edit Bash Glob Grep"
 metadata:
@@ -29,7 +29,9 @@ git-ops                        push-gate           github-ops  (this skill)
 | `gh release create` + release notes | **`github-ops`** |
 | README "Recent Updates" section maintenance | **`github-ops`** |
 | Package metadata audit (pyproject/package.json ↔ GH topics ↔ tag ↔ version) | **`github-ops`** |
-| Issues / PRs / Actions / secrets | **`github-ops`** (future) |
+| `gh issue` operations (view/list/create/comment/edit/triage/close) | **`github-ops`** |
+| `gh pr` operations (view/list/diff/checks/create/comment/review/edit/merge/close) | **`github-ops`** |
+| Actions / secrets / branch protection / social preview | **`github-ops`** (future) |
 
 ## Hard rules
 
@@ -40,6 +42,7 @@ git-ops                        push-gate           github-ops  (this skill)
 5. **README "Recent Updates" updates on every release.** This is the one README touch that always happens, regardless of how minor the release. See `references/readme-recent-updates.md` for the canonical claude-mods style.
 6. **Never push without confirming visibility decision.** When creating a new repo, surface visibility as a flippable line in the plan ("creating as **private** — say 'public' to flip"), not buried in flag soup.
 7. **No local-machine paths in committed content.** Never bake `C:\Users\<name>\…`, `/home/<name>/…`, `/Users/<name>/…`, `/tmp/<one-off-test-dir>`, or any other machine-specific path into README entries, Recent Updates bullets, CHANGELOG entries, release notes, tag annotations, or commit messages. Public release artefacts have to read the same on someone else's machine. Use generic placeholders (`~/Temp/`, `<temp-dir>`, "a temp directory") or describe the file's purpose abstractly instead. If a path genuinely is part of the project's public API (install location, config path), state it canonically (`$HOME/.claude/skills/...`), not as a literal absolute that includes a user name.
+8. **Preview every public post before sending.** Anything with author voice that lands on a third-party surface — `gh issue create/comment/edit --body`, `gh pr create/comment/review/edit --body`, `gh release create --notes`, merge commit `--subject`/`--body` — must be quoted verbatim in chat with the exact send command named, then await explicit approval before invoking. Mechanical actions with no body (label, assign, milestone, mark-ready, close-without-message) skip preview. See `~/.claude/rules/public-posts.md` for the full rule.
 
 ## Three modes
 
@@ -188,6 +191,56 @@ GITHUB STATE CHECKS (skip if no remote)
 
 Output: per-row pass/fail/warn, then a summary score and list of fixes. Fixes are suggested but not applied — the user decides whether to run mode `new` or mode `update` to act on them.
 
+## Operations
+
+Atomic GH-side actions that don't fit the three multi-step modes. Each operation that writes author voice to a third-party surface (issue/PR body, comment, review body, release notes, merge commit subject/body) is governed by **hard rule 8** and [public-posts](~/.claude/rules/public-posts.md): quote the exact body in chat, name the send command, wait for explicit approval, then send. Mechanical actions (labels, assign, close-without-message, mark-ready) skip preview.
+
+### Issues
+
+Reads (no preview): `gh issue view <n>`, `gh issue view <n> --comments`, `gh issue list`, `gh api repos/<o>/<r>/issues/<n>` (for fields not in the default view).
+
+Writes:
+
+| Op | Command | Preview? |
+|---|---|---|
+| Create | `gh issue create --title --body` | **Yes** (title + body) |
+| Comment | `gh issue comment <n> --body` | **Yes** (body) |
+| Edit title/body | `gh issue edit <n> --title --body` | **Yes** |
+| Triage (label/assign/milestone) | `gh issue edit <n> --add-label … --assignee … --milestone …` | No (mechanical) |
+| Close / reopen | `gh issue close <n>` / `gh issue reopen <n>` | No, **unless** closing with a comment — preview the comment |
+| Transfer | `gh issue transfer <n> <target-repo>` | No (mechanical), but confirm target with user |
+
+See `references/issue-ops.md` for full playbooks, triage flow, and closing-comment templates.
+
+### Pull Requests
+
+Reads (no preview): `gh pr view <n>`, `gh pr view <n> --comments`, `gh pr list`, `gh pr diff <n>`, `gh pr checks <n>`, `gh pr checks <n> --watch`, `gh api repos/<o>/<r>/pulls/<n>/comments` (inline review comments).
+
+Writes:
+
+| Op | Command | Preview? |
+|---|---|---|
+| Create | `gh pr create --title --body` | **Yes** (title + body) |
+| Comment | `gh pr comment <n> --body` | **Yes** |
+| Review (approve / request changes / comment) | `gh pr review <n> --approve --body …` | **Yes** (body, if any) |
+| Edit title/body | `gh pr edit <n> --title --body` | **Yes** |
+| Edit labels / reviewers | `gh pr edit <n> --add-label … --add-reviewer …` | No (mechanical) |
+| Mark ready (un-draft) | `gh pr ready <n>` | No (mechanical) |
+| Merge | `gh pr merge <n> --squash` (or `--merge` / `--rebase`) | No body to preview by default, but **explicit user approval required** + run pre-merge gate first. If passing `--subject` / `--body`, preview those (they become the commit message on `main`) |
+| Close | `gh pr close <n>` | No, **unless** closing with a comment — preview the comment |
+
+**PR creation lives here, not in git-ops.** git-ops handles local commits/branches/push; the `gh pr create` call itself talks to `api.github.com` and belongs in this skill. (Existing git-ops T2 PR-create still works; new flows should route through github-ops.)
+
+**Pre-merge gate** — never invoke `gh pr merge` without first confirming:
+
+1. `gh pr view <n> --json mergeable,mergeStateStatus` → `mergeable: MERGEABLE`, `mergeStateStatus: CLEAN`
+2. `gh pr checks <n>` → every check passed (or explicitly ignored with user approval)
+3. `gh pr diff <n>` reviewed — confirm no surprise scope, no committed secrets/local paths, no stale PR-body claims
+4. Merge strategy picked — **default squash** for fix/feature branches with multiple WIP commits; `--merge` only when individual commits matter; `--rebase` for linear-history repos. Ask if uncertain.
+5. Branch deletion is a **separate explicit step**, not bundled. Default to keeping the branch; delete remote + local after merge only on explicit user OK (it's destructive enough to warrant its own confirmation, and a checked-out branch can't be deleted).
+
+See `references/pr-ops.md` for full playbooks, review-flow templates, and the merge-strategy decision tree.
+
 ## Conventions enforced (load reference files for detail)
 
 | Convention | File | Default |
@@ -197,6 +250,8 @@ Output: per-row pass/fail/warn, then a summary score and list of fixes. Fixes ar
 | README Recent Updates style | `references/readme-recent-updates.md` | claude-mods per-version blocks (alternate: flarecrawl table) |
 | Repo visibility default | `references/repo-visibility.md` | `--private` unless user says "public" |
 | Metadata audit checklist | `references/metadata-checklist.md` | full source-of-truth for mode `audit` |
+| Issue operations | `references/issue-ops.md` | view → triage → comment (with preview) → close; closing comments preview-gated |
+| PR operations | `references/pr-ops.md` | create (preview body) → review → pre-merge gate → squash by default; branch deletion separate explicit step |
 
 ## Git authorship
 
@@ -254,8 +309,6 @@ When invoking git-ops T2 operations, dispatch to git-agent with a one-shot promp
 
 ## Future expansion (not yet implemented)
 
-- **Issues** — `gh issue create/list/comment/close` workflows
-- **PRs** — `gh pr` operations (note: git-ops T2 currently owns PR creation; could migrate or stay split — decide on first need)
 - **Actions** — workflow file scaffolding, `gh workflow` operations
 - **Secrets** — `gh secret set/list/delete` (with secure handling)
 - **Branch protection** — `gh api` calls for protection rules
@@ -274,6 +327,8 @@ When adding any of the above, keep the boundary discipline: anything talking to
 | `references/readme-recent-updates.md` | "Recent Updates" section format + emoji vocabulary |
 | `references/repo-visibility.md` | Private-by-default policy |
 | `references/metadata-checklist.md` | Audit checklist source of truth |
+| `references/issue-ops.md` | Issue operation playbooks (view/triage/comment/create/close) + preview templates |
+| `references/pr-ops.md` | PR operation playbooks (create/review/merge) + pre-merge gate + merge-strategy decision tree |
 | `scripts/` | (empty; reserved — extract patterns into scripts when they repeat across uses) |
 | `assets/` | (empty; reserved for README templates / snippets) |
 

+ 232 - 0
skills/github-ops/references/issue-ops.md

@@ -0,0 +1,232 @@
+# Issue Operations Reference
+
+Per-operation playbooks for `gh issue` workflows. Every write op that has author voice (`--body` / `--title`) is **preview-gated** per hard rule 8 — quote the draft verbatim in chat, name the send command, wait for explicit user approval, then send.
+
+## Reads (no preview)
+
+```bash
+# Single issue with metadata
+gh issue view <n> --repo <owner>/<repo>
+
+# Issue + full comment thread (use this when responding — you need the context)
+gh issue view <n> --repo <owner>/<repo> --comments
+
+# Raw JSON for fields the default view omits (createdAt, labels, assignees, etc.)
+gh api repos/<owner>/<repo>/issues/<n> --jq '{number,title,state,user:.user.login,labels:[.labels[].name],body}'
+
+# List + filter
+gh issue list --repo <owner>/<repo> --state open --label bug --limit 20
+
+# Search across repos
+gh search issues "is:open label:bug repo:<owner>/<repo>"
+```
+
+When reading an issue you intend to respond to, always pull comments too (`--comments`) — replying to the issue body without seeing the discussion is how stale answers happen.
+
+## Triage (mechanical, no preview)
+
+Labels, assignees, milestones carry no author voice — they're metadata. Surface what you're about to do in chat, but no body preview needed.
+
+```bash
+# Add labels
+gh issue edit <n> --repo <o>/<r> --add-label "bug,needs-repro"
+
+# Remove labels
+gh issue edit <n> --repo <o>/<r> --remove-label "needs-triage"
+
+# Assign
+gh issue edit <n> --repo <o>/<r> --add-assignee <user>
+
+# Milestone
+gh issue edit <n> --repo <o>/<r> --milestone "v2.11.0"
+```
+
+If the repo has a label scheme (`bug`/`feat`/`docs`/`question`/`needs-repro`/`good-first-issue` etc.), match it. `gh label list --repo <o>/<r>` to see what exists. Don't invent labels without asking.
+
+## Comment (preview required)
+
+The flow that gets it wrong without discipline. Always:
+
+1. **Compose** the comment as a quoted block in chat (verbatim, not paraphrased).
+2. **Name** the exact send command.
+3. **Wait** for explicit approval ("send", "ship it", "looks good", or an edit).
+4. **Send** only after approval.
+
+### Template for the chat preview
+
+> Drafted comment for issue #<n>:
+>
+> ```markdown
+> <comment body, exactly as it would be sent>
+> ```
+>
+> Command: `gh issue comment <n> --repo <o>/<r> --body "..."`
+>
+> Send?
+
+### Send
+
+```bash
+gh issue comment <n> --repo <o>/<r> --body "$(cat <<'EOF'
+<approved body>
+EOF
+)"
+```
+
+Heredoc with single-quoted `'EOF'` so the body is literal (no shell interpolation). Markdown renders on github.com — code fences, links, `@mentions`, `#refs` all work.
+
+### Tone defaults (project maintainer responding to a reporter)
+
+- Lead with thanks and acknowledge what was right about the report.
+- If a fix shipped, state the version/PR. Link the release if minor+.
+- If the report uncovered related issues, briefly note them — credit goes to the reporter.
+- Sign-off via `@mention` if directly thanking. Don't `@mention` everyone in a thread.
+- Don't apologise excessively or perform humility. Match the project's existing voice.
+- Anti-patterns: marketing fluff, emoji walls, "we'll get right on it" without a concrete plan.
+
+## Create (preview required — title AND body)
+
+A new issue's title shows in lists and notifications; body is the substance. Preview both.
+
+### Chat preview
+
+> Drafted issue for `<o>/<r>`:
+>
+> **Title:** `<title>`
+>
+> **Body:**
+> ```markdown
+> <body>
+> ```
+>
+> **Labels:** bug, needs-repro
+> **Assignee:** (none)
+>
+> Command: `gh issue create --title "..." --body "..." --label "..."`
+>
+> Send?
+
+### Send
+
+```bash
+gh issue create --repo <o>/<r> \
+  --title "<approved title>" \
+  --body "$(cat <<'EOF'
+<approved body>
+EOF
+)" \
+  --label "<labels>" \
+  --assignee "<user>"
+```
+
+### Bug report template (recommended body shape)
+
+```markdown
+## Problem
+
+<one-paragraph what's wrong + observable symptom>
+
+## Repro
+
+1. <step>
+2. <step>
+
+## Expected vs actual
+
+- Expected: <…>
+- Actual: <…>
+
+## Environment
+
+- Tool / version: <…>
+- OS: <…>
+
+## Suggested cause / fix (optional)
+
+<…>
+```
+
+## Edit title/body (preview required)
+
+Same preview discipline as create — edits are public. The original is also preserved in the issue's edit history so reviewers can see what changed.
+
+```bash
+gh issue edit <n> --repo <o>/<r> \
+  --title "<new title>" \
+  --body "$(cat <<'EOF'
+<new body>
+EOF
+)"
+```
+
+If you're only changing labels/assignees, that's mechanical — preview not required.
+
+## Close / reopen
+
+Plain close — no preview.
+
+```bash
+gh issue close <n> --repo <o>/<r>
+gh issue reopen <n> --repo <o>/<r>
+```
+
+Closing with a reason (`--reason completed|not-planned|duplicate`) — no preview, but state the reason in chat first.
+
+Closing with a parting comment — **preview the comment** (it's a public post), then:
+
+```bash
+gh issue comment <n> --repo <o>/<r> --body "..."   # preview-gated
+gh issue close <n> --repo <o>/<r>
+```
+
+### Closing-comment templates
+
+**Fixed:**
+> Fixed in v<X.Y.Z>. <one-sentence summary of the fix>. <PR link if applicable>.
+
+**Won't fix:**
+> Closing as <reason — out of scope / duplicate of #N / by design>. Brief why: <…>. Happy to reopen if <condition>.
+
+**Not reproducible:**
+> Closing as not reproducible — tried <what>, saw <what>. If you can share <specific thing>, please reopen.
+
+## Common workflows
+
+### Respond to a bug report and fix
+
+```
+1. gh issue view <n> --comments            # context
+2. Reproduce locally; identify cause
+3. Draft fix on branch; PR with "Fixes #<n>" in body
+4. After merge, GitHub auto-closes #<n>; post a closing comment
+   with version + link (preview-gated)
+```
+
+### Triage incoming issues
+
+```
+1. gh issue list --label needs-triage      # batch view
+2. For each:
+   - gh issue view <n> --comments
+   - Apply labels: gh issue edit <n> --add-label … --remove-label needs-triage
+   - Assign milestone if scoped
+   - If duplicate: comment with "Duplicate of #<m>", close with --reason duplicate
+   - If needs more info: comment requesting specifics, add label "needs-repro"
+```
+
+### Convert a discussion into an actionable issue
+
+```
+1. gh issue view <discussion-n> --comments  # distill the actionable scope
+2. gh issue create --title "<scoped title>" --body "<distilled scope, link back to #discussion-n>"
+3. Optionally close the discussion with a link to the new issue
+```
+
+## Anti-patterns
+
+- ❌ Replying to an issue without reading its existing comments.
+- ❌ Inventing labels that don't exist in the project's scheme.
+- ❌ Closing with `--reason not-planned` without a comment — leaves the reporter guessing.
+- ❌ `@mentioning` every previous commenter to "ping" them — they already got notified.
+- ❌ Promising a fix or timeline you can't commit to.
+- ❌ Sending a comment without showing the draft to the user first (hard rule 8).

+ 293 - 0
skills/github-ops/references/pr-ops.md

@@ -0,0 +1,293 @@
+# Pull Request Operations Reference
+
+Per-operation playbooks for `gh pr` workflows. Every write op with author voice (`--body` / `--title` / merge `--subject` / `--body`) is **preview-gated** per hard rule 8 — quote the draft verbatim in chat, name the send command, wait for explicit user approval, then send.
+
+## Reads (no preview)
+
+```bash
+# Single PR with metadata
+gh pr view <n> --repo <o>/<r>
+
+# PR + comment thread (the discussion is half the story)
+gh pr view <n> --repo <o>/<r> --comments
+
+# Diff (use this — not local git diff — to see exactly what the PR proposes)
+gh pr diff <n> --repo <o>/<r>
+
+# CI checks (snapshot)
+gh pr checks <n> --repo <o>/<r>
+
+# CI checks (block until all complete — for use during merge gate)
+gh pr checks <n> --repo <o>/<r> --watch --interval 10
+
+# List with filters
+gh pr list --repo <o>/<r> --state open --base main --limit 20
+
+# Inline review comments on specific lines (default --comments shows top-level only)
+gh api repos/<o>/<r>/pulls/<n>/comments --jq '.[] | {path,line,user:.user.login,body}'
+
+# Detailed merge-readiness fields
+gh pr view <n> --repo <o>/<r> --json mergeable,mergeStateStatus,reviewDecision,statusCheckRollup
+```
+
+## Create (preview required — title AND body)
+
+PR title shows in lists, notifications, and (for squash merges) becomes the commit message subject on `main`. Body should explain *why* + how to verify. Always preview both.
+
+### Chat preview
+
+> Drafted PR for `<o>/<r>`:
+>
+> **Title:** `<title>`
+>
+> **Base:** main ← **Head:** `<branch>`
+>
+> **Body:**
+> ```markdown
+> <body>
+> ```
+>
+> Command: `gh pr create --base main --head <branch> --title "..." --body "..."`
+>
+> Send?
+
+### Send
+
+```bash
+gh pr create --repo <o>/<r> \
+  --base main \
+  --head <branch> \
+  --title "<approved title>" \
+  --body "$(cat <<'EOF'
+<approved body>
+EOF
+)"
+```
+
+### Body shape (claude-mods convention)
+
+```markdown
+## Summary
+
+<1-3 bullets — what changed and why>
+
+## Test plan
+
+- [x] <thing that was tested>
+- [ ] <thing the reviewer should test>
+
+Closes #<n>   <!-- if this PR resolves an issue, link it so merge auto-closes -->
+```
+
+The "Closes #N" / "Fixes #N" footer is load-bearing — it triggers GitHub's auto-close on merge. Without it the issue stays open after the PR lands and someone has to clean up.
+
+### Draft vs ready
+
+For work-in-progress or pre-review polish, create as draft:
+
+```bash
+gh pr create … --draft
+```
+
+Promote later (mechanical, no preview): `gh pr ready <n>`.
+
+## Comment (preview required)
+
+Same discipline as issue comments. Top-level PR comments are different from inline review comments (next section).
+
+### Send
+
+```bash
+gh pr comment <n> --repo <o>/<r> --body "$(cat <<'EOF'
+<approved body>
+EOF
+)"
+```
+
+## Review (preview required for body)
+
+Three flavours: `--approve`, `--request-changes`, `--comment` (review-level, not inline). All three may include a body; if they do, **preview the body**.
+
+```bash
+# Approve with no message — preview not required (the action itself is the signal)
+gh pr review <n> --repo <o>/<r> --approve
+
+# Approve with a parting comment — preview the body
+gh pr review <n> --repo <o>/<r> --approve --body "<approved body>"
+
+# Request changes — body is required and definitely preview-gated
+gh pr review <n> --repo <o>/<r> --request-changes --body "<approved body>"
+
+# Comment-only review (no approve/block) — preview the body
+gh pr review <n> --repo <o>/<r> --comment --body "<approved body>"
+```
+
+Inline-line comments (`gh api repos/<o>/<r>/pulls/<n>/comments`) are heavier — currently out of scope; use the GitHub UI or extend this reference when first needed.
+
+## Edit title / body (preview required)
+
+```bash
+gh pr edit <n> --repo <o>/<r> \
+  --title "<new title>" \
+  --body "$(cat <<'EOF'
+<new body>
+EOF
+)"
+```
+
+Mechanical edits (labels, reviewers, milestone, base branch) don't need preview:
+
+```bash
+gh pr edit <n> --repo <o>/<r> \
+  --add-label "ready-for-review" \
+  --remove-label "wip" \
+  --add-reviewer <user> \
+  --milestone "v2.11.0"
+```
+
+## Pre-merge gate
+
+**Never invoke `gh pr merge` without running this gate first.** This is the discipline distilled from PR #11.
+
+```bash
+# 1. Merge-readiness JSON
+gh pr view <n> --repo <o>/<r> --json mergeable,mergeStateStatus,reviewDecision \
+  --jq '{mergeable,mergeStateStatus,reviewDecision}'
+# Need: mergeable=MERGEABLE, mergeStateStatus=CLEAN (or UNSTABLE if non-required checks fail)
+
+# 2. All checks pass (use --watch to block during a CI run)
+gh pr checks <n> --repo <o>/<r>
+
+# 3. Review the actual diff one more time
+gh pr diff <n> --repo <o>/<r> | less
+
+# 4. Confirm the PR body still accurately describes the diff
+#    (PRs that grew during review often have stale descriptions — edit first if so)
+gh pr view <n> --repo <o>/<r> --json title,body --jq '.body' | head -50
+```
+
+Surface the result in chat as a green/red checklist before proposing the merge command. If anything is red, **stop and report** — don't merge through a failing gate.
+
+## Merge strategy decision tree
+
+| Situation | Strategy | Why |
+|---|---|---|
+| Fix or feature branch with multiple WIP commits all serving one logical change | **Squash** (`--squash`) | Clean single-line history on main; the PR is the unit, individual commits were drafts |
+| Each commit on the branch is independently meaningful and worth preserving in `git log` | **Merge commit** (`--merge`) | Preserves authorship and intermediate steps; useful for collaborative branches |
+| Repo enforces linear history (`gh api repos/<o>/<r> --jq .allow_rebase_merge`) and commits are individually clean | **Rebase** (`--rebase`) | Each commit lands on main as a separate commit, no merge bubble |
+| Mixed / unclear | Ask the user | Don't guess; the project's history style is theirs to decide |
+
+**Default for one-off PRs in this project family (claude-mods, etc.):** `--squash`.
+
+Check repo allowance once via `gh api repos/<o>/<r> --jq '{allow_squash_merge,allow_merge_commit,allow_rebase_merge}'`. If only some are enabled, that constrains the choice.
+
+### Squash with custom subject/body
+
+When using `--squash`, the merge commit's subject and body land on `main` as a public commit. If passing `--subject` / `--body`, **preview both** (hard rule 8):
+
+```bash
+gh pr merge <n> --repo <o>/<r> --squash \
+  --subject "<approved subject — typically: PR title (#<n>)>" \
+  --body "$(cat <<'EOF'
+<approved body — typically: one-paragraph summary of the change>
+EOF
+)"
+```
+
+Without `--subject` / `--body`, `gh` uses the PR title and the concatenated commit messages — no preview required, but state in chat which you're using.
+
+## Merge — the final call
+
+After the pre-merge gate is green and the strategy is chosen:
+
+> Pre-merge gate green:
+> - mergeable: MERGEABLE / mergeStateStatus: CLEAN
+> - All 3 checks pass (validate 18s, Socket x2)
+> - Diff reviewed, PR body matches
+>
+> Proposing: `gh pr merge <n> --repo <o>/<r> --squash --subject "<…>" --body "<…>"`
+>
+> Branch deletion: **not bundled** — separate step after merge if you want it.
+>
+> Merge?
+
+Then on approval:
+
+```bash
+gh pr merge <n> --repo <o>/<r> --squash --subject "..." --body "..."
+```
+
+## Branch deletion (separate explicit step)
+
+`gh pr merge --delete-branch` exists but couples merge + delete. **Keep them separate.** Delete branches as a discrete operation after merge, with its own confirmation — both because branch deletion is destructive and because a currently-checked-out branch can't be deleted at all (relevant if the operating worktree is on the PR branch).
+
+```bash
+# After merge + user OK:
+git -C <local-repo> fetch origin --prune
+git -C <local-repo> checkout --detach origin/main   # leave the branch if it's checked out
+git -C <local-repo> branch -D <branch>              # local
+git push origin --delete <branch>                   # remote
+```
+
+## Close (without merging)
+
+```bash
+# Plain close — no preview
+gh pr close <n> --repo <o>/<r>
+
+# Close with a parting comment — preview the comment first
+gh pr comment <n> --repo <o>/<r> --body "..."   # preview-gated
+gh pr close <n> --repo <o>/<r>
+```
+
+### Closing-comment templates
+
+**Superseded:**
+> Closing in favour of #<m>, which takes a different approach: <one sentence>. Thanks for the work here — pieces of the idea live on in the new PR.
+
+**Won't merge:**
+> Closing — after discussion, decided not to land this because <reason>. Detailed why in the thread above. Not a rejection of the code quality, just the direction.
+
+## Common workflows
+
+### Standard fix flow
+
+```
+1. Branch off origin/main
+2. Commit; push branch
+3. Draft PR body in chat, preview with user, gh pr create (preview-gated)
+4. CI runs; gh pr checks --watch
+5. Address review feedback if any (responses preview-gated)
+6. Pre-merge gate
+7. Merge (squash by default; explicit user OK)
+8. Branch cleanup (separate step, explicit OK)
+```
+
+### Reviewing a PR
+
+```
+1. gh pr view <n> --comments     # full context including prior discussion
+2. gh pr diff <n>                # what actually changed
+3. gh pr checks <n>              # CI status
+4. Read the linked issue(s) for original intent
+5. Draft review body in chat → preview → gh pr review (preview-gated)
+```
+
+### Hotfix with auto-close
+
+```
+1. Branch off main, fix, commit, push
+2. PR body includes "Fixes #<bug-issue>" (auto-closes on merge)
+3. Standard merge flow
+4. After merge: post a closing-credit comment on #<bug-issue> with version + PR link
+```
+
+## Anti-patterns
+
+- ❌ Merging without running the pre-merge gate (`mergeStateStatus` / checks / diff).
+- ❌ Bundling `--delete-branch` into the merge command — couples two destructive decisions into one.
+- ❌ Defaulting to `--merge` (merge-commit) when squash gives a cleaner history; only use it when individual commits matter.
+- ❌ Sending a review body, PR description, or comment without showing the draft to the user first (hard rule 8).
+- ❌ Promising follow-up work in a PR description and not capturing it as an issue.
+- ❌ Skipping the "Closes #N" footer in PR body — leaves issues unclosed after merge.
+- ❌ Treating `mergeable: UNKNOWN` as green — wait for GitHub to compute (re-poll).