diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a02e5cf --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,97 @@ +# CLAUDE.md + +Working notes for Claude Code on pansy. [DESIGN.md](DESIGN.md) is the architecture +document and stays authoritative; this file is the operational stuff you'd +otherwise rediscover every session. + +## This is a vibe-coded project — say so + +**pansy is written by an LLM, with a human directing.** That is not a footnote, +it is a property of the software people should know before they trust it with +their garden plans. + +Rules, not preferences: + +- The README carries a prominent, near-the-top disclosure. It does not get moved + below the fold, softened into "AI-assisted", or quietly dropped in a rewrite. +- If you rewrite the README, the disclosure survives the rewrite. +- Anywhere else the project introduces itself (a landing page, a docs site, a + package description), it says the same thing. + +If you find yourself editing that section, the only acceptable direction is +clearer and more honest, never quieter. + +## Build and test + +pansy is a standalone Go module inside a parent workspace, so **`GOWORK=off` is +required** or the build picks up sibling modules: + +```sh +GOWORK=off go build ./... +GOWORK=off go test ./... +cd web && npx tsc --noEmit && npx vitest run && npm run build +make test # both halves +make build # web bundle → embed → CGO_ENABLED=0 static binary +``` + +`gofmt -l internal/` before committing. Note `internal/service/plants_test.go` is +already unformatted on `main` — leave it alone unless you're touching it, so the +diff stays about your change. + +## Architecture in one paragraph + +`internal/store` (hand-written SQL, `modernc.org/sqlite`, pure Go) → +`internal/service` (**the seam: every permission check and invariant**) → +`internal/api` (thin gin handlers: decode, call service, encode). Agent tools in +`internal/agent` are equally thin adapters over the *same* service methods, so +they inherit permission enforcement for free. If you are about to put a rule in a +handler, put it in the service instead. + +Frontend: React 19 + Vite + Tailwind 4 + TanStack Router/Query, built into +`internal/webdist/dist` and embedded with `embed.FS`. + +## Conventions that bite if you miss them + +- **Everything is centimeters**, stored as SQLite `REAL`. Imperial is a display + and entry concern only, in `web/src/lib/units.ts`. Two distinct scales live + there: *dimension* (m/ft — gardens, objects, the garden grid) and *spacing* + (cm/in — plant spacing, bed grid). Mixing them is what #47 was about. +- **Optimistic concurrency everywhere.** Every mutable row has `version`; PATCH + and DELETE carry it; the store returns `(current row, ErrVersionConflict)` on + mismatch and the API answers 409 with the row under `"current"`. +- **No-access is `ErrNotFound`, not `ErrForbidden`.** Existence is masked + deliberately. `ErrForbidden` means "you can see it but may not do that". +- **Plops (plantings) live in their parent object's local frame**, origin at the + object's center, `-y` is north. Moving or rotating a bed moves its plants free. +- **Soft removal**: "clear bed" sets `removed_at`; the editor reads + `removed_at IS NULL`. Hard delete is a different operation. +- **Migrations** are numbered `.sql` files in `internal/store/migrations/`, run + at startup, embedded. Never edit one that has shipped. +- **Every service mutation lands in history** (#48). If you add one, record it — + see `internal/service/revisions.go`. Multi-row operations pass all their + changes to a single `record` call so they undo as one unit. + +## Workflow + +Branch → PR → **Gadfly** reviews it automatically → consider every finding and +fix what's real → merge when the pipeline is green. Do not grade Gadfly findings. +A push to `main` builds the image and deploys to Komodo; the live instance at +`pansy.orgrimmar.dudenhoeffer.casa` updates a few minutes later. + +Workflow- and config-only changes (CI, this file, docs) go straight to `main` +without the PR dance. + +Planning happens in Gitea issues first: standalone issues under a tracking epic, +implemented in later per-issue sessions. + +## Environment + +`PANSY_PORT`, `PANSY_DB`, `PANSY_BASE_URL`, `PANSY_REGISTRATION`, +`PANSY_LOCAL_AUTH`, `PANSY_OIDC_*` — note it's `PANSY_DB` and `PANSY_PORT`, not +the `_PATH`/`_ADDR` names you might guess. Authentik is the primary IdP; +OIDC-first with local passwords as fallback. + +Agent config (v2): `OLLAMA_CLOUD_API_KEY` and `PANSY_AGENT_MODEL` (default +`ollama-cloud/glm-5.2:cloud`), set in Komodo. Model strings pass verbatim to +`majordomo.Parse`, so a comma-separated spec gives failover for free. +`majordomo` and `executus` are sibling repos at `../`. diff --git a/README.md b/README.md index 1a0626f..31e8e74 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ Self-hostable garden planner: drag beds, bags, and containers onto a real-scale field, click into them to place freeform plops of plants, and zoom out to see what's planted where. Go backend + React frontend, one static binary. +> ### 🤖 This is a vibe-coded project +> +> **Essentially all of the code in pansy was written by an LLM** (Claude), with a human directing the work, reviewing it, and deciding what ships. Every pull request also gets an automated adversarial review before it lands. +> +> That's said up front because you deserve to know it before you trust pansy with anything: it hasn't been through the kind of scrutiny a hand-written, widely-used project has. Read the code before you self-host it. Back up your database. Bugs here are the ordinary kind of bugs, not a scandal — but so is the fact that nobody hand-wrote the thing. + See [DESIGN.md](DESIGN.md) for the architecture. Work is tracked in this repo's issues — start from the tracking epic. ## Quickstart