Files
AgentHub/docs/MONITORING.md
T
nntrivi2001 1c5521cf2e perf: rest animations, cheaper chat typing and server polls, async per-tool hooks
UI
- No animation runs forever: Sagi moods, the custom pet sprite, status dots
  (pulse-dot, pulse-slow, ping) and the chat shimmer play a few cycles and
  rest. An infinite animation kept the browser drawing 60 frames a second.
- useSagiBrain: frames that only move lastActivityAt by <1 s keep the old
  state; the 1 s tick re-renders only when the mood changes.
- ConversationView and MessageList are memoized and PaneChat passes stable
  callbacks: typing in the chat box no longer re-renders the conversation.
- The chat's 700 ms menu poll reads plain text first and scans the terminal
  cell by cell (reusing one cell) only when a row could be a menu cursor row.

Server
- GET /sessions/:id/transcript?after=N skips lines <= N before JSON.parse.
- GET /sessions/:id/outline is cached until the session's events change.
- broadcastLane uses the cached tmux.liveSessions(); tmux.hasSession answers
  "yes" from the fresh shared list instead of a synchronous spawn (50-150 ms
  per psmux call on Windows, blocking terminal echo).
- pane-mode polls every 150 ms; writeHourly writes only changed hour buckets.
- /api/metrics: agenthub_event_loop_delay_seconds{quantile}.

Hooks
- PreToolUse/PostToolUse run with "async": true (settings installer,
  plugin.json, S3 managed settings): Claude Code no longer waits a Node start
  before and after every tool call.

Committed with --no-verify at the owner's request: the pre-commit full server
suite fails on 9 tests that fail identically on 0c2f498 (lane-sync merge: no
git identity on this host; read-pool; resolveHost; codex-usage 1 ms flake).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:55:53 +07:00

3.4 KiB

Prometheus and Grafana for AgentHub

AgentHub exposes its live counters at GET /api/metrics in the Prometheus text format (see API.md § Prometheus exposition). monitoring/ holds a scrape config, recording rules and three Grafana boards built on those series, and docker-compose.monitoring.yml runs both tools with everything provisioned.

Files

Path What
monitoring/prometheus/prometheus.yml Scrape config: job agenthub, metrics_path: /api/metrics, target host.docker.internal:4820
monitoring/prometheus/agenthub-rules.yml Recording rules agenthub:* (sessions, agents, event and token rates, cost)
monitoring/grafana/dashboards/agenthub-overview.json Overview: up, version, active sessions, working agents, tokens and spend over 24 h, sessions/agents by status, events/min, token burn, RSS, uptime, websocket clients, remote sources
monitoring/grafana/dashboards/agenthub-sessions-agents.json Sessions & agents: counts by status, errored sessions, agents waiting on you, sessions finished per hour
monitoring/grafana/dashboards/agenthub-tokens-cost.json Tokens & cost: tokens per hour by kind, burn rate, cache-read share, spend all-time / 24 h, spend per hour by tool, spend by tool, top models by spend
monitoring/grafana/provisioning/ The Prometheus datasource and the dashboard provider for the compose stack
docker-compose.monitoring.yml Prometheus + Grafana, both on loopback only

The boards choose their datasource through a ds variable, so they also import as they are into an existing Grafana (Dashboards → New → Import).

Metrics used

agenthub_up, agenthub_build_info{version}, agenthub_process_uptime_seconds, agenthub_process_resident_memory_bytes, agenthub_event_loop_delay_seconds{quantile}, agenthub_sessions{status}, agenthub_agents{status}, agenthub_events_total, agenthub_websocket_clients, agenthub_remote_sources{enabled}, agenthub_tokens_total{kind}.

The spend panels and the agenthub:cost_usd:* rules read agenthub_cost_usd_total{tool,model} (estimated USD, only ever rising except when pricing is recomputed). A dashboard that does not export it yet leaves those panels empty; each one says so in its description. server/__tests__/monitoring.test.js fails if a board or rule queries any other metric server/routes/metrics.js does not export.

Run it with Docker

# 1. The dashboard on the host must accept the container's Host header
DASHBOARD_ALLOWED_HOSTS=host.docker.internal agenthub start   # or npm start
# 2. Prometheus + Grafana
GF_SECURITY_ADMIN_PASSWORD='choose-one' docker compose -f docker-compose.monitoring.yml up -d
# 3. Grafana: http://127.0.0.1:3000 (admin / the password above), folder "AgentHub"
#    Prometheus: http://127.0.0.1:9090

Without step 1 every scrape gets 403 EBADHOST (the DNS-rebinding guard). When the dashboard sets DASHBOARD_TOKEN, put the token in monitoring/prometheus/dashboard-token and uncomment the authorization block in prometheus.yml. Stop with docker compose -f docker-compose.monitoring.yml down (-v also drops the stored series).

Without Docker

Point an existing Prometheus at the dashboard — copy the agenthub job from prometheus.yml with the target changed to 127.0.0.1:4820 (no DASHBOARD_ALLOWED_HOSTS needed for loopback), add agenthub-rules.yml to its rule_files, and import the three JSON boards into Grafana.