Add CLAUDE.md and a prominent vibe-coded disclosure in the README
Build image / build-and-push (push) Canceled after 11s
Build image / build-and-push (push) Canceled after 11s
pansy is written by an LLM with a human directing. That belongs near the top of the README, not in a footnote — someone deciding whether to self-host this and point it at their own data should know before they decide, not after. The disclosure says what it actually means in practice (less scrutiny than a hand-written project, read the code, back up the database) rather than a vague "AI-assisted" hedge. CLAUDE.md collects the operational details that otherwise get rediscovered every session: GOWORK=off, the store/service/api seam and why rules go in the middle layer, the two unit scales, version-guarded writes, ErrNotFound-as-existence-mask, the branch/Gadfly/merge/deploy loop, and the env var names that aren't guessable. It also makes the disclosure a standing rule: if the README is ever rewritten, that section survives the rewrite, and the only acceptable edit is a clearer one. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
This commit is contained in:
@@ -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 `../`.
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user