youros

How it worksUsing it

Browsing

A profile is a browser's cookie jar, history and settings, and it is a box of its own on one node (Sandbox). In it runs one real Chrome, headed on a display of its own, with a tab per pane. The pane is a view of that tab: what it shows travels over the same sealed session as everything else, and what you type travels back naming what you aimed at.

The rule nothing in the browser can change

A document's cookies and address belong to the origin it was navigated to, not to whoever fetched its bytes. That is the same-origin policy, and no proxy changes it: a page has a site's session only when it is at that site. The prototype tried four ways round it (framing through a tunnel at a second hostname, a worker in between, rewriting addresses, a service worker keeping cookies) and each failed there; a cookie jar kept on a server fixes half of it and leaves the page's own script writing the other half to the wrong place (docs/REMOTE-BROWSER.md in the prototype has the whole argument). So the page renders on a node, in a browser whose own profile is the jar, and RFC 6265, the public suffix list, SameSite and HttpOnly are right with nothing of ours involved.

That also removes the tunnel's second origin. The prototype served framed sites at <label>.notez.beer, and D-6 has to keep every key-holding origin off any site like that; with no framed sites there is nothing to keep away from.

A copy of the document, and a picture when there isn't one

The node records the page's DOM (a snapshot, then its changes) from a script in an isolated world the page can't see, and the pane replays it into a frame on the shell's origin that is sandboxed with no allow-scripts. The copy is real markup, so scrolling, selecting, find, zoom, comments and screenshots are the browser's own and instant. Images, fonts and styles cross as ids the node minted while building the snapshot it is serving, never as addresses: an id from another document names nothing. The frame's policy is default-src blob: data:, so the copy makes no request of its own, and a stylesheet in it can't send what is on screen anywhere. It is the document frame your own pages are drawn in (build/document-frame): one frame, two sources of DOM.

Fonts are matched by face, not by name. The prototype found that a viewer holding a family of the same name draws with its own copy, so lines break differently. The node resolves the face each element was drawn with, sends those faces, and the copy declares them under family names of its own minting and points each element at its face, so nothing on the viewer can match. Not built, and not yet tested (web/same-faces).

Live <canvas> and <video> elements are filled with a track captured from that element on the node and drawn into the copy's own element, never laid over it. Without a track a canvas loses its size, and the page under it moves (measured in the prototype: 240×120 became 0×20), so this is part of layout, not decoration.

Input names the element it landed on, by the id the recorder gave it, with an offset inside it; coordinates go only where a point is the input (drags, the inside of a canvas). The node makes the clicks, double clicks and scrolls from the presses it is sent, as a real mouse would.

When the page is mostly one canvas, or the copy has diverged past what the node measures as tolerable, the node sends the tab as video instead and the pane says so in its bar. The prototype had a switch for this and no way to fall back by itself, because a framed page can't report that it failed; a browser on the node can.

Pictures come first. Video of the tab is right on every site, so the first release sends pictures only, and the box, profiles, the gate, downloads and dialogs are proven against something that works. The copy replaces it once it passes a fixed list of ordinary sites, compared pixel by pixel against the node's own rendering.

Frames ride the session

Video is encoded on the node and sent as datagrams of the session, sealed like every other message, and the pane decodes them with WebCodecs. It crosses the relay or a direct pipe the same way, and DTLS is never what keeps it private (D-9). A browser's own media stack is not used for it, so there is no second path to trust and nothing for ICE to do.

Its own browser UI

Alerts, confirms and prompts are shown by the pane and answered there; permissions (camera, location, notifications) are refused unless the profile allows them; a file chooser asks the pane for a file and sends it; a download is saved into the profile's downloads folder, reachable through the files service. A new window or target=_blank opens as a sibling pane. Back, forward and reload are on the bar. A tab outlives its pane and its pipe: a pane that reattaches asks for the tab back, and the node sends a fresh snapshot.

Reach and audit

Each profile is a box made by the sandbox service, and the box's only way out is the node's gate, TCP and UDP alike. A profile names its reach: internet (no addresses of the node or its networks), local (the node and its networks, never the internet) or both, and the gate checks the address after DNS, at every dial, so a name that resolves to a private address is refused too. The prototype could only bind Chrome's HTTP to its policy; a page's own WebRTC dialled around it, and closing that would have broken the video tracks. With the box's network the gate's, UDP is checked like TCP, and STUN and TURN to the internet are allowed while a LAN address is not.

An agent's grant names one profile, usually a throwaway made for it, and the audit says what it opened.

Where it breaks:

  • Passkeys. A site's WebAuthn call happens on the node, not where the phone or the security key is. The only way that works is an authenticator held by the node for that profile, which moves those passkeys onto the node. Until then such sites sign in by password and a second factor, or not at all.
  • Camera, microphone and screen share. A video call in the pane would need your camera fed to a fake device on the node. Calls stay in a browser of your own.
  • A node has to be on. A person with only a phone and a browser has no node to browse from, unless they add one in the cloud.
  • Robot checks. Some sites refuse anything that looks driven: a headless browser, navigator.webdriver, an emulated screen, no GPU, globals the recorder left behind. The prototype met each of them; each is fixed by being an ordinary browser on an ordinary display, and the list doesn't end.
  • Everything in one place. A node that is taken over has every session in its profiles. A box keeps them from each other and from the node's key, not from the node.
  • Cost. About 2 s from cold and 350 MB a profile while it runs, a browser to ship, and a GPU wanted for WebGL.

Not this

Not your own pages and apps: they are docs, open offline, edit with nothing in between and are reviewed code (D-13), so they stay in the shell. Not a browser extension in your own browser: it works only where it is installed, never on a phone, and it would be a second authority crossing the origin boundary. And not a reader, a proxy or a tunnel beside this: a readable version of a page is a view of the same tab, and a dev server on the node is a local profile.