Warning
🚧 THIS DOCUMENT IS WORK IN PROGRESS 🚧
This work is currently published as a Request For Comments (RFC), feel free to give opinions and propose changes!
Note
Please notice that the emojis found in this document are only meant as a visual aid for the reader, THEY ARE NOT part of the standard.
Please notice that the collapsable sections are likely to contain meaningful parts of the standard, once again, they are collapsable just as a visual aid.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
The Standard Commits format is a structured approach to writing commit messages that enhance clarity and consistency in version control systems. This format is particularly beneficial for projects with multiple contributors, as it provides a common language for describing changes. Without getting lost in too many frills:
Why use Standard Commits?
- Create a history that is easily greppable and log-like
- Make commits context-rich so that they are easily interpretable even in the future
- Bring consistency even among commits of different people
- Let projects relying on the repo determine compatibility with new changes just by looking at the commits headers
What are the benefits of using the Standard Commits format over existing commit message formats?
The following table summarizes the main advantages of the Standard Commits format compared to other commit message formats:
| Feature/Aspect | Standard Commits | Conventional Commits | Gitmoji Commits | Tim Pope Style |
|---|---|---|---|---|
| Grammar-based | 🟢 Yes | 🟢 Yes | 🔴 No | 🔴 No |
| Structured Format | 🟢 High | 🟡 Medium | 🔴 Low | 🔴 Low |
| Readability | 🟡 Medium | 🟡 Medium | 🟡 Medium | 🟢 High |
| Consistency | 🟢 High | 🟡 Medium | 🔴 Low | 🔴 Low |
| Greppability | 🟢 High | 🟡 Medium | 🟡 Medium | 🔴 Low |
| Scope Annotation | 🟢 Yes | 🟢 Yes | 🟢 Yes | 🔴 No |
| Reason Annotation | 🟢 Yes | 🔴 No | 🟡 Partially | 🔴 No |
| Importance Levels | 🟢 Yes | 🟡 Partially | 🟡 Partially | 🔴 No |
| Expressiveness-Length ratio | 🟢 High | 🟡 Medium | 🟣 Top | 🔴 Low |
| Concision | 🔴 Low | 🟡 Medium | 🟢 High | 🟣 Top |
The Standard Commits format, as universally recognized, is composed of two distinct fragments: the structured (or formal) fragment and the unstructured (or expository) fragment.
The former adheres to a prescribed format, ensuring clarity and consistency in commit messages. It is formally expressed as: <verb><importance?>(<scope?>)[<reason?>].
The latter expands upon the structured prefix, providing deeper insight into the modification. It consists of three elements: <summary>, <body>, and <footer>.
Each commit MUST have a <verb> and a <summary> but all the other fields are present on a case-by-case basis.
Syntax Specification
<verb><importance?>(<scope?>)[<reason?>]: <summary>
<body?>
<footer?>
| 🔊 verb | 🔖 scope | 💡 reason | |
|---|---|---|---|
add (add) |
? (possibly breaking) |
exe (executable) |
int (introduction) |
rem (remove) |
! (breaking) |
lib (backend library) |
pre (preliminary) |
ref (refactor) |
!!(critical) |
test (testing) |
eff (efficiency) |
fix (fix) |
build (building) |
rel (reliability) |
|
undo (undo) |
doc (documentation) |
cmp (compatibility) |
|
release (release) |
ci (continuous integration) |
mnt (maintenance) |
|
cd (continuous delivery) |
tmp (temporary) |
||
exp (experiment) |
|||
sec (security) |
|||
upg (upgrade) |
|||
ux (user experience) |
|||
pol (policy) |
|||
sty (styling) |
| 📝 summary | ℹ️ body | ⚙️ footer |
|---|---|---|
| Starts with a lowercase letter | Starts with an uppercase letter | Each tag on a new line, format: <key>: <value> |
| Concise and descriptive of what the change does | Expands on why and how, not what (already in summary) | MUST be separated from body by a blank line |
| MUST not repeat info from the structured fragment | Organized in short, clear paragraphs | Breaking: ─ describe breaking changes |
| ≤ 50 UTF-8 characters (excluding the structured prefix) | Written in imperative mood | Fixes: #N ─ closes referenced issues |
| SHOULD use a subset of Markdown | SHOULD use a subset of Markdown | Co-authored-by: ─ attributes co-authorship |
Example
add!(lib/type-check)[rel]: enforce type checking in function calls
Previously, the semantic analyzer allowed mismatched parameter types
in function calls, leading to runtime errors. This fix implements
strict type validation during the semantic analysis phase.
Breaking: The `validateCall` function now returns `TypeMismatchError`
instead of returning a boolean, requiring updates in error handling.
Fixes: #247
Co-authored-by: Foo Bar <foo.bar@compiler.dev>
A <verb> describes how something has changed via an expectation. An expectation is a requirement that the code should respect.
The Standard Commits format provides a set of predefined verbs to ensure consistency and clarity in commit messages, and other verbs SHOULD be avoided.
-
➕
add(add) : Adds an expectation Introduces new content to the repository with the expectation that it SHALL behave as intended.add(lib/lexer)[int]: token recognition for string literals -
➖
rem(remove) : Removes an expectation Eliminates content from the repository, and consequently MUST drop all expectations associated with it.rem(lib/parser)[mnt]: deprecated recursive descent methods -
♻️
ref(refactor) : Maintains the expectation but changes the approach Changes approach (e.g., implementation) details while MUST maintain the same expectations about its behavior.ref(lib/codegen)[eff]: use hash table for symbol lookup -
🩹
fix(fix) : Makes the approach comply with expectations Corrects the approach, so that it SHALL comply with the expectations that were previously believed satisfied.fix(lib/parser)[rel]: handle nested function declarations -
🔙
undo(undo) : Undoes changes to an expectation Brings the expectation back to a previous state by reverting specific commits, ensuring that it SHALL meet the original requirements.undo(lib/optimizer)[cmp]: aggressive loop unrolling introduced in #a1b2c3dCompliance details - undo
- MUST prefer
undooveraddorremif the changes to revert are perfectly covered by some commits. - MUST prefer
reforfixoverundoif the expectations SHALL remain unchanged - SHOULD specify the reverted commit(s) if known
- MUST prefer
-
📌
release(release): Releases the set of expectations met Declares that a set of expectations MUST now be satisfied and ready to be publicly distributed.# Pre-release release[pre]: v1.2.0 # Release release: v1.2.0
Compliance details - release
-
Use
releasewhen officially publishing a version — such as tagging a release, deploying, or pushing to a package registry. -
If you're only preparing for a release — e.g., writing the changelog, bumping internal versions, cleaning up — use
[pre]as<reason>. -
Follow Semantic Versioning when choosing version numbers. As explained in SemVer Specification, the version MAY be prefixed with
v(e.g., either1.2.3orv1.2.3).
-
Compliance details - omission
Implies the change MUST NOT be particularly relevant for maintainers or users.
This field is a marker that is intended to be applied only to specific commits that maintainers/users should pay attention to.
-
❔
?(question) : Changes something exposed externally, but not an API. It SHOULD NOT be breaking for projects that depend on the underlying repository.Example
An example of a question (
?) importance could be used when the output of the program shifts to a new more explicative version. For instance, changing the output from:Result: 7
to
Calculation Result: 7 (Success)
This update does not break compatibility since the core functionality and APIs remain unchanged, but users or scripts parsing the output may notice differences.
-
❗
!(exclamation) : Changes an API exposed externally. It is breaking for projects that depend on the underlying repository. The <footer> MUST specify the breaking change (Breaking).Example
An example of an exclamation (
!) importance would be renaming or removing a public function that downstream projects rely on. For instance, changing the signature of a function from:pub fn calculate(a: i32, b: i32) -> i32
to
pub fn calculate(values: Vec<i32>) -> i32
-
‼️ !!(loud exclamation) : This change is critical ─ previous versions have severe issues that must be addressed. Projects depending on the underlying repository SHOULD update immediately. The <footer> MUST specify the last safe commit (Last-safe-commit).Example
An example of a loud exclamation (
!!) importance would be fixing a severe security vulnerability or resolving a bug that causes data corruption. For instance:- Fixing a bug where a memory leak causes system crashes under heavy load.
- Patching a security flaw that exposes sensitive user data.
Compliance details - omission
- Implies the change MUST affect the entire repository.
- Implies the enclosing parenthesis
()MUST be omitted as well.
Compliance details - customization
Standard Commits does not impose any specific identifier for the scope, but it is RECOMMENDED to use a consistent naming convention throughout the project. Guidelines for naming scopes include:
- The folder structure of the repository SHOULD NOT be used as a scope because it is not always unambiguous and can change over time.
- The identifier MUST be in lowercase ─ e.g.,
lib/parser. - The identifiers, when composed of multiple words, MUST be separated by underscores or hyphens ─ e.g.,
lib/parser-json(kebab-case) orlib/parser_json(snake_case).
The scope defines what has changed. A scope MAY be a single identifier or a nested sequence of identifiers separated by a slash /.
Suggestions for common prefix identifiers include:
-
▶️ exe: Concerns the executableE.g., all code that defines the command‑line interface, argument‑parsing logic, individual commands or subcommands, and any binary‑specific setup (e.g., packaging, environment bootstrapping).
-
📚
lib: Concerns libraryE.g., modules, APIs, data models, algorithms, and business‑logic routines that can be imported by the executable or by other consumers without depending on any CLI‑specific code.
-
✅
test: Concerns testsE.g., unit tests, integration tests, property‑based tests.
-
🏗️
build: Concerns the build processE.g., build scripts, Dockerfiles, Makefiles, compilation flags.
-
📓
docs: Concerns documentationE.g., README files, API docs, man pages, changelogs.
-
♾️
ci: Concerns continuous integrationE.g., GitHub Actions, GitLab CI, linter, or test workflows.
-
📤
cd: Concerns continuous deliveryE.g., deployment pipelines, release automation, versioning.
Compliance details - omission
- Implies the reason for the change MUST not be any of the "standards".
- Implies the enclosing brackets
[]MUST be omitted as well. - Implies the reason for the change SHOULD be reported in the unstructured fragment.
The reason explains why something has changed. It MUST be a single identifier chosen from a predefined set of reasons.
The reasons identifiers include:
-
🆕
int(introduction) : Introduces new functionality or componentsE.g., features, services, abstractions.
-
🔜
pre(preliminary) : Prepares for future changesE.g., scaffolding, placeholders, or partial implementation. The <footer> with the
Follow-upis mandatory. -
⚡
eff(efficiency) : Improves performance or resource usageE.g., space/time complexity, optimizes CPU, memory, or I/O.
-
🛡️
rel(reliability) : Improves runtime correctnessE.g., reduces the error rate, handles edge cases, prevents crashes.
-
🧩
cmp(compatibility) : Improves backward or cross-platform compatibilityE.g., supports older APIs, avoids breaking changes.
-
🛠️
mnt(maintenance) : Improves maintainabilityE.g., refactor code, simplifies the structure, removes dead code, and improves modularity.
-
⌛
tmp(temporary) : Temporary workaround or shortcutE.g., to be reverted, removed, or rewritten.
-
🧪
exp(experiment) : Introduces experimental codeE.g., exploratory changes, often reverted or iterated on later.
-
🔒
sec(security) : Improves security or privacyE.g., fixes vulnerabilities, hardens authentication, prevents leaks.
-
🆙
upg(upgrade) : Upgrades external dependenciesE.g., bumping versions, migrating frameworks.
-
🕹️
ux(user experience) : Enhances the final user’s experienceE.g., better UI behavior, clearer feedback or error messages, accessibility.
-
📑
pol(policy) : Enforces a policyE.g., legal compliance, internal coding standards, external specs.
-
💄
sty(styling) : Changes formatting, naming, layout, or any purely cosmetic characteristicE.g., no semantic change.
In all the sections of the unstructured fragment apply the following guidelines:
- 🧾 Use Markdown where helpful
It is RECOMMENDED to use some lightweight Markdown formatting, in the following cases:
- backticks
`_`─ to enclose identifiers - quotes
"_"─ to enclose words not used in their proper/most used meaning - unordered / ordered lists: it's RECOMMENDED to use only one style of markers (i.e.
*|-|+,1.|1)) - links
⚠️ Warning
Other formatting options SHOULD NOT be used. - backticks
- 🔍 Be as direct as possible Do not repeat information that appears in the structured fragment or previous parts of the message. Assume the reader has access to the entire commit (source files included).
- 🧭 Separate sections with a blank line The following sections MUST be ordered as follows and each one is separated from the next one by a blank line.
The summary is a single-line sentence that gives a concise, human-readable description of the change. It appears immediately after the structured fragment and is separated from it by a colon (:) and a space.
To ensure clarity, consistency, and compatibility across tooling, the commit header (i.e., the first line after the structured fragment) MUST follow these rules:
- ✓ Start with a lowercase letter The first word of the header MUST be lowercase, unless it is a proper noun or acronym.
- ✏️ Phrase as a short description The header MUST be written as a concise description of what the change does.
- 🚫 Avoid redundancy with the structured fragment The header MUST NOT repeat information already encoded in the structured prefix (e.g., affected module, type of change, "add ...", "remove ...", ...)
- 📏 Limit to 50 UTF-8 characters
While the summary should be as short as possible (without compromising its clarity), it SHOULD NOT exceed 50 characters. Note that this limitation applies only to the
<summary>, the structured fragment is not included in the 50 characters mentioned.
Compliance details - omission
Implies that if the <body> is omitted, and the <footer> is also omitted, then the blank line that would normally separate <summary> and <body> SHOULD be omitted as well.
The body elaborates on the summary. It provides additional context and technical details to help maintainers and contributors understand the rationale, approach, trade-offs, or limitations of the change.
It MUST follow these rules:
- ✍️ Use imperative mood
Write as if giving instructions to the codebase:
"Refactor logic to avoid side effects" ✅ "Refactored logic to avoid side effects" ❌
- 📚 Structure content clearly
Write in full sentences organized into short, readable paragraphs; separated by newlines (not blank ones) and starting with an uppercase letter. Use inline code syntax (
like_this) to refer to identifiers, paths, constants, or symbols. Use Markdown's unordered lists when listing examples, behaviors, or consequences. - 🧠 Document rationale and tradeoffs Clearly state the reasoning behind the change. When applicable, mention tradeoffs, rejected alternatives, and known limitations of the solution.
Compliance details - omission
Implies the blank line separating "<body>-<footer>" SHOULD be omitted.
The footer contains structured metadata, usually meant to be parsed by external tooling.
It MUST follow these rules:
- 🏷️ Use standardized key-value tags
Each tag appears on a new line in the format:
<key>: <value>⚠️ Warning
While is NOT RECOMMENDED to use multiline values, what follows the colon (:), and lines indented under a tag MUST be treated as a unique value - 📌 Commonly used tags include:
Fixes: #N─ references the issue or bug being resolved
Co-authored-by:─ attributes co-authorship
Reviewed-by:─ acknowledges peer review
Signed-off-by:─ affirms compliance with the Developer Certificate of Origin (DCO)
Follow-up:─ indicates work or changes that this commit is preparing for
Breaking:─ describes breaking changes introduced by the commit
Last-safe-commit:─ identifies the last known safe commit before a critical issue
Important
Future plans:
- Regulating merges
- Provide regexes for parsing this commit format
- Provide customizable git hooks and CI actions to "enforce" this policy in your project
- A customization form that will easily let users pick and communicate their choices about customization