Skip to content
 
 

Latest commit

 

History

65 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

yas

Terminal multiplexer and experimental Wayland compositor for browsers and AI agents. Nothing to configure, no required dependencies.

Wayland surfaces support Display-P3 and HDR, with SDR fallback for other viewers.

We publish a computer agent skill.

Install and run locally:

curl -sf https://yas.run | sh
yas open # opens a browser

Share over WebRTC:

yas share # prints a URL anyone can open

For full-control access through an untrusted relay, yas uplink requires mutually pinned X25519 identities and encrypts the YAS session end to end with Noise IK and AES-256-GCM. On each endpoint, set YAS_UPLINK_IDENTITY from yas uplink-keygen --private, and print its public key with yas uplink-public-key. The producer can generate a connection URL with yas uplink-url. Exchange public keys independently of the relay and follow uplink setup. Existing bearer-only uplinks must configure keys; there is no plaintext fallback.

Manage named remotes and connect to them:

yas remote add rabbit ssh:rabbit          # save a named remote
yas remote add prod ssh:alice@prod.co     # another one
yas remote add work local:work            # a named local server
yas remote list                           # show all remotes
yas remote set-default rabbit             # make rabbit the CLI default

yas open                                  # local + all configured remotes
yas terminal list                         # lists terminals on rabbit
yas --on prod terminal list               # one-off override
yas --on ssh:newhost terminal list        # full URI also works

The CLI default remote is stored in ~/.config/yas/yas.conf as yas.target = rabbit and can also be set via the YAS_TARGET environment variable. Named remotes live in the home server's own KV store, under the remotes key, which is per instance; the server watches it and publishes all routes over Relay. Any client of that server can read the stored URIs, credentials included. yas open shows the home server and its routes; the modern browser keeps its active route selection in the attached backend workspace, alongside its layout and panel state. The browser URL names only that session. SSH remotes are auto-installed on first connection. local:NAME entries work in both the CLI and the home server's Relay catalogue.

Forward ports to whatever the server can reach — ssh -L over any yas transport, plus UDP:

yas forward 8080:localhost:3000                # local 8080 → server's :3000
yas forward 8080:localhost:3000 5432:db:5432    # a list, over one connection
yas forward udp/5353:resolver.internal:53       # UDP too
yas forward add web 8080:localhost:3000         # remember it
yas forward --all                               # start every saved forward

Or proxy everything the server can reach through one port — ssh -D:

yas socks 1080                                  # SOCKS5 on 127.0.0.1:1080
curl -x socks5h://localhost:1080 http://api.internal/

Names are resolved on the server, so socks5h:// (or a browser set to proxy DNS) reaches hosts your machine cannot look up.

Listeners bind to loopback unless you name a bind address. The relay reaches whatever the server reaches; restrict it with yas server --allow-forward 'host[:ports]'. Saved forwards live in ~/.config/yas/yas.forwards (mode 0600). See docs/design/net.md.

Control terminals programmatically:

yas terminal start htop # start a terminal, print its ID
yas terminal show 1     # dump current terminal text
yas terminal send 1 q   # send keystrokes
yas terminal journal 1  # commands the shell has run (needs OSC 133)
yas terminal output 1 --wait 60  # that command's output

Interact with the muster supervisor in a terminal UI:

yas mustard

Install, update, or uninstall persistent extensions with an inline mouse-and-keyboard picker:

yas ext manage
yas ext manage --from http://localhost:10003/ext # development registry

Navigate stacks, units, current and retained terminals, and windows; inspect live terminal output and send input without leaving the UI. The Muster list fits its expanded rows; panels share compact separators. Drag the Events header to resize it, down to a single header line. Scroll a terminal with the mouse wheel or PageUp/PageDown. While sending terminal input, use Shift+PageUp/PageDown; Shift+Home/End jumps to oldest/latest output unless the application enables enhanced keyboard input. Typing returns to latest output. Focused mouse-aware applications receive normal wheel events; Shift+wheel always scrolls history. Retained terminals remain scrollable after exit. Press ? in navigation mode for all controls. Browser panes and the native viewer support application-negotiated Kitty keyboard input: distinct modified Enter/Tab/Backspace, control chords, keypad keys, repeat/release events, and extended modifiers. Without negotiation, Enter sends \r and Ctrl+Enter sends \x1b[13;5u. Native input depends on the host terminal; browser input depends on keys delivered by the browser and OS. See keyboard handling for details.

Run a pipe-oriented process without a terminal, connecting its stdin, stdout, and stderr and returning its exit code:

yas run --in /src/yas --env RUST_LOG=debug -- cargo test

--in selects the server-side working directory and --env is repeatable. The program is executed directly; use an explicit shell when shell syntax is needed.

Inspect and disconnect other clients attached to the same server:

yas client list
yas client disconnect "$SESSION_ID" --reason "duplicate browser tab"

In the browser, open the Ctrl/Cmd-K menu and choose Connected clients to see a live list of every client's age, measured outbound bandwidth, audio, filesystem, Git, LSP, KV, network, terminal, and surface subscriptions. Terminal and surface entries include their requested view sizes. Disconnecting asks for confirmation and lets you give the peer a reason.

Ordinary connections that can reach the private server socket receive the full catalogue and may list or disconnect peers. Read-only yas share consumers use a REQUIRED Core HELLO marker; the server itself selects a least-authority catalogue and rejects every unadvertised operation. A share can observe the selected Terminal, Surface, Media, and Font state, but cannot enumerate peers, create or control resources, inject input, or shut down the server.

Run GUI apps — on Linux, every terminal includes an experimental headless Wayland compositor:

yas terminal start foot    # launch a Wayland terminal emulator
yas surface list           # list graphical windows
yas surface capture 1      # screenshot a surface
yas surface click 1 100 50 # click at (x, y)
yas surface type 1 "hello{Return}" # type into a GUI window

The server auto-starts when needed.

Run isolated local instances by giving the server a name, or address one as local:<name> and let the client auto-start it:

yas server --name work
yas --on local:work terminal list
yas --on local:test terminal start htop # auto-starts a second instance

Every server has a name; omitting --name uses default. Each instance uses a named socket and stores its KV database, installed extensions, and object cache under yas/instances/<name>/ in the platform state/cache directories. The server holds an exclusive kv.redb.server.lock for that persistent instance; a second server with the same state exits even if it was given another socket. @xdg-desktop extension's intent is in that instance's KV database, while @muster reads the corresponding platform configuration directory at yas/instances/<name>/muster/. Explicit YAS_SOCK, YAS_KV_PATH, YAS_EXTENSION_PATH, YAS_WASM_CACHE, and YAS_MUSTER_DIR overrides still win. Add --export-sock if commands launched in an instance's terminals should automatically target that instance.

Supported platforms

For a GPU sandbox with Ubuntu, systemd, and browsers, see YAS on Tensorlake.

Platform Arch Wayland compositor Notes
Linux x86_64, arm64 Yes Full features
macOS arm64 No PTY multiplexing only
Windows x86_64 No PTY multiplexing only

SSH remotes are auto-installed on first connection. Requirements on the remote: curl or wget, CA certificates, and a supported OS/arch.

The embedded SSH client authenticates via ssh-agent (SSH_AUTH_SOCK) or key files (~/.ssh/id_{ed25519,ecdsa,rsa}), and resolves ~/.ssh/config for Hostname, User, Port, and IdentityFile.

Install

curl -sf https://yas.run | sh

The default binary is MIT-licensed (software H.264 via openh264). On Linux you can opt into a GPL build that uses x264 (GPL-2.0-or-later) for better software H.264 instead:

curl -sf https://yas.run | YAS_GPL=1 sh

Every binary prints its exact terms with yas --license.

Windows (PowerShell)

irm https://yas.run/install.ps1 | iex

This downloads yas.exe to %LOCALAPPDATA%\yas\bin and adds it to your user PATH. Set YAS_INSTALL_DIR to override the install location on Windows.

How it works

yas hosts terminals and tracks their parsed state. Through the native Terminal family, each browser watches complete lifecycle State and opens its own grid view. The server sends sequenced keyframes or deltas in the negotiated grid codec; deltas can use LZ4 compression, cell patches, and copy rectangles. The browser validates and acknowledges applied frames, then renders them with WebGL.

On Linux, every yas server includes an experimental headless Wayland compositor shared by all terminals. GUI applications launched inside any terminal (anything that speaks the Wayland protocol — terminal emulators, browsers, editors, media players) automatically connect to it. Surfaces are captured, encoded as H.264 or AV1 video, and streamed to connected browsers in real time. No X server, no display, no GPU required — rendering uses GPU compositing (Vulkan via dlopen) when available, with a CPU software fallback. Encoding uses openh264 or x264 (a build-time choice, see Install) and rav1e, with optional NVENC or VA-API hardware acceleration on Linux. The compositor is available on Linux only.

Each client is paced independently based on render metrics it reports back: display rate, frame apply time, backlog depth. A phone on 3G doesn't stall a workstation on localhost. The focused terminal gets full frame rate; background terminals throttle down. Keystrokes go straight to the PTY — latency is bounded by link RTT.

yas open opens the browser with an embedded YAS edge. For persistent browser access, yas edge serves the web app and authenticates either its baseline yas.v1 WebSocket or an optional native WebTransport session. WebTransport pairs the authoritative stream with QUIC datagrams; WebSocket keeps reliable fallback delivery. Both adapt to one fixed native YAS home endpoint. Relay routing and font service live in yas server; the edge has no destination mux, configuration WebSocket, font side channel, or alternate wire protocol. yas server can also run standalone for headless/daemon use. For embedding in your own app, @yas-run/react and @yas-run/solid provide framework bindings.

The browser passphrase is a full-control credential, not a viewer token. A connected client can use every family the home server advertises, including opening every Relay route with credentials held by that server. Route URIs and credentials never enter route snapshots or routine errors in the default edge mode. Font export is enabled by default and remains subject to each face's OS/2 embedding restrictions; only exportable faces are listed. Set YAS_FONT_EXPORT=0 to disable export and empty the font catalogue. Non-loopback deployments must protect every browser transport with TLS; exposing the default plaintext WebSocket listener to an untrusted network leaks full server authority. See the complete trust model.

yas proxy-daemon keeps reusable remote transport sessions alive across short-lived CLI invocations. In particular, share: retains one WebRTC ICE/DTLS/SCTP session per target while every command gets a fresh reliable DataChannel and an independent unreliable datagram DataChannel; SSH targets reuse their underlying SSH connection. The proxy auto-starts transparently on Unix and Windows — set YAS_PROXY=0 to opt out.

For the native protocol entry point, see docs/protocol.md; the canonical contract is docs/design/yas.md plus the generated wire registry. System topology and transport deployment are covered by ARCHITECTURE.md and docs/transports.md.

Configuration

Variable Default Purpose
YAS_SOCK owner-only runtime directory Exact native YAS override used by YAS clients and the fixed-home edge
YAS_SERVER_UID edge process effective UID Numeric kernel peer UID required by standalone and embedded edges for the native home socket (root is also accepted); set it for explicit cross-UID deployments
YAS_PROXY_SOCK owner-only per-user runtime socket Exact proxy socket override; automatic Unix sockets use a validated mode-0700 runtime directory
YAS_PROXY_UID client process effective UID Numeric kernel peer UID required for the proxy (root is also accepted); cross-UID use also requires an explicitly permissioned YAS_PROXY_SOCK
YAS_SERVER_NAME default Server instance name (also yas server --name NAME); isolates the socket, state, cache, and built-in extension settings. Address it with --on local:NAME
YAS_EXPORT_SOCK unset Set to 1 (or pass --export-sock to yas server) to export the server's socket path as YAS_SOCK in spawned terminals, so yas commands inside them target that server
YAS_INJECT_PATH unset Set to 1 (or pass --inject-path to yas server) to append the server binary's directory to PATH in spawned terminals, so yas itself is callable inside them
YAS_UPLINK_TOKEN unset Bearer token for the yas uplink control endpoint
YAS_UPLINK_CLIENT_TOKEN unset Consumer routing token for yas uplink-url; overridden by --client-token
YAS_UPLINK_IDENTITY unset X25519 private key as 43-character base64url; producer --identity or consumer URI identity overrides it
YAS_UPLINK_CLIENT_KEYS unset Producer allowlist of comma-separated X25519 public keys (43-character base64url each); equivalent to repeatable --allow-client
YAS_TARGET unset Default remote for non-browser CLI commands: a URI or named remote (overrides yas.target in yas.conf)
YAS_REMOTES ~/.config/yas/yas.remotes Only the file the one-time import reads; the live catalogue is the home server's remotes KV key
YAS_RELAY 1 Set to 0 on the home server to disable route publication and nested connections
YAS_FONTS 1 Set to 0 on the server to disable font enumeration, descriptions, and fetch
YAS_FONT_EXPORT enabled Set to 0 to disable font byte export and empty the catalogue; only faces whose embedding metadata permits export are listed
YAS_FONT_DIRS platform defaults Additional server font scan roots (:-separated on Unix, ;-separated on Windows)
YAS_SCROLLBACK 10000 Scrollback rows per PTY
YAS_EVENTS_SIZE 1048576 Binary server event-ring capacity
YAS_EVENTS low-throughput lifecycle events Fine-grained event names/selectors (default,+frame.*,+pty.*, or all)
YAS_EVENTS_FILE unset Stream binary events to this server-side file from startup
YAS_HUB wss://yas.run Default WebRTC signaling hub for CLI and read-only share connections
YAS_PASSPHRASE unset Passphrase for yas edge or yas share; an edge also accepts an Argon2 PHC hash from yas hash-passphrase, while browsers still enter the plaintext
YAS_EDGE unset 1 makes yas server serve the browser itself, instead of a separate yas edge (also --edge)
YAS_SHARE unset 1 makes yas server publish itself over WebRTC, instead of a separate yas share (also --share)
YAS_EDGE_PASSPHRASE YAS_PASSPHRASE The edge's own passphrase, for one server hosting both an edge and a share
YAS_SHARE_PASSPHRASE YAS_PASSPHRASE The share's own passphrase, for one server hosting both an edge and a share
YAS_TRUSTED_PROXY_IPS unset Exact comma-separated reverse-proxy IPs whose bounded X-Forwarded-For chain may identify auth clients; all forwarding headers are ignored by default
YAS_WEBTRANSPORT unset 1 enables the edge's TLS WebTransport/QUIC listener and native protocol datagrams
YAS_WEBTRANSPORT_ADDR YAS_ADDR UDP bind for edge WebTransport
YAS_WEBTRANSPORT_PUBLIC_PORT bind port UDP port advertised to the bundled browser UI
YAS_WEBTRANSPORT_CERT / YAS_WEBTRANSPORT_KEY ephemeral identity Stable PEM TLS certificate chain and private key; set both or neither
YAS_WEBTRANSPORT_PIN_CERT unset 1 advertises a configured certificate's SHA-256 pin; browser short-validity rules apply
YAS_PREFIX /usr/local or ~/.local (Unix) Override install prefix (bin/, lib/, share/ go under this)
YAS_INSTALL_DIR %LOCALAPPDATA%\yas\bin (Windows) Override install location (Windows PowerShell installer)
YAS_SURFACE_ENCODERS see below Comma-separated encoder priority list (see below)
YAS_SURFACE_BANDWIDTH ultra Ceiling on video bandwidth: low, medium, high, ultra, or a raw AV1 quantizer 10255. Adaptation is always on and only moves cheaper than this
YAS_SURFACE_SPEED realtime Encoder speed preset: slow, medium, fast, realtime, or a raw 10255 (10 = slowest, 255 = fastest)
YAS_VAAPI_DEVICE /dev/dri/renderD128 VA-API render node for hardware-accelerated encoding
YAS_COMPOSITOR_DEVICE CUDA GPU when NVENC is enabled Vulkan compositor render node; otherwise defaults to YAS_VAAPI_DEVICE
YAS_CUDA_DEVICE 0 CUDA device ordinal for NVENC hardware encoding

Surface video encoders

Set yas server --surface-encoders (or YAS_SURFACE_ENCODERS) to a comma-separated priority list of encoders. The server tries each in order and uses the first that works.

# Default priority (dedicated encode engines, compositor-resident, then software):
# av1-nvenc,h264-nvenc,av1-vaapi,h264-vaapi,av1-vulkan,h264-vulkan,h264-software,av1-software

# Force software AV1 only:
YAS_SURFACE_ENCODERS=av1-software

# Prefer NVENC, fall back to software:
YAS_SURFACE_ENCODERS=av1-nvenc,h264-nvenc,h264-software

# Same, as a flag — a typo here stops the server instead of being ignored:
yas server --surface-encoders av1-nvenc,h264-nvenc,h264-software

The other direction — what viewers may send from their camera and microphone — is --camera-codecs / --microphone-codecs (or YAS_MEDIA_CAMERA_CODECS / YAS_MEDIA_MICROPHONE_CODECS). Viewers choose within what both ends allow, from the media panel. See docs/server.md.

Value Codec Backend Max resolution Notes
av1-nvenc AV1 NVIDIA NVENC 8192×4352 RTX 40+ series; fastest AV1 encode
h264-nvenc H.264 NVIDIA NVENC 3840×2160 Requires proprietary NVIDIA driver
av1-vaapi AV1 VA-API 8192×4352 Intel/AMD GPU
h264-vaapi H.264 VA-API 3840×2160 Intel/AMD GPU
av1-vulkan AV1 Vulkan Video 8192×4352 On the compositor's GPU; per-client scaling and pacing; 4:4:4 where the driver supports it
h264-vulkan H.264 Vulkan Video 3840×2160 On the compositor's GPU; per-client scaling and pacing; 4:4:4 where the driver supports it
h264-software H.264 openh264 or x264 3840×2160 Build-time choice (x264 = GPL opt-in)
av1-software AV1 rav1e (software) 3840×2160 CPU-bound; capped to stay interactive

The browser automatically detects the codec from each frame and configures its WebCodecs decoder accordingly. Clients advertise which codecs they support and the largest frame they can decode; the server skips encoders the client can't decode.

The resolution ceiling is per viewer, not per surface. At ordinary display scales a surface is composited at whatever its most capable subscriber can receive — so an AV1 client on a 5K display gets a native 5120×2880 stream — and any viewer whose encoder or decoder stops lower is served an aspect-preserving downscale of that same surface rather than dragging it down for everyone. At a sub-1× zoom the 1× compositor source may be larger than the encode ceiling; the viewer still receives only its viewport-sized downscale. Clients that don't report a decode ceiling (anything predating the field) stay at 3840×2160.

For yas edge configuration, running as a systemd/launchd service, and Nix module setup, see SERVICES.md and nix/README.md.

Optional dependencies

yas has no required dependencies — software H.264 and AV1 encoders are statically linked, and the CPU software renderer works everywhere. GPU acceleration and audio are enabled automatically when the right libraries or binaries are present. All GPU libraries are loaded at runtime via dlopen; missing ones are silently skipped.

Video — GPU compositing and hardware encoding (Linux)

Library Used for
libvulkan.so.1 GPU compositing, Vulkan Video encode
libva.so.2, libva-drm.so.2 VA-API hardware encode (Intel/AMD)
libgbm.so.1 DMA-BUF allocation for zero-copy VA-API encoding
libcuda.so.1, libnvidia-encode.so.1 NVENC hardware encode

Without any of the above, the compositor falls back to CPU rendering and software encoding. No configuration needed.

Desktop services and audio (Linux)

Dependency Used for
pipewire Audio daemon (private instance per compositor)
pipewire-pulse PulseAudio compatibility for apps
libpipewire-0.3.so.0 Monitor capture (in-process, loaded via dlopen)
dbus-daemon Private desktop and PipeWire D-Bus sessions
wireplumber Session manager (optional, started if available)
xwayland-satellite X11 applications (optional, started if available)

Audio is disabled automatically when PipeWire is not installed or libpipewire-0.3.so.0 is not resolvable via ld.so (set LD_LIBRARY_PATH if you have it in a non-default location), or explicitly with YAS_AUDIO=0.

X11 applications run through xwayland-satellite, which yas starts once per session when the binary is on PATH and exports the resulting DISPLAY to every terminal. Wayland stays the first choice for anything that speaks it; X11 is the fallback behind it. Without the binary, sessions are Wayland-only and no DISPLAY is exported. Set YAS_XWAYLAND=0 to opt out.

How it compares

yas ttyd gotty Eternal Terminal Mosh xterm.js + node-pty
Architecture Single binary Single binary Single binary Client + daemon Client + server Library (BYO server)
Multiple PTYs ✅ First-class ❌ One per instance ❌ One per instance ❌ One per connection ❌ One per connection ⚠️ Manual
Browser access
Delta updates ✅ Only changed cells ✅ State diffs
LZ4 compression
Per-client backpressure ✅ Render-metric pacing ⚠️ SSH flow control
WebGL rendering ⚠️ Addon
Transport YAS over WS, WebRTC, Unix, SSH, TCP WebSocket WebSocket TCP UDP WebSocket
Embeddable (React/Solid)
Wayland compositor ✅ Built-in headless (experimental)
GUI app streaming ✅ H.264 / AV1
Agent / CLI subcommands
SSH tunneling built-in

Browser tips

Disable Ctrl+W tab close (Chrome / Brave / Edge)

When using yas in the browser, Ctrl+W closes the browser tab instead of reaching your terminal. Chromium-based browsers let you disable this:

  1. Navigate to chrome://settings/system/shortcuts (or brave://settings/system/shortcuts in Brave)
  2. Find the Close Tab shortcut and remove or reassign it

This frees Ctrl+W for terminal use (e.g. deleting a word in bash/zsh).

Contributing

Building from source, running tests, dev environment setup, code conventions, and release process are all covered in CONTRIBUTING.md. CI/CD pipelines, the install site, and the signaling hub are documented in SERVICES.md. The crate and package map is in ARCHITECTURE.md.

About

All-in-one remoting solution

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages