Install
$ agentstack add skill-mralaminahamed-wp-dev-skills-wp-github-flow ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
GitHub Contribution Flow
> Model note: Issue-driven mode (root-cause tracing + fix) requires sonnet or opus. Changes-driven mode (group + commit existing edits) is mechanical and works well on haiku.
Overview
Two entry modes that converge on the same shipping flow (branch → scoped commits → push → PR):
- Issue-driven — fetch issue → trace root cause → fix → ship. Wraps
superpowers:systematic-debugging. Root cause MUST be confirmed before any fix is written. - Changes-driven — read the working tree → group changes by conventional-commit scope → one commit per scope → ship. No issue required.
Both end at §6 Branch, Commit, PR, which is shared.
When to use
Issue-driven:
- User says "analyze/debug/fix/investigate issue #NNN"
- User pastes a GitHub issue URL and asks to debug it
- User says "find the root cause of this bug" with an issue reference
Changes-driven:
- "commit my changes", "commit these scope by scope", "commit by scope"
- "create a branch and PR", "open a PR for these changes"
- "read all changes from X and commit + create PR"
- Any request whose end goal is commits/branch/PR from existing working-tree edits
Not for: Plugin version releases or WP.org SVN deploy — use wp-plugin-release and wp-org-submission. QA failure triage on an already-open PR — use wp-ci-qa.
Required Sub-Skill
Issue-driven only: Invoke superpowers:systematic-debugging before any fix. Do NOT skip Phase 1 (root cause investigation). Changes-driven mode skips this — the edits already exist.
References
references/gh-reference.md—ghCLI commands, branch naming rules, label discovery, PR template sections, common CI failuresreferences/project-entry-points.md— project layout template: repos, plugin dirs, entry-point files, and key conventions; copy and fill in for your projectreferences/conventional-commits.md— type/scope table, WP-specific scope list, summary rules, multi-commit PR rules, footer conventions, rebase reword
Repo ≠ where the issue lives
The repo that hosts the issue is often NOT the repo that holds the code / receives the PR. Resolve two names up front and keep them distinct:
ISSUE_REPO— wheregh issue view/gh issue editrun.CODE_REPO— where the affected code lives; where you branch, push, andgh pr create --repo "$CODE_REPO".
When they differ, the PR's close footer must be cross-repo: Closes ISSUE_OWNER/ISSUE_REPO#N (a bare Closes #N only closes an issue in the same repo).
Real example: issues live in my-org/my-plugin, but the buggy code + PR live in my-org/my-plugin-pro → PR opens on my-plugin-pro, body says Closes my-org/my-plugin#247.
Changes-Driven Workflow
Use this when the user wants to ship existing uncommitted edits. Skip to §6's mechanics but commit scope by scope rather than one lump.
A. Read every change
git status
git diff # unstaged
git diff --staged # staged
Read the full diff, not just the file list — a single file can contain edits belonging to different scopes, and the commit message's "why" depends on what actually changed.
B. Group changes by scope
Map each change to one conventional-commit scope. Scopes are project-defined — read the repo's CLAUDE.md for the list, don't assume.
- ShopFlow:
api, cart, checkout, orders, products, customers, payments, shipping, taxes, coupons, inventory, admin, dashboard, blocks, spa, database, templates, email, reports, build, i18n.
Group by what the change is about, not just which directory it lives in. Examples from real sessions:
pages/Coupons/index.jsx+pages/Coupons/CouponList/index.jsx→ bothcouponspages/AbandonedCart/index.jsx,pages/Transactions/...→admin.yarnrc.yml,package.json→build
One scope can span multiple files; one file can split across commits via git add -p if it genuinely mixes concerns (rare — prefer not to).
Exception — one cohesive cross-cutting task = one commit. Scope-by-scope is the default, but when the change is a single logical task that inherently touches many files across categories (e.g. fixing all findings from an audit, a mechanical rename, a dir restructure), a single commit with an enumerated body is cleaner and more honest than forcing fragile per-file git add -p splits. Judge by intent: distinct concerns → separate commits; one purpose expressed across many files → one commit.
C. Branch first, then commit each scope
Create the branch (§6.1), then make one commit per scope so each is independently reviewable and revertable:
git add
git commit -m "fix(coupons): "
git add
git commit -m "fix(admin): "
# ...repeat per scope
Use the correct ` per scope (fix, feat, build, refactor, …) — don't blanket-fix everything. Use caveman:caveman-commit` for terse, exact messages.
D. Push + PR
Push and open the PR via §6 — but the PR body summarizes all scopes, and there is no Closes #N unless an issue was given. PR title uses the dominant scope or a neutral summary across scopes.
> Heads-up: only commit what the user asked for. If git status shows unrelated files (e.g. a stray package.json from another task), call them out and leave them unstaged rather than sweeping them in.
Issue-Driven Workflow
1. Detect Canonical Repo(s)
Before anything else, resolve the true repo(s) — remotes go stale when orgs rename or transfer, and the issue repo may differ from the code repo (see "Repo ≠ where the issue lives").
# What git thinks origin is, vs what GitHub actually says (follows redirects)
git remote get-url origin
gh repo view --json nameWithOwner -q .nameWithOwner
# If they differ — update origin
git remote set-url origin $(gh repo view --json cloneUrl -q .cloneUrl)
Store BOTH names — they may be the same, but never assume it:
ISSUE_REPO=my-org/my-plugin # where the issue is tracked
CODE_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) # where you'll PR
2. Fetch Issue
gh issue view --repo "$ISSUE_REPO" --comments
Extract: title, description, screenshots, reproduction steps, error messages, and the comment thread (assignee, "need to update API", "issue not found" all live there). For a parent/tracking issue, also fetch each sub-issue + its comments.
3. Locate Affected Code
grep -rfor identifiers, class names, function names from the issue- Trace from UI/endpoint inward to data origin
- Check recent commits:
git log --oneline -- - Find the code's repo. It may not be the issue repo, and not even the same plugin (free vs pro).
git -C remote get-url originto confirm which GitHub repo each path maps to → that'sCODE_REPO.
4. Root Cause Investigation
Follow superpowers:systematic-debugging Phase 1 fully:
- Read error messages / inspect screenshots carefully
- Reproduce data flow mentally (or add logging)
- Form ONE explicit hypothesis: "Root cause is X because Y"
- Confirm hypothesis before writing any fix
No fixes until root cause is stated and confirmed.
5. Fix
One minimal change. No cleanup, no refactoring, no "while I'm here" edits.
6. Branch, Commit, PR (shared by both modes)
# Confirm base branch with user if unclear — never assume main/develop
BASE_BRANCH=
6.1 — Create branch from the FRESH base. Local branches go stale; always branch from origin/ after fetching, so the PR diff is clean.
git fetch origin "$BASE_BRANCH"
git checkout -b "origin/$BASE_BRANCH"
Name it by mode:
- Issue-driven:
bugfix/- - Changes-driven:
/(e.g.fix/container-height-full)
Cluster (multiple sub-issues): do NOT lump fixes for several issues into one branch. One branch + one PR per issue, each cut fresh from origin/$BASE_BRANCH, each Closes its own issue. Fix file A on its branch → push → PR → git checkout "$BASE_BRANCH" → next. Independent files = no conflicts.
6.2 — Commit. Use caveman:caveman-commit for messages.
- Issue-driven: one minimal commit, with
Closes #footer. - Changes-driven: one commit per scope (see Changes-Driven §C). No
Closesunless an issue was given.
git add
git commit -m "fix(): " # +blank line + why + Closes when issue-driven
Follow project conventions in the repo's CLAUDE.md — check it for deprecated function patterns, naming conventions, and scope definitions before committing.
6.3 — Push (must happen before the PR). gh pr create fails with "must first push the current branch" if you skip this.
git push -u origin
6.4 — Discover labels, THEN create the PR. Label names are per-repo; gh pr create aborts the whole command if any --label doesn't exist (e.g. needs testing vs needs-testing). List them first and map to what's real:
gh label list --repo "$CODE_REPO"
Then create — always pass --repo "$CODE_REPO" (gh context can differ from git remote), --assignee @me, and only labels that exist. Common mapping: a "ready for QA" label (needs-testing / needs testing) + an area label (frontend, backend). Never add bug — QA assigns it if they find issues; dev-added bug conflicts with QA triage. Cross-repo close footer when ISSUE_REPO ≠ CODE_REPO.
gh pr create \
--repo "$CODE_REPO" \
--base "$BASE_BRANCH" \
--assignee @me \
--label "" \
--label "" \
--title "(): " \
--body "$(cat
---
## 🛠️ Related Issues / Tickets
Closes /#
---
## 📦 Type of Change
- [x] 🐛 Bug fix
---
## 🔍 Changes Made
-
---
## 🧪 Test Instructions
1.
2.
---
## ✅ Checklist
- [x] My code follows the project's coding style and conventions
- [x] This PR is scoped, focused, and doesn't mix unrelated changes
EOF
)"
> Verification honesty: if an automated test isn't feasible (e.g. Elementor edit-mode render needs a bootstrap the suite lacks), say so plainly in the checklist and rely on php -l + manual steps — don't claim a test you didn't write.
6.5 — Merge PR. When the user asks to merge a PR, always use a regular merge commit (--merge). Never squash (--squash) — it collapses the branch's individual commits into one, destroying the per-scope history that §6.2 deliberately preserved. Never rebase (--rebase) unless the user explicitly requests it.
gh pr merge --merge --delete-branch
--delete-branch is safe and keeps the remote tidy. Do not add --squash or --rebase.
6.6 — After merge: verify, then re-sync before the next branch. A merge isn't done until it's confirmed landed and local main is caught up — otherwise the next branch is cut from a stale base.
gh pr view --json state,mergedAt -q '{state: .state, mergedAt: .mergedAt}' # expect MERGED
git checkout "$BASE_BRANCH"
git pull origin "$BASE_BRANCH"
git rev-parse "$BASE_BRANCH"; git rev-parse "origin/$BASE_BRANCH" # must match
Sequential PRs in one session
When an open PR already exists and the user asks for the next piece of work, do NOT stack the new changes on the unmerged branch. The user's preferred flow:
- Merge the open PR first (
gh pr merge --merge --delete-branch). git checkout "$BASE_BRANCH"+git pullso the base is current.- Branch fresh off the updated base for the new work.
If the new work genuinely depends on the unmerged branch and can't wait, branch off that branch and rebase onto the base once it merges (the cluster pattern) — but the default is merge-first.
Keep an open PR's body in sync
If you push more commits to a branch whose PR is already open (scope grew mid-review), update the PR title/body so the description still matches the diff:
gh pr edit --title "" --body "$(cat remote get-url origin` |
| Fix stale remote | `git remote set-url origin ` |
| Fetch issue + comments *(issue mode)* | `gh issue view --repo "$ISSUE_REPO" --comments` |
| Read changes *(changes mode)* | `git status`, `git diff`, `git diff --staged` |
| Find code | `grep -r`, `find`, file reads |
| Branch from fresh base | `git fetch origin "$BASE_BRANCH" && git checkout -b "origin/$BASE_BRANCH"` |
| Commit message | `caveman:caveman-commit` |
| Discover labels (before PR) | `gh label list --repo "$CODE_REPO"` |
| Push (before PR) | `git push -u origin ` |
| Create PR | `gh pr create --repo "$CODE_REPO" --base "$BASE_BRANCH" --assignee @me --label ""` |
| Merge PR | `gh pr merge --merge --delete-branch` — **never `--squash` or `--rebase`** |
| Verify merge + re-sync | `gh pr view --json state,mergedAt` then `git checkout && git pull` (rev-parse local == origin) |
| Update open PR after new commits | `gh pr edit --title … --body …` |
---
## Common Mistakes
| Mistake | Fix |
|---------|-----|
| Hardcoded repo name | Always derive from `gh repo view --json nameWithOwner` |
| Assuming issue repo == code repo | Resolve `ISSUE_REPO` + `CODE_REPO` separately; PR on `CODE_REPO`; cross-repo `Closes owner/repo#N` |
| Stale `origin` remote | Run remote detect step (§1) before every push |
| Branching off a stale local base | `git fetch origin ` then branch from `origin/` |
| `gh pr create` without `--repo` | `gh` context can differ from `git` remote — always pass `--repo "$CODE_REPO"` |
| PR command before pushing branch | Push first — `gh pr create` errors "must first push the current branch" |
| Hardcoded label aborts PR | `gh label list` first; one unknown `--label` fails the whole `gh pr create` |
| Lumping multiple issues in one branch | One branch + PR per issue, each from fresh `origin/` |
| Claiming an automated test you didn't write | If a test isn't feasible, say so; rely on lint + manual steps, stated plainly |
| One lumped commit for mixed changes | Changes mode: split by scope, one commit each |
| Reading only the file list | Read full `git diff` — a file can mix scopes, and the "why" needs the actual change |
| Sweeping in unrelated files | Only stage what the user asked for; flag stray changes, leave them unstaged |
| Blanket `fix:` on everything | Pick the right `` per scope (`feat`/`build`/`refactor`/…) |
| `Closes #N` with no issue | Omit the issue section entirely in changes mode |
| Fix without root cause *(issue mode)* | State hypothesis explicitly before coding |
| Fixing symptom not origin *(issue mode)* | Trace full data flow to find where bad value is born |
| Wrong base branch | Ask user; never assume `develop` or `main` |
| Missing assignee | Always pass `--assignee @me` |
| Missing QA label | Add the repo's "ready for QA" label (verify exact name via `gh label list`) |
| Missing area label | Add the repo's area label (`frontend`/`backend`/…) — whatever exists; never add `bug` |
| Adding `bug` label on a dev PR | **Never.** `bug` is QA's label — they add it only if they find issues during testing. Dev-adding it conflicts with QA triage. |
| Bundled refactoring in fix | One change only — keep diff minimal |
| Squash merge | **Never** use `--squash` — destroys per-scope commit history. Use `--merge` always. |
| Rebase merge without being asked | Never use `--rebase` unless user explicitly requests it — rewrites SHAs, breaks bisect. |
| Stacking next task on an unmerged PR branch | Merge the open PR first, `git pull` the base, then branch fresh (Sequential PRs). |
| Branching after merge without re-pulling | A merge updates the remote base, not your local — `git checkout && git pull` before the next branch. |
| Open PR body stale after new commits | `gh pr edit` the body to cover every commit now on the branch. |
| Forcing per-file splits on one cohesive task | An audit cleanup / rename / restructure is one commit with an enumerated body — not fragile `git add -p`. |
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [mralaminahamed](https://github.com/mralaminahamed)
- **Source:** [mralaminahamed/wp-dev-skills](https://github.com/mralaminahamed/wp-dev-skills)
- **License:** MIT
- **Homepage:** https://github.com/mralaminahamed/wp-dev-skills/blob/trunk/README.md
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.