- Go 77.1%
- Shell 7%
- Makefile 5.9%
- JavaScript 5.5%
- CSS 3%
- Other 1.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| cmd/bazinga | ||
| deploy/systemd | ||
| docs/superpowers | ||
| internal | ||
| .gitignore | ||
| AGENTS.md | ||
| go.mod | ||
| go.sum | ||
| install.sh | ||
| LICENSE.md | ||
| Makefile | ||
| rcodesign-cert.p12 | ||
| README.md | ||
| screenshot.png | ||
| SECURITY.md | ||
| VERSION | ||
bazinga
A remote Steam account switcher for Linux gaming boxes using gamescope-session. Tested on Bazzite — should work on SteamOS too (eager for someone to try it). Lets family members switch the active Steam account remotely via CLI, GUI, or web UI, but only when no game is running.
Security warning: The HTTP API has no authentication and must not be exposed to the Internet. Forwarding port 8089 through a firewall or NAT lets anyone control your Steam session, add or remove accounts, and read your Steam usernames and Steam64 IDs. bazinga is designed for a trusted LAN only. See SECURITY.md for a full risk assessment.
How it works
A Go binary runs as a systemd user service on the Bazzite box, serving a REST API and embedded web UI. Switching an account uses Steam's CEF remote debugging interface (port 8080) to click the target user's tile on the login screen — this works in ~3-5 seconds without restarting Steam. Falls back to restarting the gamescope session if no login screen is visible.
Quick start
Install on Bazzite (recommended)
curl -fsSL https://git.sync.wtf/troed/bazinga/raw/branch/main/install.sh | bash
This downloads the latest binary, sets up the systemd user service, enables
linger (if sudo is available), and starts the server. The service listens on
:8089 (all interfaces).
To upgrade, just run the same command — it stops the old service, downloads the new binary, and restarts.
Build from source
make build # native binary
make build-all # cross-compile all platforms
make deploy HOST=<host> # dev deploy via SSH
Client setup
Open the web UI at http://<hostname>:8089/ and download the binary for your
platform. Put it on your PATH.
- GUI mode: run
bazinga(no arguments) — shows a window with connection status, account switching, pairing, and Wake-on-LAN. - CLI mode: run
bazinga <subcommand>— works headless for scripts.
The downloaded binary is pre-configured with the server's address and MAC. No environment variables needed — just run it.
macOS: first run
macOS Gatekeeper will block binaries from unidentified developers. After downloading the darwin binary:
xattr -d com.apple.quarantine bazinga-darwin-arm64
Or right-click the binary in Finder and select Open. This only needs to be done once per download — the binary is properly code-signed (self-signed certificate) and will not get silently killed by the kernel.
Usage
bazinga Launch the GUI (window with status, accounts, pair, WOL)
bazinga serve Start the HTTP server (run on Bazzite box)
bazinga status Show current user and game status
bazinga switch <account> Wake + wait + switch to account
bazinga pair <pin> Send a 4-digit Remote Play pairing PIN to Steam
bazinga wake Send wake-on-LAN magic packet
bazinga accounts List available Steam accounts
bazinga accounts add <steam_id> <account_name> <persona_name>
Add an account to the registry
bazinga accounts remove <account_name>
Remove an account from the registry
Run with no arguments for the GUI — otherwise CLI subcommands behave as before.
bazinga switch <account> is the all-in-one flow: it sends a WOL packet,
polls until the server comes online, checks no game is running, verifies
you're not already on the target account, issues the switch, and waits for
Steam to restart with the new user.
bazinga pair <pin> is used for initial Steam Remote Play pairing. When you
click "Connect" on your Remote Play client, it shows a 4-digit code. Run
bazinga pair 4821 with that code, and bazinga enters it into the host's
pairing dialog via CEF.
Web UI
Open http://<hostname>:8089/ in a browser. Shows the current user, game
status, and available accounts with switch buttons. Also has download links
for the client binary for each platform (served from /download/). Polls
/api/status every 10 seconds.
Configuration
| Variable | Default | Description |
|---|---|---|
STEAMBOX_HOST |
steambox.local:8089 |
Server address |
STEAMBOX_MAC |
— | MAC address for WOL (auto-discovered via SSH/ARP) |
STEAMBOX_SSH_USER |
bazzite |
SSH user for MAC discovery |
BAZINGA_BINARIES_DIR |
~/.local/share/bazinga/binaries |
Client binary downloads |
BAZINGA_STEAM_SESSION_SERVICE |
gamescope-session-plus@steam.service |
systemd user service for Steam session restart |
Game-running guard
The server rejects switch requests if a game process is detected. Detection
scans /proc for wineserver, proton, or .exe processes, excluding
known Steam helpers (steamwebhelper, steamservice.exe, steam.exe).
Native Linux games are detected by walking Steam's process tree for any process not in the known helper list.
Account registry
Bazinga maintains its own account list in ~/.config/bazinga/users.json because
Steam's native user switching can drop accounts from loginusers.vdf. This file
is the source of truth. Two-way sync with VDF:
- VDF → users.json: On every status poll, auto-detect new accounts and update persona_name
- users.json → VDF: Before each switch, inject any missing accounts so tiles appear on the login screen
First run bootstraps users.json from loginusers.vdf automatically.
Use bazinga accounts add and bazinga accounts remove to manage accounts
from the CLI, or the REST API (POST /api/accounts, DELETE /api/accounts/{name}).
SteamOS compatibility
Nearly everything works on SteamOS as well. The only difference is the session
service name used for the restart fallback. Set
BAZINGA_STEAM_SESSION_SERVICE to the SteamOS service name if needed.
Development
go test ./internal/... # run unit tests (VDF parser, no external deps)
Built for Go 1.26+. GUI uses gogpu/ui (WebGPU, CGO-free).
Creating a release
# Bump the version
echo "0.2.0" > VERSION
# Build + publish to the forge
make release FORGEJO_TOKEN=<api-token>
This cross-compiles all four platforms, creates a release on
git.sync.wtf, and uploads the binaries
as release artifacts. The token needs write:repository scope on the repo.
macOS binaries are signed with rcodesign
using a self-signed certificate (rcodesign-cert.p12). The rcodesign binary is
expected at tools/rcodesign — download it from the
apple-platform-rs releases
(x86_64-unknown-linux-musl).
License
This project is dedicated to the public domain under CC0 1.0 Universal. No attribution required — use it freely for any purpose.
