AI Agent — Hermes Autonomous Agent
Purpose
Autonomous AI Agent service powered by Hermes, providing intelligent task automation with security controls for code review and development tasks.
Entry Point
- Main file: ai-agent.nix
- Upstream: Hermes Agent
- Package: The module routes
services.hermes-agent.packagethrough the localpkgs.hermes-agentoverlay, which carries a few upstream patches.
Options
services.ai-agent.apiServer.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable the OpenAI comptable endpoint.
services.ai-agent.apiServer.host
| Type | string |
| Default | "127.0.0.1" |
The host/IP for the API server to bind to.
services.ai-agent.apiServer.port
| Type | signed integer |
| Default | 8642 |
The port for the API server to listen on.
services.ai-agent.apiServer.tokenReference
| Type | string |
| Default | "AI_AGENT/API_SERVER_TOKEN" |
The sops secret attribute for the API server authentication token.
services.ai-agent.containerPostStart
| Type | list of (string or (submodule)) |
| Default | [ ] |
Shell commands to run inside the AI agent container after startup.
A plain string runs inside the container as root via docker exec.
An attrset { command = "..."; host = true; } runs on the host.
Commands to run after the AI agent container starts. Container commands get automatic retry to wait for Docker + container readiness.
services.ai-agent.dashboard.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable Hermes web dashboard.
services.ai-agent.dashboard.oidc.clientId
| Type | string |
The OIDC client ID for dashboard authentication.
services.ai-agent.dashboard.oidc.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable OpenID Connect authentication for the dashboard.
services.ai-agent.dashboard.oidc.issuer
| Type | string |
The OIDC issuer URL for dashboard authentication.
services.ai-agent.dashboard.oidc.provider
| Type | string |
| Default | "self-hosted" |
The OIDC plugin to use for dashboard authentication.
services.ai-agent.dashboard.oidc.scopes
| Type | list of string |
| Default | [ "openid" "profile" "email" ] |
The OIDC scopes to request for dashboard authentication.
services.ai-agent.dashboard.port
| Type | signed integer |
| Default | 9119 |
The port for the dashboard to listen on.
services.ai-agent.dashboard.publicURL
| Type | null or string |
| Default | null |
The public URL for the dashboard, used for generating links in notifications and similar. If not set, localhost URLs will be used.
If set, must be a valid URL starting with http:// or https://.
services.ai-agent.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable autonomous AI Agent service.
services.ai-agent.extras.browser
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable headless browser for web scraping and automation.
services.ai-agent.extras.plugins
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable extra plugins for the agent.
services.ai-agent.extras.scraper.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable web scraping and search plugins for the agent.
services.ai-agent.extras.scraper.searxEndpoint
| Type | null or string |
| Default | null |
The SearxNG endpoint to use for web search.
services.ai-agent.memory.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable long-term memory
When enabled this disables the builtin user profile and memory markdown features, to nudge the agent towards using the configured long-term memory provider for all memory. .
services.ai-agent.models.brains
| Type | string |
| Default | "deepseek/deepseek-v4-pro-0813" |
The smartest model to use for complex reasoning and decision-making tasks.
Used for auxiliary models:
services.ai-agent.models.compression
| Type | string |
| Default | "~deepseek/deepseek-v4-flash-latest" |
The model to use for compression of context, summorisation and similar tasks that don’t require reasoning. This model still needs a decently sized context window to be effective.
Used for auxiliary models:
services.ai-agent.models.primary
| Type | string |
| Default | "~deepseek/deepseek-v4-flash-latest" |
The primary language model to use for the AI agent.
services.ai-agent.models.provider
| Type | string |
| Default | "openrouter" |
The model provider to use.
services.ai-agent.models.simpleton
| Type | string |
| Default | "inclusionai/ling-3.0-flash" |
The simpleton model to delegate tasks to that require less reasoning, basic understanding and small context windows.
Used for auxiliary models:
services.ai-agent.models.vision
| Type | string |
| Default | "xiaomi/mimo-v2.5" |
The vision model to delegate image understanding tasks to.
services.ai-agent.platform.discord.allowedUsers
| Type | list of string |
| Default | [ ] |
A list of Discord user IDs that the agent is allowed to interact with.
services.ai-agent.platform.discord.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable Discord as a messaging channel.
services.ai-agent.platform.discord.homeChannel
| Type | null or string |
| Default | null |
The Discord channel ID to use as the home channel for the agent.
services.ai-agent.platform.discord.tokenReference
| Type | string |
| Default | "AI_AGENT/DISCORD_BOT_TOKEN" |
The sops secret attribute for the Discord bot token.
services.ai-agent.platform.hassio.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable Home Assistant as a tool and notification channel.
services.ai-agent.platform.hassio.tokenReference
| Type | string |
| Default | "AI_AGENT/HASSIO_TOKEN" |
The sops secret attribute for the Home Assistant long-lived access token.
services.ai-agent.platform.hassio.url
| Type | string |
The URL for the Home Assistant instance, including the scheme.
services.ai-agent.platform.webhook.port
| Type | signed integer |
| Default | 8654 |
The port for the webhook listener to listen on.
services.ai-agent.settings
| Type | Hermes config attrs, deep-merged with list concatenation. |
| Default | { } |
Hermes config to merge into services.hermes-agent.settings.
This is a local option that merges correctly across feature toggles.
The upstream services.hermes-agent.settings uses lib.recursiveUpdate for its config type,
which replaces lists instead of concatenating them, so separate blocks would clobber each other.
This option deep-merges with list concatenation and is emitted once as the final value of services.hermes-agent.settings.
services.ai-agent.voice.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable voice input and output using the TTS and STT.
services.ai-agent.voice.wyoming-stt.enable
| Type | boolean |
| Default | false |
| Example | true |
Whether to enable use existing Wyoming faster-whisper server for STT instead of running a separate Whisper instance.
services.ai-agent.voice.wyoming-stt.host
| Type | string |
| Default | "localhost" |
The host of the Wyoming faster-whisper server.
services.ai-agent.voice.wyoming-stt.port
| Type | signed integer |
| Default | 10300 |
The port of the Wyoming faster-whisper server.
Architecture / Services / Scope
The module enables services.hermes-agent (running inside a Docker container) and adds optional components on top:
- Dashboard — a separate
hermes-dashboardsystemd service runsdocker execinto thehermes-agentcontainer to serve the dashboard under thehermesuser. Environment files configured viaservices.hermes-agent.environmentFilesare loaded by systemd’sEnvironmentFiledirective (read as root) and passed into the container viadocker exec --env-file. The dashboard stays local by default and does not open a browser. - Voice & STT — optional voice input and output. With
services.ai-agent.voice.wyoming-stt.enable, Hermes reuses an existing Wyoming faster-whisper server instead of running a separate Whisper instance:HERMES_LOCAL_STT_COMMANDis set to invokewyoming-transcribe, which sends audio over the Wyoming protocol and returns the transcript. No second Whisper process needed. - OIDC Authentication — optional OpenID Connect authentication for the dashboard using a public PKCE client (no
client_secret). The client ID is a public identifier — it does not need to be stored as a secret. The module generates aHERMES_DASHBOARD_OIDC_ENVenvironment file with the OIDC settings, loaded by thehermes-dashboardservice. - Memory (Mnemosyne) — with
services.ai-agent.memory.enable, the memory provider switches from the built-in user profile (USER.md injection) to Mnemosyne, a local SQLite-backed memory system with semantic recall (SQLite with FTS5 hybrid ranking + vector search).
Secrets
Hermes requires API keys via environment files. Configure via sops-nix:
sops = {
secrets = {
"AI_AGENT/OPENROUTER_API_KEY" = { };
};
templates."HERMES_ENV".content = ''
OPENROUTER_API_KEY=${config.sops.placeholder."AI_AGENT/OPENROUTER_API_KEY"}
'';
};
services.hermes-agent.environmentFiles = [ config.sops.templates."HERMES_ENV".path ];
The module itself declares secrets for the enabled optional components:
- API server token (default
AI_AGENT/API_SERVER_TOKEN) — authenticates the OpenAI-compatible API server. - Discord bot token (default
AI_AGENT/DISCORD_BOT_TOKEN) — Discord platform. - Home Assistant token (default
AI_AGENT/HASSIO_TOKEN) — Home Assistant platform. - Dashboard OIDC uses a public PKCE client, so no client secret is stored.
Operational Notes / Assumptions
Usage Example
{ ... }: {
services.ai-agent = {
enable = true;
};
}
Voice & STT
Enable voice input and output with services.ai-agent.voice.enable = true;. To reuse an existing Wyoming faster-whisper server instead of running a separate Whisper instance:
{ ... }: {
services.ai-agent = {
enable = true;
voice = {
enable = true;
wyoming-stt.enable = true;
};
};
}
Dashboard & OIDC
Enable the web dashboard with services.ai-agent.dashboard.enable = true;, and OIDC authentication with services.ai-agent.dashboard.oidc.enable = true;:
{ ... }: {
services.ai-agent = {
enable = true;
dashboard = {
enable = true;
publicURL = "https://dashboard.example.com";
oidc = {
enable = true;
provider = "self-hosted";
issuer = "https://auth.example.com/oauth2/openid/hermes";
clientId = "hermes";
scopes = [ "openid" "profile" "email" ];
};
};
};
}
Memory (Mnemosyne)
Enable long-term memory with services.ai-agent.memory.enable = true;:
{ ... }: {
services.ai-agent = {
enable = true;
memory.enable = true;
};
}