BubbleTea Code Review Quick Reference Issue Type Reference Elm architecture, tea.Cmd as data references/elm-architecture.md Model state, message handling references/model-update.md View rendering, Lipgloss styling references/view-styling.md Component composition, Huh forms references/composition.md Bubbles components (list, table, etc.) references/bubbles-components.md CRITICAL: Avoid False Positives
Read elm-architecture.md first! The most common review mistake is flagging correct patterns as bugs.
NOT Issues (Do NOT Flag These) Pattern Why It's Correct return m, m.loadData() tea.Cmd is returned immediately; runtime executes async Value receiver on Update() Standard BubbleTea pattern; model returned by value Nested m.child, cmd = m.child.Update(msg) Normal component composition Helper functions returning tea.Cmd Creates command descriptor, no I/O in Update tea.Batch(cmd1, cmd2) Commands execute concurrently by runtime ACTUAL Issues (DO Flag These) Pattern Why It's Wrong os.ReadFile() in Update Blocks UI thread http.Get() in Update Network I/O blocks time.Sleep() in Update Freezes UI <-channel in Update (blocking) May block indefinitely huh.Form.Run() in Update Blocking call Review Checklist Architecture No blocking I/O in Update() (file, network, sleep) Helper functions returning tea.Cmd are NOT flagged as blocking Commands used for all async operations Model & Update Model is immutable (Update returns new model, not mutates) Init returns proper initial command (or nil) Update handles all expected message types WindowSizeMsg handled for responsive layout tea.Batch used for multiple commands tea.Quit used correctly for exit View & Styling View is a pure function (no side effects) Lipgloss styles defined once, not in View Key bindings use key.Matches with help.KeyMap Components Sub-component updates propagated correctly Bubbles components initialized with dimensions Huh forms embedded via Update loop (not Run()) Critical Patterns Model Must Be Immutable // BAD - mutates model func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.items = append(m.items, newItem) // mutation! return m, nil }
// GOOD - returns new model func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { newItems := make([]Item, len(m.items)+1) copy(newItems, m.items) newItems[len(m.items)] = newItem m.items = newItems return m, nil }
Commands for Async/IO // BAD - blocking in Update func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { data, _ := os.ReadFile("config.json") // blocks UI! m.config = parse(data) return m, nil }
// GOOD - use commands func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, loadConfigCmd() }
func loadConfigCmd() tea.Cmd { return func() tea.Msg { data, err := os.ReadFile("config.json") if err != nil { return errMsg{err} } return configLoadedMsg{parse(data)} } }
Styles Defined Once // BAD - creates new style each render func (m Model) View() string { style := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205")) return style.Render("Hello") }
// GOOD - define styles at package level or in model var titleStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
func (m Model) View() string { return titleStyle.Render("Hello") }
When to Load References First time reviewing BubbleTea → elm-architecture.md (prevents false positives) Reviewing Update function logic → model-update.md Reviewing View function, styling → view-styling.md Reviewing component hierarchy → composition.md Using Bubbles components → bubbles-components.md Review Questions Is Update() free of blocking I/O? (NOT: "is the cmd helper blocking?") Is the model immutable in Update? Are Lipgloss styles defined once, not in View? Is WindowSizeMsg handled for resizing? Are key bindings documented with help.KeyMap? Are Bubbles components sized correctly?