CLI Architecture (Explanation)
This doc explains how the Typer CLI is wired, how global configuration is applied, and how daemon mode works.
Layout
The CLI lives in src/kalshi_research/cli/ (a package, not a single file):
src/kalshi_research/cli/
├── __init__.py # app, global callback, sub-app registration
├── __main__.py # enables `python -m kalshi_research.cli ...`
├── utils.py # shared Rich console + JSON helpers
├── data.py
├── market.py
├── scan.py
├── alerts.py
├── analysis.py
├── research.py
├── portfolio.py
└── news.py
Global config (--env + .env)
At CLI startup:
.envis loaded (searching upward from CWD).- The API environment is determined by precedence:
--env/-e flag > KALSHI_ENVIRONMENT > "prod"
Invalid values exit with an error (no silent fallback).
Async boundary
Most commands are implemented as a small sync wrapper that calls asyncio.run(...) internally.
This keeps the CLI ergonomic while allowing the underlying clients/DB to stay async.
Alerts daemon mode
kalshi alerts monitor --daemon spawns a detached child process:
parent: kalshi alerts monitor --daemon
└─ spawns: python -m kalshi_research.cli alerts monitor ...
Daemon mode relies on src/kalshi_research/cli/__main__.py so Python can execute the CLI package as a module.