How Versioning Works in Open-SEO: A Complete Technical Guide

Open-SEO implements a multi-layered versioning strategy that uses package.json as the single source of truth, propagating version identifiers through telemetry payloads, MCP protocol headers, immutable R2 data storage, and automated release workflows.

The every-app/open-seo repository maintains strict versioning across code, data, and infrastructure layers. Understanding how these version numbers interact ensures reliable deployments, accurate upgrade detection, and traceable data history.

Canonical Version Source in package.json

The canonical version lives in the root package.json file (e.g., "version": "0.0.11"). This serves as the single source of truth that the entire application references when it needs to identify its own release identity.

Rather than hard-coding version strings throughout the codebase, Open-SEO imports this value directly from package.json wherever runtime version awareness is required.

Runtime Version Propagation

The application propagates the canonical version through two critical runtime channels: telemetry reporting and MCP client transport.

Telemetry and Upgrade Detection

In src/server/lib/self-host-telemetry.ts, the version is imported from package.json and included in every telemetry payload sent by self-hosted instances:

// src/server/lib/self-host-telemetry.ts
import { version } from "../../../package.json";

export async function sendTelemetry(state: TelemetryState) {
  const payload = {
    version,                     // <-- current app version from package.json
    ...state,
  };
  // ...send payload to telemetry endpoint
}

The database schema in src/db/telemetry.schema.ts stores this value in a lastVersion column. When a self-hosted instance starts, the system compares the current package.json version against the stored value to detect upgrades automatically.

MCP Protocol Headers

The MCP client transport layer hard-codes the version string in src/server/mcp/transport.ts to ensure protocol compatibility:

// src/server/mcp/transport.ts
export const client = new Client({
  name: "open-seo",
  version: "0.0.11",           // <-- matches package.json version
});

This value is sent in the mcp-protocol-version header on every request, allowing the server to validate client compatibility before processing commands.

Immutable Data Versioning for Project Context

Open-SEO treats project context data as an append-only log with immutable versioning. According to specs/0006-onboarding-agent-implementation.md, each version is stored as a markdown blob in Cloudflare R2 under project-context/{projectId}/{versionId}.md.

The system records metadata in a project_context_versions table:

// Conceptual implementation from onboarding spec
async function persistProjectContext(md: string, note?: string) {
  const versionId = crypto.randomUUID();        // immutable version identifier
  await r2.put(`project-context/${projectId}/${versionId}.md`, md);
  await db.insert('project_context_versions', {
    projectId,
    versionId,
    note,
    createdAt: new Date(),
  });
}

This architecture allows the UI to retrieve any historic snapshot of a project's context and perform safe rollbacks without mutating previous records.

Release Automation and Changelog Management

Release artifacts follow a strict naming convention tied to the package.json version. Each release gets a dedicated Markdown file in the release-notes/ directory (e.g., release-notes/v0.0.26.md).

The workflow defined in .opencode/command/release-notes.md automates creation of these files:


# Workflow extracts version from package.json

VERSION=$(jq -r .version package.json)
cat <<EOF > release-notes/v${VERSION}.md

# Open-SEO ${VERSION}

Full Changelog: https://github.com/every-app/open-seo/compare/v${PREV}...v${VERSION}
EOF
git add release-notes/v${VERSION}.md
git commit -m "release: v${VERSION}"

CI pipelines use the filename to publish GitHub releases after merge, ensuring human-readable documentation stays synchronized with the codebase.

Summary

  • package.json serves as the single source of truth for the application version number.
  • Self-host telemetry (src/server/lib/self-host-telemetry.ts) imports this version to track deployments and detect upgrades via src/db/telemetry.schema.ts.
  • MCP transport (src/server/mcp/transport.ts) hard-codes a matching version string for protocol negotiation.
  • Project context data uses immutable versioning in R2 with an append-only log pattern defined in the onboarding spec.
  • Release notes are generated automatically from the package.json version and stored in release-notes/ following semantic naming conventions.

Frequently Asked Questions

How does Open-SEO detect when a self-hosted instance has upgraded?

The system compares the current version imported from package.json against the lastVersion value stored in the telemetry table. When src/server/lib/self-host-telemetry.ts sends a startup payload, the server checks for mismatches to identify upgrade events and can trigger automatic migration steps.

Why is the MCP version hard-coded in transport.ts instead of imported from package.json?

The MCP client version in src/server/mcp/transport.ts is hard-coded as "0.0.11" to ensure the transport layer maintains strict protocol compatibility guarantees. This prevents accidental protocol mismatches that could occur if the version were dynamically imported during runtime bundling or if the transport module were distributed separately.

How does Open-SEO handle versioned data storage for project contexts?

According to specs/0006-onboarding-agent-implementation.md, the system stores each project context version as an immutable markdown blob in R2 under project-context/{projectId}/{versionId}.md. An append-only log table tracks these versions, enabling time-travel queries and safe reversion without data mutation, as each write creates a new UUID-versioned blob rather than updating existing files.

Where does Open-SEO store its release notes and how are they automated?

Release notes live in the release-notes/ directory with filenames matching the package.json version (e.g., v0.0.26.md). The workflow in .opencode/command/release-notes.md reads the version from package.json to generate new files automatically, which CI then uses to create GitHub releases after merge.

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 →