Skip to content

feat: shareable terminals#6484

Draft
gustavosbarreto wants to merge 4 commits into
masterfrom
feature/shareable-terminal
Draft

feat: shareable terminals#6484
gustavosbarreto wants to merge 4 commits into
masterfrom
feature/shareable-terminal

Conversation

@gustavosbarreto

Copy link
Copy Markdown
Member

Adds shareable terminals to ShellHub: a live, public link to a running terminal session that anyone can open in a browser and watch, without signing in. Read-only by default, with an optional collaborative mode where guests can also type. Think tmate or upterm, built into ShellHub.

There are two ways to start a share.

From the web terminal

While connected to a device in the console, click the share icon in the terminal toolbar, pick a name, a time limit and whether guests can type, and you get a link to send.

Share dialog

Live share link

Anyone with the link gets a read-only (or collaborative) view of the live session. A guest joining mid-session sees the current screen right away, not a blank terminal.

Public viewer

From the device, with the agent CLI

Run shellhub-agent share on a device to share a local terminal directly, the same way you would reach for tmate. You keep using the terminal normally while guests watch.

$ shellhub-agent share -- bash
Sharing this terminal (public, read-only). Anyone with this link can watch live:

    https://your.shellhub.example/share/722956b6-59e8-45c7-baf7-1ffc9b71c2c5

The share ends when this command exits (press Ctrl-D).

Flags: --name to label it, --write for collaborative input, --duration 30m for a time limit, --user to choose the host account. A small host wrapper script (agent/scripts/shellhub-agent) forwards the invocation into the agent container and runs the command as the invoking host user, so the same command works in development and production.

Managing shares

Active shares show up under a new Shared Terminals page, with the device, mode, live viewer count and time left, plus controls to copy the link, open it, or end the share.

Shared Terminals page

How it works

The share lifecycle lives entirely in the ssh service, in a new share hub (ssh/web/share). There are no new database tables: an active share is in-memory state keyed by an opaque, unguessable token.

New endpoints, proxied through the gateway:

  • POST /ssh/shares create a share (agent-authenticated)
  • GET /ssh/shares list active shares for the namespace (user-authenticated)
  • DELETE /ssh/shares/:token revoke a share (namespace owner)
  • GET /ssh/shares/:token/stream producer stream pushed by the host
  • GET /ws/share/:token public guest viewer (no auth)

The producer (a web terminal session or the agent) pushes raw PTY output to the hub, which fans it out to every connected guest. A small per-share ring buffer keeps the most recent output so a late joiner can be replayed the current screen. It resets on screen-clear sequences, so full-screen apps replay just the current screen and memory stays bounded. A guest that cannot keep up is dropped rather than back-pressuring the producer. In collaborative mode, guest keystrokes are forwarded back into the PTY.

Safety defaults: read-only unless explicitly made collaborative, an opaque token, a configurable default lifetime (SHARE_TTL, 4h), and the share always ends when the underlying session closes.

Notes

The screenshots above are from the web flow. The agent CLI path produces the same shares (they appear in the Shared Terminals list and open in the same viewer); it is just harder to capture in a screenshot since it runs in your own terminal.

Adds a tmate/upterm-style shareable terminal: a public, read-only (or
collaborative) web link that mirrors a live terminal session to guests
without requiring them to sign in.

The ssh service gains an in-memory share registry and a fan-out hub
(one producer, N consumers, with a scrollback ring buffer), exposed via:

  - POST   /ssh/shares                 create a share (device-authenticated)
  - GET    /ssh/shares                 list a namespace's active shares
  - DELETE /ssh/shares/:token          revoke a share
  - GET    /ssh/shares/:token/stream   agent producer stream
  - GET    /ws/share/:token            public guest viewer

The console web terminal can also share its own live session in-process
(CreateLocal), teeing PTY output to the hub and, in collaborative mode,
feeding guest input back into the session. CE-compatible — it does not
depend on the Enterprise session recorder.
`shellhub-agent share [-- command]` hosts a command in a PTY and exposes
it as a public shareable terminal. Flags: --name, --write (collaborative),
--duration (time limit) and --user. The command runs on the host using the
same path as SSH sessions (command.NewCmd, i.e. nsenter+setpriv in Docker
mode) as the resolved user.

Adds a host wrapper (scripts/shellhub-agent) to install at
/usr/local/bin: it auto-detects the agent container and binary and
forwards the invoking host user via SHELLHUB_SHARE_USER, so the shared
command runs on the host as that user with no configuration.
Adds a "Share" action to the console terminal that creates a public link
to the live session (name, time limit, collaborative toggle); a public,
no-login viewer page at /share/:token (xterm, themed, mirrors host
geometry, read-only or collaborative, with clear ended/expired states);
and a "Shared Terminals" page listing a namespace's active shares with
live viewer counts, duration, mode and a revoke action.
A guest opening a share link mid-session saw a blank terminal until new
output arrived, because the shared console session only captured output
from the moment the share was created.

Capture the console session's output from the start and seed the share hub
with it when the share begins, so a late joiner is replayed the screen that
was already there. The hub's replay buffer is also reset whenever the screen
is cleared (erase screen / scrollback, alternate-screen enter/leave, full
reset), so the replay starts from a clean screen and stays bounded at 128KB
per share. Viewers reconstruct the current screen at full fidelity from the
raw replayed output — no server-side terminal emulator needed.
@gustavosbarreto gustavosbarreto requested review from a team as code owners June 13, 2026 18:52
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown

Claude finished @gustavosbarreto's task in 2m 7s —— View job


Code Review

  • Gathered PR context
  • Reviewing with 5 specialized agents (in progress)
    • Code Quality
    • Security
    • Testing
    • Go/TypeScript Patterns
    • Architecture & Cross-repo
  • Aggregating and validating findings
  • Posting feedback

@gustavosbarreto gustavosbarreto marked this pull request as draft June 13, 2026 19:44
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