{ config, lib, pkgs, inputs, ... }: let # Edge TTS: Seraphina — friendly, multilingual German female voice (free, no API key) edgeVoice = "de-DE-SeraphinaMultilingualNeural"; agentSkillExclusions = { m3ta-agents = []; anthropic = ["pdf" "skill-creator" "xlsx"]; basecamp = []; kestra = []; mattpocock = ["grill-me" "caveman"]; superpowers = ["brainstorming" "systematic-debugging"]; vercel = []; }; agentLibSourceSelections = lib.mapAttrs (_sourceName: exclude: { skills = { all = true; inherit exclude; }; }) agentSkillExclusions; # Deterministic store renderer consumed directly by Hermes. m3ta-home # re-exports the focused helper so nixos-config does not need a direct # agent-lib flake input. hermesSkills = inputs.m3ta-home.lib.mkHermesSkillsDir { system = pkgs.stdenv.hostPlatform.system; name = "hermes-agent-lib-skills"; lockFile = ../../../agent-sources.lock.json; sources = agentLibSourceSelections; }; in { virtualisation.docker.enable = true; systemd.tmpfiles.rules = [ "d /var/lib/hermes/.config 0755 hermes hermes -" "d /var/lib/hermes/.config/tea 0755 hermes hermes -" "L+ /var/lib/hermes/.config/tea/yml - - - - ${pkgs.writeText "tea-yml" '' logins: - name: m3ta url: https://code.m3ta.dev token: ssh_host: code.m3ta.dev user: m3ta-chiron default: true ''}" ]; systemd.services.hermes-agent.restartTriggers = [hermesSkills]; services.hermes-agent = { enable = true; addToSystemPackages = true; # v0.14 lazy-installs heavy optional backends by default. In the sealed # Nix package, include the backends this host config actively uses so the # gateway, Matrix bridge, memory, web search, TTS, and local STT work # without runtime pip/uv mutation. extraDependencyGroups = [ "matrix" "honcho" "exa" "edge-tts" "voice" ]; extraPackages = with pkgs; [ basecamp docker git curl jq tea nix python3Minimal uv zellij ]; # Secrets via agenix environmentFiles = [ config.age.secrets."hermes-env".path config.age.secrets."hermes-cloud-env".path config.age.secrets."hermes-api-server-key".path ]; # Non-secret environment variables # Git identity is set entirely via env vars (GIT_AUTHOR_*, GIT_COMMITTER_*, # GIT_INIT_DEFAULT_BRANCH) — no .gitconfig file needed. Env vars take # precedence over any gitconfig, and the hermes gateway injects them into # all terminal sessions via .env. environment = { GLM_BASE_URL = "https://api.z.ai/api/coding/paas/v4/"; GIT_AUTHOR_NAME = "m3ta-chiron"; GIT_AUTHOR_EMAIL = "m3ta-chiron@agentmail.to"; GIT_COMMITTER_NAME = "m3ta-chiron"; GIT_COMMITTER_EMAIL = "m3ta-chiron@agentmail.to"; GIT_INIT_DEFAULT_BRANCH = "master"; # ── API Server (OpenAI-compatible, for Hermes Desktop App) ───────── # Accessible via Netbird mesh VPN — not exposed to the public internet. # Bind to 0.0.0.0 so the Netbird interface can reach it. API_SERVER_ENABLED = "true"; API_SERVER_HOST = "0.0.0.0"; API_SERVER_PORT = toString (config.m3ta.ports.get "hermes-api"); }; # ── Container mode (podman) ────────────────────────────────────────── container = { enable = false; backend = "podman"; extraVolumes = ["/home/m3tam3re/p:/projects:rw"]; extraOptions = []; }; settings = { # ── Model ────────────────────────────────────────────────────────── model = { default = "gpt-5.5"; provider = "openai-codex"; }; fallback_providers = [ { provider = "zai"; model = "glm-5.1"; } { provider = "minimax"; model = "MiniMax-M2.7"; } ]; credential_pool_strategies = { zai = "fill_first"; }; toolsets = ["all"]; # ── Agent ────────────────────────────────────────────────────────── agent = { max_turns = 90; gateway_timeout = 1800; tool_use_enforcement = "auto"; reasoning_effort = "high"; }; # ── Skills ───────────────────────────────────────────────────────── skills = { external_dirs = [ hermesSkills ]; }; # ── Terminal ─────────────────────────────────────────────────────── terminal = { backend = "local"; modal_mode = "auto"; cwd = "."; timeout = 180; persistent_shell = true; }; # ── Browser ──────────────────────────────────────────────────────── browser = { inactivity_timeout = 120; command_timeout = 30; cloud_provider = "local"; }; # ── Checkpoints v2 ───────────────────────────────────────────────── # v0.13.0: Single-store rewrite with real pruning + disk guardrails. checkpoints = { enabled = true; max_snapshots = 50; }; file_read_max_chars = 100000; compression = { enabled = true; threshold = 0.5; target_ratio = 0.2; protect_last_n = 20; }; # ── Display ──────────────────────────────────────────────────────── display = { compact = false; personality = "kawaii"; resume_display = "full"; busy_input_mode = "interrupt"; inline_diffs = true; skin = "default"; tool_progress = "all"; }; # ── TTS / STT / Voice ────────────────────────────────────────────── tts = { provider = "edge"; edge = { voice = edgeVoice; }; }; stt = { enabled = true; provider = "local"; local = {model = "base";}; }; voice = { record_key = "ctrl+b"; max_recording_seconds = 120; silence_threshold = 200; silence_duration = 3.0; }; # ── Memory ───────────────────────────────────────────────────────── memory = { provider = "honcho"; memory_enabled = true; user_profile_enabled = true; memory_char_limit = 2200; user_char_limit = 1375; }; # ── Delegation / Orchestrator ──────────────────────────────────────── delegation = { max_iterations = 50; orchestrator_enabled = true; max_spawn_depth = 2; }; # ── Kanban (v0.13.0 — Multi-Agent Board) ────────────────────────── # Durable task board with embedded dispatcher in gateway process. # Workers are full OS processes with identity, heartbeat, reclaim, # zombie detection, and hallucination gate. kanban = { dispatch_in_gateway = true; dispatch_interval_seconds = 60; }; # ── Matrix ──────────────────────────────────────────────────────── matrix = { homeserver = "https://matrix.m3ta.dev"; user_id = "@chiron:m3ta.dev"; allowed_users = ["@m3tam3re:m3ta.dev"]; encryption = true; group_sessions_per_user = true; auto_thread = true; dm_mention_threads = true; }; # ── Approvals / Security ─────────────────────────────────────────── approvals = { mode = "manual"; timeout = 60; }; security = { redact_secrets = true; tirith_enabled = true; tirith_fail_open = true; }; # ── Cron / Session ───────────────────────────────────────────────── cron = {wrap_response = true;}; session_reset = { mode = "both"; idle_minutes = 1440; at_hour = 4; }; # ── Web ──────────────────────────────────────────────────────────── web = {backend = "exa";}; }; }; users.users.hermes = { isNormalUser = false; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAVF7jGP1S6vc5CxeBFD/UxiImHOgbPlKg8WYyNtOA3" ]; }; }