The garden command
garden reads garden's publications from a terminal or a script. Each call is one read, and each reply is one JSON document on standard output.
Availability today. The garden command is built locally as the package @fernworks/garden and is not published to any registry; there is no public download. Its hosted endpoint is https://garden-api.fernworks.dev/ and requires a valid access key. What garden offers today and how to install it says what works now.
garden needs Node.js 22.12.0 or later.
The key and the endpoint#
- The key. garden reads the access key from the
GARDEN_API_KEYenvironment variable, and from nowhere else: no flag, no file, no other variable. An empty value counts as no key. Without a key, every read is refused asunauthorized, and nothing is sent. - The endpoint. garden uses the
--urlflag if it is given, then theGARDEN_URLenvironment variable, then the hosted endpointhttps://garden-api.fernworks.dev/. The endpoint must be HTTPS, or HTTP on a loopback address (one in127.0.0.0/8, or[::1]; not the namelocalhost), and must carry no user name, password, query or fragment. garden sends the key only to that endpoint and never follows a redirect.
The commands#
| Command | What it reads |
|---|---|
garden snapshot --id current|ID | the current publication, resolved once, or the exact one named |
garden vocabulary --snapshot ID | every value a facet, kind or responsibility may carry in the publication |
garden list --snapshot ID with filters | the units matching the filters, their listing metadata only, in id order |
garden read --snapshot ID --id UNIT | full units, their exact text with its revision and content hash |
garden resolve --snapshot ID --anchor NAME | the unit that carries an anchor |
garden changes --from ID --to ID | a comparison of two exact publications; no unit text, and it satisfies no read |
garden capabilities | the version, the result format, the six reads and the six MCP tools, offline |
garden mcp | the local MCP server over standard input and output (the MCP guide) |
--snapshot takes current or an exact publication id. Every read but changes resolves current once, and every request of that read names the exact id it resolved, so one read never mixes two publications. changes takes two exact ids and refuses current.
Flags every read takes:
--url URL: the endpoint, beforeGARDEN_URLand the hosted default.--call-id ID: your identity for the call, echoed in the reply; visible ASCII, 1 to 128 characters. Without it, garden generates one.--timeout-ms MS: the call's one deadline, in milliseconds, at most 30000. It spans every request of the call and is never reset. The default is 10000, and 30000 forread.
list filters, each repeatable: --language, --purpose, --technology, --task, --concern, --kind, --responsibility. At least one is required. Values of one filter are alternatives; different filters must all hold. Every value is literal, and a value the publication's vocabulary does not hold is refused. garden ranks nothing.
read flags:
--id UNIT: a unit to read, repeatable.--requires: read the units each selected unit requires, before the units that require them.--exclude UNIT: a unit never to read, repeatable. A read that reaches it stops withexcluded, and that unit is never fetched.--max-units N: at most N units, and never more than 16.--max-bytes N: at most N bytes of unit text, and never more than 262144.
A limit is a whole number written in decimal digits. You may lower a limit and never raise one.
Help and version are plain text, not a reply document: garden --help, garden help COMMAND or garden COMMAND --help (for mcp, only garden help mcp), and garden --version. They, and garden capabilities, need no key and no network.
export GARDEN_API_KEY=<your key>
garden snapshot --id current
garden read --snapshot <id> --id <unit> --requires
The reply#
Every reply is one JSON document, garden.result/v1, on one line of standard output:
| Field | Holds |
|---|---|
format | garden.result/v1; refuse any other value |
clientVersion | the version of the garden command that wrote it |
ok | true for a success, false for a refusal |
operation | the command: one of the six reads or capabilities; in a refusal, null when the command line named none of the six reads |
callId | your call id, or the one garden generated |
origin | the endpoint the call used, as garden wrote it: ending in /; null when none was used |
snapshot | the publication read, { "id", "publishedAt" }, the from and to pair of a comparison, or null |
delivery | each full unit delivered, { "id", "revision", "contentHash", "bytes" }, and their total bytes |
limits | the deadline and, for read, the unit and byte limits the call ran under |
result | the read's answer; null in a refusal |
error | { "kind", "subject" } in a refusal; null in a success |
A read's result holds each unit's family and exact original text. Its delivery lists the same units in the same order: contentHash is the SHA-256 of the unit's text as UTF-8, revision the SHA-256 of JSON.stringify([family, text]), and bytes the text's UTF-8 length. Check all three before you use a unit. Every other read delivers no unit text, and a refusal delivers nothing.
Error kinds#
kind | Meaning |
|---|---|
cancelled | the call was cancelled |
deadline | the call's deadline passed |
unavailable | garden could not be reached, failed, or limited the rate |
unauthorized | no key, or garden refused the key or its entitlement |
invalid-result | an answer that was malformed or cut off: unverified text, a mismatched identity, another protocol version, a redirect, a requires cycle |
private-data | the key would have left its credential (an argument, the endpoint or an answer spelled it), so nothing carrying it was sent or printed |
excluded | the read reached a unit you excluded |
budget | the read would pass its unit or byte limit |
not-found | garden holds no publication, unit or anchor by the name you gave |
invalid-request | your input or the command line was refused |
subject names what was refused: a unit, an anchor, a publication, a flag, or the step that failed. It never holds the key.
Exit status and output streams#
| Exit status | Meaning |
|---|---|
| 0 | a success: one reply with "ok": true |
| 2 | a typed refusal: one reply with "ok": false, and one line garden: KIND: SUBJECT on standard error |
| other | the process failed; there is no reply |
garden mcp is the one exception: when its own command line is refused, it starts no server and writes no reply, since its standard output carries the MCP protocol only. Its one line on standard error is garden mcp: invalid-request: SUBJECT, and its exit status is 2.
A process ended by a signal writes no reply. Standard output never holds anything but the one reply, so read it as JSON and check its format, callId and origin against the call you made.