commitlint (Agent Skills)

GitHub

📓 Lint commit messages

18,694 stars TypeScript 1 Rule Files Full Docs MCP View JSON API #commit#conventions#git#lint

docs/reference/rules.md

# Rules

## body-case

- **condition**: `body` is in case `value`
- **rule**: `always`
- **value**

  ```text
  'lower-case'
  ```

- **possible values**

  ```js
  [
    "lower-case", // default
    "upper-case", // UPPERCASE
    "camel-case", // camelCase
    "kebab-case", // kebab-case
    "pascal-case", // PascalCase
    "sentence-case", // Sentence case
    "snake-case", // snake_case
    "start-case", // Start Case
  ];
  ```

## body-empty

- **condition**: `body` is empty
- **rule**: `never`

## body-full-stop

- **condition**: `body` ends with `value`
- **rule**: `never`
- **value**

  ```text
  '.'
  ```

## body-leading-blank

- **condition**: `body` begins with blank line
- **rule**: `always`

## body-max-length

- **condition**: `body` has `value` or less characters
- **rule**: `always`
- **value**

  ```text
  Infinity
  ```

## body-max-line-length

- **condition**: `body` lines have `value` or less characters, or contain a URL
- **rule**: `always`
- **value**

  ```text
  Infinity
  ```

## body-min-length

- **condition**: `body` has `value` or more characters
- **rule**: `always`
- **value**

  ```text
  0
  ```

## breaking-change-exclamation-mark

- **condition**: Either both or neither `header` has an exclamation mark before the `:` marker
  and a line in `footer` matches the regular expression `^BREAKING[ -]CHANGE:`
- **rule**: `always`

> [!NOTE]
>
> This rule enforces that breaking changes are marked by both a `!` in the header
> and `BREAKING CHANGE` in the footer. The behavior is that of an XNOR operation:
>
> - It passes when either both are present or both are not.
> - It fails when one is present and the other is not.

## footer-empty

- **condition**: `footer` is empty
- **rule**: `never`

## footer-leading-blank

- **condition**: `footer` begins with blank line
- **rule**: `always`

## footer-max-length

- **condition**: `footer` has `value` or less characters
- **rule**: `always`
- **value**

  ```text
  Infinity
  ```

## footer-max-line-length

- **condition**: `footer` lines have `value` or less characters
- **rule**: `always`
- **value**

  ```text
  Infinity
  ```

## footer-min-length

- **condition**: `footer` has `value` or more characters
- **rule**: `always`
- **value**

  ```text
  0
  ```

## header-case

- **condition**: `header` is in case `value`
- **rule**: `always`
- **value**

  ```text
  'lower-case'
  ```

- **possible values**

  ```js
  [
    "lower-case", // default
    "upper-case", // UPPERCASE
    "camel-case", // camelCase
    "kebab-case", // kebab-case
    "pascal-case", // PascalCase
    "sentence-case", // Sentence case
    "snake-case", // snake_case
    "start-case", // Start Case
  ];
  ```

## header-full-stop

- **condition**: `header` ends with `value`
- **rule**: `never`
- **value**

  ```text
  '.'
  ```

## header-max-length

- **condition**: `header` has `value` or less characters
- **rule**: `always`
- **value**

  ```text
  72
  ```

## header-min-length

- **condition**: `header` has `value` or more characters
- **rule**: `always`
- **value**

  ```text
  0
  ```

## header-trim

- **condition**: `header` must not have initial or trailing whitespaces
- **rule**: `always`

## references-empty

- **condition**: `references` has at least one entry
- **rule**: `never`

## scope-case

- **condition**: `scope` is in case `value`
- **rule**: `always`
- **value**

  ```text
  'lower-case'
  ```

- **possible values**

  ```js
  [
    "lower-case", // default
    "upper-case", // UPPERCASE
    "camel-case", // camelCase
    "kebab-case", // kebab-case
    "pascal-case", // PascalCase
    "sentence-case", // Sentence case
    "snake-case", // snake_case
    "start-case", // Start Case
  ];
  ```

- extended value (object based)

  ```js
  {
    cases: ["kebab-case"],
    delimiters: ["/"]
  }
  ```

  - `cases` — list of allowed case formats
  - `delimiters` — optional list of delimiter strings used to split multi-segment scopes (default: `["/", "\", ","]`)

## scope-delimiter-style

- **condition**: all delimiters found in `scope` must match `value`
- **rule**: `always`
- **value**

  ```text
    ["/", "\", ","]
  ```

> [!NOTE]
>
> - When using this rule together with [scope-enum](#scope-enum) or [scope-case](#scope-case), make sure to provide the same `delimiters` configuration in those rules as well. Otherwise scope parsing may become inconsistent.

## scope-empty

- **condition**: `scope` is empty
- **rule**: `never`

## scope-enum

- **condition**: `scope` is found in value
- **rule**: `always`
- **value**

  ```text
  []
  ```

- extended value (object based)

  ```js
  {
    scopes: ["foo", "bar"],
    delimiters: ["/"]
  }
  ```

  - `scopes` — list of allowed scope values
  - `delimiters` — optional list of delimiter strings used to split multi-segment scopes (default: `["/", "\", ","]`)

> [!NOTE]
>
> - This rule always passes if no scopes are provided in the message or the value > is an empty array.
> - When set to `always`, all message scopes must be found in the value.
> - When set to `never`, none of the message scopes can be found in the value.

## scope-max-length

- **condition**: `scope` has `value` or less characters
- **rule**: `always`
- **value**

  ```text
  Infinity
  ```

## scope-min-length

- **condition**: `scope` has `value` or more characters
- **rule**: `always`
- **value**

  ```text
  0
  ```

## signed-off-by

- **condition**: `message` has `value`
- **rule**: `always`
- **value**

  ```text
  'Signed-off-by:'
  ```

## subject-case

- **condition**: `subject` is in case `value`
- **rule**: `never`
- **value**

  ```js
  ["sentence-case", "start-case", "pascal-case", "upper-case"];
  ```

- **possible values**

  ```js
  [
    "lower-case", // lower case
    "upper-case", // UPPERCASE
    "camel-case", // camelCase
    "kebab-case", // kebab-case
    "pascal-case", // PascalCase
    "sentence-case", // Sentence case
    "snake-case", // snake_case
    "start-case", // Start Case
  ];
  ```

## subject-empty

- **condition**: `subject` is empty
- **rule**: `never`

## subject-exclamation-mark

- **condition**: `subject` has exclamation before the `:` marker
- **rule**: `never`

## subject-full-stop

- **condition**: `subject` ends with `value`
- **rule**: `never`
- **value**

  ```text
  '.'
  ```

## subject-max-length

- **condition**: `subject` has `value` or less characters
- **rule**: `always`
- **value**

  ```text
  Infinity
  ```

## subject-min-length

- **condition**: `subject` has `value` or more characters
- **rule**: `always`
- **value**

  ```text
  0
  ```

## trailer-exists

- **condition**: `message` has trailer `value`
- **rule**: `always`
- **value**

  ```text
  'Signed-off-by:'
  ```

## type-case

- **description**: `type` is in case `value`
- **rule**: `always`
- **value**

  ```text
  'lower-case'
  ```

- **possible values**

  ```js
  [
    "lower-case", // default
    "upper-case", // UPPERCASE
    "camel-case", // camelCase
    "kebab-case", // kebab-case
    "pascal-case", // PascalCase
    "sentence-case", // Sentence case
    "snake-case", // snake_case
    "start-case", // Start Case
  ];
  ```

## type-empty

- **condition**: `type` is empty
- **rule**: `never`

## type-enum

- **condition**: `type` is found in value
- **rule**: `always`
- **value**

  ```js
  ["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"];
  ```

## type-max-length

- **condition**: `type` has `value` or less characters
- **rule**: `always`
- **value**

  ```text
  Infinity
  ```

## type-min-length

- **condition**: `type` has `value` or more characters
- **rule**: `always`
- **value**

  ```text
  0
  ```