I am building a browser
Ten days ago, I started building a keyboard-native browser that thinks with you. Not because the world needs another browser—we have plenty. But because we need a different relationship with information.
Traditional browsers optimize for consumption: Search → Click → Scroll → Forget. Flakes is designed for thinking: Intent → Read → Reflect → Act.
The difference? Your browser becomes an extension of your cognitive process, not just a window to the internet. Every page you read becomes a building block in your personal knowledge graph. Every session is a task flow, not a collection of forgotten tabs.
Week 1: The Messy Reality of “Simple” Features
OAuth Popups (4 hours planned, 11 hours actual)
Thought it’d be straightforward. It wasn’t.
The problem: window.open() creates popups that need to maintain window.opener relationship for OAuth callbacks. On macOS with WKWebView, this is… delicate.
The solution: NSWindow-based popup manager that keeps child windows attached to parent, cleans up automatically, and doesn’t crash when JavaScript tries to close windows during event callbacks.
Learning: Every “simple” feature in a browser touches 5 systems you didn’t know existed.
File Uploads + Drag-and-Drop (6 hours)
Users expect to drag files into web apps. Turns out WKWebView doesn’t support accept attribute filtering or drag-and-drop out of the box.
Solution involved:
- Private API via KVC to extract file type filters
- Custom WKWebView subclass for drag handling
- Preventing unwanted file:// navigation from drops
Tested with Google Drive, Notion, Linear. All working.
The Keyboard Hijacking Bug (3 hours of panic)
With 10+ tabs open, keyboard stopped working entirely. Cmd+K? Nothing. Cmd+W? Nothing. Arrow keys? Dead.
Root cause: All WebViews exist in a ZStack, hidden with isHidden=true. Hidden views still capture keyboard events.
Fix: Created KeyboardSafeWebView wrapper that blocks ALL keyboard events from inactive tabs. 167 lines of code to ensure Cmd+K always works.
This is the unglamorous work that makes software feel “polished.”
Week 2: Making It Real
Multiple Profiles (12 hours)
Not “switch profiles” like Chrome. True multi-instance architecture—run Work and Personal profiles simultaneously, with complete data isolation.
Challenges:
- macOS sandbox prevents command-line arguments
- Lock files alone don’t track ownership
- Race conditions between URL handlers and init()
Solution: Custom URL scheme (flakes://openProfile/
The Testing Marathon (14 hours)
Coverage was 27%. Not acceptable for a browser handling people’s data.
Built:
- Mock infrastructure for AI services, MemoryStore, WebViews
- 135 tests covering P0 critical paths
- TestContext helper (reduces test boilerplate from 10 lines to 1)
- Production data protection during test runs
Coverage: Now ~50%. Still climbing.
Also fixed: Singleton isolation, @Observable memory leaks, dependency injection patterns.
Developer Experience
- Full Console API support (console.log, error, table, group, time—all working)
- Auto Insert mode when focusing text fields (no manual mode switching)
- Download manager with profile isolation and delightful animations
These aren’t “features”—they’re table stakes for a modern browser. But each one required deep integration with WebKit internals.
The Numbers
- 12 days of focused work
- ~100 hours (8-12 hour days)
- 372 tests (from 32)
- 50% coverage (from 27%)
- 11 major features shipped
- v0.5.3 (from v0.3.2)
- 96.9% web compatibility (tested 32 popular sites)
What I’ve Learned
1. Browser development is humbling. Every feature you take for granted—file uploads, popups, keyboard shortcuts—is a week of work. Chrome’s team has good reasons for being large.
2. Keyboard-first is hard to get right. Not just adding shortcuts. It’s about creating a responder chain that never breaks, handling focus intelligently, and making mode switching invisible.
3. Testing is not optional. One @Observable memory leak crashed the app 50% of the time. Without tests, I’d still be debugging it. With tests, it’s a 30-line fix.
4. Web compatibility is non-negotiable. OAuth, file uploads, WebRTC, fullscreen—these aren’t “nice to have.” They’re baseline expectations. Miss one, users leave.
5. Details compound. Download animation: 0.6 seconds, easeInOut curve, flies from center to toolbar. Took 2 hours to get right. Users notice it for 0.6 seconds. But they smile.
What’s Next
The foundation is solid, but there’s still a long way to go. Before adding any AI, I need to get the basics right—if the browser doesn’t feel good to use, AI won’t save it.
Most AI browsers chase the “AI vibe” instead of the fundamentals of what users actually want, and building on Chromium is unrealistic alone, yet I’m still solving problems Google solved a decade ago. But the world doesn’t need another Chrome; it needs tools that amplify thinking, not just clicking.
Flakes won’t be the fastest or the most feature-packed, but every part of it will exist for one reason—helping you think better. It won’t be perfect, but it will be intentional.
Try It
This project is as hard as I expected, but modern tools like Swift and Claude Code make it possible for a solo developer to build something real. Flakes is early. Like, “I’m still fixing crashes” early. But if you:
- Live in keyboard shortcuts
- Think in commands, not clicks
- Want a browser that respects your cognition
You might like where this is going.
GitHub: https://github.com/chagel/flakes
Let’s see where this goes.