Skip to content

Browser preview breaks root-relative links/assets served from session worktrees #391

Description

@areycruzer

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
  1. Create a disposable git repo with an index.html and second.html.

  2. 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>
  3. Add the repo in Electron.

  4. Start a worker session.

  5. Open the worker session Browser inspector tab.

  6. 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

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdaemonHTTP daemon lanefrontendElectron frontend laneneeds-triageMaintainer needs to evaluate this issuepriority: mediumFix when convenient

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions