Disciplines · Decisions (ADRs)

ADR-0006: Versioning and Release Strategy

The Oshun monorepo requires a unified versioning and release strategy to manage package versions, generate changelogs, and publish packages across all domains.

Superseded · 2026-01-10
11sections7 minread

On this page

Status: Superseded Date: 2026-01-10 Authors: Development Team Reviewers: DevOps Team, Architecture Team Supersedes: N/A Superseded by: ADR-0073 (the changesets implementation plan below was never executed; nx release is the mechanism actually wired into release.yml and owns versioning/publishing)

Context and Problem Statement#

The Oshun monorepo requires a unified versioning and release strategy to manage package versions, generate changelogs, and publish packages across all domains. Currently:

Lilith (Current State):

  • No automated versioning or release process
  • Manual version bumps in package.json
  • No changelog generation
  • Version: 0.1.0 (static)

Yemaya (Current State):

  • Uses Changesets for versioning (@changesets/cli)
  • Configured with GitHub changelog generation
  • Scripts: version-packages, release
  • Access: restricted (private packages)
  • Automated internal dependency updates

We need to standardize on a versioning/release approach that:

  1. Works well with the Nx monorepo structure
  2. Supports independent and synchronized versioning
  3. Generates meaningful changelogs
  4. Integrates with CI/CD for automated releases
  5. Handles both public npm packages and private deployable services

The main options are:

  • Changesets: Community-driven, battle-tested approach (already used by Yemaya)
  • Nx Release: Nx-native release management (newer, integrated with Nx)

Decision Drivers#

  • Nx Integration: Seamless integration with Nx workspace
  • Changelog Quality: Meaningful, well-formatted changelogs
  • Independent Versioning: Ability to version packages independently
  • Fixed Versioning: Option to lock certain packages to same version
  • Automation: CI/CD integration for automated releases
  • Developer Experience: Simple workflow for contributors
  • Existing Investment: Yemaya's Changesets configuration
  • Ecosystem Support: npm/GitHub integration, community adoption
  • Flexibility: Support for various release strategies

Considered Options#

Description: Use Changesets for version management and changelog generation. Changesets is a popular approach used by Babel, Atlassian, and many other monorepos.

Workflow:

text
Developer creates PR
       │
       ▼
Run `pnpm changeset` to create changeset file
       │
       ▼
PR merged with changeset
       │
       ▼
CI runs `changeset version` (bumps versions, updates changelogs)
       │
       ▼
Version PR created/updated
       │
       ▼
Version PR merged
       │
       ▼
CI runs `changeset publish` (publishes to npm)

Pros:

  • Already In Use: Yemaya has working Changesets configuration
  • Battle-Tested: Used by major projects (Babel, Atlassian, Pnpm itself)
  • Flexible: Supports independent, fixed, and linked versioning
  • Rich Ecosystem: Multiple changelog formatters, bot integrations
  • Explicit Intent: Developers explicitly declare change significance
  • Human-Readable Changelogs: Generates quality CHANGELOG.md
  • Works with pnpm: First-class pnpm workspace support
  • GitHub Integration: Changeset bot, PR changelogs

Cons:

  • Learning Curve: Developers need to learn pnpm changeset workflow
  • Extra Step: Requires changeset creation in each PR
  • Not Nx-Native: Separate tool from Nx ecosystem
  • Two-PR Process: Version bump is a separate PR

Cost: Low - minimal setup, leverage existing Yemaya config Risk: Low - proven at scale Effort: 1-2 days to configure for full monorepo

Option 2: Nx Release#

Description: Use Nx's built-in release management (nx release). Nx Release is newer but designed specifically for Nx workspaces.

Workflow:

text
Developer creates PR with conventional commit
       │
       ▼
PR merged
       │
       ▼
CI runs `nx release` (analyzes commits, bumps versions)
       │
       ▼
Git tags created, changelogs updated
       │
       ▼
Packages published to npm

Pros:

  • Nx-Native: Integrated with Nx, uses project graph
  • Conventional Commits: Automatic version bumps from commit messages
  • Single Command: nx release handles everything
  • Project Awareness: Understands Nx project dependencies
  • Git Integration: Automatic tagging and changelog

Cons:

  • Newer Tool: Less battle-tested than Changesets
  • Conventional Commit Enforcement: Requires strict commit conventions
  • Less Flexible: Fewer options for changelog customization
  • Would Discard: Yemaya's existing Changesets setup
  • Learning New Tool: Team needs to learn Nx release specifics

Cost: Medium - need to migrate from Changesets Risk: Medium - less proven than Changesets Effort: 3-4 days for setup and migration

Option 3: Manual/Script-Based#

Description: Custom scripts for version management without a dedicated tool.

Pros:

  • Full Control: Complete flexibility
  • No Dependencies: No external tools

Cons:

  • Reinventing Wheel: Solved problem, no need for custom solution
  • Maintenance Burden: Custom code to maintain
  • Error Prone: Manual processes are error-prone
  • No Ecosystem: No bot integrations, changelog generation

Cost: High - significant custom development Risk: High - maintenance burden, errors Effort: 2+ weeks for complete solution

Decision Outcome#

Chosen option: Option 1 - Changesets

Justification:

Changesets is the optimal choice for the Oshun monorepo because:

  1. Existing Investment: Yemaya already has a working Changesets configuration. This provides a proven foundation that can be extended to the full monorepo.

  2. Maturity: Changesets is battle-tested by major projects including Babel, Atlassian, pnpm itself, and hundreds of open-source monorepos. Nx Release, while promising, is newer and less proven.

  3. Explicit Intent: The changeset workflow requires developers to explicitly declare the significance of their changes (major/minor/patch). This produces higher-quality changelogs than automated commit message parsing.

  4. Flexibility: Changesets supports multiple versioning strategies:

    • Independent: Each package versioned independently
    • Fixed: Groups of packages locked to same version
    • Linked: Packages always bump together but can have different versions
  5. pnpm Integration: Changesets has first-class support for pnpm workspaces, which aligns with ADR-0002.

  6. Ecosystem: Rich ecosystem of tools (changeset bot, changelog formatters, GitHub Action) that would take significant effort to replicate with Nx Release.

Nx Compatibility Note: Changesets works well alongside Nx. Nx handles task orchestration (build, test, lint), while Changesets handles versioning and publishing. This separation of concerns is clean and well-established.

Implementation Plan:

  1. Phase 1: Root Configuration (Day 1)

    • Create .changeset/config.json at oshun root
    • Configure changelog format (GitHub-linked)
    • Define fixed/linked package groups
    • Add changeset scripts to root package.json
  2. Phase 2: Package Groups (Day 1)

    • Define fixed groups for tightly-coupled packages
    • Configure independent versioning for standalone packages
    • Set up internal dependency update rules
  3. Phase 3: CI/CD Integration (Day 2)

    • Configure GitHub Actions for version PR creation
    • Set up automated npm publishing
    • Configure changeset bot for PR status
  4. Phase 4: Documentation (Day 2)

    • Create contributor guide for changesets
    • Document release process
    • Add PR template with changeset reminder

Success Metrics:

  • All package releases tracked via changesets
  • Changelogs generated for all releases
  • Zero manual version bumps
  • Release process takes < 5 minutes from merge to publish
  • Contributors successfully create changesets in 95% of PRs

Review Schedule: 60 days post-implementation

Implementation Details#

Technical Specifications#

Root Changeset Configuration:

json
// .changeset/config.json
{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": ["@changesets/changelog-github", { "repo": "oshun/oshun" }],
  "commit": false,
  "fixed": [
    // Packages that always share the same version
    ["@oshun/types", "@oshun/errors", "@oshun/config"],
    ["@oshun/proto", "@oshun/openapi"]
  ],
  "linked": [
    // Packages that bump together but can have different versions
    ["@oshun/auth", "@oshun/auth-client"],
    ["@oshun/events", "@oshun/events-client"]
  ],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": [
    // Private packages that don't get published
    "@oshun/tools-*",
    "@lilith/service-*",
    "@yemaya/app-*"
  ],
  "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
    "onlyUpdatePeerDependentsWhenOutOfRange": true
  }
}

Root Package.json Scripts:

json
{
  "scripts": {
    "changeset": "changeset",
    "changeset:add": "changeset add",
    "changeset:status": "changeset status",
    "version": "changeset version && pnpm install --lockfile-only",
    "release": "pnpm build && changeset publish",
    "release:dry": "changeset publish --dry-run"
  }
}

Package Groups Explanation:

text
Fixed Groups (same version number):
┌────────────────────────────────────────┐
│  @oshun/types     v1.0.0               │
│  @oshun/errors    v1.0.0  ──► Always   │
│  @oshun/config    v1.0.0      same     │
└────────────────────────────────────────┘

Linked Groups (bump together, different versions):
┌────────────────────────────────────────┐
│  @oshun/auth          v2.3.0           │
│  @oshun/auth-client   v1.5.0  ──► Bump │
│                            together    │
└────────────────────────────────────────┘

Independent (versioned separately):
┌──────────────────┐  ┌──────────────────┐
│  @oshun/isis     │  │  @oshun/sophia   │
│  v3.2.1          │  │  v1.0.5          │
└──────────────────┘  └──────────────────┘

GitHub Action for Version PR:

yaml
# .github/workflows/release.yml
name: Release

on:
  push:
    branches:
      - main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: 10

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install Dependencies
        run: pnpm install

      - name: Create Release Pull Request or Publish
        id: changesets
        uses: changesets/action@v1
        with:
          version: pnpm run version
          publish: pnpm run release
          title: 'chore: release packages'
          commit: 'chore: release packages'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Changeset Bot Configuration:

yaml
# .github/changeset-bot.yml
# Automatically comments on PRs missing changesets
sinceMajor: true

PR Template Addition:

markdown
<!-- .github/pull_request_template.md -->

## Description

<!-- Describe your changes -->

## Checklist

- [ ] I have added a changeset (`pnpm changeset`) if this PR includes
      user-facing changes
- [ ] Tests pass locally
- [ ] Documentation updated if needed

## Changeset

<!--
If this PR affects published packages, run:
  pnpm changeset

Then select:
- Which packages are affected
- Semver bump type (major/minor/patch)
- Summary of changes for changelog
-->

Versioning Strategy by Package Type#

Package Type Strategy Example
Shared Foundation Fixed @oshun/types, @oshun/errors, @oshun/config - always same version
Contracts Fixed @oshun/proto, @oshun/openapi - breaking changes affect all consumers
Domain Libraries Independent @oshun/isis-, @oshun/sophia- - version based on their own changes
Client SDKs Linked @oshun/auth + @oshun/auth-client - bump together
Internal Tools Ignored @oshun/tools-* - not published
Services Ignored @lilith/service-, @yemaya/app- - deployed, not published

Semver Guidelines#

text
MAJOR version: Breaking changes to public API
  - Removing exported functions/types
  - Changing function signatures
  - Removing fields from interfaces
  - Changing behavior in incompatible ways

MINOR version: New features, backward-compatible
  - Adding new exports
  - Adding optional fields
  - Adding new functionality
  - Deprecating (not removing) features

PATCH version: Bug fixes, backward-compatible
  - Bug fixes
  - Performance improvements
  - Documentation updates
  - Internal refactoring

Changelog Format#

markdown
# @oshun/types

## 1.2.0

### Minor Changes

- feat: add AssetMetadata type for generation outputs (#123)

  Added new AssetMetadata interface that includes provenance, licensing, and
  lineage information for generated assets.

- feat: add Result<T, E> utility type (#125)

### Patch Changes

- fix: correct ProjectId branded type (#124)
- Updated dependencies
  - @oshun/errors@1.1.0

Migration Strategy#

From Yemaya:

  1. Copy .changeset/config.json to oshun root
  2. Update repo reference
  3. Define package groups for new structure
  4. Test with dry-run publish

For Lilith Packages:

  1. Add to Changesets scope (remove from ignore if needed)
  2. Set initial versions
  3. Create initial changeset if needed

Consequences#

Positive Consequences#

  • Consistent Releases: All packages follow same release process
  • Quality Changelogs: Human-written, meaningful changelogs
  • Automation: CI/CD handles version bumps and publishing
  • Flexibility: Different strategies for different package types
  • Traceability: Each release linked to PRs and commits
  • Proven Process: Battle-tested workflow

Negative Consequences#

  • Extra Step: Developers must create changesets
  • Learning Curve: Team needs to understand changeset workflow
  • Two PRs: Version bump is separate PR
  • Tool Dependency: Relies on external tool

Risks and Mitigation#

Risk Probability Impact Mitigation Strategy
Forgotten changesets Medium Low Changeset bot comments on PRs, PR template reminder
Wrong semver selection Medium Medium PR review, documented guidelines
CI publish failures Low Medium Dry-run before publish, manual fallback
Package group misconfiguration Low High Test in staging, careful initial setup

Compliance and Security#

Security Implications#

  • npm Tokens: Stored as GitHub secrets, not in code
  • Publish Access: Only CI can publish, not individual developers
  • Audit Trail: All releases tracked in GitHub, npm, and changelogs
  • 2FA: npm publish protected by token, not password

Compliance Requirements#

  • Version History: Complete changelog for each package
  • Release Tracking: Git tags for each release
  • Reproducibility: Lockfile ensures consistent builds

Monitoring and Observability#

Metrics to Track#

  • Release Frequency: Releases per week/month
  • Changeset Compliance: % of PRs with changesets
  • Publish Success Rate: % of successful publishes
  • Time to Publish: Time from merge to npm availability

Alerting Strategy#

  • Critical: Publish failure, npm token expiration
  • Warning: PR missing changeset for affected packages
  • Info: New release published, version PR created

Upstream Dependencies#

  • ADR-0002: pnpm (Changesets uses pnpm workspace protocol)
  • ADR-0001: Git Consolidation (single repo for changesets)

Downstream Impacts#

  • CI/CD: GitHub Actions for release automation
  • Contributors: Must learn changeset workflow
  • Consumers: Semantic versions for dependency management

References#

External Resources#

Internal Resources#


Revision History#

Version Date Author Changes
1.0 2026-01-10 Development Team Initial version