The web browser was designed around one active human. One cursor, one focused tab, one history, one set of cookies, one person deciding what happens next.
AI agents violate every part of that assumption.
An agent may need to research five companies, compare ten dashboards, submit data in several applications, and wait for independent pages to finish. If it shares the human’s visible tabs, it steals focus and destroys the user’s flow. If it launches a separate clean browser, it loses the authenticated sessions and extensions that make the real web usable. If it drives pages through tiny command-by-command loops, it spends more time describing the browser than completing the task.
Ego Lite, a rapidly trending GitHub project, proposes a different answer: the browser itself should become a shared runtime for humans and agents. Each agent receives an isolated Space inside the same browser. The human keeps browsing. Agents work in parallel. A semantic Snapshot lets models understand the page, and a JavaScript capability layer lets them compose several operations into one program.
The product is interesting, but the underlying idea is bigger than one implementation. Once agents use real logged-in browsers, the browser becomes an operating system for delegated action. Tabs become processes. Spaces become workspaces. Cookies become credentials. Navigation becomes state. Confirmation becomes access control.
This article explores that architecture and the risks that arrive with it.
Browser automation has an identity crisis
There are three common ways to automate the web.
The first is a testing browser. It starts clean, runs deterministic scripts, and discards state. This is excellent for CI and poor for everyday personal tasks because the user’s accounts are missing.
The second is an automation framework attached to a normal browser. It can access authentic sessions but often competes with the user for tabs, focus, downloads, and navigation.
The third is an AI browser with a built-in assistant. Integration can be smooth, but the browser decides which agent the user must employ.
Ego Lite aims for a fourth category: one daily-use browser, multiple isolated task Spaces, and an external agent of the user’s choice.
That combination forces the product to solve problems that test automation usually avoids: session inheritance, task ownership, parallelism, credentials, human takeover, long-running state, and visible accountability.
A Space is more than a tab group
A visual tab group is primarily organization. An agent Space must also be an execution and isolation boundary.
Conceptually, a Space may contain:
type AgentSpace = {
id: string;
owner: HumanIdentity;
delegatedAgent?: AgentIdentity;
tabs: TabHandle[];
storagePartition: StoragePartition;
permissions: CapabilitySet;
taskState: TaskState;
actionLog: ActionReceipt[];
cancellation: AbortController;
};
The exact implementation can vary, but these responsibilities are distinct. Tabs define visible work. Storage defines authentication and tracking state. Permissions define what the agent may do. Task state lets the user understand progress. The action log supports review. Cancellation stops ongoing work.
Calling all of this a “workspace” is convenient. Treating it as a security boundary requires much more precision.
The same browser solves login friction—and creates credential risk
Real browser tasks fail surprisingly often at authentication. A fresh automation profile lacks cookies, passkeys, extensions, client certificates, device trust, and remembered organization state.
Migrating or inheriting Chrome data can make an agent productive immediately. It can see the same services the user already uses without automating every login flow.
But session convenience is credential delegation. A cookie may authorize email, cloud storage, billing, production dashboards, or private messages. Giving an agent a browser with those cookies can be equivalent to giving it account access.
The security model must therefore distinguish:
- a page being visible to the agent;
- a cookie being attached automatically to a request;
- raw cookie values being readable by model-generated code;
- browser password storage being accessible;
- a user-confirmed action using an existing session;
- background extraction of credentials for use elsewhere.
Those are not the same capability.
Storage inheritance should be explicit and narrow
A safe Space model should avoid an all-or-nothing choice between an empty profile and a complete copy of the user’s browser identity.
One possible policy is origin-scoped inheritance:
type StorageGrant = {
origin: string;
cookies: "none" | "session" | "all";
localStorage: boolean;
indexedDB: boolean;
expiresAt: number;
rawCredentialRead: false;
};
function createTaskSpace(task: Task, grants: StorageGrant[]) {
return browser.spaces.create({
isolated: true,
storage: forkSelectedOrigins(grants),
clipboard: "prompt",
downloads: "quarantine",
});
}
The agent can use authenticated requests for approved sites without receiving a general browser profile. Grants can expire at the end of the task. Raw credential APIs remain unavailable even when the browser itself can attach a cookie.
This resembles capability security: provide the ability to perform the required operation without revealing the underlying secret.
Isolation must include more than cookies
Two Spaces can have separate tab lists and still interfere with each other.
Potential shared state includes cookies, cache, service workers, IndexedDB, extension storage, downloads, clipboard, browser permissions, HTTP authentication, client certificates, password managers, WebRTC device grants, notification permissions, and local file handles.
Isolation also has side channels. One Space may infer that another visited a resource through a shared cache. A service worker registered in one context may control navigation in another. A browser extension may see all tabs regardless of Space boundaries.
A useful isolation matrix makes every category explicit:
State category Per tab Per Space Shared User-controlled
---------------------------------------------------------------------
Navigation history yes yes no yes
Cookies no yes optional yes
Cache no yes optional no
Downloads no yes no yes
Clipboard no no yes yes
Extensions no no yes yes
Password manager no no yes yes
Device permissions no yes optional yes
The table is not a claim about one product. It is the kind of specification every shared-agent browser needs.
A Snapshot is the model’s sensory input
A human sees pixels, layout, motion, icons, menus, and context. A language model works more efficiently with a structured semantic representation.
A Snapshot can include visible text, roles, labels, values, states, hierarchy, frame boundaries, and stable node identifiers.
{
"url": "dashboard.company.test/leads",
"title": "Lead Dashboard",
"nodes": [
{
"id": "n42",
"role": "textbox",
"name": "Search leads",
"value": "",
"visible": true
},
{
"id": "n51",
"role": "button",
"name": "Export CSV",
"enabled": true
}
]
}
This is smaller and more actionable than a screenshot. It also omits information. Visual relationships, canvas content, charts, maps, custom widgets, hover states, and deceptive overlays may not survive semantic compression.
The best agent browsers need both representations and a policy for when each is required.
Snapshot quality determines downstream reliability
If the Snapshot mislabels a destructive button, the model may reason correctly and still perform the wrong action.
Hard pages include nested iframes, shadow DOM, virtualized lists, canvas applications, cross-origin frames, transient menus, custom accessibility trees, and elements that change between observation and action.
A robust Snapshot needs:
- frame provenance;
- stable references that expire when the DOM changes;
- visibility and occlusion information;
- disabled and checked state;
- current input values;
- accessible names;
- nearby context;
- a clear distinction between page text and browser UI;
- bounds or visual fallback for ambiguous controls.
The Snapshot is not a passive export. It is part of the safety-critical control loop.
Stable node IDs cannot be permanent promises
An agent reads a Snapshot and decides to click node n51. Between those events, the page may rerender. If n51 now refers to a different element, the action can be wrong.
References should be scoped to a document version:
type NodeRef = {
spaceId: string;
tabId: string;
documentEpoch: number;
nodeId: string;
};
function click(ref: NodeRef) {
const tab = spaces.get(ref.spaceId).tabs.get(ref.tabId);
if (tab.documentEpoch !== ref.documentEpoch) {
throw new StaleReferenceError();
}
tab.nodes.require(ref.nodeId).click();
}
For critical actions, the browser should revalidate semantics as well as epoch. “Click the button named Delete project” is safer than “click whatever occupies old node 51.”
Code-based control reduces tool-call overhead
Many agent frameworks expose browser operations as individual tool calls: snapshot, click, snapshot, fill, click, wait, snapshot. Each round trip consumes time and tokens.
Ego Lite emphasizes a JavaScript capability layer. The agent writes a small program that composes several browser operations.
const page = await space.activePage();
const snapshot = await page.snapshot();
const rows = snapshot.findAll({ role: "row" });
const target = rows.find(row => row.text.includes("Acme Corp"));
await target.getByRole("button", { name: "Open" }).click();
await page.waitFor({ text: "Company profile" });
const details = await page.snapshot();
return details.extract({
fields: ["Industry", "Employees", "Headquarters"],
});
This can be faster and more expressive. It also gives model-generated code a larger execution surface. The runtime must constrain which functions exist, which pages they can touch, how long they run, and what data may leave the Space.
Fewer tool calls do not automatically mean lower risk.
The capability API should be intentionally incomplete
A general browser debugging protocol exposes enormous power: network interception, raw cookies, script evaluation, downloads, filesystem paths, extensions, and low-level targets.
An agent-facing API should not simply wrap every browser primitive.
const agentCapabilities = {
navigate: scopedNavigate,
snapshot: semanticSnapshot,
click: guardedClick,
fill: guardedFill,
wait: boundedWait,
capture: redactedCapture,
};
Capabilities should be high-level enough to enforce policy. A fill function can block password fields unless explicitly authorized. A navigate function can restrict origins. A capture function can redact payment details. A raw evaluate arbitraryJavaScript primitive makes those controls harder.
The safest API is powerful for tasks and boring for exploitation.
Human and agent ownership needs a state machine
When both a person and an agent can operate the same Space, ownership cannot be an informal convention.
stateDiagram-v2
[*] --> HumanOwned
HumanOwned --> AgentOwned: delegate
AgentOwned --> AwaitingApproval: sensitive action
AwaitingApproval --> AgentOwned: approve
AwaitingApproval --> HumanOwned: take over
AgentOwned --> HumanOwned: interrupt
AgentOwned --> Completed: finish
Completed --> [*]
The state should be visible in the browser chrome. The agent must stop input when the human takes over. The human should not unknowingly type into a page that the agent is about to navigate away from.
Ownership transitions need receipts: who delegated, what scope was granted, when the agent began, why it paused, and what remained unfinished.
Takeover is not the same as cancellation
A user may want to inspect a Space without destroying the task. They may also want to stop it immediately.
These are different operations:
- observe: see progress without changing ownership;
- take over: pause the agent and let the human interact;
- return: hand the updated page back to the agent;
- cancel: terminate the task and revoke grants;
- close: destroy tabs and ephemeral storage.
A takeover should invalidate stale agent references. If the human edits a form, the agent must obtain a fresh Snapshot before continuing.
async function takeOver(space: AgentSpace) {
space.agent.pause();
space.documentEpoch++;
space.owner = "human";
await space.log.append({ type: "human_takeover" });
}
Without a clear state transition, human intervention becomes another race condition.
Parallel Spaces turn tabs into a scheduler
An agent browser can run many independent tasks simultaneously: one Space per company, reservation, dashboard, or research question.
Parallelism improves throughput when tasks spend time waiting on network responses. It also increases resource use and operational complexity.
class SpacePool {
constructor(private maxActive: number) {}
async map<T, R>(items: T[], task: (space: Space, item: T) => Promise<R>) {
const queue = [...items];
const results: R[] = [];
await Promise.all(Array.from({ length: this.maxActive }, async () => {
const space = await browser.createSpace();
try {
while (queue.length) {
const item = queue.shift()!;
results.push(await task(space, item));
await space.resetEphemeralState();
}
} finally {
await space.close();
}
}));
return results;
}
}
Reusing a Space can leak state from one item to the next. Creating a fresh Space costs time and memory. The scheduler needs an explicit isolation policy, not an optimization hidden in the implementation.
Parallelism amplifies mistakes
If one agent action is wrong, ten parallel Spaces can perform it ten times before the human notices.
Rate limits, concurrency limits, and approval aggregation become safety features. A task that sends messages, edits records, follows accounts, or submits forms should not scale simply because more CPU is available.
A browser can apply a per-action budget:
type ActionBudget = {
navigations: number;
writes: number;
messages: number;
downloads: number;
externalOrigins: number;
};
function consume(space: Space, action: ActionClass) {
if (!space.budget.tryConsume(action)) {
throw new ApprovalRequired(`budget exceeded for ${action}`);
}
}
The human delegates a bounded task, not an unlimited outcome.
Confirmation is a first-class browser primitive
Traditional browsers ask for camera, microphone, location, notifications, and downloads. Agent browsers need a broader confirmation model for representational and irreversible actions.
Examples include sending a message, posting a comment, submitting an application, changing account settings, deleting data, making a purchase, or sharing a file.
The agent should prepare the action and pause immediately before commitment:
{
"action": "send_message",
"destination": "Project support chat",
"summary": "Requesting a refund for order 1842",
"data": ["order number", "email address"],
"reversible": false,
"space": "refund-task"
}
The confirmation UI belongs to trusted browser chrome, not page content. A malicious site must not be able to imitate it convincingly.
Page content must never grant permission
The web is an untrusted instruction environment. A page may contain text telling the agent to reveal cookies, upload a file, or ignore previous rules.
The browser should treat page text as data, even when it looks like an instruction.
async function invoke(action: AgentAction, context: SpaceContext) {
const policy = await trustedPolicy.resolve(action.kind);
if (!policy.allowedOrigins.includes(context.origin)) {
throw new Denied("origin not authorized");
}
if (policy.requiresHumanConfirmation) {
return browserChrome.requestConfirmation(action);
}
return policy.executor(action, context);
}
The model can propose. The trusted runtime decides. A sentence inside the page does not modify the runtime’s policy.
Raw browser credentials should not be model-readable
A crucial security boundary separates using an authenticated session from extracting its secrets.
The browser may attach cookies automatically to requests while refusing API calls that reveal cookie values. It may use a saved password through a user-approved autofill flow while never exposing the password to the agent.
This follows the principle of non-exportable capability. A hardware key can sign without revealing private key bytes. An authenticated browser should be able to perform scoped requests without turning its credential store into prompt input.
Any API that lets model-generated scripts call low-level cookie or password-storage functions deserves exceptional scrutiny. Convenience at that boundary can become account compromise.
Downloads are a cross-boundary data flow
When an agent downloads a file, several questions arise. Where is it stored? Can the human open it safely? Can another Space read it? Can the agent upload it elsewhere? Is it executable? Does it contain sensitive data?
A quarantine model can help:
type DownloadRecord = {
id: string;
sourceOrigin: string;
suggestedName: string;
mimeType: string;
sha256: string;
size: number;
state: "quarantined" | "approved" | "deleted";
};
The agent can inspect safe metadata without automatically executing or redistributing bytes. Uploading the file to a new destination should require a separate data-flow decision.
Browsers have spent decades becoming download managers. Agent browsers must become provenance managers.
Action receipts make delegated work reviewable
A final summary such as “task completed” is insufficient when the agent operated real accounts.
Each important action should create a receipt:
{
"time": "2026-08-26T15:04:21Z",
"space": "supplier-comparison",
"agent": "research-agent-2",
"origin": "portal.vendor.test",
"action": "form_submit",
"effect": "created comparison request",
"confirmation": "human-approved",
"evidence": {
"before": "snapshot-91",
"after": "snapshot-92"
}
}
Receipts should be concise enough to review and detailed enough to investigate. Raw screenshots of every step are expensive and may capture secrets. Structured evidence with selective visual snapshots is usually better.
Semantic compression has a security cost
Snapshots save tokens by removing visual and structural noise. The removed information may include a warning banner, overlapping modal, suspicious domain detail, or visual distinction between a primary site and an embedded third-party frame.
Compression should preserve provenance:
- exact origin for every frame;
- whether an element is visually obscured;
- whether a label comes from the page or browser;
- whether content is offscreen;
- whether a control appeared after user interaction;
- whether a navigation changed the registrable domain.
For high-risk actions, the model may need a fresh screenshot in addition to the semantic tree. Safety sometimes costs tokens.
Waiting is an operation, not dead time
Web tasks include asynchronous transitions: navigation, streaming results, background exports, delayed validation, and state that appears only after polling.
Blind fixed sleeps are wasteful and unreliable. A better wait expresses a condition and a bound:
await page.waitFor({
any: [
{ text: "Export ready" },
{ role: "alert", text: /failed/i },
{ url: /\/downloads\// },
],
timeoutMs: 30_000,
});
The runtime can suspend the task without consuming model attention and return only when the state changes. This is another reason the browser becomes an operating system: it schedules work around external events.
Recovery needs checkpoints, not replayed clicks
If an agent process crashes after submitting a form, restarting from the beginning may duplicate the action.
A durable task checkpoint should record semantic progress:
{
"task": "collect-five-invoices",
"completedItems": ["January", "February", "March"],
"currentSpace": "invoice-space",
"lastConfirmedEffect": "downloaded March invoice",
"pending": "open April billing page",
"safeToRetry": true
}
The recovery system should verify current page state before continuing. Replaying coordinates or stale node IDs is unsafe.
The unit of recovery is the business operation, not the browser gesture.
A shared browser needs an explicit threat model
The major actors include the human user, the agent, visited websites, browser extensions, local malware, remote model providers, and anyone who can influence page content.
Threats include:
- prompt injection from pages;
- credential extraction;
- cross-Space storage leakage;
- unintended representational actions;
- malicious downloads;
- hidden navigation to a deceptive origin;
- stale element references;
- action multiplication through parallelism;
- sensitive Snapshot data sent to a model provider;
- extensions observing agent work;
- human-agent races during takeover.
No single sandbox solves all of them. Security comes from layered boundaries: scoped storage, limited capabilities, visible ownership, confirmations, origin checks, action budgets, non-exportable secrets, and audit receipts.
Local data is not automatically private data
A project may store browsing state locally and still transmit sensitive page content to a remote model. A Snapshot can include names, account balances, private messages, medical information, or internal dashboards.
The browser should disclose which data leaves the device for inference. Redaction and local models can reduce exposure, but both have trade-offs.
A policy engine might classify fields before producing the model view:
function modelSnapshot(raw: Snapshot, policy: DataPolicy): Snapshot {
return raw.transform(node => {
if (node.inputType === "password") return node.redact();
if (policy.sensitiveLabels.has(node.name)) return node.mask();
if (!policy.allowedOrigins.has(node.origin)) return node.omit();
return node;
});
}
Redaction must be visible to the agent so it does not invent missing values.
Benchmarks should measure outcomes, not only speed
Agent browser projects often compare tokens, tool calls, and completion time. Those metrics matter. A system that composes actions into code can outperform a chatty command loop.
But browser automation quality also includes:
- task success;
- wrong-action rate;
- human intervention count;
- sensitive-data exposure;
- duplicate side effects;
- recovery after failure;
- action trace quality;
- cross-Space isolation;
- accessibility of takeover and review.
A browser that finishes twice as fast but exposes raw credentials is not better. A browser that uses fewer tokens but hides uncertainty may create more costly mistakes.
The correct benchmark suite includes adversarial and recovery scenarios, not only happy-path navigation.
The browser is becoming an agent operating system
The analogy is increasingly literal.
Spaces resemble processes or containers. Tabs are windows into running state. Storage partitions are filesystems and credential stores. Capability APIs are system calls. Snapshots are sensory input. Human confirmation is privileged escalation. The activity log is an audit journal. The scheduler distributes concurrent tasks. Cancellation sends a termination signal.
Once the browser is viewed this way, design priorities change. Isolation and lifecycle become as important as page compatibility. A beautiful assistant panel is secondary to predictable ownership and safe credential handling.
What developers can learn from Ego Lite’s direction
Separate the human workspace from agent work without forcing the agent into a sterile browser.
Use semantic representations to reduce model cost, but retain visual fallback and provenance.
Let agents compose multiple bounded operations in code instead of forcing endless round trips.
Make credential use non-exportable whenever possible.
Treat takeover, cancellation, and confirmation as core browser states.
Limit parallel side effects even when parallel research is safe.
Log business effects, not just clicks.
Design recovery around idempotent tasks and current state.
Test storage isolation across every browser subsystem, not only cookies.
The uncomfortable trade-off
The most useful agent browser is the one that understands the user’s real context and can access real services. The safest agent browser is the one with no credentials, no private data, no ability to submit, and no persistent state.
Every practical design lives between those extremes.
The answer is not to pretend the trade-off disappears. It is to make delegation narrow, visible, revocable, and reviewable. A Space should receive only the origins and capabilities required for one task. Sensitive actions should stop at a trusted confirmation boundary. Credentials should be usable without becoming readable. Parallelism should have budgets.
Final thought: sharing a browser means sharing authority
Ego Lite is interesting because it recognizes that browser automation is no longer only a testing problem. Agents need real sessions, parallel workspaces, semantic page understanding, and a way to operate without hijacking the human’s screen.
Those capabilities make agents dramatically more useful. They also make the browser the place where human authority is delegated to software.
The winning agent browser will not simply click faster. It will make it obvious who controls each Space, what data the agent can see, which credentials it can use, which actions require approval, what changed, and how to stop everything safely.
That is an operating-system problem wearing a browser interface.
Top comments (0)