Skip to content

Live campaign dashboard: render HTML in Preview, keep it live, pop out to browser #2140

Closed
4 of 4 issues completed

Description

@jacktrnr

Important

Problem — During a research campaign the researcher has no live, glanceable view of where the loop stands. What works today is a workaround: asking the agent to write an HTML status page and open it in a browser that refreshes every 15 s (status, key findings, plots). It is the fastest way to know whether to intervene, but it lives outside the studio, re-polls blindly, cannot be opened from chat (the open-in-browser path only passes https links), and breaks when the editor runs on a remote machine. Preview, the side-panel file workspace that sits beside the chat, would be the right home, but it shows .html files as source text.
Approach — Make Preview render HTML. The page is shown in a sandboxed frame with scripts off: static HTML + CSS, tables, inline SVG, and images the page references from beside it on disk (inlined by the host). Preview's existing reload-on-change makes it live with no polling in the page itself; a visible-tab poll covers files the engine's watcher does not see. A pop-out button opens the same file in the system browser for a second monitor. The research loop then writes one dashboard page per campaign at every record boundary and links it once in chat.
Approaches considered — (1) External browser tab only: closest to today's workaround, but needs the https-only rule relaxed plus a local server, and fails when the editor runs remotely. (2) A dedicated editor window: the most code (a fourth custom panel with its own security policy and panel-invariant updates) and it duplicates Preview. (3) The home campaign tile: glanceable but has no room for plots, and its data feeds no longer reach the engine server. (4) Scripts-on HTML in Preview: would let pages use CDN charting libraries, but any .html file in a repo could then run code next to the host bridge; rejected for v1 (see flip condition).
Scope — in: HTML rendering in Preview (sandboxed, scripts off), relative-image inlining, link handling, Rendered/Source toggle, zoom; live refresh when the page or its images change, including files outside the watcher; a pop-out-to-browser control; the research loop's dashboard contract. · out: running page scripts (CDN Plotly/MathJax); a new agent tool to open Preview (the agent posts a file link, one click opens it); the home campaign tile (separate follow-up); external stylesheets.
Assumptions — Agent-written dashboards are static HTML with inline CSS and sibling PNG/SVG plots (true of the researcher's existing status pages). The researcher's existing workaround pages (one uses CDN Plotly) degrade to their static content, which is acceptable.

Acceptance Criteria

  • Opening an .html file in Preview renders the page, not its source, with a Rendered/Source toggle like Markdown's.
  • Nothing in a previewed page executes: <script>, inline event handlers, and meta refresh have no effect.
  • Images the page references by relative path, absolute path or file:// URL render; remote https images render; nothing else is fetched.
  • Clicking an https link opens the system browser; clicking a relative or file:// link opens that file in Preview; nothing navigates the frame.
  • Rewriting the page on disk — by the agent's write tool or by any process, inside or outside the project — updates the visible view within a few seconds without losing scroll position; regenerating a referenced plot does the same.
  • A pop-out control opens the previewed page in the system browser when the file is on this machine, and names why when it is not.
  • The research loop's record step writes the campaign dashboard (status, latest verdicts, key findings, plots, and a "needs you" line) and links it once in chat.

Key Decisions

  • Scripts off, same-origin sandbox. The frame carries a sandbox with same-origin allowed and scripts not allowed: page scripts cannot run, and the host can read the frame to intercept links, apply zoom and keep scroll. This pairing is safe only because scripts are never allowed alongside it.
  • The host prepares the document. Before display the host parses the page, removes scripts, meta refresh, base and embedded frames, and replaces local image sources with data URIs read through the engine's file API. The original file is never modified.
  • Reload is host-driven. Page-side refresh is stripped; the watcher event (and, while the tab is visible, a periodic re-read that only re-renders on a content change) is the single refresh mechanism.
  • Pop-out is a new bridge message, restricted to existing local .html/.htm files, separate from the https-only open-external message.
  • No new agent tool. A chat file:// link already opens Preview through link resolution; the page then stays live.

Data Contracts

  • Dashboard location: inside a Research Project, under the project's reports (one folder per campaign ledger); otherwise under the local Amico home's dashboards folder — never the synced vault, where per-loop plot churn would bloat its history. One index.html per folder with a sibling plots/ folder.
  • Pop-out message: kind open-html-external, one absolute path; the extension refuses anything that is not an existing local .html/.htm file.

Constraints & Invariants

  • The frame never runs page code; the sandbox never combines script permission with same-origin.
  • Unsaved Source edits are never overwritten by a reload (existing Preview rule).
  • Existing Preview behaviour for Markdown, images, PDFs and text files is unchanged.
  • Inlining is bounded (image count and total size) so a pathological page cannot stall the panel.

Prior Art

Source

  • Idea: Jackson ↔ Aaron DM, 2026-11-06 ("open an html window in my browser that updates every 15 seconds…"; Aaron: "this is something I've been wanting to add").

Notes

  • Flip condition (scripts): if researchers need interactive charts, add an opt-in, per-file "run scripts" mode served as its own document with a no-network policy and an opaque origin (the widget-frame pattern), never by adding script permission to the same-origin frame.
  • Follow-up (not here): the home campaign tile (campaign-digest) is registered but its campaign feeds are not served by the engine server and were dropped from the widget fetch allowlist in the 2026-09-02 overlay re-extract.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions