From Web App to CLI: A Case Study in Building a Developer Focus Tool

How user feedback on a simple web prototype led to a complete strategic pivot and a better product for a professional audience.

By Marwin ZoepfelPublished on July 15, 202520 min read

Like many developers, I often struggle with maintaining deep focus. The modern digital environment is a minefield of distractions, and the cost of a single interruption—the "context switching cost"—can be enormous. For my Design Thinking course at university, I decided to tackle this problem head-on: could I build a system to create a protected space for deep work?

What started as a straightforward web application became a journey in user research, strategic pivoting, and ultimately building a tool that serves its intended audience far better than my original vision. This is the story of how listening to users—especially when they tell you something you don't want to hear—led to a fundamentally better product.

Understanding the User: It's Not Just Me

Before building anything, I needed to validate that this wasn't just my personal problem. I conducted interviews with IT professionals across different roles—software engineers, system administrators, and technical leads. Their feedback confirmed the core pain points and revealed something crucial: this wasn't about productivity apps or time management techniques.

"What we call multitasking is in truth rapid context switching... The expectation to react to emails, chats, or calls in real-time fragments the workday enormously and makes it difficult to get into the 'flow' state essential for complex IT problem-solving."

This insight shaped everything that followed. I wasn't building a generic productivity tool—I was building for professionals who understood the true cost of interruption and valued deep, uninterrupted work above all else.

Prototype 1: The "Sensible" Web App

My initial approach seemed logical: build a web application that users could access from any device. The prototype featured a focus timer, break suggestions, and a "thought capture" modal that allowed users to quickly jot down distracting thoughts without breaking their flow state.

Web app focus timer interface

Focus timer with clean, minimal interface

Thought capture modal

Thought capture modal for quick notes

The implementation was straightforward—a JavaScript timer with local storage for persistence and a clean, distraction-free interface. Here's the core timer logic:

focus-timer.js
// Focus Timer Implementation
class FocusTimer {
  constructor() {
    this.duration = 25 * 60; // 25 minutes in seconds
    this.timeLeft = this.duration;
    this.isRunning = false;
    this.interval = null;
  }

  start() {
    if (!this.isRunning) {
      this.isRunning = true;
      this.interval = setInterval(() => {
        this.timeLeft--;
        this.updateDisplay();
        
        if (this.timeLeft <= 0) {
          this.complete();
        }
      }, 1000);
    }
  }

  updateDisplay() {
    const minutes = Math.floor(this.timeLeft / 60);
    const seconds = this.timeLeft % 60;
    document.getElementById('timer').textContent = 
      `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
  }

  complete() {
    this.isRunning = false;
    clearInterval(this.interval);
    this.showBreakSuggestion();
  }
}

The web app worked as intended. It was accessible, easy to use, and followed established UX patterns. I was confident this would solve the problem. I was wrong.

The Turning Point: When the Solution is Part of the Problem

User testing revealed a critical flaw I hadn't anticipated. While the app itself was functional, the medium—a web browser—was fundamentally at odds with the goal of maintaining focus.

"As a digital minimalist, the requirement to always have a web browser open—and with it, the one-click possibility of opening YouTube or similar distractions—had a massively negative impact on me."

The feedback was consistent and damning:

  • "The design feels generic—it could be any productivity app"
  • "There's no pressure to stick to the ritual—I can just close the tab"
  • "The browser itself is a source of distraction—bookmarks, tabs, notifications"
  • "I need something that feels more intentional, more committed"

This was the moment I realized I had been solving the wrong problem. I wasn't building a tool for "normal users"—I was building for professionals who, like me, valued a distraction-free environment above convenience or accessibility.

The Pivot: Building for Professionals

The user feedback forced me to reconsider everything. Instead of trying to make the web app "better," I needed to ask a fundamental question: what medium would best serve my actual target audience?

I created a weighted decision matrix to evaluate different approaches:

FeatureWeightWeb AppDesktop AppTerminal App
No browser distractions
High
--+++
Professional feel
High
-+++
Easy to access
Medium
++++
Cross-platform
Low
++-++
Total Score--2+3+7

The terminal application won decisively. For my target audience—developers and IT professionals—the command line wasn't a barrier; it was a feature. It signaled intentionality, professionalism, and most importantly, it eliminated the browser as a source of distraction.

Prototype 2: A Tool for Focused Work

I rebuilt the application from scratch using Go and the Bubble Tea framework for terminal user interfaces. The new version maintained all the core functionality while embracing the constraints and advantages of the terminal environment.

Terminal focus app interface

Clean terminal interface with focus timer

Terminal thought capture

Thought capture without leaving the terminal

The Go implementation leveraged the language's excellent concurrency features and the Bubble Tea framework's elegant event-driven architecture:

main.go
package main

import (
    "fmt"
    "time"
    tea "github.com/charmbracelet/bubbletea"
)

type model struct {
    timer        time.Duration
    isRunning    bool
    phase        string // "focus", "break", "complete"
    thoughts     []string
    currentInput string
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.KeyMsg:
        switch msg.String() {
        case "space":
            if m.phase == "focus" {
                m.isRunning = !m.isRunning
                if m.isRunning {
                    return m, tea.Tick(time.Second, func(t time.Time) tea.Msg {
                        return tickMsg{}
                    })
                }
            }
        case "t":
            // Capture thought without breaking focus
            return m, tea.Cmd(func() tea.Msg {
                return thoughtCaptureMsg{}
            })
        }
    case tickMsg:
        if m.isRunning && m.timer > 0 {
            m.timer -= time.Second
            return m, tea.Tick(time.Second, func(t time.Time) tea.Msg {
                return tickMsg{}
            })
        }
    }
    return m, nil
}

func (m model) View() string {
    if m.phase == "focus" {
        return fmt.Sprintf(
            "🎯 Focus Session\n\n%s\n\n%s",
            formatTime(m.timer),
            "Press 't' to capture a thought • Space to pause",
        )
    }
    return ""
}

Key improvements in the terminal version:

  • Zero browser distractions: No tabs, bookmarks, or notification temptations
  • Professional aesthetic: Feels like a serious tool for serious work
  • Keyboard-driven: No mouse required, perfect for developer workflows
  • Lightweight: Minimal resource usage, starts instantly
  • Intentional usage: Requires deliberate action to start and stop

The response from users was dramatically different. Instead of generic feedback, I received specific, enthusiastic responses about how the tool "felt right" and "matched their workflow."

Lessons Learned from a Strategic Pivot

This project taught me more about product development than any course or book could. The journey from web app to CLI wasn't just a technical pivot—it was a fundamental shift in understanding who I was building for and what they truly valued.

Listen to your users, especially when they tell you something you don't want to hear

The feedback that the web app was "generic" was the most valuable data I received. It forced me to question not just the implementation, but the entire approach. Sometimes the most important insights come disguised as criticism.

Understand your target audience deeply

I initially thought "easy to use for everyone" was a strength, but my real users valued a "distraction-free" environment far more than accessibility. Building for everyone often means building for no one in particular.

Don't be afraid to pivot

Throwing away the first prototype felt like a failure, but it was the necessary step to building a much better product. The sunk cost fallacy is real, but so is the opportunity cost of persisting with the wrong solution.

Medium is part of the message

The choice of platform—web, desktop, or terminal—wasn't just about technical capabilities. It was about communicating values and setting expectations. The terminal app succeeded partly because it signaled seriousness and intentionality.

Most importantly, this project reinforced that good product development isn't about building what you think users need—it's about building what they actually need, even when that's different from what you originally envisioned.

MZ

Marwin Zoepfel

Systems Engineer & Technical Writer. I build and explain complex systems, from backend services in Go to bare-metal operating systems. When I'm not coding, I'm writing about the intersection of technology and human behavior.