Summary
The Electron Browser preview serves worktree HTML through the session-scoped daemon route:
/api/v1/sessions/{sessionId}/preview/files/index.html
But root-relative links/assets inside that HTML, such as /second.html, resolve against the daemon origin root instead of the session preview file namespace. The preview panel then navigates to http://127.0.0.1:<AO_PORT>/second.html, which is not a registered daemon route, and shows a JSON ROUTE_NOT_FOUND response.
This breaks common static app output that uses root-relative links, scripts, CSS, image paths, or router URLs.
Severity
P2 user-visible Browser preview bug.
The preview surface loads the initial detected entry file, but normal root-relative navigation from that page leaves the preview file server and lands on daemon API root.
Repro from clean main
Tested on main at afe0817 with isolated state:
AO_DATA_DIR=/tmp/reverbcode-qa-next/ao-data \
AO_RUN_FILE=/tmp/reverbcode-qa-next/running.json \
AO_PORT=31012 \
AO_TELEMETRY_EVENTS=off \
AO_TELEMETRY_METRICS=off \
AO_TELEMETRY_REMOTE=off \
VITE_AO_POSTHOG_HOST=http://127.0.0.1:9 \
npm --prefix frontend run dev
-
Create a disposable git repo with an index.html and second.html.
-
Put a root-relative link in index.html:
<!doctype html><html><head><title>QA Preview</title></head><body><h1>QA Preview Page</h1><a href="/second.html">second</a></body></html>
-
Add the repo in Electron.
-
Start a worker session.
-
Open the worker session Browser inspector tab.
-
Click the second link in the rendered preview.
Expected behavior
The preview should keep worktree-local navigation inside the session preview file route and serve:
/api/v1/sessions/<sessionId>/preview/files/second.html
That path does work when requested directly.
Actual behavior
The Browser view navigates to daemon root instead:
http://127.0.0.1:31012/second.html
The daemon returns a route-not-found JSON response:
{"error":"not_found","code":"ROUTE_NOT_FOUND","message":"GET /second.html has no handler"}
Control check from the same run:
GET /second.html -> 404 ROUTE_NOT_FOUND
GET /api/v1/sessions/qa-alpha-2/preview/files/second.html -> 200 OK
Evidence from local QA
Initial preview URL from the worker session API:
{
"id": "qa-alpha-2",
"projectId": "qa-alpha",
"kind": "worker",
"previewUrl": "http://127.0.0.1:31012/api/v1/sessions/qa-alpha-2/preview/files/index.html",
"previewRevision": 1
}
Daemon log line after clicking the root-relative link:
time=2026-06-23T10:58:52.297+05:30 level=INFO msg="http request" method=GET path=/second.html status=404 bytes=148
Direct proof that the session-scoped file route serves the target file correctly:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<!doctype html><html><head><title>Second Preview</title></head><body><h1>Second Page</h1><a href="/index.html">home</a></body></html>
Code references
backend/internal/preview/entry.go: FileURL builds preview URLs under /api/v1/sessions/{id}/preview/files/....
backend/internal/httpd/controllers/sessions.go: the only preview file route is mounted at /sessions/{sessionId}/preview/files/*.
backend/internal/httpd/controllers/sessions.go: previewFile serves files only after mapping the wildcard path into the session workspace.
backend/internal/httpd/controllers/sessions.go: explicit local paths are normalized into the preview file route, but HTML content served through that route is not adjusted for root-relative links/assets.
Duplicate / PR check
I checked open issues and PRs before filing:
gh search issues "preview files root relative browser" --repo aoagents/ReverbCode --state open
gh search prs "preview files root relative browser" --repo aoagents/ReverbCode --state open
Both returned no matches.
Nearby open work does not appear to cover this:
Possible fix shape
One focused fix could keep root-relative worktree paths inside the preview namespace, for example by:
- serving preview HTML with a session-scoped base URL, if safe for expected static app behavior;
- rewriting root-relative
href/src URLs for daemon-served preview files;
- adding a session preview root handler that maps
/... navigation back into the active preview namespace; or
- using a dedicated preview origin/root per session instead of nesting files under the API route.
The important behavior is that static app root-relative links/assets should resolve to the session worktree preview server, not the daemon API root.
Summary
The Electron Browser preview serves worktree HTML through the session-scoped daemon route:
But root-relative links/assets inside that HTML, such as
/second.html, resolve against the daemon origin root instead of the session preview file namespace. The preview panel then navigates tohttp://127.0.0.1:<AO_PORT>/second.html, which is not a registered daemon route, and shows a JSONROUTE_NOT_FOUNDresponse.This breaks common static app output that uses root-relative links, scripts, CSS, image paths, or router URLs.
Severity
P2 user-visible Browser preview bug.
The preview surface loads the initial detected entry file, but normal root-relative navigation from that page leaves the preview file server and lands on daemon API root.
Repro from clean
mainTested on
mainatafe0817with isolated state:Create a disposable git repo with an
index.htmlandsecond.html.Put a root-relative link in
index.html:Add the repo in Electron.
Start a worker session.
Open the worker session Browser inspector tab.
Click the
secondlink in the rendered preview.Expected behavior
The preview should keep worktree-local navigation inside the session preview file route and serve:
That path does work when requested directly.
Actual behavior
The Browser view navigates to daemon root instead:
The daemon returns a route-not-found JSON response:
{"error":"not_found","code":"ROUTE_NOT_FOUND","message":"GET /second.html has no handler"}Control check from the same run:
Evidence from local QA
Initial preview URL from the worker session API:
{ "id": "qa-alpha-2", "projectId": "qa-alpha", "kind": "worker", "previewUrl": "http://127.0.0.1:31012/api/v1/sessions/qa-alpha-2/preview/files/index.html", "previewRevision": 1 }Daemon log line after clicking the root-relative link:
Direct proof that the session-scoped file route serves the target file correctly:
Code references
backend/internal/preview/entry.go:FileURLbuilds preview URLs under/api/v1/sessions/{id}/preview/files/....backend/internal/httpd/controllers/sessions.go: the only preview file route is mounted at/sessions/{sessionId}/preview/files/*.backend/internal/httpd/controllers/sessions.go:previewFileserves files only after mapping the wildcard path into the session workspace.backend/internal/httpd/controllers/sessions.go: explicit local paths are normalized into the preview file route, but HTML content served through that route is not adjusted for root-relative links/assets.Duplicate / PR check
I checked open issues and PRs before filing:
Both returned no matches.
Nearby open work does not appear to cover this:
Possible fix shape
One focused fix could keep root-relative worktree paths inside the preview namespace, for example by:
href/srcURLs for daemon-served preview files;/...navigation back into the active preview namespace; orThe important behavior is that static app root-relative links/assets should resolve to the session worktree preview server, not the daemon API root.