This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1{ 2 self, 3 config, 4 pkgs, 5 ... 6}: 7{ 8 imports = [ 9 self.inputs.hermes-agent.nixosModules.default 10 ]; 11 12 # Hermes Agent (Nous Research) — autonomous agent run as a native systemd 13 # gateway, reachable over Matrix (@hermes:lassul.us). Model backend is Nous 14 # Portal (one key, 266 models) driving MiniMax M2.5 — an agentic model, per 15 # Nous's own guidance that the Hermes-4 chat models are NOT for the agent. 16 # Any Portal model is a one-line settings.model.default swap. 17 services.hermes-agent = { 18 enable = true; 19 20 # Build the Matrix platform dependency group into the sealed venv (mautrix 21 # SDK + liboqs for optional E2EE; Linux-only). 22 extraDependencyGroups = [ "matrix" ]; 23 24 settings.model = { 25 # Nous does NOT recommend the Hermes-4 chat models for Hermes Agent — it 26 # wants a dedicated *agentic* model. Community/Nous consensus agentic pick 27 # is the MiniMax M2 family (Nous co-optimizes it for Hermes Agent); M2.5 28 # is the cheapest tool-calling option ($0.12/$0.48 per 1M). All 266 Nous 29 # Portal models share this key, so this is just a model-id swap. 30 # Alternatives: minimax/minimax-m2.7, z-ai/glm-4.6, deepseek/deepseek-v3.2. 31 default = "minimax/minimax-m2.5"; 32 # hermes's built-in "nous" provider is OAuth-only and hardcodes the dead 33 # host inference.nousresearch.com (NXDOMAIN) — true on both 0.17.0 and 34 # main; "nous-api" exists only in docs, not code. So we drive Nous Portal 35 # through the generic OpenAI-compatible "custom" provider pointed at the 36 # live endpoint, authenticating with the Nous key as OPENAI_API_KEY. 37 provider = "custom"; 38 base_url = "https://inference-api.nousresearch.com/v1"; 39 # The custom provider can't auto-detect limits, so it left context 40 # uncompressed and defaulted max_tokens to 65536 — once history passed 41 # ~65k tokens, input + max_tokens exceeded the 131072 window and the 42 # endpoint 400'd ("check the model name and other parameters"). Pin both: 43 # context_length so hermes compresses before the window fills, and a sane 44 # output cap (covers thinking + reply) so input + max_tokens stays under. 45 context_length = 204800; 46 max_tokens = 16384; 47 48 # Frontier-on-tap alternative (uncomment to default to Claude instead): 49 # default = "anthropic/claude-sonnet-4-6"; 50 }; 51 52 # In rooms Hermes requires an @mention by default; DMs always respond. 53 settings.matrix.session_scope = "room"; 54 55 # Non-secret connection + SECURITY gate. Invites are auto-accepted and that 56 # cannot be disabled, so the agent may join any room it's invited to. Joining 57 # is harmless on its own — what matters is who can *trigger* the agent, which 58 # on this host has terminal / filesystem / web tools (chat-driven RCE). 59 # MATRIX_ALLOWED_USERS is the universal trigger gate (applies even in DMs); 60 # only these MXIDs can make the agent act, in any room it's joined. 61 environment = { 62 MATRIX_HOMESERVER = "https://matrix.lassul.us"; 63 MATRIX_USER_ID = "@hermes:lassul.us"; 64 MATRIX_ALLOWED_USERS = "@lassulus:lassul.us"; 65 # Element makes DMs end-to-end encrypted by default, so the bot must do 66 # E2EE or it can't read messages. The `matrix` dep group already bundles 67 # mautrix[encryption] (python-olm); "optional" initializes E2EE when those 68 # deps are present (they are) and keeps the crypto store under 69 # /var/lib/hermes/.hermes/platforms/matrix/store/. 70 MATRIX_E2EE_MODE = "optional"; 71 # Optional defense-in-depth (confine to specific rooms; DMs are exempt): 72 # MATRIX_ALLOWED_ROOMS = "!yourRoomId:lassul.us"; 73 }; 74 75 # Secrets (MATRIX_ACCESS_TOKEN + NOUS_API_KEY) come from clan vars below, 76 # merged into $HERMES_HOME/.env at activation. 77 environmentFiles = [ 78 config.clan.core.vars.generators.hermes-env.files."hermes.env".path 79 ]; 80 }; 81 82 # Boot-race guard. matrix.lassul.us is IPv6-only; on this desktop 83 # network-online.target can fire before v6 DNS is ready, so the gateway's 84 # first Matrix connect fails ("Name or service not known") and it does not 85 # retry — leaving the bot silent until a manual restart. Block startup until 86 # the homeserver resolves (best-effort, ~60s cap) so reboots come up 87 # connected. 88 systemd.services.hermes-agent.serviceConfig.ExecStartPre = [ 89 "${pkgs.writeShellScript "hermes-wait-matrix-dns" '' 90 i=0 91 while [ "$i" -lt 30 ]; do 92 ${pkgs.getent}/bin/getent ahosts matrix.lassul.us >/dev/null 2>&1 && exit 0 93 ${pkgs.coreutils}/bin/sleep 2 94 i=$((i + 1)) 95 done 96 echo "matrix.lassul.us did not resolve within 60s; starting anyway" >&2 97 exit 0 98 ''}" 99 ]; 100 101 # Matrix bot access token for @hermes:lassul.us (minted against the neoprism 102 # Synapse). persist=true so the prompt value is stored once. 103 clan.core.vars.generators.hermes-matrix.prompts.matrix-access-token = { 104 description = "Matrix access token for @hermes:lassul.us"; 105 type = "hidden"; 106 persist = true; 107 }; 108 109 # Nous Portal API key (portal.nousresearch.com, Plus subscription). 110 clan.core.vars.generators.hermes-nous.prompts.nous-api-key = { 111 description = "Nous Portal API key (NOUS_API_KEY) from portal.nousresearch.com"; 112 type = "hidden"; 113 persist = true; 114 }; 115 116 # Assemble the .env Hermes reads (mirrors the opencrow-env pattern). 117 clan.core.vars.generators.hermes-env = { 118 dependencies = [ 119 "hermes-matrix" 120 "hermes-nous" 121 ]; 122 files."hermes.env" = { }; 123 runtimeInputs = [ pkgs.coreutils ]; 124 script = '' 125 key=$(cat "$in"/hermes-nous/nous-api-key) 126 cat > "$out/hermes.env" <<EOF 127 MATRIX_ACCESS_TOKEN=$(cat "$in"/hermes-matrix/matrix-access-token) 128 NOUS_API_KEY=$key 129 OPENAI_API_KEY=$key 130 EOF 131 ''; 132 }; 133}