Files
coder/docs/.style
Nick Vigilante 83cb587c3f docs(docs/.style/style-guide): add directional-language and contractions rules (#26729)
Adds two new accessibility-and-voice rules to the style guide.

**Directional language**
(`docs/.style/style-guide/accessibility-and-inclusion.md`).
Screen-reader users navigate documents linearly and cannot follow
spatial references like "see below" or "the menu on the left". The rule
prescribes anchor links, section headings, document order ("the previous
section", "the following section"), and named UI elements instead. A
replacement table covers the common cases.

**Contractions are the default**
(`docs/.style/style-guide/voice-and-tone.md`). Prefer contractions in
body prose for the same reason the docs use second person and present
tense. Three exceptions: auxiliary contractions (`you'd`, `there's`,
`it's`, `we'd`, `they're`) need an explicit complement and cannot end a
sentence; contractions join exactly two words (no `you'd've` or
`wouldn't've`); spell out for emphasis and high-stakes operations like
deletion or data loss (`do not`, `cannot`, `will not`).

The PR also sweeps the existing style-guide subpages so the existing
prose comply with both rules.

Resolves
[DOCS-462](https://linear.app/codercom/issue/DOCS-462/add-screen-reader-aware-directional-language-rule-and-sweep-existing).

<details>
<summary>Directional-language sweep targets</summary>

| File | Change |
| --- | --- |
| `docs/.style/style-guide/README.md` | "pages below" becomes "linked
pages" |
| `docs/.style/style-guide/accessibility-and-inclusion.md` | "top of the
page" becomes "beginning of the page". Captions "follow" instead of "go
below". Latin abbreviation table cells drop "as described below". Sample
captions name widgets instead of panel positions. |
| `docs/.style/style-guide/audience-and-scope.md` | Don't example
rewritten without "below". "Above the first paragraph" becomes "before
the first paragraph". "At the top of the page" becomes "at the beginning
of the page". |
| `docs/.style/style-guide/capitalization-and-punctuation.md` |
"Exceptions above" becomes "exceptions listed earlier". |
| `docs/.style/style-guide/formatting.md` | Captions "follow" instead of
"go below". Sample captions renamed by widget. Don't example "as shown
above" becomes "as shown in the screenshot". |
| `docs/.style/style-guide/numbers-units-and-dates.md` | "10th and up"
becomes "10th and higher". |

Idiomatic stack metaphors like "built on top of Terraform" and phrasal
verbs like "set up", "back up", "log in", and "shut down" are explicitly
carved out as not directional and stay as-is.

</details>

<details>
<summary>Contractions rule scope</summary>

The rule lands as `## Contractions are the default` in
`voice-and-tone.md`, placed between `Present tense by default` and
`Trailing prepositions are a judgment call` because all three rules sit
in the natural-phrasing cluster.

The sweep applies the rule across all eight style-guide subpages: 76
lines updated where the spelled-out form (`does not`, `is not`,
`cannot`, `you have`, `there is`, `that is`) reads more naturally as a
contraction.

Skipped:

- Don't blocks inside the contractions rule that intentionally
demonstrate the wrong form.
- Do blocks inside the emphasis sub-rule that intentionally model `do
not`, `cannot`, and `will not` for high-stakes operations.
- The Churchill joke inside the trailing-prepositions Don't blocks.
- The "that is" dictionary definition of `i.e.` in the Latin
abbreviations table.
- `may not` (no contraction in modern English).
- `that has` relative clauses where `'s` could read as possessive.

</details>

<details>
<summary>Lints</summary>

- `make lint/markdown`: 0 errors across 495 files.
- `make lint/prose`: only the pre-existing intentional `[Demo]`
annotations in `docs/.style/_vale-annotation-demo.md` fire.

</details>

---

*Filed via [Coder Agents](https://coder.com/docs/ai-coder/agents) on
Nick's behalf.*
2026-07-08 12:05:24 -04:00
..

docs/.style/

Contributor-facing style and content guidance for the Coder documentation. Nothing under this directory is published to coder.com/docs.

What lives here

Path Purpose
content-guidelines.md Canonical content rules: what belongs in docs/, what doesn't, why
style-guide.md Canonical prose style guide for docs/
styles/Coder/ Custom Vale rules specific to Coder (product voice, terms)

See content-guidelines.md for the canonical rules on what content belongs in docs/ and what should be routed elsewhere (blog, changelog, Support KB, etc.).

See style-guide.md for the prose style guide. The styles/Coder/ directory holds the custom Vale rules that enforce parts of the guide; Vale's StylesPath in the repo-root .vale.ini points at docs/.style/styles/.

Why a hidden directory

The leading dot mirrors the .github/, .vscode/, and .claude/ convention already used in this repo for tooling-internal directories. Vale and the structural Markdown linters still pick it up; coder.com's docs site does not.

How exclusion from coder.com works

coder.com/docs routes and search are manifest-driven:

Net result: not adding anything from docs/.style/ to docs/manifest.json gives us no route, no Algolia record, and no sidebar entry. Two defense-in-depth changes in .github/workflows/deploy-docs.yaml keep the deploy workflow from running on .style-only commits and exclude the directory from the surgical-reindex payload on mixed commits.

What still runs against this directory

  • make lint/markdown (markdownlint-cli2) processes every Markdown file here. The repo-root package.json invokes markdownlint-cli2 --fix $(find docs -name '*.md').
  • make fmt/markdown (markdown-table-formatter) reflows tables here for the same reason.
  • Vale lints the entire docs/**/*.md set, including docs/.style/style-guide/. Refer to the repo-root .vale.ini for the active configuration. Run make lint/prose locally to reproduce.

What does not run against this directory

  • linkspector: excluded via excludedDirs in .github/.linkspector.yml. External-link checking is overkill for contributor tooling.
  • The deploy-docs workflow: its paths: filter negates docs/.style/**, and the surgical-reindex git-diff invocation excludes the same path. See .github/workflows/deploy-docs.yaml.
  • The docs-preview workflow: its paths: filter negates docs/.style/**, so .style-only PRs produce no preview comment. The selection logic also skips .style files when picking the preview target on mixed PRs. See .github/workflows/docs-preview.yaml.

Editing the content guidelines

Open a PR against docs/.style/content-guidelines.md. The rules in that file apply to humans and AI-assisted workflows alike; when it conflicts with another style or contributing doc in the repo, it governs.

Editing the style guide

Open a PR against the appropriate subpage of docs/.style/style-guide/. Follow-up PRs add each rule and the matching style-guide section together.

Adding a Vale rule

Each rule in the repo-root .vale.ini ships clean: zero baseline findings against the current docs/ corpus. The PR that adds a rule is the rule's complete unit:

  1. Cleanup commit: fix every existing-content violation of the new rule so make lint/prose reports zero findings for it. The cleanup ships in the same PR as the enable, ordered first.
  2. Enable commit: add the rule to .vale.ini at its chosen severity, write a corresponding section under the matching subpage of docs/.style/style-guide/, and add the custom rule YAML under docs/.style/styles/Coder/ if applicable. The rule's message: field points at the relevant style-guide subpage anchor.

Severity is a deliberate per-rule choice:

  • error blocks merge. Use for hard policy where any violation is wrong: brand-name casing, first-person pronouns we ban outright, em-dash bans.
  • warning surfaces an annotation without failing CI. Use for strong guidance with legitimate human-judgment exceptions: terms that need context (disabled as a technical state vs. ableist usage), judgment-bound style preferences.
  • suggestion surfaces a notice annotation. Use for soft guidance where the right fix is contextual: noun-as-adjective patterns like desired state, wordiness, optional sentence reshaping.

The severity choice and the cleanup discipline are independent. A rule landing at warning or suggestion still ships with zero baseline findings; the rule's purpose is to catch new violations, not to surface a backlog of existing ones. A rule that surfaces a standing backlog teaches contributors to ignore the annotation channel, which erodes trust in CI regardless of the severity at which the noise arrives.

PR title: feat(docs/.style): enable <RuleName>.

False-positive policy: one confirmed false positive after enable, either refine the rule or revert. We do not maintain rules that occasionally cry wolf, regardless of severity.

If a policy is judgment-bound (passive voice, weasel words, sentence-case headings on a corpus with many proper nouns), write a Coder-authored rule with the precision the situation needs instead of accepting an imprecise third-party rule at any severity.

This applies equally to Coder-authored rules (under docs/.style/styles/Coder/) and third-party rules from Google, alex, and write-good. Third-party rules are not loaded by default. Each returns through the same per-rule PR pattern after its corpus is clean.