name: vcluster-docs-writer description: 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. context: fork
vCluster Documentation Writer
Specialized knowledge and workflows for writing vCluster documentation in Docusaurus.
Dependencies
When this skill is loaded, also invoke: vcluster-brand:vcluster-brand
When to Use
Trigger when:
- Working in
/home/decoder/loft/vcluster-docsrepository - User asks to write, edit, review, or fix documentation
- User mentions: vale, partials, doc links, versioned docs, releases
- User needs to discover partials, components, or code blocks
- User asks about vCluster terminology or style guidelines
Quick Workflows
Writing New Documentation
- Review style guidelines in
references/style-guide.md - Follow document template structure (Overview → How to use → Examples → Limitations)
- Discover available resources:
scripts/discover_partials.sh # Find partials scripts/detect_language.sh <file> # Get language identifier scripts/generate_import.sh <path> # Generate import statement - Run vale for style checking:
scripts/run_vale.sh <file-path> - Verify links before committing (see Link Validation below)
See references/style-guide.md for complete writing guidelines.
Editing Existing Documentation
- Check if file is versioned (
vcluster_versioned_docs/version-*/)- ⚠️ CRITICAL: NEVER modify versioned docs unless explicitly requested
- Only update files in main
vcluster/folder for current docs
- Run vale before and after edits:
scripts/run_vale.sh <file-path> - Verify links if modified (see Link Validation below)
Link Validation and Fixing
Core principle: Use relative file paths with .mdx extensions, NOT URL paths.
❌ WRONG (URL paths):
[Pod Identity](/vcluster/integrations/pod-identity/eks-pod-identity)
✅ CORRECT (file paths with .mdx):
[Pod Identity](../../../../third-party-integrations/pod-identity/eks-pod-identity.mdx)
Debugging broken links efficiently:
cd vcluster_versioned_docs/version-X.X.X/path/from/error/
grep -r "filename-from-error" . --include="*.mdx"
# Fix relative path in file that appears
See references/link-formatting.md for detailed examples and rules.
Release Preparation
⚠️ CRITICAL before cutting new versioned docs release:
- Check for problematic patterns:
grep -r "/vcluster/integrations\|/vcluster/deploy/security" vcluster_versioned_docs/version-X.X.X/ - Fix absolute URL paths → relative file paths (common files listed in reference)
- Clear caches before building:
rm -rf .docusaurus build node_modules/.cache - NEVER run
npm run build- User runs when needed
See references/release-checklist.md for complete release workflow.
Versioned Docs and lastVersion Routing
Critical concept: When lastVersion changes in docusaurus.config.js, URL routing changes.
lastVersion: "0.30.0" → /docs/vcluster/... routes to 0.30.0 content
/docs/vcluster/0.29.0/... routes to 0.29.0 content
Key insight: /docs/vcluster/... (no version) ALWAYS routes to lastVersion content.
Why links break:
- Older versioned docs using unversioned paths resolve to new lastVersion
- Cross-plugin links (vCluster→Platform or Platform→vCluster) resolve to each plugin's lastVersion
- Path restructuring between versions causes 404s
Version isolation principle: Each version should link within itself:
<!-- In 0.29.0 docs - CORRECT -->
[Link](../configure/something.mdx) <!-- relative file path -->
<!-- In 0.29.0 docs - RISKY (resolves to lastVersion) -->
[Link](/docs/vcluster/configure/something) <!-- unversioned URL -->
Cross-plugin links (vCluster→Platform): Always resolve to Platform's lastVersion:
<!-- These will break when Platform restructures paths -->
[Platform docs](/docs/platform/administer/monitoring/...)
<!-- After Platform 4.6.0, this became: -->
[Platform docs](/docs/platform/maintenance/monitoring/...)
Fixing broken links after version release:
# Find unversioned platform links that need updating
grep -r "/docs/platform/administer/\|/platform/api/" vcluster vcluster_versioned_docs --include="*.mdx"
# Bulk fix with sed
find vcluster vcluster_versioned_docs -name "*.mdx" \
-exec sed -i 's|/platform/old/path|/platform/new/path|g' {} \;
Sidebar Navigation Conventions
Docusaurus sidebar categories can be made clickable (navigating to a page on click) in two ways. Both are banned — sidebar section labels must expand/collapse only.
Anti-pattern 1: link field in _category_.json
// WRONG — do not add a link field
{
"label": "Deploy",
"position": 2,
"link": {
"type": "generated-index"
}
}
Remove the link field entirely. The label and position fields are sufficient.
Anti-pattern 2: README.mdx as a folder index (general docs)
Docusaurus automatically converts a README.mdx file into the category's landing page and makes the section label clickable — even without a link in _category_.json. Do not create README.mdx files as folder indices in general docs sections.
Instead, use overview.mdx with an explicit slug: that matches the directory URL:
---
title: Networking
sidebar_label: Overview
sidebar_position: 0
slug: /configure/vcluster-yaml/networking
---
When converting an existing README.mdx to overview.mdx:
- Add
slug:matching the directory's URL (plugin-relative, no/vcluster/prefix). - Set
sidebar_label: Overview— not the section name, to avoid duplication. - Migrate
sidebar_positionandsidebar_class_nameout of the MDX frontmatter and into_category_.jsonaspositionandclassNamerespectively. The_category_.jsoncontrols the section label in the sidebar; theoverview.mdxfrontmatter controls only the child item. - Update any relative links inside the file that previously resolved from a directory URL — they now resolve from the slug URL.
_category_.json structure for a folder that has an overview.mdx:
{
"label": "Networking",
"position": 3,
"className": "host-nodes private-nodes"
}
Do not add a link field.
Exception: vcluster/configure/vcluster-yaml/ uses README.mdx
The vcluster-yaml section mirrors the structure of the vcluster.yaml config file — every folder is a yaml key. Labeling these pages "Overview" is semantically wrong because there is no overview key in the yaml. In this section only, use README.mdx (not overview.mdx) as the folder index. Docusaurus treats it as the category header click target; it does not appear as a named sidebar item. Do NOT set sidebar_label: Overview or sidebar_position: 0 on these files — they are irrelevant once the file becomes the category index.
PR Preview URLs
Preview links MUST point to actual changed pages, NOT the docs root.
Base: https://deploy-preview-{PR}--vcluster-docs-site.netlify.app/docs
Derive the path from the file location — version goes after product name:
docs/platform/install/x.mdx→/docs/platform/next/install/xdocs/vcluster/deploy/x.mdx→/docs/vcluster/next/deploy/xversioned_docs/version-0.31/vcluster/deploy/x.mdx→/docs/vcluster/0.31/deploy/xversioned_docs/version-0.28/platform/api/x.mdx→/docs/platform/0.28/api/x
The version marked as lastVersion in docusaurus.config.ts has NO version segment in the URL. For example, if platform lastVersion is 4.6.0, then versioned_docs/version-4.6.0/platform/install/x.mdx → /docs/platform/install/x.
List a preview link for EVERY modified document in the PR body's Preview section.
Backporting Assessment
New work typically lands in docs/ (the next version). Before completing a PR, assess whether changes should also apply to released versions in versioned_docs/:
- Backport: Factual errors, broken links, typos — apply to relevant prior versions
- Don't backport: New feature documentation — only applies to
next - When unclear: Note in the PR description that backporting should be reviewed
When backporting: make the same changes in relevant versioned_docs/version-X.XX/ folders and include preview links for those versions too.
Integration Tests (BrowserStack)
Cross-browser tests for documentation rendering (mermaid diagrams, etc.).
Location: tests/ directory
Structure:
tests/
├── specs/ # Test files go here
│ └── mermaid-rendering.spec.js
├── browserstack.yml # BrowserStack SDK config
├── playwright.config.js # Playwright config
└── package.json
Creating new tests:
- Create spec file in
tests/specs/with.spec.jsextension - Use Playwright Test format:
const { test, expect } = require('@playwright/test'); test.describe('Feature Name', () => { test('description', async ({ page }) => { await page.goto(process.env.TEST_URL || 'https://www.vcluster.com/docs/...'); // assertions }); }); - Tests run on 7 browser configs (Safari/Chrome/Firefox on macOS/Windows)
Running tests:
cd tests
npm run test:local # Local Safari only
npm run test:browserstack # All browsers via BrowserStack (needs credentials)
CI: Tests run automatically on PRs via .github/workflows/integration-tests.yml
Partials and Components
Quick commands:
scripts/discover_partials.sh # List all partials
scripts/detect_language.sh file.yml # Get language for code blocks
scripts/generate_import.sh <path> <dir> # Generate import statement
Import patterns:
// Code block with raw loader
import Code from '!!raw-loader!@site/docs/_code/example.yaml';
<CodeBlock language="yaml">{Code}</CodeBlock>
// Regular partial
import Partial from '@site/docs/_partials/example.mdx';
<Partial />
See references/partials-guide.md for complete patterns and troubleshooting.
Critical Rules
Never-Do
- ⚠️ NEVER modify versioned docs unless explicitly requested
- ⚠️ NEVER run
npm run build(user runs when needed) - ⚠️ NEVER use URL paths for links (use file paths with
.mdx) - ⚠️ NEVER place admonitions inside JSX components like
<Step> - ⚠️ NEVER add a
linkfield to_category_.json— sidebar section labels must expand/collapse only, not navigate - ⚠️ NEVER create
README.mdxas a folder index in general docs sections — useoverview.mdxwith an explicitslug:instead. Exception:vcluster/configure/vcluster-yaml/usesREADME.mdxbecause every folder is a yaml key and "Overview" is semantically wrong there (see Sidebar Navigation Conventions)
Always-Do
- ✅ Always run vale before finalizing documentation
- ✅ Always use file paths with
.mdxextension for links - ✅ Always check vCluster terminology in
references/vcluster-terms.md - ✅ Always use relative paths for versioned content
- ✅ Always add descriptive comments in YAML code blocks
vCluster Terminology Quick Reference
Key terms (see references/vcluster-terms.md for complete guide):
- vCluster: The trademark (never "vClusters" - legally incorrect)
- tenant clusters: The clusters that vCluster creates ("virtual clusters" is retired); lowercase in prose
- control plane cluster: The cluster that hosts tenant cluster control planes ("host cluster" is retired); lowercase in prose
- vCluster Pro: Enhanced/paid tenant cluster with Pro functionality
- vCluster Platform: Management platform and UI for tenant clusters
- vcluster: The CLI command name
Resources
scripts/
discover_partials.sh- Find all _partials, _fragments, _code directoriesdetect_language.sh- Map file extension to language identifierrun_vale.sh- Run vale linter with proper configurationgenerate_import.sh- Generate correct import statement
references/
style-guide.md- Complete writing style guide from CONTRIBUTING.mdrelease-checklist.md- Critical rules for documentation releaseslink-formatting.md- Link formatting rules with examplespartials-guide.md- Complete partials and components guidemdx-components.md- MDX/JSX component usage and admonition rulesvcluster-terms.md- vCluster product terminology and naming