Building my way back into poker
I used to play poker professionally. Now I’m starting over. I wanted a tool for low-stakes, six-max cash games that imports my hands, helps me work through mistakes and turns them into practice. That became KQs.
The goal is a poker companion I can use on Mac, Windows and my phone wherever I go. The Tauri desktop app collects the hands; web and mobile access carry review and practice with me. I build the interface, data processing and decision engine, including offline CFR+ calibration.
Why build the tracker myself?
Low-stakes six-max cash games limit the scope to the game I’m returning to. Position, stack depth and the behaviour of that player pool determine which situations the trainer needs to cover. They also set the order of the work. My own hands first have to arrive reliably in the review; the exercises build on the decisions found there. I also wanted the engineering challenge. Building an engine and layering different methods is a large part of the appeal. Preflop charts supply a reference, observed actions describe the player pool, and equity calculations evaluate cards against ranges. CFR+ adds an offline check for selected postflop situations. The interface has to show which method produced an answer; a rough estimate can otherwise look just as authoritative as a calculated frequency.
25,000 hands of playing and revising KQs
I use KQs while I build it. Across my last 25,000 hands at NL2 through NL10, my win rate moved from 6 to 18 big blinds per 100 hands. I kept changing the tool in practice throughout that period. These figures describe my own play. They do not separate the effects of KQs, returning experience and variance. For the product work, using it gives me something concrete after each session: hands to investigate and parts of the tool to revise.
Starting win rate
NL2–NL10 · Six-Max Cash Games
Latest reported win rate
NL2–NL10 · Six-Max Cash Games
Hands across this period
Personal playing results · NL2–NL10 · reported by Luka, September 2026
Why the desktop app uses Tauri
Desktop comes first because that is where the hand histories are created. Tauri connects the interface to the local machine: choose a folder, import completed hands and keep the session running while the window sits in the tray. In a release build, the Rust shell starts a bundled Node process running the built Next.js server. Database migrations run before the server starts. SQLite lives in the application data directory, independently of the installed bundle. This arrangement keeps the poker logic in TypeScript alongside the web application. Rust handles the desktop lifecycle and native capabilities. The user does not need to run a development server. The Tauri foundation targets Mac and Windows; automatic attachment to PokerStars windows is currently implemented in the macOS alpha path. I want to take the review with me when I leave the computer. Desktop and browser therefore share the product interface. Supabase connects private hands and training data to an account, and the code also includes a cloud snapshot of session status. The current phone entry point is the installable web app. A standalone native phone app is part of the longer-term vision. What matters to me is being able to continue with the same hand on another device.
Tauri · Mac / Windows
Collect local hand histories, maintain SQLite and run the desktop session.
Web app
Open review and training through the same account.
Phone
Access personal study data away from the desk; currently through the installable web app, with a native app in the longer-term vision.
What has to survive the import
A PokerStars hand history becomes a shared HandRecord containing the external hand ID, positions, stacks and action sequence. Wagers are normalised to big blinds, while the original stake and currency are retained separately. That lets the review compare decisions across sessions without treating the cash amount alone as the size of a mistake. The record also carries its source and completeness. Imported hands, training hands and manual entries have different source identifiers. The desktop folder watcher uses the same storage path as a regular import and can attach the active session ID. For older hands without that ID, the review uses a 45-minute gap to separate sessions. For opponents, the action is usually observable while the hole cards remain hidden. KQs therefore counts each action together with the opportunities to take it. Revealed hands are stored separately. Showdowns expose a selected part of someone’s play, which makes them a biased sample of their whole range.
Imported hands
What was observed in a particular hand, including gaps in the record.
Player pool
Action frequencies from the HandHQ corpus or personal observations, filtered by dimensions such as stake, position and decision node.
Preflop reference
Authored action distributions for supported table sizes, positions and stack depths.
CFR+ artifact
An offline strategy calculation with declared ranges, board assumptions and available actions.
A mistake needs a denominator
Ten similar mistakes mean something different in twelve opportunities than in two hundred. A leak entity keeps both counts, along with affected sessions and example hands. Its key combines the situation, position and difference between the chosen and recommended action. Estimated costs in big blinds retain the confidence grade of the underlying assessment. The trainer lets me play the decision again, and saved training sessions can be opened in Review. The hands that led to an exercise remain traceable.
How much do I know about this opponent?
An opponent who raises several times in a small sample can acquire a firm label too quickly. KQs initially pulls observed rates towards a baseline. For VPIP, the proportion of hands entered voluntarily, the normalisation uses a 24% prior weighted as 40 opportunities. That specific value is an assumption in the model. Five voluntary entries in ten opportunities produce an internally smoothed rate of 29.2%. As observations accumulate, the prior carries less weight. The interface also hides derived rates and style labels below the current floor of 50 observed hands. Postflop statistics track their own action opportunities: a total hand count says little about how often someone actually faced a particular raise.
VPIP smoothing · illustrative observations
(5 + 0.24 × 40) / (10 + 40) = 0.292
The range changes with the situation
The matrix displays the preflop reference for the selected position, table size and stack depth. A selected hand stays highlighted, with its action distribution below. Review and Spot Coach use the same reference. Moving from the button to early position therefore changes both the displayed range and the basis for assessment. I want the lookup view and the hand review to work from the same assumption.
Dark mode
Desktop · 1920 × 1080
Light mode
Desktop · 1920 × 1080
Checking the engine against a calculated game tree
Postflop brings many combinations of boards, ranges and bet sizes. Board-texture rules and pot odds give the engine an initial assessment. I wanted to calculate selected situations more deeply as well. That is the job of the separate poker-cfr package. CFR+ stands for Counterfactual Regret Minimization Plus. In simplified terms, it repeatedly calculates how much better another action would have been than the current strategy mixture. Positive cumulative regrets determine the next mixture, with negative values clamped to zero. Both sides are updated over many iterations. The calibration exports averaged action frequencies. The first KQs version uses a bounded heads-up tree on one street: check or one fixed bet, followed by fold or call. Both players enter as weighted ranges. Card combinations that overlap with the board or each other are removed. Every compatible private-card pairing contributes to an information set before the implementation updates its strategy. That ordering matters because a player cannot see the opponent’s hidden cards. The computation stays offline; the application loads compact artifacts. Before a matching V1 artifact can replace a heuristic recommendation, the code checks range provenance and promotion conditions, and requires a finite stored NashConv value of at most 0.1. This residual check applies to the declared game tree. It does not measure performance across all of no-limit Hold’em.
V1
One street and one fixed bet size. The runtime can use approved artifacts with an exact match.
V2
One street with one or two fixed bet sizes for calibration comparisons.
V3
Flop and a public turn card with bounded actions. Experimental comparison results, ineligible for promotion into the active policy.
Let the review create calibration work
Review can queue offline calibration requests for supported situations. The current V3 path covers a heads-up flop after a single raise between button and big blind, checked to the player in position. The request records board class, pot size, stack and stack-to-pot-ratio buckets, plus IDs and fingerprints for both ranges. It leaves out names, hand IDs and the actual hole cards. For larger ranges, V3 uses reproducible sampling. The request pipeline defaults to 128 private deals and eight turn cards. Three seeds then check how much root action frequencies move, with a default limit of five percentage points. A separate residual audit examines the stored strategy for exploitable deviations inside the calculated tree. For sampled trees, that audit is itself an estimate. This is the part I want to develop further: turning situations from my own review into bounded calculations I can inspect. A stable V3 run remains a comparison result. Using it in the assessment engine would require its assumptions and coverage to match the decision being reviewed.
The same hand on the next device
Mobile
On a phone, the table and actions stack vertically. Navigation moves into a menu, and range filters open on demand.
Mac · Windows · Web
Tauri handles local imports at the desk. Through the web app, I want to continue studying those hands away from it. A native phone app is part of the longer-term plan.





