Skip to content

Release and Versioning

Caracal uses CalVer for all release artifacts. A single git tag triggers the CI release pipeline for CLI binaries and container images. npm and PyPI packages are published from a maintainer workstation using the scripts in scripts/.


All release artifacts share the same version format:

vYYYY.MM.DD[.N]
  • vYYYY.MM.DD — primary release for that date.
  • vYYYY.MM.DD.1, .2, … — subsequent releases on the same date (hotfixes or corrections).

Examples: v2026.05.12, v2026.05.12.1, v2026.06.01.

The version is set by the git tag. The release pipeline reads the tag and propagates it to all artifact types.


Releases are triggered by pushing a CalVer tag to main:

Terminal window
git tag v2026.05.12
git push origin v2026.05.12

This triggers release.yml in GitHub Actions. The pipeline:

  1. Verifies the pushing actor is listed in .github/MAINTAINERS.
  2. Builds CLI/TUI binaries and container images in parallel.
  3. Pushes images to GHCR with SLSA provenance and SBOM.
  4. Creates a GitHub Release with generated release notes, binaries, checksums, and provenance attestations.

Only maintainers push release tags. Do not push CalVer tags from feature branches.


The CLI (caracal) and the optional TUI (caracal-tui) are compiled to self-contained binaries using bun --compile. Ten archives are produced per release (five targets × two tools), each containing one executable:

TargetCLI archiveTUI archive
linux-amd64caracal-cli-linux-amd64-vYYYY.MM.DD.tar.gzcaracal-tui-linux-amd64-vYYYY.MM.DD.tar.gz
linux-arm64caracal-cli-linux-arm64-vYYYY.MM.DD.tar.gzcaracal-tui-linux-arm64-vYYYY.MM.DD.tar.gz
darwin-amd64caracal-cli-darwin-amd64-vYYYY.MM.DD.tar.gzcaracal-tui-darwin-amd64-vYYYY.MM.DD.tar.gz
darwin-arm64caracal-cli-darwin-arm64-vYYYY.MM.DD.tar.gzcaracal-tui-darwin-arm64-vYYYY.MM.DD.tar.gz
windows-amd64caracal-cli-windows-amd64-vYYYY.MM.DD.zipcaracal-tui-windows-amd64-vYYYY.MM.DD.zip

Archives are attached to the GitHub Release with a SHA256SUMS file and SLSA provenance attestations.

The CLI is the default install target. The TUI is opt-in:

Terminal window
# Linux/macOS — CLI only (default)
curl -fsSL https://raw.githubusercontent.com/Garudex-Labs/caracal/main/install.sh | sh
# Linux/macOS — CLI + TUI
curl -fsSL https://raw.githubusercontent.com/Garudex-Labs/caracal/main/install.sh | sh -s -- --tui
# Windows — CLI only
iwr -useb https://raw.githubusercontent.com/Garudex-Labs/caracal/main/install.ps1 | iex
# Windows — CLI + TUI
$installer = (iwr -useb https://raw.githubusercontent.com/Garudex-Labs/caracal/main/install.ps1).Content
& ([scriptblock]::Create($installer)) -Tui

The installers detect OS and architecture, resolve the latest release tag from the GitHub API (or accept --version/-Version), download the matching archive, verify it against SHA256SUMS, extract it, and place the binary on PATH.

Re-run the same install command. The installer overwrites the binary in place with the new version.

Linux/macOS: rm ~/.local/bin/caracal (and ~/.local/bin/caracal-tui if installed).

Windows: delete %LOCALAPPDATA%\Programs\caracal and remove the user PATH entry.


Five container images are published to GitHub Container Registry on every release:

ImageService
ghcr.io/garudex-labs/caracal-apiControl-Plane API
ghcr.io/garudex-labs/caracal-stsSecurity Token Service
ghcr.io/garudex-labs/caracal-gatewayGateway
ghcr.io/garudex-labs/caracal-coordinatorCoordinator
ghcr.io/garudex-labs/caracal-auditAudit service

All images are multi-arch (linux/amd64, linux/arm64) and are tagged with the CalVer version, the vYYYY.MM series, and latest.


npm and PyPI packages are published from a maintainer workstation using the scripts in scripts/. Each script opens an interactive picker (up/down, space to toggle, a toggles all, enter confirms), prompts for the registry token, builds the selected packages, and uploads them — skipping versions already present on the registry.

Terminal window
./scripts/publishNpm.sh
./scripts/publishPypi.sh # PyPI
./scripts/publishPypi.sh --testpypi # TestPyPI

npm packages (@caracalai/*): core, oauth, admin, identity, revocation, sdk, transport-mcp, transport-a2a, mcp-express, mcp-fastmcp, tokenstate-postgres, revocation-redis. Browse at npmjs.com/~caracal-run.

PyPI packages (caracalai-*): core, identity, revocation, sdk, transport-mcp, mcp-fastmcp, revocation-redis. Browse at pypi.org/user/CaracalAI.


The release pipeline generates SLSA Level 3 provenance attestations for binaries and container images. Verify an artifact:

Terminal window
gh attestation verify caracal-cli-linux-amd64-v2026.05.12.tar.gz --repo garudex-labs/caracal

For a critical fix on an already-released version:

  1. Branch from the release tag: git checkout -b hotfix-jti v2026.05.12
  2. Apply the fix and open a PR against main.
  3. Merge after review; cherry-pick to main if needed.
  4. Tag the hotfix: git tag v2026.05.12.1 && git push origin v2026.05.12.1.

Tags must point to commits reachable from main.


Every release tag has a directory under caracal/releases/<tag>/ that owns all of its metadata:

  • manifest.json — pins every published artifact (binaries, containers, PyPI, npm) to a version, committed alongside the changeset version bump.
  • validation.md — the aggregated post-release validation report.
  • findings/*.jsonl — raw per-area findings.

The .github/workflows/postReleaseValidation.yml workflow triggers after release.yml completes successfully for a release tag, or via workflow_dispatch, and opens a PR that adds validation.md and findings/ to that directory.

Run a single check locally:

Terminal window
CARACAL_RELEASE=v2026.05.12 FINDINGS_DIR=/tmp/findings \
bash caracal/scripts/postRelease/validateRegistryMetadata.sh