OpenHuman Versioning Practices: A SemVer-Based Release Workflow

OpenHuman uses a centralized SemVer system where 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 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:

When the CI cuts a release, it reads the version from Cargo.toml and synchronizes downstream:


# 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 reads the compiled version and injects it into the frontend environment:

// 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 – Core Rust crate version
  2. app/package.json – Frontend npm/yarn workspace version
  3. app/src-tauri/tauri.conf.json – Tauri bundle version (displayed in installers)

The 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 workflow runs on every push to main. It automatically bumps the patch version in Cargo.toml and creates a pre-release tag with the -staging suffix:


# 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 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:

// 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:

// 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 holds the canonical version that becomes CARGO_PKG_VERSION at compile time
  • Automated propagation: CI scripts update app/package.json and 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
  • 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 as the single source of truth. During the CI release process, scripts/prepare-build.sh reads the version from Cargo.toml and injects it into app/package.json and 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →