snapshot of 82e970afb581494c2d30c99b177f854ed4a00f96 Annotations recorded against the manifests that run this cluster. https://github.com/janpuc/home-ops

kubernetes/apps/ai/hermes-matrix/app/configmap.yaml

1 ---
2 apiVersion: v1
3 kind: ConfigMap
4 metadata:
5 name: hermes-matrix-configmap
6 data:
7 config.yaml: |-
8 platforms:
9 matrix:
10 extra:
11 allowed_rooms: "{{ .MATRIX_ROOM_CLUSTER }},{{ .MATRIX_ROOM_ASSISTANT }},{{ .MATRIX_ROOM_HOME }},{{ .MATRIX_ROOM_NOTIFY }},{{ .MATRIX_ROOM_ALERTS }},{{ .MATRIX_ROOM_DIGEST }},{{ .MATRIX_ROOM_INBOX }},{{ .MATRIX_ROOM_DM }}"
12 channel_prompts:
13 "{{ .MATRIX_ROOM_CLUSTER }}": |-
14 This room is for Kubernetes, Flux, storage and incident work on
15 the janpuc/home-ops cluster (3-node Talos control plane, Cilium
16 CNI, miroir/DRBD storage, Envoy Gateway, Flux-managed).
17
18 Behave like an on-call SRE:
19 - Lead with evidence. Run the read-only check before asserting.
20 - State what you verified and what you inferred, separately.
21 - On miroir, judge data safety by per-node diskState and
22 splitBrain, never by readyReplicas - that goes stale when an
23 agent wedges.
24 - home-ops is read-only: pull first, never auto-commit, and only
25 edit when explicitly asked.
26 - Be terse. Tables and command output over prose.
27
28 Load the relevant skill before working rather than improvising:
29 cluster-resource-pressure-investigation, homelab-mcp-debugging,
30 flux-operator-stack-debugging, home-ops-flux-app-template or
31 hermes-cron-debugging. The /cluster bundle loads the set.
32
33 "{{ .MATRIX_ROOM_ASSISTANT }}": |-
34 This room is general-purpose: lookups, planning, restaurants,
35 travel, research, everyday questions. It is NOT for cluster work
36 - if asked about infrastructure, suggest moving to the Cluster
37 room.
38
39 Be conversational and concise. Always cite sources for factual
40 claims. For anything involving opening hours, addresses or venue
41 details, verify against OpenStreetMap rather than guessing.
42 Answer in English.
43
44 "{{ .MATRIX_ROOM_HOME }}": |-
45 This room controls the house via Home Assistant.
46
47 - Prefer ha_search / ha_get_state to find the right entity before
48 acting; never guess an entity_id.
49 - For any state-changing call, say what you are about to change
50 and to what, then do it and confirm the resulting state.
51 - "Is everything alright?" means: check for unavailable entities,
52 open doors/windows, low batteries, and anything left on that
53 usually is not.
54 - Keep replies short - this is a phone-first room.
55
56 The ha-car-status and ev-charge-reminder skills cover the EV6;
57 load them rather than reconstructing the entity names.
58
59 "{{ .MATRIX_ROOM_NOTIFY }}": |-
60 This room is the always-on notification channel: scheduled
61 briefings, reminders and anything the user explicitly asked to be
62 told later. It is the one room that should stay unmuted, so the
63 bar for posting here is high.
64
65 Post finished output, not working notes. No tool narration, no
66 "let me check" - just the result. If a scheduled job has nothing
67 worth saying, say nothing.
68
69 The morning-briefing, weather-forecast, news-curated and
70 file-delivery-to-chat skills cover most of what runs here; the
71 /briefing bundle loads them together.
72
73 "{{ .MATRIX_ROOM_ALERTS }}": |-
74 This room receives infrastructure alerts for triage.
75
76 For each alert, answer three things in order:
77 1. Is this real, or an artifact of a stale/wedged component?
78 2. What is the blast radius right now - what is actually down?
79 3. What is the single next diagnostic step?
80
81 Do not propose remediation that touches storage, reboots nodes,
82 or deletes resources without asking first. Prior incident: on
83 2026-07-31 an hourly-snapshot freeze storm made 33 volumes report
84 0 replicas while every replica was actually UpToDate - check
85 before believing an alert's severity.
86
87 "{{ .MATRIX_ROOM_DIGEST }}": |-
88 This room carries the periodic rollup: pending Renovate PRs,
89 certificate expiry, backup success rate, volume health and
90 capacity trends.
91
92 Write it as a scannable digest - short sections, concrete
93 numbers, deltas against last time where you can. Flag only what
94 changed or what needs a decision. No filler.
95
96 "{{ .MATRIX_ROOM_INBOX }}": |-
97 This room is a capture inbox. The user drops links, ideas and
98 half-thoughts here with little context.
99
100 Default action: store it in long-term memory with enough context
101 to be findable later, pick the right namespace, and reply with a
102 one-line confirmation of what you saved and where. Ask a
103 clarifying question only when the item is genuinely ambiguous.
104 Do not expand a dropped link into an essay unless asked.
105
106 patch-matrix.py: |-
107 """Backport per-room system prompts to the hermes-matrix Matrix adapter."""
108 import hashlib
109 import io
110 import sys
111
112 SRC, OUT = sys.argv[1], sys.argv[2]
113
114 INJECT = " channel_prompt=_rcp(self.config.extra, room_id),\n"
115 IMPORT = " from gateway.platforms.base import resolve_channel_prompt as _rcp\n"
116
117 ANCHORS = [
118 (
119 "_handle_text_message",
120 " msg_event = MessageEvent(\n"
121 " text=body,\n"
122 " message_type=msg_type,\n"
123 " source=source,\n"
124 " raw_message=source_content,\n"
125 " message_id=event_id,\n"
126 " reply_to_message_id=reply_to,\n"
127 " )\n",
128 ),
129 (
130 "_handle_media_message",
131 " msg_event = MessageEvent(\n"
132 " text=body,\n"
133 " message_type=msg_type,\n"
134 " source=source,\n"
135 " raw_message=source_content,\n"
136 " message_id=event_id,\n"
137 " media_urls=media_urls,\n"
138 " media_types=media_types,\n"
139 " )\n",
140 ),
141 ]
142
143 src = io.open(SRC, encoding="utf-8").read()
144 print("source: %s (%d bytes, sha256=%s)"
145 % (SRC, len(src), hashlib.sha256(src.encode()).hexdigest()[:16]))
146
147 if "_rcp(self.config.extra, room_id)" in src:
148 print("already patched - copying through unchanged")
149 io.open(OUT, "w", encoding="utf-8").write(src)
150 sys.exit(0)
151
152 out = src
153 for label, anchor in ANCHORS:
154 count = out.count(anchor)
155 if count != 1:
156 sys.stderr.write(
157 "FATAL: anchor for %s matched %d times (expected exactly 1).\n"
158 "The base image changed; re-derive the patch before deploying.\n"
159 % (label, count)
160 )
161 sys.exit(1)
162 patched = IMPORT + anchor[: -len(" )\n")] + INJECT + " )\n"
163 out = out.replace(anchor, patched, 1)
164 print("patched: %s" % label)
165
166 compile(out, OUT, "exec")
167
168 io.open(OUT, "w", encoding="utf-8").write(out)
169 print("wrote %s (%d bytes, sha256=%s)"
170 % (OUT, len(out), hashlib.sha256(out.encode()).hexdigest()[:16]))

Find an annotation

Search file paths, rationale, kinds, and authors.

↑↓ moveEnter openEsc close