Back to the catalog

pktui Knowledge Bundle

Bundle OKF 0.1 · 6 conceitos · ImperialBower/pktui

Open source Repository Open in the app JSON README (API)

About

# pktui Knowledge Bundle

Knowledge for [pktui](https://github.com/ImperialBower/pktui) — a ratatui
terminal client for the pkcore poker engine.

# Start here

* [pktui — overview](getting-started.md) - what the crate is, its modes, and its architecture.

# Architecture

* [Architecture](architecture/) - the Elm-style Model / Message / Update loop and error handling.

# Modes

* [Modes](modes/) - Play, Arena, Replay, and Spectate.

# UI / Rendering

* [UI / Rendering](ui/) - the view dispatch, table, action bar, odds cache, log panel, and overlays.

# Configuration

* [Configuration](config/) - the CLI and the persistent user config.

# Design Decisions

* [Design Decisions](decisions/) - per-street Win% display and the Spectate snapshot dump.

Details

Kind
OKF bundles
Topic
Developer tools
Publisher
imperialbower
Origin
okf_github
Category
dados
Version
0.1
Last push
2026-08-31T01:04:59Z
Repository state
ativo
Language
Rust
License
Apache-2.0
Added
2026-09-08 16:02:35
Updated
2026-09-08 16:02:35
Origin id
ImperialBower/pktui:.okf/index.md

README

# pktui

A [ratatui](https://ratatui.rs) terminal client for the
[pkcore](https://github.com/ImperialBower/pkcore) poker engine.

`pktui` is the terminal sibling of
[pkarena0-web](https://github.com/ImperialBower/pkarena0-web): same engine,
same three modes (Play / Arena / Replay), same bot roster, swap the SVG
table for a ratatui one.

## Install / run

```sh
# from the workspace root, with ../pkcore checked out alongside ../pktui
cargo run --release                                # default: Play / NLHE (you vs 8 bots)
cargo run --release -- play                        # same as above, explicit
cargo run --release -- play --variant plo          # Pot-Limit Omaha (you vs 8 bots)
cargo run --release -- play --variant stud-hi      # 7-card Stud Hi (you vs 7 bots)
cargo run --release -- play --variant razz         # 7-card Razz lowball (you vs 7 bots)
cargo run --release -- arena --speed-ms 400        # all-bot NLHE
cargo run --release -- arena --variant plo         # all-bot PLO (9 bots)
cargo run --release -- arena --variant stud-hi     # all-bot Stud Hi (8 bots)
cargo run --release -- arena --variant razz        # all-bot Razz (8 bots)
cargo run --release -- replay path/to/session.yaml # step through saved hand history
cargo run --release -- spectate                          # watch a live pkdealer table (http://localhost:50051)
cargo run --release -- spectate --endpoint http://host:50051
```

### Variants and seat caps

| Variant   | `--variant` flag | Max seats | Play table | Arena table |
|-----------|------------------|-----------|------------|-------------|
| NLHE      | `nlhe` (default) | 9         | 1 hero + 8 bots | 9 bots |
| PLO       | `plo`            | 9         | 1 hero + 8 bots | 9 bots |
| Stud Hi   | `stud-hi`        | 8         | 1 hero + 7 bots | 8 bots |
| Razz      | `razz`           | 8         | 1 hero + 7 bots | 8 bots |

Stud-family variants are capped at 8 seats — pkcore's `Table::MAX_STUD_SEATS`.
Eight players need 56 cards across 7 streets and the deck holds 52, so when the
stub runs short on 7th street the dealer turns a single face-up community card
that every remaining player counts as their seventh. Nine runs dry two streets
earlier, which no community card can rescue, so the engine rejects it.

### Forced-bet flags by variant

Hold'em-family (NLHE, PLO) uses blinds; stud-family (Stud Hi, Razz) uses
ante + bring-in + small-bet / big-bet. Pass the flags applicable to the
variant you picked — others are ignored.

```sh
# NLHE / PLO — blinds + chips
cargo run --release -- play --small-blind 50 --big-blind 100 --chips 10000
cargo run --release -- play --variant plo --small-blind 50 --big-blind 100

# Stud Hi / Razz — ante / bring-in / small-bet / big-bet
cargo run --release -- play --variant stud-hi \
    --ante 10 --bring-in 25 --small-bet 50 --big-bet 100 --chips 10000
cargo run --release -- play --variant razz \
    --ante 10 --bring-in 25 --small-bet 50 --big-bet 100
```

If `--small-bet` / `--big-bet` are omitted for stud-family, they fall back
to `--small-blind` / `--big-blind` so the existing NLHE defaults still
produce a playable Stud / Razz table.

`pktui` uses Rust edition 2024 and pins `rust-version = 1.94.1`. The
[`Cargo.toml`](Cargo.toml) declares `pkcore` as a `crates.io` dependency but
overrides it with `[patch.crates-io] pkcore = { path = "../pkcore" }` so
local engine work is picked up without publishing. Comment out the patch
section to build against the published crate exclusively.

## Modes

| Mode     | Subcommand                      | Description                                          |
|----------|---------------------------------|------------------------------------------------------|
| Play     | `pktui play`                    | One human at seat 0; bots at the remaining seats. NLHE seats 8 bots, stud-family seats 7. |
| Arena    | `pktui arena`                   | Bots only, watch-only. NLHE seats 9, stud-family seats 8. Use `+` / `-` to adjust pace. |
| Replay   | `pktui replay <FILE>`           | Step through a saved `HandCollection` YAML file.     |
| Spectate | `pktui spectate [--endpoint …]` | Read-only live viewer of a running `pkdealer` table. |

All live modes accept `--variant {nlhe,plo,stud-hi,razz}`, `--seed N`, and
`--chips N`. Hold'em-family (NLHE, PLO) adds `--small-blind` / `--big-blind`;
stud-family adds `--ante` / `--bring-in` / `--small-bet` / `--big-bet`.
Arena additionally accepts `--speed-ms N` (default 800).

### Spectate mode

`spectate` is a read-only viewer of a live
[`pkdealer`](https://github.com/ImperialBower/pkdealer) table. It connects to
the dealer's gRPC `StreamEvents` endpoint and renders the table, a per-seat
profit/loss column, and a rolling event log — the terminal counterpart to the
web `pkspectator`. It needs the `pkdealer` repo checked out as a sibling
(`../pkdealer`) so the shared protobuf crate is available. Press `space` to
freeze/unfreeze the display, `q` to quit. The viewer auto-reconnects if the
dealer restarts.

## Keyboard

| Mode       | Key            | Action                                                          |
|------------|----------------|-----------------------------------------------------------------|
| Global     | `?`            | Toggle help overlay                                             |
| Global     | `q` / `Ctrl+C` | Quit                                                            |
| Global     | `D`            | Dump Play state to `./pktui-dump-<seed>-<phase>-<unix>.yaml`    |
| Play       | `f`            | Fold                                                            |
| Play       | `k`            | Check                                                           |
| Play       | `c`            | Call                                                            |
| Play       | `a`            | All-in                                                          |
| Play       | `b` / `r`      | Confirm bet/raise using the current bet amount                  |
| Play       | `Enter`        | Confirm bet/raise — or deal next hand between hands             |
| Play       | `1` / `2` / `3`| Set bet to min / ½-pot / pot                                    |
| Play       | digits         | Type bet amount digit-by-digit                                  |
| Play       | `+` / `-`      | Bump bet amount by 50                                           |
| Play       | `Backspace`    | Delete last digit of bet amount                                 |
| Arena      | `+` / `-`      | Faster / slower bots (100 ms steps)                             |
| Replay     | `n` / `→`      | Next street                                                     |
| Replay     | `p` / `←`      | Previous street                                                 |
| Replay     | `N` / `Enter`  | Next hand                                                       |
| Replay     | `P`            | Previous hand                                                   |
| Spectate   | `space`        | Freeze / unfreeze the display                                   |

## Config file

On first save, `pktui` writes
`$XDG_CONFIG_HOME/pktui/config.toml` (typically
`~/.config/pktui/config.toml` on Linux/macOS,
`%APPDATA%\pktui\config.toml` on Windows):

```toml
small_blind = 50
big_blind = 100
chips = 10000
arena_speed_ms = 800
play_speed_ms = 600
```

Anything on the command line overrides the config.

## Architecture

`pktui` follows an Elm-style Model / Message / Update loop:

```text
crossterm event ──► Event ──► event_to_msg ──► Msg ──► update(app, msg) ──► App
                                                                            │
                                                                            ▼
                                                                       ui::view ──► ratatui Frame
```

* [`src/app.rs`](src/app.rs) — the `App` model, plus the `AppMode` enum that
  dispatches to per-mode state.
* [`src/modes/`](src/modes/) — `PlayState`, `ArenaState`, `ReplayState`.
* [`src/update.rs`](src/update.rs) — `Msg` enum and the `update` reducer.
* [`src/event.rs`](src/event.rs) — crossterm polling with tick timer for bot
  pacing.
* [`src/ui/`](src/ui/) — render functions (`table`, `action_bar`, `log_view`,
  `help`, `replay_view`).
* [`src/main.rs`](src/main.rs) — thin entry point: parse CLI, init terminal,
  run loop, restore terminal on exit.

The engine boundary is small: pktui reads `session.table` for rendering,
calls `session.next_step()` to advance, and calls `session.apply_action(seat,
PlayerAction)` for both bot and human decisions.

## Development

```sh
cargo build                  # build the binary + library
cargo test                   # unit + integration tests
cargo test --doc             # doc tests (CLAUDE.md requires one per public fn)
make ayce                    # full pipeline: fmt + test + clippy + deny + docs
```

CLAUDE.md in the repo root captures the coding conventions (every public
function has a unit test and a doc test, `unwrap`/`expect`/`panic` are
forbidden outside tests, etc.). New code should follow them.

## Licence

Dual-licensed under MIT OR Apache-2.0 (your choice), matching the upstream
`pkcore` engine.

More