prosolis c6bf36bddf Triage the whole queue from the keyboard, and never type an n
The last of the UX review's item 8. Ctrl+. and Ctrl+, step through the
underlines from anywhere in the text; the card that opens takes focus and
answers Tab / Shift+Tab / Enter / Del / ? / Esc itself. Answering a card
advances to the next by itself, and the last one closes and puts the caret
back in the prose — so a document is triaged in five presses of Enter.

The item asked for bare Tab or n/p. Neither can exist in a text editor: an
unmodified letter is a letter. They work fine once a card holds focus, which
is where the item wanted them; getting there needs a chord that is safe to
press mid-sentence, and mid-composition, so the entry keys are IME-guarded
like every other binding.

The queue is the underlines read off the decoration DOM in document order,
not the suggestion list: a stop she cannot see is worse than one she never
visits, and it guarantees the card can anchor itself.

Escape is stopped at the card. Unhandled it would also have left
distraction-free mode, restoring the sidebar and — via the rail-follows-the-
mode fix — pulling the rail out from under her mid-triage.

The legend is bilingual and leads with the pair language, unlike the card's
English buttons: those name what she is learning, this is an instruction for
operating Petal, like the status bar. Key names are as printed on her
keyboard (Entrée, Suppr, Intro, Supr). The es pack's own punctuation test
caught the "?" and is right in general; the key cap is one named exemption.

Verified in a real browser at 1517x810 on a fresh database with no model,
over CDP — a keystroke feature deserves real keystrokes. Both layouts, wrap
in both directions, the accept/dismiss/advance loop, Ask Petal and back, the
full triage-to-empty criterion, and Accept-all clicked from a keyboard card.
The wiring has no unit test for the reason items 6, 7 and 8 recorded: jsdom
has no layout. triage.ts is pure and tested; browser-verified is written
down as browser-verified.

Claude-Session: https://claude.ai/code/session_01GJHNvirh7Hzhc9RL3HAvz7
2026-07-28 21:11:42 -07:00

🌸 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.

S
Description
Petal is a self-hosted, privacy-first writing editor for an ESL user. It replaces Grammarly with a warm, bubbly web app that combines Tiptap rich text editing, auto-save cloud storage, and periodic AI-powered grammar/ESL suggestions backed by a local vLLM inference endpoint.
Readme
27 MiB
Languages
TypeScript 49.2%
Go 44.1%
Python 3.8%
CSS 1.7%
Shell 0.9%
Other 0.2%