# The cloud was my laptop

By Munawar Khel / November 2026 / 6 min read

Published at https://munawarkhel.com/thoughts/the-cloud-was-my-laptop/

Everyone talks about AI agents as if they live in the cloud. The model does. Everything the model asks for does not. The browser it opens to check its work, the dev server it starts, the test suite it runs: all of it lands on whatever machine the agent is sitting on. On 5 November that machine was my Mac, and it was not coping.

This is not a piece about Playwright being bad. Playwright is very good, which is part of the problem. It is about what happens when a tool built to run one careful test suite is handed to several AI agents at once, all on the same laptop, all quietly convinced the machine is theirs.

## What it looked like from the chair

Some of my windows kept going black and reloading. Slack, Figma, Orca. Not all of them, only a few, and never the same pattern twice. The Mac is an M3 Max with 16 cores, driving three displays, one of them at 7680 by 3240. So my first theory, and the first theory of the AI session I asked to investigate, was the obvious one: too many pixels and a graphics chip that could not keep up. There was even a documented macOS bug where Electron apps overloaded the window server. Plausible, sourced, and wrong.

It was not memory either, which is what everyone assumes first. Memory was 94% free, with no swap and no pageouts. Whatever was breaking my Mac was not running out of room.

The display theory died on evidence. The graphics processes for Slack, Orca and Claude never restarted; they kept the same process ids for hours. Slack's own log said its renderer had "exited with 'killed'". Not a crash. Killed, from outside. And Orca's terminal sessions ended in that same second.

## 20:29

Then the two halves of the story met. In another tab, the lead of my agent crew had logged three jobs ending at the same moment with "Agent process ended", at about 15:30 UTC. That is 20:29 to 20:30 in Karachi, the same minute Slack's renderer was killed. The sampler I had left running caught a headless Chromium starting at 20:29:45. And the crew's session had one more number: at that moment the Mac's load was 38, on 16 cores.

A load of 38 on 16 cores means more than twice as much work waiting for the processor as there were cores to run it. My normal is 6 to 10. The spikes came in bursts, and the bursts lined up with browser checks.

The agents were in the cloud. Their browsers were on my desk.

## Three browsers in three days

It started on one client build, where the project rule said browser checks use headless Chrome from the command line, because it was installed and needed no pairing. Jobs that finished, or died, left headless Chrome processes behind, orphaned and adopted by the system, and those ghosts started catching `open -a`. An agent asked macOS to open Chrome and the request landed in a browser nobody could see. A screenshot script called `process.exit` inside a `try/finally`, so on any error Chrome stayed behind with its temporary profile.

Then, on an early-stage transportation management system for drayage, real Chrome windows kept interrupting my work. So on 4 November I moved browser testing there to Playwright, headless, in Chromium and WebKit. To be fair to it, it earned its keep: one accessibility pass covered 2,040 focus stops, a layout sweep ran 928 rows in both engines, and it caught a real bug where a press on the sign-in form before the scripts arrived left a blank page.

But every job started its own engines, two at a time. Cleanup stopped servers with `pkill -f serve.cjs` and `pkill -f next-server`, killing by name, so one job tidying up could kill another job's server mid-check. Several jobs ran side by side on one laptop. That is how you get to 38.

## Why headless hides the bill

A visible window is a cost you notice. It covers your work and annoys you into closing it. A headless browser is the same processor time and the same child processes, with the one signal removed that would have told you something was wrong.

For one developer running one suite, that trade is a good one. For agents running in parallel it is a trap, because every agent is being perfectly reasonable. Each one starts just one browser, for just this check. The sum is a machine with no owner.

Headless removed the window. It did not remove the browser.

## What I chose instead

On 5 November I changed it again: from this point onwards, Orca's browser and not Playwright. Orca is the workspace I already run the agents in, and its embedded browser is one I can see. The rules that came with it matter more than the browser does:

- One browser tab per job, reused for every page, state and width, and closed before the job reports.
- Every job stops only the process id it started, on its own port. Never a kill by name.
- Project browser suites, Playwright, Cypress, Vitest in browser mode, do not run on the Mac at all. A report says `e2e: left to CI`, so nobody mistakes a skipped suite for a passing one.
- The Safari pass, when a task needs one, runs one job at a time, in a private window, closed afterwards.

The obvious alternative was to keep Playwright and write better cleanup: a reaper for orphans, a cap on concurrency, a tighter `finally`. I had already tried that version. It fixed one script, not the habit. A rule that depends on every agent cleaning up perfectly is a rule that fails on the one run that crashes.

## The honest part

I have not proven that the browsers caused the kills. I have one minute where everything lines up, a load figure and a sampler line. What actually sent the kill to Slack's renderer is still unidentified. The Mac also restarted at 21:26 that night, and I still do not know why.

The fix cost something too. WebKit is no longer tested in any job on that project, and the decision record names what would reopen it: a bug that shows only in Safari. The big keyboard sweeps now belong to CI, which means a longer wait between a change and the proof that it holds. And I changed this rule three times in three days. The decision log shows every reversal, with its reason. I would rather have that log than pretend I got it right first time.

## What I would tell anyone running agents

The thinking is rented. The side effects are not. Treat your machine as a shared resource with an owner, because the agents will not. Every process an agent starts is a process it ends, by id, on success and on failure. Prefer the browser you can see, because the cost you can see is the cost you will manage. And send the heavy, parallel, unattended work to the place where heavy and parallel is the point, which is CI, not the laptop you are trying to think on.

Headless is a display setting. It was never a budget.
