Claude code qc
Quick commit + auto-push. Stages changes, drafts a Conventional Commit message from the diff, commits, and pushes. `/qc` pushes the current branch to its origin upstream; `/qc main` switches to main first and pushes there (solo-speed flow — skips PR review). Bootstraps `gh` (install + browser auth) if not already configured. Never bypasses hooks (`--no-verify`), signing (`--no-gpg-sign`), or rewrites commits (`--amend`). No AI attribution lines in commit messages.From its SKILL.md
npx -y skills add TimothyVang/claude-code-qcAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
10.7 KB, ~2.6k tokens by cl100k_base, as published. Nobody here has run it
qc — quick commit + auto-push
Portable, project-agnostic quick-commit skill. Drop this file at ~/.claude/skills/qc/SKILL.md to make /qc available in every project on the machine.
A project may override this with its own .claude/skills/qc/SKILL.md (project-local takes precedence). Use that for project-specific commit conventions (e.g. required task IDs).
Two invocations
/qc— commit + push the current branch to its upstream on origin. Default. Use during normal feature-branch work./qc main— switch tomain(ormaster, whichever the repo's default branch is — detect withgit symbolic-ref refs/remotes/origin/HEAD), commit, push origin's default branch directly. Solo-speed flow — skips the PR review path. Only use when the user is the only reviewer and the change is ready.
If /qc main is invoked while on a feature branch with uncommitted changes, carry the changes across with git stash --include-untracked → git checkout <default> → git stash pop → resolve any conflicts → continue. If conflicts can't be resolved cleanly, stop and surface to the user; do not throw away work.
Step 0 — Prerequisite: gh installed and authenticated
/qc relies on gh having configured git's credential helper so git push over HTTPS doesn't prompt. Before staging anything, verify:
command -v gh >/dev/null && gh auth status >/dev/null 2>&1
If that exits non-zero, bootstrap before continuing.
Install gh if missing
Detect platform first; pick the matching command:
- Ubuntu / Debian:
type -p curl >/dev/null || sudo apt install -y curl curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null sudo apt update && sudo apt install -y gh - macOS (Homebrew):
brew install gh - Fedora / RHEL / CentOS Stream:
sudo dnf install -y gh - Arch:
sudo pacman -S --noconfirm github-cli - Alpine:
sudo apk add github-cli - Windows (winget):
winget install --id GitHub.cli - Other / unknown: point the user at https://cli.github.com/ and stop.
sudo will prompt the user — that is expected; do not try to bypass.
Authenticate via browser (one-time)
gh auth login --hostname github.com --git-protocol https --web
This prints a one-time code, opens the user's browser to https://github.com/login/device, and configures git's credential helper on success.
If the host is headless and can't open a browser:
gh auth login --hostname github.com --git-protocol https
Follow the prompts (paste-the-code flow works without a local browser). For SSH protocol instead, swap --git-protocol https → --git-protocol ssh and let gh upload an SSH key for the user.
Verify
gh auth status # expect "Logged in to github.com account <user>"
git push --dry-run # confirms credential helper is active for this repo
Re-run the gh auth status check after install/auth before continuing to staging. If any step still fails, stop and surface the failure to the user — do not commit work that can't be pushed.
Step 1 — Inspect the working tree
Run in parallel; read the actual changes before drafting any message:
git status
git diff --stat
git diff --cached
git log -5 --oneline
Look for:
- Files the user may not have meant to commit (
.env,*.key,node_modules/, large binaries,__pycache__/). - Two unrelated concerns mixed in one diff (split into two commits if so — see "Multi-commit batches" below).
- The repo's commit-message conventions, inferred from
git log(Conventional Commits? Project-specific tags like[JIRA-123]or[W1.A.0]? Plain prose?). Match the existing style.
Step 2 — Detect project conventions
Before drafting the message, check for project-specific rules in this order (stop at the first hit):
CLAUDE.mdat repo root — if it specifies a commit format (e.g. Conventional Commits + task ID), follow it exactly.CONTRIBUTING.md— same; many projects encode commit rules here..gitmessagetemplate orcommit.templatein.git/config— pre-fill it.- Recent commit log — match the dominant style (
type(scope): summaryif Conventional,JIRA-123: ...if ticket-prefixed, plain imperative one-liner otherwise).
If a project mandates a task ID (e.g. [W1.A.0], JIRA-123, #42), resolve it from:
- An explicit ID the user gave in this turn.
git log -20 --pretty=%s | grep -oE '<id-pattern>' | head -1to reuse the active task.- Project's plan file (
BUILD_PLAN.md,ROADMAP.md,.linear/, etc.) cross-referenced with the touched paths. - If still unresolved, ask before defaulting.
Step 3 — Stage
Prefer named-path staging over git add -A:
git add path/to/file.py path/to/other.md
This avoids sweeping in .env, credentials, __pycache__/, build artifacts, or large binaries the user didn't mean to commit.
git add -A / git add . is acceptable only if:
- The user explicitly said "everything" / "all changes" / "stage all", AND
git statusshows no unexpected files (no.env*, no*secret*, no large unfamiliar additions).
Step 4 — Draft the commit message
One sentence, imperative voice ("add", "fix", "remove" — not "added", "adding"), focused on why the change is being made, not what files changed (the diff already shows that).
Defaults if no project convention is detected:
- Format:
<type>(<scope>): <summary> type∈ {feat,fix,test,chore,docs,refactor,perf,style,ci,build,revert}.scopeis optional but recommended — the module/area touched.- Summary ≤ 70 chars where possible.
- Body only when the change is non-obvious; skip otherwise.
Verb mapping when picking type:
- New user-visible capability →
feat - Behavior bug fix →
fix - Test added/changed without behavior change →
test - Version pins, tooling, config, dependencies →
chore - Docs only →
docs - No-behavior-change cleanup →
refactor - Performance only, no behavior change →
perf
Forbidden in commit messages:
Co-Authored-By: Claude …,🤖 Generated with [Claude Code], or any AI-attribution line. Authorship is git committer + signature only.- Padding like
Update files.orMisc changes.— say what changed and why.
State the drafted message to the user in one line before committing, so they can correct it if needed.
Step 5 — Commit
git commit -m "<type>(<scope>): <summary>"
Hard rules — never violate:
- No
--no-verify(skipping pre-commit / commit-msg hooks). - No
--no-gpg-sign(skipping GPG signing if the repo requires it). - No
git commit --amendto fold in a fix — that rewrites history. Always make a new commit. - No
--allow-emptyunless explicitly requested.
If a pre-commit hook fails: read the failure output, fix the underlying issue (lint, format, type-check, etc.), re-stage the fix, and create a new commit (the hook failure means the prior commit didn't happen — --amend would fold into the previous successful commit, which is wrong). If the hook fails repeatedly on the same issue, stop and root-cause; do not loop.
If the user asks you to bypass hooks, refuse and explain why. Hooks exist because the project's maintainers wanted them; bypassing is a project-policy decision, not a one-off override. Ask the user to either fix the issue or, if they're sure, run the bypass themselves with git commit --no-verify — don't do it on their behalf.
Step 6 — Push
git push -u origin HEAD
If the branch already tracks an upstream, plain git push is fine.
For /qc main:
git push origin <default-branch>
Force-push is not part of /qc. If git push rejects with non-fast-forward, stop and surface to the user. Do not --force or --force-with-lease autonomously — that overwrites someone else's work and is destructive.
Multi-commit batches
If the staged changes are obviously two unrelated concerns (e.g. a feat + an unrelated docs fix), split into two commits with two messages rather than mushing them together. State the split plan before staging the first one.
A reasonable rule of thumb: if you'd write two different type(scope) headers for the same diff, it's two commits.
What /qc does not do
- Open PRs (
gh pr create --fill) — that's a separate/shiporgh pr createstep. - Merge PRs (
gh pr merge) — same. - Run tests / lint / type-check manually — pre-commit hooks own that. If hooks aren't installed, run
pre-commit installfirst or surface to the user. - Force-push, rebase, or rewrite history.
- Skip signing or hooks under any circumstance.
- Edit
~/.gitconfigor set committer identity. Ifuser.name/user.emailaren't set, surface to the user — guessing the identity is wrong.
Failure modes — surface, don't silently swallow
- Working tree contains files the user may not want committed (
.env, large binaries, secrets) → list them, ask. - No commit-message convention detectable AND no recent commits to mimic → ask the user for preferred format.
- Required task ID can't be resolved → ask before defaulting.
- Pre-commit hook fails repeatedly on the same issue → stop, root-cause, do not loop.
git pushrejected (non-fast-forward, branch protection, etc.) → show the error verbatim; do not--force.gh auth statusfails after attempted bootstrap → stop, show the error, ask the user to rungh auth loginmanually.
Sharing this skill
This file is the entire skill. To share it with a teammate:
- Send them this
SKILL.md. - They drop it at
~/.claude/skills/qc/SKILL.md(create the dir if needed). - Next Claude Code session,
/qcis available globally on their machine.
Or commit a copy at <your-project>/.claude/skills/qc/SKILL.md so anyone working in that project gets it project-locally without installing globally.
What ships with it: 4 files
10.5 KB alongside SKILL.md, 1 of them executable
- .gitignore38 B
- install.shruns723 B
- LICENSE1.0 KB
- README.md8.7 KB