Skip to main content

Claude without leaving

I work in VS Code and Figma. Switching to a browser tab to ask Claude something breaks what I was doing. By the time I’m back, I’ve lost the thread. So I built a floating window that sits above apps and mirrors a live claude.ai conversation.

What I built

A small Electron window that floats above every other app on the Mac. Always on top, visible through fullscreen. A Chrome extension reads the claude.ai page and types into it. No API key. The same conversation you already have open, mirrored.

works

Live replies stream in

Word by word, as Claude types. Markdown, code blocks, tables land correctly.

works

Type from the bubble

You type. The extension injects it into the composer and submits.

partial

Conversation history

Works when the claude.ai tab is visible. Fails when it is in the background.

not built

Images

Sending confirmed possible in a test. Claude’s image replies cannot display. The relay carries text only.

The Build

The version I deleted

I built the relay first because I understood it. Chrome extension reads the page, sends to Cloudflare, Cloudflare fans it out to a web panel. I finished it and then wrote down what I actually needed: something still visible when I switch to Figma.

A web page lives in a tab. It disappears the moment you leave. I had built the thing I was trying to escape.

Three parts. One on the internet.
Chrome extensionreads and types into claude.aiCloudflare relaypublic endpoint on the internetPanel on a websitedisappears when you switch apps

Deleting the relay removed the public endpoint, the round trip to the internet, and the Cloudflare account. Two processes on the same machine talking to each other over localhost don’t need any of that.

The protocol stayed identical. Every message type, turn.start, turn.delta, turn.end, the same. The extension never knew where the server was. Building the wrong version first is what made the right version obvious.

What the virtualizer cost me

Claude.ai shows a moving window onto the conversation. Only the messages near your scroll position exist. I assumed the page was the conversation. It isn’t.

assumptionwhat broke
Store what the page showsv1 kept six messages and silently threw away 136. Position-based merging fixed it.
A message vanishedIt scrolled out of the DOM. Not deleted.
A message appearedNew only if that position hadn’t been seen before.
6held in page
136destroyed

Seven controls, each one from a bug

I didn’t design these up front. Each appeared after something broke. Click a marker to see what the bubble looked like before the fix, and what it cost.

Weather data APIs
Connected and capturing.
27 of 34 loaded
what are the free tier limits
OpenWeatherMap: 1,000 calls/day.
GET /data/2.5/weather
  ?q=london&units=metric
and the rate limits
Message Claude...
← click a marker to see the decision behind it

Five attempts at one bug

A week in, every reply appeared twice. Four fixes. Each one broke something new.

Widen where the code looks

Widening the selector found the missing message and created a second copy beside it.

before
and the free tier limits
OpenWeatherMap gives 1,000 calls/day free.
↑ duplicate ↑
OpenWeatherMap gives 1,000 calls/day free.
after
and the free tier limits
OpenWeatherMap gives 1,000 calls/day free.
one message, one element

The background tab problem

If a conversation has context in older messages, the bubble can’t reach it. Loading older messages means scrolling the claude.ai page. But the bubble sits in the background while you use it, and Chrome suspends rendering in background tabs. The scroll lands. Nothing redraws. The context stays out of reach.

Read the network responses

Works, but it means reading an authenticated API response the same way an API key would. The project deliberately has neither.

Force the tab to the front

Brings Chrome forward at the OS level. Chrome can’t hand focus back to a non-Chrome app afterward. Every history load yanks you out of Figma.

Patch the render loop

Replace requestAnimationFrame with a timer so it runs in background tabs. Two unknowns: timers are throttled unpredictably, and it’s an unconfirmed guess which virtualizer claude.ai uses.

Fetch history before you leave

Harvest eagerly on attach, before switching away. Doesn’t help conversations you open while already in the background.

What the tab does

The tab renders, authenticates, and displays. The bubble reads what the tab produces.

tabbubble
Holds the full conversation. 6 of 142 messages visible at onceMerges by position. Fails when the tab is backgrounded.
Renders images, artifacts, cardsText only. [image] [artifact: title]
Owns the session. Cookie, keys, permissionsNothing crosses the relay. It types into a tab that’s already authenticated.

What I built works. It is faster than switching tabs and stays visible through fullscreen and app switches. It fails in the ways the architecture predicts and says so when it does.

This is a personal experiment on one machine. Automated access to the consumer interface sits outside Anthropic’s terms. That’s worth stating plainly.
Next case studyFinominal8 tools revamped for professional investors