Never say a feature is complete without running the actual binary.
cd /Users/steve.calvert/workspace/personal/glean-cli
mise run build # build the binary
./glean # run the TUI and test the feature manuallyFor TUI features specifically:
- Build the binary, run it, interact with the feature being built
- If it involves keystrokes (e.g.
/mode,@file picker), actually type them - If it involves streaming (stages, spinner, elapsed), ask a real question
- Screenshots from the user are ground truth — believe them over unit tests
Unit tests pass ≠ feature works. The TUI has UI state that tests cannot cover.
Before any git push, run tests and linters locally. They MUST pass.
go test ./... # all tests must pass
golangci-lint run # linter must be cleanEquivalently: mise run test:all (runs lint + test + build).
Pushing code that breaks CI is unacceptable. No exceptions.
- Repo:
github.com/gleanwork/glean-cli— pre-1.0, breaking changes OK - Module:
github.com/gleanwork/glean-cli - Task runner:
mise(not go-task) - Go version: 1.24
mise run build # build glean binary
mise run test # run tests
mise run test:all # lint + test + build (CI equivalent)
./glean # run TUI (requires valid GLEAN_HOST + token)internal/tui/— Bubbletea TUI (model.go, view.go, commands.go, filepicker.go, session.go, styles.go)internal/client/— Glean SDK wrapper + streaming HTTP clientinternal/auth/— OAuth PKCE + DCR flowcmd/— Cobra commands (search, chat, api, config, etc.)
- Worktree LSP errors are noise — the worktree (
/.claude/worktrees/) is stale. Always build in the main repo at/Users/steve.calvert/workspace/personal/glean-cli - Viewport key isolation — never pass
tea.KeyMsgto viewport in the catch-all; scroll keys are handled explicitly above - Collect-then-display for content — streaming stages show live via channel; content waits until complete
- No viewport jumping —
conversationActivepins viewport height;recalculateLayout()only called on terminal resize or deliberate state changes
- Rendering picker only in active state — UI elements visible before a conversation starts need to work in the welcome state too (
!m.conversationActivebranch in View()) - Skipping
mise run build && ./gleanverification — unit tests don't catch TUI rendering bugs - Spinner below input — spinner goes in the viewport content area, never in statusLine()
- Large decimal elapsed — show integer seconds (
12snot11.6s)