Update code # No type, no scope
feature(everything): big refactor # Wrong type, too broad scope
fix(auth): WIP # Incomplete work
feat: add AI content gen + fix bugs # Two features in one commit
Add secret key abc123def456 # SECRET IN COMMIT
Severity Mapping
CRITICAL
Commit containing secrets/credentials (API keys, passwords, tokens, database URLs, even if removed in a later commit — git history is persistent)
Includes hardcoded: OpenAI/Gemini API keys, Stripe secret keys, database passwords, OAuth tokens, private URLs
If found: invalidate the credential immediately, force-push (with human approval), or escalate to security
Merge commit in PR (indicates work was not rebased; should be linear history)
Impact: Credentials can be exfiltrated; git history becomes non-linear and hard to bisect.
Confidence: Always report if you can confirm the credential is present.
HIGH
Commit message does not follow conventional format (no type(scope):, or type is not in the approved list)
Single giant commit containing 5+ unrelated changes (should be split into atomic commits)
fixup! or squash! commits left unresolved (work in progress left in branch)
Commit message is unintelligible ("asdf", "quick fix", "ugh", "still broken")
Impact: Release notes cannot be generated; bisecting is impossible; hard to understand intent.
Confidence: Report at 85%+.
MEDIUM
Commit message missing Linear issue reference (should include SYN-XXX or UNI-XXXX unless doc-only)
Scope not matching any directory (e.g., fix(something) where something/ does not exist)
Commit message >100 characters (harder to scan in log)
Multiple logical changes in one commit (two bug fixes, or a feature + refactor combined)
Branch name not following convention (should be feature/foo, fix/bar, not my-branch or work)
Impact: Harder to track which issue a commit addresses; navigation less efficient.
Confidence: Report at 80%+.
LOW
Commit message missing description (has type(scope): but no explanation of why)
Message casing inconsistency (first word not capitalised: feat(api): add endpoint vs feat(api): Add endpoint)
Trailing punctuation missing (convention is no period at end of subject)
Using past tense (feat(auth): added login instead of feat(auth): add login)
Scoped to version number or ticket number (e.g., fix(SYN-123): — issue goes in message, not scope)
Impact: Minor readability; standards consistency.
Confidence: Report at 80%+.
Checklist
Before reporting a finding:
Is this a commit in the PR, or a commit from main (only flag PR commits)?
Does the message follow type(scope): description?
Is the type in the approved list (feat, fix, docs, chore, test, refactor, perf, style, ci, build)?
Does the scope match an actual directory in the codebase?
Is the description capitalised and clear?
Does the commit message include a Linear issue reference?
Is this a merge commit (if so, flag)?
Are there any hardcoded secrets/credentials in the commit?
Is the commit atomic (one logical change) or does it combine multiple unrelated changes?
Is the commit message >100 characters (if so, note but don't flag as HIGH)?
Is this a doc-only change (if yes, issue reference is optional)?
1---2name: commit-hygiene3description: Commit Hygiene Review Specialist4---5# Commit Hygiene Review Specialist67---8name: commit-hygiene9description: Enforce conventional commits, atomic changes, no merge commits, branch naming, Linear issue references10type: review-specialist11severity_levels: [CRITICAL, HIGH, MEDIUM, LOW]12confidence_threshold: 8013---1415## Context1617This specialist ensures **commit and branch hygiene** across Synthex development. Clean commit history is essential for:18- Root-cause analysis and bisecting (finding which commit introduced a bug)19- Release notes generation (automated from conventional commit types)20- Code review clarity (atomic commits are easier to review)21- Team collaboration (consistent naming reduces cognitive load)22- Regulatory compliance (audit trails for financial/campaign data)2324**Synthex commit standards:**25- **Conventional format**: `type(scope): description (LINEAR-ISSUE)`26- **Valid types**: `feat`, `fix`, `docs`, `chore`, `test`, `refactor`, `perf`, `style`, `ci`, `build`27- **Valid scopes**: directory names from `app/`, `lib/`, `components/`, `prisma/`, `scripts/`, etc.28- **Atomic commits**: one logical unit per commit (not 10 features in one commit, not one feature split across 20 commits)29- **No merge commits**: all work integrated via rebase or squash30- **No secrets**: credentials never in git history (even if later removed)31- **Linear issue reference**: all non-doc commits should reference a Linear issue (SYN-XXX, UNI-XXXX)3233**Example good commit:**34```35feat(dashboard): add campaign performance widget (SYN-234)36```3738**Example bad commits:**39```40Update code # No type, no scope41feature(everything): big refactor # Wrong type, too broad scope42fix(auth): WIP # Incomplete work43feat: add AI content gen + fix bugs # Two features in one commit44Add secret key abc123def456 # SECRET IN COMMIT45```4647---4849## Severity Mapping5051### CRITICAL52- **Commit containing secrets/credentials** (API keys, passwords, tokens, database URLs, even if removed in a later commit — git history is persistent)53 - Includes hardcoded: OpenAI/Gemini API keys, Stripe secret keys, database passwords, OAuth tokens, private URLs54 - If found: invalidate the credential immediately, force-push (with human approval), or escalate to security55- **Merge commit in PR** (indicates work was not rebased; should be linear history)5657**Impact:** Credentials can be exfiltrated; git history becomes non-linear and hard to bisect.5859**Confidence:** Always report if you can confirm the credential is present.6061### HIGH62- **Commit message does not follow conventional format** (no `type(scope):`, or type is not in the approved list)63- **Single giant commit** containing 5+ unrelated changes (should be split into atomic commits)64- **fixup! or squash! commits left unresolved** (work in progress left in branch)65- **Commit message is unintelligible** ("asdf", "quick fix", "ugh", "still broken")6667**Impact:** Release notes cannot be generated; bisecting is impossible; hard to understand intent.6869**Confidence:** Report at 85%+.7071### MEDIUM72- **Commit message missing Linear issue reference** (should include SYN-XXX or UNI-XXXX unless doc-only)73- **Scope not matching any directory** (e.g., `fix(something)` where `something/` does not exist)74- **Commit message >100 characters** (harder to scan in log)75- **Multiple logical changes in one commit** (two bug fixes, or a feature + refactor combined)76- **Branch name not following convention** (should be `feature/foo`, `fix/bar`, not `my-branch` or `work`)7778**Impact:** Harder to track which issue a commit addresses; navigation less efficient.7980**Confidence:** Report at 80%+.8182### LOW83- **Commit message missing description** (has `type(scope):` but no explanation of why)84- **Message casing inconsistency** (first word not capitalised: `feat(api): add endpoint` vs `feat(api): Add endpoint`)85- **Trailing punctuation missing** (convention is no period at end of subject)86- **Using past tense** (`feat(auth): added login` instead of `feat(auth): add login`)87- **Scoped to version number or ticket number** (e.g., `fix(SYN-123):` — issue goes in message, not scope)8889**Impact:** Minor readability; standards consistency.9091**Confidence:** Report at 80%+.9293---9495## Checklist9697Before reporting a finding:9899- [ ] Is this a commit in the PR, or a commit from `main` (only flag PR commits)?100- [ ] Does the message follow `type(scope): description`?101- [ ] Is the type in the approved list (feat, fix, docs, chore, test, refactor, perf, style, ci, build)?102- [ ] Does the scope match an actual directory in the codebase?103- [ ] Is the description capitalised and clear?104- [ ] Does the commit message include a Linear issue reference?105- [ ] Is this a merge commit (if so, flag)?106- [ ] Are there any hardcoded secrets/credentials in the commit?107- [ ] Is the commit atomic (one logical change) or does it combine multiple unrelated changes?108- [ ] Is the commit message >100 characters (if so, note but don't flag as HIGH)?109- [ ] Is this a doc-only change (if yes, issue reference is optional)?110111---112113## Output Format114115```json116{117 "specialist": "commit-hygiene",118 "tier": "standard",119 "duration_ms": 0,120 "findings": [121 {122 "severity": "CRITICAL|HIGH|MEDIUM|LOW",123 "confidence": 90,124 "file": "N/A",125 "line": 0,126 "issue": "Commit message does not follow conventional format: 'add stuff' (no type/scope)",127 "fix": "Reword commit to 'feat(dashboard): add campaign widget (SYN-123)'",128 "reference": "CLAUDE.md — Commit conventions"129 }130 ],131 "summary": {132 "critical": 0,133 "high": 1,134 "medium": 0,135 "low": 0136 },137 "verdict": "BLOCK"138}139```140141**Rules:**142- `file` is typically `N/A` (applies to commit, not a file)143- `line` is typically 0 (applies to entire commit)144- `confidence` must be ≥80 to include145- `verdict` = "BLOCK" if any CRITICAL, else "PASS"146147---148149## Synthex-Specific Rules150151### Conventional Commit Format (Strict)152**Pattern:** `type(scope): description (LINEAR-ISSUE)`153154**Valid types:**155- `feat` — new feature156- `fix` — bug fix157- `docs` — documentation update158- `chore` — routine maintenance (deps, config, tooling)159- `test` — test additions or fixes160- `refactor` — code restructure without behaviour change161- `perf` — performance improvement162- `style` — formatting, whitespace, lint fixes (no logic change)163- `ci` — CI/CD pipeline changes164- `build` — build system, bundler, deployment changes165166**Valid scopes:** any directory name at root level (e.g., `app`, `lib`, `components`, `prisma`, `scripts`, `public`, `config`) or subsystem (e.g., `api`, `auth`, `dashboard`, `forms`)167168**Examples:**169```170feat(dashboard): add campaign performance widget (SYN-456)171fix(api): resolve org-scoping bypass in /api/posts (UNI-123)172docs(readme): update installation steps173test(auth): add PKCE flow test cases (SYN-789)174refactor(lib): extract email validation to util (SYN-234)175perf(database): add index on campaign.created_at (SYN-567)176style(components): fix ESLint violations in Button.tsx177ci(github): add type-check to pre-commit hook178chore(deps): upgrade Next.js to v15.1179build(vercel): configure environment variables180```181182**Invalid examples:**183```184Update code # No type/scope185feature(everything): big change # Wrong type, too broad scope186fix(SYN-123): something # Issue goes in message, not scope187Add stuff and refactor utils and fix # Multiple unrelated changes + no type/scope188Quick fix lol # Unintelligible189```190191### Atomic Commits192A commit should represent **one logical unit of work**:193- One feature → one commit (or a small series: add types, add logic, add tests)194- One bug fix → one commit195- One refactor → one commit196- Never: feature + bug fix + style cleanup in one commit197198**If a commit touches:**199- API route, model, tests, and docs → acceptable as one atomic commit200- Dashboard page + unrelated API endpoint → should be split into two commits201202### Linear Issue References203- **All commits** (except doc-only) should include a Linear issue: `(SYN-XXX)` or `(UNI-XXXX)`204- **Location**: end of commit message subject line205- **Format**: `type(scope): description (LINEAR-ISSUE)`206- **Doc-only exception**: `docs(readme): update onboarding steps` (no issue required)207208**Examples:**209```210feat(dashboard): add campaign widget (SYN-456)211fix(auth): resolve session timeout (UNI-123)212```213214### Branch Naming Convention215- **Feature branch**: `feature/short-descriptive-name` (e.g., `feature/campaign-scheduler`)216- **Bug fix branch**: `fix/short-descriptive-name` (e.g., `fix/org-scoping-bypass`)217- **Documentation branch**: `docs/short-descriptive-name` (e.g., `docs/api-endpoints`)218- **Chore branch**: `chore/short-descriptive-name` (e.g., `chore/upgrade-deps`)219220**Invalid examples:**221- `my-branch` (no prefix)222- `SYN-456` (bare issue number)223- `work` (too vague)224- `feature-VERY-LONG-DESCRIPTIVE-NAME-WITH-LOTS-OF-WORDS` (too long)225226### No Merge Commits227- Commits in PR should be **linear** (rebased, not merged)228- If history shows a merge commit, flag as CRITICAL229- Before merging to main, ensure no merge commits exist in branch history230231**Good:**232```233feat(dashboard): add widget234fix(api): resolve timeout235docs(readme): update236```237238**Bad (merge commit):**239```240Merge pull request #123 from ...241```242243### Secrets Detection (CRITICAL)244Flag any hardcoded or committed secrets:245- API keys: OpenAI, Gemini, Stripe, AWS, etc.246- Tokens: GitHub, OAuth, Bearer tokens247- Passwords: database, service account, SSH keys248- URLs: private endpoints, database connection strings249- Even if "removed" in a later commit — git history is persistent250251**If found:**2521. Report as CRITICAL2532. Note: "Credential visible in git history; if real, invalidate immediately and force-push with caution"254255**Safe patterns:**256- Environment variables: `process.env.OPENAI_API_KEY`257- `.env.example`: placeholder values only (`OPENAI_API_KEY=your-key-here`)258- Secrets in `.env.local` or `.env.production` (these files are `.gitignore`d)259260### Excluded from Review261- Commits on `main` (review only PR branch commits)262- Revert commits (e.g., `revert: ...` is acceptable for rollbacks)263- Merge commits from automated tools (e.g., Dependabot) — flag only if manual merge in user PR264- Pre-existing commits already merged (historical hygiene is lower priority)265266---267268## Methodology2692701. **Extract commit list** — get all commits in PR branch (not in main)2712. **Parse each commit message** — extract type, scope, description, issue ref2723. **Validate format** — check against conventional commit spec2734. **Check for secrets** — scan message and diff for hardcoded credentials2745. **Assess atomicity** — verify one logical unit per commit2756. **Check branch naming** — verify branch name follows convention2767. **Report findings** — only confidence ≥80%, map to severity277278---279280## Examples281282### Example 1: CRITICAL — Commit contains API key283```284commit abc123def456285Author: dev@synthex.social286Date: 2026-03-31287288 feat(api): add OpenAI integration289290 OPENAI_API_KEY=sk-proj-abc123def456xyz789...291292❌ FAIL293```294295**Finding:**296- Severity: CRITICAL297- Issue: OpenAI API key visible in commit message298- Fix: If real key, invalidate immediately. Rewrite history with `git rebase -i` or force-push. If placeholder, reword commit to remove credential.299300### Example 2: HIGH — Commit message not conventional301```302commit abc123def456303Author: dev@synthex.social304305 Update code306```307308**Finding:**309- Severity: HIGH310- Issue: Commit message does not follow conventional format (no type/scope)311- Fix: Reword to `feat(dashboard): add campaign widget (SYN-456)`312313### Example 3: MEDIUM — Missing Linear issue reference314```315commit abc123def456316317 fix(auth): resolve session timeout318319 User session was not being refreshed correctly. Added token refresh logic.320```321322**Finding:**323- Severity: MEDIUM324- Issue: Commit message missing Linear issue reference325- Fix: Reword to `fix(auth): resolve session timeout (SYN-789)`326327### Example 4: MEDIUM — Commit combining multiple features328```329commit abc123def456330331 feat(dashboard): add widget and fix API timeout and update docs332333 - Added campaign widget334 - Fixed /api/posts timeout335 - Updated README336337❌ FAIL (three unrelated changes)338```339340**Finding:**341- Severity: MEDIUM342- Issue: Single commit contains multiple logical changes (should be split into three commits)343- Fix: Split into:344 - `feat(dashboard): add campaign widget (SYN-456)`345 - `fix(api): resolve /api/posts timeout (SYN-457)`346 - `docs(readme): update documentation (no issue ref)`347348### Example 5: LOW — Message casing inconsistency349```350commit abc123def456351352 feat(auth): add PKCE flow support (SYN-789)353354 added support for PKCE...355356❌ FAIL (first word of body not capitalised)357```358359**Finding:**360- Severity: LOW361- Issue: Message body should be capitalised362- Fix: Reword to `Added support for PKCE...`363364---365366## References367368- [Conventional Commits spec](https://www.conventionalcommits.org/)369- [Git commit message best practices](https://chris.beams.io/posts/git-commit/)370- Synthex conventions: `.claude/CLAUDE.md` section "Code Conventions"371- Linear issue project: [unite-hub Synthex](https://linear.app)
Run npx skillmds@latest add cleanexpo/commit-hygiene in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Commit Hygiene Review Specialist It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
cleanexpo (@cleanexpo) published this skill. Their other Agent Skills are listed on their SkillMD profile.