The only rule that matters
A spec is markdown. Write it in your own words, at whatever length the feature deserves. One rule carries all the weight:Anything you assert should be checkable by a person using the app.That is how it will be judged. The agent that judges your run never sees your code — it opens the app, clicks through it, and reads state back off the network. A claim it cannot settle that way is a claim it cannot pass you on.
Implementation choices are still worth writing down — put them under Constraints, where they read as instructions to the builder rather than as promises the judge has to keep.
A worked example
What the harness does with it
Before a single line is written, the derive stage reads your spec — only the spec, never the code — and turns the claims it can pin down into a checklist. The app does not exist yet, so nothing about the implementation can shape the bar it is later measured against. Each item names what to read and what the reading should say:
Each is held against one expectation: equals, contains, matches a pattern, or is at least some number.
The checklist is deliberately not the whole judgement. Anything it cannot express — “the error message is readable”, “the layout does not break” — stays with the judging agent, which checks it against the running app and cites what it saw. The checklist is the part the harness can keep books on; the judge covers the rest.
Run with
--review to read the checklist and approve it before anything is built. It is the cheapest moment to discover that a sentence you thought was precise was not.
Writing claims the judge can settle
Name the things it has to find. Anid or a stable selector turns “the balance is shown” into something a browser can read without guessing. The same goes for routes: /status beats “the status page”.
Say what should not happen. undefined, a blank panel, an unhandled rejection — a judge that knows the failure mode you fear will look for it specifically.
Describe changes as before and after, not as a delta. The judge reads network state before it touches the app and again afterwards, so “after the transfer, the recipient’s balance is higher than it was” is something it can stand behind. A bare “the balance increases by 2.5” leaves it nothing to compare against.
Be explicit about read-only versus transactional. A spec that signs anything needs HEDERA_OPERATOR_ID and HEDERA_OPERATOR_KEY exported for the run; a read-only one needs neither, and saying so in the spec keeps the builder from reaching for a key it does not need.
Keep one spec to one feature. A spec that passes is a foundation: harness run --spec specs/next.md --continue starts from the branch the last one produced, which is how a second feature builds on the first instead of re-litigating it.
Next
Run it
Install, point it at your repo, and go
Reference
Commands, flags,
harness.yaml, and run artifacts