Skip to main content

kryten-economy

Python 3.11+ License: MIT Tests

Channel engagement currency microservice for CyTube, built on the kryten ecosystem.

What It Does

kryten-economy turns passive viewers into active participants by rewarding channel presence, chat activity, and social interaction with Z-Coins — a fully configurable virtual currency. Users spend Z on queueing media, vanity items, tipping, and gambling. A B-movie-themed rank system (Extra → Stunt Double → … → Director) grants real perks like queue discounts and extra queue slots.

Feature Highlights

  • Presence earning — per-minute Z rewards with night-watch bonuses and hourly milestones
  • Chat triggers — 12+ earning triggers for long messages, kudos, laughs, conversation starters, and more
  • Daily streaks — consecutive-day bonuses with milestone multipliers and bridge recovery
  • Gambling — slot machine, coin flip, player duels, and cooperative channel heists
  • Media queue — search and queue content from a MediaCMS instance, paid with Z
  • Tipping — alias-aware peer-to-peer transfers with self-tip prevention
  • Vanity shop — custom greetings, chat colors, titles, channel GIFs (with admin approval)
  • Achievements — one-time badges with Z rewards for milestones
  • Rank progression — automatic rank-ups with CyTube rank promotions
  • Multiplier events — scheduled and ad-hoc earning multipliers, daily competitions, user bounties
  • Admin tooling — 16 admin commands for grants, bans, economy health, trigger analytics, config hot-reload
  • Monitoring — Prometheus metrics endpoint with per-trigger, per-command, and per-channel gauges

Everything is configurable via a single YAML file — every rate, threshold, reward, cost, and message template.

Requirements

  • Python 3.11+
  • NATS server (via kryten infrastructure)
  • kryten-py >= 0.11.5 — CyTube ↔ NATS client library
  • kryten-robot — event source bridging CyTube websocket events to NATS
  • kryten-userstats — alias resolution for tip self-transfer prevention
  • Optional: MediaCMS instance for content queue features

Installation

From PyPI

pip install kryten-economy

From GitHub

pip install git+https://github.com/grobertson/kryten-economy.git

Development Install

git clone https://github.com/grobertson/kryten-economy.git
cd kryten-economy
python -m venv .venv
source .venv/bin/activate   # Linux/macOS
# .venv\Scripts\activate    # Windows
pip install -e ".[dev]"

Quick Start

# 1. Copy the example config
cp config.example.yaml config.yaml

# 2. Edit with your NATS and channel settings
$EDITOR config.yaml

# 3. Run
kryten-economy --config config.yaml

# Or as a module
python -m kryten_economy --config config.yaml

systemd Deployment

sudo cp systemd/kryten-economy.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now kryten-economy

The included service file has resource limits (MemoryMax=512M, CPUQuota=50%) and security hardening (NoNewPrivileges, ProtectSystem=strict).

Configuration

See config.example.yaml for the complete reference with inline documentation. Key sections:

Section Controls
database SQLite path and PostgreSQL connection/pool settings
currency Name, symbol, starting balance, daily cap
presence Base rate, night watch, milestones, greeting absence
streaks Streak bonuses, milestones, bridge recovery
chat_triggers 12 chat-based earning triggers with cooldowns
content_triggers Media interaction rewards
social_triggers Kudos, laughs, greetings, mentions
gambling Slot payouts, flip odds, challenge/heist rules
spending Queue costs, tip limits, vanity shop items
ranks Tier names, thresholds, perks, CyTube promotions
achievements Badge conditions and rewards
events Scheduled multipliers, competitions, bounties
announcements Public chat templates and toggle gates
admin Owner level, digest schedules
commands PM rate limit
metrics Prometheus endpoint port

Environment variable substitution is supported: ${NATS_URL}, ${VAR:-default}.

Database backend status

SQLite remains the production data layer, and remains the default. The postgres backend is complete as of 0.16.0 and is verified against a live PostgreSQL 16 server — an asyncpg store covering the full EconomyDatabase surface, with transactional, row-locked currency mutations.

Do not switch production over by editing config.yaml. Moving live currency is a deliberate, reversible operation with its own procedure — see docs/postgres-cutover.md for the cutover, verification, smoke-test, and rollback steps, and docs/admin-guide.md for the data-migration tool itself. Rollback is database.backend: "sqlite" plus a restart; the SQLite file is left untouched and stays valid for one full release.

The PostgreSQL schema is managed by Alembic (the single schema authority for this service):

uv run alembic upgrade head

Alembic resolves its database URL from KRYTEN_ECONOMY_ALEMBIC_URL, or from the service's own database.postgres block, so no database credential is stored in the repository.

When PostgreSQL connection plumbing is used, DSN resolution follows this precedence:

  1. The environment variable named by postgres.dsn_env
  2. postgres.dsn
  3. A DSN assembled from host, port, user, dbname, and the password selected by password_env (preferred) or password

Prefer KRYTEN_ECONOMY_DSN for a complete DSN or KRYTEN_ECONOMY_PG_PASSWORD for only the password. Keep secrets out of config.yaml and source control.

Note that the migration tool reads a DSN through its own --pg-dsn-env name and does not share Alembic's KRYTEN_ECONOMY_ALEMBIC_URL; see the runbook.

Documentation

PM Commands

User Commands

Command Description
help Brief command overview
balance / bal Current balance, rank, and streak
rank Rank progress and perks
profile Full user summary
achievements Earned badges and progress
top / leaderboard Leaderboards
history Recent transaction history
search <query> Moved to the web queue → https://queue.dropsugar.co/
queue <id> Moved to the web queue → https://queue.dropsugar.co/
playnext <id> Moved to the web queue → https://queue.dropsugar.co/
forcenow <id> Attempt immediate play (typically expensive/admin-gated)
tip @user <amount> Transfer Z to another user
shop Browse vanity items
buy <item> Purchase a vanity item
spin [wager] Slot machine
flip <wager> Coin flip
challenge @user <wager> Player duel
bounty <amount> "<desc>" Create a bounty
bounties List open bounties
events View active multipliers
status / eventstatus Show event timing and queue availability

Admin Commands (CyTube Rank ≥ 4)

Command Description
grant @user <amount> [reason] Credit Z to a user
deduct @user <amount> [reason] Debit Z from a user
rain <amount> Distribute Z equally to all present users
set_balance @user <amount> Hard-set a user's balance
set_rank @user <rank> Override a user's economy rank
ban @user [reason] / unban @user Economy access control
reload Hot-reload config without restart
announce <message> Post a message in public chat
econ:stats Economy overview dashboard
econ:user <name> Full user inspection
econ:health Inflation/deflation indicators
econ:triggers Trigger hit analytics with dead-trigger detection
econ:gambling Actual vs. configured house edge
event start/stop <name> Ad-hoc multiplier events
claim_bounty <id> @user Award a bounty to winner
approve_gif @user / reject_gif @user Manage GIF purchase approvals

Testing

# Run the whole suite
uv run pytest

# With coverage
uv run pytest --cov=kryten_economy --cov-report=term-missing

# Skip the tests that need a real PostgreSQL server
uv run pytest -m "not postgres"

# Just the PostgreSQL backend + ETL tests (requires KRYTEN_ECONOMY_TEST_DSN)
uv run pytest -m postgres -v

# Specific sprint area
uv run pytest tests/test_gambling_engine.py tests/test_slots.py tests/test_flip.py -v

Most tests need no external services: no NATS server and no database. The PostgreSQL backend is the exception — it is validated against a real PostgreSQL server rather than a mock, because a mock would pass while asyncpg failed in production. Those tests carry the postgres marker and skip cleanly when no DSN is configured:

export KRYTEN_ECONOMY_TEST_DSN='postgresql://kryten:...@host:5432/kryten_economy_test'
uv run alembic upgrade head   # apply the schema to that database first
uv run pytest -m postgres -v

Point that at a disposable database — the PostgreSQL tests create and drop rows, and the ETL tests truncate tables. CI does this automatically with a postgres:16-alpine service.

Monitoring

Prometheus metrics served at http://localhost:28286/metrics (port configurable).

Counters: Z earned by trigger, Z spent by type, gamble in/out, events processed, commands processed, trigger hits, achievements awarded, rank promotions, competitions, bounties.

Gauges: Active users, total circulation, median balance, participation rate, active multiplier, rank distribution — all per-channel.

Architecture

kryten-economy/
├── kryten_economy/
│   ├── __init__.py              # Version from metadata
│   ├── __main__.py              # CLI entry, signal handling
│   ├── main.py                  # EconomyApp orchestrator
│   ├── config.py                # Pydantic config models
│   ├── database.py              # SQLite store (default backend)
│   ├── db/                      # PostgreSQL backend
│   │   ├── protocol.py          # EconomyStore Protocol (backend contract)
│   │   ├── boundary.py          # SQLite≡PostgreSQL value normalisation
│   │   ├── pool.py              # DSN resolution + asyncpg pool
│   │   └── database_pg.py       # asyncpg store (full EconomyDatabase surface)
│   ├── migrate_sqlite_to_pg.py  # One-time SQLite → PostgreSQL ETL (operator tool)
│   ├── presence_tracker.py      # Dwell tracking, join debounce
│   ├── earning_engine.py        # Centralized earning + multipliers
│   ├── spending_engine.py       # Spending validation + rank discounts
│   ├── gambling_engine.py       # Slots, flip, challenge, heist
│   ├── pm_handler.py            # 34 PM commands + rate limiting
│   ├── command_handler.py       # NATS request-reply API
│   ├── achievement_engine.py    # One-time badges
│   ├── rank_engine.py           # B-movie rank progression
│   ├── multiplier_engine.py     # Multiplier stack
│   ├── competition_engine.py    # Daily competitions
│   ├── bounty_manager.py        # User bounties
│   ├── event_announcer.py       # Chat announcements (dedup + batching)
│   ├── greeting_handler.py      # Custom greetings on join
│   ├── admin_scheduler.py       # Snapshots + digests
│   ├── scheduled_event_manager.py  # Cron-based events
│   ├── metrics_server.py        # Prometheus endpoint
│   ├── media_client.py          # MediaCMS API client
│   └── utils.py                 # Shared utilities
├── tests/                       # 65 test files, 574 tests
├── config.example.yaml          # Full reference config (~570 lines)
├── systemd/
│   └── kryten-economy.service   # Production systemd unit
├── pyproject.toml
├── LICENSE
└── CHANGELOG.md

Design Principles

  • Zero raw NATS — all messaging through kryten-py wrappers
  • Atomic debits — single-transaction debit-or-fail prevents negative balances
  • SQLite WAL — write-ahead logging with busy_timeout=30s for concurrent access
  • Transactional currency — credit/debit/refund apply the balance change and write the ledger row in one transaction on both backends, so a balance can never move without a matching transactions row. debit is a conditional UPDATE ... WHERE balance >= $ on PostgreSQL, so simultaneous spends serialise on the row lock and a debit that cannot be covered updates zero rows rather than going negative.
  • Error isolation — every event handler wrapped in try/except; one bad event never crashes the service
  • Hot-reloadable config — admin reload command re-validates via Pydantic and applies without restart

Publishing to PyPI

# Build
python -m build

# Upload to TestPyPI first
python -m twine upload --repository testpypi dist/*

# Upload to PyPI
python -m twine upload dist/*

License

MIT

Contributing

This is part of the kryten ecosystem. Issues and PRs welcome at github.com/grobertson/kryten-economy.

Metadata

Release files for kryten-economy 0.16.1

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

Source distribution (sdist)

Source distribution for kryten-economy 0.16.1
File Size Uploaded Provenance
kryten_economy-0.16.1.tar.gz 658.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for kryten-economy 0.16.1
File Interpreter ABI Platform
kryten_economy-0.16.1-py3-none-any.whl Python 3 none any Details

Total release size: 895.7 kB

Release files / kryten_economy-0.16.1.tar.gz

Download URL kryten_economy-0.16.1.tar.gz
Size 658.8 kB
Tags Source
SHA-256 checksum
How to use checksums
076fc7426c054c614594028db980e2c8f15971a4d59f428a85a2584ebd4a4d05
BLAKE2b-256 checksum
How to use checksums
fc189cbf71b85cf1a06eafdc4afda211681182209f2c772be74f32323e4e5344
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 26, 2026.

Transparency log

Release files / kryten_economy-0.16.1-py3-none-any.whl

Download URL kryten_economy-0.16.1-py3-none-any.whl
Size 236.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d37ae699af30dca60fbe2b7e8c6e8744603b4d4dc373c83b983ff01fd6a6376f
BLAKE2b-256 checksum
How to use checksums
7168a74ede0121944ea7a8bfa5256e568ad6588e1b42465af5f3a659e0593210
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 26, 2026.

Transparency log

Security for kryten-economy 0.16.1

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 kryten_economy-0.16.1.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 Sep 26, 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.

Release history Release notifications | RSS feed

This release

0.16.1 This release

2 release files Full provenance

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