HUD Architecture¶
This page explains how the HUD is structured internally. Read it before debugging a panel or adding a new one.
Data Flow¶
graph TD
DB[(raise.db)] --> DM["HUDDataManager\n(data.py)"]
DM -->|"missions, active_mission,\nmissions_detail"| MP[MissionsPanel]
DM -->|"active_session, session_state,\nmission, signals, pipeline_runs"| SP[SessionPanel]
DM -->|pipeline_runs| PP[PipelinePanel]
DM -->|signals| EP[EventsPanel]
DM -->|"session_index, skill_events, kpis"| IP[InsightsPanel]
TIMER["Poll Timers\n(app.py)"] -->|"3s / 5s / 30s"| DM
raise.db is the only data source. No panel reads the database directly.
Module Responsibilities¶
| Module | Responsibility | Does NOT |
|---|---|---|
app.py |
Composes the TUI, owns keybindings, schedules poll timers | Read from DB directly |
data.py |
Single gateway to raise.db — all queries through HUDDataManager |
Import Textual |
panels/missions.py |
Navigable mission list (left) + coordinator detail pane (right) | Query DB |
panels/session.py |
Active session state, mission progress bar, HITL gates | Query DB |
panels/pipeline.py |
Sortable DataTable of pipeline runs with phase chain | Query DB |
panels/events.py |
Signal console with filter bar and status line | Query DB |
panels/insights.py |
Delivery KPIs (velocity, cycle time, flow efficiency) and token health | Query DB |
Poll Cycle¶
Three independent intervals are set in app.py:79-81:
| Interval | Method | What it refreshes | Why |
|---|---|---|---|
| 3 s | _poll_signals |
New lifecycle signals | Signals are bursty; Events tab needs near-real-time updates |
| 5 s | _poll_fast |
Active session, missions, pipeline runs | Frequent enough to feel live without saturating SQLite |
| 30 s | _poll_slow |
Session index, KPIs, token health | Expensive aggregations; trend data tolerates higher latency |
action_refresh (key r) triggers all three immediately on demand.
Panel Contract¶
Every panel exposes a single update_data(**kwargs) method. HUDDataManager pushes data to each panel; the panel owns all rendering logic. Panels never pull data themselves.
| Panel | update_data keyword args |
|---|---|
MissionsPanel |
missions: list[Mission], active_mission: Mission \| None, missions_detail: dict \| None |
SessionPanel |
active_session: dict \| None, session_state: SessionState \| None, mission: Mission \| None, signals: list[dict], pipeline_runs: list[dict], last_closed_session: dict \| None |
PipelinePanel |
pipeline_runs: list[dict] |
EventsPanel |
signals: list[dict] |
InsightsPanel |
session_index: list[dict], skill_events: list[dict], kpis: dict \| None |
When adding a new panel, implement update_data(**kwargs) and register the call in app.py's _poll_fast or _poll_slow method depending on the data's refresh requirements.
What's Next¶
- Extension Guide — step-by-step: Hello World panel → data-driven panel → poll-driven panel (coming in a future release)