Skip to content

Run the TUI in the web UI as a per-connection console - #1182

Merged
edwin-zvs merged 2 commits into
mainfrom
webui-tui-console
Aug 3, 2026
Merged

Run the TUI in the web UI as a per-connection console#1182
edwin-zvs merged 2 commits into
mainfrom
webui-tui-console

Conversation

@edwin-zvs

Copy link
Copy Markdown
Contributor

Two clients render this fleet and they have never been at parity. Every TUI
capability has had to be ported into the web UI a second time — view modes,
playbook, split panes, session controls, the chord keymap — and the queue does
not empty.

This adds a console: the daemon spawns its own TUI in a PTY and streams it
to an xterm in the browser. Not one session's PTY — the whole client, session
list and all. Anything reachable in the TUI becomes reachable from a browser
the day it lands, which turns parity from a blocker into a preference about
which surface is nicer for a given task.

A console is a client, not a session (specs/0182).
It is never listed, persisted, resumed, or counted; it belongs to exactly one
connection and is reaped when that connection drops. Modeling it as a session
would have been less code — attach, input, resize and reconnect all exist — and
would have been wrong: it would appear in its own list, count itself in its own
token meter, and persist a transcript of nothing.

Because it has exactly one viewer, its geometry is just that viewer's fit. The
ownership arbitration a shared session PTY needs (0153) does not apply and is
deliberately not introduced.

The keymap has to stand down

The web UI deliberately speaks the TUI's C-x chord vocabulary (0150).
Pointed at a console that becomes two consumers of one vocabulary: C-x C-f
opens a web dialog stacked over a terminal that never saw the prefix. So while
the console is open the web keymap stands down entirely and every key, chord
included, goes to the child.

That leaves a second hole, which the follow-up commit closes: with the web
keymap down, clicking the bar or the padding around the grid takes focus off
the terminal and keystrokes reach neither consumer. Focus is handed straight
back on mouseup, skipping the close button and any live text selection.

Verified

Against the built binary with embedded assets, each keystroke sent exactly once
and no web dialog opening:

keys bytes to the child
C-x \x18
C-f \x06
C-x o \x18 o
C-x C-b \x18 \x02

Corroborated by reading the xterm buffer — the TUI's own harness picker was
open: New session: 1/11 ↑/↓ C-p/C-n select Enter choose Tab complete Esc cancel.

Scope

Desktop viewports only — a full-screen TUI on a phone has no modifier keys and
no room for the grid it wants. The modern web client stays the default surface
(0144); this is an escape hatch, not a replacement, and not a reason to stop
bringing TUI capabilities into the web UI natively.

This is a prototype: it proves the shape end to end rather than polishing it.
Known gaps are the terminal-emulator affordances listed in the spec's
Consequences — background reporting, OSC 52 clipboard, and any chord the
browser reserves for itself.

Try it

crates/daemon only → the binary is construct:

.claude/worktrees/webui-tui-console/target/debug/construct

Run construct daemon run, open the web UI, click the console button.

The web UI reimplements the TUI surface by surface, and the queue of
"web UI reaches parity on X" never empties. This adds a console: the
daemon spawns its own client under a PTY and streams it to the browser,
so anything the TUI can do is reachable from a browser the day it lands.

A console is a client, not a session — never listed, persisted, counted,
or resumable, and reaped when its connection drops. It has exactly one
viewer, so it needs none of the PTY geometry arbitration sessions do.

While the console is open the web UI's own chord keymap stands down.
Both surfaces speak the same C-x vocabulary, so leaving it armed meant
C-x C-f opened a web dialog over a terminal that never saw the prefix.

Desktop only, opt-in from settings; the web client stays the default.
While the console is open the web UI's chord keymap stands down, so any
click that moves focus off the terminal — the console bar, the padding
around the grid — leaves keystrokes with no consumer at all. Hand focus
back on mouseup, unless the click was the close button or left a
selection to copy.
@edwin-zvs
edwin-zvs merged commit 7cd9909 into main Aug 3, 2026
1 check passed
@edwin-zvs
edwin-zvs deleted the webui-tui-console branch August 3, 2026 03:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant