adr 0041 native browser and artifacts - Alshival-Ai/neural-labs GitHub Wiki

ADR 0041: Native browser tools and private artifacts

Status: implemented in source; image and destination acceptance are separate gates.

Decision

Codex and Claude Code receive the same optional browser tool through their existing, revocable native MCP connection. There is no additional AI account, Responses agent, Gateway, browser subscription, or image-generation API. Search uses public search pages; search-site challenges are reported rather than bypassed. The agent can navigate, read snapshots and find text, follow element references, interact with forms, inspect errors, capture screenshots, upload approved workspace files, download files, and read PDFs or capture PDF pages. Screenshots are returned to the model as MCP image content and to chat as artifacts.

Trust boundary

A lazily started Playwright worker launches the image's Chromium with its sandbox explicitly enabled. Bubblewrap gives the worker separate user, mount, PID, IPC, UTS and network namespaces. It receives a disposable home and bounded temporary filesystem, read-only system dependencies, and a private Unix proxy socket. It receives no selected CLI home, workspace mount, provider token, runtime state, private skills, host socket, or public CDP listener. Isolation failure is fatal.

The trusted HTTP/CONNECT proxy resolves destinations, rejects non-public IPv4 and IPv6 addresses (including mapped addresses and mixed DNS answers), and opens the connection to the validated address. Redirects and subresources use the same proxy. The network namespace prevents direct bypass. HTTP WebSockets and HTTPS CONNECT tunnels use the same destination checks. Only public ports 80 and 443 are supported. Operators may deny additional domain suffixes with NEURAL_LABS_BROWSER_DENIED_HOSTS (comma separated). Existing workspace host firewall policy remains independently required for CLI processes.

Local preview exceptions are explicit: http://files.workspace.invalid/path/index.html creates a random origin confined to that file's directory. Registered apps use http://app-name.workspace.invalid/ and the existing .neural-labs/public-apps.json ports 30000–30999. Neither exception grants general loopback access. Files are opened through directory descriptors with symlink traversal refused.

Every tool call revalidates its execution grant. External click/type/select/press/ upload actions require an approval for the exact page, element and action; changed pages or targets invalidate that approval. Personal users approve their own actions and Team approvals retain administrator-only resolution. Unattended jobs cannot grant interactive approval; read-only policies reject interactions. Page content remains untrusted input; a permitted public navigation can itself send HTTP requests, and normal page JavaScript runs in the browser.

Lifecycle and media

Browser state belongs to one personal conversation and connection, or one Team/ automation run. It is never imported from a user's browser. Personal contexts expire after 30 idle minutes. Run completion closes Team/job contexts; cancellation closes the worker. Turn release disconnects proxy sockets and disables authority until a new live turn reauthorizes reuse. Default capacity is two sessions with four tabs each, configurable through NEURAL_LABS_BROWSER_MAX_SESSIONS (1–8) and NEURAL_LABS_BROWSER_MAX_TABS (1–16). Operations have time limits and temporary storage is capped.

Artifacts are stored below the private native state root, with a SQLite index binding each artifact to its conversation/actor or Team channel. Retrieval rechecks current membership, channel access and conversation deletion. Artifacts are limited to 50 MiB each and 1 GiB in aggregate, with at most 100 attachments per Team run. MIME detection permits a small passive media subset; active content downloads as octet-stream. Browser contexts are disposable; successful artifacts persist with chat history.

GET/HEAD /workspace/api/native/artifacts/:id supports authenticated download and byte ranges. POST to the same resource accepts {destination,name,conflict} and saves through the Files upload/recovery pipeline with same-origin checks. It never accepts an arbitrary source URL. Native artifact-created events replay as chat attachments. Team messages carry artifact identifiers and authenticated URLs; possession of a URL does not grant channel access. Saving to shared Files is an explicit user action. Conversation deletion removes its artifacts.

Acceptance

Run the focused native browser/HTTP, MCP, desktop history and approval tests, then make validate. Run tests/native-browser-smoke.mjs in each native image under the documented native AppArmor/seccomp policy with generated state and no provider credentials. Do not disable Chromium's sandbox or namespace isolation for a failing architecture. Validate public egress and private destination rejection before product testing. Source push, image publication and managed workspace deployment are separate outcomes.

Image generation, persisted browser sign-ins, broad localhost access, unrestricted browser debugging, and the Team migration are outside this change.