web-terminal.md RawHistoryFolder

Browser terminal

vev --web-daemon

This starts a background web server on 127.0.0.1:8778 and prints a private link. Open it in a browser to get the normal vev UI: palette, tabs, and splits.

  • Each browser tab is its own client. Closing the page detaches; shells keep running.
  • Reloading creates a new session. Find old ones with the session picker (SSP) and close the ones you don't need.
  • Running the command again prints the same link.

Access from another machine

vev serves plain HTTP. For HTTPS, put a reverse proxy in front of it (for example Caddy, nginx, or a NetBird app).

vev --web-daemon --web-listen 127.0.0.1:8778 \
  --web-origin https://terminal.example.internal

Or in ~/.config/vev/config:

web.listen = 127.0.0.1:8778
web.origin = https://terminal.example.internal
  • web.listen: IP and port to listen on, such as 100.64.0.10:8778 or [::1]:8778. No hostnames.
  • web.origin: the URL users type in the browser, without a path. Required when not listening on loopback.
  • Flags override config. Restart the gateway to apply changes; shells survive.

The proxy must:

  • keep the original Host and Origin headers,
  • forward WebSocket upgrades,
  • serve vev at the root path (no /vev/ prefix).

[!WARNING] Access to this page is access to your shell. Prefer loopback or one private IP. Avoid 0.0.0.0 unless a firewall restricts access.

Controls

Input Action
Alt+Space or Palette button command palette
Alt+h/j/k/l focus pane
Alt+1…9 switch tab
Click focus pane
Shift + wheel scroll 10× faster
Ctrl+Shift+F6 move focus out of the terminal to the Palette button
  • The terminal fits the window, up to 512×256 cells.
  • On touch devices, Select allows native text selection and Keys opens the keyboard.
  • Your browser or window manager may catch some shortcuts first. The Palette button avoids the common Alt+Space conflict.

Not supported yet: browser scrollback, touch scrolling, copy-mode clipboard export, Kitty images, OSC 52, and full emoji fidelity.

Security

  • The access token is random, kept only in memory, and gone when the gateway stops.
  • The link carries it once; the page then swaps it for an HttpOnly cookie.
  • vev --web-renew-token revokes all links and browser sessions and prints a new link. Shells keep running.
  • Host and Origin checks, a strict Content Security Policy, and input limits protect the endpoint.
  • Everything is embedded in the binary. No CDN or frontend framework.

Stop the gateway

The gateway is a separate process. Stopping the session daemon does not stop it. Send it SIGTERM.

Testing a build

Use an isolated profile so tests don't touch your real sessions:

go build -o .dev/vev-web .
VEV_ENV=web-visual .dev/vev-web --web-daemon
VEV_ENV=web-visual .dev/vev-web ls

Keep the printed link out of screenshots.

scripts/web-visual-smoke.cjs and scripts/web-access-smoke.cjs run Playwright checks. Set PLAYWRIGHT_MODULE, VEV_BINARY, VEV_ENV=web-visual, and optionally CHROMIUM_PATH. Run them only against an isolated profile: they create sessions and revoke access.

source
1# Browser terminal
2
3```sh
4vev --web-daemon
5```
6
7This starts a background web server on `127.0.0.1:8778` and prints a private link. Open it in a browser to get the normal vev UI: palette, tabs, and splits.
8
9- Each browser tab is its own client. Closing the page detaches; shells keep running.
10- Reloading creates a **new** session. Find old ones with the session picker (`SSP`) and close the ones you don't need.
11- Running the command again prints the same link.
12
13## Access from another machine
14
15vev serves plain HTTP. For HTTPS, put a reverse proxy in front of it (for example Caddy, nginx, or a NetBird app).
16
17```sh
18vev --web-daemon --web-listen 127.0.0.1:8778 \
19  --web-origin https://terminal.example.internal
20```
21
22Or in `~/.config/vev/config`:
23
24```ini
25web.listen = 127.0.0.1:8778
26web.origin = https://terminal.example.internal
27```
28
29- `web.listen`: IP and port to listen on, such as `100.64.0.10:8778` or `[::1]:8778`. No hostnames.
30- `web.origin`: the URL users type in the browser, without a path. Required when not listening on loopback.
31- Flags override config. Restart the gateway to apply changes; shells survive.
32
33The proxy must:
34
35- keep the original `Host` and `Origin` headers,
36- forward WebSocket upgrades,
37- serve vev at the root path (no `/vev/` prefix).
38
39> [!WARNING]
40> Access to this page is access to your shell. Prefer loopback or one private IP. Avoid `0.0.0.0` unless a firewall restricts access.
41
42## Controls
43
44| Input | Action |
45|---|---|
46| Alt+Space or **Palette** button | command palette |
47| Alt+h/j/k/l | focus pane |
48| Alt+1…9 | switch tab |
49| Click | focus pane |
50| Shift + wheel | scroll 10× faster |
51| Ctrl+Shift+F6 | move focus out of the terminal to the Palette button |
52
53- The terminal fits the window, up to 512×256 cells.
54- On touch devices, **Select** allows native text selection and **Keys** opens the keyboard.
55- Your browser or window manager may catch some shortcuts first. The Palette button avoids the common Alt+Space conflict.
56
57Not supported yet: browser scrollback, touch scrolling, copy-mode clipboard export, Kitty images, OSC 52, and full emoji fidelity.
58
59## Security
60
61- The access token is random, kept only in memory, and gone when the gateway stops.
62- The link carries it once; the page then swaps it for an HttpOnly cookie.
63- `vev --web-renew-token` revokes all links and browser sessions and prints a new link. Shells keep running.
64- Host and Origin checks, a strict Content Security Policy, and input limits protect the endpoint.
65- Everything is embedded in the binary. No CDN or frontend framework.
66
67## Stop the gateway
68
69The gateway is a separate process. Stopping the session daemon does not stop it. Send it `SIGTERM`.
70
71## Testing a build
72
73Use an isolated profile so tests don't touch your real sessions:
74
75```sh
76go build -o .dev/vev-web .
77VEV_ENV=web-visual .dev/vev-web --web-daemon
78VEV_ENV=web-visual .dev/vev-web ls
79```
80
81Keep the printed link out of screenshots.
82
83`scripts/web-visual-smoke.cjs` and `scripts/web-access-smoke.cjs` run Playwright checks. Set `PLAYWRIGHT_MODULE`, `VEV_BINARY`, `VEV_ENV=web-visual`, and optionally `CHROMIUM_PATH`. Run them only against an isolated profile: they create sessions and revoke access.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close