Live dashboard
The server serves a live, server-rendered dashboard at DASHBOARD_PATH (default
/deploy/dashboard). It uses htmx with Server-Sent Events; the htmx assets are vendored, so it
works offline. Cards refresh every DASHBOARD_REFRESH_MS (default 2000 ms).
Screens
Section titled “Screens”The top navigation has five screens plus a light/dark theme toggle:
- Live — the operational overview (cards described below).
- Agents — a per-agent table: name, ip, connection uptime, heap, agent-reported version, and connected/disconnected status.
- Config — the effective value of every configuration variable at runtime, with secrets masked.
- Aliases — the list of alias files and, for a selected alias, its commands
(
agents/name/arguments) plus the raw YAML. - Log — a tail of the server log file (
SERVER_LOG_FILE); shows an explicit reason when the file is unconfigured or empty.
Live cards
Section titled “Live cards”The Live screen streams these cards over {DASHBOARD_PATH}/events:
- Service — process uptime, heap usage, connected-agent count.
- Agents — the connected agent ids.
- Current task — the most recently executed deploy task and its state.
- Issues queue — issue ids waiting to be processed (with an inline form to enqueue one).
- Delivery — the durable Redmine/Telegram queues: pending, dead, sent, dead-lettered counts and send-latency percentiles (p50/p95/p99).
- Agent logs — a live tail of recent command output from the agents.
Enqueuing an issue
Section titled “Enqueuing an issue”The Issues queue card has a form that POSTs to {DASHBOARD_PATH}/issue with an issue_id
field, enqueuing the issue exactly as the webhook would. The endpoint is method-agnostic so a
reverse proxy may rewrite the POST to a GET without breaking it.
Behind a reverse proxy
Section titled “Behind a reverse proxy”The live cards, the Log tail and the Agent logs tail are Server-Sent Events streams
({DASHBOARD_PATH}/events, /log/events, /agentlog/events). Each stream flushes its response
headers immediately with a : connected comment, sends a : keepalive comment after 15 s of
silence, and sets X-Accel-Buffering: no, so nginx defaults (proxy_read_timeout 60s,
proxy_buffering on) work without tuning. A minimal location:
location /deploy { proxy_pass http://127.0.0.1:9090; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_buffering off; # optional: X-Accel-Buffering already disables it per response}If the deploy server sits behind a second proxy, that proxy must also pass the stream through
unbuffered (honour X-Accel-Buffering or set proxy_buffering off), or events arrive in bursts.