# How the No-Mistakes TUI Integrates with the Pipeline and Daemon

> Discover how the no-mistakes TUI seamlessly integrates with your pipeline and daemon. Visualize and control execution with real-time state synchronization for an error-free workflow.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: how-to-guide
- Published: 2026-07-16

---

**The no-mistakes terminal user interface (TUI) is a thin, event-driven front-end that visualizes and controls the underlying pipeline execution through real-time state synchronization with the background daemon.**

The `kunchenguid/no-mistakes` repository implements a terminal-based workflow manager where the TUI serves as a visual control plane for the headless daemon process. Understanding how the TUI integrates with the pipeline and daemon reveals an architecture built on **gRPC state streams**, **read-only rendering**, and **bidirectional command forwarding**.

## Architecture Overview

The integration follows a **client-server model** where the daemon maintains the single source of truth. The TUI never executes pipeline logic locally; instead, it subscribes to state changes and forwards user commands via an IPC channel.

- The **daemon** manages pipeline execution, file system watching, and git operations
- The **TUI** provides real-time visualization and user interaction
- Communication occurs through protocol buffer definitions with gRPC streaming

## Launching the TUI: The Attach Command

Entry into the TUI begins with the `no-mistakes attach` CLI command implemented in [`internal/cli/attach.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/attach.go). This command ensures the daemon is running before initializing the interface.

```go
// internal/cli/attach.go
runTUI = tui.Run                // exported variable, replaceable in tests
...
func attachRun(cmd *cobra.Command, args []string) error {
    // ... ensure daemon is reachable ...
    return runTUI(ctx, client, runID) // start TUI with IPC client
}

```

The `attachRun` function performs three critical steps:

1. Verifies daemon availability through the singleton lock mechanism
2. Establishes a gRPC client connection via [`internal/daemon/client.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/client.go)
3. Invokes `tui.Run` with the active run ID to begin the event loop

## State Propagation: Real-Time Synchronization

State synchronization relies on the `internal/daemon/state` package, which defines the shared `State` struct streamed from daemon to TUI. In [`internal/tui/app.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/app.go), the application creates a `state.Listener` that subscribes to the daemon's `StateStream`.

```go
// internal/tui/app.go (simplified)
func (a *app) watchState(ctx context.Context, client *daemon.Client) {
    stream, _ := client.StateStream(ctx, &daemon.StateRequest{})
    for {
        s, err := stream.Recv()
        if err != nil { return }
        a.mu.Lock()
        a.state = s               // store latest snapshot
        a.mu.Unlock()
        a.render()                // trigger UI redraw
    }
}

```

The `watchState` loop blocks on `stream.Recv()`, updating `app.state` atomically whenever the daemon emits new data. This includes pipeline step transitions, new findings, or branch-sync events. The mutex-protected `a.state` ensures thread-safe access between the gRPC receive loop and the UI rendering thread.

## Rendering the Pipeline

The [`internal/tui/pipeline.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/pipeline.go) view renders the `state.Pipeline` object, mapping each `pipeline.Step` struct to visual components. The TUI implements **selective redraws** using `tuiRelevantSyncState` guards to ignore updates from unrelated runs.

```go
// internal/tui/pipeline.go (excerpt)
func (p *pipelineView) Draw(s tcell.Screen) {
    steps := a.state.Pipeline.Steps
    for i, step := range steps {
        style := stepStyle(step.Status) // success / running / failed
        s.SetContent(x, y+i, rune(step.Icon), nil, style)
    }
}

```

Each step status—**review**, **lint**, **test**, or **push**—translates to distinct visual indicators. The view reacts immediately when the daemon updates `state.Pipeline.RunID` or modifies step completion states.

## Command Handling: User Input to Daemon Execution

User interactions flow in the reverse direction, from TUI to daemon. Keystrokes mapped in [`keys.go`](https://github.com/kunchenguid/no-mistakes/blob/main/keys.go) dispatch to handlers in [`internal/tui/commands.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/commands.go), which invoke gRPC methods on the daemon client.

```go
// internal/tui/commands.go (partial)
func (a *app) handleKey(k tcell.Key) {
    switch k {
    case tcell.KeyF5: // "sync"
        a.client.SyncBranch(context.Background(), &daemon.SyncRequest{RunID: a.state.Pipeline.RunID})
    case tcell.KeyCtrlC: // "abort"
        a.client.AbortRun(context.Background(), &daemon.AbortRequest{RunID: a.state.Pipeline.RunID})
    }
}

```

Common commands include:

- **Retry**: Resubmit failed pipeline steps
- **Abort**: Cancel the current run via `AbortRun`
- **Sync**: Trigger branch synchronization via `SyncBranch`

The daemon enqueues these operations, updates the shared state, and the new state streams back to the TUI, completing the feedback loop.

## Specialized Views: Branch Sync and Findings

Beyond the main pipeline view, the TUI integrates specialized components for specific daemon operations.

### Branch Synchronization

The [`internal/tui/branch_sync.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/branch_sync.go) view listens for `branchsync.State` emissions from the daemon. It renders progress bars during sync operations and highlights **stale-error conditions** detected in [`stale_error_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/stale_error_test.go) scenarios.

### Findings and Reviews

The findings system demonstrates bidirectional data flow:

1. The daemon populates `state.Findings` with lint errors and review comments
2. [`internal/tui/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/findings.go) renders the slice as an interactive list
3. The [`review.go`](https://github.com/kunchenguid/no-mistakes/blob/main/review.go) view allows users to approve, reject, or edit findings
4. These actions post back to the daemon via the same RPC channel established in [`attach.go`](https://github.com/kunchenguid/no-mistakes/blob/main/attach.go)

## Lifecycle Coordination and Error Handling

The TUI respects the daemon's **singleton lock** defined in [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go). If the daemon process terminates unexpectedly, the TUI detects the closed gRPC stream, displays a terminal error message, and exits gracefully.

Conversely, the daemon can request TUI shutdown by emitting a `state.Shutdown` flag in the state stream. This occurs after successful pipeline completion or when the daemon requires a hard restart for configuration changes.

## Summary

- The **TUI** is a read-only renderer of daemon state, ensuring the pipeline and daemon remain the single source of truth
- **State synchronization** occurs through gRPC streaming via `state.Listener` in [`internal/tui/app.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/app.go)
- **User commands** forward to the daemon through [`internal/daemon/client.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/client.go) RPC methods
- The **attach command** ([`internal/cli/attach.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/attach.go)) establishes the initial IPC channel and validates daemon health
- **Specialized views** handle branch-sync progress and finding reviews through the same bidirectional channel
- **Lifecycle management** includes graceful handling of daemon crashes and coordinated shutdown sequences

## Frequently Asked Questions

### How does the TUI initially connect to the daemon?

The `no-mistakes attach` command in [`internal/cli/attach.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/attach.go) verifies the daemon is running through the singleton lock mechanism, then establishes a gRPC client connection before invoking `tui.Run` with the active run ID and client instance.

### What happens when the daemon updates pipeline state?

The daemon emits a new `State` protobuf message through the `StateStream` RPC. The TUI's `watchState` loop in [`internal/tui/app.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/app.go) receives this message, updates the mutex-protected `app.state` field, and triggers a UI redraw to reflect the new pipeline step statuses.

### Can the TUI control pipeline execution or is it read-only?

While primarily a read-only renderer, the TUI supports **bidirectional control**. User keystrokes mapped in [`keys.go`](https://github.com/kunchenguid/no-mistakes/blob/main/keys.go) dispatch commands via [`internal/tui/commands.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/commands.go) that send gRPC requests—such as `AbortRun` or `SyncBranch`—to the daemon, which then executes the requested operations.

### How does the TUI handle daemon crashes or unexpected disconnections?

If the daemon terminates, the gRPC stream closes and `stream.Recv()` in `watchState` returns an error. The TUI detects this closure, displays an error message to the user, and exits gracefully rather than attempting to reconnect or continue with stale data.