# Runtime and Routing
## UI modes
`nntp-proxy` has one runtime binary with two public UI modes:
- `--ui headless`
- `--ui tui`
Shorthands:
- `--headless`
- `--tui`
`--no-tui` still exists as a hidden compatibility alias for headless mode.
## Dashboard attach/listen
Headless mode can publish dashboard state over a loopback websocket:
```bash
nntp-proxy --ui headless --tui-listen 127.0.0.1:8120
```
Another terminal can attach a read-only TUI client:
```bash
nntp-proxy --ui tui --tui-attach 127.0.0.1:8120
```
Rules:
- `--tui-listen` requires headless mode
- `--tui-attach` requires TUI mode
- Both addresses must stay on loopback
- The dashboard socket must be different from the main NNTP listener
## Routing modes
The config surface and CLI expose three modes:
| `per-command` | Stateless routing, each supported command may use a different backend |
| `hybrid` | Starts per-command and switches to a dedicated backend for stateful commands |
| `stateful` | One client session maps to one backend connection |
## Current runtime behavior
Hybrid is the default routing mode. `per-command` and `stateful` remain available as explicit modes, and the runtime honors the configured mode.
## What per-command mode supports
Per-command mode is meant for stateless operations, especially message-ID lookups such as:
- `ARTICLE <message-id>`
- `BODY <message-id>`
- `HEAD <message-id>`
- `STAT <message-id>`
- `LIST`
- `HELP`
- `DATE`
- `CAPABILITIES`
Commands that depend on selected group or current article state are not a good fit for `per-command` mode.
## CLI overrides
Most day-to-day runtime overrides map directly to config:
| `--config <FILE>` | `NNTP_PROXY_CONFIG` | config source |
| `--ui <MODE>` | `NNTP_PROXY_UI` | runtime UI |
| `--tui-listen <IP:PORT>` | `NNTP_PROXY_TUI_LISTEN` | dashboard publisher |
| `--tui-attach <IP:PORT>` | `NNTP_PROXY_TUI_ATTACH` | dashboard client |
| `--host <HOST>` | `NNTP_PROXY_HOST` | `[proxy].host` |
| `--port <PORT>` | `NNTP_PROXY_PORT` | `[proxy].port` |
| `--routing-mode <MODE>` | `NNTP_PROXY_ROUTING_MODE` | `[routing].mode` |
| `--backend-selection <STRATEGY>` | `NNTP_PROXY_BACKEND_SELECTION` | `[routing].backend_selection` |
| `--article-cache-capacity <SIZE>` | `NNTP_PROXY_ARTICLE_CACHE_CAPACITY` | `[cache].article_cache_capacity` |
| `--article-cache-ttl <SECONDS>` | `NNTP_PROXY_ARTICLE_CACHE_TTL_SECS` | `[cache].article_cache_ttl_secs` |
| `--store-article-bodies <BOOL>` | `NNTP_PROXY_STORE_ARTICLE_BODIES` | `[cache].store_article_bodies` |
| `--threads <N>` | `NNTP_PROXY_THREADS` | `[proxy].threads` |
CLI flags override the loaded config.
## Metrics persistence
Metrics are persisted to:
- `[proxy].stats_file` when set
- otherwise `stats.json` next to the config file
The dashboard uses that persisted state to survive restarts.