# OpenHuman Versioning Practices: A SemVer-Based Release Workflow

> Explore OpenHuman's robust SemVer versioning practices. Learn how Cargo.toml centralizes releases and automates updates across Rust core, Tauri desktop, and npm frontend via CI.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: best-practices
- Published: 2026-06-11

---

**OpenHuman uses a centralized SemVer system where [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml) serves as the single source of truth, automatically propagating version strings to the Rust core, Tauri desktop bundle, and npm frontend through CI workflows.**

The OpenHuman repository maintains a strict release process that coordinates the Rust core (`tinyhumansai/openhuman`), the Tauri desktop application, and the web-based UI. This standardized approach ensures that every binary, installer, and API response carries a consistent, traceable version identifier derived from a single canonical location.

## Centralized Version Control in Cargo.toml

### Single Source of Truth

The versioning system anchors to [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml) at the repository root. The `version` field defined here becomes `CARGO_PKG_VERSION` at compile time, serving as the canonical reference for the entire monorepo.

According to the source code, this value is baked into the Rust binary and exposed via multiple channels:

- **Runtime access**: Retrieved via `env!("CARGO_PKG_VERSION")` in Rust source files
- **Health checks**: Embedded in [`src/openhuman/health/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/health/ops.rs) for system status reporting
- **UI injection**: Passed from [`app/src-tauri/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/lib.rs) into the Vite frontend bundle

When the CI cuts a release, it reads the version from [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml) and synchronizes downstream:

```toml

# Cargo.toml

[package]
name = "openhuman"
version = "0.57.35"  # Canonical version

edition = "2021"

```

### Propagating to Frontend Components

The Tauri bridge in [`app/src-tauri/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/lib.rs) reads the compiled version and injects it into the frontend environment:

```rust
// app/src-tauri/src/lib.rs
let version = env!("CARGO_PKG_VERSION");
println!("OpenHuman core version: {}", version);

```

This value flows into three locations that must remain synchronized:

1. **[`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml)** – Core Rust crate version
2. **[`app/package.json`](https://github.com/tinyhumansai/openhuman/blob/main/app/package.json)** – Frontend npm/yarn workspace version
3. **[`app/src-tauri/tauri.conf.json`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/tauri.conf.json)** – Tauri bundle version (displayed in installers)

The [`scripts/prepare-build.sh`](https://github.com/tinyhumansai/openhuman/blob/main/scripts/prepare-build.sh) script handles this propagation automatically during the release process.

## Automated Release Workflows

OpenHuman employs two distinct GitHub Actions workflows that handle version bumps and artifact generation without manual intervention.

### Staging Releases

The [`release-staging.yml`](https://github.com/tinyhumansai/openhuman/blob/main/release-staging.yml) workflow runs on every push to `main`. It automatically bumps the **patch** version in [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml) and creates a pre-release tag with the `-staging` suffix:

```bash

# scripts/prepare-build.sh (simplified)

VERSION=$(awk '/^version =/ {print $3}' Cargo.toml | tr -d '"')
npm version "$VERSION" --no-git-tag-version
jq ".tauri.bundle.version = \"$VERSION\"" app/src-tauri/tauri.conf.json -i
git commit -am "chore(release): bump to $VERSION"
git tag "v$VERSION-staging"

```

Staging tags follow the format `v1.2.3-staging`, which sorts lexicographically before the production tag `v1.2.3`. This allows the team to test installers and auto-updaters before final promotion.

### Production Promotions

The [`release-production.yml`](https://github.com/tinyhumansai/openhuman/blob/main/release-production.yml) workflow supports two paths:

- **Promotion**: Takes a validated staging tag and removes the `-staging` suffix without generating a new version number
- **Main-head releases**: On direct `main` branch runs, can bump `patch`, `minor`, or `major` versions (restricted to the main branch only)

If any matrix build fails during the process, a cleanup job removes the draft release and associated tag, leaving the preceding staging tag untouched for later promotion.

## Version Enforcement and Gates

### Minimum Supported App Version

The frontend enforces a **minimum-supported-app-version** gate for OAuth authentication flows. This prevents outdated clients from completing OAuth deep-links when critical security updates are required.

The gate is configured via the `VITE_MINIMUM_SUPPORTED_APP_VERSION` environment variable during CI builds and checked in [`app/src/utils/oauthAppVersionGate.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/utils/oauthAppVersionGate.ts):

```typescript
// app/src/utils/oauthAppVersionGate.ts
import { MIN_SUPPORTED_VERSION } from '@/utils/config';

export function isVersionSupported(current: string): boolean {
  // semver compare – returns true if current ≥ minimum
  return semver.gte(current, MIN_SUPPORTED_VERSION);
}

```

### Health Check and RPC Exposure

Every OpenHuman component reports the same version string through the health system. The `openhuman.health_system_info.version` field in RPC responses contains the `CARGO_PKG_VERSION` value, ensuring that agents, monitoring tools, and CLI utilities see consistent versioning:

```rust
// src/openhuman/health/ops.rs example pattern
let version = env!("CARGO_PKG_VERSION");
// Exposed via health RPC schema

```

## Rollback and Cleanup Procedures

The CI workflows include defensive measures for failed releases. If any build matrix job fails (Windows, macOS, or Linux), a cleanup job automatically removes the draft GitHub release and deletes the associated tag. This leaves the repository in a clean state with the previous staging tag available for immediate promotion, eliminating the need for manual version rollback or tag deletion.

## Summary

- **Single source of truth**: [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml) holds the canonical version that becomes `CARGO_PKG_VERSION` at compile time
- **Automated propagation**: CI scripts update [`app/package.json`](https://github.com/tinyhumansai/openhuman/blob/main/app/package.json) and [`tauri.conf.json`](https://github.com/tinyhumansai/openhuman/blob/main/tauri.conf.json) to match the Rust crate version
- **Staging vs. production**: Staging tags use the `-staging` suffix; production promotes by removing the suffix without changing version numbers
- **Security gates**: OAuth flows enforce minimum app versions via `VITE_MINIMUM_SUPPORTED_APP_VERSION` and [`app/src/utils/oauthAppVersionGate.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/utils/oauthAppVersionGate.ts)
- **Atomic rollbacks**: Failed builds trigger automatic cleanup of draft releases and tags, leaving the previous staging tag intact

## Frequently Asked Questions

### How does OpenHuman ensure version consistency across Rust and TypeScript codebases?

OpenHuman treats [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml) as the single source of truth. During the CI release process, [`scripts/prepare-build.sh`](https://github.com/tinyhumansai/openhuman/blob/main/scripts/prepare-build.sh) reads the version from [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml) and injects it into [`app/package.json`](https://github.com/tinyhumansai/openhuman/blob/main/app/package.json) and [`app/src-tauri/tauri.conf.json`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/tauri.conf.json) using `npm version` and `jq`. The Rust code exposes this value to the frontend via Tauri's `env!("CARGO_PKG_VERSION")` injection, ensuring the Vite bundle receives the exact same version string that is compiled into the binary.

### What is the difference between staging and production tags in OpenHuman?

Staging tags append the `-staging` suffix (e.g., `v1.2.3-staging`) and are created automatically on every `main` branch push with a patch version bump. Production tags drop the suffix (e.g., `v1.2.3`) and are created either by promoting an existing staging tag or by running a main-head release with manual version bumping. The suffix ensures staging releases sort before production releases in semantic versioning comparisons while remaining distinct from final artifacts.

### How does OpenHuman prevent outdated clients from authenticating via OAuth?

The repository implements a minimum supported app version gate through [`app/src/utils/oauthAppVersionGate.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/utils/oauthAppVersionGate.ts). During CI builds, the `VITE_MINIMUM_SUPPORTED_APP_VERSION` environment variable is baked into the frontend bundle. When processing OAuth deep-links, the application compares the running binary's version (exposed via Tauri) against this minimum threshold using semantic versioning comparison. If the current version is lower, the authentication flow is blocked until the user updates.

### What happens if a release build fails in the CI pipeline?

If any matrix build (Windows, macOS, or Linux) fails during the release process, a cleanup job automatically removes the draft GitHub release and deletes the associated git tag. This atomic rollback leaves the previous staging tag untouched, allowing the team to either fix the issue and retry or promote the previous stable staging tag to production without manual version manipulation or repository cleanup.