Play chess in your terminal over SSH. No account, no browser, no install, just:
ssh chessh.org
cheSSH is an SSH server that drops you into a chess game instead of a shell. It's built with Go using Wish (SSH server), Bubble Tea (TUI framework), and Lip Gloss (styling). Game rules are handled by notnil/chess.
When you connect, you land in a lobby where you can host or join a game. Hosting gives you a 6-character room code to share. Once both players are in, the match starts. White for the host, Black for the joiner. Moves sync in real-time over SSH channels, and there's an in-game chat.
SSH connection
└─ Wish server (main.go)
└─ Bubble Tea TUI per session
├─ Screens: Menu -> Nicname -> Join/Host -> Play
├─ Game engine (internal/game/)
│ └─ notnil/chess wrapper - move validation, check, promotion
└─ Multiplayer manager (internal/multiplayer/)
├─ Room registry - create/join/leave by code
├─ Room state - White/Black players, turn tracking
└─ Event broadcast — moves, chat, disconnects via Go channels
Each SSH session gets its own Bubble Tea model. The multiplayer manager is a shared singleton that coordinates rooms across sessions. Rooms are ephemeral - they exist only while players are connected.
- No persistence. Games vanish on disconnect. Adding a storage layer (SQLite, Redis) would enable reconnection, game history, and ELO tracking.
- Single-process, in-memory rooms. The room manager uses Go maps + mutexes. This works for one server but doesn't scale horizontally. A pub/sub backend (Redis, NATS) would allow multiple server instances.
- No spectators. The room model is hardcoded for two players. The event broadcast system already uses channels, so adding read-only subscribers would be straightforward.
- No matchmaking. Players must share room codes out-of-band. A queue-based matchmaker could pair strangers automatically.
- No time controls. There's no clock - games can stall indefinitely. Adding per-move or per-game timers would complete the competitive experience.
In-game:
| Action | Keys |
|---|---|
| Move cursor | Arrow keys / h j k l |
| Select / place piece | Enter / Space |
| Cancel selection | Esc |
| Promote to Q/R/B/N | q r b n or arrows + Enter |
| Toggle chat | Tab |
| Quit | q / Ctrl+C |
Mouse is also supported - click to select and move pieces.
In the lobby: arrow keys or j/k to navigate, Enter to confirm.
go run .Then in another terminal:
ssh localhost -p 23234Environment variables:
| Variable | Default | Description |
|---|---|---|
CHESSH_HOST |
localhost |
Bind address |
CHESSH_PORT |
23234 |
Listen port |
CHESSH_HOST_KEY_PATH |
.ssh/id_ed25519 |
SSH host key path |
See deploy/chessh.service for a production systemd unit. The short version:
- Build:
go build -o chessh . - Create a service user:
useradd --system --home /opt/chessh --shell /usr/sbin/nologin chessh - Generate an SSH host key:
install -d -m 755 /etc/chessh ssh-keygen -t ed25519 -f /etc/chessh/host_key -N '' chown -R chessh:chessh /opt/chessh /etc/chessh - Install the binary and service file, then:
systemctl enable --now chessh
To let players connect on port 22, move your admin SSH to another port first.
- Go 1.25+
- An SSH client
