15 KiB
status, system, requirements
| status | system | requirements | |
|---|---|---|---|
| current | ui |
|
Native HTML File Preview System Design
Purpose and boundaries
Native HTML preview is a one-click static-server workflow built on Kandev's existing browser iframe policy and session port proxy. It favors browser fidelity over hostile-content isolation. Agentctl serves the current editor buffer as an in-memory entry document and serves relative assets from the selected task workspace. The active file viewer replaces its source body with an iframe that renders the page with normal HTML, CSS, and JavaScript behavior.
The feature does not create a virtual browser, transform user scripts, or introduce a second executor-routing protocol. It also does not make a security claim for arbitrary workspace HTML. The user-selected trust model is recorded in ADR-2026-09-05-trusted-browser-html-preview.
Requirement mapping
| Requirement | Design sections |
|---|---|
REQ-UI-NATIVE-HTML-PREVIEW-001 |
Architecture, Contracts, Control flow, Trust and security, Responsive contract, Failure and recovery, Verification strategy |
Architecture
File editor current buffer
|
| POST session-scoped preview request
v
Kandev backend task handler
|
| authenticated agentctl request
v
Agentctl workspace preview manager
|-- in-memory entry-document overlay
|-- workspace-rooted static files
`-- loopback ephemeral HTTP port
|
| existing session port proxy
v
Desktop or mobile file-preview iframe
The existing gateway port proxy remains responsible for session authorization, executor reachability, capability cookies for iframe subresources, response rewriting, and Browser-panel compatibility. The preview feature adds no public listener and no direct browser-to-agentctl connection.
Components and responsibilities
Agentctl
- A workspace preview manager starts one loopback HTTP server per selected root when it receives the first request. The manager closes every server during agentctl instance teardown. A port identifies one static root, including for multi-repository tasks.
- The manager stores entry-document overlays by canonical repository-relative path. Publishing the same path replaces its previous buffer and increments a version token.
- The static handler serves an overlay for an exact entry-document match and otherwise serves files from the selected workspace or repository root.
- Existing repository path resolution remains authoritative. Request paths are URL-decoded once, cleaned, joined through the workspace path helper, and rejected if the resolved path or symlink target escapes the selected root.
- Responses use standard MIME detection and
Cache-Control: no-storeso a republished current buffer and edited assets are visible on refresh.
Backend
- A task-session handler authorizes the requested session and validates the request. It also makes sure that agentctl is ready. Then it forwards the request through the existing agentctl client.
- The agentctl client preserves non-success status codes in a typed error without retaining the response body. The task-session handler maps agentctl validation, size, and availability responses to 400, 413, and 503; other upstream failures and malformed success responses become 502.
- The backend does not store HTML or proxy asset bytes itself.
- The response contains the agentctl port, scoped entry path, and version needed to construct a session port-proxy URL.
Frontend
- Preview eligibility remains derived from editable
.htmland.htmfile paths after binary-file classification. - The frontend API publishes the current editor buffer and converts the result into the same port-proxy URL form used by development servers.
- Desktop renders the URL through
HtmlPreviewContentin place of the active source editor.Show coderestores the source body, refresh republishes the latest buffer, and an explicit secondary action can callopenBrowserPanel(url)without making that panel the primary outcome. - Mobile renders the same URL in the focused file viewer and uses the same source-recovery, refresh, trust, loading, and error semantics.
- Markdown keeps its sanitized in-place renderer and existing preview state.
Contracts
Browser-to-backend request
POST /api/v1/task-sessions/{sessionID}/html-previews
Content-Type: application/json
{
"repo": "optional repository identity",
"path": "relative/path/index.html",
"content": "current editor buffer"
}
The request body is capped at 5 MiB. path must be an editable .html or
.htm file within the task workspace. repo uses the same optional multi-repo
identity accepted by existing workspace-file operations.
The successful response is:
{
"port": 43127,
"path": "/relative/path/index.html",
"version": 4
}
The frontend appends the version as a cache-busting query value when opening the session port-proxy URL. The port is an implementation detail scoped to the live task session, not a durable public identifier.
Backend-to-agentctl request
POST /api/v1/workspace/html-previews
Content-Type: application/json
The body and response use the same fields. Agentctl repeats size, extension, and path validation because the backend is not its trust boundary. Existing agentctl authentication applies.
Overlay bounds
Each document is limited to 5 MiB. An agentctl instance retains at most 32 entry-document overlays across its root servers. Replacing an existing path does not consume another slot. When the limit is reached, the least recently published overlay is evicted. The number of loopback servers is bounded by the task's configured workspace and repository roots. Overlay bytes, versions, and access metadata live only in memory.
These limits constrain accidental memory growth. They are not a hostile-code sandbox and do not constrain resources consumed by browser scripts.
Control flow
Desktop
- The file editor derives HTML preview eligibility from the current path.
- The user activates
Preview HTMLafter seeing the trusted-code affordance. - The frontend sends the current buffer, path, and repository identity to the task-session endpoint without saving the file.
- The backend authorizes the session and publishes the entry document through agentctl.
- Agentctl starts or reuses its workspace preview server and returns its port, path, and new version.
- The frontend constructs the existing session port-proxy URL and replaces the
source editor body with
HtmlPreviewContentat that URL. - The iframe loads the page. Relative subresources traverse the same proxy and are read from the workspace by agentctl.
Refreshrepublishes the latest unsaved buffer and loads the new versioned URL.Show coderestores source, whileOpen in Browser panelexplicitly opens the same URL as a secondary workflow.
The file tab, current buffer, and dirty state remain owned by the source editor flow while the iframe is visible.
Mobile
- The focused file viewer exposes the same
Preview HTMLaction. - Publishing follows the desktop flow.
- The focused viewer replaces its code body with a full-height iframe at the
returned proxy URL and keeps a
Show codeaction outside the iframe. Show codeor file identity change restores source without changing its buffer. A preview failure keeps source recovery and retry actions available.
Relative assets and browser fidelity
For an entry document at site/pages/index.html, ../styles/site.css resolves
to site/styles/site.css and /images/logo.svg resolves from the selected
workspace or repository root. Query strings and fragments do not participate
in filesystem path resolution.
The static server does not rewrite HTML, CSS, JavaScript, or import maps. Standard browser behavior covers scripts, modules, DOM APIs, fetch, media, forms, canvas, WebGL, and available Browser-panel APIs. An application that requires a build step, custom fallback routing, server-side endpoints, or HMR must continue to use the configured development-server workflow.
Trust and security
HTML preview uses the existing Browser-panel iframe policy, including scripts and same-origin behavior. It is intentionally a trusted-code workflow.
The following remain required:
- Preview HTML is never inserted into the Kandev parent DOM.
- Browser access always traverses the session-authorized port proxy.
- Static file reads stay within the selected workspace or repository root, including after symlink evaluation.
- Agentctl listens only on loopback and stops the preview server with the instance.
- The UI tells the user that previewing runs workspace code with Browser-panel capabilities.
- Logs and errors do not include the HTML buffer.
These controls protect routing and host filesystem scope. They do not isolate the user from malicious JavaScript. In deployments where Browser-panel content shares an origin with Kandev, previewed code can exercise the authority that origin and the Browser panel expose. Operators who cannot trust workspace HTML must not enable or use this action until a dedicated-origin mode exists.
Lifecycle and persistence
- A root's preview server starts on first publish and is reused for the agentctl instance lifetime.
- Entry overlays are in-memory only and do not save or modify workspace files.
- Leaving preview or closing the file tab unmounts the iframe but does not stop the shared server. Agentctl teardown stops the server.
- In-editor preview state and URLs are not persisted. Activating
Preview HTMLafter reload or executor restart publishes the current buffer to the live instance and obtains a valid URL. - Preview state is scoped to the active session plus repository-and-path identity and resets when that identity changes.
Responsive contract
- Desktop entry and outcome: The existing file toolbar exposes
Preview HTML. The action replaces the source body inside the same file tab with an iframe and keepsShow code, refresh, and optional Browser-panel actions in Kandev-owned chrome. - Phone entry and outcome:
MobileFileViewerPanelexposes a minimum 44-pixel action target. It shows a focused full-height iframe and putsShow codein Kandev-owned chrome. - Nearest shipped exemplars: Markdown preview supplies the in-place source toggle and file identity behavior. The mobile HTML focused viewer supplies the iframe toolbar, source recovery, and full-height composition. The development-server preview keeps ownership of automatic Browser-panel use.
- Scroll ownership: Browser content owns iframe scrolling. Kandev's focused viewer owns its header and must not add page-level horizontal overflow.
- Shared behavior: Eligibility, publication, errors, trust copy, proxy URL, refresh, source recovery, and retry semantics are shared. Only toolbar density and viewport composition differ.
Failure and recovery
- Invalid paths, unsupported extensions, oversized buffers, and workspace-root escapes return validation errors and do not start or update a preview.
- A missing or stopped task session returns the existing session-unavailable response. The UI preserves source and shows localized retry guidance.
- An agentctl start or publish failure keeps the in-editor preview surface open
with localized retry and
Show codeactions. Retry republishes the latest buffer. - A missing relative asset receives a normal HTTP 404 inside the preview so the browser's native diagnostics remain meaningful.
- A stale URL after agentctl restart is not restored as active preview state. Republishing obtains the current ephemeral port and version.
- The UI never falls back to
srcDoc, QuickJS, a virtual DOM, or direct file URLs when the server path fails.
Compatibility and migration
Remove the QuickJS worker, virtual-DOM renderer, source-navigation normalizer,
and their dependencies. Existing persisted markdownPreview compatibility only
applies to Markdown. HTML in-place preview starts from source after reload and
publishes only after the user activates it.
The explicit development-server action remains unchanged. Native HTML preview is the zero-configuration static case, while the development-server path remains the correct choice for applications with build or backend behavior.
Observability
Agentctl emits structured lifecycle logs for preview-server start, stop, and publish failures. Logs can include the canonical relative path, response status, and byte count, but not source content. Existing port-proxy logs and metrics continue to cover browser routing.
Verification strategy
- Agentctl unit tests cover server start, reuse, shutdown, concurrent publish/read, per-root ports, GET/HEAD/405 method handling, overlays, disk assets, MIME types, no-store headers, path traversal, symlink escape, and missing files.
- Backend handler and client tests cover session authorization, agentctl readiness, payload bounds, forwarding, typed 400/413/503 propagation, malformed requests, unavailable sessions, malformed responses, and response validation.
- Frontend API and component tests cover unsaved-buffer publication, in-editor source/preview toggling, explicit Browser-panel opening, versioned URLs, trusted-code copy, errors, retry, refresh, source-state preservation, identity reset, and stale publish completion guards.
- Desktop Chromium E2E proves that an unsaved document runs native JavaScript and loads relative CSS, JavaScript, and images. It also proves use of a native browser API and refresh after a second publish.
- Mobile Chrome E2E proves the same proxied content, 44-pixel action, full-height
containment,
Show code, and source preservation. - Existing development-server and Browser-panel tests guard against regressions in explicit server workflows and generic port-proxy behavior.
Open implementation risks
- Every executor lifecycle path must own the agentctl preview server. This ownership prevents ephemeral port leaks after stop or restart.
- Root-relative and module subresource requests must retain the session proxy capability cookie through redirects and rewritten URLs.
- Multi-repository tasks must use the same repository identity and path helper as existing workspace-file APIs.
- Preview publication completion must remain scoped to the file and session that initiated it so a stale response cannot replace another editor's body.