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