bee-tui 1.1.0

Production-grade k9s-style terminal cockpit for Ethereum Swarm Bee node operators.
Documentation

bee-tui

Crates.io CI Docs License: MIT OR Apache-2.0

Operator handbook: https://ethswarm-tools.github.io/bee-tui/ — full per-screen reference, command bar, keymap, FAQ.

A k9s-style terminal cockpit for Ethereum Swarm Bee node operators — nine live screens that surface the state Bee's API hides: bucket collisions, redistribution skip reasons, bin starvation, NAT reality, and a live HTTP tail so operators trust what they see.

bee-tui cold-start tour

 bee-tui   prod-1 @ http://10.0.1.5:1633   ping 12ms   UTC 14:32:18
 [Health]  Stamps  Swap  Lottery  Peers  Network  Warmup  API  Tags    :cmd · Tab · ? help
─────────────────────────────────────────────────────────────────────────────────────
HEALTH   prod-1 · http://10.0.1.5:1633     ping: 8ms

 ✓  API reachable                /health 200 in 3ms
 ⚠  Chain RPC                    block 8412930 · Δ +1
 ✓  Wallet funded                BZZ 27.97 · native 5.02
 ✓  Warmup complete              ready
 ✓  Peers                        87 connected
 ✓  Reserve                      65,536 chunks (in-radius: 65,536) · radius 8
 ⚠  Bin saturation               2 starving: bin 4, bin 5
        └─ manually `connect` more peers or wait — kademlia fills bins…
 ✓  Healthy for redistribution   yes
 ✓  Not frozen                   yes
 ✓  Sufficient funds to play     yes
─────────────────────────────────────────────────────────────────────────────────────
:cmd
┌ bee::http ──────────────────────────────────────────────────────────────────────────┐
│ 14:32:18  GET   /status                  200    3ms                                 │
│ 14:32:18  GET   /redistributionstate     200  104ms                                 │
│ 14:32:18  GET   /chainstate              200    0ms                                 │
└─────────────────────────────────────────────────────────────────────────────────────┘

Install

Prebuilt installer (Linux / macOS / Windows — no Rust toolchain required):

# Linux / macOS — picks the right tarball for your arch
curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/ethswarm-tools/bee-tui/releases/latest/download/bee-tui-installer.sh \
  | sh

# Windows (PowerShell)
powershell -c "irm https://github.com/ethswarm-tools/bee-tui/releases/latest/download/bee-tui-installer.ps1 | iex"

Or grab a tarball directly from the releases page. Builds are produced for aarch64-apple-darwin, x86_64-apple-darwin, aarch64-unknown-linux-gnu, x86_64-unknown-linux-gnu, and x86_64-pc-windows-msvc.

From source (needs Rust ≥ 1.85):

cargo install bee-tui

Quickstart

Point bee-tui at a running Bee node:

# Default config talks to http://localhost:1633
bee-tui

# Or point at a remote node via env
BEE_TUI_CONFIG=~/.config/bee-tui/config.toml bee-tui

# Force ASCII glyphs (Windows Terminal pre-Win11, screen readers, broken SSH chains)
bee-tui --ascii

# Suppress colour (also honours NO_COLOR env per <https://no-color.org>)
bee-tui --no-color

A minimal ~/.config/bee-tui/config.toml:

[[nodes]]
name    = "prod-1"
url     = "http://10.0.1.5:1633"
token   = "@env:BEE_TOKEN_PROD1"   # resolves at startup; never logged
default = true

[[nodes]]
name = "lab"
url  = "http://localhost:1633"

[ui]
theme           = "default"        # "default" | "mono"
ascii_fallback  = false            # true = same as `--ascii`

The @env:VAR token form keeps Bearer tokens out of the config file. With the local default profile, bee-tui works with zero config against a local Bee.

What you get

Nine operator screens plus an always-on command-log pane:

Screen What it answers
S1 Health "Why is my node unhealthy?" — 10 gates with WHY tooltips encoding tribal knowledge (e.g. "storageRadius decreases ONLY on the 30-min reserve worker tick").
S2 Stamps "Which batch is about to fail uploads?" — worst-bucket fill bar, immutable-vs-mutable rejection semantics (bee#5334), 5-state status ladder. drills into the per-bucket fill histogram.
S3 Swap / cheques Chequebook headroom (with on-chain contract address), per-peer net (received − sent) with |net| > 0.5 BZZ flagging, last-received cheque table.
S4 Lottery "Why am I not earning rewards?" — round timeline, anchor summary (last won / played / selected / frozen with Δ), stake card with frozen / unhealthy / insufficient-gas reasoning, on-demand r-key rchash benchmark.
S5 Warmup "What's Bee actually doing during the 25–60-minute cold start?" — five-step checklist with a depth-stability window.
S6 Peers Bin saturation strip (Empty / Starving / Healthy / Over) anchored on bee-go's SaturationPeers=8 and OverSaturationPeers=18 constants — surfaces the bin-starvation gap no other tool derives. drills into per-peer balance / cheques / settlement / ping.
S7 Network / NAT "Why am I unreachable?" — public-vs-private underlay classification, AutoNAT reachability with stability window (flickers under symmetric NAT).
S8 RPC / API health Bee API call stats (p50 / p99 latency, error rate over the last 100 calls), pending operator transactions.
S9 Tags / uploads "Where is my upload stuck?" — per-tag lifecycle counters (split → sent → synced) and a TagStatus ladder. Long lists scroll with j k / PgUp PgDn / Home.
S10 Command log Always-visible bee::http request tail (lazygit-style). The trust anchor — operators learn the API by watching it.

Drill panes

Two screens have a per-row drill that fans out to the relevant Bee endpoints on demand. Both follow the same UX: ↑↓ / j k move selection, opens the drill, Esc closes it.

  • S2 Stamps drill: fetches /stamps/{id}/buckets and renders a fill-percentage histogram (six bins from 0% to 100%) plus the top 10 worst buckets. Two batches with the same headline utilization can fail uploads under wildly different conditions — the drill answers how concentrated the load is.

    S2 stamp drill

  • S6 Peers drill: parallel fetch of peer_balance + peer_cheques

    • peer_settlement + ping_peer for the selected peer. Each field fails independently — a 404 on /chequebook/cheque/{peer} (peers you've never exchanged cheques with) shows error: 404 for that one field instead of blanking the drill.

    S6 peer drill

Keys

Tab / Shift+Tab cycle screens forward / backward
? toggle per-screen help overlay
: open command bar
qq quit (double-tap within ~1.5s; :q also works)
Ctrl+C / Ctrl+D quit immediately (escape hatch)
↑↓ / j k move selection (S2, S6) or scroll (S9)
drill selected row (S2, S6)
Esc close drill / overlay
r run rchash benchmark (S4 Lottery)
PgUp / PgDn / Home page through long lists (S9)

? is the source of truth for screen-specific keymaps — every screen advertises its keys in the overlay.

Copying values out of the cockpit: mouse mode is off by default, so your terminal's native selection works. Click-drag a peer overlay or batch ID, then paste it into a block explorer / Discord / etc. — bee-tui doesn't intercept it.

Command bar

:health, :stamps, :swap, :lottery, :peers, :network, :warmup, :api, :tags jump to that screen
:context <name> switch to another node from config.nodes
:diagnose export a redacted bundle to $TMPDIR/bee-tui-diagnostic-<ts>.txt (paste-ready for support threads — Bearer tokens never captured)
:pins-check walk every pinned root via /pins/check, write results to $TMPDIR/bee-tui-pins-check-<profile>-<ts>.txt (NDJSON streamed by Bee, collected and tail-friendly) — see demo
:loggers snapshot /loggers to $TMPDIR/bee-tui-loggers-<profile>-<ts>.txt, sorted loudest-first
:set-logger <expr> <level> call PUT /loggers/{exp}/{level} — bump a Bee subsystem to debug / info / etc. without curl
:quit, :q quit

Multi-node

Define multiple [[nodes]] in config.toml. The default profile loads at startup; :context <name> swaps the active connection without restarting. The top bar reflects the active profile.

Theme & accessibility

[ui]
theme           = "default"   # vibrant green/yellow/red
# theme         = "mono"      # monochrome — same status glyphs, no colour
ascii_fallback  = false       # true → ASCII glyphs (OK / X / ! / > / # / .)

Themes are slot-based (Pass / Warn / Fail / Accent / Dim / Info) — adding a new theme is one file. Glyphs are slot-based too: every component reads theme::active().glyphs.X rather than hardcoding , so --ascii (or ascii_fallback = true) flips every screen at once.

CLI overrides (highest priority):

  • --ascii — same as ascii_fallback = true
  • --no-color — same as theme = "mono"
  • NO_COLOR=1 env honours no-color.org

Runtime theme switching (:theme <name>) lands in v0.6.

Status

v1.0.0 on crates.io (May 2026). Full nine-screen cockpit with drill panes, command bar, multi-node, theme system, ASCII fallback, scrollbars, ? help overlay, and prebuilt installers for all five major targets.

Version Scope State
v0.1.0 S1 Health, S2 Stamps, S10 Command log; single-node; CI; insta tests ✅ shipped
v0.2.0 S3 SWAP, S4 Lottery, S5 Warmup, S6 Peers, S7 NAT, S8 RPC, S9 Tags, command bar, multi-node, theme system ✅ shipped
v0.9.0 :pins-check / :loggers / :set-logger, S2 + S6 drill panes, scrollbars, ? help, --ascii / --no-color, cargo-dist ✅ shipped
v1.0.0 Cold-start spinner, footer ? chips, copy-affordance docs, semver-stable surface ✅ shipped

Backed by bee-rs v1.6 (full coverage of the Bee 8.0.0 OpenAPI surface). Full screen specs in docs/PLAN.md.

Stack

  • Ratatui 0.30 — terminal UI framework
  • crossterm — terminal backend
  • Tokio — async runtime
  • bee-rs ≥ 1.6 — Bee API client
  • 106 lib + insta tests cover every gate / status ladder / drill view / scroll edge / glyph slot
  • MSRV 1.85, clippy --all-targets -- -D warnings clean

Contributing

Issues and PRs welcome at github.com/ethswarm-tools/bee-tui. The [lib] + [[bin]] layout makes integration tests cheap — every new screen should ship with insta snapshot tests of its pure view_for function. Drill panes follow the same pattern: pure compute_*_view fn + insta tests for realistic / pathological / empty inputs (see tests/s2_stamps_drill.rs and tests/s6_peers_drill.rs).

License

Dual-licensed under either Apache-2.0 or MIT at your option.