mit einem Klick
mit einem Klick
vCluster Documentation Release Skill
Write and edit vCluster Docusaurus documentation. Use this skill when working with .mdx or .md files in the vcluster-docs repository. Handles vale linting, partials discovery, link validation, versioned docs, and release processes.
Archive End-of-Life vCluster documentation versions. Use this skill when creating EOL documentation branches for vCluster or Platform versions. Handles branch creation, Docusaurus configuration, link fixing, Netlify deployment, and main branch updates.
Manages the Kubernetes compatibility matrix data and React component. Use when adding/removing K8s versions, updating conformance test results, or documenting known issues.
Generate MDX config reference partials from vCluster JSON schema. Use when automation is skipped for alpha releases or when manually refreshing config docs.
Upgrades Docusaurus to latest version in vCluster documentation. Use when upgrading Docusaurus packages from older to newer versions. Handles package updates, compatibility fixes, testing, and rollback procedures.
| name | platform-docs-releaser |
| description | Platform Documentation Release Skill |
This skill automates the vCluster Platform documentation release process, handling API generation, version updates, configuration changes, and SEO setup for new Platform releases.
Starting with Platform v4.8, docs versioning happens at rc-1, NOT on release day.
platform/ on main as usual. If a change needs to land in the upcoming release, add the backport-v4.8.0 label to the PRThe config flip PR changes only the version visibility in docusaurus.config.js:
lastVersion to point to the new versionThis separation means all the heavy lifting (version creation, API partials, content, link fixes) is done during the rc-1 window, and release day is a low-risk config change.
Trigger this skill when:
Note: This skill is for Platform releases only. vCluster releases have a separate skill (vcluster-docs-releaser).
Before starting:
npm run docusaurus docs:version:platform X.Y.Zplatform_versions.json and platform_versioned_docs/version-X.Y.Z/ existconfigsrc/vcluster/main/vcluster.schema.jsonCRITICAL FIRST STEP: Platform releases require updating the Go API dependency and regenerating API documentation partials before any other changes.
The generator at hack/platform/partials/main.go produces docs from two sources:
github.com/loft-sh/api/v4 — platform config fields, resource references (must match the new platform version)Process:
Bump github.com/loft-sh/api/v4 to the version matching the new platform release:
go get github.com/loft-sh/api/v4@vX.Y.Z # e.g. v4.9.0
go mod tidy
go mod vendor
The api module version tracks the platform version (platform v4.9.x → api v4.9.x). Check available tags with:
cd ~/git/vcluster/api && git tag | sort -V | grep "^vX\.Y" | tail -5
Use the highest stable tag for the target minor version (e.g. v4.9.1 over v4.9.0-rc.1).
Locate the vCluster schema file:
ls configsrc/vcluster/main/vcluster.schema.json
Run the Go generation script:
go run hack/platform/partials/main.go configsrc/vcluster/main/vcluster.schema.json
This generates/updates API documentation in:
platform/api/_partials/resources/ - API resource documentationconfig/reference.mdx, config/status_reference.mdx)Audit deleted files for cross-plugin consumers. The generator removes the entire platform/api/_partials/resources/ directory before regenerating. When an API field is removed, its partial files disappear. Frozen versioned vCluster docs (0.28–0.33, etc.) may still import those files via @site/platform/api/_partials/.... Check for any such orphaned imports:
# List files the generator just deleted (compared to git HEAD)
git diff --name-status platform/api/_partials/resources/ | grep "^D"
# For each deleted path, check if any versioned vCluster docs import it
git diff --name-status platform/api/_partials/resources/ | grep "^D" | awk '{print $2}' | \
xargs -I{} basename {} | \
xargs -I{} grep -rl "{}" vcluster_versioned_docs/ --include="*.mdx"
If any versioned doc still imports a deleted partial, add the path to .generator-preserve (see API Partials Generation section below).
Why this matters: The Go types in api/v4 define the platform config schema. If the dependency is stale, new config fields (like database) will be missing from the docs and removed fields will remain as dead content.
IMPORTANT: Understand the difference between versioned and non-versioned partials.
Two types of imports:
Same-plugin imports (platform→platform/_partials):
// ✅ CORRECT - relative path for platform's own partials
import InstallNextSteps from "../../_partials/install/install-next-steps.mdx";
import BasePrerequisites from '../../_partials/install/base-prerequisites.mdx';
Cross-plugin imports (platform→vcluster/_partials or platform→docs/_partials):
// ✅ CORRECT - @site for shared cross-plugin partials
import InstallCli from '@site/vcluster/_partials/deploy/install-cli.mdx';
import KubeconfigUpdate from '@site/docs/_partials/kubeconfig_update.mdx';
import ProAdmonition from '@site/vcluster/_partials/admonitions/pro-admonition.mdx';
// ❌ WRONG - relative paths break when versioned
import InstallCli from '../../../vcluster/_partials/deploy/install-cli.mdx';
Why this matters:
npm run docusaurus docs:version:platform runs, same-plugin partials copy WITH the docs (relative paths still work)@site alias (absolute)Files that need @site for cross-plugin imports:
platform/install/environments/{aws,azure,gcp}.mdxplatform/install/quick-start-guide.mdxplatform/understand/what-are-virtual-clusters.mdxVerification command:
# Find cross-plugin imports using relative paths (should use @site instead)
grep -r "import.*\.\./\.\./\.\./vcluster\|import.*\.\./\.\./\.\./docs" platform/ --include="*.mdx" -l
At rc-1, the version is added to the build but hidden from the dropdown. Do NOT change lastVersion, SEO, netlify redirect, or announcement bar — those are Part 5 (release day).
docusaurus.config.js — Platform plugin configAdd the new version to onlyIncludeVersions and versions with hidden/unreleased flags:
lastVersion: "X.Z.0", // DO NOT CHANGE — stays on current stable
onlyIncludeVersions: ["current", "X.Y.0", "X.Z.0", ...], // Add new version
versions: {
current: {
label: "main 🚧",
},
"X.Y.0": { // NEW ENTRY — hidden pre-release
label: "vX.Y",
banner: "unreleased", // Shows warning banner on every page
badge: true,
noIndex: true, // Prevents search engine indexing
},
"X.Z.0": { // KEEP as-is — still current stable
label: "vX.Z Stable",
banner: "none",
badge: true,
},
// ... rest unchanged
}
src/config/versionConfig.js — hide from dropdownAdd the version to the hidden array so it doesn't appear in the version dropdown:
export const vclusterHiddenVersions = [];
export const platformHiddenVersions = ["X.Y.0"];
This is the single source of truth for hiding versions. Two custom components consume it:
src/theme/DocSidebar/Desktop/Content/index.js): filters useVersions() and passes visible names to DocsVersionDropdownNavbarItem versions propsrc/theme/TOCCollapsible/index.js): filters useVersions() before renderingResult: the version is built, accessible via direct URL (e.g., /docs/platform/X.Y.0/), shows the "unreleased" banner, but does not appear in the dropdown.
AI performs:
ls -la platform_versioned_docs/version-X.Y.0/ls platform/api/_partials/resources/platformHiddenVersions array in versionConfig.js)User performs:
npm run build (per CLAUDE.md, AI never runs build — user only)If build errors occur: Reference CLAUDE.md for link resolution rules and broken link debugging.
This is the release-day action. All heavy work was done at rc-1. This PR only flips visibility.
PR title: docs: expose Platform X.Y docs in version dropdown
PR body: "Config flip to make the pre-deployed vX.Y docs visible in the version dropdown. All content was deployed at rc-1."
src/config/versionConfig.js — unhide from dropdownexport const platformHiddenVersions = []; // Remove the version string
docusaurus.config.js — promote to stablelastVersion: "X.Y.0", // Was X.Z.0 — now points to new version
versions: {
"X.Y.0": {
label: "vX.Y Stable", // Was "vX.Y" — add "Stable"
banner: "none", // Was "unreleased" — remove banner
badge: true,
// noIndex removed — allow search engine indexing
},
"X.Z.0": {
label: "vX.Z", // Was "vX.Z Stable" — demote
banner: "none",
badge: true,
},
}
docusaurus.config.js — SEO sitemap prioritiesif (item.url.match(/\/vcluster\/0\.XX\.0\//) ||
item.url.match(/\/platform\/X\.Y\.0\//)) {
return { ...item, priority: 1.0, changefreq: 'daily' };
}
docusaurus.config.js — announcement barannouncementBar: {
id: "platform-X-Y-release",
content: '... vCluster Platform X.Y ...',
},
netlify.toml — redirectCRITICAL: Add the redirect for the new lastVersion AND remove the redirect for the previous lastVersion (X.Z.0). The previous version is still in onlyIncludeVersions — its versioned URL serves real content and must not redirect.
# ADD this block for the new lastVersion (canonical URL is the unversioned path)
[[redirects]]
from = "/docs/platform/X.Y.0/*"
to = "/docs/platform/:splat"
status = 301
force = true
# REMOVE the block for X.Z.0 — it is now a live versioned URL, not the lastVersion
Only two categories of versions belong in this redirect section:
lastVersion (whose canonical URL is the unversioned path)onlyIncludeVersionshack/test-platform-X.Y.hurl — create hurl testCopy from previous version, update version numbers. Include cross-version tests (vCluster→Platform links). Hurl tests run AFTER PR is deployed to Netlify preview.
This PR is small, reviewable, and safe to merge by anyone with merge rights.
| File | Changes | Phase |
|---|---|---|
platform/api/_partials/resources/** | Generated API docs | rc-1 |
docusaurus.config.js | Add to onlyIncludeVersions, add version with banner: "unreleased" + noIndex: true | rc-1 |
src/config/versionConfig.js | Add version to platformHiddenVersions array | rc-1 |
docusaurus.config.js | lastVersion, labels, SEO, announcement bar | Release day |
src/config/versionConfig.js | Remove version from platformHiddenVersions | Release day |
netlify.toml | Add redirect for new lastVersion; remove redirect for previous lastVersion | Release day |
hack/test-platform-X.Y.hurl | New test file | Release day |
| Platform support dates file | Release/EOL dates | User |
@site for cross-plugin importsnetlify.tomlnpm run docusaurus docs:version:platform X.Y.Znpm run build4.5.0vX.Y (without patch)vX.Y Stable (current release)vX.Y (EOL) or banner: unmaintained// Platform typically keeps 2-3 versions (current + 2 stable)
versions: {
current: {
label: "main 🚧",
},
"4.5.0": {
label: "v4.5 Stable",
banner: "none",
badge: true,
},
"4.4.0": {
label: "v4.4", // Removed "Stable"
banner: "none",
badge: true,
},
"4.3.0": {
label: "v4.3",
banner: "none",
badge: true,
},
}
// When 4.6.0 releases, 4.3.0 might get EOL treatment
The Go script at hack/platform/partials/main.go:
github.com/loft-sh/api/v4 (vendored) to generate platform config and resource reference docsconfig/reference.mdx and config/status_reference.mdxThe Go dependency must be bumped to match the new platform release before running the generator. See Part 1 above.
.generator-preserve — protecting legacy partialsThe generator does os.RemoveAll on all of platform/api/_partials/resources/ before regenerating. When an API field is removed, its partial files are deleted permanently. This breaks frozen versioned vCluster docs that still import those files via @site/platform/api/_partials/....
platform/api/_partials/resources/.generator-preserve lists paths (relative to that directory) that are backed up before RemoveAll and restored afterward:
# Example entry
config/external.mdx
config/external/
The manifest file itself is always preserved. To protect a new path, add it to the file — no code change required. Current entries and their reason are documented with comments in the file.
If the schema path changes, check:
configsrc/vcluster/main/vcluster.schema.json (typical location)configsrc/vcluster/vX.Y/vcluster.schema.json (version-specific)# 1. Bump api/v4 dependency to match new platform version
go get github.com/loft-sh/api/v4@vX.Y.Z
go mod tidy
go mod vendor
# 2. Generate API partials
go run hack/platform/partials/main.go configsrc/vcluster/main/vcluster.schema.json
# 3. Verify partials generated
ls platform/api/_partials/resources/ | wc -l # Should have multiple files
# 4. Review what changed in the generated partials
git diff --stat platform/api/
# 5. Verify other changes
git diff docusaurus.config.js netlify.toml
# 6. Check versions
cat platform_versions.json
# Run hurl tests
hurl --test --variable BASE_URL=https://deploy-preview-XXXX--vcluster-docs-site.netlify.app \
hack/test-platform-X.Y.hurl
Solution:
cd hack/platform/partials && go mod downloadSolution: User already ran versioning command - proceed with config updates
Solution: User responsibility - they run npm run build
Solution:
Solution:
Cause: The generator deleted a partial that frozen versioned vCluster docs still import via @site/platform/api/_partials/....
Solution:
platform/api/_partials/resources/.generator-preserve (one relative path per line)git show <last-good-commit>:"platform/api/_partials/resources/config/external.mdx" > \
platform/api/_partials/resources/config/external.mdx
# Repeat for each deleted file
go run hack/platform/partials/main.go configsrc/vcluster/main/vcluster.schema.json
ls platform/api/_partials/resources/config/external.mdx # should still exist
.generator-preserve explaining which versioned docs depend on the file and why it can't be removed yet.Root Cause Understanding: When lastVersion changes in docusaurus.config.js, URL routing fundamentally changes.
lastVersion: "4.6.0" → /docs/platform/... routes to 4.6.0 content
/docs/platform/4.5.0/... routes to 4.5.0 content
/docs/platform/4.4.0/... routes to 4.4.0 content
Key insight: /docs/platform/... (no version) ALWAYS routes to lastVersion content.
/docs/platform/... links will now resolve to 4.6.0 contentconfigure/config.mdx moved to configure/introduction.mdx)RULE: Each version should link within itself using version prefixes.
<!-- In 4.5.0 docs - CORRECT -->
[Link](/docs/platform/4.5.0/configure/config)
<!-- In 4.5.0 docs - WRONG (will resolve to 4.6.0) -->
[Link](/docs/platform/configure/config)
When releasing a new version, check if these paths changed:
administer/monitoring/... → maintenance/monitoring/...install/advanced/air-gapped → install/air-gappedadminister/users-permissions/... → administer/authentication/...api/authentication → administer/authentication/access-keysconfigure/config.mdx → configure/introduction.mdxdocs/_partials/) → use versioned paths or update to new structure# Add version prefix to older platform docs
find platform_versioned_docs/version-4.5.0 -name "*.mdx" \
-exec sed -i 's|/docs/platform/configure/|/docs/platform/4.5.0/configure/|g' {} \;
# Update vCluster cross-plugin links to new paths
find vcluster vcluster_versioned_docs -name "*.mdx" \
-exec sed -i 's|/platform/administer/monitoring/|/platform/maintenance/monitoring/|g' {} \;
Versions NOT in onlyIncludeVersions won't be built:
onlyIncludeVersions: ["current", "4.6.0", "4.5.0", "4.4.0"]
// 4.3.0 NOT included = /docs/platform/4.3.0/... will 404
When removing a version: Update any links pointing to that version to use an included version or the generic path.
When triggered by Linear issue:
After completing workflow, provide summary:
✅ Platform 4.5.0 Release Configuration Complete
Files Updated:
- platform/api/_partials/resources/ (API docs generated)
- platform/ (verified @site alias usage for cross-plugin imports)
- docusaurus.config.js (4 locations)
- netlify.toml (redirect updated)
- hack/test-platform-4.5.hurl (created)
My Tasks Complete (1, 3-5):
✅ Generated API partials
✅ Verified main branch uses @site alias for cross-plugin imports
✅ Updated docusaurus config
✅ Updated netlify redirect
✅ Created hurl test file (including cross-version tests)
Your Tasks Remaining (2, 6-8):
⏳ Review enterprise/pro tags
⏳ Update support dates
⏳ Update compatibility matrix
⏳ Run build: npm run build
⏳ Run hurl tests (after PR deployed)
Ready to commit and push!
Version pattern: 4.5.0 → display: v4.5
Files to modify: 4 types (API partials, config, redirect, tests)
Critical first step: Generate API partials with Go script
Time estimate: 3-5 minutes for AI tasks
backport-v4.8.0 label for changes that must land in the upcoming releasenpm run build