This page is a map of Commitizen's subsystems and extension points. It is aimed at contributors (human or AI) who are about to change code and need to know where things live and how they fit together.
For end-user concepts, see the Commands and Configuration sections.
commitizen/
├── cli.py # CLI entry point and argument parsing (uses decli)
├── commands/ # One module per CLI subcommand (commit, bump, changelog, ...)
├── config/ # Configuration discovery, parsing, and base classes
├── providers/ # Version providers (where to read/write the version)
├── changelog_formats/ # Changelog file format handlers (markdown, asciidoc, ...)
├── cz/ # Built-in commit conventions (conventional_commits, jira, customize)
├── version_schemes.py # Version schemes (pep440, semver, semver2)
├── tags.py # Tag format parsing and matching
├── changelog.py # Changelog generation engine
├── bump.py # Version-bump engine
├── defaults.py # Default settings and the Settings TypedDict
├── exceptions.py # CLI-facing exception types and exit codes
├── out.py # Standard output helpers
├── git.py # Git wrapper used by all commands
├── hooks.py # Pre/post bump hook execution
└── templates/ # Built-in Jinja2 templates for changelog rendering
Commitizen is plugin-friendly. Four kinds of extensions can be registered by external packages via Python entry points; the built-in implementations use the same mechanism.
| Kind | Entry-point group | Built-ins registered in pyproject.toml |
Base class / Protocol |
|---|---|---|---|
| Commit convention | commitizen.plugin |
cz_conventional_commits, cz_jira, cz_customize |
commitizen/cz/base.py:BaseCommitizen |
| Version provider | commitizen.provider |
cargo, commitizen, composer, npm, pep621, poetry, scm, uv |
commitizen/providers/base_provider.py:VersionProvider |
| Version scheme | commitizen.scheme |
pep440, semver, semver2 |
commitizen/version_schemes.py:VersionProtocol |
| Changelog format | commitizen.changelog_format |
markdown, asciidoc, textile, restructuredtext |
commitizen/changelog_formats/base.py:BaseFormat |
Each kind is loaded lazily via importlib.metadata.entry_points(...). To add a new built-in implementation you register it in pyproject.toml under the appropriate [project.entry-points."..."] table.
End-user documentation for these extension points lives elsewhere — see Version Provider, Customized Python Class, and Changelog Template. This page focuses on where the source lives and how it is wired together.
Configuration is discovered, parsed, and exposed as a Settings TypedDict.
- Discovery —
commitizen/config/__init__.py:read_cfgsearches the working directory (and the git project root when different) for known config files in a defined order (seecommitizen/defaults.py:CONFIG_FILES). - Format-specific parsing —
commitizen/config/factory.py:create_configdispatches to one of:commitizen/config/toml_config.py:TomlConfig(TOML; includespyproject.tomlunder[tool.commitizen])commitizen/config/json_config.py:JsonConfigcommitizen/config/yaml_config.py:YAMLConfig
- Defaults merge — every parser inherits from
commitizen/config/base_config.py:BaseConfig, which starts fromcommitizen/defaults.py:DEFAULT_SETTINGSand overlays the user values. - Consumption — commands read
config.settings[...]; providers and formats receive the liveBaseConfigso they can react to settings such asencoding,tag_format, andversion_scheme.
The Settings TypedDict in defaults.py is the authoritative list of recognized keys. Adding a new setting almost always means touching this file.
cli.py parses argv with decli, resolves the chosen subcommand to a class under commitizen/commands/, then instantiates and calls it. A typical command:
- Reads
config.settings. - Resolves dependencies (provider, scheme, changelog format) via the
get_*helpers in the respective subpackages. - Does its work, surfacing user-visible text through
commitizen/out.pyand errors throughcommitizen/exceptions.py(each exception carries an exit code defined incommitizen/exceptions.pyand documented in Exit Codes).
cz commit and cz bump are the most stateful commands — they call git through commitizen/git.py, run user-defined pre_bump_hooks/post_bump_hooks via commitizen/hooks.py, and may mutate version files through the active provider.
Changelog rendering uses Jinja2. Built-in templates live under commitizen/templates/. The template loader is a ChoiceLoader whose first loader is FileSystemLoader(".") and whose second loader is provided by the active commit-convention class (default: a PackageLoader for built-in templates), so a repository can override any built-in template by placing a file of the same name at the project root or in the configured template directory.
Tests are organized to mirror the source modules:
| Source | Test |
|---|---|
commitizen/providers/* |
tests/providers/, tests/test_factory.py |
commitizen/changelog_formats/* |
tests/test_changelog_format_*.py, tests/test_changelog_formats.py |
commitizen/version_schemes.py |
tests/test_version_schemes.py, tests/test_version_scheme_*.py |
commitizen/commands/* |
tests/commands/, tests/test_cli/ |
commitizen/config/* |
tests/test_conf.py |
commitizen/bump.py |
tests/test_bump_*.py |
commitizen/changelog.py |
tests/test_changelog.py, tests/test_incremental_build.py |
commitizen/tags.py |
tests/test_tags.py |
When you add or modify a subsystem, the targeted test file is usually obvious from this mirror. The targeted-test map for agents captures the most useful selectors.