Lucas Almeida Picture

A 1986 aviation writing standard made my AI model write better technical documentation

A writing specification built for aircraft maintenance manuals in 1986, packaged as a Claude Code skill, fixed the documentation my model kept writing badly.

Available in: EN· PT

#claude code #artificial intelligence #technical writing #documentation

Technical documentation written by a model reads well and ages badly. Six months later the file cannot answer the questions I actually have, so I end up rewriting most of it.

A writing specification built for aircraft maintenance manuals in 1986 fixed most of that for me. This post covers how I packaged it as a skill, where to install it, and how to choose between calling it yourself and letting the model call it.

Everything here assumes Claude Code. The skill format, the install paths and the invocation rules are all Claude Code specific.

What was actually wrong with the docs

The text was never incorrect. That is the part that took me a while to name.

A model would write that a component is reliable, with no measurement behind the word. It would mention a constraint like “the agent must not write here” without saying what stops the agent from writing there. It would write “recently updated” in a file someone opens a year later. It would describe a step the model itself decides as if the outcome were fixed.

Every one of those sentences survives a review. They fail later, when the person reading the file has no memory of the day it was written.

Where the standard comes from

ASD-STE100, Simplified Technical English. The European aerospace industry published it in 1986, and the current issue is from January 2025. It has 53 rules and a dictionary of roughly 900 approved words, where each word carries one meaning and one grammatical job.

It exists because a mechanic reading a repair manual in a second language cannot afford to guess. A misread repair manual kills people, so the industry specified the language itself.

The parts that transfer to software are the mechanical ones. One instruction per sentence. Hard word caps, 20 for an instruction and 25 for a description. Active voice. No semicolons. One name for one thing, held across the whole document.

What I changed for code

I dropped the 900-word dictionary. Locking vocabulary makes sense for a repair manual and no sense for a codebase full of identifiers.

I kept the sentence discipline, and added the rules that addressed my actual problem:

Installing it in Claude Code

A skill is a directory containing a SKILL.md file. The directory name is the skill name.

For a personal skill, available in every project on your machine:

~/.claude/skills/ste-technical-writing/SKILL.md

For a project skill, committed to the repository and shared with everyone who clones it:

<repo>/.claude/skills/ste-technical-writing/SKILL.md

The file is identical in both cases. I keep this one personal, because it encodes how I want to read documentation rather than a team decision. A team convention belongs in the repository, where a code review can argue with it.

The frontmatter needs a name and a description. Adding user-invocable: true makes the skill callable by name as a slash command.

Letting the model decide versus calling it yourself

There are two ways a skill enters a session, and they behave differently.

Auto-invocation. Only the description sits in the model’s context. When your request matches it, the model loads the body of SKILL.md and follows it. This costs you almost nothing until it fires, which is the whole design. It also means a vague description never fires, and a greedy description fires on files you never wanted it to touch.

Direct invocation. You type /ste-technical-writing and the body loads, every time, regardless of what the model would have decided. In a non-interactive run, prefixing the prompt with “Use the ste-technical-writing skill” does the same job.

I use auto-invocation for documentation written in the middle of another task, a PR description at the end of a feature for example, where I am not thinking about writing rules at all. I use direct invocation when the document is the task and I want the same behavior on every run.

There is a third state worth knowing. Running claude --print --disable-slash-commands turns skills off entirely. That flag is how I produced the “without the skill” outputs below, on the same prompt and the same model.

The description field is the real interface

Most of my iteration went into the description, not the rules.

The description is the only thing the model sees when deciding whether to load the skill, so it has to name the document classes explicitly: README, CLAUDE.md, AGENTS.md, architecture decision record, runbook, incident note, migration guide, pull-request description, release notes, changelog.

The exclusions matter more than the inclusions. My description says the skill does not apply to code, identifiers, command syntax, prompts, SKILL.md files, or anything that needs a voice. Before I added that line the skill fired while I was writing other skills, and rewrote instructions meant for an agent into prose meant for a person.

What it looks like in practice

I built a fictional project to be able to show this publicly: a CLI that reads a GitHub issue, picks a label and drafts a reply for a maintainer to approve. Ten lines of raw engineering notes, one request for the “How it works” section of the README, run with and without the skill.

What was measured, and what was not.

Without the skill:

On a 200-issue sample from May 2026, 173 labels were correct. Treat the
suggestion as a starting point, not a decision.

With the skill:

Harbormaster labeled 173 of 200 sampled issues correctly. The sample came from
May 2026. No production measurement exists. tests/label-match.test.ts covers six
unknown-label cases. No test covers an empty issue body.

The first gives the number and appends advice that was in none of the notes. The second gives the number, says where the sample came from, and names what nobody measured and what no test covers.

What stops the agent, and what does not.

Without the skill:

The agent should never modify the billing/ directory or push directly to main.

With the skill:

The agent must not modify billing/. No hook, permission rule, or CI check blocks
a write to billing/. The rule is convention only.

The agent must not push to main. The pre-push hook in .githooks/pre-push rejects
the push and returns exit code 2.

The first version gives two constraints equal weight in one sentence. One of them the agent genuinely cannot cross. The other exists only in the head of whoever wrote it. Reading the first version, you cannot tell which is which.

When this was true.

Without the skill:

The label matching logic was recently updated and currently supports the new
taxonomy. The model version will be upgraded soon.

With the skill:

labels.json holds the label taxonomy. Harbormaster reads the model id from
config/model.json.

“Recently” relative to when? The last sentence also promises a change nobody guaranteed, so it ships already expired. The second version points at the file holding the answer, and stays true after the value changes.

What it does not fix

The standard governs form. A skill can turn a hollow paragraph into a clean, confident, well-punctuated hollow paragraph, and it will not make a claim true.

The output is also flatter. In the example above, most sentences start with the same two subjects. That is the trade, and it is why the skill explicitly excludes marketing copy, essays, and anything that needs a voice. A torque wrench specification applied to a poem produces neither.

And the mechanical rules are the checkable ones. Whether a sentence makes sense still needs a person. The people who maintain the original standard say plainly that no software certifies full compliance, and they are right.

A rule you can check is a rule you can hand to a model. Everything else is taste, and taste does not survive a handoff.

The full skill

Copy this into ~/.claude/skills/ste-technical-writing/SKILL.md and it works in every project on your machine.

---
name: ste-technical-writing
description: Write technical prose that humans read, using Simplified Technical English adapted for AI-augmented codebases (STE-AC). Use whenever writing or editing a technical report, technical refinement, resumo técnico, README, CLAUDE.md, AGENTS.md, architecture decision record, design note, runbook, incident note, handover document, migration guide, pull-request description, release notes, changelog, or any other Markdown or plain-text prose file a human will read. Enforces short active sentences, present-tense description of current behavior, explicit marking of model-decided steps, evidence for every capability claim, enforcement points for agent constraints, and absolute dates. Does not apply to code, identifiers, command syntax, prompts, subagent definitions, or SKILL.md files.
user-invocable: true
---

# STE-AC technical writing

Adapted from ASD-STE100 Simplified Technical English. The approved-word dictionary
is not part of this adaptation. The section "Terms" gives the replacement.

Plain STE removes long sentences, passive voice, and vague synonyms. A document
about an AI-augmented codebase can pass all of those checks and still fail the
reader. The failures live in what the sentence omits: which step a model decides,
what evidence backs a claim, and what enforces a rule. The rules below force those
facts into the sentence.

## When this applies

Apply this skill to any prose file that a human will read, including files that
both humans and agents read:

- Technical reports, technical refinements, and resumos técnicos.
- `README.md`, `CLAUDE.md`, `AGENTS.md`, `CONTRIBUTING.md`.
- Architecture decision records, design notes, and handover documents.
- Runbooks, incident notes, and migration guides.
- Pull-request descriptions, release notes, and changelogs.
- Long comments and error messages that a human reads.

## When this does not apply

Do not apply this skill to these files. They are not written for humans:

- `SKILL.md` files and their reference files. Write a skill with Anthropic skill
  authoring guidance instead. This rule covers this file as well.
- Subagent definitions in `.claude/agents/`, tool descriptions, and system prompts.
- Prompts under test, and evaluation fixtures.

Never apply this skill to code, identifiers, command syntax, or configuration
values. Never rewrite a quoted error string, a log line, or a transcript.

Never apply this skill to marketing copy, essays, or any text that needs a voice.
STE strips voice on purpose.

## Rules

### Sentences

- One instruction per sentence. Maximum 20 words for an instruction. Maximum 25
  words for a descriptive sentence.
- No contractions. Keep the articles: a, an, the, this, these.
- No semicolons. Write two sentences.

### Verbs

- Active voice. The subject is a component, a file, a command, a service, or a
  role.
- Use a verb for an action. Write "analyze the log", not "perform an analysis of
  the log".
- Use the present tense for current behavior. Do not narrate the change history.
- No stacked auxiliaries. Do not write "it is important to note that this may help
  to improve". Write "this improves X".
- No `-ing` main verb where a simple tense works.

### Structure

- One topic per paragraph. Maximum six sentences.
- For steps, use a numbered vertical list. One action per item. Imperative form.
- Put a condition before its command.

### Terms

- Use one name for one thing. Do not call the same item by two names.
- If the repository declares a glossary, use its terms. If it does not, pick one
  term per thing and hold it across the whole document.
- Use American spelling.

### Determinism

- Mark every step that a model decides. A fixed step and a model step must not
  share a voice.
- Use "may" and "can" only for model variance. Do not use them to hedge a fact.
- Do not promise a model behavior. Write what the code does when the model returns
  an unexpected result.
- Label sample model output as one observed run, with the date of the run. Never
  present a sample run as the specification.

### Claims

- Every capability claim carries evidence in the same paragraph, or carries the
  word "unverified".
- Evidence is a test path, a measurement, or a log reference.
- Use a number and its measurement basis. Do not use an unquantified quality
  adjective such as accurate, fast, reliable, robust, or stable.
- State the known gap. If the text lists what the tests cover, list what they do
  not cover.

### Boundaries

- Every constraint on an agent names its enforcement point in the same paragraph.
  Give the hook, the permission rule, the CI check, or the sandbox.
- A constraint with no enforcement point carries the words "convention only".
- State the failure mode. Write what happens when an agent tries the blocked action.

### Time

- Use absolute dates in ISO form: 2026-07-26.
- Do not use a relative time word: currently, recently, now, soon, lately, today,
  at the moment, as of writing.
- For a claim that depends on a version, name the file that holds the version.
  Do not copy the version into the prose.

### Reference

- Do not use a pronoun across a sentence boundary.
- Do not use "this" or "it" to refer to a clause. Repeat the noun.
- Use one canonical form for each path, command, and identifier.
- Use the imperative for an instruction to an agent. Do not use "should" or "would".
- Do not use a mentalistic verb for a model: understands, knows, thinks, learns,
  remembers, realizes, wants, decides to. Use an observable verb: reads, writes,
  calls, retries, returns, produces.

## Never invent evidence

The Claims and Time rules ask for facts. Get each fact, or mark its absence. Do
not fill the gap with a plausible value.

- If you do not know the test path, write "unverified". Do not name a test file
  that you did not read.
- If you do not know the number, write "unmeasured". Do not estimate a percentage.
- For a date, use the real current date from the environment. Do not guess.
- If a fact is missing and the document needs it, ask the user.

A marked gap is correct output. An invented citation is a defect.

## Document classes

- **agent-facing**`CLAUDE.md`, `AGENTS.md`, and any file that an agent acts on.
  Apply every rule and both length caps. Ambiguity here becomes a wrong action,
  not a confused reader.
- **operational** — runbooks, incident notes, migration guides, refinements.
  Apply every rule. Determinism, Boundaries, and Time matter most.
- **explanatory** — README files, decision records, design notes. Relax the length
  caps to 30 words. Keep Claims, Determinism, and Time at full strength.

## Examples

| Rule | Before | After |
| --- | --- | --- |
| Verbs | An analysis of the queue depth is performed by the collector every minute. | The collector reads the queue depth every minute. |
| Determinism | The agent reads the failing test and fixes the bug. | The agent reads the failing test. The agent then proposes a patch. A model chooses the patch content, so the patch changes between runs. |
| Claims | Tool calls are validated and errors are handled well. | `validateToolCall()` rejects a call with an unknown name. `tests/tool-call.test.ts` covers four rejection cases. No test covers a malformed JSON payload. |
| Claims | The classifier is highly accurate. | The classifier labeled 94 of 100 sampled tickets correctly. The sample came from June 2026. No production measurement exists. |
| Boundaries | Agents must never push to main. | Agents must not push to `main`. A `PreToolUse` hook in `.claude/settings.json` blocks the command. The hook returns exit code 2 and the agent receives the reason. |
| Time | This currently uses the latest Sonnet model. | `worker/summarize.ts` reads the model id from `config/model.json`. |
| Reference | The agent understands the repo layout and knows which files to skip. | The agent reads `.claudeignore`. The agent skips every path in that file. |

## Final check

Run these checks before you write the file or return the text.

1. Does a model decide any step? Mark the step.
2. Does any capability claim lack evidence? Add the test path or the number, or
   write "unverified".
3. Does any constraint on an agent lack an enforcement point? Add it, or write
   "convention only".
4. Is any date relative? Replace it with an ISO date.
5. Does any sentence start with "This" or "It"? Repeat the noun.
6. Does the text use a mentalistic verb for a model? Use an observable verb.
7. Is any sentence over 20 words? Split it.
8. Any semicolon, contraction, passive voice with a known subject, or
   nominalization such as "perform an analysis"? Fix each one.
9. Does the same thing carry two names? Pick one name.

Write only the requested text. No preamble, no summary, no closing remarks.