# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What This Is **pi-stat** is a fast status monitoring tool for Stellar Core nodes on the Pi Network. It provides quick system diagnostics as an alternative to the slow `pi-node status` command. ## Running ```bash ./pi-stat.py # Standard report ./pi-stat.py -p / --peers # Extended peer table ./pi-stat.py -g / --geo # With geolocation (implies -p) ./pi-stat.py -s / --show-ip # Show IP column (hidden by default) ./pi-stat.py -x / --extended # Show full RX/TX/RX-rate/TX-rate columns (default: ratio only) ./pi-stat.py -i [SEC] / --interactive [SEC] # Interactive auto-refresh (default: 10s) ``` No build step. Requires `pip install docker` and a running Docker daemon. Runs on Linux, WSL2, and Windows. ## Architecture Single self-contained script (`pi-stat.py`). Logic is split into helper functions and a `run_cycle()` function that collects data and renders one full screen, called either once (normal mode) or in a loop (interactive mode). ### Data sources - **Docker SDK** — container CPU/RAM stats; all commands run inside the auto-detected container (`mainnet` → `testnet2` → `testnet`, first running one) via `exec_run` - **Stellar Core HTTP API** — `exec_json()` runs `stellar-core http-command ` inside the container - **Horizon API** — `http://localhost:31401` - **PostgreSQL** — `psql` inside the container; used for peer DB counts and pubkey→IP mapping - **ZFS CLI** — `zpool`/`zfs` commands on the host for disk health (`z01pool`); if `zpool` is not found (`HAS_ZFS = False`), falls back to `shutil.disk_usage()` — works on Linux without ZFS, WSL2, and Windows - **ip-api.com** — batch geolocation (Country, City), cached in `_geo_cache`; only fetched with `-g` ### Output sections (in order) 1. Container stats — Docker CPU/RAM, Horizon + Core versions (skipped in `-p`/`-g` mode) 2. Disk — ZFS (`z01pool`) if `zpool` is available, otherwise `shutil.disk_usage()` (skipped in `-p`/`-g` mode) 3. Protocol status — Stellar Core state, ledger, quorum phase 4. API status — Horizon ingest lag 5. Peer connections — compact counts, or full table with `-p`/`-g` ### Interactive mode (`-i`) `interactive_loop()` renders via `run_cycle()` into a `StringIO` buffer, writes it atomically to avoid flicker, then waits for keypresses using `select` in `setcbreak` mode: - `d` — drop a single outbound peer (`do_drop_workflow`) - `a` — drop all outbound peers (`drop_all_workflow`) - `q` / Ctrl+C — clean exit with terminal state restore Outbound peers are numbered in the table. Full node IDs are fetched via `peers?fullkeys=true` for the `droppeer` API call. ### Key patterns - **Graceful degradation** — every external call is wrapped in try-except; missing data renders as `—` - **Dynamic column widths** — all table columns sized at runtime from actual data length - **NAT detection** — inbound peers with private IPs are replaced with their DB-stored public IP (`db_peer_addr` from PostgreSQL) - **Validator matching** — `load_validators()` parses `stellar-core.cfg` and indexes by IP, name, and public key; matched peers show a truncated key + `(Vn)` label - **Geo caching** — `_geo_cache` is a module-level dict; `geo_batch()` only fetches IPs not already cached - **Flag parsing** — manual `sys.argv` parsing; `-g` implies `-p`; `-i` accepts an optional next argument as the refresh interval