From 20fe83c679d31816ad55f53812cb8665342f8b87 Mon Sep 17 00:00:00 2001 From: omartelo Date: Sat, 25 Jul 2026 19:10:34 -0300 Subject: [PATCH] docs: keep only the traps in CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Known Ceilings had drifted into decision history. The self-update bullet and the No AppImage note describe mechanism that already lives in internal/appupdate and docs/chromium-shell.md, and no work breaks by not knowing either — so they were costing a prompt every session to say what the code says better. Both are gone. The Windows and macOS bullets kept what breaks code (cmd.exe as the shell, a GUI build with no console, unsigned binaries) and dropped the roadmap of what is missing, which is issue material. The release fan-out narrative restated release.yml job by job and became one sentence, keeping the one trap in it: the version is injected into nfpm.yaml, never hand-edited there. Two things were missing, and both do break work when unknown. docs/hooks is a contract-first spec whose other side ships in omartelo/lich-plugin, so changing an endpoint or a payload breaks a repo this one cannot see, and the handler gives no hint of that. And a user-facing change needs its CHANGELOG [Unreleased] entry in the same PR, because the release notes are read from there and an entry written later missed its release. The Stack bullet for the frontend was describing xterm and CodeMirror, which frontend/CLAUDE.md already does whenever that directory is touched; it now points there instead. The api-types.ts rule stayed on the root, deliberately: it breaks in the backend direction, where the nested file never loads. The section intro now states the criterion the bullets are held to, so the next one written there has a bar to clear. --- CLAUDE.md | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 9e45cec1d..2e48f6b22 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,9 +17,13 @@ feature history lives in `CHANGELOG.md` — don't duplicate it here. runtime checks — the PTY is the model (`internal/terminal`: creack/pty on Unix, ConPTY on Windows). - **Shell**: system Chromium-family browser launched in `--app` mode (`internal/chromium`), persistent profile under the user config dir (`os.UserConfigDir` + `lich/chromium-profile`). Window closed = app exit. -- **Frontend**: React 18 + TypeScript + Vite. Terminal: xterm.js 6 + WebGL addon. Code/Review dock: CodeMirror. - Sessions spawn any registered provider (`internal/providers`: Claude Code, Codex, OpenCode, Crush). Service shapes - are hand-owned in `frontend/src/lib/api-types.ts` (mirrors of the Go structs' JSON tags — keep in sync). +- **Frontend**: React 18 + TypeScript + Vite; the UI rules and the visual system are `frontend/CLAUDE.md` and + `frontend/DESIGN.md`. Sessions spawn any registered provider (`internal/providers`: Claude Code, Codex, OpenCode, + Crush). Service shapes are hand-owned in `frontend/src/lib/api-types.ts` — touch a Go struct's JSON tags and that + mirror moves in the same change; there is no codegen. +- **Session hooks**: `docs/hooks/` is the canonical, contract-first spec. lich owns the server side; the scripts + live in the companion repo `omartelo/lich-plugin`, so an endpoint or payload change breaks a repo this one cannot + see — move the contract first, then both sides. - **Build/tasks**: [Task](https://taskfile.dev) — see Commands. ## Commands @@ -36,14 +40,14 @@ task package # .deb, .rpm, .pkg.tar.zst into bin/ (needs nfpm) task package:windows # bin/lich-setup.exe installer (needs Inno Setup 6 — CI/Windows) ``` -Frontend in isolation: `cd frontend && pnpm run build` (runs `tsc` + `vite build`). - ## Local Gate (before every commit / PR) - `gofmt -l .` clean (fix with `gofmt -w .`) and `go vet ./...` clean. - `cd frontend && pnpm check` clean — biome is the frontend's gofmt + vet (fix with `pnpm format`). - `go test ./...` (backend) and `cd frontend && pnpm test` (frontend) green — or `task test` for both. - `cd frontend && pnpm build` succeeds (tsc typecheck + vite). +- Shipped anything a user can see? Its `CHANGELOG.md` `[Unreleased]` entry lands in the same PR — the release notes + are read from there, so an entry written later is an entry that missed its release. - Touched an OS seam or a `_test.go` build tag? Run the same cross-compile loop CI runs: `for os in linux darwin windows; do GOOS=$os go build ./... && GOOS=$os go vet ./...; done` Cross-compiling only proves it builds — label the PR `ci:os` to run the backend suite on real Windows and macOS @@ -75,12 +79,11 @@ Non-negotiable rules. A violation means the work is not done. ## Releases -Push a `vX.Y.Z` tag. `.github/workflows/release.yml` fans out into three parallel build jobs — `linux` (packages), -`windows` (exe + Inno Setup installer), `mac` (both-arch raw binaries), each running the backend suite on its own -OS — then `release` fans in (one `checksums.txt`, notes from the matching `CHANGELOG.md` section) and `aur` -publishes `lich-bin`. A `workflow_dispatch` run from any branch exercises the whole pipeline without publishing. -The version comes from the git tag (`git describe` in the Taskfile, env `VERSION` overrides) and is injected into -`build/linux/nfpm/nfpm.yaml`. +Push a `vX.Y.Z` tag — `.github/workflows/release.yml` builds every OS, runs the backend suite on each, publishes the +artifacts and the AUR `lich-bin`, and takes the release notes from the matching `CHANGELOG.md` section. A +`workflow_dispatch` run from any branch exercises the whole pipeline without publishing. The version comes from the +git tag (`git describe` in the Taskfile, env `VERSION` overrides) and is injected into `build/linux/nfpm/nfpm.yaml` +— never hand-edit it there. Before tagging: @@ -90,7 +93,8 @@ Before tagging: ## Known Ceilings -Deliberate limits and shortcuts — one line of *what and where*; the mechanism and its history live in the code and +Deliberate limits and shortcuts. A bullet earns its place by naming a trap — something that breaks work when +nobody knows it and that the call site never shows. The mechanism and the history stay in the code and `CHANGELOG.md`. - **Session cwd is polled** from the PTY child (`internal/terminal/cwd.go`, per-OS readers behind build tags); a @@ -104,19 +108,13 @@ Deliberate limits and shortcuts — one line of *what and where*; the mechanism - **Hidden sessions are serialized and destroyed**: 2MB replay rings on both sides (`frontend/src/lib/terminal/replay-buffer.ts` page-side, `internal/terminal/replay.go` backend-side — the latter survives a full page reload). waveterm's disk filestore is the upgrade path if size ever matters. -- **Terminal I/O rides the loopback WebSocket**; when the socket is down, output falls back to `/events` and input - to the RPC — slower, never broken. +- **Terminal I/O degrades, never breaks**: with the WebSocket down, output falls back to `/events` and input to the + RPC — slower, still working. - **Single instance via the pinned port**: the bind is the lock (`internal/singleton`); a duplicate launch focuses the running window (best-effort, untested against a real window) and exits 0. -- **Self-update** (`internal/appupdate`): checks at startup, then hourly. Self-apply is Windows/macOS only; Linux - pastes a distro-specific command (AUR `lich-bin` on Arch, `install.sh` elsewhere) and relaunches through - `/restart` (`internal/restart`). - **Reordering rides dnd-kit's pointer sensors** (`frontend/src/lib/use-sortable-list.ts`); the activation distance is load-bearing — without it plain clicks stop selecting a session. -- **No AppImage** — deliberate (`docs/chromium-shell.md`; CEF is the bundling path if it ever matters). Ships - `.deb`/`.rpm`/`.pkg.tar.zst`, `install.sh`, and AUR `lich-bin`. -- **Windows is experimental**: cmd.exe shell, GUI subsystem build — no console, diagnostics in - `%AppData%\lich\lich.log`. Missing: code signing, winget manifest, Windows PTY tests. -- **macOS is experimental**: unsigned raw binaries only (Gatekeeper quarantines; no `.dmg`/Homebrew yet); the window - path has not been smoke-tested on real hardware. Only darwin-specific code: the browser candidates - (`internal/chromium`). +- **Windows is experimental**: cmd.exe is the shell, and the GUI subsystem build has no console — diagnostics only + reach `%AppData%\lich\lich.log`. The PTY has no Windows tests. +- **macOS is experimental**: the window path has never run on real hardware, and the binaries are unsigned, so + Gatekeeper quarantines them. Only darwin-specific code: the browser candidates (`internal/chromium`).