|
| 1 | +# Docs versioning strategy proposal |
| 2 | + |
| 3 | +## Status |
| 4 | + |
| 5 | +Draft - April 2026 |
| 6 | + |
| 7 | +## Problem statement |
| 8 | + |
| 9 | +Stacklok is introducing Stacklok Enterprise, an enterprise |
| 10 | +distribution of ToolHive that will be semantically versioned with |
| 11 | +support for N-1 and N-2 minor releases. The ToolHive open source |
| 12 | +(OSS) documentation currently follows a rolling "latest" model with |
| 13 | +no versioning. We need a strategy that: |
| 14 | + |
| 15 | +- Gives Enterprise customers pinned, version-accurate documentation |
| 16 | +- Keeps OSS documentation on a rolling latest without friction |
| 17 | +- Presents Enterprise features inline with OSS docs as an upsell |
| 18 | + opportunity |
| 19 | +- Handles auto-generated reference content (CLI reference, CRD specs, |
| 20 | + API specs) that is produced upstream |
| 21 | +- Minimizes maintenance burden across active versions |
| 22 | + |
| 23 | +## Current state |
| 24 | + |
| 25 | +- Single unversioned Docusaurus docs instance at `/` |
| 26 | +- ~96 auto-generated CLI reference pages, 5 API/schema spec files, |
| 27 | + and 1 CRD spec page - all generated upstream |
| 28 | +- Enterprise landing page exists at `/toolhive/enterprise` with |
| 29 | + feature comparison and CTAs |
| 30 | +- No enterprise-specific inline content in existing docs |
| 31 | +- No Docusaurus versioning configured |
| 32 | + |
| 33 | +## Proposed approach |
| 34 | + |
| 35 | +### Versioning model |
| 36 | + |
| 37 | +Use Docusaurus's built-in docs versioning with the following mapping: |
| 38 | + |
| 39 | +| Audience | Docs state | URL path | |
| 40 | +| ---------------------------------- | -------------------------------------- | ------------------------------ | |
| 41 | +| OSS users | Rolling latest (unversioned "current") | `/toolhive/...` (default) | |
| 42 | +| Enterprise users on latest release | Most recent versioned snapshot | `/enterprise/1.2/toolhive/...` | |
| 43 | +| Enterprise users on older releases | Older versioned snapshots | `/enterprise/1.1/toolhive/...` | |
| 44 | + |
| 45 | +- **"Current"** always tracks the OSS rolling latest. This is the |
| 46 | + default path and what search engines index. |
| 47 | +- **Versioned snapshots** are cut on each Enterprise minor release |
| 48 | + (e.g., 1.0, 1.1, 1.2). |
| 49 | +- **Prune policy:** remove versions older than N-2. At any given time, |
| 50 | + at most 3 Enterprise versions are live (current release + N-1 + |
| 51 | + N-2). |
| 52 | + |
| 53 | +Docusaurus configuration (validated in spike): |
| 54 | + |
| 55 | +```ts title="docusaurus.config.ts (docs plugin options)" |
| 56 | +lastVersion: 'current', |
| 57 | +versions: { |
| 58 | + current: { |
| 59 | + label: 'Latest (OSS)', |
| 60 | + }, |
| 61 | + '1.1': { |
| 62 | + label: 'Enterprise 1.1', |
| 63 | + path: 'enterprise/1.1', |
| 64 | + banner: 'none', |
| 65 | + noIndex: true, |
| 66 | + }, |
| 67 | +}, |
| 68 | +``` |
| 69 | + |
| 70 | +- `lastVersion: 'current'` keeps the `docs/` folder as the |
| 71 | + default, served at the root route base path (`/`). No change to |
| 72 | + existing OSS URLs. |
| 73 | +- `path: 'enterprise/1.1'` routes the versioned snapshot under the |
| 74 | + `/enterprise/1.1/` prefix instead of the default `/1.1/`. |
| 75 | +- `banner: 'none'` suppresses the "unmaintained version" banner |
| 76 | + (not appropriate for an Enterprise pinned version). |
| 77 | +- `noIndex: true` prevents search engines from indexing versioned |
| 78 | + pages, avoiding duplicate content with the OSS latest. |
| 79 | + |
| 80 | +A `docsVersionDropdown` navbar item renders the version picker. |
| 81 | + |
| 82 | +**Constraint:** the `versions` config block must not reference a |
| 83 | +version until after `docs:version` has been run and `versions.json` |
| 84 | +contains it. Docusaurus validates at startup and errors on unknown |
| 85 | +versions. The version cut and config update must happen in |
| 86 | +sequence. |
| 87 | + |
| 88 | +### Enterprise content inline |
| 89 | + |
| 90 | +Enterprise-specific content lives inline alongside OSS docs to serve |
| 91 | +as a natural upsell. Two patterns: |
| 92 | + |
| 93 | +**Enterprise-only pages:** added to the docs tree like any other page |
| 94 | +and included in every versioned snapshot. Examples based on current |
| 95 | +Enterprise differentiation: |
| 96 | + |
| 97 | +- Configuration server setup and administration (enterprise lockdown |
| 98 | + controls for the Desktop UI) |
| 99 | +- Turnkey IdP integration guides (Okta, Entra ID) - distinct from |
| 100 | + the generic OIDC/OAuth auth docs in OSS |
| 101 | +- Enterprise Cloud UI administration (the full CRUD management |
| 102 | + console) |
| 103 | +- Enterprise Connectors catalog and qualification guides |
| 104 | +- Canonical policy packs (pre-built read-only, full CRUD, and custom |
| 105 | + Cedar policy sets) |
| 106 | + |
| 107 | +**Enterprise-specific sections within existing pages:** marked with a |
| 108 | +custom admonition or component. These appear inline in OSS docs as a |
| 109 | +natural upsell, showing Enterprise users what's available and giving |
| 110 | +OSS users a reason to upgrade. Examples: |
| 111 | + |
| 112 | +```mdx title="In the Desktop UI guide" |
| 113 | +:::enterprise |
| 114 | + |
| 115 | +The Enterprise distribution of the Desktop UI includes a |
| 116 | +**configuration server** that lets administrators enforce lockdown |
| 117 | +controls across your organization - restricting which MCP servers |
| 118 | +can be installed, enforcing approved registries, and managing |
| 119 | +update policies centrally. |
| 120 | + |
| 121 | +[Learn more about Stacklok Enterprise](/toolhive/enterprise). |
| 122 | + |
| 123 | +::: |
| 124 | +``` |
| 125 | + |
| 126 | +```mdx title="In the auth/identity guide" |
| 127 | +:::enterprise |
| 128 | + |
| 129 | +Stacklok Enterprise includes turnkey integrations for common |
| 130 | +identity providers. Instead of manually configuring OIDC, use the |
| 131 | +built-in Okta or Entra ID integration to map IdP groups directly |
| 132 | +to ToolHive roles and policy sets. |
| 133 | + |
| 134 | +[Learn more about Stacklok Enterprise](/toolhive/enterprise). |
| 135 | + |
| 136 | +::: |
| 137 | +``` |
| 138 | + |
| 139 | +```mdx title="In the MCP server management guide" |
| 140 | +:::enterprise |
| 141 | + |
| 142 | +Enterprise Connectors are production-ready MCP servers maintained |
| 143 | +on the Enterprise release cadence, built on hardened base images |
| 144 | +(Chainguard or equivalent), signed with SigStore, and qualified |
| 145 | +for target workloads. They include backported security patches and |
| 146 | +SBOM/dependency vetting. |
| 147 | + |
| 148 | +[Learn more about Stacklok Enterprise](/toolhive/enterprise). |
| 149 | + |
| 150 | +::: |
| 151 | +``` |
| 152 | + |
| 153 | +Both patterns snapshot cleanly with Docusaurus versioning - no special |
| 154 | +handling needed at version cut time. |
| 155 | + |
| 156 | +### Auto-generated reference content |
| 157 | + |
| 158 | +Auto-generated content (CLI reference, API specs, CRD specs) is |
| 159 | +produced upstream and pulled into the docs repo on release. |
| 160 | + |
| 161 | +**CLI reference and API specs:** these are already pulled in per |
| 162 | +release. When an Enterprise version is cut, the snapshot captures |
| 163 | +whatever reference docs are current at that point. |
| 164 | + |
| 165 | +**CRD specs:** use separate pages per CRD API version (e.g., |
| 166 | +`crd-spec-v1alpha1.md`, `crd-spec-v1beta1.md`) since the upstream |
| 167 | +generation has limited customization options and CRD versions may |
| 168 | +coexist. |
| 169 | + |
| 170 | +### Version cut process |
| 171 | + |
| 172 | +Enterprise development continuously syncs and pins the latest |
| 173 | +upstream releases. When an Enterprise release is cut, the pinned |
| 174 | +upstream versions are typically the latest available. This means |
| 175 | +`main` already reflects the correct component versions at cut |
| 176 | +time, and the snapshot can usually be taken directly from `main` |
| 177 | +HEAD. |
| 178 | + |
| 179 | +See [enterprise-version-cut-process.md](enterprise-version-cut-process.md) |
| 180 | +for the full worked example and validated process. |
| 181 | + |
| 182 | +**Happy path (most releases):** |
| 183 | + |
| 184 | +1. Verify all pinned-version docs PRs have merged to `main`. |
| 185 | +2. Add enterprise overlay content to `main` (enterprise-only |
| 186 | + pages, `:::enterprise` admonitions). |
| 187 | +3. Run `npx docusaurus docs:version <version>` on `main`. |
| 188 | +4. Add the version-specific Docusaurus config. |
| 189 | +5. Prune versions older than N-2. |
| 190 | +6. Commit and deploy via PR. |
| 191 | + |
| 192 | +**Fallback - release branch:** if a component is rolled back to an |
| 193 | +older version (e.g., a late regression in v0.23.0 forces a pin to |
| 194 | +v0.22.0 after v0.23.0 docs have already landed), a release branch |
| 195 | +from the right point in `main`'s history is needed. See the |
| 196 | +process doc for the branch-based approach. |
| 197 | + |
| 198 | +This is a quality forcing function, not a guarantee of perfection. |
| 199 | +The goal is "accurate enough" at cut time, with the understanding |
| 200 | +that narrative docs may have minor drift. |
| 201 | + |
| 202 | +**Upstream requirement:** this process depends on each pinned |
| 203 | +component version being fully documented before the cut. The |
| 204 | +release-triggered docs PR for each component version is the |
| 205 | +completeness gate - see the process doc for details. |
| 206 | + |
| 207 | +### Automated docs pipeline integration |
| 208 | + |
| 209 | +A parallel initiative is introducing automated, release-triggered docs |
| 210 | +PRs: when an OSS component release is cut, a docs PR is generated |
| 211 | +with an AI-drafted changelog and review required from contributors |
| 212 | +on that release. |
| 213 | + |
| 214 | +This creates a natural per-component checkpoint. When an Enterprise |
| 215 | +release is cut (comprising specific versions of each OSS component), |
| 216 | +the docs will have already been reviewed in the context of each |
| 217 | +constituent release. This significantly reduces the accuracy gap at |
| 218 | +Enterprise version cut time. |
| 219 | + |
| 220 | +The release-triggered docs PR also serves as a potential automation |
| 221 | +point for the version snapshot itself - the Enterprise release |
| 222 | +pipeline could trigger the `docs:version` command after all component |
| 223 | +docs PRs are merged. |
| 224 | + |
| 225 | +## Release cadence impact |
| 226 | + |
| 227 | +| Cadence | Active versions | Max drift (N-2 to latest) | Maintenance load | |
| 228 | +| --------- | --------------- | ------------------------- | ------------------------------------------------------ | |
| 229 | +| Monthly | 3 | ~2 months | Low - minimal divergence between versions | |
| 230 | +| Quarterly | 3 | ~6 months | Moderate - guides and UI docs may diverge meaningfully | |
| 231 | + |
| 232 | +Starting monthly and moving to quarterly as the product stabilizes. |
| 233 | +The quarterly cadence is where cross-version maintenance becomes a |
| 234 | +real concern - at that point, the automated docs pipeline and |
| 235 | +per-release review process will be critical for keeping versions |
| 236 | +accurate. |
| 237 | + |
| 238 | +## Risks and mitigations |
| 239 | + |
| 240 | +**Maintenance burden of versioned snapshots.** Each snapshot is a full |
| 241 | +copy of every doc page. A typo fix or security correction must be |
| 242 | +patched in up to 4 places (current + 3 versions). |
| 243 | + |
| 244 | +- _Mitigation:_ Prune at N-2 to limit active versions. Automate |
| 245 | + cherry-picking of critical fixes to active versions. Accept that |
| 246 | + non-critical fixes only go into current. |
| 247 | + |
| 248 | +**Docs not matching Enterprise release at cut time.** The Enterprise |
| 249 | +release pins specific upstream versions, but docs may describe |
| 250 | +features not yet in that release. |
| 251 | + |
| 252 | +- _Mitigation:_ Release-triggered docs PRs reduce the gap. A |
| 253 | + lightweight review checklist at cut time catches obvious issues. |
| 254 | + Perfect accuracy is a non-goal - "useful and mostly correct" is the |
| 255 | + bar. |
| 256 | + |
| 257 | +**Search engine indexing of versioned pages.** Duplicate content |
| 258 | +across versions can dilute SEO. |
| 259 | + |
| 260 | +- _Mitigation:_ Set `noIndex: true` in the version config (validated |
| 261 | + in spike). Docusaurus also sets canonical URLs to the latest |
| 262 | + version by default. Verify both are working correctly after the |
| 263 | + first production version cut. |
| 264 | + |
| 265 | +**Build time and repo size growth.** Each version snapshot adds a full |
| 266 | +copy of the docs directory. |
| 267 | + |
| 268 | +- _Mitigation:_ Prune at N-2. Monitor build times after first few |
| 269 | + cuts. If repo size becomes an issue, consider moving versioned docs |
| 270 | + to a separate branch or git subtree. |
| 271 | + |
| 272 | +## Implementation phases |
| 273 | + |
| 274 | +### Phase 1: Foundation |
| 275 | + |
| 276 | +- Add the custom `:::enterprise` admonition component. |
| 277 | +- Create separate CRD spec pages per API version |
| 278 | + (`crd-spec-v1alpha1.md`, `crd-spec-v1beta1.md`). |
| 279 | +- Add initial enterprise-specific inline content to existing pages. |
| 280 | + |
| 281 | +### Phase 2: First version cut |
| 282 | + |
| 283 | +- Follow the release branch process to cut the first Enterprise |
| 284 | + version snapshot (see |
| 285 | + [enterprise-version-cut-process.md](enterprise-version-cut-process.md)). |
| 286 | +- Add the `lastVersion`, `versions`, and `docsVersionDropdown` |
| 287 | + config to `docusaurus.config.ts` (config validated in spike - |
| 288 | + see Docusaurus configuration above). |
| 289 | +- Suppress the default version banner with `banner: 'none'`. |
| 290 | +- Verify URL structure (`/enterprise/<version>/toolhive/...`), |
| 291 | + `noIndex` on versioned pages, and version dropdown navigation. |
| 292 | + |
| 293 | +### Phase 3: Automation |
| 294 | + |
| 295 | +- Integrate version cut into Enterprise release pipeline. |
| 296 | +- Automate pruning of versions older than N-2. |
| 297 | +- Connect release-triggered docs PRs to version snapshot process. |
| 298 | + |
| 299 | +## Open questions |
| 300 | + |
| 301 | +- **Version label format:** `1.0`, `v1.0`, or `2026.04`? Should align |
| 302 | + with the Enterprise product versioning scheme. |
| 303 | +- **Version switcher UX:** ~~Should Enterprise users see a version |
| 304 | + dropdown in the navbar, or is URL-based navigation sufficient?~~ |
| 305 | + **Decision: navbar version picker.** The dropdown serves double duty |
| 306 | + as a wayfinding indicator for Enterprise users on pinned versions and |
| 307 | + as a discovery/upsell moment for OSS users who see Enterprise |
| 308 | + versions listed. Docusaurus supports this natively via the |
| 309 | + `docsVersionDropdown` navbar item. |
| 310 | +- **Backport policy:** Which types of doc fixes warrant backporting to |
| 311 | + older versions? Suggest limiting to factual errors and security |
| 312 | + content. |
| 313 | +- **Enterprise content gating:** ~~Is the inline enterprise content |
| 314 | + purely informational (visible to all, with CTA), or should any of |
| 315 | + it be gated behind authentication?~~ **Decision: no gating.** All |
| 316 | + documentation, including Enterprise-specific content, is public. |
| 317 | + No plans for gated material on the docs site. |
0 commit comments