Admin Dashboard - Z-M-Huang/openhive GitHub Wiki
Admin Dashboard
Operator dashboard for observing OpenHive system state. The agent acts; the dashboard observes. Purpose-built views over the SQLite data model -- not a SQL browser, not a config editor.
See Architecture for system overview, Architecture-Decisions#ADR-31 for rationale, and Scenarios#14 for an operational walkthrough.
Table of Contents
- Overview
- Technology Stack
- REST API Endpoints
- Dashboard Views
- Frontend File Structure
- Visual Design
- Deliberately Excluded from v1
- Cross-References
Overview
The admin dashboard is an observability-first operator tool served from the same Docker container as the main process. It provides consolidated views of system health, org structure, task queues, logs, memories, triggers, conversation history, and plugin tool state -- everything an operator needs to diagnose issues without running SQLite queries.
The only dashboard-initiated mutations are trigger enable/disable toggling and plugin tool lifecycle actions (deprecate/remove). All other mutations go through the agent via normal channels.
Access model: Local-only. No authentication. For remote access, front the dashboard with a reverse proxy that provides auth (Traefik, Cloudflare Tunnel, or similar).
Technology Stack
| Aspect | Choice | Rationale |
|---|---|---|
| Frontend | Vanilla HTML/CSS/JS | No React, no Vue, no build step, no npm on frontend |
| Serving | Fastify via @fastify/static |
Serves /app/public/ directory; no companion container |
| API | REST under /api/v1 |
JSON responses; reuses existing SQLite data access layer |
| Container | Same Docker container | No additional infrastructure; dashboard is a static asset |
| Auth | None | Local-only tool; reverse proxy for remote access |
Zero frontend build toolchain. Files in /app/public/ are served as-is. The API routes import existing store instances from OrgToolContext -- no new data access code beyond query composition.
REST API Endpoints
All endpoints are mounted under /api/v1. Responses are JSON. The API is read-only except for trigger state toggling and plugin tool lifecycle actions (deprecate/remove).
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/overview |
GET | Health + aggregated stats (uptime, SQLite size, team count, queue depth) |
/api/v1/teams |
GET | Org tree with aggregated stats per team |
/api/v1/teams/:name |
GET | Single team detail (config, scope, queue, active sessions) |
/api/v1/tasks |
GET | Paginated tasks (team, status, type, limit, offset query params) |
/api/v1/tasks/:id |
GET | Single task detail |
/api/v1/tasks/stats |
GET | Counts by status, type, and priority |
/api/v1/logs |
GET | Paginated log entries (level, team, since, search, limit query params) |
/api/v1/memories |
GET | Paginated memories (team, type, search, limit query params) |
/api/v1/memories/:id/chain |
GET | Supersede chain for a memory (full lineage) |
/api/v1/triggers |
GET | All triggers (team, state filters) |
/api/v1/triggers/:id/enable |
POST | Enable a trigger (pending/disabled -> active) |
/api/v1/triggers/:id/disable |
POST | Disable a trigger (active -> disabled) |
/api/v1/topics |
GET | Conversation topics (state filter) |
/api/v1/interactions |
GET | Message history (channel, team, limit query params) |
/api/v1/vault |
GET | Vault entries for a team (team required; returns keys + metadata, values NEVER shown for is_secret=1) |
/api/v1/vault/:team/:key |
GET | Single vault entry detail (value shown for is_secret=0 only; is_secret=1 returns key + metadata, no value) |
/api/v1/learning |
GET | Learning status summary (team filter; journal summary, last run, topic coverage) |
/api/v1/learning/:team/journal |
GET | Full learning journal for a team (topic_coverage, sessions_completed, sources_visited, deprioritized_sources) |
Query patterns: Pagination uses limit + offset. Filtering uses query parameters. All endpoints return { data, total?, error? } envelopes.
| /api/v1/trust/audit | GET | Trust audit log (since, decision, limit filters) |
Plugin Tool Management Endpoints
Plugin tool lifecycle and security audit endpoints:
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/tools |
GET | List all plugin tools across teams (team filter optional) |
/api/v1/tools/:team/:name |
GET | Single tool detail (source code, verification status, security scan results) |
/api/v1/tools/:team/:name/deprecate |
POST | Mark tool as deprecated (prevents new sessions from loading) |
/api/v1/tools/:team/:name/remove |
POST | Delete tool file (requires deprecated status first) |
/api/v1/tools/audit |
GET | Recent tool invocations, blocked attempts, security violations |
/api/v1/tools and /api/v1/tools/:team/:name read lifecycle state and verification summaries from the SQLite plugin_tools table, then join source code from .run/teams/{team}/plugins/{name}.ts. deprecate updates the SQLite row to deprecated; remove deletes the file and archives the metadata row (status set to removed, row preserved for audit trail).
Tool listing response returns an array of tool objects, each containing the team name, tool name, namespaced name, file path, lifecycle status, verification summary, creation/verification timestamps, and 24-hour invocation count. Tool detail response extends the listing fields with the full source code, granular verification results (TypeScript validity, interface compliance, security scan findings), the list of skills that declare the tool, and the last invocation timestamp. In both responses, status and verification come from persisted SQLite metadata; source_code (in detail responses) comes from the plugin file on disk.
Vault API security note: The /api/v1/vault and /api/v1/vault/:team/:key endpoints NEVER return the value field for entries where is_secret=1. Not even masked. The response includes key, is_secret, updated_by, created_at, and updated_at -- but the value is omitted entirely. This matches the vault_list tool behavior (see Organization-Tools).
Dashboard Views
Ten views ship in v1. Each corresponds to a primary data domain and one or more API endpoints.
1. System Health Overview
Aggregated system state at a glance.
- Uptime, SQLite database size, total team count
- Queue backlogs (pending/running tasks across all teams)
- Trigger health (active count, recent failures, circuit-breaker trips)
- Auto-refreshes on a configurable interval
2. Live Org Tree
Visual hierarchy of the team structure.
- Tree rendering of parent-child relationships from
OrgStore - Per-node: team status, queue depth, scope keywords
- Expand/collapse with drill-down to team detail
3. Task Queue Dashboard
Operational view of the task pipeline.
- Pending, running, done, failed, and cancelled tasks
- Filters: team, task type, priority, status
- Sortable columns with pagination
- Task detail on click (full task record, delegator, result)
4. Log Viewer
Structured log search over the log_entries table.
- Filters: level, team, time range, free-text search
- Expanded view shows full
contextJSON (team, taskId, tool name, duration) - Level-based color coding (error = red, warn = amber, info = neutral)
5. Memory Browser
Browse and inspect the memory system.
- Filter by team and memory type (identity, lesson, decision, context, reference, historical)
- View supersede chains: select a memory, see its full lineage via
/memories/:id/chain - Badges distinguish injected types (identity, lesson, decision, context) from search-only types (reference, historical)
6. Trigger Manager
View and manage trigger state machines.
- All triggers with current state (pending, active, disabled), type, failure count
- Filter by team and state
- Enable/disable toggles
- Failure count and circuit-breaker status visible per trigger
- Overlap policy per trigger (
skip-then-replace,always-skip,always-replace,allow) - Overlap count: current consecutive overlap counter (0 = normal, 1+ = has been skipped)
- Active task ID: links to task queue entry when a triggered task is pending or running
- Visual badge when a trigger is in "overlap skipped" state (overlap_count > 0)
7. Conversation History
Message flow and topic lifecycle.
- Inbound and outbound messages with timestamps
- Topic states (active, idle, done) with filter
- Channel activity breakdown (WebSocket, Discord)
The Trust Audit Viewer for the trust_audit_log table is accessible via /api/v1/trust/audit.
8. Vault Browser
Browse team vault entries with enforced secret protection.
- Filter by team name
- Displays all vault keys with metadata:
key,is_secret,updated_by,created_at,updated_at - Values shown for
is_secret=0entries (team state data) - Values NEVER shown for
is_secret=1entries -- not even masked. The value column is omitted entirely for secret rows. This is a hard security boundary: the dashboard never requests, receives, or displays secret values - Badge distinguishes secret entries (locked icon) from state entries
- Click-through to single entry detail via
/api/v1/vault/:team/:key
9. Learning Status
Monitor autonomous learning cycle progression. Learning triggers are per subagent (ADR-40), not per team — the dashboard aggregates across subagents within a team.
- Filter by team name, then by subagent
- Trigger state per subagent: displays whether
learning-cycle-{subagent}is active or disabled (matches trigger manager state) - Summary panel per subagent:
sessions_completed,last_runtimestamp, total findings stored across all topics - Topic coverage table: one row per learning topic showing
last_searched,searches_completed,findings_stored,findings_discarded,consecutive_no_findings,next_focus(if set) - Corroboration confidence per finding: displays corroboration count and confidence level (single/partial/corroborated)
- Exhausted topics visually flagged (dimmed row, "exhausted" badge when
consecutive_no_findings >= 3) - Deprioritized sources: count displayed in summary panel; expandable list showing URL, reason, and
sincetimestamp - Sources visited expandable per topic: URL,
last_fetched,yielded_findingstatus - Per-subagent readiness gate status: displays whether each gate (tool bundle,
bootstrapped=1,scope_keywords) is satisfied or blocking. See Architecture-Decisions#ADR-35 - Click-through to full journal via
/api/v1/vault/:team/learning:{team}:{subagent}:journal
Reflection Status
- Trigger state per subagent:
reflection-cycle-{subagent}active or disabled - Last reflection run: timestamp, diagnosis summary, outcome (change applied / skipped)
- Reflection journal viewer: click-through to vault journal via
/api/v1/vault/:team/reflection:{team}:{subagent}:journal - See Architecture-Decisions#ADR-37
Stall Detection Monitor
- Pending task counts exceeding thresholds (>1 hr warning, >24 hr error)
- Stalled task table: task ID, team, age, severity, last status change
- Escalation history: recent stall detection alerts with resolution status
- Stall detection is engine-level infrastructure, not a managed trigger. It does not appear in the Trigger Manager panel.
- See Architecture-Decisions#ADR-38
10. Plugin Tools Manager
View and manage team-local plugin tools.
- Filter by team name
- List all plugin tools with namespaced name, verification status, invocation count
- Status indicators: active, deprecated, failed verification
- Click-through to tool detail: source code, verification results, security scan
- Lifecycle state and verification badges are sourced from the SQLite
plugin_toolstable; source code is read from the team plugin directory - Lifecycle actions:
- Deprecate — marks tool as deprecated, prevents new sessions from loading it
- Remove — deletes tool file (requires deprecated status first)
- Security audit view: recent invocations, blocked attempts, forbidden pattern detections
- Skills using each tool: shows which skills declare the tool in
## Required Tools
Frontend File Structure
The frontend follows a single-page architecture rooted in public/. The SPA shell (index.html) loads a single stylesheet and a hash-based router (app.js). Ten view modules (health.js, org-tree.js, tasks.js, logs.js, memories.js, triggers.js, conversations.js, vault.js, learning.js, plugin-tools.js) each export a render(container) function called by the router. Shared components include a sortable table, tree renderer, filter bar, and toast notifications. Hash-based routing (#/health, #/tasks, etc.) means no server-side routing is required.
Visual Design
Premium dark theme with glassmorphism aesthetics. No external CSS frameworks -- hand-crafted CSS.
| Property | Value |
|---|---|
| Theme | Dark with CSS custom properties for theming |
| Cards | Glassmorphism: backdrop-filter: blur(), semi-transparent backgrounds |
| Animations | Smooth transitions on view changes and data refresh |
| Typography | Monospace accent font for data and metrics |
| Status indicators | Glow effects color-coded by state |
| Layout | Responsive, optimized for tablet monitoring |
All visual tokens are CSS custom properties, making it straightforward to add a light theme or adjust branding without touching component code.
Deliberately Excluded from v1
| Exclusion | Reason |
|---|---|
| Rule/config editing | Too dangerous without a governance UI; agents manage rules through normal channels |
| Raw SQL browser | Structured views cover 95% of operator needs; raw SQL risks accidental mutations |
| Team creation/deletion | Should go through the agent for governance enforcement |
| Build toolchain | Zero npm on frontend; files served as-is |
| Authentication | Local-only tool; reverse proxy for remote access |
These are intentional scope boundaries, not missing features. Each was evaluated and deferred to avoid scope creep and security surface area.
Cross-References
- Architecture -- system overview, code inventory, data layout
- Architecture-Decisions#ADR-31 -- dashboard architectural decision
- Organization-Tools --
OrgToolContextprovides the store instances used by API routes - Memory-System --
memories/memory_chunksschema for the Memory Browser - Logging --
log_entriesschema for the Log Viewer - Triggers -- trigger state machine, circuit breaker, management tools
- Conversation-Threading -- topic lifecycle for the Conversation History view
- Architecture-Decisions#ADR-32 -- team vault (vault browser data source)
- Architecture-Decisions#ADR-33 -- autonomous learning system (learning status data source)
- Scenarios#14 -- Admin Dashboard Access walkthrough