An agent that can act on the web needs two things that are easy to confuse. It needs a browser that does not get blocked, and it needs an identity that can receive mail, because almost every meaningful action behind a login starts with a code or a link sent to an address.
They look like two halves of one product. They are not. One of them is a commodity and one of them is not, and getting that backwards is an expensive way to spend a year.
The commodity half
Stealth browser runtimes are a solved and crowded category. Steel ships a self-hostable stealth Chromium. Browserbase ships the hosted version. Browser-use added stealth sessions. Anthropic and Microsoft both expose browser-level primitives directly to a model. These products differ on price, on residential proxy quality, on geography, and on how quickly they respond when an anti-bot vendor ships an update. They do not differ on what they fundamentally are.
When four or five funded teams ship the same primitive, the honest read is that it is infrastructure now. The correct move for a small team is to buy it.
So we run on Steel. browser-executor.ts opens a Steel session with stealth on, runs the plan against it, and deletes the session in a finally block so a thrown step cannot leak a browser. That is the entire relationship. It is about a hundred lines of client code, and if the anti-bot landscape shifts, that is Steel's problem to solve and ours to benefit from.
We would not win a stealth arms race against five better-resourced teams. Entering it would have cost us the thing we can actually win.
The half that is not a commodity
Now the other side. An agent needs an address that can receive a verification code. The available options are worse than they look:
- A real mailbox on a consumer provider. Automating a personal account is against terms, and consumer providers are aggressive about flagging automated access. This works until it very suddenly does not.
- A disposable inbox service. Built for humans testing signup flows. Public inboxes, addresses on domains that half the internet already blocks, and no API contract you would put in a production path.
- A raw transactional email provider. Excellent at sending. Receiving means running your own MX, parsing MIME, and building everything above it yourself.
None of these is a mailbox an agent can reason about. That is a different object, and the gap between "an email arrived" and "the agent knows what to do" is where the work actually is.
The test we used
One question, applied to each half: if we do nothing here, does someone else's roadmap solve it for us within a year?
For the browser, the answer was clearly yes. Five teams are already sprinting at it and their output arrives as a version bump.
For the agent mailbox, the answer was no. Every adjacent vendor is optimising for a different customer. Transactional email vendors optimise for sending at volume. Disposable inbox tools optimise for a human watching a test run. Nobody in that set has a reason to build long-poll retrieval or structured extraction, because their users do not need it.
Build where the answer is no. Buy where the answer is yes. It is not a sophisticated test, but applied honestly it kills a lot of appealing projects, including our own stealth browser.
What "a mailbox an agent can reason about" means concretely
The difference is not the mail. It is what sits between the mail arriving and the agent continuing.
Blocking retrieval instead of polling. An agent waiting for a code should not run a sleep-and-check loop, burning tokens re-reading an empty inbox and guessing at an interval. It should make one request that returns when the mail lands or times out. A polling loop is a retry policy the caller has to invent; a long poll is one line.
Extraction as part of the contract. The agent wants the six digit code, not a MIME tree. Handing a model the full HTML body of a marketing-styled verification email and asking it to find the code costs tokens and introduces a failure mode that did not need to exist. Pulling the code out is deterministic string work. Do it once, server side, and return the code.
The same for links. Magic link flows need the link extracted and followed, not summarised.
That is why the browser plan has wait_for_email, use_otp_from_inbox, and open_link_from_inbox as first class steps rather than as escape hatches into user code. Because the inbox and the browser session are in one runtime, the verification step in a signup flow is a step in the plan, not a handoff out of the plan and back into it. Most signup automation breaks at exactly that handoff.
What we are honest about
Buying the browser is a real dependency. If Steel has an outage, browser tasks fail; a provider abstraction is on the roadmap and it is not built today, so a swap would mean a code change, not a config change. That is the price of the decision and it is the right price to pay at our size. Writing an abstraction layer for a second implementation you do not have yet is how small teams accidentally build frameworks instead of products.
Some things are worth owning. A stealth Chromium is not one of them when five teams already ship it. The mailbox the agent thinks with is.
If you want the second half without building it, that is what Lumbox is: a real inbox per agent, with blocking retrieval and structured extraction, on one API key.