Show pages inside Berd instead of handing them off to the system browser
- Dominant language
- TypeScript
- Stars
- 909
- Forks
- 116
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 156
Description
- [x] I searched open and closed issues for duplicates.
- [x] I am using a recent release (v0.6.2) and this doesn't already exist.
- [x] This is one request, not several bundled together.
**Closest existing issue:** none found. #89 and #90 are window-lifecycle requests and #1 is the Renovate dashboard.
## Is this new, or an improvement?
New capability. Berd cannot do this today.
## The problem, in my terms
Most of what my agents produce is URLs. A viewer for a cloud device while a test runs, a local dev server after a rebuild, a run report, a PR. Every one of them hands me off to Chrome, and from that point the conversation and the thing the conversation is about live in different windows.
It costs the most when the page is something I have to keep watching. Yesterday an agent was driving a phone on a device farm: it narrated each step in Berd while the phone streamed in a browser tab. I read a message, switched to the tab, switched back, and lost my place in both. Berd also stops being the front window while I'm over there, so I miss the moment the agent asks me something.
## What I do today
Berd on one half of the screen, a Chrome window on the other, and I alt-tab between them. That holds until I change spaces or the browser window slips behind something, and then I'm hunting for it. Pasting a screenshot back into the chat covers a static page. It does nothing for a live stream.
## What I'd like to see
A panel beside the chat that holds one page:
- a toggle in the top bar and a keyboard shortcut
- an address field
- back, forward, reload, and an "open in default browser" escape hatch
- a way for an agent to put a page there itself, along the lines of `berdctl browser open --url `
The agent-facing half is the part I want most. An agent that just started a dev server should be able to show me the dev server.
## Why this belongs in Berd itself
A skill, agent, extension, or automation can only shell out to `open`, which is the behavior I'm trying to get away from. Putting a page inside the app window means creating a webview, or a window that tracks the main window's geometry, and nothing outside the app can reach that. The agent-facing half has the same problem: berdctl is the app-control surface, and its command set is compiled into the app.
## Non-goals
- Not a general browser. One page at a time, no tabs, no history UI, no bookmarks, no profiles.
- Not the default for every link. Ordinary links should keep opening in the system browser unless someone asks for the panel.
- Not devtools or a page inspector.
- Not for the detached session windows. The main window is enough.
- Not a scraping surface for agents. This is for a human to watch.
## Alternatives I considered
An iframe in the existing artifact or MCP app surface. Plenty of pages set `X-Frame-Options` or `frame-ancestors` and refuse to load, and Berd's CSP has no `frame-src`, so it would need widening to arbitrary hosts.
Adding a second webview to the main window, which is where I started and where I got stuck. Once a window hosts more than one webview, `get_webview_window("main")` returns `None`, because `Window::is_webview_window` requires every webview on the window to carry the window's own label. Lookups across the app go dark, the app-test-driver plugin included.
A second ordinary window the user arranges themselves. That is a browser window, and arranging it is the thing I'm trying to stop doing.
Screenshots into the chat. Fine for a static page, useless for anything live.
## Mockups, prior art, or other context
I built this in a local fork first, to find out whether it was a reasonable thing to ask for. Two things bit me that would bite anyone else implementing it:
1. The multi-webview problem above. A borderless child window built with `.parent(&main)` sidesteps it. On macOS that lands as an `NSWindow` child, so it follows the main window when the window moves and only needs repositioning when the panel's own rect changes.
2. WebKit suspends a webview whose window isn't frontmost. The panel paints white the moment you switch apps, which is exactly the case the feature exists for. `BackgroundThrottlingPolicy::Disabled` on the window fixes it.
Happy to share the branch if any of it is useful. I'm not proposing you take a patch, and I read the policy on outside PRs before filing this.
## Environment
- Berd version: 0.6.2
- OS: macOS 26.5.1 (25F80)
- Hardware: Apple M5
Contributor guide
Research direction
Start by tracing the main window and berdctl command paths, including get_webview_window("main") and the app-test-driver plugin behavior described here. Review the existing window lifecycle before evaluating a child webview approach. Done means a one-page main-window panel with navigation controls, a shortcut and toggle, an "open in default browser" action, and agent access through berdctl browser open --url.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, typescript
- Domain
- cli, desktop
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100