Skip to content

Use Commitlint's conventional configuration

Status

Accepted

Context

EOS requires consistent local and CI validation of conventional commit messages. The same policy must validate local commit-message files, pull-request titles used for squash merges, and newly introduced commits reported by CI on main.

EOS already uses Lefthook to manage repository-provided Git hooks and GitHub Actions for CI. The remaining tooling choice must balance predictable behavior, actionable diagnostics, maintenance cost, commit-time performance, and compatibility with the existing Node.js and pnpm toolchain.

Conventional Commits 1.0.0 defines a flexible base convention. Commitlint’s maintained @commitlint/config-conventional preset narrows that convention with a fixed type list, lowercase and subject-style rules, 100-character limits, and default ignored-message behavior. Adopting the preset unchanged trades literal specification coverage for a maintained policy that does not require EOS to design and support custom lint rules.

Decision Drivers

  • No EOS-owned Commitlint rules or plugins.
  • One validation result for the same message in local hooks and CI.
  • Maintained, documented defaults with actionable diagnostics.
  • Support for commit-message files, standard input, and Git commit ranges.
  • Validation completes within the PRD’s one-second local latency target.
  • Compatibility with the existing pnpm, Node.js, Lefthook, and GitHub Actions toolchain.
  • Pinned dependency resolution and explicit review of preset upgrades.
  • Minimal third-party GitHub Action and supply-chain surface.

Considered Options

Commitlint with @commitlint/config-conventional

Use @commitlint/cli and extend the conventional preset without custom rules, plugins, parser overrides, formatters, or ignore overrides. Lefthook passes the commit-message file to the CLI, and GitHub Actions uses the same CLI and configuration for pull-request titles and commit ranges.

The preset provides a maintained, recognizable policy with standard diagnostics. EOS accepts its additional type, casing, subject, and line-length constraints and its default ignored messages as part of that policy.

Commitlint with EOS-owned configuration and rules

Use Commitlint as the framework but define EOS-owned rules and a local plugin to match only the machine-verifiable Conventional Commits 1.0.0 syntax.

This gives EOS tighter specification fidelity but makes the repository responsible for rule design, diagnostics, parser edge cases, and compatibility through Commitlint upgrades. It conflicts with the requirement not to maintain custom Commitlint rules.

Conventional Commits reference parser with an EOS-owned CLI

Use @conventional-commits/parser and build EOS-owned validation, diagnostics, Git-range loading, and command-line behavior around its syntax tree.

This avoids custom Commitlint rules but replaces them with a larger custom validator. The parser is not a complete linting workflow, and EOS would own more code than with the maintained Commitlint preset.

Separate third-party tools for local and GitHub validation

Use a local commit linter through Lefthook and a purpose-built GitHub Action for pull-request titles or commit ranges.

This can reduce workflow scripting but creates two policy and upgrade surfaces. The tools may accept different messages, and an additional Action expands the workflow supply chain without providing a capability missing from Commitlint’s CLI.

Decision Outcome

EOS will use Commitlint with @commitlint/config-conventional unchanged.

The workspace will add @commitlint/cli and @commitlint/config-conventional as root development dependencies. A root commitlint.config.mjs will extend the preset and declare no custom rules, plugins, parser preset, formatter, or ignore behavior. The committed lockfile will pin the resolved dependency graph.

The existing Lefthook configuration will add a commit-msg command using its documented Commitlint integration to pass the proposed message file to Commitlint. A repository-owned GitHub Actions workflow will invoke the same workspace CLI and configuration for pull-request titles and newly introduced commits on main; EOS will not use a separate commit-validation Action.

Dependency updates to Commitlint or the conventional preset require explicit review because they may change EOS commit-message policy.

This decision extends, rather than replaces, ADR 0005: Lefthook owns local hook installation and execution, while Commitlint owns parsing, policy, and diagnostics.

Consequences

Positive

  • EOS does not maintain custom Commitlint rules, plugins, or parser behavior.
  • Local and CI validation use one executable, preset, and lockfile.
  • Commitlint supplies established file, standard-input, Git-range, formatting, and exit-code behavior.
  • Lefthook and GitHub Actions remain the existing execution boundaries.
  • No additional third-party GitHub Action receives repository event data or expands the workflow supply chain.

Negative

  • The preset rejects some messages allowed by Conventional Commits 1.0.0, including arbitrary types, uppercase types, some subject casing, and lines over 100 characters.
  • Commitlint’s default ignore functions allow some merge, revert, version, automatic-merge, fixup!, and squash! messages without applying the preset rules.
  • Preset upgrades can change EOS policy even when the EOS configuration file is unchanged.
  • CI cannot prevent an invalid direct push from reaching main; it can only report the violation after the push.

Neutral

  • Semantic correctness, such as whether a change is truly a feat or fix, remains an author and reviewer responsibility because syntax tooling cannot infer intent reliably from a message alone.
  • Local Git hooks remain bypassable; required pull-request checks provide the merge boundary for the normal squash workflow.
  • GitHub repository rules and squash-merge settings remain external configuration dependencies.
  • The ADR does not select an interactive commit-message authoring tool; it covers validation only.