Skip to content

Releasing Victor

Guide for maintainers on creating and publishing Victor releases.

Table of Contents

Release Process Overview

The release-train diagram separates dependency readiness from tag-triggered publication.
Victor depends directly on Sandhi and optionally on ProximaDB; there is no automatic
Sandhi → ProximaDB → Victor trigger. Victor AI and contracts have independent version trains.
Use the promotion procedure for branch and tag placement:

---
title: Independent release trains and promotion
---
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#E8EFF7","primaryTextColor":"#17324D","primaryBorderColor":"#456987","lineColor":"#456987","fontFamily":"Arial"}}}%%
flowchart TB
  S["sandhi-gateway release availability"]
  P["ProximaDB release availability"]
  READY["Verify Victor dependency pins"]
  DEV["develop<br/>version sync and validation"]
  PR["Promotion PR<br/>develop → main"]
  MAIN["main promotion merge commit"]
  TAG["vX.Y.Z tag"]
  AI["release.yml"]
  PY["PyPI<br/>victor-ai and native distributions"]
  GH["GitHub Release<br/>checksums and built artifacts"]
  DOCKER["Docker publication"]
  SDK["Independent contracts version"]
  SDKTAG["sdk-vX.Y.Z tag"]
  SDKWF["release-contracts.yml"]
  SDKPY["PyPI · victor-contracts"]
  S -->|"required dependency"| READY
  P -->|"optional extra dependency"| READY
  READY -.->|"release readiness"| DEV
  DEV -->|"open reviewed promotion"| PR
  PR -->|"merge after promotion battery"| MAIN
  MAIN -->|"tag release commit"| TAG
  TAG -->|"trigger"| AI
  AI -->|"build, verify and publish"| PY
  AI -->|"assemble release assets"| GH
  AI -->|"publish image"| DOCKER
  SDK -->|"tag SDK release"| SDKTAG
  SDKTAG -->|"trigger"| SDKWF
  SDKWF -->|"test, build and publish"| SDKPY

Pre-Release Checklist

Before creating a release, ensure:

  • All tests pass: make test
  • Linting passes: make lint
  • Documentation is updated
  • CHANGELOG.md is updated (if applicable)
  • Deprecation inventory is updated for any new or removed compatibility surfaces
  • Release notes/changelog include replacement path, target removal version/date, and shim status for every deprecation touched in the release
  • If the release changes first-party vertical packaging, the authoritative package, bundled-shim status, and earliest removal milestone are called out explicitly
  • If the release publishes or updates an extracted first-party vertical, package versions remain aligned with the Victor suite version for that release
  • Clean-environment install/discovery smoke tests pass for every extracted vertical touched by the release
  • Version in pyproject.toml is correct
  • All PRs for this release are merged
  • Dependencies are up to date

Version Numbering

We follow Semantic Versioning:

  • MAJOR.MINOR.PATCH (e.g., 1.2.3)
  • Pre-release: 1.0.0-alpha, 1.0.0-beta, 1.0.0-rc.1
Change Type Version Bump Example
Breaking changes MAJOR 0.1.0 → 1.0.0
New features (backward compatible) MINOR 0.1.0 → 0.2.0
Bug fixes PATCH 0.1.0 → 0.1.1
Pre-release Suffix 0.2.0-beta

Extracted Vertical Release Rules

When a release touches first-party extracted vertical packages:

  • use the canonical package identities from
    docs/development/vertical-package-naming-ownership-versioning-policy-2026-03-12.md
  • treat extracted first-party vertical packages as lockstep-versioned with the
    Victor suite for that release
  • treat bundled contrib copies as compatibility shims only once a vertical flips
  • do not remove bundled shims until the retirement policy in
    docs/development/bundled-vertical-shim-retirement-milestones-2026-03-12.md
    is satisfied

Release notes should always state:

  • which package is authoritative
  • whether a bundled shim still exists
  • the earliest removal version/date for that shim
  • the install/upgrade command users should follow

Creating a Release

# 1. Ensure you're on main branch with latest changes
git checkout main
git pull origin main

# 2. Run tests
make test
make lint

# 3. Create the release (updates version, commits, tags)
make release VERSION=0.2.0

# 4. Push to trigger automated release
git push origin main
git push origin --tags

Manual Steps

# 1. Update version in pyproject.toml
sed -i 's/version = ".*"/version = "0.2.0"/' pyproject.toml

# 2. Commit the version change
git add pyproject.toml
git commit -m "Release v0.2.0"

# 3. Create annotated tag
git tag -a "v0.2.0" -m "Release v0.2.0"

# 4. Push changes and tag
git push origin main
git push origin v0.2.0

Automated Release Pipeline

When a tag matching v* is pushed, GitHub Actions automatically:

1. Runs Tests

  • Unit tests on Python 3.12 and 3.13
  • Linting with ruff and black
  • Type checking with mypy

2. Builds Artifacts

Python Package:
- Source distribution (.tar.gz)
- Wheel (.whl)

Standalone Binaries:
- victor-macos-arm64.tar.gz
- victor-linux-x64.tar.gz
- (victor-linux-arm64.tar.gz — pending sandhi-gateway publishing a
manylinux-aarch64 wheel; the pinned exact version cannot install there yet)
- victor-windows-x64.zip

Each artifact is smoke-tested in CI (cold/warm --version, --help, size
tripwire) before it reaches the release.

Docker Images:
- vjsingh1984/victor-ai:<version>
- vjsingh1984/victor-ai:latest

3. Publishes to Distribution Channels

  • PyPI: Automatic via trusted publishing (OIDC, no token needed)
  • uv: uv tool install --python 3.12 victor-ai (recommended CLI path;
    resolves straight from PyPI — no separate channel)
  • GitHub Releases: Creates release with artifacts and checksums
  • Docker Hub: Pushes images to vjsingh1984/victor-ai
  • Homebrew: Auto-updates via PyPI polling (every 6 hours)

Release-engineering checklist addition: verify the uv path against the
TestPyPI rehearsal before a stable tag
(uv tool install --python 3.12 --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ victor-ai==<version> && victor --version).

Required Secrets

Configure these in GitHub repository settings:

Secret Purpose
DOCKERHUB_USERNAME Docker Hub username (vjsingh1984)
DOCKERHUB_TOKEN Docker Hub access token

Notes:
- PyPI uses trusted publishing (OIDC, no token needed)
- Homebrew tap uses PyPI polling (no cross-repo token needed)

Manual Release Steps

If automated release fails, follow these manual steps:

Publish to PyPI

# Build packages
pip install build twine
python -m build

# Check packages
twine check dist/*

# Upload to PyPI
twine upload dist/*

Build Binaries

# Install build dependencies
pip install -e ./victor-contracts -e ".[build]"

# Build for current platform
python scripts/build_binary.py --onefile

# Output in dist/
ls dist/

Build and Push Docker

# Build
docker build -t vjsingh1984/victor-ai:0.2.3 .
docker tag vjsingh1984/victor-ai:0.2.3 vjsingh1984/victor-ai:latest

# Push
docker push vjsingh1984/victor-ai:0.2.3
docker push vjsingh1984/victor-ai:latest

Create GitHub Release

  1. Go to GitHub Releases
  2. Click "Draft a new release"
  3. Select the tag (e.g., v0.2.0)
  4. Title: "Victor v0.2.0"
  5. Description: Include changelog
  6. Upload binary artifacts
  7. Check "Pre-release" if applicable
  8. Publish

Distribution Channels

PyPI

GitHub Releases

Docker Hub

Homebrew

  • Tap: vjsingh1984/tap
  • Install: brew install vjsingh1984/tap/victor
  • Formula: Auto-updates every 6 hours via PyPI polling

Post-Release Tasks

After a successful release:

  1. Verify Installation

    pip install victor==0.2.0
    victor --version
    

  2. Test Docker Image

    docker pull vjsingh1984/victor-ai:0.2.3
    docker run vjsingh1984/victor-ai:0.2.3 victor --version
    

  3. Update Documentation
    - Update version references in docs
    - Update changelog

  4. Announce Release
    - GitHub Discussions
    - Social media (if applicable)

  5. Monitor for Issues
    - Watch GitHub Issues for reports
    - Check PyPI download stats

Hotfix Releases

For critical bug fixes:

# 1. Create hotfix branch from tag
git checkout -b hotfix/0.2.1 v0.2.0

# 2. Apply fixes
# ... make changes ...
git commit -m "Fix critical bug"

# 3. Update version
make release VERSION=0.2.1

# 4. Merge to main
git checkout main
git merge hotfix/0.2.1

# 5. Push
git push origin main
git push origin --tags

# 6. Clean up
git branch -d hotfix/0.2.1

Troubleshooting

PyPI Upload Fails

"Invalid distribution":

# Check package
twine check dist/*

# Rebuild
rm -rf dist/
python -m build

"Version exists":
- Version already published to PyPI
- Increment version number

Docker Build Fails

"No space left on device":

# Clean Docker cache
docker system prune -af

"Permission denied":

# Ensure logged in
docker login
docker login ghcr.io

Binary Build Fails

Missing dependencies:

pip install -e ./victor-contracts -e ".[build]"

PyInstaller errors:
- Check scripts/build_binary.py for missing hidden imports
- Add imports to get_hidden_imports()

GitHub Actions Fails

  1. Check workflow logs in Actions tab
  2. Verify secrets are configured
  3. Check for rate limiting
  4. Re-run failed jobs

Homebrew Formula Not Updated

  1. Check vjsingh1984/homebrew-tap workflow ran successfully
  2. Formula auto-updates via PyPI polling (every 6 hours)
  3. Manually trigger: Go to Actions → "Update Formula" → Run workflow
  4. Run: brew update && brew upgrade victor

Release Artifacts Reference

Artifact Location Purpose
victor_ai-0.2.3.tar.gz PyPI, GitHub Source distribution
victor_ai-0.2.3-py3-none-any.whl PyPI, GitHub Python wheel
victor-macos-arm64.tar.gz GitHub macOS Apple Silicon binary
victor-macos-x64.tar.gz GitHub macOS Intel binary
victor-windows-x64.zip GitHub Windows binary
vjsingh1984/victor-ai:0.2.3 Docker Hub Docker image
checksums.txt GitHub SHA256 checksums

See Also