Replace the `docs/.style/style-guide.md` scaffold with the populated
prose style guide,
structured as a `README.md` landing page plus one subpage per topic so
GitHub auto-renders the landing when readers open the style-guide
folder.
## Layout
```text
docs/.style/
style-guide/
README.md (landing: intro, section list, editing conventions, Vale enforcement)
audience-and-scope.md (one audience, one outcome, declared up front; canonical personas)
voice-and-tone.md
word-choice.md
accessibility-and-inclusion.md (new)
capitalization-and-punctuation.md
formatting.md (text formatting + block elements + screenshots sparingly)
numbers-units-and-dates.md
editor-setup.md (placeholder)
```
Every repo reference to the old path is rewired to the new path:
`AGENTS.md` (and its `CLAUDE.md` / `.cursorrules` symlinks),
`.claude/docs/DOCS_STYLE_GUIDE.md`,
`docs/about/contributing/documentation.md`, `docs/.style/README.md`,
`docs/.style/styles/Coder/README.md`, and a comment in
`.github/workflows/ci.yaml`. The touched paragraph in each of those
files is reformatted to one sentence per line per the touch-paragraph
rule (refer to [Conventions the guide
dogfoods](#conventions-the-guide-dogfoods)).
## What each page covers
- **Audience and scope** (new): every page targets **one audience
working toward one outcome**; the **install-vs-deploy Coder example**
(workspace user vs platform engineer); pick one audience per page (write
two pages and cross-link rather than tagging sections); pick one outcome
per page (`Configure SSO with Okta` is one outcome, `Configure SSO` is
not); declare audience and scope up front (the H1 names the outcome; the
first paragraph names the audience); **canonical Coder personas**
inlined as four primary (Dave the Developer, Ada the Infrastructure
Admin, Perry the Platform Engineer, Steven the Sponsor) and six
secondary (Melissa the Machine Learner, Tommy the Tester, Caitlin the
Citizen Developer, Felipe the FinOps, Sergio the Security Officer, Tara
the Team Leader), each with a `Coder surface:` line covering the
relevant CLI/workspace/template/RBAC surfaces.
- **Voice and tone**: address the reader directly, avoid first-person
singular, reserve first-person plural for **Coder Technologies the
company** (with an explicit ban on `we` for the product itself and on
combined `you and the docs`), active voice, present tense with a
**conditional/predictive `will` exception** (`If you do X, Y will
happen`), **no sentence-ending prepositions** with a clunky-exception
note.
- **Word choice**: Coder product and feature names with the **Coder CLI
always in backticks (`coder`)** rule, brand names with a parallel
**Terraform CLI in backticks (`terraform`)** rule, **Dev Container**
terminology (proper-noun specification vs lowercase instance, parallel
to Coder / workspace), **phrasal verbs and their noun forms generalized
as a table** (set up/setup, log in/login, sign in/sign-in, log
out/logout, back up/backup, roll out/rollout, start up/startup, shut
down/shutdown, with the `Quickstart` exception), `refer to` / `check
out` / `visit` over `see`, `Learn more` versus `Next steps` with an
**ableism rationale** (`steps` as a physical-mobility metaphor),
`tutorial` versus `walkthrough` with an **ableism rationale**,
**`select` over `click`**, **`Don't assume simplicity or
difficulty`** (covers both `simple`/`easy` and `complex`/`non-trivial`),
**`Avoid weasel words`** (vague attributions in the Wikipedia sense like
`many believe`, `experts agree`, `studies show`), plain language for
product actions with an **industry-term exception scope** for the Linux
`kill` command, the `SIGKILL` signal, and the `disabled` config flag
state.
- **Accessibility and inclusion** (new): WCAG 2.1 Level AA as the
minimum target with AAA as a stretch goal; heading structure (one H1 per
page, no skipped levels, **substantive content between headings**);
inclusive pronouns; inclusive-language substitutions including a
**dedicated `sanity check` row** with `smoke testing` / `confidence
testing` / `acceptance testing` alternatives; descriptive link text; alt
text and decorative-image conventions; **plain English for international
readers** (no idioms; common Latin abbreviations `e.g.`, `i.e.`, `etc.`,
`vs.`, and `et al.` allowed, less common ones not); page descriptions in
`docs/manifest.json` (the docs site does not yet support YAML front
matter); reading level; color contrast deferred to the docs site theme.
- **Capitalization and punctuation**: sentence-case headings, no
gerund-leading headings with **documented exceptions** (`Pricing`,
`Billing`, `Logging`, `String formatting`, etc.), **trailing heading
punctuation in three tiers** (periods and exclamation marks forbidden at
error severity, question marks allowed sparingly at suggestion severity,
characters inside backticks exempt for both), no em or en-dashes with a
**corrected example** showing parenthetical em-dash use rather than
series-joining, Oxford comma, US-style quotation, semicolons sparingly,
rare exclamation marks, numeric ranges.
- **Formatting**: text formatting (bold for UI with **explicit
greater-than separator rule for navigation paths**, italics for
emphasis, code font for identifiers presented as a **bulleted list**)
and block elements (code blocks with language fences plus **link to the
Prism supported-languages reference**, callouts with tightened
scenarios, tabs with the actual `` syntax and a **macOS/Linux/Windows
example**, lists with a **five-item prose-list cap rule** and an
**explicit terminal-punctuation rule** (complete sentences end in
periods, phrases completing a lead-in paragraph end in periods,
single-word labels carry no terminal punctuation, no mixing styles in
one list), tables with a **narrow-table guideline** that reconsiders the
structure when many columns are needed, links including the rule that
**non-docs codebase links also use relative paths**, images,
**screenshots sparingly** with a maintenance-burden rationale and an
adapted quote from Lorna Jane Mitchell's `Short tech writing style
guide for developers`), with cross-references to the accessibility page
for link text and alt text.
- **Numbers, units, and dates**: digits everywhere preference,
non-breaking space between number and unit with **separate pre-render
(Markdown source) and post-render (visible output) demonstrations** plus
a **window-shrink tip** for confirming the rule visually, `Month Day,
Year` date format, 12-hour time with AM/PM, ordinals exception.
- **Editor setup**: placeholder.
## Conventions the guide dogfoods
- **One sentence per line**. Source lines follow a one-sentence-per-line
policy: each sentence sits on its own Markdown source line, sentences
are not split across lines, and lines do not wrap to a fixed column
width. The same convention applies corpus-wide through an **incremental
touch-paragraph rule**: when a contributor edits any line inside a
paragraph, the whole paragraph is reformatted to one sentence per line
as part of the same edit. Bullet items, numbered list entries, and
blockquote lines are each their own paragraph for the rule. Headings,
fenced code blocks, and tables are out of scope. `markdownlint`'s
`MD013` is already disabled, so the convention is editorial.
- **No navigational `see`**. Replaced with **refer to** (formal
default), **check out** (informal/tutorials), or **visit** (external
URLs). `See` is reserved for the observational meaning.
- **HTML entities for em-dashes inside demos**. The em-dash demo encodes
`—` / `–` so the source stays ASCII while the rendered output still
shows the character.
- **No semicolons in body prose**. Body prose prefers two sentences over
a semicolon. Semicolons survive only in heading and rule labels where
they act as separators.
- **Common Latin abbreviations allowed in own prose**. `e.g.`, `i.e.`,
`etc.`, `vs.`, and `et al.` (citation contexts) are fine. Less common
Latin abbreviations (`a priori`, `q.v.`, `viz.`, `n.b.`, `cf.`, `ibid.`)
are not. The rule covers punctuation too: prefer parentheses around
`e.g.` and `i.e.` clauses, one period when `etc.` ends a sentence, both
periods when `etc.` ends a parenthetical that ends a sentence.
- **No idioms or industry-jargon idioms**. `deep dive`, `paved path`,
etc. are rewritten in plain language.
## Rule conventions
Each rule pairs a rationale with **Do** / **Don't** blockquoted
examples and a parenthetical noting the Vale rule that enforces (or will
enforce) the policy. Documentation-only rules are explicitly labeled as
such. Substitution rules use tables.
## Out of scope
- Wiring any new Vale rule. Per-rule PRs land separately per the
rule-authoring doctrine in `docs/.style/README.md`.
- Editor setup page population.
- Redirecting `docs/about/contributing/documentation.md` to the
populated guide (needs a coordinated `coder.com` PR after merge).
- Trimming the `Writing Style` block in
`.claude/docs/DOCS_STYLE_GUIDE.md` and removing the `currently a
scaffold` framing in the agent docs.
- A separate demo PR for the callout types rendered against an existing
docs page.
- Sweeping navigational `see` out of other docs files. The new rule only
dogfoods on the style guide itself; a corpus-wide sweep is a separate
ticket.
## Validation
- `make fmt/markdown`: clean.
- `make lint/markdown`: 0 errors across 494 files.
- `./scripts/check_emdash.sh`: clean.
- Pre-commit-light: passes (fmt + lint + emdash + shellcheck + typos +
actionlint + migrations + helm).
- Dogfood scan: no first-person singular in own prose, no idioms, only
the five allowed Latin abbreviations in own prose, no `walkthrough` or
`Next steps` outside rule definitions and examples, no navigational
`see`, no `click` outside rule definitions and examples, no semicolons
in body prose.
<details>
<summary>CI flake note: <code>check-docs</code> (linkspector)</summary>
The `check-docs` job can fail intermittently on pre-existing external
links in `docs/about/contributing/documentation.md` (lines 29 and 30):
Merriam-Webster occasionally returns HTTP 403 to GitHub Actions runners
and Chicago Manual of Style can time out at 30s. Neither link is touched
by this PR. `docs/.style/` itself is in `.github/.linkspector.yml`
`excludedDirs`, and linkspector annotations confirm zero broken links
from the new pages.
</details>
Resolves DOCS-434.
---
*Filed via [Coder Agents](https://coder.com/docs/ai-coder/agents) on
Nick's behalf.*
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:
- Route discovery lives in
coder/coder.com:src/utils/docs/docs.ts(getDocsStaticPaths). It iteratesroutesfromdocs/manifest.jsonand emits one Next.js static path per entry. Files not in the manifest do not become routes. - The Algolia surgical indexer at
coder/coder.com:src/utils/algoliaDocs/surgical.tsexplicitly skips paths that are not in the manifest, incrementingpathsSkipped.
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-rootpackage.jsoninvokesmarkdownlint-cli2 --fix $(find docs -name '*.md').make fmt/markdown(markdown-table-formatter) reflows tables here for the same reason.- Vale lints the entire
docs/**/*.mdset, includingdocs/.style/style-guide/. Refer to the repo-root.vale.inifor the active configuration. Runmake lint/proselocally to reproduce.
What does not run against this directory
linkspector: excluded viaexcludedDirsin.github/.linkspector.yml. External-link checking is overkill for contributor tooling.- The
deploy-docsworkflow: itspaths:filter negatesdocs/.style/**, and the surgical-reindex git-diff invocation excludes the same path. See.github/workflows/deploy-docs.yaml. - The
docs-previewworkflow: itspaths:filter negatesdocs/.style/**, so.style-only PRs produce no preview comment. The selection logic also skips.stylefiles 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:
- Cleanup commit: fix every existing-content violation of the new
rule so
make lint/prosereports zero findings for it. The cleanup ships in the same PR as the enable, ordered first. - Enable commit: add the rule to
.vale.iniat its chosen severity, write a corresponding section under the matching subpage ofdocs/.style/style-guide/, and add the custom rule YAML underdocs/.style/styles/Coder/if applicable. The rule'smessage:field points at the relevant style-guide subpage anchor.
Severity is a deliberate per-rule choice:
errorblocks merge. Use for hard policy where any violation is wrong: brand-name casing, first-person pronouns we ban outright, em-dash bans.warningsurfaces an annotation without failing CI. Use for strong guidance with legitimate human-judgment exceptions: terms that need context (disabledas a technical state vs. ableist usage), judgment-bound style preferences.suggestionsurfaces anoticeannotation. Use for soft guidance where the right fix is contextual: noun-as-adjective patterns likedesired 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.