The garden HTTP API

garden serves maintained engineering guidance as immutable publications, called snapshots. The HTTP API reads them. It is read-only: every request is a GET, and nothing a request sends is stored as content.

Availability today. garden's hosted endpoint is https://garden-api.fernworks.dev/. It serves current and historical publications to a valid access key. There is no public sign-up.

Requests#

Every request carries an access key as a bearer credential:

GET /v1/snapshots/current HTTP/1.1
Host: garden-api.fernworks.dev
Authorization: Bearer <your key>

The key is the only credential. garden sets no cookie and asks for no other header. Keep the key out of URLs, logs and files you share: garden reads it only from the Authorization header, and never echoes it in an answer.

Request headers may total at most 16,384 bytes. Query parameters are accepted by the list read and the comparison only.

The reads#

A publication is named by its exact id, or by current, which garden resolves to the exact id of the publication current at that moment.

RequestAnswer
GET /v1/snapshots/currentthe current publication: { "id": …, "publishedAt": … }
GET /v1/snapshots/:snapshotthat exact publication, in the same form; a missing id is not found, never current
GET /v1/snapshots/:snapshot/vocabularyevery value a facet, kind or responsibility may carry in that publication
GET /v1/snapshots/:snapshot/unitsthe units matching the filters: their listing metadata, in id order, with the exact count
GET /v1/snapshots/:snapshot/units/:idone unit's family and exact text, with its revision and content hash
GET /v1/snapshots/:snapshot/anchors/:anchorthe id of the unit that carries the anchor, as a JSON string
GET /v1/snapshots/:to/changes?from=:fromthe comparison of two exact publications by revision and content hash

Resolve once, then read by the exact id#

Resolve current once, then name the exact id it answered in every later read. Each read then comes from that one publication, even if a newer one becomes current while you read. changes takes two exact ids and refuses current.

Listing units#

GET /v1/snapshots/:snapshot/units takes the filters language, purpose, technology, task, concern, kind and responsibility. A filter may be repeated: values of one filter are alternatives, and different filters must all hold. A unit that names no value for an applicability facet (language, purpose, task, concern) applies everywhere and matches any value of that facet; technology names what a unit is about, so a unit with no technology matches no technology filter. A value the publication's vocabulary does not hold is refused, and the refusal names the vocabulary's values. With no filter the listing holds every unit. There is no pagination and no truncation: the count is exact.

GET /v1/snapshots/<id>/units?language=typescript&task=implement HTTP/1.1

The listing carries each unit's id, kind, title, when it applies, summary, facets, option group, the units it requires and contains, related units, and its verification record. It never carries a unit's text.

Reading a unit#

GET /v1/snapshots/:snapshot/units/:id answers:

{ "family": "…", "content": "…", "revision": "…", "contentHash": "…" }

content is the unit's exact original text. contentHash is the SHA-256 of that text as UTF-8, and revision is the SHA-256 of JSON.stringify([family, content]), both in lowercase hexadecimal. Verify both before you use the text. A unit's front matter names the units it requires; read those too when the unit's instruction depends on them.

Comparing two publications#

GET /v1/snapshots/:to/changes?from=:from answers which units were added, changed and removed between the two publications, each with the revision and content hash before and after, a count, and whether the vocabulary changed. It delivers no unit text.

Response headers#

HeaderMeaning
X-Garden-Protocolthe version of this HTTP contract, 1, on every answer
X-Garden-Snapshotthe exact id of the publication a successful read came from
Content-Typeapplication/json; charset=utf-8
Cache-Controlno-store

Check X-Garden-Protocol on every answer and refuse any other version. Check that X-Garden-Snapshot names the publication you asked for.

Errors#

A refused request answers with a JSON body of one shape:

{ "error": { "kind": "…", "input": "…", "message": "…" } }

kind is the machine-readable reason, input names what was refused (a field, an id, an anchor, a publication), and message is for a person. The body never carries the key or any internal detail.

StatuskindMeaning
400unknown facet, unknown value, unknown kind, unknown responsibilitya list filter garden does not know, or a value the publication's vocabulary does not hold
400invalid request, invalid operationa malformed request, a misplaced query parameter or a bad comparison
401unauthorizedno key, or a key garden does not accept
403forbiddena key without a live entitlement
404no snapshot, unknown id, unknown anchor, not foundthe publication, unit, anchor or read named is not there
405method not alloweda method other than GET
431invalid requestrequest headers over 16,384 bytes
503unavailablegarden could not answer; try again later

A missing exact publication is never answered with current.