Skip to content

Latest commit

 

History

87 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mirai

A KataGo analysis and playing GUI for the Linux desktop, plus a purpose-built protocol for driving KataGo over a network.

mirai

Point it at a local KataGo and it analyses positions, reviews SGF files and plays games against you. Point it at mirai-server on the machine with the GPU and it behaves identically from a laptop that has none.

cargo run -p mirai

What it does

Analysis and review

  • Live pondering of the position under the cursor, with candidate moves drawn on the board: win rate, score lead and visit count, coloured by relative visits.
  • Ownership and policy heat maps.
  • Hover any candidate to preview its principal variation, numbered, without touching the tree.
  • Win-rate and score-lead curves over the game, with a blunder strip along the bottom.
  • A branch graph of the whole game tree; variations are first-class.
  • Whole-game analysis with bounded concurrency, producing a blunder list that jumps to the move.
  • SGF load and save, including multi-game collections, with unknown properties preserved byte-for-byte so files from other programs survive a round trip.
  • Browse a Fox Go player's latest public games by exact nickname or UID, then download and open one directly for review.

Playing

  • Play KataGo at a chosen strength (visit cap, time budget, or a human-imitation profile when the model provides one), on any board from 2×2 to 19×19, with handicap and any of nine rulesets.
  • Byo-yomi, Fischer increment or absolute time controls, with clocks in the header bar.
  • Two passes open scoring: dead stones are derived from KataGo's ownership map, and clicking a group toggles its status with the total updating instantly and locally.
  • "Analyse after game" hands the finished game to whole-game analysis.

Remote

  • mirai-server hosts one or more KataGo instances and shares them across clients. Concurrency comes from KataGo's own numAnalysisThreads, not from spawning a process per client.
  • Token authentication, and trust-on-first-use certificate pinning.
  • Cancelling an analysis discards buffered results rather than delivering them.

Requirements

  • Current Rust nightly 1.99 or newer (edition 2024), selected by rust-toolchain.toml.
  • GTK 4.22+, libadwaita 1.9+, and Blueprint Compiler 0.22+ with their development packages.
  • A KataGo binary and a network model. Any recent KataGo works; mirai uses the JSON analysis engine (katago analysis), never GTP, and writes the analysis config itself unless you supply one.

On Arch: pacman -S gtk4 libadwaita blueprint-compiler. On Debian/Ubuntu, install libgtk-4-dev, libadwaita-1-dev, and blueprint-compiler.

The interface follows the GNOME Human Interface Guidelines. Static UI is written in Blueprint and integrated with gtk-rs composite templates.

cargo build --release --workspace

Getting started

On first run mirai looks for katago on PATH and merges every network found in the ordered XDG katago/models and mirai/models directories, with ~/.katago/models between user and system data. The first candidate seeds local-default; the rest stay one click away in each profile editor, listed by file name. If none is found, Preferences prompts for the binary and model paths. mirai generates the analysis config unless you pick a discovered one or a file of your own.

Everything else is discoverable from the interface. The parts that are not:

space toggle live analysis
previous / next move
Page Up Page Down jump ten moves
Home End start / end of the line
previous / next variation
o ownership overlay
y policy overlay
c coordinates
n move numbers
p pass
Delete delete this branch
Ctrl+n new game
Ctrl+Shift+n clear board
Ctrl+z undo
Ctrl+e score estimate
Ctrl+a analyse the whole game
Ctrl+o / Ctrl+s / Ctrl+Shift+s open / save / save as SGF
Ctrl+c / Ctrl+v copy / paste SGF

Right-click the board for "Play here", "Set as main line", "Delete branch" and "Copy SGF".


Configuration

$XDG_CONFIG_HOME/mirai/config.toml, editable from Preferences or by hand:

active_engine = "local-default"

[[engine_profile]]
name   = "local-default"
kind   = "local"
katago = "/path/to/katago"
model  = "/path/to/model.bin.gz"
# config = "/path/to/analysis.cfg"  # optional; omitted, mirai writes its own
analysis_threads           = 4    # numAnalysisThreads
search_threads             = 16   # numSearchThreadsPerAnalysisThread
nn_max_batch_size          = 64   # nnMaxBatchSize
nn_cache_size_power_of_two = 20   # nnCacheSizePowerOfTwo — 2^20 evaluations, about 3 GiB

[[engine_profile]]
name        = "workstation"
kind        = "remote"
url         = "mirai://192.168.1.10:9678"
token       = ""
engine      = "default"       # which of the server's engines
cert_sha256 = ""             # filled in on first connect

[analysis]
live_max_visits    = 1000000  # ceiling for pondering one position
report_interval_ms = 100
batch_visits       = 100      # per move, for whole-game analysis
max_suggestions    = 10       # 0 shows every move the engine searched

[play]
temperature      = 0.0        # > 0 samples among candidates instead of always the best
resign_threshold = 0.05
resign_streak    = 3
rules            = "Chinese"

[play.strength]
kind   = "visits"
visits = 800

[ui]
show_coordinates    = true
show_move_numbers   = false
ownership_overlay   = false
policy_overlay      = false
save_analysis_in_sgf = false  # store cached analysis in an MRAI property

Autosave, KataGo's logs and the generated analysis config live under $XDG_DATA_HOME/mirai/.


Running over a network

On the machine with the GPU:

mirai-server --generate-token          # prints a token; put it in server.toml
mirai-server --config server.toml

server.toml (see crates/mirai-server/server.example.toml for the annotated version):

listen = "0.0.0.0:9678"
cert   = "cert.pem"                    # generated on first start if missing
key    = "key.pem"

[[engine]]
name   = "default"
katago = "/path/to/katago"
model  = "/path/to/model.bin.gz"
# config = "/path/to/analysis.cfg"    # optional here too
analysis_threads  = 4
search_threads    = 16
nn_max_batch_size = 64

[[token]]
value    = "…64 hex chars…"
name     = "laptop"
max_subs = 4

The server prints its certificate fingerprint at boot (--print-fingerprint prints it on its own). Add a remote profile in the client's Preferences; on the first connection mirai shows the fingerprint for confirmation and pins it. A different certificate afterwards is a hard connection failure, not a warning.

Every configured engine starts eagerly at boot — loading a large net takes seconds, and a lazy first query would look like a hang. If one engine fails to start it is logged and skipped; the server exits only if none came up.


Architecture

flowchart TB
    gtk["mirai — GTK application"]
    client["mirai-client — analysis, session, play, Fox"]
    engine["mirai-engine — Engine trait"]
    local["LocalEngine"]
    remote["RemoteEngine"]
    proto["mirai-proto — MRP/1 types, frame, QUIC"]
    core["mirai-core — geometry, rules, tree, SGF"]
    server["mirai-server"]
    katago["katago analysis"]

    gtk --> client
    gtk --> engine
    client --> engine
    client --> core
    engine --> local
    engine --> remote
    engine --> proto
    engine --> core
    proto --> core
    server --> engine
    local --> katago
    remote --> server
Loading

Four decisions shape everything else:

One engine interface: KataGo's JSON analysis engine. Analysis queries are stateless — each carries its own moves, initialStones, rules and komi — so there is no engine-side state to keep in sync, no replay or undo machinery, and the remote protocol is a pure request/stream forwarder. Moves in play mode are chosen by mirai from the returned playSelectionValues.

KataGo's point encoding, unchanged. index = y * width + x, y = 0 is the top row. The ownership and policy arrays therefore share their ordering with the board array, and overlays need no index remapping.

All engine values are Black-perspective. KataGo is launched with reportAnalysisWinratesAs=BLACK, so stored values are sign-stable; the UI converts to side-to-move only where it displays them.

Quantised integers on the wire. Every float that crosses the network is fixed-point, and the conversion lives in the type. A live report with 50 candidates, principal variations and a full ownership map is 2622 bytes framed — against roughly 45 KB of equivalent KataGo JSON — with a bounded round-trip error (win rate ≤ 1e-4, score lead ≤ 0.02 points, ownership ≤ 0.005). Dropping a subscription terminates the underlying search; cancelling a remote one resets the QUIC stream so buffered stale reports are discarded rather than delivered.

The board, win-rate graph and move tree are custom gtk::Widget subclasses drawn with gsk in snapshot(). There is no GtkDrawingArea and no cairo anywhere.


Development

cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings

Check an engine end to end without the GUI — the same binary drives either path:

cargo run -p mirai-engine --example probe -- \
    --katago /path/to/katago --model /path/to/model.bin.gz \
    --config /path/to/analysis.cfg --visits 200

cargo run -p mirai-engine --example probe -- \
    --remote mirai://127.0.0.1:9678 --token <token> --visits 200

Debug builds carry a scripted-UI harness for driving and screenshotting the real application. It activates the application's own actions — the same handlers the keyboard accelerators reach — and renders through the live GSK renderer, so it works on Wayland with no external tooling:

MIRAI_HARNESS="wait:2500,action:win.next10,action:win.toggle-analysis,\
wait:10000,shot:/tmp/board.png,quit" cargo run -p mirai -- game.sgf

Steps are wait:<ms>, action:<prefix.name>[=<arg>], press:<button label>, shot:<path> and quit.


Documentation

docs/user/GUIDE.md the user manual: interface, analysis, review, playing, remote engines, settings, troubleshooting
AGENTS.md start here to work on the code — invariants, conventions, known traps
docs/dev/ARCHITECTURE.md module map, data model, concurrency, extension recipes
docs/dev/PROTOCOL.md the normative MRP/1 specification — enough to write an interoperable client in any language
docs/dev/TESTING.md how to prove a change works, including driving the GUI
docs/archive/RETROSPECTIVE.md how this was built: obstacles, how the GUI was debugged, defects found
docs/archive/PLAN.md the original build plan, kept as a historical record

Scope

Deliberately not included: online-server game fetching, screen-board OCR, joseki dictionaries, KataGo auto-download, theme skinning, and dual-engine comparison.

Board sizes are 2×2 to 19×19, matching stock KataGo builds. Rulesets are Tromp-Taylor, Chinese, Chinese (OGS), Japanese, Korean, stone scoring, AGA, AGA (button) and New Zealand, transcribed from KataGo's own definitions so local legality never disagrees with the engine.


License

GNU General Public License, version 3 or later (LICENSE).

mirai is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

About

A KataGo analysis and playing GUI for the Linux desktop, plus a purpose-built protocol for driving KataGo over a network.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages