Core Commands
Essential slash commands: /commit, /pr, /cpm (commit-PR-merge), /gs (git status), /ghi (create issue).
Tags
README
commands-core
Essential slash commands for everyday git and GitHub workflows.
What This Module Does
Provides five foundational commands that cover the most common development operations:
- /commit - Stage and commit changes with conventional format
- /pr - Push branch and create a pull request that closes an issue
- /cpm - One-shot commit + PR + merge workflow for solo developers
- /gs - Show git status and project overview
- /ghi - Create a GitHub issue with proper labels
Also ships two reusable skills:
- pr-description - Pure writer that returns
{title, body}for a PR in CCGM voice. Callable from/pr,/cpm, or any agent that needs a PR body without the publishing plumbing. Does NOT invokegh pr createorgh pr edit. - cpm - Sequenced commit-PR-merge workflow encoded as a skill so other commands can embed it.
Files
| File | Type | Description |
|---|---|---|
commands/commit.md |
command | Stage all changes and commit with conventional format |
commands/pr.md |
command | Push branch and create PR closing an issue |
commands/cpm.md |
command | Commit, create PR, and merge in one shot |
commands/gs.md |
command | Git status dashboard with project info |
lib/gs-gather.sh |
lib | Helper script that gathers git and project info for /gs |
commands/ghi.md |
command | Create GitHub issue with labels |
skills/cpm/SKILL.md |
skill | Sequenced commit-PR-merge workflow |
skills/pr-description/SKILL.md |
skill | Pure PR title and body writer (returns structured output, no publishing) |
skills/pr-description/references/default-template.md |
skill-reference | Fallback PR body structure when no repo template exists |
Dependencies
None.
Manual Installation
Copy command files to your Claude Code commands directory:
# Create commands directory if it does not exist
mkdir -p ~/.claude/commands
# Copy each command
cp commands/commit.md ~/.claude/commands/commit.md
cp commands/pr.md ~/.claude/commands/pr.md
cp commands/cpm.md ~/.claude/commands/cpm.md
cp commands/gs.md ~/.claude/commands/gs.md
cp commands/ghi.md ~/.claude/commands/ghi.md
# Lib helper
mkdir -p ~/.claude/lib
cp lib/gs-gather.sh ~/.claude/lib/gs-gather.sh
# Skills
mkdir -p ~/.claude/skills/cpm ~/.claude/skills/pr-description/references
cp skills/cpm/SKILL.md ~/.claude/skills/cpm/SKILL.md
cp skills/pr-description/SKILL.md ~/.claude/skills/pr-description/SKILL.md
cp skills/pr-description/references/default-template.md ~/.claude/skills/pr-description/references/default-template.md
After copying, the commands are available as /commit, /pr, /cpm, /gs, and /ghi in Claude Code. The pr-description and cpm skills are invocable by name from other commands or agents.
Will install
| Path | Action | Target | Type |
|---|---|---|---|
commands/commit.md | → | commands/commit.md | command |
commands/pr.md | → | commands/pr.md | command |
commands/cpm.md | → | commands/cpm.md | command |
commands/gs.md | → | commands/gs.md | command |
lib/gs-gather.sh | → | lib/gs-gather.sh | lib |
commands/ghi.md | → | commands/ghi.md | command |
skills/cpm/SKILL.md | → | skills/cpm/SKILL.md | skill |
skills/pr-description/SKILL.md | → | skills/pr-description/SKILL.md | skill |
skills/pr-description/references/default-template.md | → | skills/pr-description/references/default-template.md | skill-reference |
Dependencies
No dependencies.
Required by
No other module depends on this one.
Included in presets
Install this module
Agent prompt
Recommended for agent users -- hands the whole install off to your assistant.
Fetch https://ccgm.dev/modules/commands-core.md and install this module into my Claude Code setup.
Native plugin marketplace
One command via the native plugin marketplace -- additive, does not merge settings.json.
claude plugin install commands-core@ccgm
The marketplace path is additive, not a replacement: it installs commands, agents, and skills as native plugin components, but it does not perform the bash installer's deep settings.json merge, and it does not write the always-loaded global CLAUDE.md context. Rules are only injected via an opt-in SessionStart hook rather than being auto-loaded. Use the bash installer when those pieces matter to you.
Files
command (5)
commands/commit.md
---
description: Stage all changes and commit with conventional format
allowed-tools: Agent
---
# /commit - Stage and Commit Changes
Use the Agent tool to execute this entire workflow on a cheaper model:
- **model**: sonnet
- **description**: commit workflow
Pass the agent all workflow instructions below. Include the received arguments: `$ARGUMENTS`
After the agent completes, relay its final report to the user exactly as received.
---
## Workflow Instructions
Stage all current changes and create a commit with conventional format.
Arguments: $ARGUMENTS
### 1. Verify There Are Changes to Commit
```bash
git status --short
```
If no changes exist, report that there is nothing to commit and stop.
### 2. Understand the Context
Gather context to write a good commit message:
```bash
# Current branch name (often contains issue number)
git branch --show-current
# What has changed
git diff --stat
git diff --cached --stat
# Recent commits for style reference
git log --oneline -5
```
### 3. Extract Issue Number
Derive the issue number from the branch name. Convention: branches are named `{issue-number}-{description}`.
```bash
BRANCH=$(git branch --show-current)
ISSUE_NUM=$(echo "$BRANCH" | grep -oE '^[0-9]+')
```
If no issue number is found in the branch name and the arguments contain an issue number, use that instead. If neither source has an issue number, proceed without one.
### 4. Run Verification
Before committing, run the project's verification suite to ensure nothing is broken:
```bash
# Check for common verification commands (adapt to project)
# Look for package.json scripts
cat package.json 2>/dev/null | grep -E '"(lint|type-check|test:run|test|build)"'
```
Run available checks:
- Linting (if available)
- Type checking (if TypeScript project)
- Tests (if available)
- Build (if available)
If any check fails, fix the issue before proceeding. Do not commit broken code.
### 5. Stage All Changes
```bash
git add -A
```
Review what is staged:
```bash
git diff --cached --stat
```
### 6. Create the Commit
Format: `{issue_number}: {brief description}`
If an issue number was found:
```bash
git commit -m "{issue_number}: {brief description of changes}"
```
If no issue number:
```bash
git commit -m "{brief description of changes}"
```
Rules for the commit message:
- Keep the first line under 72 characters
- Use imperative mood ("Add feature" not "Added feature")
- Be specific about what changed
- Do not include any AI attribution or co-author trailers
- If the arguments contain a specific message, use it (but still prepend the issue number)
### 7. Confirm Success
```bash
git log --oneline -1
```
Report the commit hash and message to the user.
commands/pr.md
---
description: Push branch and create a pull request that closes an issue
allowed-tools: Agent
---
# /pr - Push Branch and Create Pull Request
Use the Agent tool to execute this entire workflow on a cheaper model:
- **model**: sonnet
- **description**: push and create PR
Pass the agent all workflow instructions below. Include the received arguments: `$ARGUMENTS`
After the agent completes, relay its final report to the user exactly as received.
---
## Workflow Instructions
Push the current branch to the remote and create a PR that closes the associated issue.
Arguments: $ARGUMENTS
### 1. Pre-Flight Checks
Verify the working directory is clean:
```bash
git status --short
```
If there are uncommitted changes, warn the user and suggest running `/commit` first. Do not proceed with uncommitted changes.
### 2. Gather Context
```bash
# Current branch
BRANCH=$(git branch --show-current)
# Extract issue number from branch name
ISSUE_NUM=$(echo "$BRANCH" | grep -oE '^[0-9]+')
# Check we are not on main
if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
echo "ERROR: Cannot create PR from main/master branch"
exit 1
fi
# Get commit history for this branch
git log --oneline origin/main..HEAD 2>/dev/null || git log --oneline -5
```
### 3. Run Verification
Run the project's full verification suite before pushing:
```bash
# Detect and run available checks
npm run lint 2>/dev/null
npm run type-check 2>/dev/null
npm run test:run 2>/dev/null || npm test 2>/dev/null
npm run build 2>/dev/null
```
All checks must pass. Fix any failures before proceeding.
### 4. Rebase on Main
Ensure the branch is up to date with the latest main:
```bash
git fetch origin
git rebase origin/main
```
If there are conflicts, resolve them. After resolving:
```bash
git rebase --continue
```
### 5. Push the Branch
```bash
git push -u origin "$BRANCH"
```
If the branch was rebased and already existed on the remote:
```bash
git push --force-with-lease -u origin "$BRANCH"
```
### 6. Check for PR Template
One local check — if a template file is in the repo, use it; otherwise write a value-first body (do NOT query the org's `.github` repo or create a template):
```bash
ls pull_request_template.md PULL_REQUEST_TEMPLATE.md \
.github/pull_request_template.md .github/PULL_REQUEST_TEMPLATE.md 2>/dev/null
```
If a template is found, read it and structure the PR body using the template's sections and headings.
### 7. Create the Pull Request
Build the PR title and body:
- **Title**: `{issue_number}: {brief description}` (matching commit format)
- **Body**: Must include `Closes #{issue_number}` to auto-close on merge
If a PR template was found, fill in its sections. Otherwise use:
```bash
gh pr create \
--title "{issue_number}: {description}" \
--body "## Summary
{Summary of changes}
## Changes
{Key changes made}
## Test Plan
{How this was tested}
## Issue
Closes #{issue_number}"
```
### 8. Tracking Update
Note: Tracking status is updated automatically by the PostToolUse hook on `gh pr create` (sets status to "pr-created"). No manual label management needed.
### 9. Report Result
Display:
- PR URL
- PR number
- Issue it closes
- Any CI checks that are running
commands/cpm.md
---
description: One-shot commit, create PR, and merge workflow
allowed-tools: Agent
---
# /cpm - Commit, PR, and Merge
Use the Agent tool to execute this entire workflow on a cheaper model:
- **model**: sonnet
- **description**: cpm git workflow
Pass the agent all workflow instructions below. Include the received arguments: `$ARGUMENTS`
After the agent completes, relay its final report to the user exactly as received.
---
## Workflow Instructions
A one-shot workflow that commits current changes, creates a PR, and merges it. Designed for repos where you merge your own PRs (solo developer or self-merge workflow).
Arguments: $ARGUMENTS
### 1. Pre-Flight Checks
```bash
# Verify we have changes
git status --short
# Verify we are on a feature branch, not main
BRANCH=$(git branch --show-current)
if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
echo "ERROR: Cannot run /cpm from main/master. Create a feature branch first."
exit 1
fi
```
If no changes exist and no commits ahead of main, report that there is nothing to do.
### 2. Extract Issue Number
```bash
BRANCH=$(git branch --show-current)
ISSUE_NUM=$(echo "$BRANCH" | grep -oE '^[0-9]+')
```
If arguments contain an issue number, prefer that. If neither source has one, proceed without it.
### 3. Run Verification
Run the project's full verification suite:
```bash
# Detect and run available checks
npm run lint 2>/dev/null
npm run type-check 2>/dev/null
npm run test:run 2>/dev/null || npm test 2>/dev/null
npm run build 2>/dev/null
```
All checks must pass. Fix failures before proceeding. Do not skip verification.
### 4. Commit (if uncommitted changes exist)
```bash
git add -A
git diff --cached --stat
```
If there are staged changes:
```bash
git commit -m "{issue_number}: {brief description}"
```
Rules:
- Imperative mood
- Under 72 characters
- No AI attribution
- If arguments include a message, use it (prepend issue number)
### 5. Rebase on Main
```bash
git fetch origin
git rebase origin/main
```
Resolve conflicts if any arise.
### 6. Push
```bash
git push -u origin "$BRANCH"
```
Or if rebased and remote branch exists:
```bash
git push --force-with-lease -u origin "$BRANCH"
```
### 7. Create PR
Check for a PR template first:
```bash
ls pull_request_template.md PULL_REQUEST_TEMPLATE.md .github/pull_request_template.md .github/PULL_REQUEST_TEMPLATE.md 2>/dev/null
```
Create the PR:
```bash
gh pr create \
--title "{issue_number}: {description}" \
--body "## Summary
{Summary of what this PR does}
## Changes
{Key changes}
## Test Plan
{How it was verified}
## Issue
Closes #{issue_number}"
```
### 8. Merge the PR
Merge immediately with admin bypass — do not wait for GitHub Actions:
```bash
gh pr merge --squash --delete-branch --admin
```
Local pre-push verification (lint + type-check + tests + build) is the source of truth. Remote CI is best-effort: Actions minutes budget runs out, runners stall, queues back up — none of those are reasons to block a merge. `--admin` bypasses the BLOCKED state from "checks pending" or "no required reviewer present" when you ARE the repo admin. It does NOT force-merge through an actually-FAILED check; if a check is in FAILURE state (not PENDING), stop and investigate — local pre-push should have caught it.
If `--admin` itself fails — merge conflict, missing PR, you are not the admin in this repo — report and stop. Do not retry the same command; investigate the cause.
### 9. Close the Issue
If the PR body included `Closes #N`, GitHub auto-closes the issue on merge. Verify:
```bash
gh issue view "$ISSUE_NUM" --json state --jq '.state' 2>/dev/null
```
If still open, close manually:
```bash
gh issue close "$ISSUE_NUM" --comment "Completed via PR merge"
```
Note: Tracking status is updated automatically by the PostToolUse hook. The hook sets status to "closed" on `gh issue close` and "merged" on `gh pr merge`. No manual label management needed.
### 10. Return to Main
```bash
git checkout main
git pull origin main --ff-only
```
### 11. Report Result
Display:
- Commit hash and message
- PR number and URL
- Merge status
- Issue close status
- Current state (on main, clean working directory)
commands/gs.md
---
description: Show git status and project overview
allowed-tools: Agent
---
# /gs - Git Status Dashboard
Use the Agent tool to execute this entire workflow on a cheaper model:
- **model**: sonnet
- **description**: git status dashboard
Pass the agent all workflow instructions below. Include the received arguments: `$ARGUMENTS`
After the agent completes, relay its dashboard output to the user exactly as received.
---
## Workflow Instructions
Display a comprehensive overview of the current repository state.
Arguments: $ARGUMENTS
### Step 1: Gather Data
Run the gather script to collect all git data in parallel:
```bash
bash ~/.claude/lib/gs-gather.sh
```
This outputs structured `=== SECTION ===` blocks with all data needed.
### Step 2: Present Dashboard
Format the gathered data into this dashboard. Omit any section that is empty.
```
Repository: {name from REPO section}
Branch: {branch} -> {upstream}
Status: {clean / N files changed based on STATUS section}
Sync:
Main: {ahead_behind from SYNC main: line - format as "N ahead, N behind"}
Remote: {ahead_behind from SYNC upstream: line - format as "N unpushed, N to pull"}
Recent Commits:
{LOG section content}
Open PRs:
{PRS section content, highlight any from current branch}
Sibling Sessions (same repo):
{SESSIONS content, or omit if empty}
Changes:
{DIFF section content - summarize staged/unstaged/untracked}
Suggested: {recommended next action per table below}
```
| State | Recommendation |
|-------|---------------|
| Uncommitted changes on feature branch | Run `/commit` to commit your changes |
| Committed changes, no PR | Run `/pr` to push and create a pull request |
| On main with no changes | Create a feature branch or run `/ghi` |
| Behind main on feature branch | Run `git fetch origin && git rebase origin/main` |
| PR open and CI passing | Run `gh pr merge --squash --delete-branch` |
| Clean state on main | Ready for new work |
commands/ghi.md
---
description: Create a new GitHub issue with proper labels
allowed-tools: Agent
---
# /ghi - Create GitHub Issue
Use the Agent tool to execute this workflow on a cheaper model:
- **model**: haiku
- **description**: create GitHub issue
Pass the agent all workflow instructions below. Include the received arguments: `$ARGUMENTS`
After the agent completes, relay its report to the user exactly as received.
---
## Workflow Instructions
Create a new GitHub issue with appropriate labels based on the type of work.
Arguments: $ARGUMENTS
### 1. Gather Issue Details
If the arguments provide enough context (title and description), use them directly. Otherwise, ask the user for:
- **Title**: A concise, descriptive title
- **Type**: feature, bug, refactor, chore, documentation, or human-agent
- **Description**: What needs to be done and why
### 2. Determine Issue Type and Labels
Map the issue type to the appropriate label:
| Type | Label | Color | Description |
|------|-------|-------|-------------|
| feature | `enhancement` | `a2eeef` | New feature or improvement |
| bug | `bug` | `d73a4a` | Something is not working |
| refactor | `chore` | `e4e669` | Maintenance, refactoring, config |
| chore | `chore` | `e4e669` | Maintenance, dependencies, config |
| documentation | `documentation` | `0075ca` | Documentation changes |
| human-agent | `human-agent` | `f9d0c4` | Requires manual human action |
### 3. Check Existing Labels
Verify the required label exists in the repo:
```bash
gh label list | grep -i "{label-name}"
```
If the label does not exist, create it:
```bash
gh label create "{label-name}" --color "{color}" --description "{description}"
```
### 4. Build the Issue Body
Structure the issue body based on the type:
**For features/enhancements:**
```markdown
## Summary
{What this feature does and why it is needed}
## Implementation Steps
{Numbered steps if known, or "TBD - to be planned"}
## Acceptance Criteria
- [ ] {Criterion 1}
- [ ] {Criterion 2}
```
**For bugs:**
```markdown
## Bug Description
{What is happening vs. what should happen}
## Steps to Reproduce
1. {Step 1}
2. {Step 2}
## Expected Behavior
{What should happen}
## Actual Behavior
{What is happening}
```
**For human-agent tasks:**
```markdown
## Context
{Why this manual action is needed}
## Required Actions
- [ ] {Action 1}
- [ ] {Action 2}
## Instructions
{Step-by-step guide for the human}
```
Then check the body's prose before creating the issue.
<!-- ccgm:section prose-lint-gate -->
**Prose check.** Before publishing, run these steps as separate commands:
1. Write the document's prose (no code blocks, no Mermaid block) to a temp file in the session scratchpad or temp directory.
2. Run `test -x "$HOME/.claude/bin/ccgm-prose-lint"` as its own command. If it exits non-zero, print `ccgm-prose-lint not installed; skipping the prose check` and continue.
3. Otherwise run `"$HOME/.claude/bin/ccgm-prose-lint" --strict <temp file>` as its own command. Exit 1 means a sentence or paragraph is over the limit: fix it and run again until it exits 0. Warnings do not fail the run; fix the ones that are cheap to fix.
4. Report the result in one line: `Prose check: exit <code>, <N> errors` (or `Prose check: skipped` when the linter is not installed).
<!-- /ccgm:section prose-lint-gate -->
### 5. Create the Issue
```bash
gh issue create \
--title "{title}" \
--label "{label}" \
--body "{body}"
```
For human-agent issues, also assign to the repo owner if known:
```bash
gh issue create \
--title "{title}" \
--label "human-agent" \
--body "{body}"
```
### 6. Report Result
Display:
- Issue number
- Issue URL
- Title
- Labels applied
- Suggested next step (e.g., "Create a branch with `git checkout -b {issue-number}-{description} origin/main`")
skill (2)
skills/cpm/SKILL.md
# /cpm — Commit, PR, Merge
One-shot workflow: commit all changes, create a PR, merge it, close the issue, and rebase on main.
## Usage
```
/cpm
```
No arguments needed. Derives the issue number from the current branch name (expects `{issue-number}-{description}` format).
## Instructions
Execute the following steps sequentially. Do NOT skip steps or proceed if a step fails.
### Phase 1: Pre-flight
1. Run `git status` to confirm there are changes to commit.
2. Run `git diff --stat` to see what changed.
3. Extract the issue number from the current branch name (the leading digits before the first `-`).
4. Run `git log --oneline -5` to check recent commit style.
If there are no changes and no unpushed commits, stop and report "Nothing to commit or push."
### Phase 2: Commit
1. Stage all changed files with `git add` (prefer specific files over `git add -A`; never stage `.env` or credential files).
2. Create a commit with message format: `{issue-number}: {concise description of changes}`
3. Do NOT add any Co-Authored-By trailers or AI attribution.
### Phase 3: Push & Create PR
1. Push the branch: `git push -u origin HEAD`
2. Check for a PR template at `.github/PULL_REQUEST_TEMPLATE.md` or `pull_request_template.md` in the repo root.
3. Create the PR using `gh pr create`:
- Title: `{issue-number}: {concise description}`
- Body: Use the PR template if found, otherwise use Summary + Test Plan format
- Include `Closes #{issue-number}` in the body
4. Capture the PR URL.
### Phase 4: Merge
1. Merge with admin bypass so you do not wait on GitHub Actions:
`gh pr merge --squash --delete-branch --admin`
2. Confirm the merge succeeded.
Local pre-push verification is the source of truth. Remote Actions stall, run out of budget, and queue — those are not reasons to block a merge. `--admin` bypasses the BLOCKED state caused by "checks pending" or "no required reviewer present" when you are the repo admin. It does NOT force-merge through an actually-FAILED check; a FAILURE check (not PENDING) means local verification missed something — stop and investigate, do not retry with `--admin`.
### Phase 5: Close Issue
1. The issue should auto-close from "Closes #N" in the PR body.
2. Verify with `gh issue view {issue-number} --json state`.
3. If still open, close it manually: `gh issue close {issue-number}`
### Phase 6: Return to Main
1. `git checkout main`
2. `git pull origin main --ff-only`
3. If `--ff-only` fails (local main diverged), fall back to `git fetch origin && git reset --hard origin/main`
4. Confirm clean state with `git status`.
### Phase 7: Report
Output a summary in this format:
```
## Completed
- **Issue**: #{issue-number} — {issue title}
- **PR**: {PR URL} (merged)
- **Commit**: {short SHA} — {commit message}
- **Branch**: Deleted `{branch-name}`, now on `main`
- **Status**: Clean, up to date with origin/main
```
## Error Handling
- If `gh pr merge --admin` fails for a real reason — merge conflict, missing PR, you are not the admin in this repo, a check in FAILURE state — report and stop. Do not retry the same command; investigate the cause.
- A FAILURE check (not PENDING) is the one signal that should block a merge. Pre-push verification should have caught it. If a remote check disagrees with local, investigate before merging.
- If `git pull --ff-only` fails, fall back to `git fetch origin && git reset --hard origin/main`.
- If any step fails, stop and report what succeeded and what failed.
skills/pr-description/SKILL.md
---
name: pr-description
description: Pure writer for PR titles and bodies. Takes a PR reference (or the current branch), reads diff + commits + linked issue + PR template, and returns structured {title, body}. Does NOT call `gh pr create` or `gh pr edit`. Invoke from `/pr`, `/cpm`, or any caller that needs a CCGM-voice PR body without the publishing plumbing.
disable-model-invocation: false
---
# PR Description Writer
A pure writer skill. One job: produce `{title, body}` for a pull request in CCGM voice, value-first, matching the repo's PR template when one exists.
Never publishes. Never calls `gh pr create`, `gh pr edit`, `gh pr comment`, or any mutating GitHub command. The caller is responsible for doing something with the returned text.
## When to Run
- A caller (e.g., `/pr`, `/cpm`, a coordinator agent) needs PR text and wants the voice separated from the publishing flow
- Rewriting an existing PR body to sharpen it before a second review pass
- Generating text for a PR that does not yet exist, so the caller can preview before pushing
Do NOT run this skill when the caller already has a finalized title and body - pass them through instead.
## Input Parsing
Accept any of the following as the PR reference:
| Form | Example | Meaning |
|------|---------|---------|
| bare number | `561` | PR #561 in the current repo |
| hash number | `#561` | same |
| prefixed | `pr:561` | same |
| full URL | `https://github.com/owner/repo/pull/561` | PR in that repo |
| branch name | `288-pr-description-writer-skill` | find the open PR for this branch, or fall through to "no PR yet" |
| empty / current | (no argument) | current branch; PR may or may not exist |
| steering text | `emphasize the benchmarks` | applied on top of any other input as a tone/content hint |
Multiple forms can coexist. `pr:561 emphasize the perf numbers` means "PR #561, lean on perf."
If no PR exists yet (e.g., the caller is about to create one), operate on the branch: compare `origin/main...HEAD` for the diff and commit set.
## Inputs to Collect
Collect in this order. Stop once each input is captured or confirmed absent.
1. **Linked issue** - from the branch name (`{issue-number}-{description}` convention) or from the PR body's `Closes #N` line. Read with `gh issue view {num}`.
2. **Commits on the branch** - `git log origin/main..HEAD --pretty=format:"%s%n%n%b%n---"`
3. **Diff stat** - `git diff origin/main...HEAD --stat`
4. **Full diff** - `git diff origin/main...HEAD` (sampled; see "Diff Sampling" below)
5. **PR template** - check in order:
- `pull_request_template.md` in the repo root
- `PULL_REQUEST_TEMPLATE.md` in the repo root
- `.github/pull_request_template.md`
- `.github/PULL_REQUEST_TEMPLATE.md`
- If none found, use the fallback structure in `references/default-template.md`
6. **Existing PR body** - if a PR already exists, `gh pr view {num} --json body,title`. Treat as prior art to improve, not replace wholesale.
7. **Steering text** - whatever hint the caller passed. Apply after drafting; do not let it override the template structure.
### Diff Sampling
For diffs over ~500 lines, sample rather than dump:
- Read the full diff stat (every file, every ± count)
- Read full diffs for files with substantive changes (>20 lines added or removed)
- For large generated/lockfile changes, record one line: "`{file}`: {N} lines; generated/lockfile, skipped"
Never claim coverage of a file you did not actually read.
## Title Rules
- Conventional-commit shape: `{type}({scope}): {summary}` or CCGM-style `#{issue}: {summary}` if the branch name carries an issue number
- Under 72 characters total, including any prefix
- Imperative mood (`add`, `extract`, `fix`), not past tense
- Lead with the value or action, not the filename
- If the repo uses `#{issue}:` prefix (check recent `git log --oneline -20` on main), match that convention
Examples:
| Bad | Good |
|-----|------|
| Updated pr.md and cpm.md to use new skill | #288: extract PR description writer as reusable skill |
| Refactor commands-core | #288: move inline PR body generation into pr-description skill |
| Big changes to review flow | feat(review): add scope-drift audit before specialist agents |
## Body Rules - Value-First
The body leads with what the PR enables, fixes, or changes in the user's world. File churn is supporting evidence, not the lead.
Write it in plain words: state what changed and why, active voice, short words. No achievement language — no "comprehensive", no "robust", no "seamless", no "Successfully". A reviewer should know what the PR does in one read. The full standard is `~/.claude/rules/writing-system.md` when the writing-system module is installed.
### Structure (when no PR template exists)
1. **Closes #N** - first line if the PR closes an issue. No other content on this line.
2. **One-sentence summary** - what this PR does, in user-facing terms. No filenames.
3. **Why** - what problem this solves or what capability it unlocks. Two sentences max.
4. **What changed** - bulleted list of concrete changes, each one a noun phrase with a verb:
- "Adds `pr-description` skill under `commands-core`"
- "Updates `/pr` to delegate body generation to the skill"
- "Removes inline body template from `cpm.md`"
5. **Test plan** - how the change was verified. Name commands: `bash tests/test-modules.sh`, manual smoke test of `/pr` on a test issue, etc.
6. **Notes / follow-ups** - optional; only include if there is real carry-over work.
### When a PR Template Exists
Fill the template's sections verbatim. Do not add sections the template does not include. Do not remove sections the template marks required.
If a section in the template does not apply to this PR (e.g., "Screenshots" for a backend-only change), write `N/A - {one-line reason}` rather than leaving it blank.
### Value-First Rationalizations to Avoid
| You are about to write... | The reality is... |
|---------------------------|-------------------|
| "This PR modifies `foo.ts` and `bar.ts`..." | Lead with what those modifications do for the user. File names are not value. |
| "I refactored the review flow for cleanliness." | Cleanliness is not a user-visible outcome. What does the refactor enable? |
| "Adds a new module." | Which module, what does it do, why does that matter? One sentence each. |
| "Various improvements." | If you cannot name them, do not mention them. Delete the bullet. |
| "Comprehensive error handling has been implemented..." | "Adds error handling to every API endpoint." State the change; drop the adjectives and the passive. |
## Diagram: `### How it fits`
Add a `### How it fits` section to the body when the diff changes how control or data moves across 3 or more files, or adds a hook, pipeline stage, or component. Otherwise add no diagram. Apply the trigger as written; do not decide first and justify later.
The section holds one Mermaid `flowchart` with at most 12 nodes. GitHub renders it in the PR body. If `npx` exists, check the diagram before returning:
```bash
npx -y @mermaid-js/mermaid-cli -i x.mmd -o x.svg
```
Fix the diagram until the command exits 0. If `npx` does not exist, leave the diagram out. When a PR template exists, put the section under the template's closest "what changed" heading rather than adding a heading the template lacks.
## Prose Check
Before returning, run these steps as separate commands:
1. Write the body's prose (no code blocks, no Mermaid block) to a temp file in the session scratchpad or temp directory.
2. Run `test -x "$HOME/.claude/bin/ccgm-prose-lint"` as its own command. If it exits non-zero, print `ccgm-prose-lint not installed; skipping the prose check` and continue.
3. Otherwise run `"$HOME/.claude/bin/ccgm-prose-lint" --strict <temp file>` as its own command. Exit 1 means a sentence or paragraph is over the limit: fix it and run again until it exits 0. Warnings do not fail the run; fix the ones that are cheap to fix.
4. Return the body only when the final run exits 0. After three fix attempts you may return it with the findings that remain. Either way, record the final run on the `- Prose check:` METADATA line below. That line is required: a check that is not reported has not run.
## Output Format
Return exactly this structure as the skill's output. The caller parses it.
```
### TITLE
{title, single line, no trailing punctuation}
### BODY
{full body, markdown, starts with `Closes #N` line if applicable}
### METADATA
- Issue: #{num} or "none"
- Branch: {branch-name}
- Commits: {count}
- Files changed: {count}
- Template used: {path} or "default"
- Steering applied: {yes/no}; {one-line summary if yes}
- Diagram: {fired/not fired}; {one line: which part of the trigger applied or why none did}
- Prose check: exit {code}, {N} errors (from the linter's final run on the body; after three failed fixes, list the remaining findings here), or "skipped (ccgm-prose-lint not installed)"
```
Do NOT wrap in additional prose. Do NOT invoke `gh` commands with the result. Do NOT emit a "here's your PR body" preamble.
## Non-Goals
- Creating the PR (`gh pr create`)
- Editing an existing PR (`gh pr edit`)
- Commenting on the PR
- Pushing the branch
- Running verification (tests, lint, build). The one exception is the prose lint on the body and the diagram check, both above
- Deciding whether the PR is mergeable
The caller handles all of the above.
## Integration With Callers
### `/pr` and `/cpm`
Both commands currently write PR bodies inline. A caller that delegates to this skill should:
1. Gather context the skill needs (branch, issue number, template detection) if it already did that work
2. Pass `$ARGUMENTS` (steering text) straight through
3. Use the returned `TITLE` and `BODY` blocks as `--title` and `--body` args to `gh pr create`
4. Leave publishing, merging, and issue-closing to the caller's own flow
This keeps the writer pure and the publisher in charge of side effects.
### Headless Mode
When invoked by another skill or agent (not a human), behave as if `mode:headless`:
- No clarifying questions
- No asking the user to choose between drafts
- Return the single best draft given the inputs available
- If a required input is missing, emit a one-line `BLOCKED` note at the top of the output and stop
## Source
Ported from EveryInc/compound-engineering's `skills/ce-pr-description/SKILL.md`. Adapted to CCGM voice, to match existing commands-core conventions (`{issue}: {description}` title prefix, `Closes #N` body line), and to slot into the skill-authoring rules (imperative voice, no AI attribution, value-first body, references file for the default template).
lib (1)
lib/gs-gather.sh
#!/usr/bin/env bash
# gs-gather.sh - Parallel data gathering for /gs command
# Runs git status, PR, and session checks concurrently.
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT
# --- Identity (synchronous) ---
BRANCH=$(git branch --show-current 2>/dev/null || echo "detached")
UPSTREAM=$(git rev-parse --abbrev-ref @{upstream} 2>/dev/null || echo "No upstream tracking branch")
REPO_NAME=$(git remote get-url origin 2>/dev/null | xargs basename 2>/dev/null | sed 's/\.git$//' || echo "unknown")
# --- Parallel jobs ---
# 1. Fetch + sync status
(
git fetch origin 2>/dev/null
AB_MAIN=$(git rev-list --left-right --count origin/main...HEAD 2>/dev/null || echo "? ?")
AB_UP=$(git rev-list --left-right --count @{upstream}...HEAD 2>/dev/null || echo "? ?")
echo "main:$AB_MAIN"
echo "upstream:$AB_UP"
) > "$TMPDIR/sync" 2>/dev/null &
# 2. Working directory status
(
git status --short 2>/dev/null
) > "$TMPDIR/status" 2>/dev/null &
# 3. Recent commits
(
git log --oneline -5 2>/dev/null
) > "$TMPDIR/log" 2>/dev/null &
# 4. Open PRs
(
gh pr list --state open --limit 10 2>/dev/null || echo "none"
) > "$TMPDIR/prs" 2>/dev/null &
# 5. Sibling sessions
(
python3 ~/.claude/lib/agent_sessions.py --repo "$REPO_NAME" --exclude-cwd "$PWD" --text 2>/dev/null || true
) > "$TMPDIR/sessions" 2>/dev/null &
# 6. Diff stats
(
echo "---UNSTAGED---"
git diff --stat 2>/dev/null
echo "---STAGED---"
git diff --cached --stat 2>/dev/null
) > "$TMPDIR/diff" 2>/dev/null &
wait
# --- Output ---
cat <<GATHER_EOF
=== REPO ===
name:${REPO_NAME}
branch:${BRANCH}
upstream:${UPSTREAM}
=== SYNC ===
$(cat "$TMPDIR/sync")
=== STATUS ===
$(cat "$TMPDIR/status")
=== LOG ===
$(cat "$TMPDIR/log")
=== PRS ===
$(cat "$TMPDIR/prs")
=== SESSIONS ===
$(cat "$TMPDIR/sessions")
=== DIFF ===
$(cat "$TMPDIR/diff")
GATHER_EOF
skill-reference (1)
skills/pr-description/references/default-template.md
# Default PR Body Template (value-first, no repo template found)
Use this structure when the target repo does not ship a PR template under the four paths the skill checks.
```markdown
Closes #{issue_number}
{One-sentence summary of what the PR does, in user-facing terms.}
## Why
{Two sentences max. What problem this solves, or what capability it unlocks.
Lead with the user outcome, not the implementation.}
## What Changed
- {Concrete change as a noun phrase with a verb}
- {...}
- {...}
## Test Plan
- {Named command or manual step, one line each}
- {...}
## Notes
{Optional. Include only if there is real carry-over work, a follow-up issue,
or a known limitation. Delete the section if empty.}
```
## Rules
- `Closes #N` goes on the first line, alone. GitHub uses it to auto-close the issue on merge.
- No `Co-Authored-By: Claude`, `Generated with Claude Code`, or any AI-attribution footer.
- If a section has nothing real to say, omit it rather than padding with filler.
- Keep bullets under ~12 words each. Long bullets are a sign the change should be split.
## When to Skip the Default
If any of these are true, do NOT use this template - the skill should have detected and used the repo's own template instead:
- A file named `pull_request_template.md` or `PULL_REQUEST_TEMPLATE.md` exists in the repo root
- A file exists under `.github/` with either casing
The check is local-only: do not query the org's `.github` repo over the API. A missing repo-level template means use this default, not that you should hunt further.