Work / Lab
Night/Day
A Brave fork with two persistent personas, Night and Day, and a one-key switch, compiled clean from source.
- C++
- Chromium / brave-core
- GN
- siso
- GRIT
- Visual Studio 2026 Build Tools
- Windows SDK
TL;DR
- I forked Brave’s browser core (brave-core 1.97.2 on Chromium 153) to give one browser two selves, Night and Day: persistent personas, each with its own history, cookies, saved logins, bookmarks and extensions.
- The design came before any code: two multi-agent research workflows over the upstream source, a 640-line design doc, and a switch that needed zero Chromium overrides.
- Milestone one compiled clean inside a full Component build from source: 60,672 steps, 13 hours 50 minutes, zero errors.
The problem
Private browsing only forgets. It doesn’t let you keep two lives, like work and personal, each with its own logins, history and extensions, and move between them with one key. Browser profiles can do the storage part, but switching is buried in menus.
What I built
I directed Claude Code through two research workflows over Brave’s source: 49 subagents produced 97 findings, and none were refuted. Three calls came out of it and shaped the code:
- Reframe. Brave already ships Containers, which isolate cookies per tab but share history, bookmarks and passwords. The real question is “a different identity to the web” versus “a different me”, and “share nothing” means separate profiles.
- Precedent. Brave’s Tor windows are off-the-record profiles that share bookmarks and preferences with their parent, so the design rejects them as the model. The personas follow Brave’s persistent AI-chat agent profile instead.
- Footprint. Upstream Chromium already has a function that finds or creates a profile and activates its window, so the switch needed zero Chromium overrides.
Milestone one adds a new browser command bound to Ctrl+Shift+E (Cmd+Shift+E on macOS), with 2 new files and 7 touched upstream files. I set the goal, directed the research and the build, set up the Windows toolchain, and forked and published the repo. Claude Code wrote the C++ and the design doc.
Key decisions
- Decision: separate profiles, not Containers. Why: “share nothing” has to include history, bookmarks and passwords. Trade-off: a switch opens a different window rather than flipping the current one.
- Decision: reuse upstream’s find-or-create-then-activate. Why: no Chromium overrides means the fork stays cheap to rebase on every security release. Trade-off: behavior is bound to what upstream’s profile switcher does.
- Decision: identify a persona by its profile directory name. Why: a free function avoids adding a virtual to the Profile class and a header cascade into Chromium’s content layer. Trade-off: renaming a profile directory changes its persona.
The hard part
Adding a persona switch to a browser where every window is permanently bound to one profile, without patching Chromium. There is no way to flip a window’s profile, so a switch is find-or-create-then-activate on another profile directory, which upstream already implements.
The build had hazards too. Checking the original build guide against upstream first caught the Node version range, Visual Studio 2026 detection, the exact Windows SDK pin and a link-time-optimization trap of roughly 45 GB per link. A check that only resolved through a transitive include was fixed before the 13 hour 50 minute build, so the first full build compiled clean on the first attempt.
The design is explicit about its limits. Two profiles give storage isolation, not identity isolation: the OS-level encryption key, the network stack and the download folder are shared.
Results
- A clean first full build: 60,672 steps in 13 hours 50 minutes, zero errors, with the new persona code compiled in.
- GN generated 34,992 targets in 35 seconds, and dependency checks passed for the touched browser targets.
- The upstream diff stays small: 2 new files, 7 modified, no Chromium overrides.
What I’d do next
- Press the switch in a fresh build and verify it end to end.
Links
- Code: walkthrough on request.
Verified numbers
| Metric | Value | Source |
|---|---|---|
| Steps in the full Component build, compiled with 0 errors | 60,672 | local: Night/Day build transcript, record 1748 |
| Build time from source | 13 h 50 min | local: Night/Day build transcript, record 1748 |
| Upstream files touched (2 new, 7 modified), with 0 Chromium overrides | 9 | github.com/mit37/nightday/compare/master...nightday-m1 |