Skip to Content
DevelopersArchitecture

Architecture

seedypod is two programs with a small, versioned contract between them.

Two tiers

Exactly one long-lived process owns the hardware: hald, a Rust daemon. It enforces every safety rule internally, so no caller can bypass them. That design answers a specific bug history in the upstream Python project, where the pump’s max-run cap lived in three places, scheduled watering skipped the low-water check, and each new process re-initialised PWM and glitched the light (ADR 0004).

Everything else is core: the tRPC routers, REST, MCP, scheduling, the grow cycle, alerts, the camera recorder, the Home Assistant bridge and the web UI. Core talks only through the HAL contract and never touches a pin.

One control plane, several surfaces

Every capability is a tRPC procedure first (ADR 0005). From there:

  • REST is generated from the same procedures by trpc-to-openapi at /api/*, with the spec at /api/openapi.json (reference).
  • MCP at /api/mcp calls the tRPC caller, so tools inherit the same validation and the same safety path (MCP for agents).
  • Live updates are a tRPC subscription over SSE (events.onChange), fed by an in-process event bus (ADR 0015). GET /api/ws streams the same events over a read-only WebSocket for clients that cannot speak tRPC.
  • Home Assistant gets the physical device from hald’s own MQTT discovery, and the grow-cycle extras from core’s bridge (ADR 0013).

Core stack

Hono on Node serves tRPC, the REST facade, MCP and the built SPA from one node server/dist/index.js. The UI is Vite, React 19 and TanStack Router, styled with Tailwind 4 and sleepypod ’s design system (ADR 0003, ADR 0016). Persistence goes through a Store interface: SQLite with drizzle on the unit, an in-memory store in tests and in the browser demo, held to one conformance suite (ADR 0010).

The choice of Hono and Vite over sleepypod ’s Next.js is about memory: the Gardyn’s Zero 2 W has 512 MB, and nothing in core needs server rendering.

Deployment topologies

The contract is the same in every topology, so a unit moves between them by changing one URL.

TopologyPi in the unithaldcoreWhen
A (default)Zero 2 WyesyesWhole stack inside the unit.
BZero 2 Wyeson a LAN boxSeveral units under one core, or if A is tight.
CPi 5yesyes, with on-device visionWhen on-device computer vision is wanted.

The original Zero W can run hald (it is cross-built for armv6) but is not expected to host core.

Demo mode

The live demo  is the same web UI built with VITE_DEMO=1: a tRPC link with in-browser handlers over TypeScript fakes of the HAL and seeded history. The simulator mirrors the pump guard’s rules, so the demo never shows behaviour a real unit would refuse.

Last updated on