For agents · protocol
Protocol.
Everything an agent must know to speak to harness.talk without reading the source. Short on purpose. Each rule has an anchor so problem responses can point at it.
Reference grammar
A canonical reference is BOOK.CHAPTER[.VERSE[-VERSE]] with a lowercase book id. Human forms are accepted on input and always normalised on output.
ref := book "." chapter [ "." verse [ "-" verse ] ]
book := 2–3 lowercase letters, optionally prefixed by 1|2|3 (gn, ps, 1jn, re)
chapter := 1..N (N from /api/v1/books/{id})
verse := 1..M (M from the chapter)
Accepted on input, never emitted:
"John 3:16" "Jn 3.16" "1 John 5:7" "Psalm 119:176" "Song of Solomon 2:1"Book ids are listed at /api/v1/books. They are stable and will never be renumbered.
Quartet addressing
127.BOOK.CHAPTER.VERSE. Book is the canon ordinal (Genesis 1 … Revelation 66). Chapter and verse are 1-based. A zero collapses scope: verse 0 is the chapter, chapter 0 is the book, 127.0.0.1 is the corpus. Octets are limited to 255 by IPv4 — no chapter exceeds 150 and no verse exceeds 176, so nothing is unaddressable.
GET https://harness.talk/api/v1/resolve/127.43.3.16 # John 3:16
GET https://harness.talk/api/v1/resolve/127.19.23.0 # Psalm 23 (chapter)
GET https://harness.talk/api/v1/resolve/127.66.0.0 # Revelation (book)
GET https://harness.talk/api/v1/resolve/127.0.0.1 # corpus index
# locally, with harnessd running:
curl 127.43.3.16:1611Response envelope
Every verse object is the same shape wherever it appears — alone, in a range, inside a chapter, in search hits, or from the daemon.
{
"ref": "jn.3.16",
"display": "John 3:16",
"book": { "id": "jn", "name": "John", "ordinal": 43 },
"chapter": 3,
"verse": 16,
"text": "¶ For God so loued þ world, that he gaue his only begotten Sonne: ...",
"source": "kjv-1611",
"sha256": "…64 hex…",
"quartet": "127.43.3.16",
"url": "https://harness.talk/foundation/jn/3#v16"
}Fields are additive. New keys may appear; existing keys will not change meaning or type within /api/v1.
Hashes and the Merkle root
leaf(v) = SHA-256( v.ref + "\n" + v.text ) # UTF-8, no trailing newline
node(l,r) = SHA-256( bytes(l) || bytes(r) ) # raw 32-byte digests, not hex
# odd leaf pairs with itself
root = hex( fold over all 31,102 leaves in canon order )
published at /.well-known/harness.json → corpus.merkleRoot
and inside /exports/kjv.jsonl.gz → first lineThe leaf rule is deliberately trivial. If you cannot reproduce it in your language in five lines, it is wrong. Inclusion proofs (a leaf's sibling path to the root) are specified but not yet served — see Storage & integrity.
Errors
All errors are application/problem+json (RFC 9457). type is a URL into this page; title is the machine code below; status is the HTTP status; detail is for humans and may change.
| title | status | meaning |
|---|---|---|
ref_unparseable | 400 | Input is not a recognisable reference. Grammar is on /agents/protocol. |
book_unknown | 404 | No book matched the id, name, alias, or ordinal. |
chapter_out_of_range | 404 | Chapter exceeds the book's chapter count (given in `max`). |
verse_out_of_range | 404 | Verse exceeds the chapter's verse count (given in `max`). |
quartet_invalid | 400 | Not a 127.b.c.v address, or an octet > 255. |
source_not_ingested | 501 | The source exists in the registry but has no verified data for this request. Nothing is substituted. |
query_empty | 400 | Search requires ?q=. |
not_found | 404 | Nothing at this address. |
HTTP/1.1 404
Content-Type: application/problem+json
{
"type": "https://harness.talk/agents/protocol#book_unknown",
"title": "book_unknown",
"status": 404,
"detail": "No book with id 'zz'. See /api/v1/books for the 66 ids."
}Caching and headers
- Scripture responses are immutable for a given corpus:
Cache-Control: public, max-age=31536000, immutableplus a strongETag. SendIf-None-Matchand expect304. - Search and index responses use a short public cache (
max-age=300). X-Harness-Corpuscarries the source id;X-Harness-Rootcarries the Merkle root, on every 200.- CORS is open (
*) for GET. There is no authentication because there is nothing to protect — the API only reads.
Stability
/api/v1 is frozen at the field level: keys are additive only, ids never renumber, hashes never change for a given source id. A new corpus (a corrected KJV edition, the Geneva text) gets a new source id and a new root; the old one keeps serving. Breaking changes go to /api/v2 and /api/v1 stays up.