Join the conversation

Join the community of Machine Learners and AI enthusiasts.

Sign Up
RiverRider 
posted an update 3 days ago
Post
27
Black Window — a chat model in your browser tab, on your hardware. A memory that stays on the device that opened the page.

https://blackwindow.xyz

Open the site, pick a model (about 0.6B to 8B), hit Load. The weights run in that tab, on that computer. After they load, the network can drop. The context window is a working set, auto-sized to that device, up to ~32K tokens.

Behind the window is the Weave. Every file, picture, recording, link, lookup, and reply is embedded as it arrives. Drop in audio and it is transcribed. Drop in an image and it is described. A question pulls the nearest passages back as notes. A long document is walked once so later questions can use the whole file, not the first pages.

Nothing leaves that tab unless you turn on live lookup or connect a rented GPU box, and the chat says so each time. Prompts can go to the box. Files and the Weave stay in the tab.

Console on that page: bw.ask, bw.search, bw.digest, bw.notes. A local relay exposes /v1/chat/completions on localhost so other tools on the same computer can talk to the tab. The tab polls the relay. That is the boundary.

Not a server with a policy. Your hardware, a window, a Load button.

If on mobile add to home-screen for best performance. If you break it lmk. It can serve a few hundred of you at a time before I have to buy a real server.
This comment has been hidden (marked as Low Quality)

Love the "that is the boundary" framing. It's the same bet we made with Elffuss: the model runs in the tab, on your hardware, and nothing leaves unless you say so.

A few things that might be worth comparing notes on:

  • Elffuss Claw: an agentic OS in a browser tab. You ask for an app and it writes it as self-contained HTML. Skills are plain SKILL.md files pulled from GitHub, so installing a skill is the capability.
  • Elffuss Code: a VS Code-style IDE where the agent reads and edits your real folder through the File System Access API. For the terminal there's an optional bridge on localhost with a token, very close to your relay boundary.
  • Elffuss Translator and Copilot: speech-to-speech translation and live call notes, with Whisper and speaker separation running on the device.

Looks like we hit the same walls: sizing context to the device, long tool results that blow the window, and mobile Safari (we just moved inference into a worker because the page froze while transcribing).

Curious how the Weave decides what to evict once a long session outgrows the working set.

Claw, Code and the core are Apache-2.0; everything runs without an account.

·

The Weave never evicts. Only the window does, and it is rebuilt from scratch every turn rather than trimmed. Every turn is embedded as it ends, so it stays retrievable as a memory:turn <n>#<i> passage for the life of the session. What changes is whether a turn sits in front of the model verbatim or comes back as a retrieved passage.

Sizing happens per turn, in pickWindow. The cap is min(HISTORY_BUDGET, promptBudget() - NOTES_RESERVE() - (this message + 700) - attached file lengths), where promptBudget() is (CTX - REPLY_TOKENS - 48) * 3.8 on desktop and * 3.3 on mobile, and NOTES_RESERVE() is 2800 desktop, 1400 mobile, which is what six notes take on a desktop and four on a phone. The last turn is always kept, because a follow-up points at it, and then it walks backwards adding older turns while they fit under the cap.

The eviction order that matters is in fitPrompt, and it is not recency. Files that fit whole go first, since they are the question's material. Then the retrieved notes. Then a long file's opening last, with whatever is left. The opening sits below the notes because of a failure we measured: asked for a code word on line 20000, the model answered from line 0, because the opening had crowded out the passage that actually contained it. An opening is context, not the answer.

Two details that were not obvious until they bit. Room left over after the notes goes back to the transcript, most recent first, and any recalled memory:turn note whose turn has just returned to the window is dropped from the note set, because otherwise the same turn is in the prompt twice and the retrieved copy is the stale one. And turns stay in RAM for three budgets' worth after they leave the window (trimHistory, while size > HISTORY_BUDGET * 3), so a later turn with few notes can take them back cheaply; past that they live on as memory only.

On mobile Safari we landed where you did. WebGPU decode runs in llm_worker.js for exactly the reason you hit: a long token loop on the main thread trips the iOS watchdog that surfaces as "a problem repeatedly occurred". Media decode is a second worker, and it loads a plain build under WebKit.

Thanks — this is the most useful reply I've had in a while, and it caught a real bug in ours.

Your rule that a recalled passage is dropped once its turn is back in the window verbatim: we applied the equivalent only to the protected header, never to the verbatim tail. A toy history reproduces it at 1.5k/3k/5k budgets — the same line ships twice, once retrieved (and clamped by our per-line cap) and once verbatim, so the model gets the worse copy of something it already has in front of it. Fixed: the tail now seeds the dedup map exactly like the header. Recall on our agent-session bench didn't move (92.3% micro), which is the honest result — on that corpus the duplicate rarely fires. It bites when the repeated line is long.

"An opening is context, not the answer" lands here too. Ours pays per line with a cap and clamps the middle of long tool results, which is the same idea from the other side — but we haven't measured the ordering the way you did, so that one goes on the list.

Your fitPrompt order also matches what we measured on long-term memory: retrieving ~8% of the tokens beat feeding the full uncompressed history (28.09 vs 22.56 F1). Irrelevant context isn't neutral ballast, it distracts.

And on mobile Safari we landed in the same place the same week: the long decode loop on the main thread is what trips the watchdog. We moved inference into a worker after the page froze mid-transcription on an iPhone.