diff --git a/cliff.toml b/cliff.toml
new file mode 100644
index 0000000..3b38c0a
--- /dev/null
+++ b/cliff.toml
@@ -0,0 +1,121 @@
+# configuration file for git-cliff (0.1.0)
+
+[changelog]
+# changelog header
+header = """
+# Yary Changelog\n
+"""
+# template for the changelog body
+# https://tera.netlify.app/docs/#introduction
+body = """
+{%- set github = "https://github.com/dolysis/yary" -%}
+{%- set has_breaking = commits | filter(attribute="breaking", value=true) | length > 0 -%}
+{% if version %}\
+ ## [{{ version }} - {{ timestamp | date(format="%Y-%m-%d") }}]({{ github ~ "/releases/tag/" ~ version }})
+{% else %}\
+ ## Unreleased
+{% endif %}\
+{% if previous %}\
+ {% if previous.commit_id %}
+ [{{ previous.version }}..{{ version | default(value="HEAD") }}]\
+ ({{ github ~ "/compare/" ~ previous.commit_id ~ ".." ~ commit_id }})\
+ {% endif %}\
+{% endif %}\
+{% if has_breaking %}
+### BREAKING CHANGES ({{ version | default(value="Unreleased") }})
+{% for group, commits in commits | filter(attribute="breaking", value=true) | group_by(attribute="group") %}
+ #### {{ group | upper_first }}
+ {% for commit in commits %}
+ - {{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ github ~ "/commit/" ~ commit.id }}))\
+ {% if commit.scope %}{{ " " ~ commit.scope ~ "" | safe }}{% endif %}\
+ {% if commit.breaking_description != commit.message %}\
+ {{ "\n" }} > {{ commit.breaking_description | replace(from="\n", to=" ") }}\
+ {% endif %}\
+ {% endfor %}
+{% endfor %}
+{%- endif -%}
+{% for group, commits in commits | filter(attribute="breaking", value=false) | group_by(attribute="group") %}
+ ### {{ group | upper_first }}
+ {% for commit in commits %}
+ - {{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ github ~ "/commit/" ~ commit.id }}))\
+ {% if commit.scope %}{{ " " ~ commit.scope ~ "" | safe }}{% endif %}\
+ {% endfor %}
+{% endfor %}\n
+"""
+# remove the leading and trailing whitespace from the template
+trim = true
+# changelog footer
+footer = """
+
+"""
+
+[git]
+# parse the commits based on https://www.conventionalcommits.org
+conventional_commits = true
+# filter out the commits that are not conventional
+filter_unconventional = false
+# regex for parsing and grouping commits
+commit_parsers = [
+ # CI/CD (.github/)
+ { message = "^ci/", group = "CI/CD", default_scope = "ci" },
+ { message = "^ci:", group = "CI/CD", default_scope = "ci" },
+ { message = "^cd/", group = "CI/CD", default_scope = "cd" },
+ { message = "^cd:", group = "CI/CD", default_scope = "cd" },
+
+ # Misc. repo tasks
+ { message = "^chores?", group = "Chores" },
+ { message = "^build", group = "Build" },
+ { message = "^style", group = "Style" },
+
+ # Documentation (docs/)
+ { message = "^doc", group = "Documentation" },
+
+ # src/event
+ { message = "^lib/event", group = "Lib.Event" },
+ { message = "^event/", group = "Lib.Event" },
+ { message = "^event/parser", group = "Lib.Event", default_scope = "parser" },
+
+ # src/reader
+ { message = "^lib/reader", group = "Lib.Reader" },
+ { message = "^reader/", group = "Lib.Reader" },
+ { message = "^reader:", group = "Lib.Reader" },
+ { message = "^reader/borrow", default_scope = "borrow" },
+ { message = "^reader/owned", default_scope = "owned" },
+
+ # src/scanner
+ { message = "^lib/scanner", group = "Lib.Scanner" },
+ { message = "^scanner/", group = "Lib.Scanner" },
+ { message = "^scanner:", group = "Lib.Scanner" },
+ { message = "^scalar/", group = "Lib.Scanner", default_scope = "scalar" },
+ { message = "^scalar:", group = "Lib.Scanner", default_scope = "scalar" },
+
+ # src/token
+ { message = "^lib/token", group = "Lib.Token" },
+ { message = "^token/", group = "Lib.Token" },
+ { message = "^token:", group = "Lib.Token" },
+
+ # src/error
+ { message = "^lib/error", group = "Lib.Error" },
+ { message = "^error/", group = "Lib.Error" },
+
+ # src/queue
+ { message = "^lib/queue", group = "Lib.Queue" },
+ { message = "^queue/", group = "Lib.Queue" },
+
+ # Catch alls, should be close to/at the bottom
+ { message = "^lib", group = "Lib" },
+ { message = "^[^/]+/error:", default_scope = "error" },
+ { message = "^[^:]+: .*tests?.*", default_scope = "tests" },
+]
+# filter out the commits that are not matched by commit parsers
+filter_commits = false
+# glob pattern for matching git tags
+tag_pattern = "v[0-9]*"
+# regex for skipping tags
+skip_tags = ""
+# regex for ignoring tags
+ignore_tags = '''v[0-9]\.[0-9]\.[0-9]-.*'''
+# sort the tags chronologically
+date_order = false
+# sort the commits inside sections by oldest/newest order
+sort_commits = "newest"