Skip to main content

ACCID Commit Format

🟢 Stable

ACCID (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.

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)

Next Steps