Appearance
Capstone: The Operations Console
The Operations Console is a Hermes-based server monitor that runs in Docker on a $5 VPS, alerts you on Telegram when something breaks, accepts commands to fix things, and has a desktop plugin showing live system status. Every piece of this capstone draws directly from the five days of the course. You'll build it by composing what you've already learned, not by starting from scratch.

What you'll learn
- A cron job runs system health checks every 30 minutes and alerts on Telegram when thresholds are breached
- A custom skill documents the health check procedure, the agent wrote it after the first successful run
- A Desktop plugin shows live gateway status, active session, current model, and last health check result
- Everything runs in a Docker container with resource limits, network isolation, and non-root user
Architecture
The Operations Console utilizes a multi-layered structure connecting scheduled jobs, client gateways, and isolated sandboxes. The following diagram maps the data flow and orchestration paths between these components:
What you're building
A health check skill , a
SKILL.mdthat documents the full procedure: check disk usage (df -h), memory (free -h), running services (systemctl is-activefor each service), and recent errors (journalctl --since "30 minutes ago" --priority=err). The agent creates this skill after you walk it through the procedure once.A cron job , fires every 30 minutes, runs the health check skill, compares results against thresholds (disk > 80%, memory > 90%, any service not active), and delivers alerts to your Telegram home channel.
Telegram command interface , from your phone, you can send:
/status, run the health check on demand/restart nginx, restart a service/logs nginx 50, get the last 50 lines of a service's logs/disk, show disk usage summary
A Desktop plugin , a pane that shows gateway connection status, active model, last health check timestamp, and a "Run Health Check" button that shows results inline.
Docker deployment , the entire setup runs in a Docker container with
memory: 512m,network: bridge(needs outbound for Telegram API),user: 1000:1000, and a mounted volume for persistent logs.
Prerequisites
Complete before starting:
- Installation & Provider Setup: Hermes installed and passing
hermes doctor - Writing Skills by Hand: comfortable with the SKILL.md format
- Cron Jobs: understand cron schedules, delivery, and context
- Gateway Architecture: gateway installed as a systemd service, at least one platform connected
- Terminal Backends: Docker backend configured
- Security: approval mode set to
smart, secret redaction enabled
Build it
Phase 1: Create the health check skill
Start a Hermes session and walk it through a full health check:
I want you to document a server health check procedure as a reusable skill.
Here's what we need to check every time:
1. Disk usage on all mounted filesystems (df -h). Flag anything above 80%.
2. Memory usage (free -h). Flag anything above 90%.
3. Running services: nginx, postgresql, docker, sshd.
For each, run 'systemctl is-active <service>'.
Flag any service that isn't active.
4. Recent errors: 'journalctl --since "30 minutes ago" --priority=err --no-pager'.
Summarize any errors found.
After each check, produce a summary: what's healthy, what's not, and
recommended actions for anything that's not healthy.
Now save this as a skill called "server-health-check".Hermes will run through the checks, verify the procedure works, and call skill_manage to write ~/.hermes/skills/server-health-check/SKILL.md. Verify it was created:
bash
hermes skills list | grep server-healthPhase 2: Create the cron job
To automate the monitoring checks, register a cron job with the agent that triggers the health check skill every 30 minutes and forwards alerts to Telegram:
bash
hermes cron create "every 30m" \
--name "Server Health Check" \
--prompt "Run the server-health-check skill. If any threshold is breached \
(disk > 80%, memory > 90%, any service not active), send an alert with the \
specific issue and recommended action. If everything is healthy, write a \
one-line summary to /var/log/hermes/health.log." \
--deliver telegramVerify that the cron registration is correct and active by manually triggering the job immediately:
bash
hermes cron run <job-id>Check your Telegram, you should receive the health check result.
Phase 3: Configure Telegram commands
Hermes in the gateway naturally responds to messages. The commands are just prompts:
- "Run the server-health-check skill and report results" (mapped to
/statusby convention) - "Restart the nginx service and confirm it's active" (mapped to
/restart nginx) - "Show the last 50 lines of nginx logs" (mapped to
/logs nginx 50) - "Show disk usage summary from df -h" (mapped to
/disk)
For structured command handling, write a skill that maps these patterns:
markdown
# telegram-ops-commands
## When to Use
When the user sends a message matching one of the command patterns below.
## Procedure
- `/status` or "status": Run the server-health-check skill and report results.
- `/restart <service>` or "restart <service>": Run systemctl restart <service>,
then systemctl is-active <service> to confirm. Report the result.
- `/logs <service> <n>` or "logs <service> <n>": Run journalctl -u <service>
-n <n> --no-pager and show the output.
- `/disk` or "disk": Run df -h and report usage percentages.Install the newly written skill module locally into your agent workspace directory:
bash
hermes skills install ./ops-commandsPhase 4: Build the Desktop plugin
Create ~/.hermes/desktop-plugins/ops-console/plugin.js:
javascript
import { jsx } from 'react/jsx-runtime';
import { useValue, host } from '@hermes/plugin-sdk';
import { StatusDot, Badge, Button, ScrollArea } from '@hermes/plugin-sdk';
export default {
id: 'ops-console',
name: 'Operations Console',
register(ctx) {
ctx.register({
id: 'ops-pane',
area: 'panes',
data: {
title: 'Ops Console',
placement: 'right',
dock: { pane: 'workspace', pos: 'bottom' },
height: '220px',
},
render: () => {
const gateway = useValue(host.state.gateway);
const model = useValue(host.state.model);
const sessionId = useValue(host.state.activeSessionId);
const cwd = useValue(host.state.cwd);
return jsx(ScrollArea, {
children: jsx('div', {
style: { padding: '12px', display: 'flex', flexDirection: 'column', gap: '8px' },
children: [
jsx('div', {
style: { display: 'flex', alignItems: 'center', gap: '8px' },
children: [
jsx(StatusDot, { status: gateway ? 'online' : 'offline' }),
jsx('span', { style: { fontSize: '13px' }, children: `Gateway: ${gateway ? 'Online' : 'Offline'}` }),
],
}),
jsx(Badge, { children: `Model: ${model || 'None'}` }),
jsx('div', { style: { fontSize: '12px', color: 'var(--ui-text-secondary)' }, children: `Session: ${sessionId || 'None'}` }),
jsx('div', { style: { fontSize: '12px', color: 'var(--ui-text-secondary)' }, children: `CWD: ${cwd || 'Unknown'}` }),
jsx(Button, {
size: 'sm',
onClick: async () => {
const result = await host.request('hermes.health', {});
host.notify({ kind: 'info', message: `Health check: ${result.status}` });
},
children: 'Run Health Check',
}),
],
}),
});
},
});
},
};Phase 5: Deploy in Docker
Construct a Dockerfile to package the application, dependencies, custom skills, and environment variables into a secure container:
dockerfile
FROM python:3.11-slim
RUN apt-get update && apt-get install -y curl systemd && \
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
RUN useradd -m -u 1000 deploy
USER deploy
WORKDIR /home/deploy
COPY config.yaml /home/deploy/.hermes/config.yaml
COPY .env /home/deploy/.hermes/.env
COPY skills/ /home/deploy/.hermes/skills/
CMD ["hermes", "gateway", "run"]Build the container image and launch the process with memory constraints and auto-restart policies configured:
bash
docker build -t hermes-ops .
docker run -d \
--name hermes-ops \
--memory=512m \
--cpus=1.0 \
-v /srv/hermes/logs:/var/log/hermes \
-v /var/run/docker.sock:/var/run/docker.sock \
--restart=always \
hermes-opsConfirm it worked
- Health check skill:
hermes skills list | grep server-healthshows the skill - Cron job:
hermes cron listshows the job withevery 30mschedule. Run it manually withhermes cron run <id>and confirm a Telegram alert arrives - Telegram commands: From Telegram, send
/status, the agent should run the health check and reply with results - Desktop plugin: Open the Desktop app, the Ops Console pane should be visible at the bottom of the workspace, showing live gateway status
- Docker:
docker psshows the container running.docker logs hermes-opsshows the gateway starting up
Module map, where each piece comes from
| Capstone component | Course lesson |
|---|---|
| Health check skill | Writing Skills by Hand |
| Cron job with Telegram delivery | Cron Jobs |
| Telegram command interface | Telegram Setup |
| Desktop plugin | Desktop Plugins |
| Docker deployment with limits | Terminal Backends |
| Security (approval mode, secret redaction) | Security |