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 commands#

CommandWhat it reads
garden snapshot --id current|IDthe current publication, resolved once, or the exact one named
garden vocabulary --snapshot IDevery value a facet, kind or responsibility may carry in the publication
garden list --snapshot ID with filtersthe units matching the filters, their listing metadata only, in id order
garden read --snapshot ID --id UNITfull units, their exact text with its revision and content hash
garden resolve --snapshot ID --anchor NAMEthe unit that carries an anchor
garden changes --from ID --to IDa comparison of two exact publications; no unit text, and it satisfies no read
garden capabilitiesthe version, the result format, the six reads and the six MCP tools, offline
garden mcpthe 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:

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:

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:

FieldHolds
formatgarden.result/v1; refuse any other value
clientVersionthe version of the garden command that wrote it
oktrue for a success, false for a refusal
operationthe command: one of the six reads or capabilities; in a refusal, null when the command line named none of the six reads
callIdyour call id, or the one garden generated
originthe endpoint the call used, as garden wrote it: ending in /; null when none was used
snapshotthe publication read, { "id", "publishedAt" }, the from and to pair of a comparison, or null
deliveryeach full unit delivered, { "id", "revision", "contentHash", "bytes" }, and their total bytes
limitsthe deadline and, for read, the unit and byte limits the call ran under
resultthe 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#

kindMeaning
cancelledthe call was cancelled
deadlinethe call's deadline passed
unavailablegarden could not be reached, failed, or limited the rate
unauthorizedno key, or garden refused the key or its entitlement
invalid-resultan answer that was malformed or cut off: unverified text, a mismatched identity, another protocol version, a redirect, a requires cycle
private-datathe key would have left its credential (an argument, the endpoint or an answer spelled it), so nothing carrying it was sent or printed
excludedthe read reached a unit you excluded
budgetthe read would pass its unit or byte limit
not-foundgarden holds no publication, unit or anchor by the name you gave
invalid-requestyour 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 statusMeaning
0a success: one reply with "ok": true
2a typed refusal: one reply with "ok": false, and one line garden: KIND: SUBJECT on standard error
otherthe 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.