Package garden is Gnotchi's Phase 1 on-chain slice: the one signature the owner wants (CLAUDE.md / the build brief's Phase 1 note, "adoption is the one signature"). Adopt mints a soulbound GRC721 gnome for the caller; a read and a Render page let anyone, including the gnoweb UI, see what that signature produced.
Grounded in gno.land/p/nt/grc721/v0's own reference consumer, examples/gno.land/r/demo/foo721 (NewToken/CallerTeller/wrapper shape), not written from memory -- the GRC721 API here (NewToken(name, symbol, id, rlm), RegisterExtension, the (_ int, rlm realm) Teller methods) is newer than the pre-crossing-call grc721 some training data remembers.
What this realm deliberately does NOT have: Approve, SetApprovalForAll, a public TransferFrom, Mint/Burn admin endpoints, or any notion of more than one gnome per address. The brief's Part 1 says "what it needs, and nothing more" -- a soulbound pet has no legitimate caller for any of those, so exposing them would only be surface to audit for no gameplay reason. Transfer is still provable: it is exercised directly against the ledger in garden_test.gno, which is honest because the extension hook that refuses it (soulboundExtension.OnTransfer) runs inside grc721's transfer path itself, not inside a wrapper this realm would otherwise own.
SECURITY: no code in this realm, now or later, may ever recover() around a call into ledger or token (grc721's PrivateLedger/Token). The soulbound guarantee below is real, but it is NOT that the ledger write never happens -- it does, before the panic -- it is that an *uncaught* panic aborts the whole enclosing transaction, so that write (and everything else the transaction did) is discarded and never committed on chain. p/nt/grc721/v0/types.gno says this outright, about extension hooks like soulboundExtension below: "Hooks run after the ledger write so they observe the post-movement state; only a caller that recovers from the panic keeps that write." A recover() anywhere between a ledger call and the transaction boundary -- even one added for an unrelated reason, even one several call-frames away -- would silently convert every refused transfer into a permanent, successful one. Don't add one. This is not limited to code textually inside this file: a pure `p/` package this realm calls runs in garden's own call frame too, so a helper as innocuous as `Try(func(){ ledger.TransferFrom(...) })` imported from some future `p/` dependency would break the same guarantee just as surely as a recover() written here directly.