---
url: /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
  ```
