Skip to content

feat(docs): add content linting — Vale, markdownlint, cspell - #1324

Merged
jeremyeder merged 1 commit into
mainfrom
feature/docs-linter
Apr 16, 2026
Merged

feat(docs): add content linting — Vale, markdownlint, cspell#1324
jeremyeder merged 1 commit into
mainfrom
feature/docs-linter

Conversation

@jeremyeder

@jeremyeder jeremyeder commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Custom ACP Vale style with 6 rules: active voice, sentence length, heading punctuation, terminology enforcement, jargon detection, readability scoring
  • markdownlint config tuned for Starlight (allows HTML figures, disables line length)
  • cspell config with ~90 custom ACP/tech terms
  • GHA workflow (docs-lint.yml) triggers on PRs touching docs/ — runs all three linters + Astro build in ~30 seconds
  • Makefile target: make docs-lint
  • Fixes 9 existing markdownlint errors (blank lines around lists, ordered list prefix)

What the linters catch

  • Vale: passive voice, long sentences, deprecated terms (vTeam), unexplained jargon
  • markdownlint: heading structure, list formatting, code block syntax
  • cspell: typos, misspelled product names, unknown terms

Test plan

  • vale src/content/docs/ — 0 errors, 11 warnings, 10 suggestions
  • markdownlint-cli2 "src/content/docs/**/*.md" — 0 errors
  • cspell lint "src/content/docs/**/*.md" — 0 errors
  • npm run build — passes (28 pages)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Added automated documentation linting workflow with integrated style checking, spell-checking, and readability analysis to maintain documentation quality standards.
    • Added documentation linting command to project build tooling.
  • Documentation

    • Fixed documentation formatting and corrected step numbering in workflow guides.

- Custom ACP Vale style with rules for active voice, sentence length,
  heading style, terminology, jargon, and readability
- ACP vocabulary (accept/reject lists for product-specific terms)
- markdownlint config tuned for Starlight (allow HTML figures, disable
  line length, allow duplicate headings in siblings)
- cspell config with ACP tech dictionary (~90 custom words)
- GHA workflow: docs-lint.yml triggers on PRs touching docs/
- Makefile target: make docs-lint
- Fix 9 markdownlint errors in existing docs (blank lines around lists,
  ordered list prefix)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 16, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Introduces documentation linting infrastructure via GitHub Actions workflow, Makefile target, and configurations for Vale, markdownlint, and cspell. Adds Vale style rules for documentation quality checks (active voice, heading style, jargon, readability, sentence length, terminology). Includes minor Markdown formatting adjustments to existing documentation files.

Changes

Cohort / File(s) Summary
Workflow & Build Configuration
.github/workflows/docs-lint.yml, Makefile
New GitHub Actions workflow (docs-lint) for documentation linting on PR changes to docs/**, running Vale, markdownlint, and cspell checks. Makefile target added to run same linting tools locally.
Linting Tool Configurations
docs/.cspell.json, docs/.markdownlint.json, docs/.vale.ini
Configuration files for spellchecker (cspell), markdown linter (markdownlint), and documentation style checker (Vale). Includes ignored paths, custom rules, and style baselines.
Vale Style Rules
docs/.vale/styles/ACP/ActiveVoice.yml, HeadingStyle.yml, Jargon.yml, Readability.yml, SentenceLength.yml, Terminology.yml
Documentation style rules enforcing active voice, proper heading formatting, terminology consistency, readability targets (Flesch-Kincaid grade 12), and sentence length limits (30 words max).
Vale Vocabulary
docs/.vale/styles/config/vocabularies/ACP/accept.txt, reject.txt
Vocabulary allowlist for approved terms (product names, tech stack, abbreviations) and rejection list for deprecated terminology (vTeam, v-team, vteam).
Documentation Formatting
docs/src/content/docs/concepts/workspaces.md, features/session-sharing.md, guides/migrating-shared-sessions.md, workflows/spec-kit.md
Minor Markdown formatting adjustments: step numbering fix, blank lines before list items for proper spacing.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title follows Conventional Commits format (feat(docs): description) and accurately summarizes the main change: adding content linting tools (Vale, markdownlint, cspell) to the documentation workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Performance And Algorithmic Complexity ✅ Passed PR introduces only documentation linting infrastructure with no algorithmic changes to backend or frontend code. All tools operate with O(n) complexity over bounded files with no performance regression.
Security And Secret Handling ✅ Passed PR adds documentation linting with no hardcoded secrets, tokens, API keys, or credentials exposed in plaintext. No command injection, authorization, or K8s-specific vulnerabilities present.
Kubernetes Resource Safety ✅ Passed Kubernetes Resource Safety check not applicable; PR adds documentation linting infrastructure only, no Kubernetes manifests modified.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/docs-linter
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feature/docs-linter

Comment @coderabbitai help to get the list of available commands and usage tips.

@netlify

netlify Bot commented Apr 16, 2026

Copy link
Copy Markdown

Deploy Preview for cheerful-kitten-f556a0 ready!

Name Link
🔨 Latest commit 36f4ed7
🔍 Latest deploy log https://app.netlify.com/projects/cheerful-kitten-f556a0/deploys/69e05dfd6241840008d2e89b
😎 Deploy Preview https://deploy-preview-1324--cheerful-kitten-f556a0.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment on lines +10 to +49
name: Lint Documentation
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: docs/package-lock.json

- name: Install Vale
run: |
curl -sfL https://github.com/errata-ai/vale/releases/download/v3.12.1/vale_3.12.1_Linux_64-bit.tar.gz | tar xz -C /usr/local/bin vale

- name: Install npm tools
run: npm install -g markdownlint-cli2 cspell

- name: Run Vale
working-directory: docs
run: vale src/content/docs/

- name: Run markdownlint
working-directory: docs
run: markdownlint-cli2 "src/content/docs/**/*.md"

- name: Run cspell
working-directory: docs
run: cspell lint --no-progress "src/content/docs/**/*.md"

- name: Build docs (structural validation)
working-directory: docs
run: |
npm ci
npx playwright install --with-deps chromium
npm run build

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/docs-lint.yml (1)

25-30: Harden tool installation for reproducibility and supply-chain safety.

Line 27 executes a downloaded archive without checksum verification, and Line 30 installs unpinned global npm packages (latest drift). Prefer checksum validation and pinned versions (or npm ci + npm exec from locked devDependencies).

Suggested patch
     - name: Install Vale
       run: |
-        curl -sfL https://github.com/errata-ai/vale/releases/download/v3.12.1/vale_3.12.1_Linux_64-bit.tar.gz | tar xz -C /usr/local/bin vale
+        curl -fsSLO https://github.com/errata-ai/vale/releases/download/v3.12.1/vale_3.12.1_Linux_64-bit.tar.gz
+        echo "<vale_tarball_sha256>  vale_3.12.1_Linux_64-bit.tar.gz" | sha256sum -c -
+        tar xzf vale_3.12.1_Linux_64-bit.tar.gz
+        install -m 0755 vale /usr/local/bin/vale

     - name: Install npm tools
-      run: npm install -g markdownlint-cli2 cspell
+      run: npm install -g markdownlint-cli2@<pinned-version> cspell@<pinned-version>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/docs-lint.yml around lines 25 - 30, The "Install Vale"
step currently streams and extracts a remote tarball without verifying integrity
and the "Install npm tools" step installs unpinned global packages; update the
"Install Vale" step to download the artifact to a file, validate it against a
known checksum (e.g., sha256) before extraction, and fail the job if the
checksum does not match, and update the "Install npm tools" step to avoid global
unpinned installs by either pinning package versions (e.g.,
markdownlint-cli2@<version> cspell@<version>) or, preferably, add these tools to
devDependencies and use npm ci followed by npm exec (or npx) to run them from
the lockfile so builds are reproducible and supply-chain safer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/docs-lint.yml:
- Around line 8-13: Update the "Lint Documentation" job (job key `lint`, name
"Lint Documentation") to explicitly scope the workflow token by adding a
`permissions` block with least privilege (e.g., `contents: read`) and pin any
used GitHub Actions to commit SHAs rather than floating versions; also review
the job steps for any secret exposures and ensure secrets are referenced only
via `secrets.*`.
- Around line 15-20: Replace the mutable action tags with pinned commit SHAs for
the GitHub Actions steps that use actions/checkout@v6 and actions/setup-node@v6:
locate the steps referencing "uses: actions/checkout@v6" and "uses:
actions/setup-node@v6", query their release tag SHAs (e.g., via the repository
releases page or git ls-remote) and replace the `@v6` short tag with the full
40-character commit SHA for each action, ensuring the workflow now references
the immutable commit SHAs instead of the version tags.

---

Nitpick comments:
In @.github/workflows/docs-lint.yml:
- Around line 25-30: The "Install Vale" step currently streams and extracts a
remote tarball without verifying integrity and the "Install npm tools" step
installs unpinned global packages; update the "Install Vale" step to download
the artifact to a file, validate it against a known checksum (e.g., sha256)
before extraction, and fail the job if the checksum does not match, and update
the "Install npm tools" step to avoid global unpinned installs by either pinning
package versions (e.g., markdownlint-cli2@<version> cspell@<version>) or,
preferably, add these tools to devDependencies and use npm ci followed by npm
exec (or npx) to run them from the lockfile so builds are reproducible and
supply-chain safer.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f3a6dbb5-78ce-4b09-8dec-65267762fb44

📥 Commits

Reviewing files that changed from the base of the PR and between 3733e68 and 36f4ed7.

📒 Files selected for processing (17)
  • .github/workflows/docs-lint.yml
  • Makefile
  • docs/.cspell.json
  • docs/.markdownlint.json
  • docs/.vale.ini
  • docs/.vale/styles/ACP/ActiveVoice.yml
  • docs/.vale/styles/ACP/HeadingStyle.yml
  • docs/.vale/styles/ACP/Jargon.yml
  • docs/.vale/styles/ACP/Readability.yml
  • docs/.vale/styles/ACP/SentenceLength.yml
  • docs/.vale/styles/ACP/Terminology.yml
  • docs/.vale/styles/config/vocabularies/ACP/accept.txt
  • docs/.vale/styles/config/vocabularies/ACP/reject.txt
  • docs/src/content/docs/concepts/workspaces.md
  • docs/src/content/docs/features/session-sharing.md
  • docs/src/content/docs/guides/migrating-shared-sessions.md
  • docs/src/content/docs/workflows/spec-kit.md

Comment on lines +8 to +13
jobs:
lint:
name: Lint Documentation
runs-on: ubuntu-latest
timeout-minutes: 5

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Scope workflow token permissions explicitly.

permissions is not set, so token scope depends on repository defaults. For this lint-only job, set least privilege (e.g., contents: read).

Suggested patch
 jobs:
   lint:
     name: Lint Documentation
+    permissions:
+      contents: read
     runs-on: ubuntu-latest

As per coding guidelines, ".github/workflows/**/*.{yml,yaml}: - Pin action versions to SHA. Verify secrets are not exposed and permissions are scoped."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jobs:
lint:
name: Lint Documentation
runs-on: ubuntu-latest
timeout-minutes: 5
jobs:
lint:
name: Lint Documentation
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 5
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/docs-lint.yml around lines 8 - 13, Update the "Lint
Documentation" job (job key `lint`, name "Lint Documentation") to explicitly
scope the workflow token by adding a `permissions` block with least privilege
(e.g., `contents: read`) and pin any used GitHub Actions to commit SHAs rather
than floating versions; also review the job steps for any secret exposures and
ensure secrets are referenced only via `secrets.*`.

Comment on lines +15 to +20
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

for repo in checkout setup-node; do
  echo "== actions/${repo} =="
  for tag in v6 v5 v4; do
    printf "  %-3s -> " "$tag"
    resp="$(curl -fsSL "https://api.github.com/repos/actions/${repo}/git/ref/tags/${tag}" || true)"
    if echo "$resp" | jq -e '.ref and .object.sha' >/dev/null 2>&1; then
      echo "$resp" | jq -r '"\(.ref) \(.object.sha)"'
    else
      echo "NOT_FOUND"
    fi
  done
done

Repository: ambient-code/platform

Length of output: 478


Pin GitHub Actions to immutable commit SHAs.

Lines 16 and 19 use mutable major version tags (actions/checkout@v6, actions/setup-node@v6) instead of pinned commit SHAs. This violates the workflow hardening guideline and can break unexpectedly if the tag is retagged or removed.

Obtain the commit SHAs from GitHub's releases page (e.g., https://github.com/actions/checkout/releases/tag/v6) or via git ls-remote https://github.com/actions/checkout refs/tags/v6, then replace with the full 40-character SHA.

Patch structure (replace SHA placeholders with actual commit hashes)
-    - name: Checkout
-      uses: actions/checkout@v6
+    - name: Checkout
+      uses: actions/checkout@<commit-sha>

-    - name: Setup Node.js
-      uses: actions/setup-node@v6
+    - name: Setup Node.js
+      uses: actions/setup-node@<commit-sha>

Per guideline: ".github/workflows/**/*.{yml,yaml}: Pin action versions to SHA."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/docs-lint.yml around lines 15 - 20, Replace the mutable
action tags with pinned commit SHAs for the GitHub Actions steps that use
actions/checkout@v6 and actions/setup-node@v6: locate the steps referencing
"uses: actions/checkout@v6" and "uses: actions/setup-node@v6", query their
release tag SHAs (e.g., via the repository releases page or git ls-remote) and
replace the `@v6` short tag with the full 40-character commit SHA for each action,
ensuring the workflow now references the immutable commit SHAs instead of the
version tags.

@jeremyeder
jeremyeder merged commit 4aa907b into main Apr 16, 2026
17 of 18 checks passed
@jeremyeder
jeremyeder deleted the feature/docs-linter branch April 16, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants