npx claudepluginhub data-wise/craft --plugin craftdocs/# /craft:docs:check-links - Documentation Link Validation Validate internal links in documentation files to prevent broken references. ## Purpose **Fast, focused link validation:** - Internal markdown links (relative & absolute) - Detects broken file references before deployment - Catches issues like v1.20.0 workflows/ directory not deployed - CI-ready with exit codes ## Philosophy > **"Find broken links before they break production."** ## Usage ## Modes | Mode | Time | Focus | Use Case | |------|------|-------|----------| | **default** | < 10s | Internal links only | Quick pre-c...
/check-linksAnalyzes Nuxt project links for broken internals, poor text (accessibility/SEO), and externals using nuxt-link-checker. Produces markdown report with summary, issues tables, and recommendations.
/check-linksCrawls a specified webpage to find all links, validates them via HEAD requests, categorizes internal/external, and reports broken links, redirects, warnings, and summaries in markdown or JSON.
Validate internal links in documentation files to prevent broken references.
Fast, focused link validation:
"Find broken links before they break production."
# DEFAULT: Quick check of all docs
/craft:docs:check-links
# MODES: Different thoroughness levels
/craft:docs:check-links default # Quick check (< 10s)
/craft:docs:check-links debug # Verbose with context (< 120s)
/craft:docs:check-links optimize # Parallel checking (< 180s)
/craft:docs:check-links release # Comprehensive validation (< 300s)
# SPECIFIC PATH
/craft:docs:check-links docs/guide/ # Check specific directory
/craft:docs:check-links README.md # Check specific file
# DRY-RUN: Preview what will be checked
/craft:docs:check-links --dry-run
/craft:docs:check-links release -n
| Mode | Time | Focus | Use Case |
|---|---|---|---|
| default | < 10s | Internal links only | Quick pre-commit check |
| debug | < 120s | + Context + verbose | Troubleshooting broken links |
| optimize | < 180s | + Parallel processing | Large doc sets |
| release | < 300s | + Anchors + comprehensive | Pre-release validation |
# Import and parse .linkcheck-ignore file
from utils.linkcheck_ignore_parser import parse_linkcheck_ignore
# Load ignore rules (returns empty IgnoreRules if file doesn't exist)
ignore_rules = parse_linkcheck_ignore(".linkcheck-ignore")
print(f"Loaded {len(ignore_rules.patterns)} ignore patterns from {len(ignore_rules.get_categories())} categories")
# Determine what to check
if [ -n "$path" ]; then
# Specific path provided
if [ -f "$path" ]; then
FILES="$path"
elif [ -d "$path" ]; then
FILES=$(find "$path" -name "*.md" -type f)
fi
else
# Default: all docs
FILES=$(find docs/ -name "*.md" -type f 2>/dev/null)
FILES+=" "$(ls *.md CLAUDE.md 2>/dev/null)
fi
echo "Checking ${#FILES[@]} markdown files..."
For each markdown file, extract links:
# Extract markdown links: [text](url)
grep -oP '\[([^\]]+)\]\(([^)]+)\)' file.md
# Extract reference-style links: [text][ref]
grep -oP '\[([^\]]+)\]\[([^\]]+)\]' file.md
# Extract link definitions: [ref]: url
grep -oP '^\[([^\]]+)\]:\s*(.+)$' file.md
For each broken link found, check if it should be ignored:
# For each broken link discovered
broken_link = {"file": "docs/index.md", "line": 34, "target": "/docs/config.md"}
# Check against ignore rules
should_ignore, category = ignore_rules.should_ignore(
broken_link["file"],
broken_link["target"]
)
if should_ignore:
expected_broken_links.append({**broken_link, "category": category})
else:
critical_broken_links.append(broken_link)
๐ CHECKING INTERNAL LINKS...
docs/index.md:
โ Line 12: [Quick Start](guide/quickstart.md)
โ Line 25: [API Reference](reference/api.md)
โ Line 34: [Configuration](/docs/config.md) โ File not found
docs/guide/setup.md:
โ Line 8: [../reference/commands.md](../reference/commands.md)
โ Line 15: [missing.md](missing.md) โ File not found
README.md:
โ Line 45: [Documentation](docs/index.md)
โ Line 67: [Guide](docs/guide/nonexistent.md) โ File not found
Summary:
Total: 45 internal links
Valid: 42 โ
Broken: 3 โ
๐ DEBUG: Link Validation with Context
docs/index.md:34 (BROKEN):
Link: [Configuration](/docs/config.md)
Target: /docs/config.md
Resolved: /path/to/project/docs/config.md
Error: File does not exist
Context (lines 32-36):
32: ## Getting Started
33:
34: Check the [Configuration](/docs/config.md) guide to set up your
35: environment. This will walk you through all the necessary steps
36: to get started with Craft.
Suggestions:
โข Did you mean: docs/reference/configuration.md?
โข Or: docs/guide/setup.md?
docs/guide/setup.md:15 (BROKEN):
Link: [missing.md](missing.md)
Target: missing.md
Resolved: /path/to/project/docs/guide/missing.md
Error: File does not exist
Context (lines 13-17):
13: ### Installation
14:
15: See [missing.md](missing.md) for detailed installation
16: instructions. Follow these steps carefully to avoid
17: common pitfalls.
Suggestions:
โข Check filename case (case-sensitive filesystems)
โข Verify file exists in repository
โก OPTIMIZE: Parallel Link Checking
Processing batches of 10 files concurrently...
[Batch 1/5] Checking 10 files... โ (1.2s)
[Batch 2/5] Checking 10 files... โ (1.1s)
[Batch 3/5] Checking 10 files... โ 1 broken (1.3s)
[Batch 4/5] Checking 10 files... โ (0.9s)
[Batch 5/5] Checking 5 files... โ (0.6s)
Total time: 5.1 seconds (vs ~15s sequential)
Broken links found:
docs/index.md:34 โ /docs/config.md
docs/guide/setup.md:15 โ missing.md
README.md:67 โ docs/guide/nonexistent.md
๐ฏ RELEASE: Comprehensive Link Validation
Phase 1: Internal file links... โ 42/45 (3 broken)
Phase 2: Anchor validation...
Checking anchor targets in 12 files with cross-references...
docs/guide/quickstart.md:
โ Line 23: [Setup](setup.md#installation) โ setup.md has #installation
โ Line 45: [Config](../reference/config.md#options) โ #options not found
docs/reference/api.md:
โ Line 12: [Example](#examples) โ #examples exists in same file
โ Line 78: [Auth Flow](#authentication-flow) โ heading case mismatch
Found: ## Authentication flow (lowercase 'flow')
Phase 3: Link consistency...
Checking for inconsistent link patterns...
โ Mixed link styles detected:
- docs/index.md: Uses absolute paths (/docs/...)
- docs/guide/: Uses relative paths (../...)
Recommendation: Use relative paths for portability
Summary:
File links: 42/45 valid (3 broken)
Anchor links: 15/17 valid (2 broken)
Consistency: 1 warning
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ /craft:docs:check-links (default mode) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โ Checked: 45 internal links in 54 files โ
โ โ Loaded: 5 ignore patterns from 5 categories โ
โ โ
โ โ Critical Broken Links (2): โ
โ 1. docs/index.md:34 โ
โ [Configuration](/docs/config.md) โ
โ โ File not found โ
โ โ
โ 2. README.md:67 โ
โ [Guide](docs/guide/nonexistent.md) โ
โ โ File not found โ
โ โ
โ โ Expected Broken Links (3): โ
โ 1. docs/test-violations.md:12 โ
โ [nonexistent.md](nonexistent.md) โ
โ โ Expected (Test Violation Files) โ
โ โ
โ 2. docs/specs/SPEC-teaching-workflow.md:45 โ
โ [brainstorm](../brainstorm/BRAINSTORM-teaching.md) โ
โ โ Expected (Brainstorm References) โ
โ โ
โ 3. docs/TEACHING-DOCS-INDEX.md:23 โ
โ [README](../README.md) โ
โ โ Expected (README References) โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Exit code: 1 (2 critical broken links) โ
โ โ
โ Fix critical links before deployment. โ
โ Expected links documented in .linkcheck-ignore โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Exit Code Logic (UPDATED):
0: No critical broken links (expected links OK)1: Critical broken links found (must fix)2: Validation errorVS Code Integration (file:line:col format):
docs/index.md:34:10: [Configuration](/docs/config.md) โ File not found
docs/guide/setup.md:15:5: [missing.md](missing.md) โ File not found
README.md:67:23: [Guide](docs/guide/nonexistent.md) โ File not found
| Format | Example | Validated |
|---|---|---|
| Relative | [text](../other.md) | โ File exists |
| Relative same dir | [text](file.md) | โ File exists |
| Absolute repo | [text](/docs/file.md) | โ File exists |
| Anchor (release) | [text](file.md#heading) | โ Heading exists |
| Format | Example | Status |
|---|---|---|
| HTTP/HTTPS | [text](https://example.com) | โ Skipped (use /craft:site:check) |
| Mailto | [text](mailto:user@example.com) | โ Skipped |
# For each link in markdown file
for link in $(extract_links "$file"); do
# Skip external links
if [[ $link =~ ^https?:// ]]; then
continue
fi
# Skip anchors in default mode
if [[ $mode != "release" ]] && [[ $link =~ \# ]]; then
link=${link%%#*} # Strip anchor
fi
# Resolve path
if [[ $link =~ ^/ ]]; then
# Absolute repo path
target="${repo_root}${link}"
else
# Relative path
target=$(realpath -m "$(dirname "$file")/$link")
fi
# Check if target exists
if [ ! -f "$target" ]; then
echo "BROKEN: $file:$line:$col: $link โ File not found"
broken_count=$((broken_count + 1))
fi
done
# Extract heading from markdown file
extract_headings() {
grep -E '^#{1,6} ' "$1" | sed 's/^#* //' | \
tr '[:upper:]' '[:lower:]' | \
tr ' ' '-' | \
sed 's/[^a-z0-9-]//g'
}
# Check if anchor exists
validate_anchor() {
local file=$1
local anchor=$2
headings=$(extract_headings "$file")
if ! echo "$headings" | grep -qx "$anchor"; then
return 1 # Anchor not found
fi
return 0 # Anchor exists
}
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ DRY RUN: Documentation Link Validation โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โ Mode: default (Quick check) โ
โ Time budget: < 10 seconds โ
โ Focus: Internal file links only โ
โ โ
โ โ Scope Detection: โ
โ - docs/ directory: 45 markdown files โ
โ - Root level: 3 files (README.md, CLAUDE.md, CHANGELOG.md) โ
โ - Total: 48 files to check โ
โ โ
โ โ Link Types to Validate: โ
โ โข Relative links: ../other.md, file.md โ
โ โข Absolute repo links: /docs/file.md โ
โ โข Skipping: External links (https://) โ
โ โข Skipping: Anchors (file.md#heading) - use release mode โ
โ โ
โ โ Validation Process: โ
โ 1. Parse markdown files for [text](url) patterns โ
โ 2. Extract internal links (skip external URLs) โ
โ 3. Resolve relative/absolute paths โ
โ 4. Check if target files exist โ
โ 5. Report broken links with file:line:col format โ
โ โ
โ โ Output Format: โ
โ - Success: "โ All 45 internal links valid" โ
โ - Failures: file:line:col format (VS Code clickable) โ
โ - Exit code: 0 (no broken links) or 1 (broken links found) โ
โ โ
โ โ Estimated Time: ~3 seconds (48 files) โ
โ โ
โ ๐ Summary: 48 files, internal links only, ~3s โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Run without --dry-run to execute โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
/craft:docs:check-links release --dry-run
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ DRY RUN: Documentation Link Validation (Release Mode) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โ Mode: release (Comprehensive validation) โ
โ Time budget: < 300 seconds โ
โ Focus: Internal links + anchors + consistency โ
โ โ
โ โ Validation Phases (3): โ
โ โ
โ Phase 1: Internal file links โ
โ โข Relative links: ../other.md, file.md โ
โ โข Absolute repo links: /docs/file.md โ
โ โข Estimated: ~3 seconds โ
โ โ
โ Phase 2: Anchor validation โ
โ โข Cross-file anchors: [text](file.md#heading) โ
โ โข Same-file anchors: [text](#heading) โ
โ โข Heading extraction and normalization โ
โ โข Estimated: ~8 seconds โ
โ โ
โ Phase 3: Link consistency โ
โ โข Check for mixed link styles (absolute vs relative) โ
โ โข Detect case sensitivity issues โ
โ โข Validate link patterns โ
โ โข Estimated: ~2 seconds โ
โ โ
โ โ Total Estimated Time: ~13 seconds โ
โ โ
โ โ Strict Mode: โ
โ โข Any broken link causes failure โ
โ โข Anchor mismatches reported as errors โ
โ โข Consistency warnings don't block โ
โ โ
โ ๐ Summary: 3 phases, comprehensive checks, ~13s โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Run without --dry-run to execute โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
| Code | Meaning | Action |
|---|---|---|
| 0 | All links valid OR only expected broken links | โ Safe to deploy |
| 1 | Critical broken links found | โ Fix before deployment |
| 2 | Validation error | โ Check command syntax |
Behavior with .linkcheck-ignore:
Called by:
/craft:check - Pre-flight validation/craft:site:check - Site validationWorks with:
/craft:docs:lint - Markdown quality checks/craft:ci:validate - CI pipeline validation# .github/workflows/docs-quality.yml
- name: Check Documentation Links
run: |
claude "/craft:docs:check-links"
# Exit code 1 if broken links found
# Quick check before commit
/craft:docs:check-links
# โ Fast, internal links only
# Debug broken link
/craft:docs:check-links debug
# โ Verbose with context and suggestions
# Release validation
/craft:docs:check-links release
# โ Comprehensive with anchors
# Specific file
/craft:docs:check-links README.md
# โ Check just one file
# Preview without executing
/craft:docs:check-links --dry-run
# โ Shows what will be checked
| Files | Mode | Time |
|---|---|---|
| 50 | default | ~3s |
| 50 | debug | ~15s |
| 50 | optimize | ~5s (parallel) |
| 50 | release | ~13s (+ anchors) |
Optimization Tips:
optimize mode for large doc sets (100+ files)/craft:docs:check-links docs/guide/Issue: Link reported as broken but file exists
# Check case sensitivity
ls -la docs/guide/ # Verify exact filename
# Check current directory
pwd # Ensure you're in repo root
# Try absolute path
/craft:docs:check-links /full/path/to/docs/
Issue: Checking takes too long
# Use optimize mode (parallel)
/craft:docs:check-links optimize
# Or check specific directory
/craft:docs:check-links docs/guide/
Issue: Anchors reported as broken but heading exists
# Headings are normalized: lowercase, spaces โ dashes
# "Setup Guide" โ #setup-guide
# "API Reference" โ #api-reference
# Debug mode shows normalized anchor
/craft:docs:check-links debug release
Ignore expected broken links by creating a .linkcheck-ignore file in your project root. This allows you to:
# Known Broken Links
### 1. Category Name
File: `path/to/file.md`
Target: `path/to/target.md`
- Purpose: Why this link is intentionally broken
### 2. Multiple Files
Files with broken links:
- `docs/specs/*.md`
- `docs/other.md`
Targets: `docs/brainstorm/*.md` (gitignored)
| Pattern | Example | Matches |
|---|---|---|
| Exact | File: docs/test.md | Exact file path only |
| Glob | Files: docs/specs/*.md | All files matching pattern |
| Multiple | List with - file.md | Each listed file |
| Any target | No Target: line | All broken links in file |
| Specific target | Target: ../README.md | Only links to that target |
| Glob target | Targets: docs/brainstorm/*.md | Links matching pattern |
# Known Broken Links
### Test Files (Intentional)
File: `docs/test-violations.md`
- Purpose: Test data for validation
- All broken links in this file are expected
### Brainstorm References (Gitignored)
Files with broken links:
- `docs/specs/SPEC-feature-a.md`
- `docs/specs/SPEC-feature-b.md`
Targets: `docs/brainstorm/*.md` (gitignored)
- Brainstorm files not published to website
- Fix: Reference GitHub URLs or remove links
### External References
File: `docs/index.md`
Target: `../README.md`
- Reason: README not published to docs site
When .linkcheck-ignore exists:
When .linkcheck-ignore is missing:
# .github/workflows/docs-quality.yml
- name: Check Documentation Links
run: |
claude "/craft:docs:check-links"
# Only fails on critical broken links
# Expected links (in .linkcheck-ignore) don't block CI
/craft:docs:check-links.linkcheck-ignore in project root/craft:docs:check-linksThe parser automatically normalizes paths:
docs/brainstorm/*.md matches ../brainstorm/file.md/craft:docs:lint - Markdown style and quality checks/craft:docs:check - Full documentation health check/craft:site:check - Site validation (includes external links)templates/dry-run-pattern.md.linkcheck-ignore - Ignore pattern file (create in project root)