UI driver
vev --ui-driver lets a script or test read the rendered screen and send keys, over JSON Lines on stdin/stdout. It uses the normal vev client, so what you capture is what a user sees.
Start
vev --ui-driver # new numbered session, 80x24
vev --ui-driver --session work # named local session
vev --ui-driver --remote user@host # remote session on a configured host
vev --ui-driver --picker # start in the session picker
| Option |
Meaning |
--session NAME |
create that named session (with --remote: open that remote session) |
--remote HOST |
target a configured remote host |
--cols N --rows N |
viewport size, max 512×256 |
--picker |
start in the picker (not with --session/--remote) |
--socket PATH |
connect to an existing client instead (see below) |
The driver uses your normal broker and daemon. It never starts, stops, or reconfigures them. Closing stdin detaches; sessions keep running.
Protocol
The first line is the discovery response:
{"version":1,"id":0,"result":{"attachment":"<handle>","generation":0,"control":true,"status":"picker"}}
status is one of:
| Status |
Meaning |
Keys accepted? |
picker |
in the local picker |
no |
connecting |
attaching |
no |
attached |
attached to a session |
yes |
Wait for attached, then use the generation it reports for input. Never assume generation == 1.
- A run that asked for a session stays
connecting while it retries, even if the broker is missing. It never shows the picker first.
picker appears for --picker runs, a refused destination, or a failure that retrying cannot fix, with a short notice.
capture and wait keep working in every state.
Every request has version, a nonzero id, op, and attachment:
{"version":1,"id":1,"op":"capture","attachment":"<handle>","format":"both"}
{"version":1,"id":2,"op":"text","attachment":"<handle>","generation":1,"text":"printf 'driver ok'"}
{"version":1,"id":3,"op":"keys","attachment":"<handle>","generation":1,"keys":["Enter"]}
{"version":1,"id":4,"op":"wait","attachment":"<handle>","after_action":3,"expect":{"text_contains":"driver ok"}}
Operations
capture: format is text (default), cells, or both. Returns one string per row, plus cursor, geometry, and focus.
text: literal printable UTF-8. No control characters; use keys for Enter or Tab.
keys: Enter, Escape, Tab, Backspace, Up, Down, Left, Right, Home, End, PageUp, PageDown, Space, one printable ASCII character, Ctrl+<char>, or Alt+<char>.
wait: waits until all conditions match. Conditions: text_contains, session, focus, status. With after_action, only screens after that action count.
Completion
- An action is
processed when vev has handled and rendered it. That does not mean the shell has finished running the command: use wait for that.
- If a request times out after the input was accepted, the reply has
accepted:true and an action_id. The input is not undone. Use wait with after_action to follow up.
Limits
| Limit |
Value |
| Request size |
64 KiB |
| Input per request |
16 KiB, 1–256 keys |
| Request timeout |
5 s default, 30 s max |
| Connections per attachment |
4 |
| Active waits |
4 |
Error codes include invalid_request, stale_attachment, unavailable, timeout, outcome_unknown, capture_too_large, input_busy, and navigation_failed. Errors never contain screen content or credentials.
Observe an interactive client
Observation is off by default. Enable it when you attach:
vev --ui-observe attach work # read-only
vev --ui-control new work # read and send input
The client prints a private socket path to stderr (or use --ui-socket /abs/path). Connect to it:
vev --ui-driver --socket /abs/path/ui.sock
- The socket is private (
0600), and on Linux only your user can connect.
--ui-observe rejects keys and text.
- Observers never resize, redraw, or slow down the real terminal. Disconnecting leaves the client running.
Not supported: image capture, mouse, paste, resize commands, and TCP access.
source
1# UI driver
2
3`vev --ui-driver` lets a script or test read the rendered screen and send keys, over JSON Lines on stdin/stdout. It uses the normal vev client, so what you capture is what a user sees.
4
5## Start
6
7```sh
8vev --ui-driver # new numbered session, 80x24
9vev --ui-driver --session work # named local session
10vev --ui-driver --remote user@host # remote session on a configured host
11vev --ui-driver --picker # start in the session picker
12```
13
14| Option | Meaning |
15|---|---|
16| `--session NAME` | create that named session (with `--remote`: open that remote session) |
17| `--remote HOST` | target a configured remote host |
18| `--cols N --rows N` | viewport size, max 512×256 |
19| `--picker` | start in the picker (not with `--session`/`--remote`) |
20| `--socket PATH` | connect to an existing client instead (see below) |
21
22The driver uses your normal broker and daemon. It never starts, stops, or reconfigures them. Closing stdin detaches; sessions keep running.
23
24## Protocol
25
26The first line is the discovery response:
27
28```json
29{"version":1,"id":0,"result":{"attachment":"<handle>","generation":0,"control":true,"status":"picker"}}
30```
31
32`status` is one of:
33
34| Status | Meaning | Keys accepted? |
35|---|---|---|
36| `picker` | in the local picker | no |
37| `connecting` | attaching | no |
38| `attached` | attached to a session | yes |
39
40Wait for `attached`, then use the `generation` it reports for input. Never assume `generation == 1`.
41
42- A run that asked for a session stays `connecting` while it retries, even if the broker is missing. It never shows the picker first.
43- `picker` appears for `--picker` runs, a refused destination, or a failure that retrying cannot fix, with a short notice.
44- `capture` and `wait` keep working in every state.
45
46Every request has `version`, a nonzero `id`, `op`, and `attachment`:
47
48```json
49{"version":1,"id":1,"op":"capture","attachment":"<handle>","format":"both"}
50{"version":1,"id":2,"op":"text","attachment":"<handle>","generation":1,"text":"printf 'driver ok'"}
51{"version":1,"id":3,"op":"keys","attachment":"<handle>","generation":1,"keys":["Enter"]}
52{"version":1,"id":4,"op":"wait","attachment":"<handle>","after_action":3,"expect":{"text_contains":"driver ok"}}
53```
54
55### Operations
56
57- **`capture`**: `format` is `text` (default), `cells`, or `both`. Returns one string per row, plus cursor, geometry, and focus.
58- **`text`**: literal printable UTF-8. No control characters; use `keys` for Enter or Tab.
59- **`keys`**: `Enter`, `Escape`, `Tab`, `Backspace`, `Up`, `Down`, `Left`, `Right`, `Home`, `End`, `PageUp`, `PageDown`, `Space`, one printable ASCII character, `Ctrl+<char>`, or `Alt+<char>`.
60- **`wait`**: waits until all conditions match. Conditions: `text_contains`, `session`, `focus`, `status`. With `after_action`, only screens after that action count.
61
62### Completion
63
64- An action is `processed` when vev has handled and rendered it. That does not mean the shell has finished running the command: use `wait` for that.
65- If a request times out after the input was accepted, the reply has `accepted:true` and an `action_id`. The input is not undone. Use `wait` with `after_action` to follow up.
66
67## Limits
68
69| Limit | Value |
70|---|---|
71| Request size | 64 KiB |
72| Input per request | 16 KiB, 1–256 keys |
73| Request timeout | 5 s default, 30 s max |
74| Connections per attachment | 4 |
75| Active waits | 4 |
76
77Error codes include `invalid_request`, `stale_attachment`, `unavailable`, `timeout`, `outcome_unknown`, `capture_too_large`, `input_busy`, and `navigation_failed`. Errors never contain screen content or credentials.
78
79## Observe an interactive client
80
81Observation is off by default. Enable it when you attach:
82
83```sh
84vev --ui-observe attach work # read-only
85vev --ui-control new work # read and send input
86```
87
88The client prints a private socket path to stderr (or use `--ui-socket /abs/path`). Connect to it:
89
90```sh
91vev --ui-driver --socket /abs/path/ui.sock
92```
93
94- The socket is private (`0600`), and on Linux only your user can connect.
95- `--ui-observe` rejects `keys` and `text`.
96- Observers never resize, redraw, or slow down the real terminal. Disconnecting leaves the client running.
97
98Not supported: image capture, mouse, paste, resize commands, and TCP access.