Skip to main content

tuimanji

PyPI Python License: LGPL v3 CI

A pubnix-local turn-based multiplayer TUI. No server. No accounts. Just log in to the same box as your friend and play something.

Tuimanji bundles ten turn-based games — Tic-Tac-Toe, Connect 4, Reversi, Chess, Checkers, Battleship, Crazy Eights, Peg Solitaire, the Royal Game of Ur, and Mastermind — behind a single Textual terminal UI. Matches live in a shared SQLite database; clients coordinate via file locks and append-only writes. It's designed for pubnix boxes, shared servers, and old-school SSH shenanigans.

Why no server?

Because everything you need to synchronize turn-based games is already on the box: a filesystem, a SQLite binary, and flock(2). Running a daemon to marshal moves would be more infrastructure to break. Instead:

  • State lives in tuimanji.db — one file under $TUIMANJI_DB, WAL mode, PRAGMA busy_timeout=5000.
  • Writes are append-only. Each turn is a new row; nothing is ever updated. Replay, spectating, and crash-resume fall out for free.
  • Concurrency is layered. The app checks "is it your turn?"; SQLite's BEGIN IMMEDIATE serializes writers; a (match_id, turn) unique constraint catches anything that slips through.
  • Identity is a session slot. flocking $TUIMANJI_DB/.sessions/<user>/N.lock lets two terminals for the same unix user claim distinct player ids (user, user#2, …) — great for local testing, still sane for shared hosts.

Install

# one-shot run
uv tool run tuimanji

# persistent install
uv tool install tuimanji
# or
pipx install tuimanji
# or
pip install --user tuimanji

Requires Python 3.13+ and a terminal that speaks 256 colors.

Run

tuimanji                # open the lobby
tuimanji new chess      # create a new match + jump to its waiting room
tuimanji join a1b2c3d4  # join (or rejoin) an existing match
tuimanji resume         # open your most recent unfinished match
tuimanji games          # list available games
tuimanji where          # print the resolved database directory
tuimanji --version

The shared database defaults to /var/games/tuimanji/. On a machine where you don't own that path, override it:

export TUIMANJI_DB=~/.local/share/tuimanji
# or per-command
tuimanji --db ~/.local/share/tuimanji

Everyone playing against each other has to point at the same directory.

Pubnix / shared host setup

For multiple users to share /var/games/tuimanji/, the directory needs to be writable by all of them. The easiest way is to mark it sticky + world-writable, the same way /tmp is, once at install time (as root):

sudo install -d -m 1777 /var/games/tuimanji

When tuimanji sees the data dir set up that way, it propagates the same intent to everything it creates inside: .sessions/ becomes 1777 so every user can mkdir their own subdir, and tuimanji.db plus its WAL sidecars get 0o666 so writes from any user succeed. If the data dir isn't sticky+world-writable, tuimanji leaves permissions alone — your personal ~/.local/share/tuimanji stays private.

If you'd rather scope sharing to a unix group:

sudo groupadd tuimanji
sudo install -d -m 2775 -g tuimanji /var/games/tuimanji
sudo usermod -aG tuimanji alice  # repeat per user

…and have each user run with a permissive umask (umask 0002) so files they create stay group-writable. The auto-propagation above only kicks in for the sticky+world-writable layout; for groups, you set the policy and tuimanji honors what it finds.

Games

id players name
tic-tac-toe 2 Tic-Tac-Toe
connect-4 2 Connect 4
battleship 2 Battleship
reversi 2 Reversi
chess 2 Chess
checkers 2 Checkers
peg-solitaire 1 Peg Solitaire
crazy-eights 2–4 Crazy Eights
royal-ur 2 Royal Game of Ur
mastermind 2 Mastermind

Controls

key action
↑ ↓ ← → move cursor
enter space commit cursor action
r rotate ship (Battleship placement phase)
tab cycle stage / suit / piece (multi-phase games)
c cancel match (waiting room, host only)
q quit to lobby

Per-game quirks are surfaced in the status strip at the bottom of each match.

Adding a game

A game is one module under src/tuimanji/games/ implementing the tuimanji.engine.Game protocol — pure functions over state dicts. No I/O, no database access. See docs/adding-a-game.md for a walkthrough, or read src/tuimanji/games/peg_solitaire.py for the minimal single-player shape.

from tuimanji import Game, REGISTRY, IllegalAction

class MyGame:  # satisfies the Game protocol structurally
    id = "my-game"
    name = "My Game"
    min_players = 2
    max_players = 2
    # ... initial_state, apply_action, current_player, winner, is_terminal,
    # ... render, initial_cursor, move_cursor, cursor_action, animation_for

Development

git clone https://github.com/alanbato/tuimanji
cd tuimanji
uv sync
uv run pytest -q
prek install    # pre-commit hooks (ruff, ty)
uv run tuimanji

See CONTRIBUTING.md for the full contributor guide.

License

LGPL-3.0-or-later. See COPYING.LESSER (which extends the GPLv3 in COPYING).

Modifications to Tuimanji itself must be released under the LGPL, but larger works that merely use the library (e.g. a game module wired into the REGISTRY) are not required to adopt the same license.

Metadata

Release files for tuimanji 0.1.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tuimanji 0.1.9
File Size Uploaded Provenance Actions
tuimanji-0.1.9.tar.gz 76.5 kB With provenance Details for tuimanji-0.1.9.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for tuimanji 0.1.9
File Interpreter ABI Platform Actions
tuimanji-0.1.9-py3-none-any.whl Python 3 none any Details for tuimanji-0.1.9-py3-none-any.whl

Total release size: 170.7 kB

Release files / tuimanji-0.1.9.tar.gz

Download URL tuimanji-0.1.9.tar.gz
Size 76.5 kB
Tags Source
SHA-256 checksum
How to use checksums
30487fe2d0539fd6ff26c033699bf8c56a83c46f05bfb53d73084272dfc7ef84
BLAKE2b-256 checksum
How to use checksums
13a5b516fe27a001a478779d0391a320ff042238bb7fde518831c742bef14a61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

Release files / tuimanji-0.1.9-py3-none-any.whl

Download URL tuimanji-0.1.9-py3-none-any.whl
Size 94.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
576ae815eb858ad9c281710d17d87dc585d3e9f9d9ed802fb998ea4ca20f47d9
BLAKE2b-256 checksum
How to use checksums
949f8dc7da10ad170304d536f9c74ec26bae22f6d3604a8d5624e2d8380b24a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

Security for tuimanji 0.1.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for tuimanji-0.1.9.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page