How the No-Mistakes TUI Renders Run Status and Findings with Bubble Tea

The no-mistakes TUI uses a three-panel Bubble Tea layout to render run status, findings, and diffs through composable helper functions in view.go, pipeline.go, and review.go.

The kunchenguid/no-mistakes repository implements a terminal UI (TUI) built with the Bubble Tea framework to visualize pipeline execution and code review findings. Understanding how this TUI renders run status and findings requires examining the strict Design MD specification and the composable rendering pipeline that translates internal state into styled terminal output.

Three-Panel Layout Architecture

The TUI follows a vertical stack architecture defined in the Design MD specification. The layout consists of three distinct panels:

  • Pipeline box: Displays the current step name, its execution status, and action-bar controls
  • Findings/Diff box: Shows either a scrolling list of findings or a diff view, depending on the active toggle
  • Action bar / help overlay: Provides keyboard shortcuts and contextual controls

The top-level composition occurs in internal/tui/view.go, where the View() method of the main Model orchestrates these panels by delegating to specialized rendering functions.

Rendering the Pipeline Box and Step Status

Status Icons and Step States

The renderPipelineBox function in internal/tui/pipeline.go handles the upper panel visualization. It prints step names alongside colored status icons determined by the statusIcon function around line 150. This function maps status constants—StepStatusRunning, StepStatusSuccess, StepStatusFailure—to specific Unicode symbols and Lip-gloss colors.

Real-time updates originate from the daemon via IPC events (ipc.EventStepCompleted, ipc.EventStepStarted). When the handleStepCompleted method receives an event, it updates Model.steps with the new StepStatus and triggers a re-render:

func (m *Model) handleStepCompleted(evt ipc.Event) {
    m.steps[evt.StepName].Status = evt.Status
    if evt.Findings != nil {
        m.stepFindings[evt.StepName] = *evt.Findings
    }
    if m.showDiff && evt.Diff == nil {
        m.showDiff = false
    }
    m.resetFindingSelection(evt.StepName)
}

Diff Toggle Integration

The UI supports toggling between findings and diff views via the d key. The showDiff boolean flag in the model controls which view appears. As implemented in internal/tui/pipeline.go lines 208-214, the action bar label updates dynamically to reflect the current mode, switching between "show diff" and "show findings" indicators.

Rendering Findings with Selection

Parsing and Pre-selection

The renderFindings function in internal/tui/review.go processes JSON-encoded findings strings through parseFindings. It initializes a default selection map where all agent-produced findings are pre-selected automatically:

func renderFindings(raw string, width int) string {
    f, _ := parseFindings(raw)
    selected := map[string]bool{}
    for _, it := range f.Items {
        if it.ID != "" {
            selected[it.ID] = true
        }
    }
    content, _ := renderFindingsWithSelection(raw, width, 0, selected, 0)
    return content
}

The renderFindingsWithSelection function (lines 71-90 in review.go) formats each line with specific UI elements:

  • Cursor indicator (>) styled in primary-action blue
  • Checkbox state ([x] for selected, [ ] for unselected) with green highlighting
  • Severity icons (⚠️) and file paths
  • Optional [user] tags for user-added findings

Lip-gloss applies the color scheme: dim styling for unfocused items, bright colors for active selections, and contextual severity colors.

Viewport and Navigation

When findings exceed the terminal height, renderFindingsViewport clamps the visible range and adds scroll indicators. The navigation state persists in Model.findingCursor and Model.findingSelections, with helper logic defined in internal/tui/findings.go lines 15-31.

The helper stepHasActionableFindings in findings.go lines 7-13 determines when to display fix controls. When actionable findings exist, the action bar shows "f fix" and "a approve" controls alongside counts from awaitingActionState (selectedCount versus totalCount), as implemented in pipeline.go lines 254-260.

Run Status Integration via IPC Events

The rendering system operates on an event-driven architecture rather than polling. Daemon events update the model state, which triggers the View() method to re-compose the display. The status integration follows this flow:


Model.View()
 ├─ renderPipelineBox()
 ├─ renderFindingsBox()   // or renderDiffBox() if showDiff
 │    └─ renderFindingsWithSelection() → renderFindingsRange()
 └─ renderActionBar()

This ensures that run status changes and new findings appear immediately without blocking the main thread.

Summary

  • The TUI uses Bubble Tea's model-view-update pattern with a three-panel layout composed in internal/tui/view.go
  • Pipeline status renders via renderPipelineBox in pipeline.go, mapping StepStatus values to colored Unicode icons through the statusIcon function
  • Findings render via review.go functions that parse JSON, pre-select agent findings by default, and apply Lip-gloss styling with cursor and checkbox indicators
  • Viewport handling in renderFindingsViewport manages long lists through findingCursor state stored in the model
  • IPC events (EventStepCompleted) drive real-time updates to both status and findings, with showDiff controlling the findings/diff toggle

Frequently Asked Questions

How does the TUI switch between diff and findings views?

The d key toggles the showDiff boolean in the model. When true, the UI renders the diff view via renderDiffBox; otherwise, it displays the findings list. The action bar label updates dynamically to indicate the available toggle direction, as noted in pipeline.go lines 208-214.

Where are the step status icons defined?

The statusIcon function in internal/tui/pipeline.go maps status constants like StepStatusRunning and StepStatusSuccess to Unicode symbols and colors around line 150.

How does the TUI handle long lists of findings?

The renderFindingsViewport function limits the visible range based on terminal height and adds scroll indicators. Navigation state persists in Model.findingCursor and Model.findingSelections, with helper functions in findings.go managing the selection state.

Which files handle the findings selection logic?

Selection state management resides in internal/tui/findings.go (lines 15-31), while the rendering logic with checkboxes and Lip-gloss styling is implemented in internal/tui/review.go (lines 71-90).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →