| name | docs-as-code |
| description | Documentation pipeline automation and docs-as-code workflows |
| allowed-tools | Read, Glob, Grep, Write, Edit, Bash |
Docs-as-Code Skill
When to Use This Skill
Use this skill when:
- Docs As Code tasks - Working on documentation pipeline automation and docs-as-code workflows
- Planning or design - Need guidance on Docs As Code approaches
- Best practices - Want to follow established patterns and standards
Overview
Implement documentation-as-code workflows with automated pipelines, version control, and CI/CD integration.
MANDATORY: Documentation-First Approach
Before implementing docs-as-code:
- Invoke
docs-management skill for documentation patterns
- Verify tooling versions via MCP servers (context7 for docusaurus/mkdocs)
- Base guidance on current best practices
Docs-as-Code Philosophy
Docs-as-Code Principles:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. Version Control │
│ - Docs live alongside code in the same repository │
│ - Changes tracked with meaningful commit messages │
│ - Branch-based workflow for documentation updates │
├─────────────────────────────────────────────────────────────────────────────┤
│ 2. Review Process │
│ - Pull requests for documentation changes │
│ - Technical review by subject matter experts │
│ - Style review by technical writers │
├─────────────────────────────────────────────────────────────────────────────┤
│ 3. Automated Testing │
│ - Linting for style and grammar │
│ - Link validation │
│ - Build verification │
├─────────────────────────────────────────────────────────────────────────────┤
│ 4. Continuous Deployment │
│ - Automatic publishing on merge │
│ - Preview deployments for PRs │
│ - Versioned documentation releases │
└─────────────────────────────────────────────────────────────────────────────┘
Documentation Tooling Comparison
| Tool | Language | Best For | Build Speed |
|---|
| Docusaurus | JS/React | Product docs, versioning | Fast |
| MkDocs | Python | Technical docs, Material theme | Fast |
| Sphinx | Python | API docs, reStructuredText | Medium |
| Hugo | Go | Large sites, speed | Very Fast |
| Astro | JS | Modern sites, MDX | Fast |
| VitePress | JS/Vue | Vue ecosystem | Very Fast |
| Jekyll | Ruby | GitHub Pages native | Medium |
Project Structure
Docusaurus Structure
docs/
├── docusaurus.config.js # Main configuration
├── sidebars.js # Navigation structure
├── package.json # Dependencies
├── docs/ # Documentation content
│ ├── intro.md
│ ├── getting-started/
│ │ ├── installation.md
│ │ └── configuration.md
│ ├── guides/
│ │ ├── quick-start.md
│ │ └── advanced.md
│ └── api/
│ └── reference.md
├── blog/ # Blog posts (optional)
├── src/
│ ├── components/ # React components
│ ├── css/ # Custom styles
│ └── pages/ # Custom pages
├── static/ # Static assets
│ └── img/
└── versioned_docs/ # Version snapshots
├── version-1.0/
└── version-2.0/
MkDocs Structure
docs/
├── mkdocs.yml # Configuration
├── docs/
│ ├── index.md
│ ├── getting-started/
│ │ ├── installation.md
│ │ └── configuration.md
│ ├── user-guide/
│ │ └── features.md
│ ├── reference/
│ │ └── api.md
│ └── about/
│ └── changelog.md
├── overrides/ # Theme customization
│ ├── main.html
│ └── partials/
└── requirements.txt # Python dependencies
Configuration Templates
Docusaurus Configuration
const config = {
title: 'Project Name',
tagline: 'Project tagline',
url: 'https://docs.example.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
organizationName: 'organization',
projectName: 'project',
i18n: {
defaultLocale: 'en',
locales: ['en'],
},
presets: [
[
'classic',
{
docs: {
sidebarPath: require.resolve('./sidebars.js'),
editUrl: 'https://github.com/org/project/edit/main/docs/',
showLastUpdateAuthor: true,
showLastUpdateTime: true,
versions: {
current: {
label: 'Next',
path: 'next',
},
},
},
blog: {
showReadingTime: true,
editUrl: 'https://github.com/org/project/edit/main/docs/',
},
: {
: .(),
},
},
],
],
: {
: {
: ,
: {
: ,
: ,
},
: [
{ : , : , : , : },
{ : , : , : },
{ : , : },
{ : , : , : },
],
},
: {
: ,
: [
{
: ,
: [{ : , : }],
},
{
: ,
: [{ : , : }],
},
],
: ,
},
: {
: (),
: (),
: [, , ],
},
: {
: ,
: ,
: ,
},
},
};
. = config;
MkDocs Configuration
site_name: Project Documentation
site_url: https://docs.example.com
repo_url: https://github.com/org/project
repo_name: org/project
edit_uri: edit/main/docs/
theme:
name: material
palette:
- scheme: default
primary: indigo
accent: indigo
toggle:
icon: material/brightness-7
name: Switch to dark mode
- scheme: slate
primary: indigo
accent: indigo
toggle:
icon: material/brightness-4
name: Switch to light mode
features:
- navigation.instant
- navigation.tracking
- navigation.tabs
- navigation.sections
CI/CD Pipeline Templates
GitHub Actions for Docusaurus
name: Documentation
on:
push:
branches: [main]
paths:
- 'docs/**'
- '.github/workflows/docs.yml'
pull_request:
branches: [main]
paths:
- 'docs/**'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: docs/package-lock.json
- name: Install dependencies
working-directory: docs
run: npm ci
- name: Lint Markdown
run: npx markdownlint-cli2
Azure DevOps for MkDocs
trigger:
branches:
include:
- main
paths:
include:
- docs/**
pool:
vmImage: 'ubuntu-latest'
variables:
pythonVersion: '3.11'
stages:
- stage: Validate
jobs:
- job: Lint
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(pythonVersion)'
- script: |
pip install -r docs/requirements.txt
pip install markdownlint-cli2
displayName: 'Install dependencies'
- script: markdownlint-cli2 "docs/**/*.md"
displayName: 'Lint Markdown'
- stage: Build
dependsOn: Validate
jobs:
- job: Build
steps:
-
Documentation Linting
Markdownlint Configuration
{
"default": true,
"MD001": true,
"MD003": { "style": "atx" },
"MD004": { "style": "dash" },
"MD007": { "indent": 2 },
"MD009": true,
"MD010": true,
"MD012": true,
"MD013": { "line_length": 120, "code_blocks":
Vale Configuration
StylesPath = styles
MinAlertLevel = suggestion
Packages = Microsoft, write-good, proselint
[*.md]
BasedOnStyles = Vale, Microsoft, write-good
BlockIgnores = (?s) *(`{3}.*?`{3})
Microsoft.Contractions = NO
Microsoft.HeadingPunctuation = YES
write-good.Passive = YES
write-good.Weasel = YES
write-good.TooWordy = YES
Living Documentation
Generating API Docs from Code
{
Task<Result<AuthenticationResponse>> AuthenticateAsync(
AuthenticationCredentials credentials,
CancellationToken cancellationToken = );
}
OpenAPI Documentation Generation
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Project API",
Version = "v1",
Description = "API documentation for the Project",
Contact = new OpenApiContact
{
Name = "API Support",
Email = "api@example.com",
Url = new Uri("https://docs.example.com")
},
License = new OpenApiLicense
{
Name = "MIT",
Url = new Uri("https://opensource.org/licenses/MIT")
}
});
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
Documentation Testing
Link Checking
import { remark } from 'remark';
import remarkLintNoDeadUrls from 'remark-lint-no-dead-urls';
import { read } from 'to-vfile';
import { glob } from 'glob';
import { reporter } from 'vfile-reporter';
const files = await glob('docs/**/*.md');
for (const file of files) {
const result = await remark()
.use(remarkLintNoDeadUrls, {
skipLocalhost: true,
skipOffline: true,
})
.process(await read(file));
console.error(reporter(result));
}
Screenshot Testing
import { test, expect } from '@playwright/test';
test.describe('Documentation Screenshots', () => {
test('homepage renders correctly', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png');
});
test('API reference page', async ({ page }) => {
await page.goto('/docs/api/reference');
await expect(page.locator('.api-content')).toBeVisible();
await expect(page).toHaveScreenshot('api-reference.png');
});
test('dark mode toggle', async ({ page }) => {
await page.goto('/');
await page.click('[data-theme-toggle]');
await expect(page).toHaveScreenshot('homepage-dark.png');
});
});
Best Practices
Content Organization
| Practice | Description |
|---|
| Single Source of Truth | Each concept documented in one place |
| Progressive Disclosure | Start simple, link to details |
| Consistent Structure | Same sections across similar pages |
| Clear Navigation | Logical hierarchy, breadcrumbs |
| Search Optimization | Good headings, keywords, descriptions |
Writing Guidelines
- Use active voice: "Configure the setting" not "The setting should be configured"
- Be concise: Remove unnecessary words
- Use examples: Show, don't just tell
- Maintain consistency: Same terms throughout
- Update regularly: Documentation rots quickly
Versioning Strategy
Documentation Versioning:
Option 1: Version Folders (Docusaurus/MkDocs mike)
├── docs/
│ ├── version-1.0/
│ ├── version-2.0/
│ └── current/
Option 2: Branch-based
├── main (current)
├── v1.x
└── v2.x
Option 3: Git Tags
├── v1.0.0
├── v2.0.0
└── latest
Recommendation: Use tool-native versioning (Docusaurus versioned_docs, mike for MkDocs)
Workflow
When implementing docs-as-code:
- Choose Tooling: Select SSG based on team skills and requirements
- Set Up Structure: Create organized folder hierarchy
- Configure CI/CD: Automated builds, previews, deployments
- Add Linting: Markdown linting, link checking, spell check
- Enable Reviews: PR-based workflow with tech writer review
- Deploy Versioning: Set up version management strategy
- Monitor Analytics: Track usage, search queries, gaps
References
For detailed guidance:
Last Updated: 2025-12-26