When I started working on modernizing Frontier last October, the obvious story would have been “old codebase gets ported to modern hardware.” That’s not wrong per se, but it’s not what actually happened.
I had already had multiple conversations with ChatGPT in early/mid-2025 about how a this project might look. They were useful… but not actionable. It was still too daunting to seriously consider attempting. (“Oh hey: Let’s climb Mt. Everest. Wait, it’s how high?!? And you’re not a mountain climber? And you don’t like the cold? And you need oxygen tanks?!? Whoops!”)
I started hearing more and more about Cursor, so I decided to try it. It’s free to download: What could possibly go wrong? I had some chats with Cursor (not even sure which model), and did some high-level planning and exploration. This yielded real fruit in terms of understanding what was there and what a modernization project might look like and getting some initial documentation in place, but when I tried to start actually implementing the kinds of changes that were needed Cursor fell over and made a mess. Pause.
So very early on, it was clear that this wasn’t going to be a simple project. Frontier came from a world where a lot of assumptions were implicit and the world has since moved on: 32-bit data structures (including even 16-bit integer and 8-bit ASCII assumptions), legacy MacOS runtime behavior, cooperative multi-tasking with time-slicing, UI code intertwined with runtime code, and a bunch of state that could just sort of “be there” in that world because there was always one user, one machine, one app, one moment in time. That world has been gone for a while.
A short time later when OpenAI launched Codex, I decided to try Codex CLI. That’s when the real work started, and the rest of October was dominated by Codex-driven work: Initial 32-bit → 64-bit migrations, database updates, and the like. The 32-bit → 64-bit move was the biggest early one, forced by Apple’s ending support for 32-bit. And also Rosetta went away, so that meant networking was going to need a rewrite. Lots of stuff.
The first phase of the project wasn’t about features at all. It was about establishing the groundwork for a new system that could coexist with modern tools, on modern operating systems, with a contemporary architecture, and cross-platform compatibility. With stdio support. With real multi-tennancy and protected user spaces. The long-lived dream of a Linux version of Frontier was still far away, but with this tooling was now in sight albeit still distant. We had even attempted a Linux port in 2005/2006 and failed. It was just too big of a job for UserLand given the resources available at the time.
Linux support would mean we had to have 64-bit, ARM support (in today’s world), headless execution, a modernized object database with a migration path and access controls, removing lots of legacy Apple dependencies. So early on in this project I decided we needed to move to standard ANSI C for cross-platform support, and POSIX compliance (same reason). And then I started sketching a rough plan for how to do all this work – initially planning using Codex.
Around this time (November or December, 2025) all of my nerd friends, and indeed the whole nerd internet, started raving about Claude Code. I installed it. I watched a bunch of videos. I looked at how people were using it. The trigger for me to switch was stumbling across this video on YouTube. Tâches, a non-coder, had created a whole software business from nothing using Claude Code, including a set of agentic tools he called Get Shit Done (GSD), which he shared as open source for anyone to use. That’s what drove me to switch to Claude Code, and I’ve been there ever since.
Around the same time, I had realized that moving this project forward absolutely required writing things down as I went: plans, notes, phase docs, architectural guardrails, status reports, handoff docs for moving between sessions, and on and on and on… And not just for my edification, but because the AI agents (first Codex, now Claude Code) would absolutely depend on this documentation and breadcrumb trail. Agents only remember what’s in the current session (for now), and whenever I started a new session, poof – it was all gone! This code base is far too large to pull it all in at the start of a session. Frontier is not a toy. 😉
The earliest work was more archaeology than anything else. You don’t just kick the tires on a codebase like this and start shipping updates. Well, you can, but then you get what you deserve. So the first step was to get the AI to read the code systematically, understand what components existed and how they worked, and document everything. That’s what the preliminary phase of this project was about: Just. Understand. The. Scope. Of. The. Problem.
Looking back at my October pull requests, a lot of the larger project is already visible there in embryo. Not the details, obviously. But the overarching shape of it. The need for portability. The need to make old databases survivable. The need to separate “it runs on my machine” from “this is now a system we can reason about.” The need to turn hidden assumptions into explicit structure.
That’s the part that I think people tend to miss about large-scale projects. The hard part usually isn’t getting it to compile or figuring out what features are supposed to be there. The hard part is finding all the invisible details, and the bargains that were made with the environment it came from.
And Frontier had a lot of those.
So if I had to point to the real beginning of this project, it wasn’t some flashy milestone later on. It was the moment the work stopped being “let’s revive this old thing” and became “okay, we’re going to systematically rebuild its operating assumptions.”
That’s a different project.
And, as it turns out, it was the real one.
Leave a Reply