gh-dev
Create a development branch linked to a GitHub issue, then implement the work with disciplined, convention-following commits. This skill handles the full loop from branch creation through development, but never pushes to the remote — the user retains full control over when and how to share their work.
Step 1: Identify the target issue
Determine which issue to work on. The user may provide:
- An issue number (e.g.,
42) - An issue URL (e.g.,
https://github.com/owner/repo/issues/42) - A description of the work without referencing a specific issue
If the user provides a number or URL, use it directly. If they describe the work without an issue reference, search for a matching open issue:
gh issue list --limit 20 --state open --json number,title --jq '.[] | "#\(.number) \(.title)"'
Present matching issues and ask the user to confirm. If no matching issue exists, ask whether to create one first (suggest the gh-issue skill) or proceed with just a branch.
Store the result as ISSUE_NUMBER.
Step 2: Check working tree state
Before creating a branch, check for uncommitted changes:
git status --porcelain
If the working tree is dirty, inform the user and ask how to proceed:
- Stash changes (
git stash) - Commit current changes first
- Abort and let the user handle it
Do not silently discard or stash changes — always get explicit consent.
Step 3: Create the linked branch
The branch name follows a fixed convention: issues/ISSUE_NUMBER. For example, issue #1 becomes issues/1, issue #42 becomes issues/42.
Pre-flight: Confirm base branch
Before creating the branch, check whether a dev or develop branch exists on the remote:
git ls-remote --heads origin dev develop
Store the result as BASE_BRANCH — either dev, develop, or the repo's default branch (e.g., main) if neither exists.
Create the branch
Pass --base with the detected BASE_BRANCH so the new issue branch is based on the correct branch:
gh issue develop ISSUE_NUMBER --checkout --name "issues/ISSUE_NUMBER" --base BASE_BRANCH
Handle these error cases:
- Branch already exists: If
issues/ISSUE_NUMBERalready exists, ask the user whether to check out the existing branch (git checkout issues/ISSUE_NUMBER) or delete and recreate it. - Issue not found: Inform the user the issue number is invalid and re-prompt.
- No remote: Inform the user a GitHub remote is required and suggest
gh repo createorgit remote add origin.
After success, confirm the branch name and that it is linked to the issue.
Step 4: Gather project conventions
Before writing any code, understand how this project handles commits:
# Recent commit history for convention patterns
git log --oneline -20
# Explicit conventions
cat CLAUDE.md 2>/dev/null || true
cat .github/CONTRIBUTING.md 2>/dev/null || true
cat CONTRIBUTING.md 2>/dev/null || true
Infer from the history:
- Prefix style: conventional commits (
feat:,fix:), ticket prefixes (PROJ-123), or plain prose - Scope usage: parenthetical scopes like
(auth),(api), or none - Tense: imperative ("add feature") vs past ("added feature")
- Capitalization: sentence case, lowercase after prefix, etc.
- Message length: single line vs multi-line body
Explicit documented conventions (in CLAUDE.md, CONTRIBUTING.md) override inferred patterns. Store the result as COMMIT_CONVENTION for use throughout development.
Step 5: Read the issue for context
Fetch the full issue details to understand what needs to be implemented:
gh issue view ISSUE_NUMBER --json title,body,labels,assignees
Use the issue title, body, acceptance criteria, and any referenced files or code paths to guide the implementation. If the issue references specific files, read them to understand the current state before making changes.
Step 6: Develop the feature or fix
Implement the changes described in the issue. During development:
- Work incrementally — complete one logical unit of work at a time.
- After each logical unit, proceed to Step 7 to commit before continuing.
- Logical commit points include: adding a new file, completing a function, fixing a specific bug, adding tests for a module, updating configuration.
- Do not accumulate all changes into a single commit at the end — this makes review harder and loses the development narrative.
Step 7: Commit at each checkpoint
At each logical checkpoint during development, follow this process:
7a: Check for files that should be gitignored
Before staging, review new untracked files:
git status --porcelain
Look for files that should not be committed:
- Environment files:
.env,.env.local,.env.*.local - Secrets:
credentials.json,*.pem,*.key,token.txt - OS files:
.DS_Store,Thumbs.db - IDE files:
.idea/,.vscode/settings.json(unless the project already tracks it) - Build artifacts:
node_modules/,dist/,__pycache__/,*.pyc - Logs:
*.log,npm-debug.log*
If any such files exist and are not already in .gitignore, update .gitignore first and commit that change separately:
echo "pattern" >> .gitignore
git add .gitignore
git commit -m "chore: add pattern to .gitignore"
Adapt the commit message prefix to match COMMIT_CONVENTION.
7b: Stage specific files
Stage only the files related to the current logical change. Always name files explicitly:
git add src/auth/login.ts src/auth/login.test.ts
Review what is staged before committing:
git diff --cached --stat
7c: Write and execute the commit
Write a commit message following COMMIT_CONVENTION. The message must:
- Match the project's prefix style, tense, scope usage, and capitalization
- Describe the change concisely and accurately
- Contain no Co-Authored-By line, no signatures, no attribution of any kind
git commit -m "feat(auth): add login endpoint with JWT validation"
The commit message is exactly the text above — nothing appended, nothing added after the fact.
7d: Return to Step 6
Continue development until the implementation is complete.
Step 8: Simplify pass
Once the implementation is working and tested — but before reporting completion or opening a PR — run the built-in simplify skill as a dedicated cleanup/refactor pass over the recently changed code:
Invoke the Skill tool with skill: "simplify"
simplify reviews changed code for reuse, quality, and efficiency, then fixes the issues it finds. Treat it as a final-mile polish, not a per-commit formatter — it works best when there is a meaningful surface of new code to evaluate.
After simplify completes:
- If it made changes, review them, then commit the cleanup separately following
COMMIT_CONVENTION(e.g.,refactor: simplify auth helpers). Do not fold simplify edits into unrelated feature commits — keep the cleanup as its own logical commit so reviewers can see the polish step. - If it made no changes, proceed directly to the next step.
Skip this step only if the work was a trivial one-line fix where there is nothing meaningful to simplify.
Step 9: Final status
After all work is committed, show a summary:
# All commits made on this branch
git log --oneline main..HEAD
# Confirm nothing is left uncommitted
git status
Report to the user:
- Branch name and linked issue number
- Number of commits made
- Summary of what was implemented
- Remind the user that nothing has been pushed — they can review, squash, or push when ready
What's Next
After the final status report, offer the user a path forward:
Ready to open a PR? I can run
/gh-prto push and create a pull request.
Wait for the user to confirm before proceeding. Do not automatically invoke /gh-pr.
Multi-issue parallel development
When the user wants to work on multiple issues simultaneously (e.g., "implement issues 17, 18, 19 in para