Skip to content

Luvus Web

Luvus Web is the browser client bundled with the normal Luvus binary. It shows the same running workspaces, tabs, panes, agents, and terminal output as the TUI. It is optional: starting luvus does not open an HTTP port or launch the web bridge.

The browser is another disposable client. Closing it or stopping the web bridge does not stop the selected Luvus server, its PTYs, or attached TUI clients.

First install Luvus and make sure its server can start normally. Then run:

Terminal window
luvus web

This command:

  1. starts or reuses the selected Luvus session;
  2. opens a foreground bridge on 127.0.0.1:4174;
  3. creates a one-use browser pairing link; and
  4. opens that link in the default browser.

The pairing link works once and expires after five minutes. Pair a browser once, then use the plain address in more tabs or after restarting the browser. Access is remembered until the bridge stops or that browser is revoked. To pair another browser or device, press Enter in the terminal running luvus web: it prints a new one-use link each time.

The default is read-only. You can inspect Mission Control and terminal output, but the browser cannot send input or change the workspace.

For interactive terminal and workspace control, opt in explicitly:

Terminal window
luvus web --control

Use --no-open when you only want the pairing link printed to the terminal, or --port 0 to let the operating system choose a free loopback port:

Terminal window
luvus web --control --port 0 --no-open

Press Ctrl+C in the terminal that started the bridge to stop web access. Luvus revokes that bridge’s temporary authority, while its server, panes, TUI clients, and named sessions keep running. Stopping the bridge any other ordinary way, such as with kill, a service manager, or by closing its terminal, does the same.

Global options come before web. To open the project session:

Terminal window
luvus --session project web --control

The browser’s Mission Control page also has a SESSION selector. Selecting a running session moves the bridge to it without detaching its other clients. In control mode, selecting a known stopped session may start it. A read-only bridge can switch only to an already-running session.

On desktop, the dashboard uses the same compact navigation as the terminal: workspaces on the left, filtered agents and panes on the right. Each desktop sidebar can be collapsed independently; tab names stay with the pane rows rather than appearing as extra workspace buttons. Both sidebar rails sit beside the rounded center frame at the same height. There is no separate desktop header bar; content fills the frame. The workspace rail stays compact on wide screens. Dashboard and terminal views share that layout; their content and navigation lists scroll independently. Mobile keeps its top navigation controls and full-screen drawer. Live stats sit in the middle of the screen without duplicate agent or workspace cards. The Luvus logo and name sit above Workspaces; the Devices icon and connection indicator sit at the bottom-left without a surrounding card. The refresh icon is there too; the same footer controls are available in terminal sidebars. Workspace rows show the name and Git branch above the path. There is no refresh button in the hero. The Active agents / All panes filter stays in sync across the dashboard and terminal. The agent/pane sidebar lists only terminals from the workspace selected in the Web UI; TUI focus changes do not change that selection. Panes opened on the Web appear most-recent-first within that list.

Smaller screens show live stats without duplicate agent/workspace cards or the old navigation bar. Use the dot beside the Luvus logo to open the full-screen workspace and agent/pane drawer from the dashboard or terminal.

One bridge has one selected upstream session, so a session switch moves every browser device paired with that bridge. TUI and CLI clients keep their own attachments.

The initial URL contains a one-use pairing code in its fragment. After the first browser connects, open Devices to create another pairing link. Scan its QR code with a phone or tablet, or use Copy or Share. QR generation happens in the browser; the pairing secret is not sent to a QR service.

A bridge allows two browser devices by default. Choose a limit from 1 through 8 in Devices, or set the initial limit at startup:

Terminal window
luvus web --control --max-devices 4

Pairing identifies a browser profile, not the physical device. Chrome and Safari on the same phone need separate pairing; normal tabs in one profile do not.

Each paired browser receives an independent ticket, remembered in that browser profile for the bridge’s origin. Open the plain address or a bookmark in another tab, or close and reopen the browser: no new pairing link is needed while the bridge runs. Tabs sharing a ticket count as one paired device, with at most eight simultaneous browser connections across the bridge. A different browser, profile, device, or origin needs its own one-use pairing link.

Access has no fixed timeout by default. It ends when you stop the bridge, revoke the browser, or reclaim its disconnected slot. To opt into finite access, set a lifetime from 1 through 86400 seconds when starting the bridge:

Terminal window
luvus web --control --ticket-ttl 3600

The lifetime starts when a browser pairs; reconnecting does not extend it. Devices → Disconnect this browser revokes that ticket, disconnects every tab using it, and frees its pairing slot. Other browsers, the server, and running terminals are not affected. Confirm the action, then use a new QR/code to pair again when you want to reconnect. Use this on a shared computer. After a bridge restart, pair again; remembered browser tickets do not restore revoked authority or survive the bridge’s shutdown.

The device limit cannot be reduced below the number of paired devices plus unspent pairing links, and a browser can never raise it above the --max-devices value the bridge started with.

Pressing Enter in the bridge’s terminal also recovers a device slot. When the limit is full, the new link replaces the oldest link nobody has used yet. If every slot belongs to a paired device, it revokes the one that has been disconnected longest. That browser must pair again if it returns. A browser is disconnected only after all its tabs close. It never revokes a connected device, or one that disconnected within the last 30 seconds and may be an open tab reconnecting.

The native bridge deliberately listens on loopback only. A phone cannot open 127.0.0.1 on your computer, and Luvus Web does not expose an unencrypted public listener. Put a trusted private tunnel or reverse proxy with TLS/WSS in front of the loopback bridge, and keep access limited to devices you trust.

Use a tunnel address known only after start

Section titled “Use a tunnel address known only after start”

Tunnels such as ngrok print their HTTPS address after they start, often a new one each time. Start the bridge, start the tunnel to its port, then paste the tunnel’s address into the terminal running luvus web and press Enter:

Terminal window
luvus web --control --no-open
# in another terminal:
ngrok http 4174
https://abc-123.ngrok-free.app
Remote access allowed for https://abc-123.ngrok-free.app.
New one-use link (expires in 5 minutes):
https://abc-123.ngrok-free.app/#pair=...

The bridge now answers to that exact host name and browser origin, uses it as the pairing address, and prints a one-use link to open on your phone. Press Enter again later for another link on the same address. Only a complete https:// origin without a path is accepted, and the change lasts until the bridge stops. Only the terminal running the bridge can do this; a paired browser cannot widen what the bridge answers to.

When the public origin is known in advance, pass it at startup instead:

Terminal window
luvus web --control \
--public-url https://luvus.example.test \
--origin https://luvus.example.test \
--max-devices 3

--public-url changes generated pairing links and must be a complete HTTPS origin without a path. --origin permits that exact browser origin during the WebSocket upgrade and accepts a complete HTTP(S) origin without a path. Repeat --origin when more than one exact origin is required:

Terminal window
luvus web --control \
--public-url https://luvus.example.test \
--origin https://luvus.example.test \
--origin https://luvus-backup.example.test

You can also add or update the pairing address while the bridge is running. From an authorized browser, open Devices, enter the tunnel’s origin under Pairing address, and choose Save address. New QR codes and links use the updated address immediately, including an unspent link already shown in the panel. Clear the field to use the address of the current browser again.

The device setting lasts for the current bridge process. Use --public-url to set its initial value after a restart. Changing the pairing address does not create a tunnel, change the loopback listener, or add an allowed origin or host.

The bridge answers only to its loopback address on the bound port, to the hosts of --public-url and every --origin given at startup, and to addresses pasted into its terminal. When your tunnel forwards the public host name to the bridge, pass that origin at startup or paste it into the terminal; otherwise the bridge refuses the request. This check blocks DNS rebinding, where a malicious page points its own domain at your computer.

The transport provider owns public reachability and TLS. Luvus remains loopback-bound and owns pairing, browser tickets, origin checks, and scoped authority. Do not publish the local HTTP port directly to the internet.

In control mode, click or tap the terminal to focus native input. Physical and mobile keyboards write to the actual PTY, so the running shell or agent still owns editing, history, cursor movement, and Tab completion. The compact control dock supplies keys that are awkward on touch keyboards.

Useful editing shortcuts include:

  • Alt/Option+Backspace or Ctrl+Backspace: delete the previous word;
  • Alt/Option+forward Delete or Ctrl+Delete: delete the next word;
  • Command+Backspace or Ctrl+U: delete to the start of the line;
  • Command+forward Delete or Ctrl+K: delete to the end of the line.

On mobile, the terminal follows the visible viewport above the software keyboard. Submitting input resumes follow-tail so streaming output stays in view. Scrolling intentionally pauses follow-tail while you read history.

Output wraps to the browser width without resizing the shared PTY. The bottom action bar provides file attachment, keyboard, and terminal key controls; there is no separate Wrap/Original toggle. Output scrolls behind the floating top controls.

On desktop, matching sidebars keep terminal output centered. The left sidebar lists workspaces; selecting one opens one of its live terminals without changing TUI focus. The right sidebar switches between live terminal panes. Its Active agents and All panes filters match the dashboard, with compact rows showing a colored status dot, plain status text, and agent name on the first row. Session titles and workspace/tab context appear on the second row. Panes you open on the Web appear most-recent-first while browsing; background updates and TUI focus changes do not reorder them. On smaller screens, use the circular dot button at the top to open a full-screen drawer with workspace selection and the workspace-scoped agent/pane list. Select a workspace or pane to return to its terminal, or use the dot at the top right to close the drawer. Click the Luvus logo to return to the dashboard; there is no separate back button over terminal output.

The + button, clipboard file paste, and drag and drop upload files up to 32 MiB in bounded chunks. Luvus stores the bytes on the selected server and pastes the resulting server-side path into the terminal. The browser never inserts its local file path into a remote shell.

The TUI and browser can be attached at the same time. Each client keeps its own viewport and render state; a phone-sized browser does not resize or replace the desktop TUI layout.

Quickly reopening a terminal can briefly wait for its previous control stream to close. The browser retries that handoff a bounded number of times; it never disconnects or overrides another client’s control stream.

These operations have different effects:

Action Result
Close a browser tab Disconnects only that browser client
Disconnect this browser in Devices Revokes its remembered ticket and disconnects all tabs using it; other browsers and running terminals are not affected
Press Ctrl+C in luvus web Stops the bridge and revokes its browser authority
Detach or close the TUI Leaves the server and panes running
Run luvus server stop Stops the selected server and its live PTYs
  • The browser never receives the owner socket, UHP pairing code, or delegated upstream token.
  • Only the terminal running the bridge can add a remote address; a paired browser can change the pairing address but not what the bridge answers to.
  • Browser pairing links are one-use; browser tickets are bearer credentials stored in origin-scoped localStorage. Pair only browsers and devices you trust. A private browser or cleared/blocked storage may require pairing again. Only the terminal running the bridge, or an already paired browser, can create a pairing link.
  • The automatically opened link is passed to the browser through an owner-only file, so the pairing code never appears in the process list where another user on the same computer could read it.
  • Read-only authority is the default; control must be requested explicitly.
  • The bridge answers only to known host names, enforces exact origins, bounded messages and uploads, separate limits for authenticated and still authenticating connections, request-rate limits, and outbound backpressure.
  • A paired browser can lower the device limit but never raise it above the operator’s --max-devices.
  • Bridge authority is process-bound. Stopping the bridge revokes it.

For the underlying automation boundary, see UHP Remote Access.

127.0.0.1 on the phone refers to the phone itself. Use a trusted TLS tunnel or reverse proxy, then paste its HTTPS address into the terminal running luvus web, or supply it with both --public-url and --origin at startup.

Section titled “The page says the browser is not paired or the link was already used”

Pairing links are one-use and expire after five minutes. Pair each browser profile once, then reuse the plain address in any tab. If you restarted the bridge, revoked access, reached an explicit ticket expiry, cleared browser storage, or changed the address, pair again. A stable HTTPS tunnel origin keeps the browser’s saved access available across visits. Private browsing and blocked storage may retain access only for the current tab.

Press Enter in the terminal running luvus web for a new link, then open it or paste it into the box on that page. A connected browser can also create one in Devices.

The page says Luvus Web does not answer to this host name

Section titled “The page says Luvus Web does not answer to this host name”

The request reached the bridge under a host name it does not know. When you use a tunnel or reverse proxy, paste its HTTPS address into the terminal running luvus web, or restart the bridge with that origin in --public-url or --origin.

Pass the public page’s exact origin to --origin. Scheme, hostname, and port must match; path-prefixed proxy mounts are not supported.

The bridge is read-only unless started with --control. Stop it and run:

Terminal window
luvus web --control

Press Enter in the bridge’s terminal: when the limit is full, it replaces an unused link or revokes a device that is no longer connected, then prints a new link. If a device disconnected moments ago, wait 30 seconds and press Enter again. If every device is still connected, forget a browser in Devices, close all its tabs, or restart with a larger --max-devices value. The accepted range is 1 through 8, and Devices can only lower the limit below that startup value.

Choose another port or let the operating system choose one:

Terminal window
luvus web --port 0

Run luvus help web for the current option reference.