Cause: lightweight mode (#580) let go of the main window once two of its 30 s looks found it "not shown", and it asked Wails' IsVisible, which on the Mac is the window's occlusion state. A window the user had Command-Tabbed away from, covered by the other app's window, counted as closed: 30-60 s later its webview was dropped and the window closed, and Command-Tab back to magpie found a blank shell or no window at all. Hidden with magpie (Command-H) it went the same way, since hiding orders every window out. Change: windowUp says whether a window is up as the user sees it: ordered in on any Space, covered or not, minimised, or open as magpie was hidden (watchHide records those on NSApplicationWillHideNotification). Only a window magpie closed itself is down. lighten (through lightShown) and mainShown use it, so the Dock-while-open setting and a restart to update also keep a covered window as open. Elsewhere windowUp is IsVisible as before (visible there covers covered and minimised). Run: - Reproduced with a sandbox build of origin/main (own HOME and CFFIXED_USER_HOME, port 3481, dock+lightweight on): with the open window covered by a full-screen window of a helper process for 70 s the log said "the main window's webview let go" and the window was a blank white shell. With this change, the same run let go only the closed panel and the window kept its page (screenshot of the window). - Activation itself was checked by handing activation from the helper to magpie (NSRunningApplication activateFromApplication): with the window there it came forward. A real Command-Tab keystroke was not sent. - New TestCoveredWindowStaysUp (AppKit, own process): open, covered by another window (until IsVisible says false), hidden with the app, minimised -> up; closed by magpie, also with the app hidden -> down. With windowUp put back to IsVisible it fails: "open: the window counts as up=false, want true"; without the hidden clause: "hidden with magpie: the window counts as up=false, want true". Passes -count=10. - gofmt -l; go vet ./internal/gui; GOOS=linux go vet -tags nogui and GOOS=windows go vet (with and without nogui) ./internal/gui; go build, GOOS=linux go build -tags nogui, GOOS=windows go build; go test ./internal/gui and go test -tags nogui ./internal/gui under a temp HOME: ok.
Subsystem design references
These pages describe current responsibilities, runtime paths, state, and contracts. Start with the subsystem relevant to your task, then follow its source links to verify the implementation you change.
| Subsystem | Reference |
|---|---|
| Built-in subscriptions moving to plugins | Provider and plugin ownership |
| Plugins that run on the gateway's requests and replies | Gateway middleware |
| Claude subscription turns across Claude Code runs | Claude subscription bridge |
| How the gateway picks a provider, key or account, and falls back | Gateway routing and fallback |
| Connecting an agent's config to the gateway, drift, disconnect, WSL twins | Agent wiring |
| Providers, keys, subscription accounts, refresh and allowance | Providers and accounts |
| Instructions, MCP servers, skills and RTK written into agents | Library |
Tray, panel, window, magpie web and the page's JSON API |
GUI app shell |
A subsystem can span several packages or repositories. Its reference describes the behavior those parts provide together; it does not need to list every function.
Maintain a reference
Update the owning reference in the same PR when a change alters a documented responsibility, interface, state transition, runtime path, compatibility rule, or failure behavior. An internal refactor that preserves these contracts does not require a prose change.
Keep each fact in one reference and link to it from agent instructions or other pages. Link to source files and named symbols rather than copying implementation details that change frequently. Explain field meanings and constraints that signatures alone do not express.
For a new reference, include the responsibilities and boundaries, source of truth, main runtime paths, state transitions, important constraints, and existing verification commands. Include failure and compatibility behavior where relevant. Document current behavior separately from proposed changes; the proposal belongs in its issue or PR.
Describe a PR's semantic changes
For each affected subsystem, explain the observable change with its trigger and before/after behavior. Include changes to interfaces, state, compatibility, and failure behavior when relevant. Link the affected reference, implementation, and verification evidence. State when a refactor preserves the documented behavior.
For example, a change to plugin adoption should explain which migration state and account condition trigger it, which implementation handles requests before and after adoption, and which test exercises that transition.
This is an author-provided explanation that a reviewer verifies against the diff and surrounding code. It is not an automatically proven compatibility verdict.
Review a change
- Identify the affected subsystem and the actual runtime path, including plugin or built-in ownership.
- Compare the claimed before/after behavior with the base and head implementation. Trace relevant callers and state transitions beyond the changed lines.
- Check that changed contracts appear in the owning reference and that source links still resolve.
- Check that the cited tests or runtime evidence exercise the claimed behavior. Report checks that were not run.
A documentation update alone does not prove the implementation. Existing tests and runtime evidence remain necessary for behavior changes.