🪨 Cliff TOML

Cliff TOML is the configuration format for git-cliff, a changelog generator. Dr. Jekyll includes a custom Rouge lexer that understands the full cliff.toml structure: TOML sections and key-value pairs, embedded Tera templates in triple-quoted strings, regex patterns, and capture-group replacement syntax.

Table of Contents
  1. How to Use
  2. Section Headers
  3. Key-Value Pairs
  4. Tera Template Strings
  5. Regex Fields
  6. Replace Fields
  7. Full Example
  8. References

How to Use

Use the cliff language tag on a fenced code block:

```cliff
[changelog]
header = """
# Changelog
"""
```

The alias cliff-toml is also accepted.


Section Headers

Sections use TOML’s [table] and [[array-of-tables]] syntax and are highlighted as named anchors:

```cliff
[changelog]

[[git.commit_parsers]]
```
[changelog]

[[git.commit_parsers]]

Key-Value Pairs

Keys and the = separator are highlighted as property names. String, number, and boolean values each receive distinct token types:

```cliff
[git]
conventional_commits = true
filter_unconventional = true
split_commits = false
topo_order = false
sort_commits = "oldest"
tag_pattern = "v[0-9]*"
skip_tags = "v0.1.0-beta.1"
ignore_tags = ""
```
[git]
conventional_commits = true
filter_unconventional = true
split_commits = false
topo_order = false
sort_commits = "oldest"
tag_pattern = "v[0-9]*"
skip_tags = "v0.1.0-beta.1"
ignore_tags = ""

Tera Template Strings

Any triple-quoted string value ("""...""") is treated as an embedded Tera template. Keywords, filters, variables, and delimiters are all highlighted within the template body:

```cliff
[changelog]
body = """
{% if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}
## [unreleased]
{% endif %}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{{ commit.message | upper_first }}
{% endfor %}
{% endfor %}
"""
```

[changelog]
body = """
{% if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}
## [unreleased]
{% endif %}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{{ commit.message | upper_first }}
{% endfor %}
{% endfor %}
"""


Regex Fields

The keys pattern, message, body, footer, and tag_pattern receive regex highlighting — metacharacters (( ) { } [ ] | ^ $ . * + ?) are styled distinctly from literal text:

```cliff
[git]
tag_pattern = "v[0-9]*"

[[git.commit_parsers]]
message = "^feat"
group = "Features"

[[git.commit_parsers]]
message = "^fix"
group = "Bug Fixes"
```
[git]
tag_pattern = "v[0-9]*"

[[git.commit_parsers]]
message = "^feat"
group = "Features"

[[git.commit_parsers]]
message = "^fix"
group = "Bug Fixes"

Replace Fields

The keys replace and href support capture-group back-references ($1, ${2}), which are highlighted as variables. These fields commonly appear inside inline-table arrays:

```cliff
[changelog]
postprocessors = [
  { pattern = '<REMOTE_URL>', replace = "https://github.com" },
  { pattern = '#\d+', replace = '' },
  { pattern = '!#!(\d+)', replace = '#$1' },
]

[git]
link_parsers = [
  { pattern = '#(\d+)', text = '!#!$1', href = "<REPO>/issues/$1" },
  { pattern = 'RFC\(?(\d+)\)?', text = "ietf-rfc$1", href = "https://datatracker.ietf.org/doc/html/rfc$1" },
]
```
[changelog]
postprocessors = [
  { pattern = '<REMOTE_URL>', replace = "https://github.com" },
  { pattern = '#\d+', replace = '' },
  { pattern = '!#!(\d+)', replace = '#$1' },
]

[git]
link_parsers = [
  { pattern = '#(\d+)', text = '!#!$1', href = "<REPO>/issues/$1" },
  { pattern = 'RFC\(?(\d+)\)?', text = "ietf-rfc$1", href = "https://datatracker.ietf.org/doc/html/rfc$1" },
]

Full Example

```cliff
# git-cliff configuration

[remote.github]
owner = "owner"
repo = "repo"

[changelog]
body = """
{#- MACROS -#}
{%- macro remote_url() -%}
  {{ "<REMOTE_URL>/" ~ remote.github.owner ~ "/" ~ remote.github.repo -}}
{%- endmacro -%}
{#- MACROS END -#}

{%- if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{%- else %}
## [unreleased]
{%- endif %}

{%- for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{%- for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
  {{ commit.message | upper_first }}
{%- endfor %}
{%- endfor %}
"""
trim = true

postprocessors = [
  { pattern = '<REMOTE_URL>', replace = "https://github.com" },
  { pattern = '#\d+', replace = '' },
  { pattern = '!#!(\d+)', replace = '#$1' },
]

[git]
conventional_commits = true
filter_unconventional = true
split_commits = true
protect_breaking_commits = false
filter_commits = false
topo_order = false
sort_commits = "oldest"
tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+$"

commit_parsers = [
  { message = '(?i)^.*!:', group = "💥 Breaking Change" },
  { message = '(?i)^feat', group = "🚀 Features" },
  { message = '(?i)^fix', group = "🐛 Bug Fixes" },
  { message = '(?i)^docs?', group = "📚 Documentation" },
  { message = '(?i)^chore\(release\): prepare for', skip = true },
  { body = '(?i).*security', group = "🛡️ Security" },
]

commit_preprocessors = [
  { pattern = '(?m)^\s*[\*-]\s*', replace = "" },
]

link_parsers = [
  { pattern = '#(\d+)', text = '!#!$1', href = "<REPO>/issues/$1" },
]
```

# git-cliff configuration

[remote.github]
owner = "owner"
repo = "repo"

[changelog]
body = """
{#- MACROS -#}
{%- macro remote_url() -%}
  {{ "<REMOTE_URL>/" ~ remote.github.owner ~ "/" ~ remote.github.repo -}}
{%- endmacro -%}
{#- MACROS END -#}

{%- if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{%- else %}
## [unreleased]
{%- endif %}

{%- for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{%- for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
  {{ commit.message | upper_first }}
{%- endfor %}
{%- endfor %}
"""
trim = true

postprocessors = [
  { pattern = '<REMOTE_URL>', replace = "https://github.com" },
  { pattern = '#\d+', replace = '' },
  { pattern = '!#!(\d+)', replace = '#$1' },
]

[git]
conventional_commits = true
filter_unconventional = true
split_commits = true
protect_breaking_commits = false
filter_commits = false
topo_order = false
sort_commits = "oldest"
tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+$"

commit_parsers = [
  { message = '(?i)^.*!:', group = "💥 Breaking Change" },
  { message = '(?i)^feat', group = "🚀 Features" },
  { message = '(?i)^fix', group = "🐛 Bug Fixes" },
  { message = '(?i)^docs?', group = "📚 Documentation" },
  { message = '(?i)^chore\(release\): prepare for', skip = true },
  { body = '(?i).*security', group = "🛡️ Security" },
]

commit_preprocessors = [
  { pattern = '(?m)^\s*[\*-]\s*', replace = "" },
]

link_parsers = [
  { pattern = '#(\d+)', text = '!#!$1', href = "<REPO>/issues/$1" },
]


References