Getting started¶
Install¶
virtufin-tui is published to a private index at
pypi.haenerconsulting.com, not public PyPI -- every install method below
needs credentials for it first. Use a Gitea personal access token (scope
read:packages) as the password.
One-off (inline credentials)¶
Simplest for a single machine / CI job -- embed credentials directly in the index URL:
export VIRTUFIN_REGISTRY_USER=<your-gitea-username>
export VIRTUFIN_REGISTRY_TOKEN=<your-gitea-token>
INDEX="https://${VIRTUFIN_REGISTRY_USER}:${VIRTUFIN_REGISTRY_TOKEN}@pypi.haenerconsulting.com/api/packages/virtufin/pypi/simple/"
# Recommended: use uvx (no install needed)
uvx --index "$INDEX" --from virtufin-tui virtufin-tui
# Or install via pip
pip install virtufin-tui --index-url "$INDEX" --extra-index-url https://pypi.org/simple
virtufin-tui
# Or install via uv into a project
uv add virtufin-tui --index "$INDEX"
Persistent (no credentials in shell history / process list)¶
pip, via ~/.netrc:
cat >> ~/.netrc <<EOF
machine pypi.haenerconsulting.com
login <your-gitea-username>
password <your-gitea-token>
EOF
chmod 600 ~/.netrc
pip install virtufin-tui \
--index-url https://pypi.haenerconsulting.com/api/packages/virtufin/pypi/simple/ \
--extra-index-url https://pypi.org/simple
uv, via the UV_INDEX env var (add to your shell profile):
export UV_INDEX="https://<your-gitea-username>:<your-gitea-token>@pypi.haenerconsulting.com/api/packages/virtufin/pypi/simple/"
uvx --from virtufin-tui virtufin-tui
uv add virtufin-tui # inside a project
Either way, public dependencies (textual, grpcio, pydantic, tomlkit,
etc.) still resolve from pypi.org as usual -- the private index is
additive, not a replacement for it.
First run¶
On first run, if ~/.config/virtufin/api/contexts.toml (or
~/.config/virtufin/tui/config.toml) doesn't exist yet, it's seeded from the
shipped defaults (a single local context pointing at localhost:5002) --
edit the copy under ~/.config to add other environments. A fuller template
lives at contexts.toml.example in the repo root.
Example contexts.toml:
[[contexts]]
name = "local"
api_host = "localhost"
api_port = 5002
description = "Local dev virtufin-api"
[[contexts]]
name = "staging"
api_host = "staging.virtufin.com"
api_port = 5002
tls = true
description = "Staging cluster"
default_worker_topic = "workmanager.lifecycle"
[[contexts]]
name = "kubernetes"
api_host = "api.virtufin.com"
api_port = 443
tls = true
worker_api_host = "api.virtufin.svc.cluster.local"
worker_api_port = 5002
description = "k3s cluster via ingress; workers dial the in-cluster Service directly"
The active context itself isn't set here -- it's state, not config; see Contexts.
Configuration¶
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Display name (must be unique within [[contexts]]) |
api_host |
string | required | Hostname of the virtufin-api gRPC endpoint |
api_port |
int (1-65535) | required | Port of the gRPC endpoint (typically 5002) |
tls |
bool | false |
Use TLS for the gRPC channel |
api_key |
string | unset (falls back to VIRTUFIN_API_KEY env var) |
Sent as x-api-key metadata on every call; required when the endpoint enforces API-key auth. See Contexts for the env-var fallback and error reporting. |
worker_api_host |
string | unset (falls back to api_host) |
Address a spawned worker process dials for its own Gateway callback; set for contexts where the worker runs somewhere api_host isn't reachable from (e.g. cluster-internal) |
worker_api_port |
int (1-65535) | unset (falls back to api_port) |
Port for worker_api_host |
default_worker_topic |
string | unset | Subscribe to this topic on start (typically workmanager.lifecycle) |
description |
string | "" |
Free-form label shown in the Config page's contexts table |
Environment variables override file values:
| Env var | Overrides |
|---|---|
VIRTUFIN_TUI_API_HOST |
api_host of the active context |
VIRTUFIN_TUI_API_PORT |
api_port of the active context |
VIRTUFIN_TUI_CONTEXT |
the active context (see Persistence in Contexts) |
Config file location: $XDG_CONFIG_HOME/virtufin/api/contexts.toml if
$XDG_CONFIG_HOME is set, otherwise ~/.config/virtufin/api/contexts.toml
on every OS (there's no platform-specific path like macOS's "Application
Support" or Windows's %APPDATA% -- the same ~/.config/... layout is
used everywhere). Runtime state (active context, active World/Scenario,
subscribed event topics) lives separately under $XDG_STATE_HOME
(default ~/.local/state), not in this file. The TUI's own log file
(tui.log, everything logged during a session -- see
Architecture) lives alongside that runtime state at
$XDG_STATE_HOME/virtufin/tui/tui.log, for the same reason: it's
generated output, not something you hand-author.
Switch context inside the TUI¶
Go to the Config tab (Infra → Config by default), highlight a row in the
contexts table, and press Enter. Switching closes the current gRPC
channel and opens a new one to the selected endpoint; the dashboard
refreshes within 1 second.
Development¶
git clone https://gitea.haenerconsulting.com/virtufin/virtufin-tui
cd virtufin-tui
uv sync
uv run virtufin-tui --context local
uv run pytest tests/
uv run ruff check src/ tests/
See Architecture for the data flow and Keybindings for the full keybinding table.