add mars host, move Hermes Agent there from jupiter
New on-site host mars runs Hermes Agent as its sole service: joins the
tailnet, mounts jupiter's samba share at /mnt/jupiter (doubling as
Hermes's shared dropbox), and hosts state locally under /var/lib/hermes.
Same Authentik OIDC app/Telegram bot as before, just relocated — neptun's
hermes.mgaction.town vhost now points at mars.orbit.sol instead of jupiter.
hosts/jupiter/hermes-agent.nix and its three sops secrets are removed;
jupiter's Caddy vhost for it is gone too. Also refreshes tailscale_authkey
across all hosts and fixes two stale "erik@laptop" keys in flake.nix's
kexec/installer-iso images (leftover from a previous laptop, already
swapped out of common.nix back in 2fd5752) to darman@terra.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FHr5ug9pu8q4XPrRkFnzJ
This commit is contained in:
@@ -6,7 +6,6 @@
|
||||
./hardware-configuration.nix
|
||||
./disk-config.nix # disko: OS-disk partitions + filesystems
|
||||
./secrets.nix # sops-nix: samba password, tailscale key, ...
|
||||
./hermes-agent.nix # Hermes Agent, isolated instance (see file for why)
|
||||
../../common.nix # shared base: user / ssh / nix / firewall
|
||||
../../services/network/samba.nix
|
||||
../../services/network/avahi.nix
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
{ config, ... }:
|
||||
|
||||
# Hermes Agent — jupiter's own instance (terra no longer runs one; see
|
||||
# 713d91d). Locked down given jupiter's much bigger blast radius
|
||||
# (irreplaceable immich photos on an unredundant RAID0, gitea/CI tokens, the
|
||||
# whole media stack):
|
||||
#
|
||||
# - Own dedicated "hermes" system user (module default: user/group "hermes",
|
||||
# createUser = true) — NOT darman. darman is in jupiter's "docker" group
|
||||
# (services/containers.nix: rootful podman with dockerCompat), which is
|
||||
# root-equivalent (`docker run -v /:/host --privileged ...`). Handing an
|
||||
# LLM-driven agent that identity would mean a container escape = root on
|
||||
# the whole NAS.
|
||||
# - container.enable = true, backend = "podman": the ENTIRE gateway process
|
||||
# runs inside a container (reusing jupiter's existing rootful podman
|
||||
# instead of also standing up a second Docker daemon), not just the shell
|
||||
# tool. Per upstream's own SECURITY.md this is "whole-process wrapping" —
|
||||
# shell, file tools, MCP subprocesses, and the code-exec tool are all
|
||||
# confined, unlike the lighter "terminal-backend"-only isolation.
|
||||
# - Its own Telegram bot (own token, in secrets.nix) with an EXPLICIT
|
||||
# TELEGRAM_ALLOWED_USERS rather than relying solely on the adapter's
|
||||
# fail-closed default. Sharing terra's bot token would 409-conflict two
|
||||
# long-pollers on the same token.
|
||||
# - No container.extraVolumes into /mnt/data or the homelab repo — nothing
|
||||
# valuable is in reach if a command goes wrong or gets injected via
|
||||
# Telegram/tool output. stateDir/workingDirectory live on the array
|
||||
# (below) purely because coding-task state (repo clones, npm/pip caches
|
||||
# inside the container's writable layer) belongs off the 29G eMMC, same
|
||||
# reasoning as postgres/containers.storage in configuration.nix — NOT
|
||||
# because anything else on /mnt/data is exposed to the agent.
|
||||
{
|
||||
services.hermes-agent = {
|
||||
enable = true;
|
||||
addToSystemPackages = true; # `hermes` on darman's PATH for interactive
|
||||
# debugging over ssh — routes through to the
|
||||
# container, does not grant darman any group.
|
||||
|
||||
# Off the eMMC: stateDir bind-mounts into the container as /data, so this
|
||||
# is where any future scoped repo clone (container.extraVolumes) and the
|
||||
# container's own writable layer (npm/pip installs during coding tasks)
|
||||
# actually land. RequiresMountsFor below (mirrors podman/sabnzbd/gitea-runner
|
||||
# in configuration.nix) keeps the service from starting — and bind-mounting
|
||||
# the wrong, empty eMMC path — before the nofail array is up.
|
||||
stateDir = "/mnt/data/AppData/hermes";
|
||||
workingDirectory = "/mnt/data/AppData/hermes/workspaces";
|
||||
|
||||
# HERMES_TIMEZONE is the highest-priority source hermes_time.py checks
|
||||
# (ahead of config.yaml's `timezone` key) — the container has no host
|
||||
# /etc/localtime bind-mount, so it defaults to UTC otherwise. Not a
|
||||
# secret, so `environment` (plain .env) rather than sops.
|
||||
environment.HERMES_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
container = {
|
||||
enable = true;
|
||||
backend = "podman"; # jupiter already runs podman (services/containers.nix);
|
||||
# default "docker" would stand up a second daemon.
|
||||
};
|
||||
|
||||
# OpenCode Go provider account (same key originally used for terra's now-
|
||||
# removed instance, copied into secrets/jupiter.yaml — just an API key,
|
||||
# not a stateful identity like the Telegram bot token).
|
||||
settings.model = {
|
||||
provider = "opencode-go";
|
||||
base_url = "https://opencode.ai/zen/go/v1";
|
||||
default = "gpt-5.6-luna";
|
||||
api_mode = "codex_responses";
|
||||
};
|
||||
|
||||
settings.platforms.telegram = {
|
||||
enabled = true;
|
||||
home_channel = {
|
||||
platform = "telegram";
|
||||
chat_id = "15151223";
|
||||
name = "Erik Simon";
|
||||
user_id = "15151223";
|
||||
};
|
||||
};
|
||||
|
||||
environmentFiles = [ config.sops.templates."hermes-agent.env".path ];
|
||||
};
|
||||
|
||||
systemd.services.hermes-agent.unitConfig.RequiresMountsFor = [ "/mnt/data" ];
|
||||
}
|
||||
@@ -64,21 +64,4 @@
|
||||
sops.secrets.sabnzbd_eweka_username.owner = "sabnzbd";
|
||||
sops.secrets.sabnzbd_eweka_password.owner = "sabnzbd";
|
||||
|
||||
# Hermes Agent (hosts/jupiter/hermes-agent.nix) — a separate, isolated
|
||||
# instance from terra's, with its OWN Telegram bot token (sharing terra's
|
||||
# would 409-conflict two long-pollers on one token). opencode_go_api_key
|
||||
# is the same provider account as terra (hosts/terra/secrets.nix) — a
|
||||
# stateless API key, fine to duplicate across hosts. No owner override:
|
||||
# sops.templates renders via a root-run activation script, which the
|
||||
# hermes module's own activation script (also root) then reads — unlike
|
||||
# sabnzbd's preStart, this doesn't run as the service's own user.
|
||||
sops.secrets.opencode_go_api_key = { };
|
||||
sops.secrets.telegram_bot_token = { };
|
||||
sops.templates."hermes-agent.env".content = ''
|
||||
OPENCODE_GO_API_KEY=${config.sops.placeholder.opencode_go_api_key}
|
||||
TELEGRAM_BOT_TOKEN=${config.sops.placeholder.telegram_bot_token}
|
||||
TELEGRAM_HOME_CHANNEL=15151223
|
||||
TELEGRAM_ALLOWED_USERS=15151223
|
||||
'';
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user