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.
Start locally
Section titled “Start locally”First install Luvus and make sure its server can start normally. Then run:
luvus webThis command:
- starts or reuses the selected Luvus session;
- opens a foreground bridge on
127.0.0.1:4174; - creates a one-use browser pairing link; and
- 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:
luvus web --controlUse --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:
luvus web --control --port 0 --no-openPress 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.
Open a named session
Section titled “Open a named session”Global options come before web. To open the project session:
luvus --session project web --controlThe 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.
Pair more devices
Section titled “Pair more devices”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:
luvus web --control --max-devices 4Pairing 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:
luvus web --control --ticket-ttl 3600The 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.
Connect from a phone or another computer
Section titled “Connect from a phone or another computer”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:
luvus web --control --no-open# in another terminal:ngrok http 4174https://abc-123.ngrok-free.appRemote 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.
Set the address at startup
Section titled “Set the address at startup”When the public origin is known in advance, pass it at startup instead:
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:
luvus web --control \ --public-url https://luvus.example.test \ --origin https://luvus.example.test \ --origin https://luvus-backup.example.testYou 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.
Use the terminal
Section titled “Use the terminal”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.
Run the TUI and web together
Section titled “Run the TUI and web together”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 |
Security model
Section titled “Security model”- 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.
Troubleshooting
Section titled “Troubleshooting”The phone cannot open the local link
Section titled “The phone cannot open the local link”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.
The page says the browser is not paired or the link was already used
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.
The WebSocket origin is rejected
Section titled “The WebSocket origin is rejected”Pass the public page’s exact origin to --origin. Scheme, hostname, and port
must match; path-prefixed proxy mounts are not supported.
Input controls are unavailable
Section titled “Input controls are unavailable”The bridge is read-only unless started with --control. Stop it and run:
luvus web --controlA new device cannot pair
Section titled “A new device cannot pair”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.
Port 4174 is already in use
Section titled “Port 4174 is already in use”Choose another port or let the operating system choose one:
luvus web --port 0Run luvus help web for the current option reference.