Skip to content

Documentation

The HI/1 format

What a hi file looks like, line by line, and why each rule is there.

A hi/*.md file is markdown a person would have typed anyway. Nothing below the frontmatter exists to serve the tool, and nothing the tool writes should look machine-generated.

markdown
---
hi: 1
families: [SEND, RECEIPT, SPEND]
owner: leif
---

# Chat

## Intent

I want to talk to people I trust without anyone in the middle being able to read it, and without it feeling like a security product. It should feel like texting.

## Criteria

- **SEND-1**  I hit enter and the message shows up right away, marked as sending.
  - **SEND-1.a**  If I have no connection it queues and tells me.
  - **SEND-1.b**  If the thread was deleted before it sends, it warns me first.
- **SEND-2**  It reaches them and the mark changes to sent.

- **RECEIPT-1**  I can tell sent from read without thinking about it.

- **SPEND-1**  An operator can cap what the service spends in a day.

## Retired

- **SEND-3**  My messages auto-delete after 24 hours.
  retired: we decided this was a different product

hi: 1 is the one machine-facing line, and it names the format version. A binary reads HI/1 and nothing else: a file declaring any other version is refused by every verb rather than read as though it were this one, and a file with no hi: line is HI/1. 0.8.0 is the 1.0 release candidate; HI-1.md is the contract 1.0 freezes.

What HI/1 promises

HI-1.md in the repository is the contract: what a 1.0 freezes, what stays free to change, the exit codes, the seven check kinds and the export envelope. It is worth reading before you build anything on top of hi, because it is also explicit about what hi does not promise. An id is permanent in the tree it was merged into, not across two branches that have not met yet.

Five rules

  1. A criterion is one markdown list item: a bold id, two spaces, and a sentence. However long the sentence runs it stays on one line, so criteria stay greppable and diffable.
  2. You write the id yourself, because you are the one who has to say it out loud. SEND-1 is a name, not a position.
  3. Letters are cases, numbers are steps, alternating strictly. Reading an id tells you what kind of thing it is.
  4. Ids are permanent and append-first. hi never renumbers anything, refuses an id that is already taken, and keeps a retired id reserved.
  5. A paragraph of prose is one line, and a blank line is the only break. In ## Intent, let the line keep going however long it runs and leave a blank line where you want a break. A newline inside a paragraph is not a break, so hi issue folds it away on the way into a ticket: a GitHub issue body is rendered with hard line breaks on, and hand-wrapped prose arrives there as a narrow column down a wide pane. The file it came from is never rewritten.

Why a list item, and not a bare line

This is the format's one correction, and it is worth knowing about. Criteria used to be written as bare SEND-1 sentence lines. They looked fine in the source, and every test passed, because every test asserted on what the parser read back.

Markdown joins consecutive plain lines into a single paragraph. So on GitHub, in any preview and on any docs site, the file rendered as one wall of run-together sentences. That falsified the first thing the format promises: that a hi file reads as an ordinary document with no tool installed. Making each criterion a list item fixed it, and cases indent two spaces per level so the tree renders as a nested list too.

The sections

  • ## Intent is human prose. What this feature is for and what it should feel like. This is the thing a spec can never carry, and the first thing an agent should read.
  • ## Criteria holds the lines.
  • ## Retired holds criteria you changed your mind about, keeping their ids spoken for. It is also where a reader learns the most: an agent handed hi/ alone, with no code and no help, got the product right, and the retirements were what taught it the rules.

Which files are criteria

A criteria file is lowercase. A family names its own file and hi lowercases it, so SEND writes hi/send.md, and an uppercase name in hi/ is never one hi wrote. Those are hi's own: hi/AGENTS.md and the hi/CLAUDE.md beside it, which carry the habit rather than criteria and stay out of the criterion count and the generated feature list.

Nothing is skipped quietly. hi check reads inside the files it does not parse as criteria and reports a criterion-shaped line as stray-criterion, because a criterion hi cannot see must be reported rather than lost. A fenced block stays an example, so documenting the format in a hi/README.md is not reported as a loss.

Two family names are therefore unavailable: AGENTS and CLAUDE would want the files hi keeps for itself. Capture refuses them on every platform, before writing anything.

What a sentence may carry

Inline markdown works: `code`, **bold**, *italic* and [links](url). Anything that looks like markup is escaped before it is interpreted, never executed. A fenced code block inside your intent prose is prose: the parser reads nothing structural between fences, so you can show an example of the format inside your own file.

A criterion is a plain sentence

No prefix, no fields, no slot in front of the sentence. For four releases hi required every criterion to open with As a <role>, and read that role back with a four-word heuristic. It is gone. It changed no behavior, it cost every line four words in front of the only part anyone reads, and parsing English prose to recover it was exactly the thing the format had refused elsewhere.

If a criterion needs to say who it speaks for, it says so in English, the way any sentence does. An operator can cap what the service spends in a day names its subject and reads as writing. Files written under the old rule still parse and render unchanged; those criteria are simply sentences that begin with As a.

The test that rule was carrying survives as advice. Try putting As a ___, in front of your sentence. If you cannot finish it, you wrote a fact about the system rather than something somebody wants. That costs nothing, because it happens in your head while you type.

Hand editing

The parser is looser than the writer. It accepts a bare line with no bullet, no emphasis around the id, and indented continuation lines, so a file you edited by hand is never rejected. Your file's own byte shape, its line ending, its trailing newline, its frontmatter style, is carried through a write rather than normalized, and hi never reflows prose it did not write.

Next

Ids covers the grammar and why permanence matters more than it sounds.