Skip to content

[Feature]: Per-project default browser profile (so agent-opened tabs use the right profile) #13254

Description

@direksethi

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I am describing a concrete problem or use case, not just a vague idea.

Area

apps/web (Settings → Browser) and the agent browser/preview tools

Problem or use case

Browser profiles are a great addition. I use them to keep two worlds apart: one profile is logged into my work accounts and one is logged into my personal/client accounts. Mixing them up means signing into the wrong account or giving an agent access to the wrong world.

The problem is that the profile a new tab uses is decided by a single global setting (browserDefaultProfileId, set with "Set as default" in Settings → Browser). When an agent opens a browser, it always gets that one profile, whatever project the thread belongs to.

In practice:

  • I work in a work project, and the agent opens a tab in my personal profile (or the reverse).
  • The agent can't fix this itself, because the agent browser tools (preview_open, preview_navigate, …) don't accept a profile.
  • The only workaround is to remember to change the global default every time I switch projects, or to catch the tab and switch it by hand before the agent does anything.

Proposed solution

Let a project (workspace root) set its own default browser profile:

  1. Per-project default profile. Add a "Browser profile" option in the project's settings (or its context menu in the sidebar) with the choices Use global default (the default) or any configured profile.
  2. Resolution order when opening a tab: thread override (if ever added) → project default → global browserDefaultProfileId → default.
  3. Agent-opened tabs use it. When an agent opens or reuses a tab for a thread, it gets that thread's project profile automatically, with no agent involvement needed.
  4. Nice to have: an optional profileId on preview_open, so agents or skills can ask for a specific profile explicitly. If the requested profile doesn't match the project's profile, it's reasonable to show a warning or refuse.
  5. Nice to have: show the active profile name in the browser toolbar for agent-opened tabs, so it's obvious which world a tab is in.

A simpler first step that would already solve most of this: store an optional browserProfileId on the project and use it instead of browserDefaultProfileId when a thread in that project opens a tab.

Why this matters

Profiles exist to keep cookies and logins separate. Today the separation only holds if the user remembers to flip a global setting, and agents open tabs without asking, so the risky moments are exactly when nobody is watching. A per-project default makes the safe behaviour automatic. It matters most for people who do client or freelance work next to a day job, or who run several clients in parallel.

Environment

T3 Code (Nightly) 0.0.43-nightly.20260922.2123, macOS.

Activity

  1. direksethi commented on Sep 23, 2026

    @direksethi
    Author

    Also posted in Discussions → Ideas, since that's where the issue templates point feature requests: #13255. Happy for either one to be closed in favour of the other.

  2. juliusmarminge commented on Sep 23, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed against current main. A new browser tab that does not name a profile uses one client setting, browserDefaultProfileId. Nothing on the project overrides it, and preview_open cannot pass a profile. The report matches the code. It is a feature request, not a bug.

    What the code does

    browserDefaultProfileId lives on client settings in packages/contracts/src/settings.ts. browserDefaultOpenProfileId in apps/web/src/browser/browserDefaults.ts resolves that single value. A missing profile falls back to default. Incognito is excluded, so it cannot be the stored default.

    Both hand-opened tabs and agent opens go through that helper:

    • openPreviewSession sends input.profileId ?? browserDefaultOpenProfileId(defaults).
    • When preview_open has no tab to reuse, PreviewAutomationHosts sends browserDefaultOpenProfileId(defaults) and nothing from the thread's project.
    • PreviewAutomationOpenInput has no profileId. The other preview_* tools do not take one either.

    reuseExistingTab defaults to true, so an agent keeps the session's current tab and its profile. The partition is fixed when the Electron guest attaches (profileId on PreviewSessionSnapshot). There is no action to move an open tab onto another profile. The hand path is a new tab: the right-panel add menu and the empty-panel Browser chevron call addBrowserSurface with a profileId. Those choices show up only once more than one profile exists.

    Project settings do not store a profile. ProjectSettingsOverrides covers model, workspace, scripts, and enableAgentBrowserAccess, which is only the on/off gate for agent browser tools. The project settings Browser row is that gate. Profiles stay in client settings because the Chromium partition is desktop-local. A profile id stored on the server would not exist on another desktop, or on mobile.

    Cookies are partitioned by environment plus profile (resolvePartitionScope in apps/desktop/src/ipc/methods/preview.ts), not by project. Every project on that desktop shares one profile's logins. A global default is what mixes the work and personal accounts.

    The toolbar already names the profile, and only when the tab's profile differs from the resolved global default (PreviewView, leadingActions). A tab on the global default shows no badge.

    Related work, not this request

    • #9704 (open) adds an optional profileId on preview_open and returns it from status. That is the explicit agent argument from the writeup. Calls that omit it still use the global default, and the PR does not add a project setting. It does not cover the unattended case.
    • #9402 (closed, not merged) asked agent-created tabs to honor the configured default. That behavior is already on main. Agents do follow browserDefaultProfileId. The gap is that the value is global.
    • #8256 (open) would put projectId into the partition so one profile's cookies no longer cross projects. That isolates jars. It does not choose which existing profile a project opens.
    • Discussion #13255 was the same writeup and is closed as a duplicate of this issue.

    Next step

    Keep this issue as the tracker for a per-project default profile. A useful shape:

    1. A client-local per-project profile, defaulting to the global profile, resolved in browserDefaultOpenProfileId so agent-created tabs and hand-opened tabs share it.
    2. Leave an explicit profile from the add-tab menu as an override for that one tab.
    3. Treat #9704's profileId argument as separate. An agent that passes it is asking, not inheriting the project.

    Until then, set the global default under Settings → Integrations → Browser before the agent opens a new tab, or open the tab from the profile submenu. An existing tab stays on the profile it was created with.

  3. added
    enhancementRequested improvement or new capability.
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    on Sep 23, 2026
  4. locked and limited conversation to collaborators on Oct 11, 2026
  5. converted this issue into a discussion #18004 on Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedenhancementRequested improvement or new capability.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions