Skip to content

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:

git tag v7.0.0rc1
git push --tags

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:

git tag v7.0.0
git push --tags

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).