Use when writing or fixing user-facing technical docs — a README, a getting-started tutorial, a how-to guide, or API/CLI/config reference — especially when a page tries to teach, explain and enumerate at once, a tutorial branches, a reference is padded with opinions, a README reads like a sales pitch, samples are stale, or weasel words have crept in. NOT an SEO blog article (that is `article-writing`), NOT the content calendar or pipeline (that is `content-engine`).
npx skills add https://github.com/ericrisco/rsc-harness --skill technical-writing
You write the document a person reads to *use* a product or codebase: a README, a tutorial, a how-to, API/CLI/config reference. Not marketing prose, not an SEO article, not a course. The craft is mostly one decision made early and held: what kind of doc does this reader actually need, then writing that one kind in its correct shape.
The backbone is Diátaxis — four documentation modes, each serving a distinct need (diataxis.fr). The sentence-level rules come from the Google developer documentation style guide (developers.google.com/style). The shipping discipline is docs-as-code: docs live with the code and lint in CI.
Before you write a line, name the reader's need and pick exactly one mode. Mixing modes in one page is the single biggest reason docs fail readers — the learner gets buried in parameters, the expert wades through a beginner tutorial to find one flag.
| Reader is… | They want… | Mode | Shape |
|---|---|---|---|
| Learning, new, hands need holding | To *acquire skill* by doing | Tutorial | Linear, runnable, guaranteed to work |
| Competent, has a specific goal | To *get a task done* now | How-to | Goal-titled, ordered steps, no teaching |
| Working, needs a fact | To *look something up* | Reference | Dry, complete, mirrors the product |
| Curious, wants the "why" | To *understand* | Explanation | Discursive, trade-offs, no steps |
Rule: one page, one mode. Why: a tutorial answers "how do I start?", reference answers "what are the flags?" — a reader arrives with one question, and a page serving two answers neither well.
If a page already mixes modes, do not patch it — split it. See references/diataxis-modes.md for a worked split of one bad page into four.
A lesson a beginner runs end to end and succeeds. You are the instructor; their success is *your* responsibility, not theirs.
Bad → Good opening:
<!-- Bad: assumes context, branches, explains -->
Depending on your package manager, install the SDK (we use a monorepo
because it scales better). Configure your environment as needed.
<!-- Good: one path, concrete, checkable -->
## Build your first report
You need Python 3.12+ and a free API key from example.com/keys.
1. Install the SDK:
pip install acme-sdk==4.2.0
2. Save your key:
export ACME_KEY="your-key-here"
Run `echo $ACME_KEY` — you should see your key printed back.
A recipe for someone who already knows the product and has a real goal right now.
Bad → Good:
<!-- Bad: teaches, no clear goal in the title -->
## Logging
Logging is important. A logger has levels: DEBUG, INFO… Here is how
levels work, and then some setup.
<!-- Good: goal title, competent reader, straight to it -->
## How to send logs to Datadog
1. Set `LOG_SINK=datadog` and `DD_API_KEY` in the environment.
2. Restart the worker: `acme worker restart`.
3. Confirm delivery in Datadog → Logs within ~1 min.
The technical facts, structured to mirror the product. The reader is not reading top to bottom — they are scanning for one entry.
### `GET /reports/{id}`
| Param | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string (uuid) | yes | Report identifier. |
| `fields` | query | string | no | Comma-separated fields to return. Default: all. |
**Responses**
| Status | Meaning |
|---|---|
| `200` | Report returned. |
| `404` | No report with that `id`. |
| `429` | Rate limit exceeded; retry after `Retry-After` seconds. |
Background and the "why" — context, design decisions, trade-offs, alternatives considered.
The one doc everyone gets wrong by turning it into a pitch. A README lives in the top-level directory, orients a *new* reader, and at minimum says what the thing is, what it is for, and links to fuller docs (Google docguide).
Skeleton, in order: what + why (two lines) → install → one minimal runnable example → link to deeper docs → status/license.
Bad → Good opening lines:
<!-- Bad: a sales page -->
# Acme SDK 🚀
The most powerful, blazing-fast, developer-friendly toolkit to
effortlessly supercharge your data workflows!
<!-- Good: what it is, what it's for, in two lines -->
# Acme SDK
A Python client for the Acme reporting API. Fetch, filter, and export
reports without writing HTTP by hand.
## Install
pip install acme-sdk==4.2.0
Apply these to every mode. Each ships clearer prose at no cost.
| Rule | Why | Bad → Good |
|---|---|---|
| Second person, imperative steps | The reader is *doing* this | "The user should run…" → "Run…" |
| Active voice | Names who acts | "The file is created by the script" → "The script creates the file" |
| Present tense | Docs describe how it works now | "This will return a list" → "This returns a list" |
| Define before use | No forward references | Spell out a term the first time, then use it |
| One idea per sentence | Scannable, translatable | Split the 40-word sentence into two |
| Cut "in order to" | It is always just "to" | "in order to deploy" → "to deploy" |
| Ban weasel/AI-tell words | They lie about difficulty and add nothing | "simply run X" → "run X" |
Banned words: simply, just, easy, effortless, seamless, robust, powerful, leverage, utilize, in order to, blazing-fast, supercharge. If a step is "simple", the reader either already knows it (delete the word) or does not (the word mocks them). Full banlist with replacements is in references/diataxis-modes.md.
bash, python, json, yaml, ini).... standing in for required lines. Elide only genuinely irrelevant detail, and say so.# Good: minimal, runnable, shows what comes back
from acme import Client
client = Client(api_key="your-key")
report = client.reports.get("3f9a-...")
print(report.title)
# -> "Q2 revenue"
Treat docs like code, or they go stale and mislead.
.vale.ini at the repo root, custom rules in a styles dir, run as a blocking check on every PR touching Markdown. Common rules ban "simply/just/easy" and enforce "sign in" over "log in". Used in production by GitLab, Datadog, and ING.pip install line in a tutorial breaks every reader.A starter .vale.ini, a custom banned-terms style, and a GitHub Actions blocking job are in references/vale-starter.md.
| Anti-pattern | Why it fails | Do instead |
|---|---|---|
| One page teaches + explains + lists params | Serves no reader well; all three are diluted | Split by mode (classify table above) |
| Tutorial that branches ("if you prefer…") | Beginner cannot judge the choice; loses the path | One guaranteed path; defer choices to a how-to |
| How-to that teaches concepts | Wastes the competent reader's time | Link to reference/explanation; just give steps |
| Reference with opinions ("we recommend…") | Pollutes a lookup with judgement | Move recommendations to how-to/explanation |
| README as a sales page | New reader still does not know what it *is* | What/why in two lines, then install + example |
| Untested or ...-gapped code samples | They rot; reader copies a broken command | Test on a clean machine; show expected output |
| Weasel words (simply, just, seamless) | Lie about difficulty, add zero information | Delete the word; the imperative stands alone |
| Wall of text, no headings or steps | Unscannable; reader cannot find their answer | Short sentences, one idea each, real headings |
... hides a line the reader needs.scripts/verify.sh path/to/doc.md).references/diataxis-modes.md — per-mode templates, a worked split of one mixed page into four, and the full weasel-word/AI-tell banlist with replacements.references/vale-starter.md — starter .vale.ini, a custom banned-terms Vale style, and a GitHub Actions job running Vale as a blocking check.../article-writing/SKILL.md.../content-engine/SKILL.md.../course-storytelling/SKILL.md.../brand-voice/SKILL.md.../accessibility/SKILL.md.Take ericrisco/technical-writing from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip.
Without those the skill loads but fails at the first command.