The Session Is a Window With a Memory

In BrowserSkill, a session is not just a short identifier passed between commands. It is the state that connects an agent request to a particular browser connection, Agent Window, reference context, and cleanup responsibility. This chapter follows that state from creation through stopping so readers can predict what a session claims, what it remembers, and what must survive a failed or interrupted task.

Starting with a claim, not a blank check

A session begins on two sides of the bridge. The daemon selects a connected browser, reserves a fresh session handle, and prepares the routing state that later tool calls will use. The extension then creates a normal browser window at about:blank, ensures that the window has an active navigable tab, and registers a session context. The exact handle is useful for addressing the session, but it is not the source of authority. The meaningful scope is the browser connection and the Agent Window associated with that context.

The extension's session context keeps several kinds of state together. It knows the Agent Window's browser-window identity. It owns a reference store for the latest page observation. It tracks tabs explicitly created or claimed by the agent and keeps a separate table for tabs borrowed from the user. It also records whether the session is remote and when it was created. These are not interchangeable facts. A reference identifies an element observed in a tab; a borrowed-tab entry identifies a user resource temporarily moved into the Agent Window; an agent-created-tab entry tells cleanup that the session is responsible for closing that tab. The session is a memory of relationships, not merely a container for commands.

The initial claim is deliberately narrow. The home tab created or activated for the new Agent Window belongs to the session. That makes it a safe place to begin navigation and observation. Other tabs that later appear in the window are not automatically agent-owned just because they are visible there. A tab created through the session's own tab-creation path can be claimed explicitly. A tab opened by Chrome UI or by a page may require a separate ownership decision. This distinction prevents event timing from becoming authorization: the browser may report that a tab exists before the system has established who may operate it.

The home tab starts at about:blank for a practical reason as well as a conceptual one. Browser-internal new-tab pages are not ordinary CDP-navigable documents, while about:blank provides a predictable starting surface that the session can navigate. The choice does not make the page permanently safe or special. It gives the session a known first resource whose identity can be recorded and whose cleanup can be attempted later.

Session start is transactional rather than optimistic. If creating the window, ensuring its tab, or registering the context is interrupted, the extension attempts to remove the window it created. If that cleanup itself fails, the failure is surfaced instead of being reported as a clean cancellation. The daemon also reserves the session handle before waiting for the extension and cancels that reservation when the round trip fails. This prevents a failed start from leaving a daemon-side session that has no corresponding Agent Window, or an Agent Window that the caller has been told does not exist.

That transaction gives the session lifecycle an important asymmetry. A successful start means the system has established a browser-side scope and can route later work into it. An unsuccessful start does not necessarily mean the browser is unchanged; it means the system must either confirm compensation or report the remaining uncertainty. The session handle is therefore an address, while the Agent Window and its recorded claims are the operational boundary.

A session also carries the interaction policy that the browser has loaded. Borrow confirmation and human-help availability are browser settings, not private guesses held by a particular CLI invocation. The policy can be returned at session start and propagated through the bridge so an agent can understand which human paths are available. That information does not grant the agent more authority. It tells the agent which transitions may require an explicit user decision and which recovery path is unavailable.

The result is a useful state model: a session is active when its daemon record, extension context, Agent Window, and routing path agree about its existence. If one side disappears, the task cannot safely be treated as a normal active session. Reconnection and disconnect handling must reconcile those records rather than quietly inventing a new meaning for the old identifier.

That agreement also explains why a session handle should not be treated like a durable identity for a person or a browser. It is generated for the live registry and can be released when the session ends. The daemon reserves a candidate before the extension round trip so a collision cannot silently overwrite an existing live session, but the handle still has meaning only while the matching browser-side context exists. A later session may receive a different handle and a different Agent Window; it must not inherit old references, borrowed-tab claims, or assumptions about what the previous task accomplished.

There is a second kind of persistence inside the session. The browser window and tab identities may remain stable while the page document changes, but a reference to an element is not meant to outlive that document. The session remembers enough to reject an old target when the document changes, while the Agent Window remains available for a new observation. This division lets a task persist as a place and a lifecycle without pretending that every page-level object persists with it.

Stopping is a reverse ownership protocol

Starting a session creates an operating space. Stopping it is a reverse ownership protocol: return what belongs to the user, discard what belongs to the task, and preserve anything whose ownership or effect cannot yet be resolved.

The first teardown step is returning borrowed tabs. This order is essential. A borrowed user tab may currently sit inside the Agent Window, so closing that window before moving the tab back could close a resource the user expected to survive. BrowserSkill records the original window and position to support the return. If the original window has disappeared, it can choose a safe normal-window fallback and report that the tab was not restored to its original location. If the move fails, the borrowed entry remains retryable and the session/window stay available for another attempt. A session stop that reports such a failure is not being stubborn; it is refusing to convert a user-state problem into a silent loss.

Once borrowed tabs have been returned, the extension clears the session's reference store. This is more than memory hygiene. References describe page elements observed at a particular time and in a particular tab and frame. Keeping them after the session has stopped would invite a later caller to treat a stale element identity as current. The extension also detaches any browser-debugger sessions associated with the task. Debugger attachments and related browser-side state can outlive the high-level command that created them, so lifecycle cleanup must release them even when no visible tab remains in the Agent Window.

The next step is to close tabs explicitly created by the agent, including the session's home tab. The session does not simply close every tab it can see. Before deciding what to do with the window, it queries the remaining tabs and distinguishes user-created tabs from agent-created ones. If only the agent's own tabs remain, the window can be closed. If a user-created tab remains in the Agent Window, the session can be released without closing that window, allowing the user's tab to survive. If an agent-created tab failed to close, the system does not count it as a reason to release the window; otherwise an agent resource could leak into a window that is no longer under session management.

This distinction is easy to miss because Chrome presents both kinds of tab through the same window interface. The lifecycle must carry an ownership ledger alongside the browser's view. A tab that the user opened inside the Agent Window is not equivalent to the home tab the session created. A tab that happens to share a window is not automatically part of the session's cleanup set. Conversely, a tab explicitly created by the agent remains its responsibility even if a later close event or browser race makes the tab difficult to find. When a cleanup query cannot establish the state, the conservative choice is to avoid releasing a window in a way that would hide an unclosed agent resource.

The same ordering protects more than tabs. Clearing references after borrowed tabs are returned prevents later operations from using page identities whose owning session is ending. Detaching browser-debugger state before the window is removed gives the extension a chance to release resources while the target still exists. Closing agent tabs only after those steps keeps the cleanup sequence aligned with the state it is trying to release. Each transition narrows what remains live; skipping one can leave a later layer with an object it can no longer interpret.

The lifecycle can be pictured as a set of ownership-sensitive transitions:

stateDiagram-v2 [*] --> Reserved: choose browser and reserve session Reserved --> Active: create Agent Window and claim home tab Reserved --> CleanupFailed: startup compensation fails Active --> Stopping: explicit stop or disconnect Stopping --> ReturningBorrowed: return user tabs first ReturningBorrowed --> CleanupFailed: a return cannot be confirmed ReturningBorrowed --> ClosingAgentState: all borrowed tabs returned ClosingAgentState --> ReleasedWindow: user-created tab remains ClosingAgentState --> Closed: only agent resources remain CleanupFailed --> ReturningBorrowed: retry after browser issue is resolved Closed --> [*] ReleasedWindow --> [*]

The diagram's terminal states have different meanings. Closed means the session's Agent Window and agent-owned tabs have been removed after the cleanup order completed. ReleasedWindow means the session binding has ended while a user-created tab remains in the window; the browser window is intentionally left for the user. CleanupFailed means the system has not established a safe terminal state and must preserve enough context to retry. None of these states says that the user's larger business task succeeded.

Disconnects and user actions create related but distinct paths. If the user closes the Agent Window, the extension can report a window-closed event and the daemon can forget the corresponding session rather than trying to close a window that is already gone. If the browser connection disappears, the daemon purges sessions owned by that browser and the extension's local context may no longer be reachable. Reconnection does not replay the old commands. A new session must be established, and the user or agent must inspect what survived. A cleanup record can explain that a session was interrupted, but it cannot reconstruct a page effect that was never confirmed.

This makes “session ended” a narrower statement than “task completed.” It can mean that the Agent Window was closed, that the browser connection was lost, or that the user closed the window manually. It may also coexist with an external website action that already happened before the interruption. The session lifecycle can account for the browser resources it owned; it cannot make the page's business state part of the daemon's transactional memory. That is why later operation results, audit records, and user inspection must keep their own meanings instead of being collapsed into the session status.

This is why session stopping should not be treated like ending a command-line process. A process can exit while a tab remains open, a borrowed resource remains moved, a debugger attachment remains active, or a page action is still unknown. BrowserSkill's lifecycle is valuable because it keeps those browser consequences in view. It uses the session as the place where the bridge remembers what it created, what it borrowed, and what it must return.

The harder case is now clear. A session has a private operating space, but a useful task may begin with a tab in the user's space. Moving that tab across the boundary requires more than a browser-window lookup. It requires a claim, user authorization, an origin record, and a return path that can survive failure. That is the lifecycle of borrowing.

References