prose

The sentences the agents write to each other.

Reference

Runs
nothing. It reads the run journal itself.
Ships as
on, as a warning
Needs
nothing

How it works

Every other writing check reads your code. This one reads the handoffs.

What a contract is

When hyperpower runs, each step writes a JSON file into .hyperpower/runs/<run-id>/. The next step reads it. That file is the contract, and it is the only thing the next agent sees. A real one, shortened:

{
  "step": "understand",
  "summary": "This handles the settings flow properly.",
  "behaviour": "The stale value is returned by loadSettings",
  "assumptions": [
    { "id": "a1",
      "claim": "the settings endpoint probably returns a bare array",
      "confidence": "low" }
  ],
  "seams": [
    { "must_agree_on": "the json format" }
  ]
}

The shape is typed and validated, so claim is always a string. Whether that string means one clear thing is a separate question, and no schema can check it. That is this check's job.

It matters most for claim. A reviewer files a finding, then a skeptic reads the code and returns confirmed, refuted, or plausible. Plausible means the code could not settle it. A vague claim cannot be confirmed or refuted, so it comes back plausible, and plausible is the one result nobody can close. Fuzzy writing upstream turns into a human reading diffs downstream.

The thirteen fields it reads

Keys that hold a sentence. Everything else in the file, including ids, paths, numbers and the deliberately unshaped notes array, is skipped.

Field Holds Written by
claim a fact relied on, or a defect found every step
reason why an option was dropped every step
summary how the affected code works today the mapper
behaviour the requirement as observable behaviour the mapper, the designer
covers what an existing test covers the mapper
question something still unresolved the mapper, the planner
why_unresolved why searching did not settle it the mapper
task one requirement to implement the planner
asserts what a test must assert the planner
approach the chosen approach the planner, the fix loop
constraint what bounds a choice the planner
why why a file changes, or why a decision went that way the planner, the designer, the mapper
failure_scenario inputs, then the wrong output the reviewer

One more field is checked differently. must_agree_on names what two sides of a boundary have to agree about, and it takes one of six terms rather than a sentence: shape, nullability, unit, encoding, ordering, error contract.

The seven rules

Each rule has a name you use in config. The right-hand column is the same sentence written so the next agent cannot misread it.

Rule Catches Rewrite
vague a word nothing can verify handles QUIC properly → reads the SNI from the first QUIC datagram
passive the actor is missing the error is swallowed → handleFlow swallows the error
hedge doubt inside the sentence getUser may return null → getUser returns null, with confidence: low
pronoun opens on It, This, That, They This breaks on retry. → retryWrite breaks on the second attempt.
one-sentence two sentences in a one-sentence field split it, or narrow the claim
too-long over the word limit, 25 by default split it, or narrow the claim
vocabulary a must_agree_on outside the six terms the json format → shape

hedge is the one that pays for the others. The contract already carries doubt as typed values: confidence is high, medium or low, and the skeptic's verdict is confirmed, refuted or plausible. A hedge in the sentence duplicates a field that already exists, and the two can disagree. getUser may return null with confidence: high states two different things, and the next agent picks one. Assert in the sentence, doubt in the field.

Configuring it

Nothing is fixed. Rules, fields, word lists and the vocabulary are all lists under gates.prose, and each takes the same three forms.

Form Effect
vague: [...] replaces the shipped list
vague_add: [...] keeps the shipped list and appends
vague_remove: [...] keeps the shipped list and drops

_add and _remove are what you normally want. Replacing words.vague means retyping twenty-five words to change one.

Start narrow while a repo has a backlog:

gates:
  prose:
    rules: [vague, hedge]

Then teach it your tree and promote it once a run comes back clean:

gates:
  prose:
    blocking: true
    max_sentence_words: 20
    rules_remove: [passive]
    words:
      vague_add: [flow, pipeline]
      hedge_remove: [should]
    fields_add: [acceptance_note]
    vocabulary:
      must_agree_on_add: ["retry budget"]

fields_add is how a contract field your own fork added gets covered without touching the check. A vocabulary term may contain a space.

Two things to know before you tune it. An empty list means the shipped list, not nothing: rules: [] carries no value, so it arrives as an absent key and the default applies. Use enabled: false to check nothing. And a rule name the check does not implement reports "did not run" rather than quietly checking less than you asked for, as does a _remove that empties a list.

Whatever you set, the evidence names the rules and the fields that ran and flags a set that is not the default, so a narrowed check cannot be read as a full one.

What a pass does not mean

A pass means the sentence is checkable. It does not mean the sentence is true. Controlled language makes a wrong claim sound authoritative, which is the one failure mode this check adds. Truth stays with the skeptic.

The rules come from ASD-STE100, the controlled English written for aircraft maintenance manuals. Those manuals are not written to read well. They are written so a mechanic at 3am cannot misread them.