Skip to content

Latest commit

 

History

History
342 lines (237 loc) · 10.9 KB

File metadata and controls

342 lines (237 loc) · 10.9 KB

The Story Behind warp-cli

Why This Started

I use Cloudflare WARP daily as a developer. I need to:

  • Test applications with different geographic origins
  • Access internal networks securely
  • Toggle VPN connectivity on demand for local development
  • Integrate VPN control into scripts and CI/CD pipelines

The problem? The official WARP GUI app is optimized for non-technical users, not developers.

The GUI Problem

The WARP app sits in your menu bar consuming:

  • Screen real estate - constant presence
  • Battery life - GUI constantly refreshing status
  • CPU cycles - background UI work
  • Mental bandwidth - notifications and visual distractions
  • Automation capability - zero scripting, no pipelines, no JSON output

Meanwhile, buried inside macOS is warp-cli - a binary that does everything. It's just hidden behind 20+ confusing command flags and no UX.

The Solution

Build a beautiful CLI wrapper that:

  1. Exposes WARP functionality through intuitive commands
  2. Leaves the daemon running (it does the real work)
  3. Provides a developer-first interface for terminal workflows
  4. Enables scripting, automation, and pipeline integration

One command instead of confusion:

# Instead of:
warp-cli tunnel host add example.com

# Just:
warp exclude add example.com

What I Learned

1. Reverse Engineering macOS Applications

I discovered that the Cloudflare WARP architecture is elegant but hidden.

The discovery process:

  • Located the CloudflareWARP daemon running as root via launchd
  • Found the communication protocol: gRPC over Unix domain socket at /var/run/warp_service
  • Extracted binaries from the .app bundle structure
  • Understood how launchd manages daemon lifecycle and auto-start

Why this matters: Most macOS apps are black boxes. Understanding the internals taught me:

  • How system daemons work
  • IPC (Inter-Process Communication) patterns
  • How to work with system-level resources
  • The importance of good process management

2. Rust for CLI Development

Building this in Rust taught me about real-world CLI design.

Key technical insights:

  • clap crate - The power of derive macros for command parsing
  • Error handling - Using anyhow for human-friendly error messages
  • Output formatting - The colored crate for terminal UX
  • JSON serialization - serde_json for structured output
  • Subprocess execution - Calling system binaries and parsing results

The bigger lesson: Rust forces you to think about:

  • Error cases upfront
  • Type safety in CLI arguments
  • Performance (single static binary, no runtime)
  • Security (memory safety matters for system tools)

3. CLI/UX Design Philosophy

This project taught me that UX design applies to CLIs just as much as GUIs.

Design principles I discovered:

  • Simplicity over completeness - 8 core commands beats 20+ flags
  • Consistency in naming - exclude add/remove/list is predictable
  • Progressive disclosure - Help text reveals advanced options
  • Feedback matters - Colored output tells you immediately if it worked
  • Scriptability is a feature - Not an afterthought

Real example:

# Good CLI feedback:
$ warp up
✓ Connected to WARP

# vs confusing daemon output:
$ warp-cli connect
Attempting connection...

4. System Integration on macOS

Working with launchd, plist files, and system binaries taught me how macOS really works.

What I learned:

  • launchd is more powerful than people realize
  • plist files are just XML with specific structure
  • Unix domain sockets are the IPC of choice on macOS
  • Permissions and sudo - when and why you need them
  • System service management - starting/stopping daemons safely

This knowledge is transferable to any system software project.

5. Installation Automation

Building smart installation scripts (install-complete.sh, install-from-github.sh) taught me:

  • Dependency detection - Check if WARP is installed before proceeding
  • Non-interactive installation - curl | bash safety practices
  • User experience in installation - Clear feedback at each step
  • Fallback strategies - Multiple installation paths for different users
  • Verification - Confirm everything worked

6. Multi-Tap Homebrew Publishing

Setting up automated Homebrew publishing with GitHub Actions revealed:

  • Tap architecture - How Homebrew discovers and installs formulas
  • SHA256 automation - Calculate and embed in CI/CD
  • Multi-app scaling - One tap can host unlimited formulas
  • CI/CD patterns - Conditional logic for different event types (push vs release)
  • Cross-repo coordination - Publishing to a separate repository safely

Why CLI > GUI Matters

The Core Difference

Aspect GUI App CLI Tool
Startup time 2-3 seconds Instant
Memory usage 150+ MB resident <10 MB
CPU idle Constantly refreshing Zero overhead
Automation Impossible Native
Pipeline integration None Full JSON support
Developer workflow Context switch required Stay in terminal
Scripting Can't script GUI clicks Shell scripts, CI/CD

It's Not Just About Performance

The philosophical difference runs deeper:

GUI philosophy: "Helpful features, always available, user-friendly"

  • Assumes users want visual feedback
  • Optimizes for discovery
  • Trades resources for convenience

CLI philosophy: "Do what you ask, get out of the way"

  • Assumes users know what they want
  • Optimizes for automation
  • Respects your system resources

For developers: CLI is the right choice because:

  1. We think in commands, not clicks
  2. We automate, not explore
  3. We integrate, not interact
  4. We script, not watch

The Space: Why This Matters for Developers

The Problem We're Solving

There's a growing trend: companies shipping GUI-first apps for things that should be CLIs.

Examples:

  • Docker Desktop (GUI wrapper around daemon)
  • GitHub Desktop (GUI wrapper around git)
  • Cloudflare WARP (GUI wrapper around daemon)

The issue: Developers are forced to pay the resource cost of GUIs they don't want.

The Opportunity

This project proves that better UX isn't the GUI's exclusive domain.

A well-designed CLI can be:

  • Easier to use than the GUI (fewer options, clear defaults)
  • More powerful than the GUI (scriptable, pipelinable)
  • Less resource-intensive than the GUI (no rendering overhead)
  • More accessible than the GUI (terminal works everywhere - remote servers, containers, CI/CD)

What This Teaches

For developers:

  • You don't need a GUI to be user-friendly
  • A good CLI is a form of great design
  • Simplicity means removing features, not adding options
  • Automation should be built-in, not bolted on

For the industry:

  • Not everything needs a GUI
  • Respecting developer workflows means providing CLI access
  • The daemon can do the heavy lifting; the interface can be simple
  • Tooling is a product too

The Ecosystem Impact

If more tools shipped with:

  • Well-designed CLIs by default
  • GUIs as optional add-ons
  • Full automation support
  • Respect for developer workflows

We'd have:

  • Less bloat on developer machines
  • More automation in CI/CD pipelines
  • Better developer experience overall
  • Faster iteration (no GUI to refresh/restart)

Key Insights

1. Simplicity Is Radical

In a world of feature-bloated apps, a tool that does one thing well is revolutionary.

The warp-cli project succeeded because it said "no" to everything except the core: intuitive VPN control.

2. UX Isn't About Pixels

Good UX is about respecting your user's time and resources.

A CLI that runs in 50ms is better UX than a GUI that takes 3 seconds to launch.

3. Reverse Engineering Builds Understanding

I didn't understand how WARP worked until I extracted the binaries and traced the socket communication.

This deep understanding allowed me to build something better.

4. Rust Forced Good Practices

Rust's compiler caught bugs I wouldn't have found in Python or Go.

Type safety and memory safety matter, even for system utilities.

5. Automation Changes Everything

The ability to script VPN control opens up possibilities:

  • Automatic VPN toggle in CI/CD
  • Location-based connection changes
  • Monitoring and health checks
  • Integration with other tools

The GUI can never do this.


What I'd Do Differently

In Retrospect

  1. Started with the CLI first - I should have built the wrapper before understanding why
  2. More comprehensive testing - Added tests later in the process
  3. Performance profiling - Measured resource usage more rigorously
  4. User feedback earlier - Validated the UX with actual users sooner
  5. Documentation alongside code - Docs became comprehensive only at the end

For Others Building Similar Tools

  1. Understand your users first - What's their pain point?
  2. Simplicity > completeness - Start with core, add features later
  3. Automation support from day one - Don't make it an afterthought
  4. Good error messages - They matter more in CLI than GUI
  5. Make it installable - Homebrew, one-liners, or package managers are table stakes

The Bigger Picture

This project started as a personal frustration: an over-engineered solution to a simple problem.

It became a lesson in:

  • How to think about design for developers
  • How systems actually work (not how they're marketed)
  • How to build tools that respect user resources
  • How small, focused tools outperform bloated all-in-ones

Why This Matters Beyond WARP

Every developer uses dozens of tools. Most are:

  • Slower than they need to be
  • More complex than necessary
  • Built with GUIs when CLIs would be better
  • Hard to automate or integrate

This project is proof that you can do better.


What's Next

For warp-cli

  • User feedback from developers using it daily
  • Expand the formula library (homebrew-tools tap)
  • Explore macOS-specific optimizations
  • Potential contribution back to Cloudflare (in some form)

For Me

  • Apply these learnings to other tools
  • Build more dev-first CLI applications
  • Contribute to the open-source CLI ecosystem
  • Help others understand that simple, focused tools matter

Final Thoughts

This project is small. It's not going to change the world.

But it represents something important: the belief that developer experience matters, and that simplicity beats complexity.

Every tool you use should respect your:

  • Time (fast startup, zero overhead)
  • Attention (clear output, no noise)
  • Workflow (CLI, not GUI if you're a developer)
  • Automation needs (scriptable by design)

warp-cli is my small contribution to that vision.

If you're building tools: Choose simplicity. Respect your users' resources. Build for automation.

If you're using tools: Demand better. CLI tools can be beautiful too.


This project is an ongoing learning experience. These insights will evolve as I build more tools and learn from the community.