I Built a Full Admin Dashboard for My AI Agent — Here's How

How I turned a headless CLI agent running on a €4/month VPS into a glassmorphic web dashboard with 15 pages, real-time monitoring, and full configuration management.


The Problem: My AI Agent Was a Black Box

I run Hermes Agent — an autonomous AI coding assistant — on a Hetzner Cloud VPS (4 vCPU AMD EPYC, 8GB RAM, €4/month). It connects to Telegram, processes cron jobs, manages my schedule, and even writes cricket score updates.

But here's the thing: I had no visibility into what it was doing.

Want to check if the gateway is running? SSH in, run systemctl status hermes-gateway. Want to see CPU usage? htop. Want to modify the config? vim ~/.hermes/config.yaml. Want to see conversation history? Query SQLite manually.

It worked, but it was tedious. I wanted a single pane of glass to monitor everything, modify configurations, and manage the agent — all from my browser.

So I built one.

What I Built

Hermes Admin Dashboard — a Next.js 16 web application that exposes every aspect of the agent through a clean, dark-themed UI. No external database. No separate backend. It reads directly from the agent's existing data sources.

Here's the main dashboard page:

Hermes Admin Dashboard - Main overview page showing system stats, connected platforms, and quick action buttons

The main dashboard — live CPU, memory, and disk stats, gateway status, connected platforms, and quick action buttons.

📊 15 Pages Across 4 Categories

Monitoring:

Alert Rules page showing alert creation form and active rules

Alert Rules — create CPU, memory, and gateway threshold alerts with Telegram notifications.

Audit Log page showing tracked dashboard actions

Audit Log — every config change, cron operation, and platform restart is recorded.

Configuration:

Configuration editor showing model settings, agent settings, and personality configs

Configuration Editor — structured form for config.yaml with tabs for Models, API Keys, Display, and Gateway.

Environment Variables page showing masked API keys

Environment Variables — view and edit .env with sensitive values automatically masked.

Agent MD editor showing the agent development guide

Agent MD — view and edit the agent's development guide directly in the browser.

Soul MD editor showing personality configuration

Soul MD — edit the agent's personality, behavior, and communication style.

Data:

Session history page showing conversation list

Session History — browse all conversations with search and pagination.

Memory viewer showing user profile, agent memory, and soul data

Memory Viewer — inspect what the agent remembers about you, its notes, and its soul data.

File browser showing directory navigation

File Browser — navigate the entire Hermes filesystem from your browser.

Log viewer with search and filtering

Log Viewer — browse log files with search, level filtering, and live streaming.

Skills browser showing all installed skills by category

Skills Browser — all installed skills organized by category (devops, mlops, research, etc).

Cron Jobs manager showing active scheduled tasks

Cron Jobs Manager — create, run, pause, and delete scheduled jobs with one click.

Processes page showing background processes

Background Processes — monitor all active Hermes processes.

Tools:

Model Playground for testing LLM models

Model Playground — test any LLM model interactively, verify API connectivity, and compare responses.

Config Backups page showing backup history

Config Backups — automatic backups before every edit, with one-click restore.

The Tech Stack

LayerTechnology
FrameworkNext.js 16 (App Router, Server Components, Standalone mode)
UIReact 19, Tailwind CSS 4, Lucide React icons
ChartsRecharts
AuthJWT (jose) + bcryptjs, middleware-based route protection
DataReads from SQLite (sessions), YAML (config), log files, env files
ExposureCloudflare Tunnel (zero open ports, auto HTTPS)
TestingPlaywright (18 E2E tests)

Total: 52 source files, ~7,800 lines of code, 23 API routes.

Architecture: Zero Infrastructure Overhead

The key design decision was no additional infrastructure. The dashboard doesn't create its own database or message queue. It reads directly from what the agent already generates:

Architecture diagram showing Browser, Cloudflare Tunnel, Next.js Server, File System, System Commands, and Hermes Agent

System architecture — Browser → Cloudflare Tunnel → Next.js Server → File System / System Commands / Hermes Agent.

No Redis. No PostgreSQL. No Docker. The Next.js standalone server runs directly on the VPS alongside Hermes, using 74MB of RAM.

The Tricky Parts

1. Platform Detection

Hermes supports 6 messaging platforms. Credentials can be in config.yaml OR in .env (environment variables like TELEGRAM_BOT_TOKEN). I had to check both sources:

// Check config.yaml
const hasConfig = !!config.telegram?.bot_token;

// Check .env
const hasEnv = !!process.env.TELEGRAM_BOT_TOKEN;

// Platform is enabled if EITHER has credentials
const enabled = hasConfig || hasEnv;

This fixed a bug where Telegram showed as "Disabled" even though it was running fine via env vars.

2. Config Validation

The config.yaml has a critical gotcha: setting api_key: '' in the YAML overrides environment variables. This silently breaks auth for cron jobs and background tasks. The dashboard now detects this:

3. Action Buttons That Actually Work

My first version had 4 action buttons on the dashboard (Restart Gateway, Clear Logs, Run All Cron, Take Backup). They looked great but 3 of 4 silently failed. The frontend was sending requests to API endpoints that didn't exist:

Nothing crashed, but nothing happened either. The catch {} blocks swallowed everything silently. I had to build the missing backend handlers, parse JSON responses, and show success/error banners.

4. Alert Creation — The Nested Object Bug

The alert form sends data as flat fields: {type: "cpu", threshold: 80, operator: "gt"}. But the backend expected a nested object: {type: "cpu", condition: {threshold: 80, operator: "gt"}}. Every create attempt failed with "type and condition are required."

Fixed with optional chaining to accept both formats:

const threshold = alert.condition?.threshold ?? alert.threshold ?? 80;
const operator = alert.condition?.operator ?? alert.operator ?? 'gt';

Security

Since the dashboard exposes config files (with API keys), environment variables, and system stats, security was critical:

Real-World Performance

Running on the same €4/month Hetzner VPS alongside Hermes Agent:

MetricValue
Dashboard memory usage~74 MB
Build size (standalone)60 MB
Source files52
Lines of code~7,800
API routes23
Pages15 (+ login)
Time to first paint< 200ms
Auto-refresh interval5 seconds
E2E tests18

The agent itself uses ~1.1 GB of the 8 GB RAM. The dashboard adds negligible overhead.

What's Next

Lessons Learned

  1. Always build the backend first. I built 4 beautiful action buttons that called non-existent API endpoints. They looked like they worked (loading spinners!), but silently did nothing.
  2. Validate your data contracts early. The flat-vs-nested object mismatch for alerts took one line to fix but an hour to debug because the error message was generic.
  3. Silent catch {} blocks are evil. Every error should at least log. I replaced all empty catches with proper error feedback.
  4. Read from existing data sources when possible. No need for a separate database when your agent already stores everything in SQLite, YAML, and log files.
  5. Cloudflare Tunnel is the easiest way to expose a local service. Zero open ports, auto HTTPS, DDoS protection. One command and it's live.

The Repo

All code is open source: github.com/vinoth12940/hermes-dashboard

Built with Next.js 16, React 19, Tailwind CSS 4, and zero additional infrastructure.


If you're running AI agents or self-hosted services on a VPS, I'd love to hear how you monitor them. Drop a comment!

#AI #NextJS #WebDevelopment #SelfHosted #DevOps #React #Dashboard #OpenSource