A manifest can bring its own HTML
Explore this workspace.
Technical background
An integration may render a complete HTML document in place of the field list, given the data every fetch step returned. It runs in a frame with sandbox="allow-scripts" and nothing else — an opaque origin, no require, no process — behind a CSP that refuses the network outright.
The problem
A field list is the right shape for a ticket and the wrong shape for anything that wants a layout of its own — a chart, a table, a run of coloured badges. The manifest format has an html key for exactly that, and both repositories documented it as "reserved, not implemented in either fork", which was wrong and cost a rediscovery.
How it works
A manifest may carry a complete HTML document, rendered in place of the fields list and given window.__data — every fetch step's JSON, keyed by step id — and window.__uri. It talks back over chrome.webview.postMessage with {height} or {open}. tabby-links/INTEGRATIONS.md has the contract, htmlHost.ts builds the document, and stith.json is the worked example.
Settings
linkTooltip.allowHtml:trueRender a plugin's own HTML. Off falls back to the plain field list.
Details
sandbox="allow-scripts", and nothing else, is the entire security story. Tabby's renderer isnodeIntegration: true,contextIsolation: falsewith no CSP anywhere in the app, so a plugin page that reached the parent realm would berequire('child_process'), not XSS. Withoutallow-same-originthe frame is on an opaque origin and can do nothing but post a message. Verified live:window.origin === 'null', norequire, noprocess, and reading into the frame from the host throwsSecurityError.- A CSP is injected ahead of the document —
default-src 'none',connect-src 'none'— which the WebView2 host this was ported from does not do. The page renders data already fetched and cannot call home.img-src https:is the one exception, for parity with an icon on a fields card. srcdocis written only when the card's key changes. Assigning it reloads the page and restarts its script, and the linkifier re-asks many times a second during output.- The page could not be verified in the hidden dev build. Chromium throttles rendering for a cross-origin subframe that is never visible, so every measurement inside it reads 0 — a
height: 77pxdiv included. The test gives the page its own window, shown without focus and off-screen, purely so a compositor runs.
What this does not claim
- This is a port of a contract the originating fork cannot run: its WebView2 host is compiled behind a feature flag with no
WebView2Loader.dllshipped, sohtmlthere always falls back tofields. This fork is the only place the key does anything. - Measure
document.body.scrollHeight, notdocumentElement's — the latter is the frame's own viewport, so a page reporting it just asks to stay the size it already is. A silent no-op that looks exactly like a broken channel.