summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-06-14 01:23:23 +0200
committerMel <mel@rnrd.eu>2026-06-14 01:23:23 +0200
commit6e8ba05449304332ad2e94b20c480a95d223ae3b (patch)
tree3488484ec89c7d364ae45e29f19c75563e11a619
parent2447db440302f2e46123c53af0f05e5d81df4661 (diff)
downloadnetwork-6e8ba05449304332ad2e94b20c480a95d223ae3b.tar.zst
network-6e8ba05449304332ad2e94b20c480a95d223ae3b.zip
Run Renard agent in Hermes harness
Signed-off-by: Mel <mel@rnrd.eu>
-rw-r--r--flake.lock237
-rw-r--r--flake.nix2
-rw-r--r--machines/renard/default.nix1
-rw-r--r--modules/agent.nix114
-rw-r--r--secrets/renard-agent.agebin0 -> 1337 bytes
-rw-r--r--secrets/secrets.nix4
6 files changed, 349 insertions, 9 deletions
diff --git a/flake.lock b/flake.lock
index 4736817..26da37a 100644
--- a/flake.lock
+++ b/flake.lock
@@ -86,6 +86,50 @@
"type": "github"
}
},
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "hermes-agent",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1772408722,
+ "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "hermes-agent": {
+ "inputs": {
+ "flake-parts": "flake-parts",
+ "nixpkgs": "nixpkgs",
+ "npm-lockfile-fix": "npm-lockfile-fix",
+ "pyproject-build-systems": "pyproject-build-systems",
+ "pyproject-nix": "pyproject-nix_2",
+ "uv2nix": "uv2nix_2"
+ },
+ "locked": {
+ "lastModified": 1781361238,
+ "narHash": "sha256-BcosUFspfB2aCZ6FyeURiwjR28uaPeOv6oaz+aEkBS8=",
+ "owner": "NousResearch",
+ "repo": "hermes-agent",
+ "rev": "cc14b74718aaab8f3dc69c004b4dccf67077a1e1",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NousResearch",
+ "repo": "hermes-agent",
+ "type": "github"
+ }
+ },
"home-manager": {
"inputs": {
"nixpkgs": [
@@ -109,7 +153,7 @@
},
"nixos-hardware": {
"inputs": {
- "nixpkgs": "nixpkgs"
+ "nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1781168557,
@@ -127,15 +171,18 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1767892417,
- "narHash": "sha256-8bW3q88CEg2u4hSP66Vf4lpbLonHz7hqDNBMcCY7E9U=",
- "rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba",
- "type": "tarball",
- "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre924538.3497aa5c9457/nixexprs.tar.xz"
+ "lastModified": 1775036866,
+ "narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "6201e203d09599479a3b3450ed24fa81537ebc4e",
+ "type": "github"
},
"original": {
- "type": "tarball",
- "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
}
},
"nixpkgs-unstable": {
@@ -156,6 +203,19 @@
},
"nixpkgs_2": {
"locked": {
+ "lastModified": 1767892417,
+ "narHash": "sha256-8bW3q88CEg2u4hSP66Vf4lpbLonHz7hqDNBMcCY7E9U=",
+ "rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba",
+ "type": "tarball",
+ "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre924538.3497aa5c9457/nixexprs.tar.xz"
+ },
+ "original": {
+ "type": "tarball",
+ "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
+ }
+ },
+ "nixpkgs_3": {
+ "locked": {
"lastModified": 1780952837,
"narHash": "sha256-Fwd1+spDtQ0hDyBwme6ufG3n4mY0UrjjFdYHv+G/Hds=",
"owner": "NixOS",
@@ -170,6 +230,27 @@
"type": "github"
}
},
+ "npm-lockfile-fix": {
+ "inputs": {
+ "nixpkgs": [
+ "hermes-agent",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1775903712,
+ "narHash": "sha256-2GV79U6iVH4gKAPWYrxUReB0S41ty/Y3dBLquU8AlaA=",
+ "owner": "jeslie0",
+ "repo": "npm-lockfile-fix",
+ "rev": "c6093acb0c0548e0f9b8b3d82918823721930fe8",
+ "type": "github"
+ },
+ "original": {
+ "owner": "jeslie0",
+ "repo": "npm-lockfile-fix",
+ "type": "github"
+ }
+ },
"oisd": {
"flake": false,
"locked": {
@@ -186,15 +267,104 @@
"type": "github"
}
},
+ "pyproject-build-systems": {
+ "inputs": {
+ "nixpkgs": [
+ "hermes-agent",
+ "nixpkgs"
+ ],
+ "pyproject-nix": "pyproject-nix",
+ "uv2nix": "uv2nix"
+ },
+ "locked": {
+ "lastModified": 1772555609,
+ "narHash": "sha256-3BA3HnUvJSbHJAlJj6XSy0Jmu7RyP2gyB/0fL7XuEDo=",
+ "owner": "pyproject-nix",
+ "repo": "build-system-pkgs",
+ "rev": "c37f66a953535c394244888598947679af231863",
+ "type": "github"
+ },
+ "original": {
+ "owner": "pyproject-nix",
+ "repo": "build-system-pkgs",
+ "type": "github"
+ }
+ },
+ "pyproject-nix": {
+ "inputs": {
+ "nixpkgs": [
+ "hermes-agent",
+ "pyproject-build-systems",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1769936401,
+ "narHash": "sha256-kwCOegKLZJM9v/e/7cqwg1p/YjjTAukKPqmxKnAZRgA=",
+ "owner": "nix-community",
+ "repo": "pyproject.nix",
+ "rev": "b0d513eeeebed6d45b4f2e874f9afba2021f7812",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "pyproject.nix",
+ "type": "github"
+ }
+ },
+ "pyproject-nix_2": {
+ "inputs": {
+ "nixpkgs": [
+ "hermes-agent",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1772865871,
+ "narHash": "sha256-/ZTSg97aouL0SlPHaokA4r3iuH9QzHVuWPACD2CUCFY=",
+ "owner": "pyproject-nix",
+ "repo": "pyproject.nix",
+ "rev": "e537db02e72d553cea470976b9733581bcf5b3ed",
+ "type": "github"
+ },
+ "original": {
+ "owner": "pyproject-nix",
+ "repo": "pyproject.nix",
+ "type": "github"
+ }
+ },
+ "pyproject-nix_3": {
+ "inputs": {
+ "nixpkgs": [
+ "hermes-agent",
+ "uv2nix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1771518446,
+ "narHash": "sha256-nFJSfD89vWTu92KyuJWDoTQJuoDuddkJV3TlOl1cOic=",
+ "owner": "pyproject-nix",
+ "repo": "pyproject.nix",
+ "rev": "eb204c6b3335698dec6c7fc1da0ebc3c6df05937",
+ "type": "github"
+ },
+ "original": {
+ "owner": "pyproject-nix",
+ "repo": "pyproject.nix",
+ "type": "github"
+ }
+ },
"root": {
"inputs": {
"agenix": "agenix",
"cloudflare-ips-v4": "cloudflare-ips-v4",
"cloudflare-ips-v6": "cloudflare-ips-v6",
"flake-compat": "flake-compat",
+ "hermes-agent": "hermes-agent",
"home-manager": "home-manager",
"nixos-hardware": "nixos-hardware",
- "nixpkgs": "nixpkgs_2",
+ "nixpkgs": "nixpkgs_3",
"nixpkgs-unstable": "nixpkgs-unstable",
"oisd": "oisd"
}
@@ -213,6 +383,55 @@
"repo": "default",
"type": "github"
}
+ },
+ "uv2nix": {
+ "inputs": {
+ "nixpkgs": [
+ "hermes-agent",
+ "pyproject-build-systems",
+ "nixpkgs"
+ ],
+ "pyproject-nix": [
+ "hermes-agent",
+ "pyproject-build-systems",
+ "pyproject-nix"
+ ]
+ },
+ "locked": {
+ "lastModified": 1770770348,
+ "narHash": "sha256-A2GzkmzdYvdgmMEu5yxW+xhossP+txrYb7RuzRaqhlg=",
+ "owner": "pyproject-nix",
+ "repo": "uv2nix",
+ "rev": "5d1b2cb4fe3158043fbafbbe2e46238abbc954b0",
+ "type": "github"
+ },
+ "original": {
+ "owner": "pyproject-nix",
+ "repo": "uv2nix",
+ "type": "github"
+ }
+ },
+ "uv2nix_2": {
+ "inputs": {
+ "nixpkgs": [
+ "hermes-agent",
+ "nixpkgs"
+ ],
+ "pyproject-nix": "pyproject-nix_3"
+ },
+ "locked": {
+ "lastModified": 1773039484,
+ "narHash": "sha256-+boo33KYkJDw9KItpeEXXv8+65f7hHv/earxpcyzQ0I=",
+ "owner": "pyproject-nix",
+ "repo": "uv2nix",
+ "rev": "b68be7cfeacbed9a3fa38a2b5adc0cfb81d9bb1f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "pyproject-nix",
+ "repo": "uv2nix",
+ "type": "github"
+ }
}
},
"root": "root",
diff --git a/flake.nix b/flake.nix
index adfd813..6ba03f3 100644
--- a/flake.nix
+++ b/flake.nix
@@ -34,6 +34,8 @@
url = "https://www.cloudflare.com/ips-v6";
flake = false;
};
+
+ hermes-agent.url = "github:NousResearch/hermes-agent";
};
outputs = inputs @ { self, nixpkgs, nixpkgs-unstable, home-manager, agenix, ... }:
diff --git a/machines/renard/default.nix b/machines/renard/default.nix
index 2be8e72..98d5860 100644
--- a/machines/renard/default.nix
+++ b/machines/renard/default.nix
@@ -10,6 +10,7 @@
../../modules/binary-cache.nix
../../modules/git.nix
../../modules/syncthing.nix
+ ../../modules/agent.nix
../../services/cgit.nix
../../services/minecraft.nix
diff --git a/modules/agent.nix b/modules/agent.nix
new file mode 100644
index 0000000..9cc0636
--- /dev/null
+++ b/modules/agent.nix
@@ -0,0 +1,114 @@
+{ config, hermes-agent, ... }:
+
+{
+ imports = [
+ hermes-agent.nixosModules.default
+ ];
+
+ age.secrets.renard-agent = {
+ file = ../secrets/renard-agent.age;
+ owner = "renard";
+ group = "renard";
+ mode = "0440";
+ };
+
+ services.hermes-agent = {
+ enable = true;
+
+ # the agent has it's own user on the host under
+ # which it runs and can change state at.
+ user = "renard";
+ group = "renard";
+ stateDir = "/home/renard";
+
+ extraDependencyGroups = [ "messaging" ];
+
+ environmentFiles = [
+ # required secrets:
+ # * OPENROUTER_API_KEY
+ # * DISCORD_BOT_TOKEN
+ # * DISCORD_ALLOWED_USERS
+ config.age.secrets.renard-agent.path
+ ];
+
+ settings = {
+ model = {
+ provider = "openrouter";
+ # my current favorite budget model, with recent price
+ # changes by far the cheapest for the performance,
+ # with other chinese models also being close.
+ # only modality is text, requires auxiliary vision model!
+ # native price: $0.44/m in, $0.87/m out.
+ default = "deepseek/deepseek-v4-pro";
+ };
+
+ agent = {
+ reasoning_effort = "high"; # 'high' rated highest in benchmarks, tune to taste!
+ max_turns = 90;
+ };
+
+ auxiliary.vision = {
+ # auxiliary vision model for image comprehension.
+ # this qwen model is built for this exact use-case and is extremely
+ # cheap for the performance (though below gemini), however,
+ # it does not do any reasoning on the visual input!
+ # possible upgrade path for reasoning: qwen3-vl-30b-a3b-thinking
+ # native price: $0.13/m in, $1.56/m out.
+ provider = "openrouter";
+ model = "qwen/qwen3-vl-32b-instruct";
+ timeout = 120;
+ };
+
+ toolsets = [ "all" ];
+
+ terminal = {
+ backend = "local";
+ persistent_shell = true;
+ timeout = 180;
+ };
+
+ memory = {
+ memory_enabled = true;
+ user_profile_enabled = true;
+ };
+
+ # slightly higher limits and targets than default for better
+ # long session preservation.
+ compression = {
+ enabled = true;
+ threshold = 0.75;
+ target_ratio = 0.35;
+ protect_last_n = 40;
+ };
+
+ # progressive message editing, a little silly in discord but looks like
+ # the classic llm chats.
+ streaming = {
+ enabled = true;
+ };
+ display = {
+ streaming = true; # small regression with streaming.enabled, keep both on.
+ tool_progress = "new"; # only show fresh new tool calls, not every call.
+ };
+
+ discord = {
+ require_mention = false;
+ thread_require_mention = false;
+ auto_thread = false;
+ reactions = true;
+ history_backfill = true;
+ allow_mentions = {
+ everyone = false;
+ roles = false;
+ users = true;
+ replied_user = true;
+ };
+ };
+
+ unauthorized_dm_behavior = "ignore"; # ignore strangers
+
+ timezone = "Europe/Berlin";
+ group_sessions_per_user = false;
+ };
+ };
+}
diff --git a/secrets/renard-agent.age b/secrets/renard-agent.age
new file mode 100644
index 0000000..0409f71
--- /dev/null
+++ b/secrets/renard-agent.age
Binary files differ
diff --git a/secrets/secrets.nix b/secrets/secrets.nix
index c56e2bd..9b09574 100644
--- a/secrets/secrets.nix
+++ b/secrets/secrets.nix
@@ -27,6 +27,10 @@ in
renard
] ++ allAdmins;
+ "renard-agent.age".publicKeys = [
+ renard
+ ] ++ allAdmins;
+
"mullvad-gluetun.age".publicKeys = [
corsac
] ++ allAdmins;