Zum Inhalt

An expert contribution guide

AI usage disclosure

The creation of this document was with the assistance of AI. The author reviewed all content, tested, and verified, its accuracy, and takes full responsibility for the correctness of this document. Please report any errors you encounter to the Rocky Linux documentation team.

Welcome

Thank you for your interest in contributing to the Rocky Linux documentation. Whether you are writing new guides, translating existing content, or editing for clarity, every contribution matters and is deeply valued by the community.

This guide is for contributors who want to set up a full local validation environment with spell checking, Markdown linting, and link checking tools. Setting up these tools is entirely optional, but recommended for first-time contributors. You can also edit documentation directly on GitHub without installing anything locally.

No matter your experience level, the Rocky Linux community is here to help. If you have questions, run into problems, or just want guidance on where to start, join the Mattermost Documentation channel. Someone will be happy to help you get started.

Quick start

  1. Fork the Rocky Linux Documentation repository
  2. Clone your fork locally
  3. Set up pre-commit hooks (optional but recommended)
  4. Create or edit documentation
  5. Run validation checks
  6. Submit a pull request

Prerequisites

Before setting up the local validation environment, you need:

Fork and clone the repository

  1. Navigate to the Rocky Linux documentation repository
  2. Click the Fork button in the upper right corner
  3. Clone your fork to your local machine:
git clone https://github.com/YOUR_USERNAME/documentation.git
cd documentation
  1. Add the upstream repository as a remote:
git remote add upstream https://github.com/rocky-linux/documentation.git

Setting up your environment

Alternative tooling

The setup instructions in this section describe one approach to documentation validation using pre-commit hooks and command-line tools. There are other methods available to check your Markdown documents, before submitting them as a PR.

If you already use a terminal-based editor (Neovim, Emacs, Helix, etc.) with integrated linting tools, you can continue using your existing workflow. Tools like:

  • markdownlint or markdownlint-cli2 - Available as editor plugins for real-time Markdown linting
  • vale - Prose linter that can enforce style guide rules
  • harper-ls - Grammar checker with LSP support
  • ltex-ls - LanguageTool-based grammar and spell checking via LSP

These tools provide the same validation capabilities. You can configure them to match the Rocky Linux documentation standards. The key requirement is that your contributions pass the automated CI checks when you submit a pull request, regardless of which tools you use locally.

Local editors

Choose a markdown editor that suits your workflow:

Graphical editors

  • ReText - Free, cross-platform, open source
  • Zettlr - Free, cross-platform, open source
  • MarkText - Free, cross-platform, open source
  • Remarkable - Linux and Windows, open source
  • Zed - Free, cross-platform, open source, written in Rust. Plugins available for vale, marksman, harper-ls, and markdownlint
  • VS Code - Partially open source, by Microsoft. Recommended extensions: Git Graph, Markdown All in One, Markdown Preview Enhanced, markdownlint

Terminal editors

Terminal editors can integrate the same validation tools used by the pre-commit hooks directly into your editing workflow:

Rocky Linux 10 setup

If you are running Rocky Linux 10, follow these steps to set up a complete documentation validation environment. This installs all required tools that you to run the same checks that the Documentation Team uses to validate pull requests.

Step 1: Install system dependencies

# Note: npm is bundled with nodejs in Rocky Linux 10
sudo dnf install -y git python3-pip hunspell hunspell-en-US nodejs

Step 2: Install Python packages

pip install pre-commit pyspelling

Step 3: Install Node.js packages

sudo npm install -g markdownlint-cli

Lychee is not available in the Rocky Linux repositories, so install the binary directly:

cd /tmp
curl -sLO https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz
tar xzf lychee-x86_64-unknown-linux-gnu.tar.gz
sudo mv lychee /usr/local/bin/
sudo chmod +x /usr/local/bin/lychee
rm -f lychee-x86_64-unknown-linux-gnu.tar.gz

Verify the installation:

lychee --version

Step 5: Clone your forked repository and configure it

git clone https://github.com/YOUR_USERNAME/documentation.git
cd documentation

If you have already cloned the repository, ensure it is up to date:

cd documentation
git pull origin main

Step 6: Verify pyspelling configuration

The repository includes a .pyspelling.yml configured for Hunspell, which is the default spell checker on Rocky Linux 10. You do not need additional configuration. Verify the installation of Hunspell with:

rpm -q hunspell hunspell-en-US

If not installed:

sudo dnf install -y hunspell hunspell-en-US

Step 7: Install pre-commit hooks

pre-commit install

Step 8: Verify your setup

Run all validation checks to confirm everything is working:

pre-commit run --all-files

Expected behavior on first run

When running pre-commit run --all-files for the first time, you might see errors from existing repository files. This is expected behavior:

Hook Expected Result Notes
trailing-whitespace May auto-fix files Changes are staged automatically
end-of-file-fixer May auto-fix files Changes are staged automatically
check-yaml Pass MkDocs config files are excluded
check-added-large-files Pass
markdownlint May show errors
pyspelling Pass (with Hunspell config) Requires Step 6 configuration
lychee Pass Some timeouts are normal

Important: The markdownlint errors you see are in existing repository documentation files, not files you created. When contributing, you only need to ensure your own files pass validation.

Step 9: Validate your document

Before submitting your documentation, validate your specific file to ensure it passes all checks:

# Spell check
pyspelling -n Markdown -S "docs/guides/your-document.md"

# Markdown lint
markdownlint "docs/guides/your-document.md"

# Link check
lychee "docs/guides/your-document.md" --no-progress

Example output for a passing spell check:

pyspelling -n Markdown -S "docs/guides/hpc/slurm-rocky.md"
Spelling check passed :)

Example output for a failing markdown lint check:

markdownlint docs/guides/automation/kickstart-rocky-broken.md
docs/guides/automation/kickstart-rocky-broken.md:1 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "---"]
docs/guides/automation/kickstart-rocky-broken.md:162 error MD001/heading-increment Heading levels should only increment by one level at a time [Expected: h2; Actual: h3]

Example output for a passing link check:

lychee docs/guides/hpc/slurm-rocky.md --no-progress
🔍 8 Total (in 0s) ✅ 8 OK 🚫 0 Errors

Rocky Linux 9 setup

If you are running Rocky Linux 9, follow these steps to set up a complete documentation validation environment. Rocky Linux 9 uses Hunspell for spell checking (aspell is not available in EPEL for Rocky Linux 9).

Step 1: Install system dependencies

sudo dnf install -y git python3-pip hunspell hunspell-en-US nodejs npm

Step 2: Install Python packages

pip install --user pre-commit pyspelling

Step 3: Install Node.js packages

sudo npm install -g markdownlint-cli

Lychee is not available in the Rocky Linux repositories, so install the binary directly:

cd /tmp
curl -sLO https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz
tar xzf lychee-x86_64-unknown-linux-gnu.tar.gz
sudo mv lychee /usr/local/bin/
sudo chmod +x /usr/local/bin/lychee
rm -f lychee-x86_64-unknown-linux-gnu.tar.gz

Verify the installation:

lychee --version

Step 5: Clone your forked repository and configure it

git clone https://github.com/YOUR_USERNAME/documentation.git
cd documentation

Step 6: Verify pyspelling configuration

The repository includes a .pyspelling.yml configured for Hunspell, which is the default spell checker on Rocky Linux 9. You do not need additional configuration. Verify the installation of Hunspell with:

rpm -q hunspell hunspell-en-US

If not installed:

sudo dnf install -y hunspell hunspell-en-US

Step 7: Install pre-commit hooks

~/.local/bin/pre-commit install

Note

When using pip install --user, the pre-commit binary is installed to ~/.local/bin/. You can either use the full path or add ~/.local/bin to your PATH:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Step 8: Verify your setup

Run all validation checks to confirm everything is working:

~/.local/bin/pre-commit run --all-files

Step 9: Validate your document

Before submitting your documentation, validate your specific file to ensure it passes all checks:

# Spell check
pyspelling -n Markdown -S "docs/guides/your-document.md"

# Markdown lint
markdownlint "docs/guides/your-document.md"

# Link check
lychee "docs/guides/your-document.md" --no-progress

Rocky Linux 8 setup

If you are running Rocky Linux 8, follow these steps to set up a complete documentation validation environment. Rocky Linux 8 uses Aspell for spell checking (available from base repositories).

Step 1: Install system dependencies

Rocky Linux 8 uses Python 3.9 and Node.js module streams:

# Install Python 3.9 and other dependencies
sudo dnf install -y git python39-pip python39 aspell aspell-en

# Enable Node.js 18 module stream
sudo dnf module enable -y nodejs:18

# Install Node.js
sudo dnf install -y nodejs

Step 2: Install Python packages

Use Python 3.9's pip:

pip3.9 install --user pre-commit pyspelling

Step 3: Install Node.js packages

sudo npm install -g markdownlint-cli

Lychee is not available in the Rocky Linux repositories, so install the binary directly:

cd /tmp
curl -sLO https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz
tar xzf lychee-x86_64-unknown-linux-gnu.tar.gz
sudo mv lychee /usr/local/bin/
sudo chmod +x /usr/local/bin/lychee
rm -f lychee-x86_64-unknown-linux-gnu.tar.gz

Verify the installation:

lychee --version

Step 5: Clone your forked repository and configure it

git clone https://github.com/YOUR_USERNAME/documentation.git
cd documentation

Step 6: Configure pyspelling for Aspell

The configuration of Hunspell in the repository .pyspelling.yml already exists. Rocky Linux 8 uses Aspell instead, so you need to create a local override. Create a .pyspelling.yml file in the repository root:

cat > .pyspelling.yml << 'EOF'
spellchecker: aspell
matrix:
  - name: Markdown
    sources:
      # Process English files only - exclude translations
      - 'docs/**/*.md|!docs/**/*.{af,de,en,es,fr,hi,id,it,ja,ko,pl,pt,pt-BR,sv,tr,uk,zh}.md'
    expect_match: false
    aspell:
      lang: en
      d: en_US
    dictionary:
      wordlists:
        - .wordlist.txt
      output: build/spelling-wordlist.dic
    pipeline:
      - pyspelling.filters.markdown:
      - pyspelling.filters.html:
          comments: true
          ignores:
            - code
            - pre
            - kbd
      - pyspelling.filters.context:
          context_visible_first: true
          escapes: '\\[\\`]'
          delimiters:
            # Ignore front matter
            - open: '(?s)^---'
              close: '^---'
            # Ignore code blocks
            - open: '(?s)^(?P<open>`{3,}).*$'
              close: '^(?P=open)$'
            # Ignore inline code
            - open: '`'
              close: '`'
            # Ignore URLs
            - open: '\('
              content: 'https?://[^\)]*'
              close: '\)'
            # Ignore email addresses
            - open: '<'
              content: '[^>]+@[^>]+'
              close: '>'
      - pyspelling.filters.url:
EOF

After creating the override, tell Git to ignore your local changes to this file so you do not accidentally commit it:

git update-index --assume-unchanged .pyspelling.yml

This prevents the modified .pyspelling.yml from appearing in git status or staging by git add. If you ever need to undo this (for example, to pull upstream changes to the file), run:

git update-index --no-assume-unchanged .pyspelling.yml

Step 7: Install pre-commit hooks

~/.local/bin/pre-commit install

Note

When using pip install --user, the pre-commit binary is installed to ~/.local/bin/. You can either use the full path or add ~/.local/bin to your PATH:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Step 8: Verify your setup

Run all validation checks to confirm everything is working:

~/.local/bin/pre-commit run --all-files

Step 9: Validate your document

Before submitting your documentation, validate your specific file to ensure it passes all checks:

# Spell check
pyspelling -n Markdown -S "docs/guides/your-document.md"

# Markdown lint
markdownlint "docs/guides/your-document.md"

# Link check
lychee "docs/guides/your-document.md" --no-progress

macOS Sequoia setup

If you are running macOS Sequoia (macOS 15), follow these steps to set up a complete documentation validation environment. These instructions have been tested on both Apple Silicon (M1/M2/M3/M4) and Intel Macs.

Step 1: Install Xcode command line tools

Before installing Homebrew, you must install the Xcode Command Line Tools:

xcode-select --install

A dialog box will appear asking you to install the tools. Click Install and wait for the installation to complete.

Step 2: Install Homebrew (if not already installed)

If you do not have Homebrew installed, run:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Important for Apple Silicon Macs (M1/M2/M3/M4): Homebrew installs to /opt/homebrew on Apple Silicon, which is not in the default PATH. After installation, run these commands to configure your shell:

(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

Verify Homebrew is working:

brew doctor

For Intel Macs

Homebrew installs to /usr/local on Intel Macs, which is already in the default PATH. You need no additional configuration.

Step 3: Install system dependencies

brew install git python node aspell lychee

Step 4: Install Python packages

The recommended approach is to use a virtual environment:

python3 -m venv ~/rocky-docs-env
source ~/rocky-docs-env/bin/activate
pip install pre-commit pyspelling

Add an alias to your shell configuration for easy activation:

echo "alias rocky-docs-env='source ~/rocky-docs-env/bin/activate'" >> ~/.zshrc
source ~/.zshrc

Step 5: Install Node.js packages

If you encounter permission errors with npm global installs, configure npm to use a user directory:

mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

Then install markdownlint:

npm install -g markdownlint-cli

Step 6: Clone your forked repository and configure it

git clone https://github.com/YOUR_USERNAME/documentation.git
cd documentation

Add the upstream remote:

git remote add upstream https://github.com/rocky-linux/documentation.git

Step 7: Configure pyspelling for macOS

The configuration of the repository .pyspelling.yml is for Hunspell by default. macOS uses Aspell (installed by way of Homebrew), so you need to create a local override. Create a .pyspelling.yml file in the repository root configured for Aspell:

cat > .pyspelling.yml << 'EOF'
spellchecker: aspell
matrix:
  - name: Markdown
    sources:
      - 'docs/**/*.md'
    expect_match: false
    aspell:
      lang: en
      d: en_US
    dictionary:
      wordlists:
        - .wordlist.txt
      output: build/spelling-wordlist.dic
    pipeline:
      - pyspelling.filters.markdown
      - pyspelling.filters.html:
          ignores:
            - code
            - pre
            - kbd
      - pyspelling.filters.context:
          context_visible_first: true
          escapes: '\\[\\`]'
          delimiters:
            - open: '(?s)^---'
              close: '^---'
            - open: '(?s)^(?P<open>`{3,}).*$'
              close: '^(?P=open)$'
            - open: '`'
              close: '`'
            - open: '\('
              content: 'https?://[^\)]*'
              close: '\)'
            - open: '<'
              content: '[^>]+@[^>]+'
              close: '>'
      - pyspelling.filters.url
EOF

After creating the override, tell Git to ignore your local changes to this file so you do not accidentally commit it:

git update-index --assume-unchanged .pyspelling.yml

This prevents the modified .pyspelling.yml from appearing in git status or staging by git add. If you ever need to undo this (for example, to pull upstream changes to the file), run:

git update-index --no-assume-unchanged .pyspelling.yml

Step 8: Install pre-commit hooks

pre-commit install

Step 9: Verify your setup

Run the validation checks:

pre-commit run --all-files

Note

The configuration of pyspelling (spell check) and lychee (link check) is as manual hooks to avoid long run times on the full repository. When running pre-commit run --all-files, you might see markdownlint errors from existing repository files. These are pre-existing issues and are not your responsibility to fix.

Validating your own documents

When contributing, validate your specific document by using these commands:

# Activate the virtual environment first
rocky-docs-env

# Markdown lint check
markdownlint docs/guides/your-document.md

# Spell check
pyspelling -n Markdown -S docs/guides/your-document.md

# Link check
lychee docs/guides/your-document.md --no-progress

Windows 11 setup

If you are running Windows 11, follow these steps to set up a complete documentation validation environment.

Step 1: Install Chocolatey package manager

Open PowerShell as Administrator (right-click Start → Terminal (Admin)) and run:

Set-ExecutionPolicy Bypass -Scope Process -Force
iwr https://community.chocolatey.org/install.ps1 -UseBasicParsing | iex

Close and reopen PowerShell as Administrator after installation.

Step 2: Install Git, Python, and Node.js

choco install -y git python nodejs-lts

Close and reopen PowerShell as Administrator to refresh the PATH.

Step 3: Install Python packages

pip install pre-commit pyspelling

Step 4: Install Node.js packages

npm install -g markdownlint-cli

Step 5: Install Hunspell (spell checker)

choco install -y hunspell.portable
choco install -y lychee

Step 7: Clone your forked repository and configure it

cd ~\Documents
git clone https://github.com/YOUR_USERNAME/documentation.git
cd documentation

Step 8: Create pre-commit configuration

Create a .pre-commit-config.yaml file in the repository root:

@"
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
        args: [--markdown-linebreak-ext=md]
      - id: end-of-file-fixer
      - id: check-yaml
        exclude: |
          (?x)^(
            tools/mkdocs-docker\.yml|
            tools/docker-compose\.yml|
            build_pdf/build_base\.yml|
            mkdocs\.yml
          )$
      - id: check-added-large-files
        args: ['--maxkb=1024']

  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.38.0
    hooks:
      - id: markdownlint
        args:
          - --config
          - .markdownlint.yml
          - --fix
        files: \.md$
        exclude: |
          (?x)^(
            LICENSE\.md|
            build_pdf/.*
          )$
"@ | Out-File -FilePath .pre-commit-config.yaml -Encoding UTF8

Step 9: Install pre-commit hooks

pre-commit install

Step 10: Verify your setup

Run validation checks to confirm everything is working:

pre-commit run --files docs/guides/automation/kickstart-rocky.md

Install pre-commit hooks

Pre-commit hooks run automatically before each commit to check spelling, Markdown formatting, and links. If you followed one of the platform-specific setup guides above, you have already completed this step.

For other platforms not listed above, here are the general instructions:

  1. Install pre-commit:
pip install pre-commit
  1. Install the required tools:
# Install pyspelling for spell checking
pip install pyspelling

# Install aspell dictionaries (varies by OS)
# On Rocky Linux / RHEL / Fedora:
sudo dnf install aspell aspell-en

# On Debian / Ubuntu:
sudo apt-get install aspell aspell-en

# On macOS:
brew install aspell

# Install markdownlint-cli for markdown linting
npm install -g markdownlint-cli

# Install lychee for link checking
# On Rocky Linux 10 (binary installation - lychee is not in repos):
cd /tmp && curl -sLO https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz
tar xzf lychee-x86_64-unknown-linux-gnu.tar.gz && sudo mv lychee /usr/local/bin/
sudo chmod +x /usr/local/bin/lychee && rm -f lychee-x86_64-unknown-linux-gnu.tar.gz

# On Fedora (may be available in repos):
sudo dnf install lychee

# On Debian / Ubuntu (via cargo):
cargo install lychee

# On macOS:
brew install lychee
  1. Install the pre-commit hooks:
pre-commit install
  1. Verify the installation by running hooks manually:
pre-commit run --all-files

Creating new documentation

Document naming

Use lowercase filenames with underscores or hyphens. Keep names short and descriptive:

  • kickstart_rocky.md - Good
  • HowToInstallRockyLinuxUsingKickstart.md - Too long
  • ks.md - Too vague

For translated documents, append the language code before .md:

  • kickstart_rocky.md - English (default)
  • kickstart_rocky.de.md - German
  • kickstart_rocky.es.md - Spanish

Document location

Place your document in the appropriate directory under docs/guides/:

Topic Directory
Automation tasks docs/guides/automation/
Backup solutions docs/guides/backup/
Cloud deployments docs/guides/cloud/
Content management docs/guides/cms/
Communication tools docs/guides/communications/
Container technologies docs/guides/containers/
Contributing guides docs/guides/contribute/
Database systems docs/guides/database/
Desktop environments docs/guides/desktop/
DNS configuration docs/guides/dns/
Text editors docs/guides/editors/
Email servers docs/guides/email/
File sharing docs/guides/file_sharing/
Hardware guides docs/guides/hardware/
Interoperability docs/guides/interoperability/
Kernel topics docs/guides/kernel/
Mirror management docs/guides/mirror_management/
Networking docs/guides/network/
Package management docs/guides/package_management/
Proxy servers docs/guides/proxies/
Repositories docs/guides/repositories/
Security docs/guides/security/
Troubleshooting docs/guides/troubleshooting/
Virtualization docs/guides/virtualization/
Web servers docs/guides/web/

If your guide does not fit any existing category, place it in the most relevant directory or ask the documentation team in the Mattermost Documentation channel.

AI usage

The Rocky Linux Documentation Team permits AI and LLM tools in the contribution process, following the Fedora AI Policy as a baseline. If you use AI for any part of your documentation (drafting, research, grammar, code generation), you must include a disclosure at the beginning of your document stating the use of AI and that you take full responsibility for the correctness of the content. You must test every procedure and verify all technical content yourself, as AI frequently produces errors. Do not pass other contributors' existing work through AI tools and resubmit it as a contribution, as this erases the original author's voice. Minor corrections such as typos and broken links do not require disclosure.

Document structure

Every document must include front matter metadata at the top:

---
title: Your Document Title
author: Your Name
contributors: Comma, Separated, Names
ai_contributors: AI Model (model-version)
tested_with: 8.10, 9.7, 10.1
tags:
  - relevant
  - tags
  - here
---

After the front matter, structure your document with:

  1. A brief introduction explaining what the guide covers
  2. Prerequisites or requirements
  3. Step-by-step instructions
  4. Conclusion or summary

Example guides

Feel free to examine some example guides to understand the formatting and styling:

Formatting guidelines

Style guide

Follow the Rocky Linux style guide for:

  • Grammar and punctuation standards
  • Voice and tone guidelines
  • Accessibility requirements

Key points:

  • Use US English spelling
  • Use active voice
  • Avoid contractions (aids translation)
  • Use sentence-style capitalization for headings
  • Use serial commas ("apples, oranges, and bananas")

Markdown formatting

Follow the Document formatting guide for:

  • Admonitions (note, warning, tip boxes)
  • Code blocks
  • Tables
  • Lists

Key rules enforced by our linter:

  • Use dashes (-) for unordered lists, not asterisks
  • Include blank lines around headings
  • Use fenced code blocks with language identifiers
  • Avoid trailing whitespace
  • End files with a single newline

Code blocks

Always specify the language for syntax highlighting:

```bash
dnf install httpd
systemctl enable --now httpd
```

For commands that show output, use text as the language:

```text
$ hostname
rocky.example.com
```

Validation checks

Before committing, the pre-commit hooks automatically run:

  1. Spell check (pyspelling) - Checks for US English spelling errors
  2. Markdown lint (markdownlint) - Validates markdown formatting
  3. Link check (lychee) - Verifies all links are valid

If any check fails, they block the commit. Fix the issues and try again.

Running checks manually

Run all checks:

pre-commit run --all-files

Run individual checks:

# Spell check only
pyspelling

# Markdown lint only
markdownlint docs/

# Link check only
lychee docs/

Rocky docs contribution guidelines validation

Beyond the standard checks, your document must comply with the Rocky Linux documentation contribution guidelines and formatting standards. Use the following checks to validate your document before submitting a pull request.

Validate a single document

Replace path/to/your-document.md with your document path in all commands below.

Run standard checks on your document:

# Spell check
pyspelling -n Markdown -S "path/to/your-document.md"

# Markdown lint
markdownlint "path/to/your-document.md"

# Link check
lychee "path/to/your-document.md" --no-progress

Metadata validation

Every document requires front matter metadata. Check that your document includes:

Field Required Description
title Yes Document title
author Yes Your name
contributors Recommended Comma-separated list of contributors
tested_with Yes Rocky Linux versions tested (e.g., 8.10, 9.7, 10.1)
tags Yes Searchable one-word terms

Check for required metadata:

# Check for title
grep -q '^title:' path/to/your-document.md && echo "✓ Title found" || echo "✗ Missing title"

# Check for author
grep -q '^author:' path/to/your-document.md && echo "✓ Author found" || echo "✗ Missing author"

# Check for contributors (recommended)
grep -q '^contributors:' path/to/your-document.md && echo "✓ Contributors found" || echo "⚠ Contributors recommended"

# Check for tested with
grep -qE '^tested.*(with|_with|on)?:' path/to/your-document.md && echo "✓ Tested with found" || echo "✗ Missing tested with"

# Check for tags
grep -q '^tags:' path/to/your-document.md && echo "✓ Tags found" || echo "✗ Missing tags"

Heading structure validation

Documents should have at most one Level 1 heading (#). If your document has title: metadata, this metadata generates the Level 1 heading for you. There is no requirement for an additional Level 1 heading.

# Count Level 1 headings (should be 0 or 1)
h1_count=$(grep -c '^# ' path/to/your-document.md || echo 0)
if [ "$h1_count" -le 1 ]; then
    echo "✓ Heading structure OK ($h1_count H1 headings)"
else
    echo "✗ Too many H1 headings: $h1_count (maximum 1 allowed)"
fi

Admonition formatting

Admonitions use the !!! syntax with proper types and 4-space indentation for content:

!!! warning "Optional Custom Title"

    This content must be indented with 4 spaces.

Valid admonition types: note, abstract, info, tip, success, question, warning, failure, danger, bug, example, quote

# Check admonition syntax
if grep -qE '^!!!\s+(note|abstract|info|tip|success|question|warning|failure|danger|bug|example|quote)' path/to/your-document.md; then
    echo "✓ Admonitions use valid types"
else
    if grep -q '^!!!' path/to/your-document.md; then
        echo "⚠ Admonitions found but may have invalid types"
    else
        echo "ℹ No admonitions found"
    fi
fi

Code block validation

Code blocks must specify a language identifier for syntax highlighting:

```bash
dnf install httpd
```
# Check for code blocks without language identifiers
blocks_without_lang=$(grep -c '^```$' path/to/your-document.md 2>/dev/null || echo 0)
blocks_with_lang=$(grep -c '^```[a-zA-Z]' path/to/your-document.md 2>/dev/null || echo 0)

if [ "$blocks_without_lang" -eq 0 ]; then
    echo "✓ All code blocks have language identifiers ($blocks_with_lang blocks)"
else
    echo "✗ $blocks_without_lang code blocks missing language identifiers"
fi

Links should use proper markdown format [text](url). Avoid bare URLs.

# Count properly formatted links
proper_links=$(grep -oE '\[[^]]+\]\([^)]+\)' path/to/your-document.md 2>/dev/null | wc -l)
echo "ℹ Found $proper_links properly formatted links"

Lab domain validation

When using example URLs in documentation, use approved domains to pass link validation:

  • example.com, example.org, example.net
  • home.arpa
  • localhost or 127.0.0.1

Internal anchors warning

Avoid internal document anchors like [link](#section-name) as they might break during translation.

# Check for internal anchors
anchors=$(grep -cE '\[.+\]\(#[^)]+\)' path/to/your-document.md 2>/dev/null || echo 0)
if [ "$anchors" -eq 0 ]; then
    echo "✓ No internal anchors found"
else
    echo "⚠ Found $anchors internal anchors (may break during translation)"
fi

Raw HTML warning

Avoid the use of raw HTML elements. Markdown linters flag them and they might not render correctly. These allowed HTML elements in the .markdownlint.yml will not trigger linting errors:

  • <sub> and <sup> - For subscript and superscript text
  • <details> and <summary> - For collapsible/expandable content sections
# Check for HTML tags (excluding allowed elements: sub, sup, details, summary)
html_tags=$(grep -cE '<(?!sub|sup|details|summary|/sub|/sup|/details|/summary)[a-zA-Z][^>]*>' path/to/your-document.md 2>/dev/null || echo 0)
if [ "$html_tags" -eq 0 ]; then
    echo "✓ No disallowed raw HTML found"
else
    echo "⚠ Found $html_tags HTML tags (use markdown instead, or allowed elements: sub, sup, details, summary)"
fi

Complete validation script

Save this script as validate-doc.sh and run it against your document:

#!/bin/bash
# Rocky Linux Documentation Validator
# Usage: ./validate-doc.sh path/to/your-document.md

if [ -z "$1" ]; then
    echo "Usage: $0 <path-to-markdown-file>"
    exit 1
fi

DOC="$1"

if [ ! -f "$DOC" ]; then
    echo "Error: File not found: $DOC"
    exit 1
fi

echo "============================================"
echo "ROCKY LINUX DOCUMENTATION VALIDATOR"
echo "============================================"
echo "Document: $DOC"
echo "--------------------------------------------"
echo ""
echo "METADATA CHECKS:"
echo "--------------------------------------------"
grep -q '^title:' "$DOC" && echo "  Title:        ✓ PASS" || echo "  Title:        ✗ FAIL - Required"
grep -q '^author:' "$DOC" && echo "  Author:       ✓ PASS" || echo "  Author:       ✗ FAIL - Required"
grep -q '^contributors:' "$DOC" && echo "  Contributors: ✓ PASS" || echo "  Contributors: ⚠ WARN - Recommended"
grep -qE '^tested.*(with|_with|on)?:' "$DOC" && echo "  Tested With:  ✓ PASS" || echo "  Tested With:  ✗ FAIL - Required"
grep -q '^tags:' "$DOC" && echo "  Tags:         ✓ PASS" || echo "  Tags:         ✗ FAIL - Required"
echo ""
echo "STRUCTURE CHECKS:"
echo "--------------------------------------------"
h1_count=$(grep -c '^# ' "$DOC" 2>/dev/null || echo 0)
if [ "$h1_count" -le 1 ]; then
    echo "  Single H1:    ✓ PASS ($h1_count heading)"
else
    echo "  Single H1:    ✗ FAIL - Found $h1_count (max 1)"
fi
echo ""
echo "FORMATTING CHECKS:"
echo "--------------------------------------------"
blocks_without_lang=$(grep -c '^```$' "$DOC" 2>/dev/null || echo 0)
if [ "$blocks_without_lang" -eq 0 ]; then
    echo "  Code Blocks:  ✓ PASS"
else
    echo "  Code Blocks:  ✗ FAIL - $blocks_without_lang missing language"
fi

anchors=$(grep -cE '\[.+\]\(#[^)]+\)' "$DOC" 2>/dev/null || echo 0)
if [ "$anchors" -eq 0 ]; then
    echo "  No Anchors:   ✓ PASS"
else
    echo "  No Anchors:   ⚠ WARN - $anchors found (translation risk)"
fi

html_tags=$(grep -cE '<(?!sub|sup|details|summary|/sub|/sup|/details|/summary)[a-zA-Z][^>]*>' "$DOC" 2>/dev/null || echo 0)
if [ "$html_tags" -eq 0 ]; then
    echo "  No Raw HTML:  ✓ PASS (sub, sup, details, summary are allowed)"
else
    echo "  No Raw HTML:  ⚠ WARN - $html_tags disallowed tags found"
fi
echo ""
echo "TOOL CHECKS:"
echo "--------------------------------------------"
echo "Running pyspelling..."
if pyspelling -n Markdown -S "$DOC" > /dev/null 2>&1; then
    echo "  Spell Check:  ✓ PASS"
else
    echo "  Spell Check:  ✗ FAIL - Run: pyspelling -n Markdown -S \"$DOC\""
fi

echo "Running markdownlint..."
if markdownlint "$DOC" > /dev/null 2>&1; then
    echo "  Markdown:     ✓ PASS"
else
    echo "  Markdown:     ✗ FAIL - Run: markdownlint \"$DOC\""
fi

echo "Running lychee..."
if lychee "$DOC" --no-progress > /dev/null 2>&1; then
    echo "  Links:        ✓ PASS"
else
    echo "  Links:        ✗ FAIL - Run: lychee \"$DOC\" --no-progress"
fi
echo ""
echo "============================================"

Make the script executable and run it:

chmod +x validate-doc.sh
./validate-doc.sh docs/guides/automation/kickstart-rocky.md

Example output:

============================================
ROCKY LINUX DOCUMENTATION VALIDATOR
============================================
Document: docs/guides/automation/kickstart-rocky.md
--------------------------------------------

METADATA CHECKS:
--------------------------------------------
  Title:        ✓ PASS
  Author:       ✓ PASS
  Contributors: ✓ PASS
  Tested With:  ✓ PASS
  Tags:         ✓ PASS

STRUCTURE CHECKS:
--------------------------------------------
  Single H1:    ✓ PASS (1 heading)

FORMATTING CHECKS:
--------------------------------------------
  Code Blocks:  ✓ PASS
  No Anchors:   ✓ PASS
  No Raw HTML:  ✓ PASS

TOOL CHECKS:
--------------------------------------------
Running pyspelling...
  Spell Check:  ✓ PASS
Running markdownlint...
  Markdown:     ✓ PASS
Running lychee...
  Links:        ✓ PASS

============================================

Adding words to the dictionary

If the spell checker flags a valid technical term, add it to .wordlist.txt in alphabetical order. Common additions include:

  • Rocky Linux specific terms
  • Package names
  • Technical acronyms
  • Command names

Important: Do not include .wordlist.txt changes in your pull request. Keep your wordlist additions local to your machine. The documentation team maintains the shared .wordlist.txt and will add any necessary terms during the review process. When staging files for your commit, only add your document:

# Only stage your document, not the wordlist
git add docs/guides/your-document.md

If you have already staged .wordlist.txt by mistake, unstage it before committing:

git restore --staged .wordlist.txt

Submitting a pull request

Pushing your changes to the Rocky Linux documentation repository

  1. Sync your fork with upstream:
git fetch upstream
git checkout main
git merge upstream/main
  1. Create a branch for your changes:
git checkout -b your-new-document
  1. Add your document and commit:
git add docs/guides/your-document.md
git commit -m "Add new document for your-document"
  1. Push and create a pull request:
git push origin your-new-document

Note

You can also edit existing documentation and push your changes to the Rocky Linux Documentation repository using the same method.

Getting help

The Rocky Linux community is welcoming and supportive of contributors of all experience levels. Do not hesitate to ask for help.

  • Mattermost: Join the Documentation channel and the community of contributors will be more than happy to help you with your document
  • GitHub Issues: Report documentation bugs or suggest improvements
  • Forums: Visit the Rocky Linux Forums for general questions

If you are unsure where to start, or if something in this guide is unclear, just ask. Someone will point you in the right direction.

Additional resources

License

The published documents contributed to Rocky Linux documentation use the Creative Commons BY-SA 4.0 license. By contributing, you agree to license your work under these terms.

Author: Howard Van Der Wal

Contributors: Steven Spencer