Term Chess is an SSH-native terminal chess server built in Go. Players connect over SSH, land directly inside a Bubble Tea interface, create time-controlled multiplayer games, or play untimed bot matches backed by elo-based-rec.
termchess.mp4
- SSH-hosted terminal UI built with
Wish+Bubble Tea - Fingerprint-based player identity with auto-assigned pet names
- Multiplayer chess with 1, 3, and 5 minute time controls
- Live clock updates and time-forfeit handling
- Bot games against
elo-based-rec - Postgres-backed player and game history storage
Term Chess is operated by Bind Ashutosh Parasnath as an individual side project. See LEGAL.md or the canonical site pages:
SSH client
|
v
Wish SSH server
|
v
Bubble Tea program per session
|
+--> UI model / page routing
|
+--> SessionManager -> active Tea programs by fingerprint
+--> GameManager -> live multiplayer state in memory
+--> ClockManager -> periodic clock ticks + time forfeits
+--> BotGameManager -> live bot games in memory
+--> DataManager -> Postgres via GORM
+--> BotAPIManager -> external HTTP chess engine service
The system is structured around one Bubble Tea model per SSH session. Each connected user gets an isolated UI state machine, while shared managers coordinate cross-session behavior such as multiplayer games and live clocks.
That split is the core architectural idea in this project:
- Session-local state lives inside the Bubble Tea model: active page, selected squares, inputs, notices, table contents, and current view state.
- Shared live domain state lives in manager types: active players, in-progress games, bot games, and session program references.
- Durable state lives in Postgres: player profiles, completed multiplayer games, and completed bot games.
This creates a clean boundary between presentation state, process-local domain state, and persisted history.
The main package owns transport and UI orchestration: it starts the SSH server, creates the shared managers, creates one Bubble Tea program per session, and routes messages into page-specific update functions.
SessionManager maps player fingerprints to active Bubble Tea programs so the server can push opponent, clock, and forfeit updates into the right sessions.
GameManager owns human-vs-human games: player registration, game creation and joining, move validation through notnil/chess, turn enforcement, clock state, and building persistence records when a game ends.
ClockManager runs a periodic tick loop, pushes live time updates into player sessions, detects expired clocks, and finalizes time-forfeit results.
BotGameManager owns the human-vs-bot flow separately from multiplayer, which keeps bot-specific rules such as single-player state, no clocks, and engine-driven moves out of the main game path.
DataManager is the persistence boundary. It connects to Postgres through GORM and handles player profiles plus completed multiplayer and bot game history.
BotAPIManager is a thin HTTP client for the external elo-based-rec service. It sends FEN + level, receives a UCI move, and keeps engine concerns outside the main application process.
- A user connects over SSH and gets a Bubble Tea session.
- The server identifies the player by SSH public key fingerprint.
- The player profile is loaded from Postgres or auto-created with a deterministic pet name on first use.
- The player creates or joins a live in-memory game.
- Moves are validated through
notnil/chess. - Opponent sessions receive update messages through
SessionManager. ClockManageremits clock updates while the game is active.- When the game ends, a record is persisted and the in-memory game is removed.
- A user starts a bot game with a selected color and difficulty.
BotGameManagercreates an in-memory game.- Player moves are applied locally.
- The current FEN is sent to the bot API.
- The returned move is validated and applied.
- Finished games are persisted and removed from live memory.
- Go
Wishfor SSH app hostingBubble Tea,Bubbles, andLip Glossfor the terminal UInotnil/chessfor chess rules and move validation- Postgres + GORM for persistence
elo-based-recfor engine-backed bot play- Docker / Docker Compose for local infrastructure
- Go
1.25+ - Docker and Docker Compose
- The
elo-based-recservice available atBOT_API_URLfor bot games
-
Start the stack:
docker compose up --build
-
Connect to the app:
ssh localhost -p 23234
This starts:
- Postgres on
localhost:5432 - the SSH chess server on
localhost:23234
-
Create an env file from the example and provide a working Postgres instance.
-
Start Postgres separately.
-
Run the server:
go run . -
Connect over SSH:
ssh localhost -p 23234
Example values are provided in .env.example.
TERN_CHESS_ENVdevelopmentbinds SSH to127.0.0.1productionbinds SSH to0.0.0.0
DB_URL- Postgres connection string
BOT_API_URL- base URL for the
elo-based-recservice (must exposeGET /healthbefore the bot page loads)
- base URL for the
DEBUG- when set, message traffic is dumped to
messages.log
- when set, message traffic is dumped to
.
├── main.go # SSH server bootstrap and top-level Bubble Tea model
├── intro.go # profile loading and historical game list
├── game.go # multiplayer game UI and board interaction
├── bot.go # bot game UI and engine-driven play
├── menu.go # page selection UI
├── session.go # active session registry
├── managers/
│ ├── game.go # multiplayer domain logic
│ ├── clock.go # live clock updates and forfeits
│ ├── bot_game.go # bot game domain logic
│ ├── bot_api.go # external engine client
│ └── data.go # Postgres persistence
├── common/
│ └── datamodel.go # persistent models
├── compose.yaml # local stack
└── Dockerfile # container build