# tmux-party Share a live tmux session with your buddies on a wide range of UNICES! `tmux-party` ships `party`, a POSIX shell utility. One person hosts a party, and others join the fun! Wanna pair-program, mentor, debug an outage together, or demo a workflow? `ssh` in, `party join` & off you go! Built for small, mutually trusted groups: a hacklab, a tech team, a circle of friends, not strangers across the internet. Inspired by epic sessions running GNU's `screen -x` way back when, now on BSD's `tmux` modern codebase! ## Requirements - POSIX shell (`/bin/sh`) - `tmux` ≥ 3.3 (for `server-access`), running when you invoke the script - A shared system group (default name `party`, override via `TMUX_PARTY_GROUP`). Every host and guest must be a member. - `write(1)`, optional: used to ping invited guests. Silently skipped when absent. ## Install ```sh make install # installs to /usr/local make install PREFIX=$HOME/.local # or any prefix you prefer ``` Installs `party` to `$(PREFIX)/bin` and `party.1` to `$(PREFIX)/share/man/man1`; `man party` is the full reference. `make uninstall` removes both. On illumos/Solaris the default prefix is `/opt/party` and the install needs root (`pfexec make install`) for the system bindir and `/etc/default/login`. The Makefile is plain POSIX make (works with `/usr/bin/make`, BSD make, GNU make). ## Quick start One-time setup, as root. Create the group and add members: ```sh groupadd party usermod -aG party alice usermod -aG party bob # alice and bob log out and back in so the new group takes effect ``` Host a party, then invite from inside it: ```sh party host standup # spawn a dedicated party tmux server party invite alice # add alice to the allowlist (read/write) party invite bob -r # invite bob as a read-only watcher ``` Guests join: ```sh party list # see what's running on this host party join standup # attach (auto-attaches if only one party is running) party leave # detach and clean up ``` The `party` group is the partyline: filesystem access to party sockets is shared among members, and `tmux server-access` decides who is actually let into a given session. No shared install directory is needed: each party keeps its own state under its own per-party private directory. ## How it works `party host` spawns a *dedicated* tmux server for the party (separate from your personal tmux) so inviting someone exposes only the party, not your other sessions. Each party gets a private directory at `${PARTY_SOCKET_DIR}/party-${USER}:${PARTY_NAME}.d/`, holding the tmux socket and a join/leave notification helper. Guests never type the path; `party join` reads the roster and handles the attach. Two gates protect every party, and both must pass: - **Filesystem gate**: the per-party directory is `chgrp`'d to `TMUX_PARTY_GROUP` at mode `0750`; the socket is `g+rw`. Non-members can't traverse in or reach the socket. - **Auth gate**: `tmux server-access` allowlist, editable only by the host. A user who clears the FS gate but isn't on the allowlist is rejected at the protocol layer. Party metadata (host, server pid, group, creation time) lives in a `roster` file beside the socket. It's bookkeeping only, as security-relevant fields (host user, socket path) are re-derived from the directory on every read, never trusted from the file. ## Configuration | Variable | Default | Purpose | |---|---|---| | `TMUX_PARTY_GROUP` | `party` | Shared group for socket access. Override to reuse an existing group (`wheel`, `users`, `staff`), or pass `--group ` to `party host`. | | `PARTY_SOCKET_DIR` | `/tmp` | Where each party's private directory (socket + roster) is created. | | `PARTY_TMUX` | `tmux` | tmux binary to use. Override if tmux ≥ 3.3 lives at a non-standard path. | ## Support The mechanism is identical everywhere: group ownership and mode bits plus `tmux server-access`. No ACL syscalls involved, so the trust path is one piece of code, not a per-OS matrix. | Platform | Status | |---|---| | Linux | supported, validated on Debian 13 & Alpine v3.21 | | FreeBSD UFS or ZFS | supported, validated on FreeBSD 15.0 ZFS | | illumos LX-branded zones | supported, validated on 4.4 BrandZ linux | | illumos native, Solaris | supported, validated on omnios-r151058 | | NetBSD, DragonFly | unconfirmed, should work, tests welcome | | OpenBSD | supported, validated on OpenBSD 7.8 | | macOS | supported, validated on Darwin 25.5.0 | ## Security `party` assumes you already know and trust everyone you add to the group; it is not a public access-control system. Both gates above protect each party, and the **auth gate** (`tmux server-access`) is authoritative, with the filesystem gate as defense in depth. Three honest caveats, with the full detail in `man party`: - On ACL-enabled filesystems (ZFS, HFS+/APFS), inherited ACLs can override the mode bits, so the FS gate is best-effort. The auth gate still holds. - A party's *existence* is not hidden the way *attaching* is. That confidentiality rides on the FS gate. - Active guests share one tmux server, where any write-capable invitee is trusted by design. Invite read-only (`-r`) if you do not trust that far. ## Status `party` is pre-release. The on-disk layout (per-party directory, roster format, socket path) may change between commits, with no upgrade migration, so close running parties before pulling. A stale roster pointing at an unreadable socket simply won't be discovered; old tmux servers left running must be killed by hand. ## Reference | Subcommand | Effect | |---|---| | `party host [name]` | Spawn a dedicated party tmux server. Only the host is on the allowlist. | | `party invite alice [-r]` | Add alice to the allowlist. `-r` / `--read-only` invites as a watcher. | | `party voice alice` | Promote alice to read/write. | | `party mute alice` | Demote alice to read-only. | | `party kick alice` | Revoke alice's invite, disconnect her, kill her guest session. | | `party detach alice` | Disconnect alice; keep her on the allowlist. | | `party list` | List live parties on this host. | | `party who [--short]` | Show invited and attached users for the current party. | | `party status` | Show the caller's own state: hosting, attached, or idle. | | `party close` | Tear down the party server and its roster entry. Host-only. | | `party join [name] [--passive]` | Join a party. Auto-attaches when one is running; picker otherwise. `--passive` attaches read-only to the host's view (watcher mode). | | `party leave` | Detach and clean up the per-guest session. | | `party role [active\|passive\|switch]` | Flip your clients between guest and host session. No arg prints the current role. | | `party --help` | Help text. | ## Credits Written by veg and kol3rby in the context of the [UNIX Social Club](https://club.unix.rocks/). Issues and contributions welcome.