Ratatui streaming dashboard (fxt watch) with 4 tabs, stub command wiring plan, and new ApproveModel/RejectModel proto RPCs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.2 KiB
FXT Dashboard & CLI Completion Design
Goal
Finalize fxt as a fully functional CLI with a live streaming dashboard (fxt watch) and all stub commands wired to real gRPC backends.
Workstream 1: fxt watch — Ratatui Streaming Dashboard
Architecture
Single-binary TUI using ratatui + crossterm. Event loop:
tokio::select! {
msg = grpc_rx.recv() => update state, mark dirty
key = crossterm_events() => handle tab switch / scroll / quit
_ = tick_interval.tick() => if dirty { render frame }
}
Tick rate: 200ms (5 fps). Only re-render when dirty.
Tabs
Tab 1 — Training (default)
┌─ Training ──────────────────────────────────────┐
│ Model Epoch Loss LR ETA GPU │
│ DQN 34/100 0.0023 1e-4 12m 78% │
│ PPO 12/50 -0.451 3e-4 8m 82% │
│ TFT 7/200 0.0891 5e-4 45m 91% │
├─────────────────────────────────────────────────┤
│ Loss ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁▂▃▄▅ (last 200 epochs) │
│ GPU% ████████████░░░░░░░░ 78% │
└─────────────────────────────────────────────────┘
Feeds: StreamTrainingMetrics
Tab 2 — Trading
┌─ Trading ───────────────────────────────────────┐
│ Symbol Side Qty Entry PnL Status │
│ ES.FUT LONG 2 5,432 +$340 OPEN │
│ NQ.FUT SHORT 1 19,876 -$120 OPEN │
├─────────────────────────────────────────────────┤
│ Recent Fills │
│ 14:32:01 BUY ES.FUT 2 @ 5,432 FILLED │
│ 14:31:45 SELL NQ.FUT 1 @ 19,876 FILLED │
├─────────────────────────────────────────────────┤
│ Day PnL: +$220 | Realized: +$580 Unreal: -$360│
└─────────────────────────────────────────────────┘
Feeds: StreamTradingUpdates
Tab 3 — Risk
┌─ Risk ──────────────────────────────────────────┐
│ Portfolio VaR (95%): $2,340 Max DD: -3.2% │
│ Kelly Fraction: 0.34 Leverage: 1.8x │
├─────────────────────────────────────────────────┤
│ Circuit Breakers │
│ ● Daily Loss OK ($220 / $5,000 limit) │
│ ● Drawdown OK (3.2% / 10% limit) │
│ ● Volatility OK (VIX 18.3 / 40 limit) │
│ ○ Kill Switch ARMED │
└─────────────────────────────────────────────────┘
Feeds: StreamRiskMetrics
Tab 4 — System
┌─ System ────────────────────────────────────────┐
│ Service Status Latency Uptime │
│ api-gateway ● UP 2ms 14d │
│ trading-service ● UP 1ms 14d │
│ ml-training ● UP 3ms 6h │
│ trading-agent ● UP 1ms 14d │
├─────────────────────────────────────────────────┤
│ GPU: ████████████░░░░ 78% VRAM: 32/48 GB │
│ CPU: ██████░░░░░░░░░░ 38% RAM: 42/128 GB │
└─────────────────────────────────────────────────┘
Feeds: StreamSystemHealth, StreamGpuMetrics
Key Bindings
1-4 switch tabs, j/k scroll, q quit
State Model
Single DashboardState with per-tab substates. Ring buffers (200 points) for chart data.
gRPC Streams
One tokio::spawn per stream, all feed a single mpsc::channel<StreamEvent>. Reconnect with exponential backoff (1s→30s).
Dependencies
ratatui = "0.29", crossterm = "0.28" in bin/fxt/Cargo.toml.
Workstream 2: Wire Stub Commands
A. Uncomment Only
| Command | Fix |
|---|---|
fxt tune start --watch |
Uncomment pub mod tune_stream; in commands/mod.rs:27. Full implementation exists. |
B. Wire to Existing RPCs
| Command | Current | Fix |
|---|---|---|
fxt model list |
Placeholder text | Call MLTrainingService::ListModels. Display table. |
fxt agent allocate-portfolio |
Hardcoded mock assets | Replace mock block (agent.rs:192-212) with GetSelectedAssets(selection_id). |
fxt auth login (non-interactive) |
Simulated JWT | Use same LoginClient as interactive path, pass args. |
C. New Proto RPCs
| Command | RPC | Proto | Request | Response |
|---|---|---|---|---|
fxt model approve |
ApproveModel |
ml_training.proto | {model_id, promoted_to} |
{success, message} |
fxt model reject |
RejectModel |
ml_training.proto | {model_id, reason} |
{success, message} |
Server handlers in ml_training_service/: move checkpoint, update DB status.
Workstream 3: Testing
- Unit: state update functions with mock
StreamEventdata - Unit: all fixed commands with mock gRPC servers
- Integration: spawn mock server, run dashboard 2s, assert no panic
- Existing tests: 134 fxt tests must stay green
Not In Scope
- Custom themes / color configuration
- Mouse support
- Persisted layout preferences
- Log file export from dashboard