I created TermSurf because I was tired of cmd+tabbing.
As a web developer who lives in the terminal, my workflow is constantly interrupted by context switches. Write some code, run the dev server, cmd+tab to the browser to see the result, cmd+tab back to the terminal. Repeat hundreds of times per day. Each switch is small, but they add up to a fragmented experience.
The thought occurred to me: wouldn’t it be cool if I could just open a browser inside my terminal? Then I would never have to leave. I could do everything from there.
TermSurf is a terminal emulator with native browser panes. You run
web open localhost:3000 and a browser appears inside your terminal, blocking
like vim or less. When you’re done, press ctrl+c and you’re back at your
shell prompt.
The browser isn’t a separate window floating above your terminal. It’s a first-class pane in the terminal’s split hierarchy. You navigate between terminal and browser panes with the same keybindings (ctrl+h/j/k/l). The experience is unified.
This is the workflow I wanted: preview my dev server in a pane, view documentation alongside my terminal, debug web applications with terminal and browser side-by-side. All without leaving the terminal.
Building TermSurf required finding a terminal emulator with the right architecture for embedding a browser. Most terminals aren’t designed for this.
Ghostty, created by Mitchell Hashimoto, has a unique structure that made it ideal. The macOS app is written in native Swift, while the core terminal emulation lives in a separate library called libghostty, written in Zig. This separation matters.
Ghostty’s macOS app uses native NSViews for each terminal pane. The pane layout is a binary tree of views managed by Swift. Adding a browser pane was natural—WKWebView is just another NSView. It slots into the same tree as a sibling to terminal views. Focus management, keyboard routing, and resizing all work through the same native AppKit mechanisms.
Compare this to alternatives. WezTerm renders everything to a single GPU texture. To add a browser, you’d need to either overlay a native window (creating focus nightmares) or composite browser frames as textures (complex and slow). Alacritty doesn’t even have panes—you’d have to build that from scratch.
Ghostty had the ideal architecture for the MVP. Fork it, add WKWebView as a pane type, and the rest follows.
TermSurf treats the browser as a command-line tool:
Console bridging: console.log() goes to stdout, console.error() goes
to stderr. You can pipe browser output to grep, jq, or AI debugging tools.
Exit codes: With the --js-api flag, pages can call
window.termsurf.exit(0) to close the browser and return an exit code. This
enables CI/CD integration for browser-based tests.
Three-mode keyboard: Vim-style modal control. Control mode gives you terminal keybindings. Browse mode lets you interact with the page. Insert mode edits the URL bar. Press Esc to return to control mode from anywhere.
Profile isolation: --profile work creates a separate session with its
own cookies and localStorage. Keep work and personal browsing separate.
Bookmarks: Save URLs with web bookmark add or press cmd+b to bookmark
the current page. Open bookmarks by name: web open google.
I used AI extensively to build TermSurf. Specifically, Claude Code wrote essentially all the Swift, Zig, and documentation. I directed and reviewed.
The key to making this work is the AGENTS.md file in the repository. It tells the AI how the project is structured: where the Swift sources live, where the Zig CLI lives, how to build and test, which files handle what functionality. With accurate context, Claude Code can navigate a complex multi-language codebase and make coherent changes across files.
This is the workflow I described in How I Use Claude Code to Do My Entire Job: know what you want, write it down, let the AI execute, review the output. For TermSurf, that meant specifying features like console bridging and modal keyboard control, then watching Claude Code implement them across Swift views, Zig socket handlers, and protocol definitions.
The result is a working terminal-browser hybrid that I couldn’t have built as quickly on my own.
TermSurf v0.1.1 is released with core features complete. Browser panes work. Console bridging works. The three-mode keyboard works. Profiles and bookmarks work.
Future plans include multi-engine support—Chromium via CEF and eventually Firefox/Gecko—so you can test your web app in any browser from the terminal. Linux and Windows support are also on the roadmap.
TermSurf is open source and available now:
github.com/identellica/termsurf
If you’re a web developer who lives in the terminal, give it a try. Open
localhost:3000 in a pane, see your console output in stdout, and never cmd+tab
again.