devtools: Add commitlint to pre-commit.
What changed, and why it matters
This change adds an automated commit-message style checker to the project's development workflow. It does not modify any payment, network, or cryptographic code, and there is no security relevance.
No security action needed. This is a routine developer-experience/tooling change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit introduces a pre-commit hook using commitlint-pre-commit-hook v9.23.0 and a custom commitlint.config.js that enforces Core Lightning-specific commit message types. It only affects the commit-msg stage and enforces formatting rules; it does not change runtime behavior, build outputs, or any security-sensitive logic.
Changed components
.pre-commit-config.yamlcommitlint.config.jsInspect captured patch +62 / −0
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 497750a0..2db847f3 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -67,6 +67,12 @@ repos:
exclude: ccan|contrib|tests/fuzz/corpora
stages: [ manual ]
+- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
+ rev: v9.23.0
+ hooks:
+ - id: commitlint
+ stages: [commit-msg]
+
- repo: local
hooks:
# Reimplementation of `make check-amount-access` for pygrep.
diff --git a/commitlint.config.js b/commitlint.config.js
new file mode 100644
index 00000000..f156abd3
--- /dev/null
+++ b/commitlint.config.js
@@ -0,0 +1,56 @@
+module.exports = {
+
+ plugins: [
+ {
+ rules: {
+ 'core-lightning': ({ type }) => {
+ // Allow standard Core Lightning types
+ const standardTypes = [
+ // Daemons
+ 'channeld', 'closingd', 'connectd', 'gossipd', 'hsmd', 'lightningd', 'onchaind',
+ 'openingd',
+ // Related
+ 'bitcoin', 'cli', 'cln-grpc', 'cln-rpc', 'db', 'wallet', 'wire',
+ // Others
+ 'ci', 'common', 'contrib', 'devtools', 'docs', 'docker', 'github', 'global',
+ 'meta', 'nit', 'nix', 'release', 'script', 'tests',
+ ];
+
+ // Extensions
+ const extensions = ['plugin-', 'pyln-', 'tool-']
+ if (type) {
+ for (const prefix of extensions) {
+ if (type.startsWith(prefix)) {
+ return [true];
+ }
+ }
+ }
+
+ // Otherwise, must be a standard type
+ if (standardTypes.includes(type)) {
+ return [true];
+ }
+
+ return [
+ false,
+ `Type must be one of [${standardTypes.join(', ')}] or match patterns [${extensions.join(', ')}]`
+ ];
+ },
+ },
+ },
+ ],
+
+ rules: {
+ // Disable the default type-enum rule since we're using custom validation
+ 'type-enum': [0],
+
+ // Enable our custom rule
+ 'core-lightning': [2, 'always'],
+
+ // Keep other standard rules
+ 'type-case': [2, 'always', 'lower-case'],
+ 'type-empty': [2, 'never'],
+ 'subject-empty': [2, 'never'],
+ 'subject-case': [2, 'never', ['upper-case']],
+ },
+};
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.