Two phases went up together because the tree could not separate them — the switcher's copy keys sit in the same files as Phase 22's, and the user chose to ship both rather than untangle them. The migration backfill is the part worth recording: `source` came out llm=100 / local=3, and the three are her existing mechanics rows claimed by type, which is exactly what 0013 said it would do. 9 documents, 33 versions, 103 suggestions, integrity ok. All three accounts are still on zh on purpose. Changing her pair from a shell is the thing this phase was built to stop needing. Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
🌸 Petal
A self-hosted, privacy-first writing editor with warm bubbly design, auto-save, and
local-LLM grammar/ESL suggestions. See petal-spec.md for the full
design spec and BUILD_PLAN.md for build progress.
Stack
Go + chi backend · SQLite (modernc, pure Go) · React + Vite + Tiptap + Tailwind v4 frontend ·
local vLLM/Ollama for AI suggestions. Single-binary deployment (frontend embedded via go:embed).
Local development
Two processes during development:
# 1. Backend (serves /api on :8080)
go run ./cmd/server
# 2. Frontend dev server (HMR on :5173, proxies /api → :8080)
cd web && npm install && npm run dev
Open http://localhost:5173 while developing.
Production build (single binary)
cd web && npm run build # emits web/dist (embedded by the Go binary)
cd .. && go build -o petal ./cmd/server
./petal # serves UI + API on :8080
Configuration is via environment variables — copy .env.example to .env.
Deployment
docker compose up -d --build # petal + the two Piper read-aloud sidecars
Behind Traefik on the parodia.dev VPS; vLLM stays on millenia over headscale.
Full runbook — first deploy, the LLM link, backups and restore — in
deploy/README.md.
Status
Early build, multi-session. Auth (Authentik OIDC) is next; Copyleaks plagiarism is
still parked — see BUILD_PLAN.md.