ACCID Commit Format
StableACCID (Atomic Conventional Consistent Immutable Durable) is a new standard for Git developer experience that combines the best practices of Conventional Commits and Atomic Commits.
ACCID provides a structured commit message format that delivers rich context about code changes while remaining human-readable and machine-parseable.
Let's be honest, we're all a little lazy when it comes to commit messages. But commit messages are critical to a software's lifetime. They're the story of why your code exists. That's why our tool helps you craft the perfect commit message with the help of AI, and we believe ACCID is the ideal format for both humans and machines, built for the future of software. That's why it's our default.
Don't just take our word for it. Here's what Linus Torvalds, arguably the greatest software engineer on the planet, has to say about commit messages:
"Commit messages to me are almost as important as the code change itself. Right? Sometimes the code change is so obvious that no message is really required. But that is very very rare."
ACCID Principles
| Principle | Description |
|---|---|
| Atomic | Each commit represents a single logical change. No mixed concerns, no partial implementations. |
| Conventional | Follows structured format with standard types (feat, fix, etc.) for automated tooling and clear intent. |
| Consistent | Uniform format across all commits using URIs, types, and tags for predictable structure. |
| Immutable | Commits describe completed work, not meant to be squashed or rewritten (except in feature branches). |
| Durable | Rich context (URIs, issue IDs, tags) makes commits useful long-term for archaeology and debugging. |
Format Overview
#<issue_id> [<uri>] <type>: (tags) <summary>
- [<uri>] <change description> (tags)
- [<uri>] <change description> (tags)
(additional tags)
Footer: additional metadata Header Line
Complete Structure
#<issue_id> [<uri>] <type>: (tags) <summary> Components
| Component | Required | Description | Example |
|---|---|---|---|
#<issue_id> | Optional* | Issue/ticket identifier | #123, #JIRA-456 |
[<uri>] | Yes | Resource identifier (top-level) | [auth], [apps::gate] |
<type> | Yes | Conventional commit type | feat, fix, refactor |
(tags) | Optional | Additional context tags | (wip), (breaking) |
<summary> | Yes | Brief description (100-150 chars) | implement OAuth login |
* Required if configured in .repo.yml
Example Headers
# With issue ID
#123 [auth] feat: implement OAuth 2.0 login
# Without issue ID
[auth::services] refactor: extract AuthService
# With tags
#456 [api] feat: (breaking) migrate to REST v2
# Monorepo with app prefix
[apps::gate] fix: resolve session timeout
# Library with crate name
[libs::pixel] feat: add dark mode support URI - Resource Identifier
URIs identify what part of the codebase changed, not the file path. Think of them as logical identifiers.
URI Syntax
- Use
::to separate path segments - Use
:::for functions/methods - Skip common folders like
src/,app/ - No file extensions
- Similar to Rust module paths
Top-Level URI (Header)
Header URIs should be high-level:
[auth] # Authentication module
[apps::gate] # Gate application
[libs::pixel] # Pixel library
[docs] # Documentation
[.github] # GitHub workflows Detailed URI (Body)
Body URIs can be more specific:
# Short form (recommended)
[auth::services::AuthService]
# Full form (when needed for clarity)
[auth::services::auth_service::AuthService:::login]
# With wildcard
[auth::controllers::*] # Multiple controllers changed
[auth::_::AuthService] # Auto-determine path segment URI Examples by Language
TypeScript/JavaScript
# File: src/modules/auth/services/auth.service.ts
# Class: AuthService
# Method: login()
[auth::services::AuthService:::login]
# Or shorter:
[auth::services::AuthService] Rust
# Crate: my_app
# Module: auth::services
# Struct: AuthService
# Function: login
[my_app::auth::services::AuthService:::login]
# Crate name is mandatory for Rust Python
# File: src/auth/services/auth_service.py
# Class: AuthService
# Method: login()
[auth::services::AuthService:::login] Commit Types
| Type | Description | Example |
|---|---|---|
feat | New feature | feat: add OAuth login |
fix | Bug fix | fix: resolve memory leak |
refactor | Code refactoring | refactor: extract service |
perf | Performance improvement | perf: optimize query |
style | Code style/formatting | style: format with prettier |
test | Add/update tests | test: add auth tests |
docs | Documentation | docs: update API guide |
build | Build system/dependencies | build: upgrade deps |
ci | CI/CD changes | ci: add deploy workflow |
chore | Maintenance tasks | chore: update gitignore |
init | Initial commit/setup | init: project scaffold |
impl | Implementation progress | impl: partial OAuth flow |
Optional Tags
Opening Tags (in header)
| Tag | Meaning | Usage |
|---|---|---|
(wip) | Work in progress | Incomplete feature, don't merge yet |
(breaking) | Breaking change | Requires major version bump |
(cleanup) | Code cleanup | Removing unused code, tidying |
(housekeeping) | Maintenance | Routine maintenance tasks |
Closing Tags (before footer)
Additional context can be added as tags before the footer:
(experimental)
(requires-migration)
(db-schema-change) Body Format
Each change should be a bullet point with detailed URI:
- [<detailed_uri>] <description up to 250 chars> (tags) Example Body
- [auth::services::AuthService:::login] implement OAuth login flow
- [auth::controllers::AuthController] add /oauth/callback endpoint
- [auth::models::User] add oauth_provider and oauth_id fields (db-schema)
- [auth::tests] add OAuth integration tests Footer
Use Git trailer format for metadata:
Reviewed-by: Jane Doe <[email protected]>
Refs: #123, #456
Co-authored-by: John Smith <[email protected]> Complete Examples
Example 1: Simple Feature
#123 [auth] feat: implement OAuth 2.0 login
- [auth::services::AuthService] add OAuth provider integration
- [auth::controllers] add /oauth/callback endpoint
- [auth::models::User] add oauth_provider field
Implements standard OAuth 2.0 authorization code flow with PKCE. Example 2: Bug Fix
#456 [session] fix: resolve race condition in cleanup
- [session::services::SessionService:::cleanup] add mutex lock
- [session::tests] add concurrent cleanup test
Fixes intermittent session data corruption during cleanup. Example 3: Breaking Change
#789 [api] feat: (breaking) migrate to REST API v2
- [api::controllers::*] update all endpoints to /v2/
- [api::middleware] add version negotiation
- [api::docs] update API documentation
BREAKING CHANGE: All API endpoints moved to /v2/.
Clients must update base URL.
(requires-migration) Example 4: Multi-Module Change
#321 [*] chore: (cleanup) remove deprecated features
- [auth::legacy] remove old password auth (deprecated in v1.5)
- [api::v1] remove API v1 endpoints (deprecated in v2.0)
- [docs] remove references to deprecated features
(housekeeping) Example 5: Monorepo
[apps::gate] feat: add rate limiting middleware
- [apps::gate::middleware::RateLimiter] implement token bucket algorithm
- [apps::gate::config] add rate_limit configuration
- [apps::gate::tests] add rate limit tests Best Practices
1. Keep Summary Concise
# Good
[auth] feat: implement OAuth login
# Too verbose
[auth] feat: implement OAuth 2.0 login flow with Google provider support 2. Use Appropriate Detail Level
# Header - high level
[auth] feat: implement OAuth
# Body - detailed
- [auth::services::AuthService:::handleGoogleCallback] process callback 3. Group Related Changes
# Good - one commit for related changes
[auth] feat: implement OAuth
- [auth::services] add OAuth service
- [auth::controllers] add OAuth endpoints
- [auth::models] add OAuth fields
# Avoid - separate commits for each file
[auth] feat: add OAuth service
[auth] feat: add OAuth controller
[auth] feat: add OAuth model fields 4. Use Tags Meaningfully
# Good - clear intent
[api] feat: (breaking) change auth endpoint
# Avoid - tag spam
[api] feat: (wip) (experimental) (breaking) new feature Tools Support
AI Generation
Nanx AI can generate ACCID-format messages:
nanx r cgm # Generate ACCID commit
# Configure:
repo:
commit:
generate_message:
format: aacid Validation
Validate commit messages:
# In .repo.yml
commit:
template: aacid
require_issue_id: true # Enforce # Parsing
ACCID messages are machine-parseable for:
- Changelog generation
- Release notes automation
- Impact analysis
- Metrics and reporting
Migration from Conventional Commits
Conventional → ACCID
# Before (Conventional)
feat(auth): implement OAuth login
Add OAuth 2.0 support with Google provider.
Includes login endpoint and callback handler.
# After (ACCID)
[auth] feat: implement OAuth login
- [auth::services::AuthService] add OAuth provider integration
- [auth::controllers] add /oauth/callback endpoint
Implements OAuth 2.0 with Google provider. Why ACCID?
The Problem with Traditional Commits
Traditional commit messages often suffer from:
- ❌ Vague descriptions like "fix bug" or "update code"
- ❌ Mixing multiple unrelated changes in one commit
- ❌ Inconsistent formats across team members
- ❌ Missing context about what/where/why changes happened
- ❌ Difficult to parse for automated tooling
ACCID Advantages
- ✅ Atomic: Single logical change per commit makes bisecting and reverting clean
- ✅ Conventional: Standard types enable automated changelogs and semantic versioning
- ✅ Consistent: Uniform structure across entire team and codebase
- ✅ Immutable: Complete commits with full context, ready for main branch
- ✅ Durable: Rich metadata (URIs, issue IDs) valuable for years of maintenance
- ✅ Traceable: Issue IDs link commits to tickets and requirements
- ✅ Precise: URIs pinpoint exact modules/functions changed
- ✅ Scalable: Designed for monorepos and large projects
- ✅ Tooling-Ready: Machine-parseable for changelogs, metrics, impact analysis
Compared to Conventional Commits
| Feature | Conventional | ACCID |
|---|---|---|
| Scope | Module name | Full resource URI |
| Detail | Body free-form | Structured bullets with URIs |
| Issue linking | In footer | In header (#id) |
| Monorepo | Good | Excellent (app:: prefix) |