Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
<div align="center">

<img src="BossTerm.png" alt="BossTerm" width="140">

# BossTerm

**A blazing-fast terminal you can embed, share to any device, and hand to your AI.**

[![CI](https://github.com/kshivang/BossTerm/actions/workflows/test.yml/badge.svg)](https://github.com/kshivang/BossTerm/actions/workflows/test.yml)
[![Release](https://github.com/kshivang/BossTerm/actions/workflows/release.yml/badge.svg)](https://github.com/kshivang/BossTerm/releases)
[![Download DMG](https://img.shields.io/github/v/release/kshivang/BossTerm?label=Download%20DMG&logo=apple)](https://github.com/kshivang/BossTerm/releases/latest)
[![Maven Central](https://img.shields.io/maven-central/v/com.risaboss/bossterm-core)](https://central.sonatype.com/namespace/com.risaboss)

A modern terminal emulator built with **Kotlin** and **Compose Desktop**.
</div>

BossTerm is a high-performance terminal emulator designed for developers who want a fast, customizable, and feature-rich terminal experience on macOS, Linux, and Windows.
| ⚡ [**Fast**](#performance) | 📱 [**Share**](#session-sharing) | 🤖 [**MCP for AI**](#bossterm-mcp) | 🧩 [**Embeddable**](#embedding-in-your-app) |
|:--:|:--:|:--:|:--:|
| 1,645 MB/s — edges out Alacritty | Watch & control from any device | Expose tabs to Claude Code & co. | Drop it into your Compose app |

A modern terminal emulator built with **Kotlin** and **Compose Desktop** — high-performance, deeply customizable, and feature-rich on macOS, Linux, and Windows.

## Performance

Expand Down Expand Up @@ -206,6 +216,10 @@ cd BossTerm
- **Debug Tools** - Built-in terminal debugging with Ctrl+Shift+D
- **Welcome Wizard** - First-time setup wizard for shell, tools, and AI assistants
- **Customizable** - JSON-based settings at `~/.bossterm/settings.json`
- **Session Sharing** - Watch or control a tab / window / all windows from any device — self-hosted, with a QR code and a mobile-friendly web viewer (LAN, Tailscale, or a zero-config Cloudflare tunnel)
- **Remote Control** - End-to-end encrypted; viewers get typing access on approval, or connect from another BossTerm as a native remote client
- **AI / MCP Server** - Built-in [Model Context Protocol](https://modelcontextprotocol.io) server exposes your terminals to Claude Code, Codex, Gemini CLI, and OpenCode
- **Embeddable** - Drop the terminal into your own Kotlin/Compose Desktop app as a library (`com.risaboss:bossterm-compose`)

## Keyboard Shortcuts

Expand Down Expand Up @@ -455,6 +469,35 @@ fun MyApp() {
}
```

## Session Sharing

Watch — or hand over — a live terminal to any device, with **no cloud relay and no account**.
BossTerm runs the share server itself; viewers open a link (or scan a QR code) in any browser, or
connect from another BossTerm as a native client.

- **Scope**: share a single **tab** (with its splits), a whole **window**, or **all windows**
(viewers see tabs grouped by window).
- **View or Control**: hand out a read-only **view** link or a **control** link (typing access).
View-only viewers can request control mid-session and you approve from a prompt — required for
public links by default, skipped on the LAN.
- **Reach**: LAN out of the box, or a public URL via **Tailscale** (Serve/Funnel) or a zero-config
**Cloudflare** quick tunnel (the default — `cloudflared` is fetched automatically, no account).
The tunnel is pre-warmed so the QR is ready the moment you hit Share.
- **Mobile web viewer**: xterm.js-based and touch-tuned — soft-keyboard push, an on-screen key bar
(Esc / Tab / Ctrl / arrows + a ⌨ toggle), pinch-zoom, fit-to-screen, and clickable links.
- **Native remote client**: "Add remote" in BossTerm to mirror another machine's shared tabs into
your own window — including its **Remote MCP** — with control relayed up the chain.
- **End-to-end encrypted**: the session key rides in the URL **fragment** (`#k=…`), which browsers
never send to the server — so even a tunnel relay can't read your session. Frames use
per-connection AES-256-GCM, and a short verification code lets both ends confirm the same key.

Enable it under **Settings → Session Sharing** (off by default), then **Share** from a tab's menu.
Defaults: binds the LAN on port `7677`, Cloudflare remote mode, approval required only for public
links.

See **[docs/session-sharing.md](docs/session-sharing.md)** for the full guide — scopes,
remote-access setup, the viewer, the native client, the encryption design, and every setting.

## BossTerm MCP

BossTerm ships an in-process [Model Context Protocol](https://modelcontextprotocol.io)
Expand All @@ -471,6 +514,9 @@ code (`run_command` — recommended default shell for AI clients).
`Host` headers (DNS-rebinding defense). Any local process running as your
user can reach it while it is enabled.
- **Opt-in**: disabled by default. Toggle on under Settings → BossTerm MCP.
- **Remote MCP**: when you [share a session](#session-sharing), the host's MCP can be driven from
the web viewer (an "MCP pill" toggles it and attaches CLIs) or from a native remote client —
calls on shared tabs are relayed to the host.

### Turning it on (as a user)

Expand Down Expand Up @@ -599,6 +645,7 @@ Run `man bossterm` after installation for the complete reference.

- [Embedding Guide](docs/embedding.md) - Embed a single terminal with custom context menus
- [Tabbed Terminal Guide](docs/tabbed-terminal.md) - Full-featured tabbed terminal with splits
- [Session Sharing](docs/session-sharing.md) - Watch & control a terminal from any device (web viewer, QR, tunnels, E2E)
- [BossTerm MCP Server](docs/mcp-server.md) - Expose tabs to MCP clients (Claude Code, Codex, Gemini, OpenCode)
- [BossTerm CLI](docs/bossterm.1) - `man bossterm` reference (troff)
- [Onboarding Wizard](docs/onboarding.md) - First-time setup wizard for users
Expand Down
16 changes: 16 additions & 0 deletions docs/mcp-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,22 @@ under the button. **Codex caveat**: registration succeeds with codex-cli 0.130,
but Codex currently speaks streamable HTTP only, so the runtime connection
will fail against the SSE endpoint until BossTerm's MCP SDK is upgraded.

## Remote MCP (over a shared session)

The MCP server is loopback-only, but [session sharing](session-sharing.md) carries it to remote
devices. When a window with MCP enabled is shared:

- The web viewer shows an **MCP pill** that mirrors the host's MCP state; from it a viewer can
toggle the server and attach AI CLIs — the operations execute on the **host**, not the viewer.
- MCP tool calls against shared tabs are **relayed to the host's** MCP server, using the host's
configured `serverName` and bound port.
- A native "Add remote" BossTerm client surfaces the same control as **Remote MCP** in the remote
tab group.

This lets a phone or a second machine drive the host's terminals through an AI client over the
shared session, without exposing the loopback endpoint directly. See
[docs/session-sharing.md](session-sharing.md#remote-mcp) for the sharing side.

## Using as Claude Code's default shell

> **Opt-in.** `run_command` is exposed by default, but the agent only uses it
Expand Down
191 changes: 191 additions & 0 deletions docs/session-sharing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Session Sharing

BossTerm can share a live terminal with another device — to **watch** it, or to **control** it —
without any cloud relay or account. Your machine *is* the server: BossTerm runs a small embedded
web server, serves an [xterm.js](https://xtermjs.org)-based viewer over a WebSocket, and other
devices reach it over your LAN or through a tunnel. The session key never leaves the URL fragment,
so even a public tunnel relay can't read your session.

> Session sharing is **off by default**. Turn it on under **Settings → Session Sharing**, then
> use **Share** from a tab's menu.

---

## Table of contents

- [What you can share (scopes)](#what-you-can-share-scopes)
- [View vs. control](#view-vs-control)
- [Reach: LAN, Tailscale, Cloudflare](#reach-lan-tailscale-cloudflare)
- [Starting a share](#starting-a-share)
- [The web viewer](#the-web-viewer)
- [The native "Add remote" client](#the-native-add-remote-client)
- [Remote MCP](#remote-mcp)
- [Security & end-to-end encryption](#security--end-to-end-encryption)
- [Settings reference](#settings-reference)
- [Troubleshooting](#troubleshooting)

---

## What you can share (scopes)

Pick a scope in the Share dialog — you can switch it live:

| Scope | Shares | Notes |
|-------|--------|-------|
| **Tab** | The selected tab and its splits | The default. |
| **Window** | Every tab of the window that owns the tab | Reacts to tabs opening/closing; viewers switch tabs themselves. |
| **All windows** | Every tab of every BossTerm window | Reacts to windows opening/closing; the viewer groups tabs by window. |

Splits are preserved: a viewer sees the same pane layout, and on a phone the splits collapse into
swipeable sub-tabs.

## View vs. control

Each share produces **two links** (and two QR codes):

- **View** — read-only. The viewer sees output but can't type.
- **Control** — typing access: input, opening/closing tabs and splits, launching AI assistants,
renaming, etc.

A view-only viewer can **request control** mid-session; you get an approval prompt and can grant or
deny. Whether *connecting* needs approval at all is governed by
[`sessionSharingApprovalScope`](#settings-reference):

- `funnel` (default) — approval is required only for **public** links (a Cloudflare/Tailscale
Funnel tunnel or a custom public URL); LAN/loopback is trusted and connects without a prompt.
- `all` — always require approval.
- `off` — never prompt.

When you approve a device it receives a rolling 24-hour access key, so reconnects from the same
device skip the prompt. Granting control to a view-only viewer is remembered the same way.

## Reach: LAN, Tailscale, Cloudflare

How the viewer URL is produced is set by **`shareTailscaleMode`** (Settings → Session Sharing →
Remote Access, also switchable live in the Share dialog):

| Mode | Reach | URL | Needs |
|------|-------|-----|-------|
| `off` | Your local network | `http://<lan-ip>:7677/…` | Nothing — works out of the box |
| `serve` | Your Tailscale tailnet | `https://<host>.ts.net/…` | Tailscale + MagicDNS/HTTPS |
| `funnel` | Public internet | `https://<host>.ts.net/…` | Tailscale Funnel enabled |
| `cloudflare` | Public internet | `https://<random>.trycloudflare.com/…` | **Nothing — the default** |

**Cloudflare** is the default: BossTerm downloads `cloudflared` for you on first use (no account, no
config) and opens a quick tunnel. Each session gets a fresh random hostname. To make the QR appear
instantly, the tunnel is **pre-warmed** at startup (when sharing is enabled with a remote provider)
and **kept warm** across re-shares — so the verified public URL is already published by the time you
open the Share dialog. Disabling sharing, switching the mode to `off`, or quitting tears the tunnel
down.

If you front the server with your own reverse proxy, set
[`sessionSharingPublicUrl`](#settings-reference) and that URL is advertised instead.

## Starting a share

1. Enable sharing once: **Settings → Session Sharing → Enable**.
2. Right-click a tab (or use the Tab menu) → **Share tab / Share window / Share all windows**.
3. The Share dialog opens with:
- an editable **session name** (defaults to `you_your-machine`),
- the **QR code** with a **View / Control** toggle and copyable links,
- the **scope** picker (Tab / Window / All windows),
- the **remote-access** mode and its status.
4. Scan the QR or send the link. On another device it opens the [web viewer](#the-web-viewer); in
another BossTerm it can be dialed with [Add remote](#the-native-add-remote-client).

A small indicator in the tab bar shows while you're sharing (toggle with
`sessionSharingShowIndicator`).

## The web viewer

The viewer is plain xterm.js served from the share server — it runs in any modern browser
(Chrome, Safari, Firefox, Edge; iOS and Android included) with nothing to install. It's tuned for
phones:

- **Soft keyboard** — the view lifts so the cursor stays visible above the keyboard, and the
keyboard stays up while a TUI streams output.
- **On-screen key bar** — Esc, Tab, Enter, Ctrl combos and arrows, plus a **⌨ toggle** to show/hide
the soft keyboard.
- **Touch** — drag to scroll (including inside mouse-reporting TUIs), pinch to zoom, and a
fit-to-screen mode so the whole grid fits without horizontal panning.
- **Links** — URLs are clickable; text selection works by touch.
- **Tabs & splits** — switch tabs and panes from chips; drag split dividers to resize (with
control).
- **Status** — a presence badge (viewer count), the terminal size, an end-to-end verification code,
and an **MCP pill** (see [Remote MCP](#remote-mcp)).

## The native "Add remote" client

Another BossTerm can connect to a share as a first-class client instead of a browser:

- **Add remote** → paste a share link. The host's shared tabs mirror into your window as remote
tabs, grouped by window when the host shared "all windows" (e.g. `Window 2 › Tab 3 (via host)`).
- Control requests relay **up the chain**: viewer → host → the host's own upstream, so you can steer
a session two hops away (each host approves in turn).
- A client refuses to add a link that points back at its own shares (no mirror loops).

## Remote MCP

If the host has the [BossTerm MCP server](mcp-server.md) running, sharing carries it along:

- The viewer shows an **MCP pill** reflecting the host's MCP state; from it you can toggle the
server and attach AI CLIs — the actions run on the host.
- MCP tool calls against shared tabs are **relayed to the host's** MCP server, using the host's
configured server name and port.

This lets a phone or a second machine point an AI client at the host's terminals through the same
shared session.

## Security & end-to-end encryption

- **The key never reaches the server.** The per-share session secret (32 random bytes) is placed in
the URL **fragment** — `…/?t=<token>#k=<secret>`. Browsers never transmit the part after `#`, so
no server or tunnel relay (Cloudflare, Tailscale) ever sees it.
- **Per-connection keys.** Client and host exchange random salts (in the clear — useless on their
own) and derive a fresh AES-256-GCM key with HKDF-SHA256. Every frame is encrypted; a direction
byte is mixed in as additional data so frames can't be reflected back.
- **Verification code.** The Share dialog and the viewer each show a short code (the first 4 bytes
of `SHA-256(secret)`, as 8 hex digits). If they match, both ends hold the same untampered key.
- **Tokens.** View and control are **separate bearer tokens**, so you can hand out read-only access
without exposing control, and revoke one role independently of the key.
- **Trusted hosts.** Loopback and private addresses (`127.0.0.1`, `10.*`, `192.168.*`,
`172.16–31.*`, `169.254.*`, `*.local`, `*.ts.net`) are treated as private. Plaintext links are
allowed only there; any `https`/tunnel link is end-to-end encrypted. An old plaintext-only client
connecting to a public tunnel is rejected with an "update BossTerm" message.

## Settings reference

All under **Settings → Session Sharing**, persisted in `~/.bossterm/settings.json`:

| Setting | Default | Meaning |
|---------|---------|---------|
| `sessionSharingEnabled` | `false` | Master switch. Off ⇒ sharing isn't offered and any tunnel is torn down. |
| `sessionSharingPort` | `7677` | TCP port for the share server. If busy, it tries the next free port. |
| `sessionSharingBind` | `"lan"` | `"lan"` (bind `0.0.0.0`), `"loopback"` (`127.0.0.1` only), or `"custom"`. |
| `sessionSharingBindHost` | `""` | Host to bind when `sessionSharingBind` is `"custom"` (blank ⇒ `127.0.0.1`). |
| `shareTailscaleMode` | `"cloudflare"` | Remote-access provider: `"off"`, `"serve"`, `"funnel"`, `"cloudflare"`. |
| `sessionSharingPublicUrl` | `""` | Advertise this URL instead of the bound/tunnel URL (for a custom proxy). |
| `sessionSharingApprovalScope` | `"funnel"` | Require join approval: `"all"`, `"off"`, or `"funnel"` (only for public links). |
| `sessionSharingShowIndicator` | `true` | Show the sharing indicator in the tab bar. |

> Note `shareTailscaleMode` defaults to `cloudflare`, but sharing is still gated by
> `sessionSharingEnabled` (off by default) — so no tunnel opens until you turn sharing on.

## Troubleshooting

- **QR/link opens "tunnel error" or a blank page** — give the Cloudflare tunnel a moment on the
very first share (it downloads `cloudflared` once). Use **Refresh link** in the dialog to spin a
fresh tunnel. Quick-tunnel hostnames are ephemeral; a new one is minted each session.
- **Viewer says "Forbidden"** — the link is pointing at the wrong local service. Re-open the Share
dialog and use its current link/QR (it always reflects the live tunnel).
- **Can't connect on the LAN** — confirm both devices are on the same network and your firewall
allows inbound on `sessionSharingPort` (7677). Check `sessionSharingBind` is `"lan"`, not
`"loopback"`.
- **Tailscale modes do nothing** — ensure `tailscale` is installed and signed in; Funnel needs to be
enabled for the node, and Serve needs MagicDNS/HTTPS certificates.
- **Verification codes differ** — do **not** trust the session; the relay or link may be tampered.
Regenerate the link.
- **Phone keyboard hides the input in a TUI** — tap the **⌨** key-bar button to toggle the keyboard;
the view re-aligns the cursor above it.

See also: [BossTerm MCP Server](mcp-server.md) · [Troubleshooting](troubleshooting.md).
15 changes: 15 additions & 0 deletions docs/wiki/Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ BossTerm is packed with features for modern terminal workflows.

---

## Sharing & AI

| Feature | Description |
|---------|-------------|
| **Session Sharing** | Watch or control a tab / window / all windows from any device — self-hosted, no cloud relay |
| **Web Viewer** | Mobile-friendly xterm.js viewer over LAN, Tailscale, or a zero-config Cloudflare tunnel, with a QR code |
| **Remote Control** | View-only or full typing access on approval; connect from another BossTerm as a native client |
| **End-to-End Encryption** | Per-connection AES-256-GCM; the key rides the URL fragment and never reaches the relay |
| **BossTerm MCP** | Built-in Model Context Protocol server exposes tabs to Claude Code, Codex, Gemini, OpenCode |
| **Remote MCP** | Drive the host's MCP from a shared web viewer or native remote client |

See [[Session-Sharing]] and [[MCP-Server]] for details.

---

## See Also

- [[Keyboard-Shortcuts]] - Full shortcut reference
Expand Down
1 change: 1 addition & 0 deletions docs/wiki/Home.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Welcome to the **BossTerm** wiki! BossTerm is a modern, high-performance termina
| [[Configuration]] | Settings and customization options |
| [[Keyboard-Shortcuts]] | Full keyboard shortcut reference |
| [[Shell-Integration]] | OSC 7 and OSC 133 shell setup |
| [[Session-Sharing]] | Watch & control a terminal from any device (web viewer, QR, tunnels, E2E) |

---

Expand Down
10 changes: 10 additions & 0 deletions docs/wiki/MCP-Server.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,16 @@ upgraded.

---

## Remote MCP (over a shared session)

The MCP server is loopback-only, but [[Session Sharing|Session-Sharing]] carries it to remote
devices. When a window with MCP enabled is shared, the web viewer shows an **MCP pill** that
mirrors and toggles the host's MCP (and attaches AI CLIs, executed on the host), and MCP tool
calls against shared tabs are **relayed to the host's** server using its configured name and port.
A native "Add remote" BossTerm client surfaces the same control as **Remote MCP**.

---

## Settings reference

All MCP-related fields are persisted to `~/.bossterm/settings.json`.
Expand Down
Loading
Loading