Documentation
CLI reference
Eight verbs, what each one does, and what each one refuses.
Every command takes --root <PATH> to work on a repository other than the one
you are standing in. hi's own options go before the id, so nothing in your sentence is mistaken
for one.
| Command | What it does |
|---|---|
hi <ID> <sentence> | Capture. The family picks the file; a new family starts one. |
hi check | Structural problems only. Exits 1 on a broken file, never on unfinished intent. |
hi ls [--family F] [--retired] | Read back what you have agreed to. |
hi retire <ID> [reason] | Change your mind. Moves a criterion and its cases into ## Retired. |
hi issue <ID> [--create] | Print a ticket, or open a real GitHub issue with gh. |
hi export [FAMILY | file] | JSON for an agent, intent prose included. |
hi index | Rewrite the feature list inside INTENT.md, and nothing else in it. Rarely needed since 0.7.0: capture and retire keep it current. |
hi view [--out FILE] | One self-contained HTML page of the whole thing. |
hi seed | Write hi/AGENTS.md when it is missing, or replace it when it is still a template hi shipped. Refuses a file you edited. |
Capture
The default verb. There is no subcommand, because the thing you do most should be the thing you type least.
Since 0.7.0 a capture also refreshes the generated feature list in INTENT.md, and so
does hi retire. The list used to drift the moment somebody captured without running
hi index, and it did: three repositories using hi had a list disagreeing with their
own files, one of them by four criteria, and nobody had noticed. A list nobody has to remember to
refresh is a list that cannot be wrong.
That refresh is best effort. Your criterion is on disk before hi touches INTENT.md,
so a capture that stored what you typed is never reported as a failure because the list could not
be rewritten; it says so on stderr and exits 0. If you type a criterion into a file by hand, which
no verb ever sees, hi check notes that the list is behind without failing.
hi SEND-1 "I hit enter and the message shows up right away."
hi SEND-1.a "If I have no connection it queues and tells me."
hi --root ../other-repo CHECKOUT-1 "I can pay without making an account." The sentence you type is the sentence that lands in the file, word for word. hi collapses runs of whitespace so the line stays one line, and does nothing else to your words.
ls
hi ls
hi ls --family SEND
hi ls --retired
Reads the whole repository back as a tree, grouped by file, with cases nested under what they
are cases of. Every sentence is printed exactly as it sits in the file: hi does not capitalize
it, wrap it, or put anything in front of it. --family narrows to one family and
--retired includes what you changed your mind about.
check
hi check reports everything it finds but exits 1 on seven
structural problems, and 1.0 freezes both the list and the policy that they are structural only:
- a duplicate id
- a case with no parent
- an id that collides with a retired one
- a line shaped like an id that is not a valid one
- a family a file never declared
-
a criterion hi cannot read where it sits: stranded outside every section, or inside a fenced
code block under
## Criteria. Either way nothing would read it, and hi refuses to hand that id out again - a family two files both declare in their frontmatter. A new criterion in that family has no unique home, so capture refuses it rather than landing in whichever file sorts first. A family listed twice in one file is the same declaration written twice, not two homes, and is fine
Everything else is a note: that never touches the exit code: an empty
INTENT.md, a retirement with no reason, a feature list that is behind. Adding a
quality gate here would break the whole premise, because incomplete intent is the normal state
of intent. --json emits the same report as JSON, with the notes as a list under
stable codes (no-product-why, index-behind, index-markers,
unexplained-retirement) so a script can act on one without matching on English.
A file whose frontmatter declares a hi: version other than 1 is not a
check finding. Since 0.8.0 every verb refuses it by name before reading or writing anything,
because a version nobody checks is a version that can never be frozen. A file with no
hi: line is HI/1.
retire
hi retire SEND-3 "we decided this was a different product"
# the reason is optional, and you can add it later:
hi retire SEND-3 "the real reason, written once you knew it"
The criterion and every case beneath it move together into ## Retired, which hi
creates if the file has none. The reason is written under the block it explains, not appended to
the end. Only the root of a retirement is asked for a reason: a case went with its parent and
was never a separate decision.
issue
hi issue SEND-1
hi issue SEND-1 --create --repo CorvidLabs/chat Prints a ticket-shaped markdown block: the sentence as the heading, the feature's intent prose as context, and the cases as a nested list. A retired criterion cannot be turned into work.
A GitHub issue body is rendered with hard line breaks on, so a single newline in it is a
visible break even though the same bytes in a file are not. Since 0.6.0 hi issue
folds a newline inside a paragraph into a space on the way into the ticket, and leaves a blank
line, a list, a quote, a heading, a table, a rule, a fenced block and a deliberate two-space
break exactly where they are. It is a render-time fix: your file is never rewritten.
export
The payload carries two versions, and they are not the same thing. hi is the format
version of the files it read, and export is the shape of the envelope around them.
Splitting them is what lets the JSON grow without claiming the files changed.
hi export # the whole repository, including INTENT.md
hi export SEND # one family
hi export hi/send.md # one file The payload an agent should read before writing a spec. Retired criteria are kept apart from the live ones, so nothing downstream writes a spec for something you dropped.
view
hi view # writes intent.html at the repository root
hi view --out share.html One file, no network, no build step. A sticky rail lists every feature with its count, search highlights what matched, j and k move a cursor, Enter copies a link, and every id is an anchor that lands on its criterion even when a filter would have hidden it. Retired criteria are on the page behind a toggle. Nothing anywhere says whether anything is built, so nobody can read it as a progress report.
index
Regenerates the feature list inside INTENT.md, between its markers, and touches
nothing else in the file. The prose around it is yours.
Next
Bringing hi to a repo, including one an agent works in.