126 lines
6.8 KiB
Markdown
126 lines
6.8 KiB
Markdown
# 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 <name>` 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.
|