Skip to content
Back to skills

Technical Writing

ASecurity

Doctrine for authoring clear, precise technical documentation in

  • 2 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 2, 2026
ai-agentspythongobashcode-reviewapidatabasefrontendsecurityperformancedocumentation

Works with

  • api

Security analysis

A100/100

Scanned September 2, 2026

npx -y skills add Canhada-Labs/ceo-orchestration --skill technical-writing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Technical Writing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Technical Writing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/canhada-labs-technical-writing/badge)](https://www.skillsdirectory.com/skills/canhada-labs-technical-writing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: core-technical-writing
description: Doctrine for authoring clear, precise technical documentation in
  {{PROJECT_NAME}}. Covers hard rules for structure, voice, and vocabulary; format
  conventions by doc type (README, ADR, plan, CHANGELOG, API reference, runbook);
  anti-patterns that degrade clarity; and WRONG/CORRECT examples across doc types.
  Use when authoring or reviewing any documentation artifact — from a one-sentence
  inline comment to a multi-section ADR or a public API reference.
owner: Technical Writer (archetype)
inspired_by:
  - source: msitarzewski/agency-agents/engineering/engineering-technical-writer.md@783f6a72bfd7f3135700ac273c619d92821b419a
    license: MIT
    relationship: pattern_reference
    authored_by: ceo-orchestration framework
    authored_at: 2026-05-06
# --- smart-loading fields (PLAN-083 Wave 0a sub-agent 0.7a) ---
domain: core
priority: 7
risk_class: low
stack: []
context_budget_tokens: 800
inactive_but_retained: false
repo_profile_binding:
  frontend: {active: true, priority: 6}
  engine: {active: true, priority: 7}
  fintech: {active: true, priority: 7}
  trading-readonly: {active: true, priority: 8}
  generic: {active: true, priority: 6}
activation_triggers:
  - {event: help-me-invoked, regex: "(?i)docs|writing|readme|technical.?writing"}
---

# Technical Writing

Ambiguous prose breaks software just like ambiguous code. A README that says
"configure the server" without specifying which file, which field, or what
value is equivalent to a function that accepts `any` — it compiles, it silences
the linter, and it fails in production when a reader's mental model diverges
from the author's.

Technical writing is engineering applied to language. Every sentence carries a
load. Imprecise sentences shift that load onto the reader, who may not have the
context to recover.

## What This Skill Is (and isn't)

**Is:** Universal doctrine for authoring technical artifacts — docs that ship
alongside code, govern architecture decisions, describe operational procedures,
or define APIs. The rules here apply regardless of project domain.

**Is not:** A style guide for marketing, sales copy, blog posts, or
user-facing product text. Those artifacts have different success criteria
(engagement, persuasion, brand) that are outside this skill's scope.

**Is not:** A writing style enforcer that overrides the project's established
conventions. When a project's CLAUDE.md or PROTOCOL.md specifies a doc format,
that format wins. This skill fills the gaps.

## Hard Rules

These rules are non-negotiable for any technical doc artifact. Violations are
findings, not suggestions.

1. **Imperative mood for instructions.** Instructions tell the reader what to
   do. Use the imperative: "Run the migration." Not "You should run the
   migration." Not "The migration should be run." Not "Running the migration
   is recommended."

2. **Sentence length cap: 25 words.** If a sentence exceeds 25 words, split
   it. Complex ideas chain into short sentences. Long sentences hide
   ambiguity — readers reach the end and are uncertain what modified what.

3. **No passive voice when an actor exists.** "The token is validated by the
   middleware" → "The middleware validates the token." If the actor is genuinely
   unknown or irrelevant, passive is acceptable. If the actor exists, name it.

4. **Code samples must be runnable.** Every code sample in a doc must execute
   without modification in the stated environment. If it requires substitutions,
   mark them explicitly: `<YOUR_API_KEY>`. If it requires setup, state the
   setup. A code sample that silently fails is worse than no sample — it teaches
   the reader a broken mental model.

5. **API parameters are typed, required-or-optional stated, and default-value
   explicit.** Every parameter in an API reference carries: name, type,
   required/optional, default (if any), and a one-sentence description.
   Missing any of these is an incomplete entry, not a minimal one.

6. **CHANGELOG entries follow keepachangelog.com format.** Every entry lives
   under a version heading (`## [X.Y.Z] — YYYY-MM-DD`), under a category
   (`Added`, `Changed`, `Fixed`, `Deprecated`, `Removed`, `Security`).
   Entries are written in past tense for shipped changes. No entry says
   "various improvements" — every line names a specific change.

7. **No smart quotes or em-dashes in code blocks.** Editors and copy-paste
   paths replace ASCII straight quotes (`"` and `'`) with curly variants
   (U+201C `“`, U+201D `”`, U+2018 `‘`, U+2019 `’`) and ASCII hyphens (`-`)
   with em-dashes (U+2014 `—`). Code blocks must use ASCII-only punctuation.
   Verify before committing — invisible curly substitution is a common source
   of broken examples.

8. **Language tag on every code block.** ` ```python `, ` ```bash `,
   ` ```yaml `. A bare ` ``` ` block disables syntax highlighting and signals
   the author did not decide what language the example uses. Undecided =
   incomplete.

9. **Pronouns must have explicit antecedents within the same paragraph.**
   "It validates the input" is acceptable if the prior sentence names the
   subject. "It" spanning a paragraph boundary is a zombie pronoun — the
   reader must re-scan to resolve it. If in doubt, repeat the noun.

10. **"Should" is ambiguous — replace it with "must" or "can" based on intent.**
    "Should" means different things to different readers: obligation, recommendation,
    or possibility. Choose: "must" (required, failure to comply is a bug),
    "can" (optional, reader decides), or "avoid" (anti-pattern).

11. **No jargon without a definition on first use.** Acronyms and domain terms
    are spelled out on first use: "JSON Web Token (JWT)". After that, the short
    form is acceptable. A glossary section is required if a doc introduces five
    or more domain terms.

12. **Heading hierarchy is structural, not decorative.** H1 for the doc title.
    H2 for top-level sections. H3 for subsections. Never skip levels (H1 →
    H3) to get a smaller visual heading. Use H4+ only when nesting is genuinely
    required — three levels of hierarchy is usually the limit before the reader
    loses orientation.

## Voice and Tone

**Neutral.** Technical docs are not cheerful, apologetic, or enthusiastic.
"Exciting new feature!" is marketing. "This endpoint returns the user record."
is technical writing.

**Factual.** Every claim is either verifiable by the reader or sourced. "The
function is fast" — compared to what? — is not a factual claim. "The function
processes 10,000 events/s at p99 < 2ms (benchmark: `bench/event-loop.js`)"
is factual.

**Instructive, not narrative.** A README does not tell the story of how the
code was built. It tells the reader how to use it. Narrative ("We started
this project because...") belongs in a blog post or an ADR's context section,
not in a reference doc.

**Show, then tell.** When possible, lead with the example, then explain it.
A reader who sees working code first can map the explanation onto concrete
evidence. A reader who reads explanation first must hold an abstract model
and retrofit it onto the example. Show first is faster and reduces
misinterpretation.

**Author is absent.** Avoid "we," "I," "our team," "you'll find." The doc
speaks for the system, not for a person. "The middleware validates the token"
not "We validate the token in the middleware." Exception: ADR Context sections
where attributing a decision to the team is explicit and intentional.

## Doc-Type Conventions

| Doc type | Required sections | Length expectation | Voice notes |
|---|---|---|---|
| **README** | What it does / Install / Quick start / Configuration / Contributing | 300–800 words for library-scale; 50–200 words for internal utility | Imperative for steps; declarative for descriptions |
| **ADR** | Status / Context / Decision / Consequences / (optional) Alternatives | 400–1200 words | Past tense for context; present tense for decision; factual throughout |
| **Plan** | Status / Objective / Scope / Phases / Acceptance criteria | 600–2000 words | Present tense for current state; future tense only for phases not yet executed |
| **CHANGELOG** | Version heading / Category sub-headings / Bullet entries | One bullet per discrete change; no prose paragraphs | Past tense for shipped; present tense only for "Deprecated" warnings |
| **API reference** | Endpoint / Method / Auth / Parameters / Request example / Response example / Error codes | Complete table for every parameter; no truncation | Declarative; no "you can call"; say "Returns the user record." |
| **Runbook** | Trigger condition / Symptoms / Diagnosis steps / Resolution steps / Escalation path | Step-by-step numbered lists; no prose paragraphs in action sections | Imperative throughout; terse |

### README

Start with a one-sentence description that a reader encountering the project
for the first time can use to decide whether to keep reading. Not the project
name. Not a tagline. A sentence: what the thing does. Example: "Parses
keepachangelog.com-format CHANGELOG files and emits structured JSON."

The Quick Start section must work on a clean machine with only the stated
prerequisites. Test it. A Quick Start that requires unwritten context is a
broken onboarding gate.

### ADR

The Context section describes the situation that made a decision necessary.
It is written in past tense: "The team needed a way to..." The Decision
section is present tense: "The framework uses X because Y." Consequences
lists trade-offs the team accepted — both positive and negative. An ADR
with no negative consequences is incomplete.

The Status field is a single word from a fixed vocabulary: `PROPOSED`,
`ACCEPTED`, `SUPERSEDED`, `RETRACTED`. Status changes are tracked in
`enforcement_commit` — not in free-form notes.

### CHANGELOG

Every version that ships gets an entry. No version is skipped. Pre-release
versions (`1.0.0-rc.1`) appear above their GA release. The Unreleased section
accumulates entries between releases and moves down when the version is tagged.

Category order within a version: `Added` → `Changed` → `Fixed` →
`Deprecated` → `Removed` → `Security`. Not all categories are required per
release, but the order is fixed when they appear.

### API Reference

Parameter tables include every parameter. Optional parameters include their
default value. When a parameter is an enum, list all valid values. Error codes
include the HTTP status, the error code string, and the condition that produces
it. A reference that documents only the happy path is half a reference.

### Runbook

Numbered steps in Diagnosis and Resolution sections. Each step is a single
action or check. If a step has a decision branch ("if X, go to step 5; if
Y, continue"), state the branch explicitly — never assume the reader knows
which path applies. The Escalation section names a person or on-call rotation,
not a team. "Contact the platform team" is unresolvable at 3 AM.

## Anti-Patterns

### Zombie Pronouns

Pronouns that reference a subject more than one paragraph away. The reader
must scroll to resolve the antecedent. Replace with the noun.

Trigger phrases: "it handles", "this manages", "they process" at the start
of a paragraph after a context switch.

### Future-Tense for Current Behavior

Describing existing behavior as if it were planned. "The function will
validate the input." If it already validates, use present tense: "The
function validates the input." Future tense in docs signals that the behavior
is aspirational, which is accurate only when describing unreleased planned
work.

### Ambiguous-Should

"Should" in a technical instruction means the reader must guess whether
non-compliance is a bug, a recommendation, or an option. Every "should" in
an instruction section is a latent ambiguity.

Replace with:
- "must" — non-negotiable requirement
- "avoid" — anti-pattern, deviation produces known problems
- "can" — optional, reader decides based on their use case

### Marketing-Prose-in-Docs

Superlatives and enthusiasm signals that belong in a product pitch, not a
reference doc: "blazing fast", "best-in-class", "powerful and flexible",
"seamlessly integrates." These phrases do not inform the reader. They signal
that the author is advocating, not describing.

Any comparative claim ("faster than X") requires a benchmark citation.
Any capability claim ("supports Y") requires an example or a link to one.

### Code-Without-Context

A code block dropped into a doc without:
- A statement of what it demonstrates
- A statement of its prerequisites
- The expected output when relevant

A code block with no prose around it is a puzzle. The reader must reverse-
engineer the author's intent. State the intent before the code.

### Unexplained-Omission

Documenting five of six configuration fields and silently omitting the sixth.
The reader does not know whether the omission is intentional ("not needed in
most cases"), an error, or a placeholder. When a field, step, or concept is
intentionally out of scope, say so: "The `debug_mode` field is internal to the
framework and not configurable in user-facing installs."

### We-Without-Antecedent

"We recommend...", "We designed...", "We do not support..." in a reference
doc where "we" is undefined. The reader does not know whether "we" means the
current project, an upstream library, or the company. Use the subject noun:
"The framework does not support...", "This endpoint returns..."

## WRONG / CORRECT Examples

### Example 1 — Instruction voice (README / runbook)

```markdown
# WRONG
You should probably run the migration before deploying. It will ensure
that the database schema is correct and things work properly.

# CORRECT
Run the database migration before deploying:

    python3 manage.py migrate

Expected output: `Applying all migrations: OK`
If the command exits non-zero, stop deployment and check logs at
`logs/migrate.log`.
```

### Example 2 — Parameter documentation (API reference)

```markdown
# WRONG
timeout — optional timeout setting

# CORRECT
| Parameter | Type    | Required | Default | Description                                           |
|-----------|---------|----------|---------|-------------------------------------------------------|
| timeout   | integer | no       | 30      | Request timeout in seconds. Range: 1–300. Requests that exceed this value return HTTP 408. |
```

### Example 3 — CHANGELOG entry

```markdown
# WRONG
## [1.4.0] — 2026-03-01
- Various bug fixes and improvements
- Performance improvements
- New feature added

# CORRECT
## [1.4.0] — 2026-03-01
### Added
- `audit_emit.register()` — registers a new audit action with schema validation.
  Caller must supply `action`, `schema_version`, and `required_fields`.

### Fixed
- `check_agent_spawn.py` now correctly rejects spawns where `AGENT PROFILE`
  section is missing the `model` field (previously allowed and caused silent
  model inheritance from parent).

### Security
- Redacted `api_key` from all audit log payloads. Previously logged as
  plaintext when `log_level=DEBUG` was set.
```

### Example 4 — ADR Decision section

```markdown
# WRONG
We decided to use HMAC instead of RSA because HMAC is better for our use case
and easier to implement. RSA seemed overkill. This should work well.

# CORRECT
The framework uses HMAC-SHA256 with a 32-byte secret per ADR-049a because:

1. The verifier and signer share the same process boundary — asymmetric
   crypto's key distribution benefit does not apply.
2. HMAC verification is constant-time via `hmac.compare_digest()`; RSA
   verification in Python stdlib requires an explicit timing-safe wrapper
   that the team assessed as error-prone (see Context §3).
3. Key rotation is a secret rotation, not a keypair rotation — simpler
   operational procedure for the target adopter profile (single-operator
   installs per ADR-096).

Consequence accepted: HMAC does not provide non-repudiation. If the secret
is compromised, an attacker can forge valid signatures. Mitigation: secret
stored in environment variable, never in source control (enforced by
`check_contamination.sh`).
```

### Example 5 — Runbook escalation

```markdown
# WRONG
If the issue persists, contact the team.

# CORRECT
If resolution steps 1–4 do not clear the alert within 10 minutes:

Escalate to: `@oncall-platform` in `#incidents` Slack channel.
Include in escalation:
- Output of `python3 audit-query.py tail --last=50` (paste verbatim)
- Current alert state from the dashboard URL in step 1
- Steps already attempted (list by number)
```

### Example 6 — Prose around code (README)

```markdown
# WRONG
```python
result = audit_query(action="spawn", since="2026-01-01")
```

# CORRECT
Query the audit log for all agent spawn events since a date:

```python
result = audit_query(action="spawn", since="2026-01-01")
# result is a list of AuditEntry objects
# each entry has: timestamp, agent_name, model, plan_id
```

Returns an empty list if no events match. Raises `AuditLogNotFoundError`
if the log file does not exist (see §Error Handling).
```

## Acceptance Criteria

A doc artifact passes technical writing review when:

- [ ] All instructions use imperative mood.
- [ ] No sentence exceeds 25 words.
- [ ] Passive voice replaced with active voice wherever an actor exists.
- [ ] Every code block has a language tag.
- [ ] Every code block is runnable or explicitly annotated with substitution
  markers.
- [ ] Every API parameter entry has: name, type, required/optional, default,
  description.
- [ ] CHANGELOG entries follow keepachangelog.com category structure.
- [ ] No "should" in instruction sections — replaced with "must", "can",
  or "avoid".
- [ ] No zombie pronouns spanning paragraph boundaries.
- [ ] No marketing superlatives in reference sections.
- [ ] Jargon defined on first use; glossary present if five or more new terms.
- [ ] Heading hierarchy is sequential (no level-skipping).
- [ ] Doc type matches the required-sections table in §Doc-Type Conventions.

## Related Skills

- `core/code-review-checklist` — Documentation-only changes (no code, no
  config, no schema) may bypass two-pass review per §When to SKIP two-pass.
  This skill defines what "documentation quality" means for that bypass gate.
- `core/architecture-decisions` — ADR authoring follows conventions in
  §Doc-Type Conventions §ADR above. This skill supplements, does not supersede,
  the ADR lifecycle and status vocabulary defined there.
- `core/pre-plan-brainstorm` — Plans authored during brainstorm follow the
  Plan row in §Doc-Type Conventions. The `spec.md` artifact produced by
  brainstorm is a technical doc subject to these rules.
- `core/observability-and-ops` — Runbooks produced for operational procedures
  follow §Doc-Type Conventions §Runbook and the Escalation anti-pattern rules
  above.
- `core/public-api-design` — API reference documentation follows §Doc-Type
  Conventions §API Reference. Parameter table completeness in this skill
  complements the interface-design rules in public-api-design.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.