Git Commit Conventions
This document defines the git commit message format (Conventional Commits types/scopes), the version-bump rules that follow from it, and how the changelog and releases are generated from that history. Read it before making any commit to this repository.
Conventional Commits
Section titled “Conventional Commits”All commit messages must follow the Conventional Commits specification:
type(scope): descriptionThese six types drive version bumps and commit review; only feat, fix and breaking changes raise the version:
| Type | Description | Version bump |
|---|---|---|
feat |
A new feature or capability | Minor |
fix |
A bug fix | Patch |
refactor |
Code restructuring without behavior change | None |
docs |
Documentation-only changes | None |
chore |
Maintenance, dependencies, tooling | None |
BREAKING CHANGE: or ! |
Incompatible API change | Major |
Scopes
Section titled “Scopes”Scopes identify the area of the codebase affected. Common scopes:
| Scope | Area |
|---|---|
backend |
Backend Python code |
frontend |
Frontend TypeScript/React code |
auth |
Authentication & authorization |
charts |
Charting & data visualization |
ci |
CI/CD pipeline |
security |
Security hardening |
accounts |
Account management |
snapshots |
Snapshot feature |
i18n |
Internationalization |
deps |
Dependency updates |
Scopes are not limited to this list — use a descriptive scope that matches the feature area.
The scope must always be a real feature or module name — never an internal ticket ID, worktree/branch name, or session identifier; put that kind of identifier in the commit body or a trailer instead, if it’s useful there.
Examples
Section titled “Examples”Real examples from project history:
fix(auth): revert SameSite=None to Laxfix(ci): resolve 3 CI failuresfeat(charts): add net worth change waterfall chart- Keep the description in imperative mood (“add”, not “added” or “adds”)
- Do not end the description with a period
- Limit the subject line to 72 characters
- Use the body for additional context (wrapped at 72 chars) when needed
- Reference issues in the footer:
Refs: #123orCloses: #123 - GPG-sign every commit
- Never reference AI/tooling authorship or a session/task identifier in the commit message
- Never run
git tagyourself — see Release Process below
Backend Package Version
Section titled “Backend Package Version”Any commit that adds, removes, or changes behavior in backend/app/routers/*.py
bumps backend/pyproject.toml’s version field in the same commit, using the
same feat=minor/fix=patch/BREAKING=major mapping as the table above — scoped
to the API surface only, so a router change bumps it while a service-layer
refactor or test-only change does not. The same commit must re-export backend/openapi.json and refresh backend/uv.lock (cd backend && uv lock); see Contributing.
This is the backend package version — a separate number from the app-wide release version described in Releases; the two are never conflated.
Changelog Generation
Section titled “Changelog Generation”The project uses git-cliff to generate CHANGELOG.md from conventional commit history.
Configuration
Section titled “Configuration”Configuration lives in cliff.toml at the repository root. It defines:
- Commit parsing rules (type + scope extraction)
- Grouping by commit type
- Sorting and formatting
Changelog entries are grouped into sections (see cliff.toml’s
commit_parsers for the exact match order):
- Features —
featcommits - Bug Fixes —
fixcommits - Refactor —
refactorcommits - Documentation —
doc/docscommits - Performance —
perf/improvementcommits - Styling —
stylecommits - Testing —
testcommits - Miscellaneous Tasks —
build,chore,cicommits - Security —
fix(security)/feat(security)commits, or any commit whose body has asecurity:line - Deprecated —
feat(deprecate)/chore(deprecate)commits - Revert —
revertcommits
This changelog grouping is a separate concern from the version-bump table
above: it’s about which section of CHANGELOG.md a commit lands in, not
whether it bumps backend/pyproject.toml’s version.
A perf/test/style commit gets its own changelog section for readability but bumps nothing
(same as chore/refactor/docs); fix(security) bumps a patch (same as
any other fix) while also being pulled into the Security section.
Generating the Changelog
Section titled “Generating the Changelog”git cliff -o CHANGELOG.md is how the release workflow regenerates
CHANGELOG.md. Contributors never run this themselves and never hand-edit
CHANGELOG.md in a PR — it is auto-generated and any manual edit gets
overwritten.
Release Process
Section titled “Release Process”Contributors do not create git tags — vX.Y.Z tags are cut separately, by
the release process, not by running git tag from a feature branch or PR.
At a high level, once a tag is cut:
- Tag — A semantic version tag
vX.Y.Zis created as part of the release process (not by a contributor commit)X— breaking changesY— new features (backward compatible)Z— bug fixes / patches
- CI builds — Pushing the tag triggers CI to build and publish container images
- Changelog — git-cliff generates the
CHANGELOG.mdentry for the release
See Releases for who/what actually cuts the tag.
Branch Strategy
Section titled “Branch Strategy”main— The integration branch. Always deployable.- Feature branches — Created from
main, named descriptively (e.g.,feat/waterfall-chart,fix/auth-samesite) - Pull requests — All changes merge to
mainvia PR. CI must pass before merge.