Skip to main content

18. Semantic Versioning Strategy

Date: 2025-10-13

Status

Accepted

Category

Development & Tooling

Context

Software projects need a clear, predictable versioning strategy that:
  • Communicates breaking changes to users
  • Manages expectations for upgrades
  • Enables dependency management for downstream consumers
  • Supports multiple release channels (stable, pre-release, nightly)
  • Integrates with CI/CD for automated releases
Without a versioning strategy:
  • Users cannot predict upgrade safety (will it break?)
  • Dependency managers struggle with version constraints
  • Changelogs become ambiguous about impact
  • Release automation becomes inconsistent

Decision

We will adopt Semantic Versioning 2.0.0 (SemVer) with the following conventions:

Version Format

Version Incrementation Rules

MAJOR version (X.0.0)

Increment when making incompatible API changes:
  • Breaking changes to public APIs
  • Removal of deprecated features
  • Major architectural changes
  • Non-backward-compatible configuration changes
Examples:
  • Changing authentication from JWT-only to OAuth2-only
  • Removing InMemoryUserProvider class
  • Changing MCP protocol version (v1 → v2)

MINOR version (x.Y.0)

Increment when adding backward-compatible functionality:
  • New features
  • New optional configuration parameters
  • New API endpoints
  • Performance improvements
  • Internal refactorings (no API impact)
Examples:
  • Adding Keycloak authentication provider
  • Adding Redis session backend
  • New observability features (LangSmith, Prometheus metrics)
  • New deployment targets (Helm, Kustomize)

PATCH version (x.y.Z)

Increment when making backward-compatible bug fixes:
  • Bug fixes
  • Security patches
  • Documentation updates
  • Dependency updates (non-breaking)
  • Test improvements
Examples:
  • Fixing session expiration bug
  • Patching JWT verification vulnerability
  • Updating Pydantic to fix deprecation warnings
  • Correcting documentation typos

Pre-release Versions

Format: X.Y.Z-PRERELEASE.NUMBER Supported pre-release identifiers:
  • alpha: Early development, unstable API
  • beta: Feature complete, testing phase
  • rc: Release candidate, final testing
Examples:

Build Metadata

Format: X.Y.Z+BUILD.INFO Used for CI/CD builds:

Consequences

Positive Consequences

  • Predictable Upgrades: Users know PATCH = safe, MINOR = safe, MAJOR = review required
  • Clear Communication: Breaking changes are immediately visible
  • Dependency Management: Package managers (pip, npm, cargo) work correctly
  • Automated Releases: CI/CD can auto-increment versions based on commit messages
  • Industry Standard: SemVer is widely adopted (npm, Rust, Go, Python)

Negative Consequences

  • Strictness: Requires discipline to follow rules consistently
  • Breaking Change Caution: Major versions are disruptive, may delay necessary changes
  • Tooling Dependency: Requires automation to avoid human error
  • Edge Cases: Some changes are ambiguous (is it MINOR or PATCH?)

Neutral Consequences

  • Version 0.x.x: Pre-1.0 versions have relaxed rules (anything can break)
  • API Surface: Must clearly define “public API” vs internal implementation

Implementation Details

Version Storage

Single Source of Truth: __init__.py is authoritative, pyproject.toml syncs on release

Changelog Format

We use Keep a Changelog format:

Git Tagging Convention

Tag format: v{VERSION} (lowercase ‘v’ prefix)

Automated Version Bumping

Using GitHub Actions .github/workflows/release.yaml:

Dependency Version Constraints

In pyproject.toml, we follow these constraints:
Rationale:
  • >=X.Y.Z: Accept MINOR and PATCH updates
  • <MAJOR+1.0.0: Block next MAJOR version (breaking changes)

Breaking Change Migration

When making MAJOR version increments:
  1. Deprecation Period: Mark features deprecated in MINOR release first
  2. Migration Guide: Provide upgrade documentation
  3. Backward Compatibility: Maintain for 1-2 MINOR releases
  4. Changelog: Clearly list all breaking changes
Example Migration:

Alternatives Considered

1. Calendar Versioning (CalVer)

Description: Version format based on release date (e.g., 2025.10.1) Pros:
  • Easy to understand (date-based)
  • No ambiguity about version age
  • Used by Ubuntu, pip, Twisted
Cons:
  • No semantic meaning (cannot determine breaking changes)
  • Poor dependency management (how to specify constraints?)
  • No pre-release concept
Why Rejected: Cannot communicate breaking changes to users or dependency managers

2. Romantic Versioning

Description: Free-form versioning with creative names (e.g., “Starship”, “Phoenix”) Pros:
  • Marketing-friendly
  • Memorable names
  • Used by macOS (Catalina, Big Sur)
Cons:
  • No ordering (is “Phoenix” newer than “Starship”?)
  • No automation (cannot auto-increment)
  • Poor dependency management
Why Rejected: Not suitable for library/framework projects with programmatic dependencies

3. Simple Integer Versioning

Description: Increment single integer on each release (e.g., 1, 2, 3) Pros:
  • Extremely simple
  • No rules to remember
  • Used by some mobile apps
Cons:
  • No semantic meaning
  • Cannot express breaking changes
  • Poor for libraries (users cannot specify safety constraints)
Why Rejected: Insufficient for production software with API contracts

4. Major.Minor Only (No PATCH)

Description: Only use MAJOR and MINOR versions (e.g., 2.3, 2.4) Pros:
  • Simpler (fewer decisions)
  • Used by some projects
Cons:
  • No distinction between features and bug fixes
  • Forces MINOR bump for security patches (confusing)
  • Less granular for dependency constraints
Why Rejected: PATCH version is valuable for communicating low-risk updates

Integration Points

Deployment Automation

Kubernetes/Helm: Version tags trigger Docker image builds
LangGraph Platform: Deploy specific versions

Documentation

README.md: Display current version badge
API Documentation: Version appears in OpenAPI spec

Health Endpoint

Version History

Future Enhancements

  • Automated version bumping from commit messages (Conventional Commits)
  • Changelog generation from Git history
  • Deprecation warnings in code (logged when deprecated features used)
  • Version compatibility matrix for LLM providers, Python versions, deployment platforms

References