Built overnight, in use the next morning. A native browser where everything outside the page rectangle is real native chrome — tab strip, omnibox, sidebar, palette — with Chromium composited inside as a single texture. This page is the story. The link below is the spec.
Your editor, your terminal, your browser — all shaped by someone else's product decisions, all of them treating your data as opaque strings. That was fine when writing software was the expensive part. It isn't anymore.
The moment it stopped making sense: an agent can now build you a native desktop application overnight. Not a wrapper. Not a script. A real one. Which means the calculus flipped — the software you live inside can be yours, tuned to your actual data model, changed by asking.
The proof of that claim, below, is a browser. Built overnight. In use the next morning.
A dense, agent-first build guide for scry: architecture, every hard-won gotcha with specifics, dependency pinning, CEF fetch mechanics, measured build times, and a stage-by-stage build order that mirrors what actually worked.
It is written to be handed to a coding agent verbatim: "build me this."
scry is the second native app in this line. The first was seance — a GPUI desktop shell for running Claude agent panes. scry reuses its patterns (control socket, session persistence, dependency pinning) and is otherwise independent.
A native browser where everything outside the page rectangle is real native chrome: tab strip, omnibox, sidebar rail, command palette, context menus, prompts, toasts. Web content is Chromium (CEF 151) rendered offscreen into a texture and composited as one element inside a native GPUI window.
The first architectural bet, in one sentence: an Electron shell can only draw inside the webview rectangle, and the interesting affordances live outside it.
The second bet is about content. It is deliberately not a browser for the open web — Chromium keeps that job. It is a browser for pages you control: your local web app, your dev servers, your internal dashboards, your generated reports. That constraint is what buys everything else, because both ends of the connection are yours.
And the omnibox is not a URL bar. It is a fuzzy query over the surfaces you actually navigate — in this instance 984 entries across 8 sources: 760 generated reports (from a sqlite index), 71 internal sites, 63 app routes, 36 canvases, your own links store with a frecency prior from browser history, workshop pages, live dev servers. Sub-millisecond, no debounce, live on every keystroke. Substitute your own sources: notes, tickets, repos, runbooks. Chromium cannot do this for you because Chromium does not know what any of those things are.
Launch it again from the app menu and the second instance takes the first one over: the old one flushes its session, replies to the handshake, dies; the new one comes up with the same six tabs. One window, always.
A wedged instance (SIGSTOP'd) escalates to SIGTERM→SIGKILL and resolves in 5.43 s with tabs surviving via the last debounced flush. Three simultaneous launches produce a takeover chain and exactly one window.
Session flushed synchronously, reply confirmed on the wire, execv in place so the pid survives, tabs restored. When the shell prompt returns, the new binary is up.
This is the actual point of the project: "add X to my browser" is a prompt, and it lands under you in under a second.
window.scry exists in every page it renders. A page can call scry.actions.declare([...]) and those actions appear at the top of the native command palette (ctrl+shift+p) under their own header, above the built-ins — cleared on navigation, because a declaration belongs to one document.
Invoking one calls back into the page's own JS. A page can also raise a native toast in the chrome outside the web content, and open a real tab. Outside scry, window.scry is simply absent and the same page still works in Chromium.
celebrate, open health) declared by the page, above the built-in rows. Greyed rows state why they are unavailable instead of silently disappearing.
scry.version back out of the shell it is running inside.The DevTools port is on (localhost only). An agent can read what you are actually looking at without re-fetching the URL — works behind session cookies, for client-side-only pages, for localhost dev servers — screenshot any tab including background ones, or put a page in front of you instead of sending you a link.
The division of labour learned the hard way: open tabs with the control socket, read and script them with CDP. CDP-created targets are invisible orphans the user can neither see nor close.
Type; get your surfaces, ranked, with kind badges. Anything marked local-only wears a local chip in gold and refuses to mint a share link.
A leading ? switches to full-text search over long-term memory — an explicit mode, never keystroke-live, because it takes 1.2–3 s warm and the honest answer to that is a mode and a spinner, not a debounce.
bro, live fuzzy matches with report / dev kind badges and a local chip on the local-only row.This audience trusts a page more for having them. Nothing here is softened.
--no-sandboxchrome-sandbox without root:root setuid. This is a real gap, not a shortcut; it is survivable only because the trust model is "pages we control". Fixing it means setuid at install time or a userns sandbox.key name → VK + CHAR. Composition needs the toolkit's input-handler trait, which is a real piece of work.native_key_codenative_key_code is reconstructed from a US/evdev table — right logical key, wrong scancode on a non-US layout.DMA-BUF path needs GPUI to expose its wgpu::Device, which is a fork-or-upstream decision.0600 mode is the entire access control, and CDP has no authentication by design. Anything running as you can drive the browser and read every open tab.// built overnight by an agent
Timeline roughly: ~13:45 scaffold + de-risk spike (does CEF-OSR-into-GPUI even work at usable latency, with input?) → spike passes at ~14:15 → v0.1 working browser with tabs, omnibox and session persistence by ~22:15 → sidebar + palette + CDP by ~23:00 → control socket, lossless restart and <select> compositing by ~23:20 → the page↔shell bridge by ~00:15 → search mode, README, desktop entry by ~00:20. Next morning: nine asks against a shipped shell, which turned up three bugs the batch would otherwise have shipped.
What made that possible is not model magic. It is method, and it is the transferable part.
One unknown gated the whole plan; a disposable spike with four explicit pass criteria answered it in 30 minutes. Everything after was breadth, not risk.
Stated out loud in the brief — "agent B never edits the app crate" — so two agents can run concurrently without stepping on the same file.
Including the measurements that came out bad. The dirty-rect optimization won 0.5 % and was documented as not a speed feature. "Clean shutdown fixes zombies" was wrong — the kernel already reaped them; the real win was an orderly profile flush. Those corrections are worth more than the feature list.
One round's "screenshot of the help overlay" showed no overlay. Re-verifying live found the feature worked and that a different real bug sat next to it. Another round's test count was wrong because the orchestrator summed lines wrong. Your own reporting is an instrument, and instruments lie.
Once ctl restart existed, every later change landed in front of the user in 0.65 s. That changes what it feels like to ask for a tweak, which changes how many tweaks get asked for.
The claim to leave you with, stated plainly and without overselling:
The software you spend your day inside is now something you can own.
Not "customize" — own. The build guide is a working recipe, the numbers in it are measured, and the whole thing was one night.