# Pentagi Release Cycle and Versioning Strategy: A Complete Technical Guide

> Understand Pentagi's release cycle and versioning strategy. Discover its automated SemVer, dynamic version strings, and hierarchical Docker image tagging for efficient development and deployment.

- Repository: [VXControl/pentagi](https://github.com/vxcontrol/pentagi)
- Tags: how-to-guide
- Published: 2026-03-21

---

**Pentagi implements a fully automated, Git tag-driven semantic versioning (SemVer) strategy where [`scripts/version.sh`](https://github.com/vxcontrol/pentagi/blob/main/scripts/version.sh) dynamically generates version strings at build time, appending commit hashes for development builds while the CI pipeline publishes Docker images with hierarchical tags (`latest`, `MAJOR`, `MAJOR.MINOR`, and full version).**

The `vxcontrol/pentagi` repository maintains a deterministic release cycle and versioning strategy for Pentagi that eliminates manual version management. This approach leverages Git tags, shell scripts, and GitHub Actions to produce consistent version strings and multi-tiered Docker distribution tags directly from source control metadata.

## Semantic Versioning Foundation

Pentagi adheres to **semantic versioning (SemVer)** principles where version numbers follow the format `MAJOR.MINOR.PATCH`. The project treats Git tags as the single source of truth for version identifiers. When a developer pushes an annotated tag (e.g., `v2.4.1`), the repository recognizes this as a release trigger, while any commit not exactly matching a tag receives a development build designation.

## How Version Strings Are Generated

The version generation logic resides in [`scripts/version.sh`](https://github.com/vxcontrol/pentagi/blob/main/scripts/version.sh), which orchestrates the extraction and formatting of version metadata during the build process.

### Extracting the Base Version from Git Tags

The script identifies the latest release tag using Git's describe command:

```bash

# From scripts/version.sh, lines 5-6

LATEST_TAG=$(git describe --tags --abbrev=0)
PACKAGE_VER=${LATEST_TAG#v}  # Strips the leading 'v'

```

This produces a clean semantic version (e.g., `2.4.1`) by stripping the `v` prefix from the tag. If the current checkout points directly to this tag, the build is classified as a release.

### Detecting Development vs. Release Commits

The script determines whether the current commit matches the tag to differentiate development from release builds:

```bash

# From scripts/version.sh, lines 15-18

TAG_COMMIT=$(git rev-list -n 1 "$LATEST_TAG")
HEAD_COMMIT=$(git rev-parse --short HEAD)
if [ "$TAG_COMMIT" != "$HEAD_COMMIT" ]; then
    PACKAGE_REV="$HEAD_COMMIT"

```

When commits differ, the short SHA (`HEAD_COMMIT`) is stored as `PACKAGE_REV`. If they match, `PACKAGE_REV` remains empty, signaling a clean release build.

### Constructing the Full Version String

The final version string assembly occurs at the end of the script:

```bash

# From scripts/version.sh, lines 30-35

if [ -n "$PACKAGE_REV" ]; then
    echo "${PACKAGE_VER}-${PACKAGE_REV}"  # e.g., 2.4.1-a1b2c3

else
    echo "${PACKAGE_VER}"                 # e.g., 2.4.1

```

Development builds append the commit hash (`2.4.1-a1b2c3`), while release builds use the clean semantic version (`2.4.1`).

## Development vs. Release Builds

Pentagi distinguishes between these build types through the presence of `PACKAGE_REV`:

- **Release builds** occur when the current commit exactly matches a Git tag. The `PACKAGE_REV` variable is empty, resulting in clean version strings like `2.4.1`. These builds are considered stable and suitable for production deployment.

- **Development builds** occur on any commit that does not match a tag. The [`scripts/version.sh`](https://github.com/vxcontrol/pentagi/blob/main/scripts/version.sh) script appends the short commit hash, producing strings like `2.4.1-a1b2c3`. This allows operators to trace running binaries back to specific source revisions.

## CI/CD Pipeline and Docker Tagging Strategy

The GitHub Actions workflow defined in [`.github/workflows/ci.yml`](https://github.com/vxcontrol/pentagi/blob/main/.github/workflows/ci.yml) (lines 160-188) automates the release process triggered by Git tags.

When a tag is pushed, the workflow extracts the version and generates a cascading set of Docker tags:

```yaml

# From .github/workflows/ci.yml

- name: Set version variables
  run: |
    VERSION=${LATEST_TAG#v}
    IFS='.' read -r major minor patch <<< "$VERSION"
    echo "version=${VERSION}" >> $GITHUB_OUTPUT
    # Tags generated: latest, 2, 2.4, 2.4.1

```

The workflow pushes four distinct tag variants to the container registry:

| Tag | Purpose |
|-----|---------|
| `latest` | Always points to the most recent stable release |
| `2` | Floating major version, includes all `2.x.x` releases |
| `2.4` | Floating minor version, includes all `2.4.x` patches |
| `2.4.1` | Immutable exact version for reproducible deployments |

This tagging strategy allows users to pin deployments to specific stability levels, from bleeding-edge (`latest`) to exact version locks.

## Accessing Version Information at Runtime

The compiled version string is exposed through the [`backend/pkg/version/version.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/version/version.go) package via the `GetBinaryVersion()` function. The main application entry point in [`backend/cmd/pentagi/main.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/cmd/pentagi/main.go) logs this at startup:

```go
import (
    "github.com/vxcontrol/pentagi/backend/pkg/version"
    "github.com/sirupsen/logrus"
)

func main() {
    logrus.Infof("Starting PentAGI %s", version.GetBinaryVersion())
}

```

Similarly, the installer in [`backend/cmd/installer/main.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/cmd/installer/main.go) displays the same version string to ensure consistency across all binary artifacts.

## Summary

- Pentagi uses **semantic versioning (SemVer)** driven entirely by Git tags, with version strings generated at build time by [`scripts/version.sh`](https://github.com/vxcontrol/pentagi/blob/main/scripts/version.sh).
- **Release builds** (clean tags) produce versions like `2.4.1`, while **development builds** append short commit hashes (`2.4.1-a1b2c3`).
- The **CI pipeline** ([`.github/workflows/ci.yml`](https://github.com/vxcontrol/pentagi/blob/main/.github/workflows/ci.yml)) automatically creates hierarchical Docker tags (`latest`, `MAJOR`, `MAJOR.MINOR`, full version) triggered by Git tag pushes.
- Version information is embedded into the binary via [`backend/pkg/version/version.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/version/version.go) and logged at startup by [`backend/cmd/pentagi/main.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/cmd/pentagi/main.go).

## Frequently Asked Questions

### How does Pentagi determine the version number during development?

During development, [`scripts/version.sh`](https://github.com/vxcontrol/pentagi/blob/main/scripts/version.sh) extracts the latest Git tag to establish the base version (e.g., `2.4.1`), then compares the current commit hash with the tag's commit. If they differ, it appends the short commit hash (e.g., `-a1b2c3`) to create a development version string like `2.4.1-a1b2c3`.

### What Docker tags are created during a Pentagi release?

The GitHub Actions workflow generates four Docker tag variants: `latest` (always the newest stable release), `MAJOR` (e.g., `2` for all 2.x.x releases), `MAJOR.MINOR` (e.g., `2.4` for all 2.4.x patches), and the full exact version (e.g., `2.4.1`). This allows users to choose between stability and specific version pinning.

### Where is the version string stored in the Pentagi source code?

The version string is not hardcoded but dynamically generated by [`scripts/version.sh`](https://github.com/vxcontrol/pentagi/blob/main/scripts/version.sh) during the build process. The resulting value is compiled into the binary through [`backend/pkg/version/version.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/version/version.go), which exposes the `GetBinaryVersion()` function. This function is called by [`backend/cmd/pentagi/main.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/cmd/pentagi/main.go) to display the version at application startup.

### How can I check which version of Pentagi is running?

You can verify the running version by checking the application logs at startup, where [`backend/cmd/pentagi/main.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/cmd/pentagi/main.go) logs the version using `logrus.Infof("Starting PentAGI %s", version.GetBinaryVersion())`. Alternatively, if you deployed via Docker, inspect the container image labels or tags, which follow the semantic versioning scheme (e.g., `2.4.1` for releases or `2.4.1-a1b2c3` for development builds).