Cremind
Contributing & Maintenance

Versioning

The single source of truth in app/__version__.py, how it flows to PyPI, npm, and Docker, the PEP 440 vs SemVer forms, and the three release channels.

Cremind has one version number that every artifact carries. This page covers where it lives, how it propagates, the tag conventions, and the three release channels.

The single source of truth

app/__version__.py's __version__ field is the single source of truth. Cremind is currently at 0.0.1.

__version__ = "0.0.1"
MIN_SUPPORTED_UPGRADE_FROM = "0.0.0"

Everything else derives from this one field:

  • pyproject.toml reads it via [tool.hatch.version] path = "app/__version__.py".
  • The runtime /version endpoint, the cremind version CLI, and the upgrader all read it.
  • ui/package.json is regenerated by scripts/sync_ui_version.py, wired into the predev / prebuild / preweb:dev / preweb:build npm hooks. Never edit ui/package.json's version by hand — it gets overwritten.

During an RC build, release-rc.yml rewrites app/__version__.py in-CI only to the PEP 440 dev form (the RC tag with the leading v stripped). The rewrite is never committed. The production workflow uses the value exactly as committed on main, which is why a production tag can't ship until the Core Maintainer commits the bump. See Releasing.

MIN_SUPPORTED_UPGRADE_FROM

MIN_SUPPORTED_UPGRADE_FROM in the same file is the oldest version this build knows how to migrate from. The upgrader refuses to proceed when the live install is older. It's currently 0.0.0, which accepts any install.

Bump it only when explicitly dropping support — that is, when a schema migration genuinely requires a minimum prior schema version — not on every release. See Schema migrations.

Tag conventions

RC tags carry the PEP 440 canonical form verbatim with a leading v — the same string lands on GitHub, Test PyPI, and Docker Hub (modulo the v). The .dev<M> counter is mandatory.

Tag patternPEP 440npm / installerDocker tagPyPIChannel
v0.0.2rc1.dev10.0.2rc1.dev10.0.2-rc.1.dev.1cremind-desktop:0.0.2rc1.dev1Test PyPItest
v0.0.20.0.20.0.2cremind-desktop:0.0.2 + :latestPyPIproduction

Within a version's slate:

  • rc<N> indexes the PR (rc1 for the first PR, rc2 for the second, …) and is assigned by the Core Maintainer.
  • dev<M> increments per bug-fix iteration on that PR (dev1, dev2, …).

Hotfixes use the four-segment form: v0.0.2.1 (production) built from v0.0.2.1rc<N>.dev<M> (dev release).

One strict, canonical shape

RC tags must match this regex exactly:

^v(\d+\.\d+\.\d+(?:\.\d+)?)rc(\d+)\.dev(\d+)$

The legacy hyphenated form (v<X.Y.Z>-rc.<N>) and the bare v<X.Y.Z>rc<N> without a .dev<M> counter are both rejected — release-rc.yml refuses to publish them, and the in-app updater ignores GitHub prereleases whose tag fails this regex.

PEP 440 vs npm/SemVer

PyPI, GitHub, and Docker Hub use the PEP 440 no-separator form (0.0.2rc1.dev1). npm and electron-builder reject that as a prerelease identifier, so scripts/sync_ui_version.py derives a SemVer form internally (0.0.2-rc.1.dev.1) for ui/package.json. That SemVer string never appears on GitHub, PyPI, or Docker Hub — it exists only inside the UI build.

The three channels

ChannelInstalls fromUsed for
productionPyPI (and cremind-desktop:latest)End users. Stable, tagged vX.Y.Z.
testTest PyPIValidating a dev release before merge — see Releasing.
devYour local checkout (pip install -e .)Iterating on installer scripts or the Docker bundle — see Dev-channel install.

Production installs poll for updates and pick up the highest stable version; test installs pick up the highest dev wheel from Test PyPI; dev installs don't auto-upgrade at all (you pull from git).

Next

On this page