Um padrão de escrita da aviação de 1986 fez meu modelo de IA escrever documentações técnicas melhores
Uma especificação de escrita criada para manuais de manutenção de aeronaves em 1986, empacotada como uma skill do Claude Code, resolveu a documentação que meu modelo insistia em escrever mal.
Disponível em: EN ·PT
Documentação técnica escrita por um modelo é agradável de ler e envelhece mal. Seis meses depois o arquivo não responde as perguntas que eu realmente tenho, então eu acabo reescrevendo mais da metade.
Uma especificação de escrita criada para manuais de manutenção de aeronaves em 1986 resolveu boa parte disso pra mim. Este post é sobre como eu empacotei ela como uma skill, onde instalar, e como escolher entre chamar a skill na mão ou deixar o modelo chamar sozinho.
Tudo aqui assume Claude Code. O formato da skill, os caminhos de instalação e as regras de invocação são específicos do Claude Code.
O que estava errado na documentação
O texto nunca estava incorreto. Essa é a parte que demorei para conseguir nomear.
O modelo escrevia que um componente é confiável, sem nenhuma medição por trás da palavra. Citava uma restrição do tipo “o agente não pode escrever aqui” sem dizer o que impede o agente de escrever ali. Escrevia “atualizado recentemente” num arquivo que alguém abre um ano depois. Descrevia uma etapa que o próprio modelo decide como se o resultado fosse fixo.
Todas essas frases passam por uma revisão. Elas falham depois, quando quem lê o arquivo não tem nenhuma memória do dia em que ele foi escrito.
De onde vem o padrão
ASD-STE100, Simplified Technical English. A indústria aeroespacial europeia publicou em 1986, e a edição atual é de janeiro de 2025. São 53 regras e um dicionário de cerca de 900 palavras aprovadas, onde cada palavra carrega um significado e uma função gramatical.
Ele existe porque um mecânico lendo um manual de reparo num idioma que não é o dele não pode adivinhar. Ler errado um manual de reparo mata gente, então o setor especificou a própria língua.
O que transfere para software é a parte mecânica. Uma instrução por frase. Limites duros de palavras, 20 para uma instrução e 25 para uma descrição. Voz ativa. Sem ponto e vírgula. Um nome para cada coisa, mantido no documento inteiro.
O que eu mudei para código
Joguei fora o dicionário de 900 palavras. Travar vocabulário faz sentido em manual de reparo e nenhum sentido num código cheio de identificadores.
Mantive a disciplina de frase e adicionei as regras que resolviam o meu problema de verdade:
- Toda afirmação de capacidade carrega evidência no mesmo parágrafo, ou carrega a palavra “unverified”.
- Toda restrição a um agente nomeia o ponto onde é aplicada, o hook, a regra de permissão ou o check de CI. Restrição sem nada por trás carrega as palavras “convention only”.
- Datas absolutas em ISO. Nada de “recentemente”, “atualmente” ou “no momento”.
- Toda etapa que um modelo decide vem marcada como tal, para que uma etapa fixa e uma etapa do modelo nunca tenham a mesma voz.
- Nenhum verbo mentalista para descrever um modelo. Nada de “entende” ou “sabe”, só o que dá para observar: lê, escreve, chama, retorna.
- Nunca inventar evidência. Uma lacuna marcada é output correto. Uma citação inventada é defeito.
Instalando no Claude Code
Uma skill é um diretório com um arquivo SKILL.md dentro. O nome do diretório é o nome da skill.
Para uma skill pessoal, disponível em todos os projetos da sua máquina:
~/.claude/skills/ste-technical-writing/SKILL.md
Para uma skill de projeto, commitada no repositório e compartilhada com todo mundo que clonar:
<repo>/.claude/skills/ste-technical-writing/SKILL.md
O arquivo é idêntico nos dois casos. Essa eu mantenho pessoal, porque ela codifica como eu quero ler documentação, e não uma decisão de time. Convenção de time pertence ao repositório, onde um code review pode discordar dela.
O frontmatter precisa de um name e uma description. Adicionar user-invocable: true deixa a skill disponível como slash command pelo nome.
Deixar o modelo decidir versus chamar você mesmo
Existem duas formas de uma skill entrar na sessão, e elas se comportam de maneira diferente.
Auto-invocação. Só a description fica no contexto do modelo. Quando o seu pedido casa com ela, o modelo carrega o corpo do SKILL.md e segue as regras. Isso não custa praticamente nada até disparar, que é justamente o desenho da coisa. Também significa que uma description vaga nunca dispara, e uma description gulosa dispara em arquivos que você nunca quis tocar.
Invocação direta. Você digita /ste-technical-writing e o corpo carrega, toda vez, independente do que o modelo decidiria. Numa execução não interativa, começar o prompt com “Use the ste-technical-writing skill” faz o mesmo trabalho.
Eu uso auto-invocação para documentação escrita no meio de outra tarefa, uma descrição de PR no fim de uma feature por exemplo, onde eu não estou pensando em regra de escrita nenhuma. Uso invocação direta quando o documento é a tarefa e eu quero o mesmo comportamento em toda execução.
Tem um terceiro estado que vale conhecer. Rodar claude --print --disable-slash-commands desliga as skills por completo. Foi essa flag que produziu os outputs “sem a skill” logo abaixo, com o mesmo prompt e o mesmo modelo.
A description é a interface de verdade
A maior parte da minha iteração foi na description, não nas regras.
A description é a única coisa que o modelo enxerga na hora de decidir se carrega a skill, então ela precisa nomear as classes de documento explicitamente: README, CLAUDE.md, AGENTS.md, architecture decision record, runbook, nota de incidente, guia de migração, descrição de pull request, release notes, changelog.
As exclusões importam mais que as inclusões. A minha description diz que a skill não se aplica a código, identificadores, sintaxe de comando, prompts, arquivos SKILL.md, nem a nada que precise de voz. Antes dessa linha, a skill disparava enquanto eu escrevia outras skills e reescrevia instrução feita para um agente como prosa feita para uma pessoa.
Como isso fica na prática
Criei um projeto fictício para poder mostrar isso publicamente: um CLI que lê uma issue do GitHub, escolhe um label e rascunha uma resposta para o mantenedor aprovar. Dez linhas de notas cruas de engenharia, um pedido da seção “How it works” do README, rodado com e sem a skill.
O que foi medido, e o que não foi.
Sem a skill:
On a 200-issue sample from May 2026, 173 labels were correct. Treat the
suggestion as a starting point, not a decision.
Com a 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.
O primeiro dá o número e emenda um conselho que não estava em nota nenhuma. O segundo dá o número, diz de onde veio a amostra, e nomeia o que ninguém mediu e o que nenhum teste cobre.
O que impede o agente, e o que não impede.
Sem a skill:
The agent should never modify the billing/ directory or push directly to main.
Com a 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.
A primeira versão dá o mesmo peso a duas restrições na mesma frase. Uma delas o agente realmente não consegue atravessar. A outra existe só na cabeça de quem escreveu. Lendo a primeira versão, não dá para saber qual é qual.
Quando isso era verdade.
Sem a skill:
The label matching logic was recently updated and currently supports the new
taxonomy. The model version will be upgraded soon.
Com a skill:
labels.json holds the label taxonomy. Harbormaster reads the model id from
config/model.json.
“Recentemente” em relação a quando? A última frase ainda promete uma mudança que ninguém garantiu, então ela já nasce vencida. A segunda versão aponta para o arquivo que tem a resposta, e continua verdadeira depois que o valor muda.
O que isso não resolve
O padrão governa a forma. Uma skill transforma um parágrafo vazio num parágrafo vazio limpo, confiante e bem pontuado, e não torna nenhuma afirmação verdadeira.
O output também fica mais chato. No exemplo acima, quase toda frase começa com os mesmos dois sujeitos. Essa é a troca, e é por isso que a skill exclui explicitamente copy de marketing, ensaio e qualquer coisa que precise de voz. Especificação de torque aplicada a um poema não produz nenhum dos dois.
E as regras mecânicas são as verificáveis. Saber se uma frase faz sentido continua exigindo uma pessoa. Quem mantém o padrão original diz com todas as letras que nenhum software certifica conformidade completa, e eles estão certos.
Uma regra que dá para verificar é uma regra que dá para entregar a um modelo. O resto é gosto, e gosto não sobrevive a uma entrega.
A skill completa
Copie isso para ~/.claude/skills/ste-technical-writing/SKILL.md e ela funciona em todos os projetos da sua máquina.
---
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.