An open-source CLI and TUI for managing game assets on the Stake Engine RGS. Upload math and front-end bundles, run compliance checks, and publish releases from your terminal or CI pipeline.
Disclaimer: this tool is not affiliated with the Stake Engine team. It is built by the community, privacy- and safety-first. We are in touch with the Stake Engine team about shipping a more convenient way to obtain API tokens — until then, session cookies are used (see Authentication below).
- Interactive TUI with team/game browser, upload wizard and publish flow
- Auto-refreshing approval conversation viewer with persistent read/unread state
- Hot-reloaded message hooks with per-hook, per-message delivery receipts
- Non-interactive CLI mode for CI/CD (
stakecli upload ...) - Optional encrypted Linux upload accelerator with automatic certificate pinning
- Native local MCP server for coding agents (
stakecli mcp) - Versioned advisory 2-star/3-star math compliance checks for interactive and headless workflows
- Built-in MLR reweighting for headerless LUT CSV files (
stakecli mlr) - Self-update (
stakecli update) - Zero external runtime dependencies (single static binary)
curl -LO https://github.com/mnemoo/cli/releases/download/v2.0.0-beta.1/stakecli_2.0.0-beta.1_linux_amd64.deb
sudo dpkg -i stakecli_2.0.0-beta.1_linux_amd64.debsudo rpm -i https://github.com/mnemoo/cli/releases/download/v2.0.0-beta.1/stakecli_2.0.0-beta.1_linux_amd64.rpmcurl -L https://github.com/mnemoo/cli/releases/download/v2.0.0-beta.1/stakecli_2.0.0-beta.1_darwin_arm64.tar.gz | tar -xz
sudo mv stakecli /usr/local/bin/
# If Gatekeeper blocks the binary, clear the quarantine flag:
sudo xattr -d com.apple.quarantine /usr/local/bin/stakecliOne-line install in PowerShell (downloads the latest release, installs
to %LOCALAPPDATA%\stakecli and adds it to your user PATH):
irm https://raw.githubusercontent.com/mnemoo/cli/main/install.ps1 | iexOr, to install a specific version:
$env:STAKECLI_VERSION = "v2.0.0-beta.1"
irm https://raw.githubusercontent.com/mnemoo/cli/main/install.ps1 | iexPrefer a manual install? Download the matching .zip archive from the
latest release and
extract stakecli.exe somewhere on your PATH.
git clone https://github.com/mnemoo/cli.git
cd cli
go build -o stakecli ./cmd/stakeGo 1.25+ is required.
The optional accelerator keeps all upload planning, ETag comparison,
multipart completion, publish behavior, and the Stake SID inside stakecli.
Only presigned PUT streams selected by the normal upload plan are relayed.
Install the amd64 or arm64 systemd daemon from a GitHub release:
curl -fsSL \
https://github.com/mnemoo/cli/releases/latest/download/install-accelerator.sh |
sudo bashThe installer asks for a password through /dev/tty, generates a self-signed
TLS identity, installs the hardened service, enables it at boot, and opens the
daemon on TCP port 7775. Firewall changes remain explicit.
Connect by IP. The certificate is pinned automatically only after the password has authenticated the first connection:
stakecli accelerator add --name relay 203.0.113.10:7775
stakecli accelerator speedtest --accelerator relay
stakecli upload ... --accelerator relay
stakecli accelerator tasks --accelerator relay --watchInteractive uploads include a complete connection wizard: choose direct or a saved relay, or add a relay by IP, optional name, and masked password. A new identity is authenticated and pinned automatically, after which the TUI can run an encrypted 64 MiB speed test before selecting the relay for that upload. Interrupted client-to-relay streams resume from the last accepted encrypted offset for up to one hour. After a complete part reaches the relay, it continues delivery without a client connection; rerunning the same upload reconciles completed remote parts and matching ETags.
See Encrypted upload accelerator for the protocol, security boundary, streaming behavior, CI/CD usage, and recovery semantics.
The TUI does not analyze books automatically. When compressed math books total at least 100 MiB, it offers a read-only Level 10 estimate first. The normal CLI only runs the estimator when explicitly requested:
stakecli repack estimate --level 10 ./publish_filesCI/headless jobs can opt into an automatic verified repack:
stakecli upload \
--team myteam --game mygame --type math --path ./publish_files \
--yes --repack--repack only uses files that save at least 5% and 16 MiB both in the estimate
and in the actual result. It works in private temporary staging, verifies the
uncompressed SHA-256, never modifies originals, and cleans staging afterward.
The TUI exposes the same operation as a reversible confirmation-screen button.
It uses the platform system temp directory, shows temporary-space, automatic
CPU-worker count, and a matching conservative working-memory requirement first,
and never writes decompressed JSONL to disk. Estimation and full repack use up
to 8 available CPU workers for each book; the TUI shows live compression and
SHA-256 verification progress with bytes, percentage, and elapsed time.
Repack is not recommended by default: Level 10 and the verification pass can consume substantial CPU, memory, time, and temporary disk space. It mainly helps very large, weakly compressed books on slow upload routes. See Zstd book repack estimator.
# Launch the interactive TUI
stakecli
# Check a local math bundle without authentication or network access
stakecli compliance .
# Preview an automatic MLR adjustment; add --save to overwrite the LUT
stakecli mlr ./publish_files/indexes/base_0.csv --target-n 250
# Estimate whether existing Zstd books can be packed better (read-only)
stakecli repack estimate --level 10 ./publish_files
# Or upload from the command line
stakecli upload \
--team myteam \
--game mygame \
--type math \
--path ./dist \
--compliance \
--yes --publish
# Or select account/team/game interactively, then upload and publish
stakecli publish math .
# Headless front-end publish
stakecli publish front ./dist --headless --team myteam --game mygame
# Also move an open approval to the version returned by publish. If the
# approval is closed, publish still succeeds and only prints a warning.
stakecli publish front ./dist --headless --team myteam --game mygame \
--update-approval-version
# Headless math skips compliance by default; add --compliance to print the
# report before continuing. Both 2-star and 3-star are always analyzed.
stakecli publish math ./dist --headless --team myteam --game mygame
stakecli publish math ./dist --headless --team myteam --game mygame \
--compliancestakecli Launch interactive TUI
stakecli compliance Check a local math bundle
stakecli mlr Reweight a LUT to adjust its most-likely result
stakecli repack Estimate better Zstd compression for math books
stakecli upload Upload files to Stake Engine
stakecli publish Upload and publish math or front-end assets
stakecli accelerator Configure and inspect encrypted upload relays
stakecli mcp Run the native MCP server over stdio
stakecli update Check for and install new releases
stakecli version Show version and build info
stakecli help Show this help
Math upload/publish compliance flags:
--compliance Show advisory compliance in headless mode
--base-mode NAME Optional display base-mode hint
--json Print structured JSON
Upload flags:
--team Team slug (required)
--game Game slug (required)
--type Upload type: math or front (required)
--path Path to local directory (required)
--yes Skip confirmation prompts (for CI/CD)
--publish Publish after upload
--update-approval-version Update an open approval to the published version
--compliance Run advisory math compliance before upload
--base-mode Optional display base-mode hint (math only)
--accelerator Profile name or direct IP:port
--accelerator-password-file Read the relay password from a protected file
--accelerator-fallback Relay failure behavior: fail or direct
--direct Upload directly without the interactive relay choice
--estimate-repack Estimate Zstd level 10 savings without changing files
--repack Repack only worthwhile Zstd books in temporary staging
MCP flags:
--sid Stake session credential (prefer STAKE_SID or keyring)
--key Alias for --sid
The interactive upload confirmation has one Upload action with persistent
Publish and Change approval version checkboxes. The approval checkbox is
available only while the selected game has an open approval, and enabling it
also enables Publish. Preferences are saved atomically in
upload-preferences.json under the stakecli config directory and reused on the
next upload.
stakecli mlr adjusts the single heaviest LUT row so the most-likely result is
no more frequent than 1 in N. It only changes weights: rows are not added,
removed, or reordered, and IDs remain aligned with payout multipliers.
The automatic operation is the default. It selects a donor band with the smallest RTP disturbance and enables RTP locking:
stakecli mlr ./base.csv --target-n 250
stakecli mlr ./base.csv --target-n 250 --saveEvery modifying operation is a dry run unless --save is present. Use
inspect to compare donor options or shift to choose one explicitly:
stakecli mlr inspect ./base.csv --target-n 250
stakecli mlr shift ./base.csv --target-n 250 --donor 0-1.00 --rtp-lock
stakecli mlr ./base.csv --target-n 250 --jsonThe accepted input is a headerless id,weight,payoutMultiplier CSV, where the
payout multiplier is stored in cents (100 means 1.00x). See
MLR reweighting algorithm for the algorithm and feasibility
limits.
| Variable | Description |
|---|---|
STAKE_SID |
Session ID for authentication. Bypasses the keyring; required for CI/CD. |
STAKE_API_URL |
Override API base URL. Default: https://stake-engine.com/api. |
STAKE_NO_UPDATE_CHECK |
Set to any value to disable the background update check. |
STAKE_STATE_DIR |
Override the private local directory used for cross-session upload progress. |
STAKE_CONFIG_DIR |
Override the private config directory containing accounts, message state, and hooks. |
STAKE_ACCELERATOR |
Default accelerator profile or direct IP address. |
STAKE_ACCELERATOR_PASSWORD |
Accelerator password. Use a CI secret or interactive prompt. |
STAKE_ACCELERATOR_FALLBACK |
fail by default; set direct only for an explicit direct-upload fallback. |
stakecli authenticates against the Stake Engine API with the same
session cookie (sid) your browser uses on
stake-engine.com. On interactive launch, you
will be asked to paste your SID; it is then stored securely in your OS
keychain and reused on subsequent runs.
We are working with the Stake Engine team on adding a more convenient way to obtain API tokens. Once that lands,
stakecliwill support the new flow as a first-class option and keep SID login as a fallback.
- Open your browser and log in to https://stake-engine.com as usual.
- Open DevTools:
- Chrome / Edge / Brave:
F12, orCmd+Option+I(macOS) /Ctrl+Shift+I(Windows/Linux) - Firefox:
F12, orCmd+Option+I/Ctrl+Shift+I - Safari: enable the Develop menu in Preferences → Advanced, then
Cmd+Option+I
- Chrome / Edge / Brave:
- Navigate to the cookies panel:
- Chrome / Edge / Brave:
Applicationtab → left sidebar →Storage→Cookies→https://stake-engine.com - Firefox:
Storagetab →Cookies→https://stake-engine.com - Safari:
Storagetab →Cookies→stake-engine.com
- Chrome / Edge / Brave:
- Find the row where Name is
sid. - Double-click the Value cell and copy the full string.
- Paste it into the
stakeclilogin screen, or export it for CI:export STAKE_SID="paste-value-here"
Treat the
sidlike a password. Anyone with this value can act as you on Stake Engine until the session expires. Do not commit it to git, share it in screenshots, or paste it into untrusted terminals. For CI/CD, store it as an encrypted secret (e.g. GitHub Actionssecrets.STAKE_SID).
stakecli mcp runs a native Model Context Protocol server over standard
input/output. It is part of the same static Go binary as the CLI and TUI; no
Node.js or Python runtime is required. It works with local MCP clients such as
Codex, Claude Code, Cursor, VS Code, and GitHub Copilot.
The server exposes typed tools for browsing teams and games, time-ranged team and game analytics, reading and replying to approval conversations, managing command/webhook hooks, reading the current compliance policy, checking local math bundles, inspecting and changing LUT MLR, planning uploads, controlling background upload operations, and publishing releases. Tool results use structured JSON schemas.
CLI publish flows accept --update-approval-version; the MCP publish tool
uses update_approval_version=true. Both read the current approval after a
successful publish and update its mathVersion or frontVersion to the exact
version returned by Stake Engine. A closed approval is a warning-only no-op.
Math compliance is a shared application API rather than UI-specific logic. It returns stable check codes, numeric bounds, hard-limit status, complete 2-star and 3-star eligibility, and per-mode RTP, volatility, hit-rate, max-win, CVaR, and ETL metrics. Platform bet level and currency are excluded from the verdict; the result reports the calculated maximum compliant bet level instead. See Math compliance API.
Run the same checker directly without authentication or network access:
stakecli compliance .
stakecli compliance ./publish_files --base-mode base
stakecli compliance . --jsonCredential lookup order:
--sid VALUEor its--key VALUEaliasSTAKE_SID- the active account in the OS keyring, created by logging in through the TUI
The key is never exposed as an MCP tool argument or result. Logging in once
with the TUI and then configuring agents with only stakecli mcp is the safest
and most portable setup.
You can explicitly insert a key when an MCP client cannot forward environment variables:
stakecli mcp --key "your-sid-value"Command-line arguments may be visible in process listings and MCP config files.
Prefer the keyring or STAKE_SID, and never commit a credential-bearing config.
Project or user config.toml:
[mcp_servers.stake]
command = "stakecli"
args = ["mcp"]
env_vars = ["STAKE_SID"]
tool_timeout_sec = 600Export STAKE_SID before launching Codex, or omit env_vars to use the
stakecli keyring.
Claude Code and clients using the common mcpServers format can launch the
same stdio command:
{
"mcpServers": {
"stake": {
"type": "stdio",
"command": "stakecli",
"args": ["mcp"]
}
}
}Use this as .mcp.json where supported, or paste the server entry into the
client's MCP settings. Launch the client with STAKE_SID exported when the OS
keyring is not being used.
VS Code uses the same command under a servers key in .vscode/mcp.json:
{
"servers": {
"stake": {
"type": "stdio",
"command": "stakecli",
"args": ["mcp"]
}
}
}MCP uploads are deliberately two-step:
- Call
plan_uploadto inspect uploads, server-side copies, deletions, compliance results, and the generatedplan_id. - Call
execute_uploadwith that exactplan_id, or callstart_uploadto queue it in the independent StakeCLI daemon and receive anoperation_idimmediately.
Use list_upload_processes to see active uploads from every local stakecli
CLI, TUI, and MCP session. Use get_upload_process for per-file bytes, S3
confirmation, multipart state, retries, and full errors. Pass
include_finished=true to the list tool to inspect recent terminal results.
Finished records are retained for one hour and then removed automatically.
Use pause_upload, resume_upload, cancel_upload, and retry_upload to
control daemon-owned work. Cancellation and retry require explicit
confirmation.
The daemon is a detached local process, not a goroutine owned by Codex, Claude,
or the MCP transport. Closing the MCP client does not stop an accepted upload.
The daemon reacquires authentication from STAKE_SID or the OS keyring and
revalidates the queued plan_id before mutation. Queue files never contain the
SID or presigned URLs.
stakecli daemon start
stakecli daemon status
stakecli daemon stopSee Background daemon and operations.
The server recalculates the plan immediately before execution. If local files
or remote scratch state changed, execution stops and asks the agent to plan
again. When compliance context is included, failed or otherwise incomplete
math is shown in the plan and requires the explicit acknowledgement
allow_compliance_failures=true; it is never a permanent upload block.
Publishing is separate and requires confirm=true. MCP math publishing skips
compliance by default. With check_compliance=true, it requires path,
reruns the advisory checker, and verifies that remote scratch exactly matches
the reviewed local bundle. Both tiers use the same LUT validation mechanism as
the moptimizer report generator. Platform bet level and currency are excluded
from the verdict; StakeCLI reports the maximum compliant bet level calculated
from every mode instead. Reported compliance issues do not block a confirmed
publish.
Choose Messages in the TUI to browse approval conversations by team. The thread list refreshes every 10 seconds and an open thread every 5 seconds. Unread counts are based on exact event IDs and persist per Stake account. The viewer renders public and private comments, attachments, and every known approval system event, and can send public or private replies.
From Game Detail, press a to open that game's Approval Thread directly.
Messages hide technical IDs and remain individually visible, while consecutive
version and checklist events are collapsed into expandable stacks. Timeline
navigation jumps by semantic block instead of scrolling one terminal line at a
time.
The MCP conversation workflow is deliberately context-bound:
- Call
get_conversationto read the complete latest timeline. - Call
conversation_reply_guideandprepare_review_reply. - Inspect warnings, then call
send_review_replywith the exactdraft_idandconfirm=true.
Drafts are bound to the latest event ID and a hash of the complete timeline. If the reviewer posts or edits a message between preparation and sending, the send is rejected. Drafts are single-use and expire after 30 minutes. Replies containing credentials, authorization material, presigned URLs, or local absolute paths are blocked. See Conversation viewer, hooks, and MCP replies for key bindings, hook configuration, payloads, and the reviewer reply policy.
The daemon polls every team for new approval activity even when the TUI and MCP
are closed. Hooks may execute a direct argv command or deliver JSON to an HTTPS
webhook. Event filters include new_message, reviewer_message,
public_message, private_message, approval_event, the raw Stake approval
event type, and *.
get_team_analytics returns time-ranged operator bets, turnover, profit,
expected profit, unique users, balance, and payment model.
get_game_analytics returns per-mode statistics plus graph buckets for profit,
turnover, and bet count. Both default to the last 30 days.
The local mlr_inspect, mlr_preview_change, and mlr_change tools expose the
built-in LUT reweighter. Preview does not modify the file. mlr_change requires
confirm=true, writes atomically, verifies the saved rows, and retains a
private sibling backup. MLR changes deliberately do not require a preview
fingerprint.
The example below builds and publishes a front-end bundle from a
pnpm + Turborepo monorepo (the same stack used by the
StakeEngine web SDK: Svelte 5 +
Vite + SvelteKit apps under apps/*, shared libraries under
packages/*). On every push to main, CI builds the target app with
Turbo, then uses stakecli to upload and publish the resulting dist
as a front-end release.
Stack assumed by this workflow:
- Node ≥ 22.16
- pnpm 10.x with workspaces (
pnpm-workspace.yaml→apps/*,packages/*) - Turborepo for orchestration (
turbo run build --filter=cluster) - Vite / SvelteKit with
@sveltejs/adapter-static— outputs a self-contained static bundle toapps/<app>/build/(the web-sdk's sharedconfig-svelteadditionally setsbundleStrategy: 'inline'andassetsInlineLimit: Infinity, so the whole app ships as a single inlined HTML, which is exactly what Stake Engine hosts as a game front-end)
# .github/workflows/publish-front.yml
name: Publish front
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: publish-front-${{ github.ref }}
cancel-in-progress: true
env:
APP_NAME: cluster # workspace package name, e.g. apps/cluster
STAKE_TEAM: myteam
STAKE_GAME: cluster
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0 # full history so Turbo can compute hashes
- name: Setup pnpm
uses: pnpm/action-setup@v4
# version is read from root package.json `packageManager` field
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Cache Turbo
uses: actions/cache@v4
with:
path: .turbo
key: turbo-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
turbo-${{ github.ref_name }}-
turbo-
- name: Build front-end bundle
run: pnpm turbo run build --filter=${{ env.APP_NAME }}
# Vite/SvelteKit output lands in apps/${APP_NAME}/build/
- name: Install stakecli
uses: jaxxstorm/action-install-gh-release@v2
with:
repo: mnemoo/cli
tag: v1.0.0 # pin a release for reproducible builds
- name: Upload and publish front-end
env:
STAKE_SID: ${{ secrets.STAKE_SID }}
run: |
stakecli upload \
--team "$STAKE_TEAM" \
--game "$STAKE_GAME" \
--type front \
--path "apps/${APP_NAME}/build" \
--yes --publishWhat each step does:
- Checkout with full history — Turborepo uses git for its content-
based cache keys;
fetch-depth: 0makes local caching effective. pnpm/action-setup@v4— installs the pnpm version declared in the rootpackage.json'spackageManagerfield (e.g.pnpm@10.5.0).actions/setup-node@v6withcache: pnpm— Node 22 to satisfy the repo'sengines.node, plus lockfile-aware pnpm store caching.pnpm install --frozen-lockfile— reproducible install; fails the build ifpnpm-lock.yamlis out of sync.- Turbo cache (
actions/cache@v4on.turbo) — skips re-building unchanged packages across runs. Swap for the Turbo remote cache if you have one. pnpm turbo run build --filter=<app>— builds only the target app and its local workspace dependencies.- Install stakecli — via
jaxxstorm/action-install-gh-release, pinned to a release tag. stakecli upload --type front … --publish— uploads the Vite/SvelteKitbuild/output and publishes the new front version in a single call.
Store
STAKE_SIDas an encrypted repository secret (Settings → Secrets and variables → Actions → New repository secret). Pintag:to an explicitstakeclirelease for reproducibility; omit it to always install the latest release.
# Run tests
go test ./...
# Lint
golangci-lint run
# Build all binaries into bin/
make build
# Run the local mock API + demo bundle (see DEMO.md)
make demo-build
make mockapi # terminal 1
make demo-run # terminal 2See DEMO.md for the full demo/development setup using the bundled mock API.
See docs/architecture.md for the application-layer boundaries shared by CLI, TUI, and MCP.
Issues and PRs are welcome. Please keep changes focused and include tests
where reasonable. Run go test ./... and golangci-lint run before
opening a PR.
See LICENSE.