Glass logoGlass

Updated

Glass documentation

Glass is a free, open-source, low-latency remote desktop for macOS and Linux (Wayland). Install it on the computer you want to control, then see and control it from a browser on an iPad, iPhone, or another computer. Typical latency is 15–30 ms from screen capture to display, over Tailscale or from anywhere through a one-time link (direct WebRTC, end-to-end encrypted). Nothing to install on the viewing device.

What Glass does

Glass streams a Mac's screen to a web browser and sends mouse, keyboard, and touch input back. It is built for speed, using the same techniques as game-streaming tools (hardware video encoding, UDP-style transport, no buffering) instead of the video-call stack that tools like Chrome Remote Desktop use.

Features:

Install

On the Mac you want to control, run in Terminal:

curl -fsSL glassdesk.dev | sh

The installer:

  1. Checks that this is macOS 13 or newer.
  2. Downloads the latest release (a universal binary for Apple Silicon and Intel) and verifies its SHA-256 checksum.
  3. Installs to ~/.glass and links the glass command into ~/.local/bin (adding that to your PATH if needed).
  4. Adds Glass.app to ~/Applications (macOS) and opens it, where setup takes a few clicks. Over SSH, or on Linux, it starts glass setup in the terminal instead.

Running the same command again updates Glass in place (it says which version it updated from), restarts the background service, and skips the setup guide if Glass is already set up. Settings and macOS permissions carry over.

The Glass app (macOS and Windows)

Open Glass from Applications or Spotlight, or choose Open Glass… from the menu bar icon. On Windows, open Glass from the Start menu or the tray icon. It does everything the glass command does, in a window:

The first time it opens, it walks through setup. It's a separate process from the background service, drawn on the GPU (with GPUI), and quits when you close its window; Glass keeps running in the background.

Setup (glass setup)

The setup guide (in the app, or glass setup in a terminal) walks through four steps and checks each one live:

  1. Tailscale (remote access). Glass uses Tailscale to reach the Mac securely from other devices, with no port forwarding. Setup checks that Tailscale is installed and signed in, and that HTTPS Certificates are enabled for your tailnet (one switch on https://login.tailscale.com/admin/dns; browsers require HTTPS for the APIs Glass uses). It then fetches a certificate for the Mac's tailnet name. Without Tailscale, skip this step: setup ends by offering a one-time link that connects your iPad from any network instead (see From anywhere below).
  2. Background service. Glass installs a per-user LaunchAgent (dev.glassdesk.host) so it runs in the background, optionally starts at login, and restarts if it crashes.
  3. Screen Recording permission. macOS asks to let glass record the screen. Setup opens the right System Settings pane (Privacy & Security › Screen Recording on macOS 13–14, Screen & System Audio Recording on 15+) and waits until capture works.
  4. Accessibility permission. Needed to inject mouse and keyboard input. Setup opens the pane and waits until it's allowed.

It finishes by showing the connect URL and a QR code to scan with the iPad.

Let an AI agent use your computer

glass mcp is an MCP server that gives an AI agent your computers running Glass: their screens, pointers and keyboards. One server reaches all of them: list_machines shows the computers on your tailnet, and every tool takes a machine (by name) to work on one, so "on the Mac mini, …" just works. You watch what it does live from any viewer, and stay in charge:

Add it to Claude Code:

claude mcp add -s user glass -- glass mcp      # this computer, and the others by name

To make another computer the default instead of this one: glass mcp --machine mac-mini. Other computers need Glass 0.4.2 or newer, and accept an agent only from their owner's devices (signed into Tailscale as the same user).

Then ask, for example: "on my Mac, export the frames from the open Figma file to the Desktop". Any MCP client works the same way (command glass, argument mcp).

Tools: list_machines, screenshot, list_displays, click (left, right, middle; double and triple), move_pointer, drag, scroll, type_text (any text), press_keys (cmd+s, return, ctrl+c…), wait_for_change, snapshot, press, set_value, request_help, confirm and check_answer. confirm and request_help take an optional wait_seconds: when you haven't answered by then, they say the question is pending (it stays up for you), and check_answer collects your answer later. Coordinates are in the pixels of the latest screenshot (1280×800 at most unless the agent asks for more), so they work with computer-use models as is.

On a Mac, snapshot reads an app's window (and its menu bar) through Accessibility as text: each element's role, name and value, with a ref like @k3f9:e12 on each one it can act on. press (buttons, links, checkboxes, tabs, menu items, rows) and set_value (text fields) act on a ref without moving your pointer, even in a window behind others. A ref is good only for the snapshot it came from: if the window changed, nothing happens and the agent is told to take a new snapshot. Password fields never show their contents, and an agent under a grant can't fill one in. Chrome and Electron apps (Slack, VS Code…) show a page's content only while their window is visible, so the agent brings the window to the front first; an app that has just launched may need a moment before it answers. Canvases, games and video don't appear in a snapshot: the agent uses screenshots for those.

Only the computer's owner can drive it: your own tailnet devices, or this computer's token (which glass mcp reads by itself on this computer). Guests and links can't. Under the hood it's an HTTP API at https://<computer>/agent/v1/ (POST /agent/v1/act with {"action": "click", "x": 640, "y": 400} and so on, sent as Content-Type: application/json), if you'd rather call it directly.

Agents from anywhere

Agents that don't run on your computers (on Vercel, in claude.ai or ChatGPT, on a server) can ask to use one. Glass is a standard MCP server over HTTP with OAuth sign-in, so anything that speaks the MCP authorization spec works, including Vercel Connect:

glass agents public on       # publish it with Tailscale Funnel; prints the URL
vercel connect create https://mac-mini.tail1234.ts.net:8443/mcp

On your tailnet no publishing is needed: use https://<computer>/mcp. Publishing needs Funnel allowed for the machine in your tailnet's settings; if it isn't, glass agents public on prints the link to allow it.

Approving takes one tap. The agent sends you to a sign-in page on your computer. Opened through your tailnet address on one of your other devices (signed in to Tailscale as you), it has an Approve button, which works a moment after the page appears. Anywhere else (through the Funnel address, on the computer itself, behind tailscale serve on Linux) it shows a number, and Glass asks you to tap the matching one of four, in the viewer or the Mac app; the notification tells you where. Picking the wrong one denies it, and that agent can't ask again for 10 minutes, so guessing doesn't work. The computer never approves on its own: not from a browser on its own screen, and not from its own viewer while an agent is working; nor while a guest is connected. After that, the agent works with no prompts: its access refreshes itself, and a grant ends after 30 days unused (180 days at most).

What an agent can do is checked on your computer, at every step:

In the Mac app (AI agents): turn agents on or off, copy the MCP address, publish with Funnel, install apps that asked, see and revoke agents, and see what they did lately.

Revoking is immediate: in the Mac app, with glass agents revoke <id> (or all), or from the agent's platform (Vercel's revoke calls Glass's). An old refresh token used again (a stolen copy) revokes its grant on the spot. Approving an agent again replaces its earlier grant. Turning it off: the Mac app's Settings (AI agents), the console's settings, or glass config agents off (the same as glass agents off) refuses every agent from another device and stops publishing with Funnel. Grants are kept for when it's back on. Agents on the computer itself (glass mcp) aren't affected.

Every action is logged to agent-audit.jsonl, each line chained to the one before by its hash: glass agents log shows the latest, glass agents verify checks nothing was changed.

Cloud agents never hang on you. A question (confirm, request_help) holds the agent's request 20 seconds at most (it can ask for up to 50), then tells it the question is pending, so serverless functions don't time out. The question stays up in Glass and on your phone for 30 minutes; the agent does other work and collects your answer with check_answer. It's told not to take the action until it's approved.

Unattended agents (Vercel Connect's app subject, OAuth client credentials, by dynamic registration or a client ID metadata document) need installing once on the computer: when one asks, you get one notification, and glass agents shows glass agents install <client>. Revoking an app's grant uninstalls it.

For providers: authorization server metadata at /.well-known/oauth-authorization-server, protected resource metadata at /.well-known/oauth-protected-resource/mcp, client ID metadata documents or dynamic registration (RFC 7591/7592), PKCE S256, authorization_code, refresh_token and client_credentials, client authentication none, client_secret_basic/post or private_key_jwt, revocation (RFC 7009), and the iss parameter on redirects (RFC 9207). Access tokens last 10 minutes. With Funnel on, only these routes are published; the viewer and everything else stay on your tailnet.

Set up with an AI agent

Glass ships an agent skill: https://glassdesk.dev/skill.md. With it, an agent like Claude Code can set Glass up on any Mac or Linux machine in your Tailscale tailnet over SSH. It finds the machine, installs Glass, runs the unattended setup, tells you exactly which permission switches to click on that machine's screen, waits until everything works, and verifies the connection.

Install it for Claude Code:

mkdir -p ~/.claude/skills/glass && curl -fsSL https://glassdesk.dev/skill.md -o ~/.claude/skills/glass/SKILL.md

Then ask, for example: "set up Glass on my Mac mini". The target needs SSH: Tailscale SSH (sudo tailscale set --ssh) or Remote Login on macOS.

The skill drives two commands you can also use in your own scripts:

Connecting

  1. Install Tailscale on the iPad (or other device) and sign in with the same account as the Mac.
  2. Open https://<your-mac>.<your-tailnet>.ts.net (shown at the end of setup, and by glass status). The same address with :8080 also works.
  3. Optional: in Safari or Chrome, tap Share → Add to Home Screen, then launch Glass from its icon. It runs fullscreen with no browser UI, so Safari's own shortcuts (⌘W, ⌘T, ⌘L, ⌘R) reach the Mac instead.

Devices that aren't on your tailnet, or belong to another tailnet user, are asked for the access token (glass token shows it; glass token --set lets you choose one). A link containing #t=<token> signs a browser in once and is then remembered.

Magic links. To let in a device without handing out the token, run glass link on the host; it prints the link and a QR code. The link works once, within 15 minutes, and gives that device its own access for 24 hours by default (glass link --for 7d to change it). Guests can use the computer but can't switch machines or update Glass. glass link --revoke cuts every guest off within seconds and voids unused links; your token and tailnet devices are unaffected. Only fingerprints of links and passes are stored, in ~/.config/glass/access.json. On your tailnet, the guest's device must be on the tailnet too; for anywhere else, see the next paragraph.

From anywhere (no Tailscale on the device). glass link --anywhere makes a link like https://glassdesk.dev/app/#r=…&l=… that works from any network. The browser and your computer connect directly over WebRTC: UDP, end-to-end encrypted, about as fast as on the tailnet. When a direct path is impossible (some cellular and corporate networks), traffic goes through Cloudflare's TURN relay, still end-to-end encrypted. glassdesk.dev only introduces the two sides; your computer keeps one outgoing connection to it and opens no ports. The link carries your computer's public key and the computer signs every connection answer, so the browser refuses anyone else, glassdesk.dev included. Remote access is off until you make such a link (or run glass remote on); glass remote off turns it off. One thing to know: in this mode the viewer page itself comes from glassdesk.dev, whereas on your tailnet it comes from your own computer.

Your computers (glassdesk.dev/computers). Sign in there with a passkey (no email, no password; it syncs through iCloud Keychain, Google Password Manager or your password manager) to see which of your computers are online and open any of them from any device. To add a computer, run glass account add on it (remote access must be on) and open the one-time link, or scan its QR code, where you're signed in. Your computer signs that claim with its key, so nobody can add a computer they don't control. The account only lists computers: opening one still takes that computer's own sign-in, so someone who got into your account would see names and who's online, never a screen. glass account remove takes a computer off every account; deleting the account on the page deletes its list. glassdesk.dev keeps the passkey's public key, each computer's name and public key, and a hash of each sign-in cookie. To look after your computers rather than just reach them (their state, actions you can take, rules they should meet), see Glass Fleet.

Help someone (quick support)

For helping a parent or a friend who doesn't have Glass, and shouldn't have to install anything:

  1. They open Terminal (on a Mac: Spotlight, type Terminal) and paste curl -fsSL glassdesk.dev/help | sh. If they already have Glass, glass support does the same.
  2. A Glass window shows a nine-digit code (in the terminal on Linux or over SSH). The first time, macOS asks them to allow Screen Recording and Accessibility for Glass; the window has buttons for both.
  3. You type the code at glassdesk.dev/help. They're asked before you can see anything, and your viewer says "You're helping …".
  4. They click Stop sharing (or press Ctrl+C, or close the window) when you're done.

Nothing stays on their computer: Glass runs from a temporary folder with its own temporary settings, token and keys, not as a background service and not at login, and stopping deletes all of it. The connection is the same as glass link --anywhere: direct, end-to-end encrypted, no ports opened. Each code works once, for an hour; glassdesk.dev keeps only a salted hash of it, and a code typed wrong too often is locked out for that browser. New code in the window (or n in the terminal) replaces it. A downloadable app for the same thing needs Apple notarization and is coming; for now it's the one line.

Glass Fleet (new)

Fleet is a new set of things in Glass, separate from connecting to a computer. Until now Glass got you into a computer. Fleet is for looking after the computers on your account: seeing what state they're in, doing things to them without opening a screen, and checking them against rules you set. It needs Glass 0.9 or newer on each computer, and everything in it is off until you turn it on, computer by computer. If you never use it, nothing else in Glass changes.

What it isTurn it onWhat authorizes it
DetailsEach computer tells your account its model, system, disk, encryption, firewall, battery and more, so you can see them all in one list.glass fleet onThe computer signs each report with its own key.
ActionsFrom your account's page: refresh details, update Glass, restart Glass, restart the computer, or run a script you placed there.glass fleet manageYour passkey signs each action, and the computer checks it.
PolicyRules every computer should meet (FileVault on, a minimum macOS…). The page marks the ones that don't.Set it on the page.Nothing: it only reads the details. It can't change a computer.

Set it up

  1. Update Glass to 0.9 or newer on the computer, and turn on remote access: glass remote on.
  2. Put the computer on your account: glass account add, then open the link where you're signed in at glassdesk.dev/computers.
  3. For details: glass fleet on. It sends the first report straight away, and the details appear on the computer's row. (If it says "not sent yet", the computer isn't on an account: do step 2.)
  4. For actions: glass fleet manage on the computer prints a link and a QR code. Open it where you're signed in, press Allow and confirm with your passkey. The computer's row gets an Actions button.
  5. For policy: open Policy on the page and tick the rules you want.

Details

Every 15 minutes (and when you ask), a computer on your account sends this, and only this:

The computer signs each report with its own key. glassdesk.dev keeps only each computer's latest report, and only for computers that are on an account. The page shows it under the computer's name and marks what needs attention: FileVault or firewall off, a nearly full disk, a low battery, a report that has gone stale. With four or more computers there's a search box that matches names, status and these details.

glass fleet status shows whether it's on and when it last sent. glass fleet report sends one now and prints it. glass fleet off stops reporting and deletes what was sent; so does glass account remove.

Actions

An action is something your account asks a computer to do. The list is fixed:

ActionWhat happens
Refresh detailsThe computer sends a report now.
Update GlassThe computer updates itself and restarts.
Restart GlassGlass restarts and anyone viewing reconnects in a few seconds.
Restart computerThe computer restarts (open apps are asked to quit); Glass is back once someone is logged in.
Run a scriptRuns a script you placed on the computer, by name.

Scripts. Put them in ~/.config/glass/fleet/scripts/. Glass only runs a script when the folder and the file are both yours and nobody else can write them (chmod go-w), the file is executable and a plain file (not a link), and its name is letters, digits, dots, dashes and underscores. It runs for at most a minute (and is stopped, along with anything it started, after that), and the last 2,000 characters of its output come back to the page. Glass never runs anything you didn't put there.

How an action is authorized. Each time, the page asks for your passkey, so you confirm with your fingerprint, face or PIN, and builds a command: this computer, this action, a one-time number, an expiry a couple of minutes away. The passkey signs that exact command. glassdesk.dev passes it to the computer, and the computer checks the signature itself against the passkey it saved when you set it up. It refuses a command that is expired, was already run, is for another computer, was signed for another site, wasn't confirmed by you, or whose passkey it doesn't know. The page has no way to run anything the computer hasn't checked.

Setting up a passkey (glass fleet manage). The link holds a one-time code that never goes to glassdesk.dev, because it sits after the #, which browsers don't send. The page uses that code to vouch for your passkey's public key, and the computer saves the key only if the vouch checks out. The link works once, for 15 minutes, for one passkey. Run it again to add another passkey (up to 8). Only ES256 passkeys can manage computers, which covers nearly all phones, Macs and security keys.

Every action, and every refusal, is logged on the computer: glass fleet manage status shows the latest, and the full log is ~/.config/glass/fleet/actions.log. glass fleet manage off forgets every passkey and stops all actions at once.

Policy

The rules live under Policy on the page, stored with your account:

Each computer's latest details are checked against the rules in the page. A computer that breaks one says so under its name (Not compliant: firewall off, system older than 16), and the count of computers that meet the policy sits next to Policy. A check that can't be made (FileVault on Linux) isn't failed, and a computer that hasn't reported yet isn't judged. Setting a rule changes nothing on any computer; to fix what it finds, use an action.

What can and can't happen

glassdesk.dev canStore each computer's latest details; store your policy; relay a signed command to a computer that's online.
glassdesk.dev can'tRun an action by itself, forge a command (it has no passkey), keep an action's result (it passes through to the page and isn't stored), or see a screen: opening a computer still takes that computer's own sign-in.
Someone who steals your signed-in browserCan see names, status and details, but can't run an action: each one needs your passkey, confirmed with your fingerprint, face or PIN. They could add a passkey of their own to the account, but a computer only takes commands from a passkey you pinned with a link printed on the computer itself.
The one moment of trustPinning happens on the page glassdesk.dev serves. After that, the website alone can't act.

Treat the glass fleet manage link like a password for 15 minutes: don't paste it into a shared chat or an agent's transcript.

Commands

glass fleet                      Is reporting on, and when was the last report?
glass fleet on | off             Start reporting; stop and delete what was sent
glass fleet report [--json]      Send a report now
glass fleet manage [--json]      Link to let your account run actions here (also turns reporting on)
glass fleet manage status        Passkeys that can run actions, and the latest actions
glass fleet manage off           Forget every passkey; stop all actions

Not included

If something's wrong

glass link takes options that limit what the device may do:

glass link --list shows the devices let in by links, each with an id; glass link --revoke <id> cuts off one. glass viewers shows who's connected now and glass kick [id] ends a session. glass log is the connection history: who, when, how, and for how long.

Using Glass

The toolbar (top right) groups its buttons: machines and displays, keyboard, sound, files, things for everyone connected (chat, drawing, recording), tools (terminal, ports), and the view (this device, fullscreen, the … menu, hide). It has:

Display previews. With two or more displays, a strip of small live previews of each one (and All) sits in the empty band below the picture whenever there's room; the one being shown is outlined, and tapping another switches to it. Without room it waits behind a small tab at the bottom. Hide it with its ⌄ button; that's remembered. Live previews of displays not being shown need macOS 14 or newer.

Touch gestures: tap = click, drag = drag, long-press = right-click, two fingers = scroll, pinch = zoom.

Trackpad mode (the trackpad button, in the keyboard group; on by default on phones): the screen works like a laptop trackpad. Drag to move the pointer (faster flicks go further), tap to click, two-finger tap to right-click, double-tap and hold (or press and hold) to drag, two fingers to scroll, pinch to zoom; when zoomed in, the view follows the pointer.

Keyboard and mouse mode (touch screens: ⋯ menu › Keyboard and mouse mode): for when another screen shows the computer, such as a car's browser or a TV, and this phone is only its trackpad and keyboard. The picture is paused and hidden here (the computer stops sending it, and this device never raises the picture's size for others), the whole screen is the trackpad, and the toolbar's keyboard types. Tap Show the screen to go back.

On a phone the toolbar folds each group into one button with a dropdown.

Apple Pencil and other styluses draw with pressure and tilt: the Mac sees a pen tablet, so Photoshop, Affinity, Krita and other drawing apps vary the stroke. Hovering (Pencil hover on newer iPads) moves the pointer without clicking.

More in the toolbar:

As an installed app (Home Screen, or Install Glass): long-press the icon for Chat, Machines, Send files and each of your other machines; share photos, files or text to Glass from other apps (Android, ChromeOS, desktop) to send them to the computer; open files with Glass on the desktop; web+glass://<machine> links open that machine. It opens even when the computer can't be reached, and says so. Only one tab of a browser shows a computer at a time; another tab asks before taking over.

Game controllers connected to the viewing device work on Linux hosts, and on Windows hosts with the free ViGEmBus driver installed, as a virtual Xbox 360 controller.

Local shortcuts (not sent to the Mac): Ctrl+Shift+F toggles fullscreen, Ctrl+Shift+H toggles the stats overlay.

A locked screen, or a closed lid

Type your password at the lock screen from the viewer, as you would at the computer. Keys pressed into a password field (the lock screen, a password prompt) aren't shown to other viewers or written to Glass's log: they see "a key, into a password field". Agents with a grant can't type into one at all; they ask you with request_help.

A laptop sleeps when its lid closes, and a sleeping computer can't be unlocked from anywhere. Turn on Stay awake with the lid closed (Glass app › Settings, or glass config lid-awake on) to keep it awake with the lid closed while it's plugged in. On battery it sleeps as usual, so it still sleeps closed in a bag. Keep a closed laptop that stays awake somewhere it can cool down.

Keyboard and ⌘ shortcuts on iPad

iPadOS reserves a few shortcuts before any app or web page sees them: ⌘Tab, ⌘Space, ⌘H, ⌘⇧3/4/5, and Globe-key combinations. Glass offers three ways around this:

These choices are remembered for each computer. Shortcut bar (⌘ menu) adds a row of Mac shortcuts above the screen on touch devices.

Everything else, including ⌘C, ⌘V, ⌘Q, ⌘W, and arrows, works directly from a hardware keyboard.

Clipboard

Sharp text

Turn on Displays › Sharp text when reading code or documents. The display streams at its native size with fewer but finer frames, in HEVC 4:2:2 colour where the Mac's encoder and the browser allow it, so coloured text keeps its edges. Once the screen stops changing, Glass sends a lossless full-colour (4:4:4) picture of it, so still text is pixel-exact; the next change resumes video. It's per viewer and remembered per computer. Elsewhere, glass config hevc on uses HEVC for everyone when every connected viewer can decode it.

Console

https://<computer>.<tailnet>.ts.net/admin/ (or Computer › Console in the viewer) is the owner's console, open to your own tailnet devices and the access token. It shows who's connected (and ends sessions), connection requests to allow or deny, one-time links with QR codes and limits, devices let in by links, connection history, settings, access rules, and an address book: your machines in groups you name, each opening in the viewer.

Teams: sign-in, access rules, posture

Single sign-on. Register Glass with any OpenID Connect provider (Google, Microsoft Entra ID, Okta, Auth0, Keycloak…) with redirect URL https://<computer>/sso/callback, then:

glass config oidc-issuer https://accounts.google.com
glass config oidc-client-id <id>
glass config oidc-client-secret <secret>

The viewer then offers Sign in with your organization instead of asking for a token.

LDAP. glass config ldap-url ldaps://dir.example.com (or ldap:// with StartTLS), then either ldap-user-dn uid={user},ou=people,dc=example,dc=com to bind directly, or ldap-base-dn plus optional ldap-bind-dn / ldap-bind-password to search for the user. Groups come from memberOf (ldap-group-attr to change). The viewer asks for a directory username and password.

Access rules. Who may sign in, and what they may do, first match wins:

glass acl add group:eng --view-only --for 8h
glass acl add @example.com
glass acl add ana@example.com --ask
glass acl                 # list
glass acl remove 0        # by position

A rule matches an email, @domain, group:name or *, and takes the same limits as glass link. With no rules, nobody signs in with a directory account. Rules live in ~/.config/glass/acl.json.

People on your tailnet. The rules apply to Tailscale too: someone else on the computer's tailnet (a member you invited, or a device you shared it with) whose Tailscale login a rule names connects without the token, as a guest with that rule's limits. glass config tailnet-members on lets everyone on the tailnet in that way (off by default; on a company tailnet that's everyone in it). Devices tagged in Tailscale belong to no one and never count.

SCIM. glass config scim-token new prints a token for SCIM 2.0 provisioning at https://<computer>/scim/v2 (Okta, Entra ID). Users and groups stay in sync; deactivated users can't sign in and lose their sessions at once.

Device posture. Checked on every connection:

Branding and self-hosting

glass config name "Studio" and glass config accent "#ff8800" change the name and colour shown in the viewer. To run remote access without glassdesk.dev, deploy the introducer and TURN relay from site/selfhost and point Glass at it with glass config relay https://glass.example.com.

CLI reference

glass               Run the host in the foreground (the background service runs this)
glass app           Open the Glass app (macOS); --install just adds Glass.app to ~/Applications
glass setup         Guided setup: Tailscale, background service, permissions, connect
glass setup --yes [--json]   Unattended setup for scripts and agents; reports what's left
glass status [--json]        Is the service running? Capturing? Permissions? Ready from anywhere? Connect URL
glass link [--for 24h]   One-time magic link (and QR code) for a device outside your tailnet
glass link --anywhere    The same, working from any network (WebRTC via glassdesk.dev)
glass link --view-only --no-files --no-clipboard --ask --passkey   Links with limits
glass link --list        Devices let in with links, with ids
glass link --revoke [id] Cut off one device, or every device let in with a magic link
glass viewers [--json]   Who's connected now
glass kick [id]          End one session, or every one
glass requests / allow [id] / deny [id]   Connection requests waiting for an answer
glass chat "…"           Message everyone viewing
glass notifications      Devices that get notifications (test, off <id>)
glass mic [install|uninstall]  Viewers' microphones here: status, set up, or remove the driver
glass support            Get help: a code for someone at glassdesk.dev/help (nothing stays afterwards)
glass privacy on|off     Blank this screen and block local input while viewed
glass log [-n 20] [--json]   Connection history
glass wake <name|mac>    Wake a machine with Wake-on-LAN
glass acl [add|remove]   Access rules for SSO and LDAP accounts
glass config [key [value]]   Settings (no arguments: list them all with descriptions)
glass remote on|off      Remote access from outside your tailnet (status without an argument)
glass account add        One-time link (and QR code) that puts this computer on your glassdesk.dev/computers account
glass account remove     Take this computer off every account
glass fleet [on|off|status|report]  Tell your account this computer's state; off deletes what was sent
glass fleet manage [off|status]  Let your account run actions here, each signed by your passkey (off forgets them)
glass token         Show the access token for devices outside your tailnet
glass token --reset Replace it with a new random token
glass token --set   Choose your own token (prompted; or piped: echo … | glass token --set)
glass mcp [--machine NAME]   MCP server letting an AI agent use this computer (or NAME on your tailnet)
glass agents [list|revoke ID|install CLIENT|log|verify|on|off|public on|off]  Agents from anywhere
glass feedback "…"  Send feedback to the developers
glass restart       Restart the background service (viewers reconnect by themselves)
glass uninstall     Stop the background service and remove it from login items
glass --version

Host options: --bind (repeatable, or comma-separated) sets the address for the web ports and WebTransport together. The default is 0.0.0.0 (every IPv4 address; WebTransport also accepts IPv6, as before). tailscale listens on this machine's Tailscale addresses and fails if Tailscale isn't running. For example --bind tailscale --bind 127.0.0.1, or --bind 127.0.0.1,100.64.0.2. The same list is saved with glass config bind and applies the next time Glass starts; a --bind flag overrides it. On macOS, port 443 needs the default bind (or 0.0.0.0): an unprivileged process can only bind a port below 1024 on the wildcard address, so a specific address falls back to the web port. --http-port (default 8080; if it's taken, the next free port up to 8099, on every chosen address), --https-port (default 443: also serve there when free, so URLs need no port; 0 turns it off), --wt-port (UDP, default 4433; likewise moves to the next free port, which browsers learn automatically), --fps (default 60), --mbps (default 30), --scale, --cert/--key (custom TLS), --token-file, --web-dir, --log-dir.

Files:

How it works

Linux host (beta)

The same one-liner installs Glass on Linux x86_64 and ARM64 (aarch64). The Linux host uses:

Dependencies: PipeWire, wl-clipboard and your desktop's screen-sharing portal (xdg-desktop-portal-hyprland, -gnome, -kde or -wlr). Setup detects pacman, apt, dnf or zypper and offers to install what's missing, e.g. on Arch / Omarchy: sudo pacman -S --needed pipewire xdg-desktop-portal-hyprland wl-clipboard; on Ubuntu: sudo apt-get install pipewire xdg-desktop-portal-gnome wl-clipboard. Tailscale: curl -fsSL https://tailscale.com/install.sh | sh, then sudo tailscale up.

Keys arrive as typed on Linux hosts: ⌘ on an Apple keyboard is Super. Paste from the viewer's clipboard sends Ctrl+V.

While the session is locked (logind's lock hint, or a locker such as hyprlock or swaylock running), keys aren't shown to viewers or logged. Stay awake with the lid closed works on Linux laptops too; see A locked screen, or a closed lid.

Windows host (beta)

On Windows 10 or 11 (x64 or Arm), run in PowerShell:

irm glassdesk.dev/install.ps1 | iex

It installs to %LOCALAPPDATA%\Programs\Glass for your user (no administrator needed), starts Glass at sign-in, and runs glass setup. For managed installs there's a per-machine MSI (msiexec /i glass-….msi /qn) and Group Policy settings; see the release notes. The Windows host uses:

To remove Glass, uninstall it in Settings › Apps › Installed apps: that takes away the programs, the start-at-sign-in entry, the Start menu shortcut, the firewall rule and the secure-desktop service (one UAC prompt), and keeps your settings in %APPDATA%\Glass. glass uninstall only stops Glass starting at sign-in.

Viewing from Linux or Windows (Omarchy included)

Open the Glass URL in Chromium, Chrome, or Firefox with Tailscale running. When the host is a Mac, PC keyboard mode (on by default for Linux and Windows browsers; toggle it in the ⌘ menu) translates PC conventions:

Hyprland keeps its own Super shortcuts. In fullscreen (Ctrl+Shift+F), Chromium's Keyboard Lock passes everything else through. If the browser has no hardware H.264 decoder, Glass uses software decoding automatically.

Security and privacy

Code signing policy

Glass's programs are signed in GitHub Actions (release.yml), built from this repository's source and nothing else: macOS builds with Glass's own key, Windows builds (glass.exe, glassw.exe and the MSI) with an Authenticode certificate. Only Glass's own code is signed, never third-party programs.

Windows signing is being set up through SignPath Foundation's free program for open-source projects. Until it's in place, the Windows downloads are unsigned: SmartScreen may warn before the MSI runs (More info › Run anyway), and a PC with Smart App Control turned on may block Glass. Each release's notes say whether its Windows builds are signed.

Free code signing provided by SignPath.io, certificate by SignPath Foundation.

Requirements

Troubleshooting

FAQ

Is Glass free? Yes, and open source under the MIT license: https://github.com/Ntarasiuk/glass

Do I need to install anything on the iPad? No, just a browser. Tailscale is optional: a one-time link from glass link --anywhere works without it.

Can I use it without Tailscale? Yes. glass link --anywhere makes a one-time link that connects any browser directly over WebRTC, end-to-end encrypted, with no open ports. On a tailnet, Glass uses WebTransport with a certificate Tailscale provides; advanced users can pass their own with --cert/--key.

How is it different from Chrome Remote Desktop? Chrome Remote Desktop uses a video-call pipeline tuned for smoothness. Glass is tuned for latency: on a tailnet it skips WebRTC entirely (UDP-style WebTransport datagrams, hardware decode straight to canvas, no jitter buffer), and from anywhere it uses WebRTC with the smallest jitter buffer the browser allows. Glass also streams multiple displays at once, transfers files, and recovers from iPad tab suspension automatically.

How is it different from Parsec, Moonlight, or Jump Desktop? Those need a native app on the viewing device. Glass runs in a browser, aims for similar latency, and is built for Mac and Linux hosts.

Does it work on Linux? Yes, as a viewer in any modern browser, and as a host on Wayland (beta).

Does it work on Windows? As a viewer, yes, in any modern browser. As a host, in beta: see Windows host.

Does it stream audio? Yes, the host's system audio, toggled per device.

Can I control a locked Mac? Yes; type your password at the lock screen. With Stay awake with the lid closed on, that works on a closed MacBook too, while it's plugged in. FileVault still requires one local login after a reboot.

Feedback