docs: scaffold docs/.style for the prose style guide (#25466)

Adds a private contributor-tooling directory at `docs/.style/` that will
host the canonical prose style guide and the custom Vale rules used to
enforce it. The directory's contents do not deploy to `coder.com/docs`.

This PR is the scaffold only. The Vale configuration, the rule set, and
the per-rule style-guide sections all land in follow-up PRs.

## What changes

- New `docs/.style/` directory with:
  - `README.md` explaining the convention
  - `style-guide.md` as a table-of-contents scaffold
- `styles/Coder/README.md` placeholder so Git tracks the empty Vale
rules dir
- `.github/workflows/deploy-docs.yaml`: skip the workflow on
`.style`-only pushes, and exclude `.style` paths from the
surgical-reindex git diff on mixed commits. Defense-in-depth on top of
the manifest-driven coder.com routing.
- `.github/.linkspector.yml`: add `docs/.style` to `excludedDirs`
- `AGENTS.md` and `.claude/docs/DOCS_STYLE_GUIDE.md`: cross-link to the
new style guide for agents

## Verification

- `make pre-commit-light` clean (`fmt/markdown`, `lint/markdown`,
`lint/typos`, `lint/emdash`, `lint/actions/actionlint`,
`lint/shellcheck`).
- `markdown-table-formatter --check` and `markdownlint-cli2` both
process the new files (existing globs are `find docs -name '*.md'`).
- `actionlint` clean on the modified workflow.
- coder.com exclusion works because route discovery and Algolia indexing
are manifest-driven; this directory is not in `docs/manifest.json`. The
workflow changes are defense in depth.

<details>
<summary>Implementation plan and decision log</summary>

### Decisions

- **Location**: `docs/.style/` (leading dot, mirrors `.github/`,
`.vscode/`, `.claude/`). Vale's `StylesPath` will be
`docs/.style/styles/`; `.vale.ini` lands at repo root in a follow-up.
- **Existing public page `docs/about/contributing/documentation.md`**:
untouched in this PR. Nick's separate information-architecture rework
will redirect it to GitHub at the right time.
- **Placeholder for empty `styles/Coder/`**: real `README.md`, not
`.gitkeep`. Discoverable on GitHub, lints with the existing tooling,
lists the planned starter rules.
- **CONTRIBUTING.md**: not touched. It's a 2-line redirect to
`coder.com/docs/CONTRIBUTING`; bloating it would defeat the redirect.
- **`.claude/docs/DOCS_STYLE_GUIDE.md`**: kept as the structure/research
companion. A blockquote at the top points at the new canonical prose
guide.

### coder.com exclusion mechanism (verified by inspection)

Direct inspection of `coder/coder.com`:

- Route discovery in
[`src/utils/docs/docs.ts`](https://github.com/coder/coder.com/blob/master/src/utils/docs/docs.ts)
iterates `routes` from `docs/manifest.json`. Files not in the manifest
never become routes.
- The Algolia surgical indexer at
[`src/utils/algoliaDocs/surgical.ts`](https://github.com/coder/coder.com/blob/master/src/utils/algoliaDocs/surgical.ts)
explicitly skips paths not in the manifest, incrementing `pathsSkipped`.

Net result: not adding anything from `docs/.style/` to `manifest.json`
is the only thing that has to be true for the exclusion to work. The
`deploy-docs.yaml` tweaks are defense in depth.

### deploy-docs.yaml changes (pre-mortem)

1. Trigger path negation `!docs/.style/**` skips the workflow on
`.style`-only pushes. GitHub Actions only suppresses when every changed
file matches a negation, so mixed commits still trigger.
2. The git-diff pathspec `:(exclude)docs/.style/**` drops `.style` paths
from the surgical-reindex payload on mixed commits.

Risks considered:

- **Test contract**: `.github/workflows/test-deploy-docs-diff.sh` only
exercises the downstream awk parser, not the git-diff invocation. The
exclusion happens at git-diff time; the parser sees the same
`<status>\0<path>\0` format. No test change needed.
- **First push to a brand-new branch**: the workflow falls back to
whole-branch reindex when `BEFORE_SHA` is all zeros. Whole-branch
reindex re-extracts records from the manifest, which still excludes
`.style` files because they are not in the manifest.
- **Workflow-dispatch**: takes the whole-branch path; same reasoning.
Safe.

### Why a real README in `styles/Coder/` instead of `.gitkeep`

It explains intent, lists the upcoming rules, and lints with the
existing tooling. The cost is one extra Markdown file; the upside is
that a contributor browsing GitHub sees the plan without clicking
around.

</details>

---

*Filed via [Coder Agents](https://coder.com/docs/ai-coder/agents) on
Nick's behalf.*


Linear: DOCS-180
This commit is contained in:
Nick Vigilante
2026-06-17 13:19:37 +00:00
committed by GitHub
parent 8d725969bf
commit 182bdc871a
8 changed files with 217 additions and 15 deletions
+33 -8
View File
@@ -9,22 +9,24 @@ Nothing under this directory is published to
| 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`](content-guidelines.md) for the canonical
rules on what content belongs in `docs/` and what should be routed
elsewhere (blog, changelog, Support KB, etc.).
> [!NOTE]
> This directory is the home for the docs scaffold being built out under
> DOCS-180. The prose style guide and the Vale rules that enforce it land
> in that work and will appear in this table when they merge.
See [`style-guide.md`](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` (added in
a follow-up PR) 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.
The structural Markdown linters still pick it up; coder.com's docs site
does not.
Vale and the structural Markdown linters still pick it up; coder.com's
docs site does not.
## How exclusion from coder.com works
@@ -38,10 +40,14 @@ manifest-driven:
do not become routes.
- The Algolia surgical indexer at
[`coder/coder.com:src/utils/algoliaDocs/surgical.ts`](https://github.com/coder/coder.com/blob/master/src/utils/algoliaDocs/surgical.ts)
explicitly skips paths that are not in the manifest.
explicitly skips paths that are not in the manifest, incrementing
`pathsSkipped`.
Net result: not adding anything from `docs/.style/` to `docs/manifest.json`
gives us no route, no Algolia record, and no sidebar entry.
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
@@ -50,9 +56,28 @@ gives us no route, no Algolia record, and no sidebar entry.
`markdownlint-cli2 --fix $(find docs -name '*.md')`.
- `make fmt/markdown` (markdown-table-formatter) reflows tables here for
the same reason.
- Vale, once `.vale.ini` lands in a follow-up PR, lints the entire
`docs/**/*.md` set including `docs/.style/style-guide.md`.
## 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 `docs/.style/style-guide.md`. Follow-up PRs add each
rule and the matching style-guide section together.
+103
View File
@@ -0,0 +1,103 @@
# Coder documentation style guide
This is the canonical style guide for the Coder documentation. It is the
source of truth that the Vale rules in `docs/.style/styles/Coder/` enforce.
Status: scaffold. Sections below are populated by follow-up PRs; this
page starts as a table of contents and grows as those PRs land.
## How to use this guide
This page is a scaffold while follow-up PRs land. Sections marked "To be
filled in" are placeholders. For anything not yet covered, see the
public summary at
[`docs/about/contributing/documentation.md`](../about/contributing/documentation.md).
- **Contributors**: read the section that matches what you are writing.
Each rule notes the Vale rule ID, if any, so you can reproduce the
warning locally.
- **Reviewers**: cite the section in a review comment. Reviews are easier
when the guidance is in one place.
- **AI agents**: read this page in full before editing anything under
`docs/`. The Coder Agents and Claude Code guides
([`AGENTS.md`](../../AGENTS.md),
[`.claude/docs/DOCS_STYLE_GUIDE.md`](../../.claude/docs/DOCS_STYLE_GUIDE.md))
link here.
## Voice and tone
To be filled in by follow-up PRs. Planned coverage:
- Active voice
- Second person
- Plural nouns and pronouns where number is uncertain
- Product voice (`stop` over `kill`, `turn off` over `disable` in
user-facing copy)
- Limiting "we"
## Word choice
To be filled in by follow-up PRs. Planned coverage:
- Inclusive-language substitutions
- HashiCorp casing
- Dev Container terminology
- "Setup" vs "set up" and Quickstart casing
- "Next steps" vs "Learn more"
- Weasel words
## Capitalization and punctuation
To be filled in by follow-up PRs. Planned coverage:
- Sentence case in titles and headings
- General capitalization policy
- Em-dash and en-dash ban (use comma, semicolon, or period)
## Formatting
To be filled in by follow-up PRs. Planned coverage:
- Bold for UI elements
- Italics for parameter names and version variables
- Code font for user input, command-line utility names, filenames,
environment variables, HTTP verbs and status codes, placeholder
variables
- Code blocks with explicit language fences
## Vale enforcement
The repo-root `.vale.ini` configures Vale to read styles from
`docs/.style/styles/`. The starter configuration combines:
- Google's developer-docs base style
- A curated subset of `alex` (inclusive-language)
- A curated subset of `write-good` (wordiness)
- Coder-specific custom rules in `docs/.style/styles/Coder/`
The rationale for the cherry-picked base styles and the severity
policy lives in the follow-up PR that lands `.vale.ini`.
## Editor setup
To be filled in by a follow-up PR. Will cover VS Code, Cursor,
JetBrains, and Neovim.
## Relationship to `docs/about/contributing/documentation.md`
A public-facing prose summary lives today at
[`docs/about/contributing/documentation.md`](../about/contributing/documentation.md).
A follow-up PR will redirect that page to this guide; until then,
follow the public summary for anything the scaffolded sections above do
not yet cover. New prose rules land here; the public page is frozen
pending the redirect.
## Third-party references
When this guide does not cover something, consult:
| Type of guidance | Reference |
|---------------------|-----------------------------------------------------------------------------------------|
| Spelling | [Merriam-Webster](https://www.merriam-webster.com/) |
| Style, nontechnical | [The Chicago Manual of Style](https://www.chicagomanualofstyle.org/home.html) |
| Style, technical | [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/) |
+40
View File
@@ -0,0 +1,40 @@
# Coder custom Vale rules
Custom Vale rules specific to Coder live here. Each rule is a YAML file
that Vale loads through the `BasedOnStyles = Coder` setting in the
repo-root `.vale.ini`.
This directory is intentionally empty for now. Follow-up PRs add rules
incrementally. Planned starter rules:
- Dev Container terminology
- HashiCorp casing
- Limit "we"
- Setup vs set up, Quickstart casing
- Next steps vs Learn more
- Vale substitution rule scaffold
- Weasel words
- Em-dash and en-dash mirror in Vale
- Inclusive-language substitutions
- Product-voice rules
## Authoring a new rule
1. Write a YAML file under this directory. Name it after the rule's
intent, for example `InclusiveLanguage.yml` or `ProductVoice.yml`.
2. Each rule's `message:` should link to the matching section in
`docs/.style/style-guide.md`, ideally with a deep-link anchor, so a
contributor reading a Vale warning can jump straight to the guidance.
3. Land at `level: warning` first. Promote to `level: error` only after
both conditions hold:
- The rule is objectively correct (typo, brand-name casing, banned
substitution).
- The existing-content violation count for the rule reaches zero.
4. A follow-up PR will add a parity CI check that verifies every rule
here has a matching section in `style-guide.md`. Add the section in
the same PR as the rule.
## Reference
- Vale docs: <https://vale.sh/docs/>
- Vale rule types: <https://vale.sh/docs/topics/styles/>