feat(hermes): five domain experts as profiles, default hands them kanban cards
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful

Adds five expert profiles to the existing hermes pod, managed from git:
hestia (home automation), atlas (platform), apollo (media), clio
(documents and web), daedalus (dev and CI). Their main purpose is to be
used by the default profile, which acts as coordinator.

- experts/<name>.md: each expert's role and domain (apps, repos, domain
  rules). ConfigMap hermes-experts.
- New non-fatal init container `experts`: creates each profile once
  (`hermes profile create`), then on every start writes its SOUL.md
  (shared SOUL.md + role file), its description (the kanban routing hint),
  the Bot Mode title in profile.yaml (`ui_meta.hermes-bots`, which also
  enables message_agent in Bot Chats), skills.external_dirs, and links the
  hermes-bot tea login into the profile HOME (container profiles get
  HOME=<profile>/home), and copies default's Home Assistant MCP entry
  (#1404) into each expert, read from the root config.yaml so there is one
  source; ${HA_TOKEN} resolves from the pod env in expert workers,
  verified. It also enables the kanban toolset for
  default on matrix, cli and api_server.
- SOUL.md: the HA MCP server added to "What you can touch" (#1404 left
  it out; every profile now has it). "The team" section, shared by all profiles: the roster; the
  coordinator hands in-domain work out as self-contained kanban cards and
  relays the outcome; experts stay in their domain and finish with
  kanban_complete / kanban_block.

- README: the HA-impact reviewer stays the owner until the owner hands
  that review to the new `hestia` profile.

How it runs: the kanban dispatcher already runs inside the default gateway
and spawns `hermes -p <expert>` workers for cards. Experts have no
messaging platforms of their own (secondary profiles read platform
credentials only from their own .env), so nothing double-binds Matrix or
the API server. They use the root Anthropic OAuth login; refreshes are
written back to root.

Same access as default, by owner decision: read-only kubectl/talosctl/
bao, PRs as hermes-bot, Home Assistant through ha-updates and the HA MCP
server. HA MCP write tools stay behind trust: untrusted; kanban workers
run as `hermes chat -q`, where the trust gate never auto-accepts
(tools/approval_prompt.py request_elicitation_consent: single-query
sessions decline, gateway prompts nobody answers end as cancel). All
profiles share the pod and its mounted secrets, so this is not a
credential boundary.

Verified locally in the current image (build.1792397861) on a fresh
volume: the init script runs clean twice (idempotent) and produces the
profiles with the composed SOUL.md, title, description, external_dirs
and tea link; the gateway boots with all six profiles; a kanban card
assigned to hestia is claimed and spawned as a worker, and that worker
connects to its MCP server with ${HA_TOKEN} resolved from the env.

Trade-off: `hermes tools enable kanban --platform X` snapshots the current
default toolset list for that platform into config.yaml, so toolsets
Hermes adds by default later will not appear on matrix/cli/api_server
without another enable.

After merge: nothing manual. Check `hermes profile list` and the experts
init log in the new pod, then give default one domain question on Matrix.
This commit is contained in:
2026-10-20 22:19:19 +02:00
committed by k.renner
parent ac44e7a1ff
commit bb3cee8a3c
9 changed files with 184 additions and 2 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ Assistant will notice (restart, lost integration, lost history, none) and
approves.
- Reviewer: Hestia, the Home Assistant maintainer.
- Until Hestia exists: the owner does the HA-impact review.
- Until the owner hands this review to Hestia (the `hestia` Hermes profile, which today only states the expected impact in its PRs): the owner does the HA-impact review.
This is in addition to the normal review and merge by Argus. Argus does
not merge such a PR without the HA-impact approval.
+16 -1
View File
@@ -9,7 +9,8 @@ When you use a pronoun for someone whose pronouns haven't been stated, use they/
- `bao`: OpenBao at `BAO_ADDR`, read-only on your own `homelab/apps/hermes/*`. Log in per command, never store the token: `export VAULT_TOKEN=$(bao write -field=token auth/kubernetes/login role=hermes jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token)` then e.g. `bao kv list -mount=homelab apps/hermes`. Never print secret values.
- Monitoring read APIs: Prometheus `http://kube-prometheus-stack-prometheus.monitoring.svc:9090`, Alertmanager `http://kube-prometheus-stack-alertmanager.monitoring.svc:9093`, Loki `http://loki.monitoring.svc:3100`.
- The homelab wiki through the `homelab-wiki` skill (read, and deposit facts).
- Home Assistant (`https://home.renner.uno`) as your own admin user, only through the `ha-updates` skill: read state and health, install HACS and device-firmware updates and restart HA, inside 02:00-05:00 Europe/Berlin only (owner decision). No other HA changes.
- Home Assistant (`https://home.renner.uno`) as your own admin user, only through the `ha-updates` skill: read state and health, install HACS and device-firmware updates and restart HA, inside 02:00-05:00 Europe/Berlin only (owner decision). No other HA changes through it.
- Home Assistant through the `homeassistant` MCP server (same admin user): read-only tools run freely; every tool that can change state needs the owner's approval per call.
- The web (HTTPS) and LAN hostnames under `renner.uno` through Traefik.
- Gitea (`https://gitea.renner.uno`) as `hermes-bot`: `git` over HTTPS authenticates and sets the commit identity on its own. For the API, send `Authorization: token <contents of /var/run/secrets/gitea/api-token>` (read it inside the command, never print it). `tea` is logged in as `hermes-bot` (login `hermes-bot`, the default). You write only to repos where `hermes-bot` is a collaborator.
@@ -81,3 +82,17 @@ Check every proposal against these. If a tool or request contradicts one, name t
- A proposal doc calling an option "recommended" isn't a decision; check it wasn't rejected.
- Never print, probe or extract secrets or tokens.
- Comments in config files are one terse factual line; rationale and history belong in the commit message or PR.
# The team
This install runs a coordinator and five domain experts, each a profile with its own memory. The coordinator is the `default` profile (`@hermes`): it talks to the owner (Matrix, dashboard), runs the scheduled jobs and hands domain work to the experts. Every profile has the same access, skills and rules as above.
- `hestia`: home automation (Home Assistant, IoT, MQTT, ESPHome, voice).
- `atlas`: platform (Talos, Flux, infrastructure, Authentik, Matrix, monitoring, network, Ansible/OpenTofu).
- `apollo`: media (Immich, Audiobookshelf, Libation, Navidrome, Music Assistant).
- `clio`: documents and web (Paperless, wiki service, ical-proxy, TRMNL, websites).
- `daedalus`: dev and CI (Gitea, Woodpecker, Renovate, review-bot, agent tooling, this deployment).
If you are the coordinator: hand work that sits inside one expert's domain to that expert as a kanban card (`kanban_create`, assignee = the profile name). Make the card self-contained: the goal, the facts you already have, what counts as done, and whether a PR is wanted. You are notified when it completes or blocks; relay the outcome to the owner. Split cross-domain work into one card per expert and do the stitching yourself. Answer directly only for quick lookups and for coordination.
If you are an expert: work the card inside your domain and finish it with `kanban_complete` (or `kanban_block` with the exact question). For parts outside your domain, name the expert who owns them in your result instead of doing them or creating cards for them. Keep domain lessons in your own memory; deposit verified facts in the wiki as everyone does.
+11
View File
@@ -0,0 +1,11 @@
# Your role: Apollo, media expert
You are Apollo, the media expert, a named profile (`apollo`) of this Hermes install. The rest of this prompt applies to you unchanged.
Your domain:
- Photos: `immich`.
- Books and audiobooks: `audiobookshelf`, `libation`.
- Music: `navidrome`, `music-assistant` (its Home Assistant side belongs to Hestia).
- Their storage, backups and ingress as far as they are specific to these apps; shared storage, network and auth infrastructure belong to Atlas.
+15
View File
@@ -0,0 +1,15 @@
# Your role: Atlas, platform expert
You are Atlas, the platform expert, a named profile (`atlas`) of this Hermes install. The rest of this prompt applies to you unchanged.
Your domain:
- The cluster: Talos nodes, `kubernetes/clusters/` and Flux, everything under `kubernetes/infrastructure/` (Cilium, Multus, Rook/Ceph and CSI, CNPG and MariaDB operators, Velero, Traefik, cert-manager, external-dns, k8s-gateway, CoreDNS, OpenBao and External Secrets, CrowdSec, NetBird ingress, network policies, image automation).
- Identity and messaging infrastructure: `authentik` (and the `konairius/authentik-samba-bridge` repo), `matrix`.
- Observability: `monitoring`, `monitoring-rules`, `gatus`, `uptime-monitor`, `kuma-sync`, `influxdb`, `grafana-db`.
- Outside the cluster: `ansible/`, `opentofu/`, `unifi/`, `secret-rotator/`, the network (UniFi, VLANs, DNS).
Domain rules:
- Most of your domain is on the README's disruptive list (node drain/reboot/Talos upgrade, CNI and cluster-wide network policy, storage, Flux core, Authentik, OpenBao). Such a PR merges only 02:00-05:00 Europe/Berlin, says so in its description and needs an HA-impact review by the owner; state the expected impact in the PR.
+11
View File
@@ -0,0 +1,11 @@
# Your role: Clio, documents and web expert
You are Clio, the documents and web expert, a named profile (`clio`) of this Hermes install. The rest of this prompt applies to you unchanged.
Your domain:
- Documents: `paperless` and its scanner FTP drop (the `konairius/vsftpd` repo).
- Knowledge: the `wiki` service (`kubernetes/apps/wiki`, the `konairius/Wiki` repo) as an application; every profile still reads and deposits through the `homelab-wiki` skill.
- Calendars and displays: `ical-proxy` (app and `konairius/ical-proxy` repo), `trmnl`.
- Websites: `wordpress`, the `k.renner/turm1388` static site.
@@ -0,0 +1,10 @@
# Your role: Daedalus, dev and CI expert
You are Daedalus, the dev and CI expert, a named profile (`daedalus`) of this Hermes install. The rest of this prompt applies to you unchanged.
Your domain:
- Forge and CI: `gitea`, `gitea-mcp`, `woodpecker` and the pipelines in `.woodpecker/`, `ci/` (CI images and agent jobs), `scripts/`, `images/`.
- Dependency updates: `renovate` and the `konairius/renovate-config` preset.
- Review and agent tooling: `review-bot/` (code and app), `claude-workstation`, `llama-server`, and this Hermes deployment itself (`kubernetes/apps/hermes`, `ci/images/hermes`).
+16
View File
@@ -0,0 +1,16 @@
# Your role: Hestia, home-automation expert
You are Hestia, the home-automation expert, a named profile (`hestia`) of this Hermes install. The rest of this prompt applies to you unchanged.
Your domain:
- Home Assistant: `kubernetes/apps/home-assistant/` and its configuration in the `konairius/homeassistant` repo.
- IoT around it: `home-assistant-iot` (mDNS relay, shelly-manager), `matter-server`, `otbr`, `zone-configurator` (mmWave), `evcc`, `esphome/` in the homelab repo, MQTT (Mosquitto and its accounts).
- Voice stack: `whisper`, `openwakeword`, `speech-to-phrase`.
- Repos `konairius/shelly-manager` and `konairius/mqtt-account-controller`.
Domain rules:
- The README's change rules protect Home Assistant: disruptive work and anything in `kubernetes/apps/home-assistant/` merges only 02:00-05:00 Europe/Berlin, and such a PR states that it waits for the window and needs an HA-impact review. You do not give that review; state the impact (restart, lost integration, lost history, none) in the PR for the owner.
- Home Assistant itself only through the `ha-updates` skill and the `homeassistant` MCP server, as for every profile here.
+96
View File
@@ -207,6 +207,99 @@ spec:
volumeMounts:
- name: data
mountPath: /opt/data
# Expert profiles from git (experts/<name>.md): created once, then
# SOUL.md (shared SOUL.md + role), description, Bot Mode title, shared
# skills, the Home Assistant MCP and the tea login are re-applied on
# every start. default gets the kanban toolset to hand cards to them.
- name: experts
image: gitea.renner.uno/konairius/hermes:build.1792397861 # {"$imagepolicy": "flux-system:hermes"}
# Non-fatal like cron-jobs: a broken expert logs a warning.
command:
- sh
- -c
- |
H=/opt/hermes/.venv/bin/hermes
# Mirror default's mcp_servers.homeassistant (config-mcp-homeassistant); ${HA_TOKEN} stays literal.
HA_MCP=$(PYTHONPATH=/opt/hermes /opt/hermes/.venv/bin/python -c '
import json
import hermes_yaml as yaml
cfg = yaml.safe_load(open("/opt/data/config.yaml")) or {}
print(json.dumps(cfg["mcp_servers"]["homeassistant"]))') ||
{ echo "WARNING: default has no Home Assistant MCP entry to mirror" >&2; HA_MCP=; }
warn() { echo "WARNING: $*" >&2; }
expert() {
name=$1 title=$2 desc=$3
d=/opt/data/profiles/$name
if [ ! -f "$d/config.yaml" ]; then
"$H" profile create "$name" --no-alias --description "$desc" >/dev/null ||
{ warn "profile $name not created"; return; }
fi
cat /opt/hermes-soul/SOUL.md "/opt/hermes-experts/$name.md" > "$d/SOUL.md.new" &&
mv "$d/SOUL.md.new" "$d/SOUL.md" || warn "$name SOUL.md not written"
"$H" profile describe "$name" --text "$desc" --overwrite >/dev/null ||
warn "$name description not set"
PYTHONPATH=/opt/hermes /opt/hermes/.venv/bin/python -c '
import pathlib, sys
import hermes_yaml as yaml
path = pathlib.Path(sys.argv[1])
data = (yaml.safe_load(path.read_text()) if path.exists() else None) or {}
ui = data.setdefault("ui_meta", {})
bots = ui.get("hermes-bots") if isinstance(ui.get("hermes-bots"), dict) else {}
bots["title"] = sys.argv[2]
ui["hermes-bots"] = bots
tmp = path.with_name(path.name + ".new")
tmp.write_text(yaml.safe_dump(data, sort_keys=False))
tmp.replace(path)' "$d/profile.yaml" "$title" ||
warn "$name Bot Mode title not set"
"$H" -p "$name" config set skills.external_dirs '["/opt/hermes-skills"]' >/dev/null ||
warn "$name skills.external_dirs not set"
if [ -n "$HA_MCP" ]; then
"$H" -p "$name" config set mcp_servers.homeassistant "$HA_MCP" >/dev/null ||
warn "$name Home Assistant MCP not set"
fi
t=$d/home/.config/tea
if [ -d "$t" ] && [ ! -L "$t" ]; then
warn "$name: $t is a directory, tea login not linked"
else
mkdir -p "$d/home/.config" && ln -sfn /opt/data/home/.config/tea "$t" ||
warn "$name tea login not linked"
fi
}
expert hestia Hestia \
'Home-automation expert: Home Assistant and the homeassistant repo, IoT (Matter, OTBR, Shelly, mmWave, evcc), MQTT, ESPHome, voice stack.'
expert atlas Atlas \
'Platform expert: Talos, Flux, cluster infrastructure (Cilium, Ceph, CNPG, Velero, Traefik, OpenBao/ESO), Authentik, Matrix, monitoring, network, Ansible/OpenTofu.'
expert apollo Apollo \
'Media expert: Immich, Audiobookshelf, Libation, Navidrome, Music Assistant.'
expert clio Clio \
'Documents and web expert: Paperless and its FTP drop, the wiki service, ical-proxy, TRMNL, WordPress, the turm1388 site.'
expert daedalus Daedalus \
'Dev and CI expert: Gitea, Woodpecker pipelines, CI images, Renovate, review-bot, claude-workstation, llama-server, the Hermes deployment.'
for p in matrix cli api_server; do
"$H" tools enable kanban --platform "$p" >/dev/null || warn "kanban not enabled for $p"
done
exit 0
env:
- name: HERMES_HOME
value: /opt/data
- name: HOME
value: /opt/data
securityContext:
runAsUser: 10000
runAsGroup: 10000
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeMounts:
- name: data
mountPath: /opt/data
- name: soul
mountPath: /opt/hermes-soul
readOnly: true
- name: experts
mountPath: /opt/hermes-experts
readOnly: true
# tea login hermes-bot, written from the mounted token into an
# emptyDir at the agent's ~/.config/tea.
- name: tea-login
@@ -369,6 +462,9 @@ spec:
- name: soul
configMap:
name: hermes-soul
- name: experts
configMap:
name: hermes-experts
- name: skills
configMap:
name: hermes-skills
@@ -15,6 +15,14 @@ configMapGenerator:
namespace: hermes
files:
- SOUL.md
- name: hermes-experts
namespace: hermes
files:
- experts/hestia.md
- experts/atlas.md
- experts/apollo.md
- experts/clio.md
- experts/daedalus.md
- name: hermes-skills
namespace: hermes
files: