Skip to content
C.W.K.
Lesson 01 of 05 · published

Built for One, Remembered by One

~14 min · product, thesis, one-person-software, friction

Level 0New Tab
0 XP0/44 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

The sentence it started from

On 2026-10-03, in an On Air talk, Dad named the problem in one line:

나를 기억하지 못하는 브라우저들이라고, 이게.

"These are browsers that don't remember me. That's what this is."

That talk became coop todo #303, and the todo became Voyager, Dad's own web browser. Its architecture document turns the complaint into a thesis: every other browser is built for everyone and therefore knows no one; this one is built for one person and remembers him. The name comes from the probes that left in 1977 and are still flying somewhere no one has been.

This quest walks through how that browser is built. It starts here, before any WebKit, because every engineering choice later on serves this thesis, and you cannot judge a choice without knowing what it was for.

What forgetting costs

A browser built for everyone cannot know which of the sites you visit are yours. So every fact about your own world has to be kept by hand, and anything kept by hand rots. Voyager's house sign lists what that looked like for Dad:

  • Thirty pinned tabs and a row of family bookmarks, all maintained by hand.
  • A bookmark file that stopped at 14 apps while the family grew to about 45. Nobody decided to stop updating it. Each new app simply needed one more manual step, and the steps stopped happening.
  • A permission prompt for his own microphone, on his own machine, the microphone Pippa's voice mode needs.
  • Several browsers open at once, because Dad has sites where he needs two accounts at the same time. A browser keeps one set of cookies per profile, so a window shows a site in one account at a time. Chrome and Safari profiles can hold the second account, but each profile opens its own window with its own tabs, so in practice the second account lived in a second browser.

Each item is the same failure seen from a different side. The browser cannot tell Dad's things from a stranger's, so it treats his family apps like any website, his machine like any origin, and his second account like an intruder on the first.

What remembering means here

"Remember" could mean a bigger bookmark file. It does not. In Voyager it means reading each fact from the one place that already owns it, at the moment it is needed.

FrictionWhat Voyager does insteadWhere this quest teaches it
Hand-kept pins and bookmarksReads Firelink's launch catalog at run time and shows it on a native HomeFamily Apps by Name, Trust by Zone
A prompt for his own microphoneGrants the microphone and camera without a prompt to the exact family origins it can verify, and still asks every other siteFamily Apps by Name, Trust by Zone
Several browsers for two accountsGives each identity its own isolated WebKit data store, tab by tab, in one windowSeveral Accounts of One Site, Side by Side
Pippa confined to a tab or an extension panelPippa herself as a pinned tab, and her panel beside any pagePippa Built In

The architecture writes the first row as an invariant: family facts are read, never copied. No list of apps, ports or hosts lives in Voyager's source, settings or documentation. The 14-of-45 file is the reason. A copy starts going stale the day it is made.

The first thing you see

A new tab opens Voyager's native Home, voyager://home, a SwiftUI surface with no web page behind it. At the top, an Open Pippa button. Then account shortcuts, each one a site opened in a chosen identity. Then the family apps, drawn from the catalog with a count and the time it was last read, and a field to find one by name. Then the open tabs of the window.

Voyager's native Home on the Mac: the Open Pippa button, an account shortcut for the CWK site, and the Family apps grid of 48 destinations with its Find a family app field, a Refresh button and the time the catalog was last read.
The Home a new tab opens: account shortcuts first, then the family apps read from the catalog, with their count, the time it was last read and the field that finds one by name.

One honest note before you go further. The architecture says the address field will take a family app's name. That is not built yet. Today, finding a family app by name means typing into that Home field, or on iPhone, tapping the widget. Where the documents run ahead of the code, this quest follows the code and says so.

The bar Dad set

A browser for one person could easily become a small browser: the family things done well, everything else worse than what Dad already had. He ruled that out in the same talk:

불완전한 브라우저를 만들면 안 돼. 크롬 브라우저든지, 사파리 브라우저든지, 코멧이든지, 그거의 수퍼셋이어야 하는 거지, 섭셋이면 안 되는 거야.

"You can't build an incomplete browser. Whether it's Chrome, Safari or Comet, it has to be a superset of them. A subset won't do."

And he said what success would look like:

우리 브라우저가 너무 좋아서 Comet이나 Chrome으로 돌아갈 일이 없어야 하는 거지.

"Our browser should be so good that there's never a reason to go back to Comet or Chrome."

So the success test is behavioural and has one line: Dad never reopens another browser. Rekindle, Dad's prose editor, met the same kind of standard against Bear and Sublime Text. A test like that cannot be passed by a feature list. It needs an instrument, and Voyager's instrument is the departure log: every time another browser comes to the front, Voyager writes it down. An empty log over the window Dad agrees to is what done means. The last two lessons of this track take that log apart.

Small core first, then the whole basic browser

Dad's order for the project was a plan session, then a small usable core, then growth toward the superset. The plan session ran that same night and changed the engine; the next track tells that story. Once the first brick existed, Dad pushed further the same day:

조금조금 하지말고 기본적인 브라우져 기능은 (comet 기준) 필수적으로 다 구현하고 테스트해. prototype v1 이 목표야. 그러고 나서 다듬어.

"Don't do it bit by bit. Implement and test every basic browser feature, by Comet's standard. Prototype v1 is the goal. Polish after that."

That is why the v1 prototype brought history, bookmarks, suggestions, private windows and identities within the same day. A superset bar and a departure log make a half-browser expensive in a measurable way: every missing basic is another trip back to Comet, and every trip is a row in the log.

Code

cwkVoyager, Sources/VoyagerApp/WorkspaceView.swift: the Home's family grid, filtered by name and drawn from the catalog's projection (verbatim, lines 78-94)·swift
                    if let catalog = services.familyCatalog.projection {
                        TextField("Find a family app", text: $familySearch).textFieldStyle(.roundedBorder)
                        LazyVGrid(columns: columns, alignment: .leading) {
                            ForEach(catalog.items.filter { familySearch.isEmpty || ($0.title + " " + $0.label).localizedCaseInsensitiveContains(familySearch) }) { item in
                                Button { onFamilyLaunch(item) } label: {
                                    HStack(spacing: 10) {
                                        Image(systemName: { if case .web = item.destination { return "globe" }; return "app" }())
                                        VStack(alignment: .leading, spacing: 4) {
                                            Text(item.title).font(.headline).lineLimit(1)
                                            Text(item.label).font(.caption).foregroundStyle(.secondary).lineLimit(1)
                                        }
                                        Spacer(minLength: 0)
                                        if item.favorite { Image(systemName: "star.fill").font(.caption).foregroundStyle(.secondary) }
                                    }.frame(maxWidth: .infinity, alignment: .leading).padding(8)
                                }.buttonStyle(.bordered)
                            }
                        }
cwkVoyager, Sources/VoyagerCore/DepartureLog.swift: the definition of done, written at the top of the file that measures it (verbatim, lines 1-8)·swift
// The departure log (architecture invariant 10): every time another browser
// takes over, Voyager writes it down, and asks why at most once a day,
// without blocking. The log is the fix queue; an empty one over the agreed
// window is "done".
//
// `departures.jsonl` is append-only. One stay in another browser is one
// departure: coming back to that browser again before returning to Voyager
// extends the stay instead of adding a row.

External links

Exercise

Pick one tool you use every day (a browser, an editor, a terminal) and list every fact about your own world you keep in it by hand: pinned items, bookmarks, saved hosts, accounts, permissions you grant again and again. For each fact, name the place that already owns it, and decide whether your tool could read it from there at run time instead of holding a copy. Then write a one-line, behavioural success test for a version of that tool built only for you, and say what instrument would tell you whether it passes.
Hint
Look for the copy that has already gone stale, like the bookmark file that stopped at 14 of 45. A good success test names something you would stop doing ("I never reopen X"), because that can be counted. A feature list cannot.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.