← Commit history
dev-skills/developing-the-bridge/SKILL.md+34−21@@ -160,29 +160,42 @@ is the pattern - the user opens the window when THEY are ready. foreground:true foregroundReason + notify, exactly like the extension path. ## ⭐ Opening native browser windows without ABE — the hard lessons (John, 2026-07-19)-Spent a whole session flailing at "open a background Edge window in the live profile" and killed the-user's AI thread TWICE. Everything below is what it actually took, and what NOT to do.+Spent a whole session flailing at "open a background window in the live profile" and CRASHED the user's+Edge (and the AI thread running in it) FOUR times. The final root cause was small and the user named it+before I did. Read this before writing any browser-launch code. -**A plain `--new-window` launch into an already-running browser just ADDS a window. It does not restart-the browser.** Edge is no different from Chrome here. If you think "opening a window is dangerous," you-are about to overcomplicate a two-line problem. The real bugs were mundane:-1. **Quote your launch args as an ARRAY, never an embedded-quote string.** `Start-Process msedge- -ArgumentList '--profile-directory="Default" ...'` passes LITERAL quotes to Chromium, corrupting the- `Default` profile match and breaking the singleton handshake → the launcher can't attach to the- running instance and things go sideways. Use `-ArgumentList @('--profile-directory=Default',- '--new-window', $url)` (or AD `launch_process` with an args array) so each arg is quoted correctly.-2. **Never guess which window you just opened by a racy diff and then MINIMIZE/CLOSE it.** That is how- you grab the workspace window instead. Snapshot the exact pre-launch hwnd set, exclude a PROTECTED- set (the workspace/editor window — match titles like `- Editor -|Hydrogen|code-server|claude.ai`- for the right browser brand — plus any other thread's live session hwnd), and only act on a window- that is genuinely new AND not protected. To background a KNOWN window, target its exact hwnd with- `ShowWindow(hwnd, SW_MINIMIZE=6)` — no diffing.+**THE ACTUAL ROOT CAUSE: opening was always fine — the BACKGROUNDING call crashed the browser.** I was+minimizing the freshly-launched window with `ShowWindow(hwnd, SW_MINIMIZE)` **inside a 30ms poll loop,+the instant the window first appeared** — i.e. hammering ShowWindow on a browser window while Chromium+was still constructing it. That race crashed the whole browser PROCESS (all its windows, including the+workspace), then Edge session-restored (windows come back with NEW hwnds — which looks like "you closed+it"). The launch itself never restarted anything. I wasted the session on exotic theories (singleton+takeover, session isolation, "Edge is fundamentally unsafe") instead of looking at my own two-line+backgrounding code and the ONE working reference implementation. -**Do NOT build a footgun and then pull the trigger.** I added a `confirmLiveProfile:true` override to a-guard whose entire point was "do not open into the live profile," then passed it on the user's live-profile and killed the thread a second time. If a guard is worth having, it should not have an escape-you'll reach for. The live-profile hazard is ONLY the minimize/close mis-targeting — solve that directly-(protected-hwnd exclude) rather than refusing the whole feature.+**READ THE WORKING IMPLEMENTATION FIRST.** Hydrogen Desktop's browser picker already opens native+browser windows reliably — `hydrogen-desktop/src-tauri/src/control.rs`, the `/open-in-profile` handler:+for Edge it just does `cmd /c start msedge <url>` — **no `--profile-directory`, no `--new-window`, and+it never minimizes.** When a working impl exists in the codebase, copy it before hand-rolling P/Invoke.++**The correct recipe (shipped 0.1.41, verified live on the user's single-profile Edge — window opened+minimized/background, workspace hwnd unchanged, no crash):**+1. **Launch clean, like HD:** don't pass `--profile-directory=Default` (only pass a profile dir when it+ is NOT the default). Args as a PowerShell ARRAY, never an embedded-quote string (`'--profile-directory=+ "Default"'` passes LITERAL quotes to Chromium). e.g. `Start-Process $exe -ArgumentList @('--new-window',$url)`.+2. **Detect the new window READ-ONLY.** Poll `EnumWindows` for a genuinely-new `Chrome_WidgetWin` hwnd+ (exclude a pre-snapshot + a PROTECTED set: the workspace/editor window — titles `- Editor -|Hydrogen|+ code-server|claude.ai|galliaApril` for the right brand — and other threads' live-session hwnds).+ **Do NOT touch any window inside this loop.**+3. **Background with ONE settled, gentle call.** After the window is found, `Start-Sleep 700ms` to let+ Chromium FULLY build it, then ONE `ShowWindow(hwnd, SW_SHOWMINNOACTIVE=7)` (minimize WITHOUT stealing+ focus). One call, on a settled window, no loop. This is the crash-safe part — the whole bug was here.++**Do NOT build a footgun, and do NOT wall off a feature you can't root-cause.** I twice over-reacted: (a)+added a `confirmLiveProfile:true` override to a guard, then passed it myself on the live profile; (b)+when crashes continued I re-added a HARD refuse that blocked the exact thing the user asked for. Both+were me guessing instead of fixing the real (tiny) bug. If you're refusing a whole capability, you don't+understand the failure yet — keep debugging. **Verify `node --check server.js` PASSES before EVERY release.** I shipped 0.1.34 and 0.1.36 with syntax errors because the release commands ran after a failed check in the same `&&` chain wasn't actually