Symptom
Any code path in the target app loaded in Bram's right-pane that triggers a browser download — including XMLUI's Inspector Export button — silently no-ops when clicked. No file, no devtools error, no Bram notification.
The same Export button works correctly when the same app is opened in a standalone browser (verified: http://localhost:5173/#/settings → click Inspector icon → Export → xs-trace-*.json lands in ~/Downloads/).
Diagnosis
The right-pane iframe (app/index.html:41-45) and the agent-tools-pane iframe (L52-57) are declared identically — no sandbox, only allow="clipboard-write; clipboard-read". What differs is origin:
| iframe |
origin |
Inspector Export |
tools-pane |
tauri://localhost (Bram's bundled UI; same-origin to host) |
works |
right-pane |
e.g. http://localhost:5173 (user's project server; cross-origin to host) |
silently no-ops |
The Export code is the same in both (xmlui-test/xmlui/xs-diff.html:7015-7024 — URL.createObjectURL(blob) + synthetic a.click()). The XMLUI runtime captures events correctly in both (_xsLogs is populated). The iframe attributes are identical. The only differential is the origin.
WKWebView (Tauri's macOS WebView) appears to drop synthetic anchor-click downloads from cross-origin iframes when the host hasn't registered an explicit download handler. I don't have a single authoritative URL pinning the rule down — this is inferred from the symptom plus the same-origin/cross-origin split.
Suggested fix
Register a Tauri WebView download handler on the main Bram window that:
- Catches downloads from any frame, including the cross-origin right-pane.
- Writes the file to
~/Downloads/ (or wherever the user has configured).
- Surfaces a brief notification on success ("Saved to ~/Downloads/
<filename>") so the user has confirmation parity with the standalone-browser experience.
This unblocks Inspector Export and any other XMLUI app using Actions.download() (https://docs.xmlui.org/howto/download-a-file-from-an-api) from inside Bram.
Bonus: agent-drawer "Download trace" button(s)
Since Bram already knows about both its own UI and the (potentially XMLUI) target app, it could expose convenience buttons in the agent-tools drawer that skip the Inspector dialog entirely.
(a) Bram's own trace — trivial, same-origin
Bram's UI lives at tauri://localhost, so window._xsLogs is directly accessible from the host context. A button labeled "Download Bram trace" serializes that array and writes to ~/Downloads/bram-xs-trace-<ts>.json. No iframe handshake needed.
(b) Target app's trace — needs cooperation
The right-pane is cross-origin, so Bram can't read its window._xsLogs directly. Two approaches:
-
postMessage handshake (preferred): Bram posts {type: "xmlui:requestTrace"} to the right-pane window. A small bootstrap that XMLUI ships (or that Bram auto-injects into the right-pane iframe) responds with {type: "xmlui:trace", logs: [...]}. Bram writes the response to ~/Downloads/app-xs-trace-<ts>.json. The button is enabled only after a positive handshake (i.e., when the target app is XMLUI and Inspector tracing is on).
-
Inspector iframe forwarding: When the user has the Inspector dialog open in the target app, its xs-diff.html iframe could postMessage _xsLogs upward on demand. Less general — requires the dialog to be open.
The postMessage handshake is cleaner: a small XMLUI-shipped script could expose _xsLogs (and any future trace channels) via a stable message contract, making any XMLUI app usable as a target.
Repro
- Run any XMLUI app via
python3 -m http.server 5173 on a Bram project (.bram.json server.command: "python3 -m http.server 5173", server.cwd pointing at the XMLUI app dir).
- Launch Bram.
- In the right pane, click the Inspector magnifying-glass icon → Inspector dialog opens.
- Click "Export" — note nothing happens; no devtools error.
- In a standalone browser, visit the same URL, repeat steps 3-4 —
xs-trace-<timestamp>.json appears in ~/Downloads/.
Notes
- The bug section (top) is the actionable item.
- The bonus section (agent-drawer button) is independent and could ship later as a separate enhancement once (a) is fixed — but (b) would also work standalone if you prefer to do (b) before tackling the general download-handler in (a).
Symptom
Any code path in the target app loaded in Bram's right-pane that triggers a browser download — including XMLUI's Inspector Export button — silently no-ops when clicked. No file, no devtools error, no Bram notification.
The same Export button works correctly when the same app is opened in a standalone browser (verified: http://localhost:5173/#/settings → click Inspector icon → Export →
xs-trace-*.jsonlands in~/Downloads/).Diagnosis
The right-pane iframe (
app/index.html:41-45) and the agent-tools-pane iframe (L52-57) are declared identically — nosandbox, onlyallow="clipboard-write; clipboard-read". What differs is origin:tools-panetauri://localhost(Bram's bundled UI; same-origin to host)right-panehttp://localhost:5173(user's project server; cross-origin to host)The Export code is the same in both (
xmlui-test/xmlui/xs-diff.html:7015-7024—URL.createObjectURL(blob)+ synthetica.click()). The XMLUI runtime captures events correctly in both (_xsLogsis populated). The iframe attributes are identical. The only differential is the origin.WKWebView (Tauri's macOS WebView) appears to drop synthetic anchor-click downloads from cross-origin iframes when the host hasn't registered an explicit download handler. I don't have a single authoritative URL pinning the rule down — this is inferred from the symptom plus the same-origin/cross-origin split.
Suggested fix
Register a Tauri WebView download handler on the main Bram window that:
~/Downloads/(or wherever the user has configured).<filename>") so the user has confirmation parity with the standalone-browser experience.This unblocks Inspector Export and any other XMLUI app using
Actions.download()(https://docs.xmlui.org/howto/download-a-file-from-an-api) from inside Bram.Bonus: agent-drawer "Download trace" button(s)
Since Bram already knows about both its own UI and the (potentially XMLUI) target app, it could expose convenience buttons in the agent-tools drawer that skip the Inspector dialog entirely.
(a) Bram's own trace — trivial, same-origin
Bram's UI lives at
tauri://localhost, sowindow._xsLogsis directly accessible from the host context. A button labeled "Download Bram trace" serializes that array and writes to~/Downloads/bram-xs-trace-<ts>.json. No iframe handshake needed.(b) Target app's trace — needs cooperation
The right-pane is cross-origin, so Bram can't read its
window._xsLogsdirectly. Two approaches:postMessage handshake (preferred): Bram posts
{type: "xmlui:requestTrace"}to the right-pane window. A small bootstrap that XMLUI ships (or that Bram auto-injects into the right-pane iframe) responds with{type: "xmlui:trace", logs: [...]}. Bram writes the response to~/Downloads/app-xs-trace-<ts>.json. The button is enabled only after a positive handshake (i.e., when the target app is XMLUI and Inspector tracing is on).Inspector iframe forwarding: When the user has the Inspector dialog open in the target app, its xs-diff.html iframe could postMessage
_xsLogsupward on demand. Less general — requires the dialog to be open.The postMessage handshake is cleaner: a small XMLUI-shipped script could expose
_xsLogs(and any future trace channels) via a stable message contract, making any XMLUI app usable as a target.Repro
python3 -m http.server 5173on a Bram project (.bram.jsonserver.command: "python3 -m http.server 5173",server.cwdpointing at the XMLUI app dir).xs-trace-<timestamp>.jsonappears in~/Downloads/.Notes