Versioning¶
Background¶
Before unified versioning, ACEX published eight packages independently, each with its own version:
| Package | PyPI name | Pre-unification version |
|---|---|---|
| backend | acex |
6.7.0 |
| client | acex-client |
4.8.0 |
| devkit | acex-devkit |
2.4.0 |
| cli | acex-cli |
4.5.0 |
| mcp | acex-mcp-server |
1.1.0 |
| worker | acex-worker |
0.2.0 |
| cisco_ios_cli | acex-driver-cisco-ioscli |
2.7.0 |
| juniper_junos_cli | acex-driver-juniper-junoscli |
1.0.3 |
The numbers don't reflect meaningful differences between packages — they drifted because version bumps happened manually and reactively. backend and devkit almost always moved together, client followed backend, drivers moved on their own schedule. A commit from 2024 captures the problem well:
"Bump version for devkit and collection-agent as code has changed but the last made changes have not been pushed to each package a bump of version is needed to get latest code pushed to each package"
The consequences: no single "ACEX 1.4.0" to talk about, eight version numbers that say nothing about cross-package compatibility, and bumps frequently forgotten until something breaks on PyPI.
How we version¶
All packages ship under a single version derived from a Git tag. To cut a release:
CI picks up the tag, builds every package with poetry-dynamic-versioning, and publishes them all to PyPI as 7.0.0rc1. No pyproject.toml edits, no version bump commits.
When staging passes, push the stable tag:
CI publishes the stable packages and builds the production agent Docker images.
How it works¶
poetry-dynamic-versioning is a Poetry build backend plugin. Every pyproject.toml carries a placeholder version ("0.0.0"); at build time the plugin calls git describe --tags and injects the version from the nearest tag.
[tool.poetry]
version = "0.0.0" # resolved from git tag at build time
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
build-backend = "poetry_dynamic_versioning.backend"
[tool.poetry-dynamic-versioning]
enable = true
vcs = "git"
style = "pep440"
Driver versioning¶
Drivers (cisco_ios_cli, juniper_junos_cli) occasionally need fixes that don't touch the backend at all. With unified versioning, a driver fix still increments the version for all packages.
We accept this trade-off. Driver fixes were almost always paired with backend or devkit changes anyway, and one clean version number across the stack is worth the occasional over-release of an unchanged package.
If we ever need driver-specific cadence, poetry-dynamic-versioning supports per-package tag prefixes (e.g., cisco-ios-cli/v2.8.0). That's a future option and doesn't affect the core workflow.
Starting version¶
We started at v7.0.0 — a clean break, well above all the old per-package numbers. First release under the new scheme was v7.0.0rc1 (RC) followed by v7.0.0 (stable).