Blame

3f985f Hermes 2026-05-05 22:17:02
Add agent infrastructure wiki page
1
# Infrastructure for Agents
2
3
> Agent-facing map of Sean/log1kal's project infrastructure. Use this as a routing table, not a diary.
4
>
5
> Last verified: `2026-05-05T22:14:24Z`
6
7
## Agent contract
8
9
- Default project host: `atom`.
10
- Tailnet domain: `tail6a522.ts.net`.
11
- Host-addressed atom DNS: `atom.tail6a522.ts.net`.
12
- Atom LAN IP used by many services: `192.168.1.12`.
13
- Durable Docker config/state convention: `/zpool1/docker_configs/<service>/`.
14
- Larger service data may live under `/zpool1/docker_data/<service>/`.
15
- Hermes workspace/repo path: `/opt/data/workspace` inside the Hermes container, mapped to `/home/hermes/workspace` on atom.
16
- Prefer Portainer-managed stacks for long-lived services on atom.
17
- Do not assume `hermes` has passwordless sudo on atom. It does not.
18
- Do not edit/redeploy the Hermes stack casually; restarting it can interrupt the active agent session.
19
- Do not print secrets. This page lists secret *locations*, not secret values.
20
21
## Access patterns
22
23
| Need | Use |
24
|---|---|
25
| Host shell/build orchestration | SSH to `hermes@atom.tail6a522.ts.net` |
26
| Long-lived Docker services | Portainer API / Portainer stack on endpoint `2` |
27
| Repo/work files | `/home/hermes/workspace` on atom or `/opt/data/workspace` in Hermes |
28
| Routine agent memory | MCP memory service |
29
| Bulk vector/RAG storage | Qdrant |
30
| Credentials | 1Password MCP or configured secret files; never hardcode |
31
| Monitoring | Uptime Kuma |
32
| Workflow automation | n8n |
33
34
## Core host: atom
35
36
| Field | Value |
37
|---|---|
38
| Tailnet hostname | `atom.tail6a522.ts.net` |
39
| Common LAN IP | `192.168.1.12` |
40
| Primary agent user | `hermes` |
41
| Hermes UID/GID in container | `10000:10000` |
42
| Docker manager | Portainer |
43
| Portainer endpoint ID | `2` |
44
| Portainer API from atom | `https://localhost:9443/api` |
45
| Portainer API token path | `/home/hermes/.config/portainer/api_token` |
46
| Preferred bind root | `/zpool1/docker_configs/<service>/` |
47
| Shared workspace | `/home/hermes/workspace` |
48
49
### Atom operational rules
50
51
1. Use SSH for host commands: `ssh atom.tail6a522.ts.net '...'`.
52
2. Use Portainer API for Docker inspection/mutation; `hermes` does not have direct Docker socket access.
53
3. Use host-visible bind mounts for service persistence.
54
4. For services needing tailnet identity, prefer a Tailscale sidecar with `network_mode: service:<tailscale-service>`.
55
5. Verify service health after stack changes through the service API, not just container state.
56
57
## Published / agent-relevant services
58
59
### Portainer
60
61
| Field | Value |
62
|---|---|
63
| Purpose | Docker stack/container management |
64
| Container | `portainer` |
65
| API from atom | `https://localhost:9443/api` |
66
| UI/API host port | `9443/tcp` on atom |
67
| Edge port | `8000/tcp` on atom |
68
| Endpoint ID | `2` |
69
| Token path | `/home/hermes/.config/portainer/api_token` |
70
71
Use for creating/updating/verifying stacks. TLS is self-signed locally; API clients usually need TLS verification disabled.
72
73
### Hermes Agent
74
75
| Field | Value |
76
|---|---|
77
| Stack | `hermes` / Portainer stack ID `100` |
78
| Containers | `hermes`, `hermes-dashboard` |
79
| Gateway port | `8642/tcp` on atom |
80
| Dashboard port | `9119/tcp` on atom |
81
| Container image | `ghcr.io/1kpio/hermes-ssh-image:latest` |
82
| Hermes home in container | `/opt/data` |
83
| Host config mount | `/zpool1/docker_configs/hermes-agent/home:/opt/data` |
84
| Workspace mount | `/home/hermes/workspace:/opt/data/workspace` |
85
| Config file | `/opt/data/config.yaml` |
86
| Env file on host | `/zpool1/docker_configs/hermes-agent/home/.env` |
87
88
Notes:
89
90
- Current active agent may be running here. Treat stack edits as disruptive.
91
- SSH key behavior inside Hermes resolves under `HERMES_HOME` (`/opt/data/.ssh`) unless an explicit `IdentityFile` is used.
92
- Hermes external memory provider is Supermemory; see memory section.
93
94
### n8n
95
96
| Field | Value |
97
|---|---|
98
| Stack | `n8n` / Portainer stack ID `101` |
99
| Containers | `ts-n8n`, `n8n` |
100
| Tailnet URL | `https://n8n.tail6a522.ts.net/` |
101
| Health URL | `https://n8n.tail6a522.ts.net/healthz` |
102
| LAN bind | `192.168.1.12:5678` |
103
| App port | `5678/tcp` |
104
| Persistent data | `/zpool1/docker_configs/n8n/data:/home/node/.n8n` |
105
| Cache | `/zpool1/docker_configs/n8n/cache:/home/node/.cache` |
106
| Local files | `/zpool1/docker_configs/n8n/local-files:/files` |
107
108
Use for workflow automation and webhook glue. Webhook base is `https://n8n.tail6a522.ts.net/`.
109
110
### MCP memory service
111
112
| Field | Value |
113
|---|---|
114
| Stack | `mcp-memory` / Portainer stack ID `99` |
115
| Containers | `ts-memory`, `mcp-memory` |
116
| Tailnet URL | `https://mcp-memory-service.tail6a522.ts.net/` |
117
| Internal app port | `8000/tcp` |
118
| Backend | `sqlite_vec` |
119
| SQLite DB in container | `/app/data/memory.db` |
120
| Host data | `/zpool1/docker_configs/mcp-memory/data` |
121
| Anonymous access | Enabled in current stack config |
122
123
Known REST endpoints:
124
125
```text
126
POST /api/memories
127
GET /api/memories
128
POST /api/search
129
POST /api/search/by-tag
130
POST /api/search/by-time
131
GET /api/search/similar/{content_hash}
132
```
133
134
Use this for routine cross-agent durable memory. Do not use Qdrant directly for small preference/fact writes unless building a bulk RAG workflow.
135
136
### Qdrant
137
138
| Field | Value |
139
|---|---|
140
| Stack | `qdrant` / Portainer stack ID `102` |
141
| Container | `qdrant` |
142
| Image | `qdrant/qdrant:v1.17.1` |
143
| HTTP API | `http://100.81.104.62:6333` |
144
| gRPC API | `100.81.104.62:6334` |
145
| Readiness | `http://100.81.104.62:6333/readyz` |
146
| Health | `http://100.81.104.62:6333/healthz` |
147
| API key path on atom | `/home/hermes/.config/qdrant/api_key` |
148
| Storage | `/zpool1/docker_configs/qdrant/storage:/qdrant/storage` |
149
| Snapshots | `/zpool1/docker_configs/qdrant/snapshots:/qdrant/snapshots` |
150
151
Use for bulk vector search, RAG corpora, document/session archives, and embeddings-backed project indexes.
152
153
### Ollama / Open WebUI / LiteLLM
154
155
| Field | Value |
156
|---|---|
157
| Stack | `ollama` / Portainer stack ID `63` |
158
| Containers | `ts-aichat-server`, `ollama`, `open-webui`, `litellm` |
159
| Tailnet URL | `https://aichat.tail6a522.ts.net/` |
160
| Ollama API via Tailnet | `https://aichat.tail6a522.ts.net/ollama` |
161
| Chat API example | `https://aichat.tail6a522.ts.net/ollama/api/chat` |
162
| Tailscale hostname | `aichat` |
163
| Ollama persistence | `/zpool1/docker_data/ollama:/root/.ollama` |
164
| Open WebUI persistence | `/zpool1/docker_data/open-webui:/app/backend/data` |
165
| GPU | Ollama stack reserves NVIDIA GPUs |
166
167
Use for local/open model inference when an agent needs tailnet-accessible model serving.
168
169
### Uptime Kuma
170
171
| Field | Value |
172
|---|---|
173
| Stack | `uptime-kuma` / Portainer stack ID `103` |
174
| Containers | `ts-uptime-kuma`, `uptime-kuma` |
175
| Tailnet URL | `https://uptime-kuma.tail6a522.ts.net/` |
176
| LAN bind | `192.168.1.12:3001` |
177
| App port | `3001/tcp` |
178
| Data | `/zpool1/docker_configs/uptime-kuma/data:/app/data` |
179
| Docker socket | `/var/run/docker.sock:/var/run/docker.sock:ro` |
180
| Admin password path | `/home/hermes/.config/uptime-kuma/admin_password` |
181
182
Use for service monitoring. Prefer application-level HTTP/API probes over container-only checks.
183
184
### ntfy
185
186
| Field | Value |
187
|---|---|
188
| Stack | `ntfy` / Portainer stack ID `38` |
189
| Container | `ntfy` |
190
| Tailnet URL | `https://ntfy.tail6a522.ts.net/` |
191
| Health URL | `https://ntfy.tail6a522.ts.net/v1/health` |
192
| LAN bind | `192.168.1.12:5080` |
193
| App port | `80/tcp` in container |
194
| Cache | `/zpool1/docker_configs/ntfy/var/cache/ntfy` |
195
| Config | `/zpool1/docker_configs/ntfy/etc/ntfy` |
196
| Common alerts topic | `alerts` |
197
198
Use for push notifications and alert delivery. Verify message history via `/alerts/json?...` when debugging mobile display problems.
199
200
### OtterWiki
201
202
| Field | Value |
203
|---|---|
204
| Stack | `otter` / Portainer stack ID `79` |
205
| Containers | `ts-otter-server`, `otter-otterwiki-1` |
206
| Tailnet URL | `https://otter.tail6a522.ts.net/` |
207
| App image | `redimp/otterwiki:2` |
208
| Host data | `/zpool1/docker_configs/otter/app-data` |
209
| Wiki repository | `/zpool1/docker_configs/otter/app-data/repository` |
210
211
This page is hosted here. OtterWiki stores pages as Markdown files in a Git-backed repository.
212
213
### Caddy
214
215
| Field | Value |
216
|---|---|
217
| Stack | `caddy` / Portainer stack ID `11` |
218
| Container | `caddy` |
219
| Public HTTP | `80/tcp` on atom |
220
| Public HTTPS | `443/tcp` on atom |
221
| Caddyfile | `/zpool1/docker_configs/caddy/Caddyfile` |
222
| Site root | `/zpool1/srv` mounted at `/srv` |
223
| Config/data | `/zpool1/docker_configs/caddy/config`, `/zpool1/docker_configs/caddy/data` |
224
225
Use for conventional HTTP reverse proxy/site hosting when not using Tailscale Serve.
226
227
### SearXNG
228
229
| Field | Value |
230
|---|---|
231
| Stack | `searxng` / Portainer stack ID `66` |
232
| Containers | `ts-searxng-server`, `searxng-searxng-1` |
233
| Tailnet URL | `https://searxng.tail6a522.ts.net/` |
234
235
Use as a private metasearch endpoint when browser/search tools are constrained.
236
237
### OpenClaw
238
239
| Field | Value |
240
|---|---|
241
| Stack | `openclaw` / Portainer stack ID `96` |
242
| Containers | `ts-openclaw`, `openclaw-gateway` |
243
| Image | `openclaw:local` |
244
| Host config referenced by Hermes | `/zpool1/docker_configs/openclaw/.openclaw` mounted at `/opt/openclaw` |
245
246
Use only if the current task specifically needs OpenClaw. Do not infer its API surface from this page alone.
247
248
### Kasm browser/desktops
249
250
| Stack | Containers | Published port / URL hints |
251
|---|---|---|
252
| `kasm-ubuntu` / ID `97` | `tailscale-kasm-ubuntu`, `kasm-ubuntu` | `6901/tcp` published |
253
| `kasm-claw` / ID `98` | `tailscale-kasm-claw`, `kasm-claw` | `6910/tcp` published |
254
255
Use for GUI/browser desktop workloads when available. Check current health before depending on them.
256
257
## Other running services on atom
258
259
These exist and may be useful, but many are personal/media/home services rather than agent infrastructure.
260
261
| Service/stack | Known port or endpoint |
262
|---|---|
263
| `adguardhome` | DNS `192.168.1.12:53` TCP/UDP; UI `192.168.1.12:8008` |
264
| `frigate` | HTTP `:5000`, RTSP `:8554`, WebRTC `:8555`, go2rtc `:1984` |
265
| `mealie` | `:9925` |
266
| `scrutiny` | `192.168.1.12:4080`, collector `:4086` |
267
| `rebootcontrol` | `:7234` |
268
| `radarr` | `:7878` |
269
| `sonarr` | `:8989` |
270
| `bazarr` | `:6767` |
271
| `sabnzbd` | `:8080` |
272
| `overseerr` | `:5055` |
273
| `tautulli` | `:8181` |
274
| `readarr` | `:9157` |
275
| `calibre` | `:19901`, `:19902`, `:19903` |
276
| `heimdall` | `:7080`, `:7443` |
277
| `pairdrop` | `:4000` |
278
| `homarr` | `:7575` |
279
| `stash` / `xbvr` | `:9999`; xbvr also `:12345` |
280
281
Check live Portainer state before using any of these.
282
283
## Memory architecture
284
285
| Layer | Role | Endpoint / location |
286
|---|---|---|
287
| Hermes Supermemory provider | Hermes's own external long-term memory provider | Configured in `/opt/data/config.yaml`; API key in `/opt/data/.env` |
288
| MCP memory service | Shared agent-facing memory front door | `https://mcp-memory-service.tail6a522.ts.net/` |
289
| Qdrant | Bulk vector/RAG/document/session substrate | `100.81.104.62:6333/6334` |
290
| Shared-memory skill repo | Policy/runbook for other agents | `https://github.com/dixie-rom/agent-shared-memory-skill` |
291
292
Rules:
293
294
- Store durable facts/preferences/architecture decisions in MCP memory or the agent's native memory layer.
295
- Store large documents, session archives, and embedding corpora in Qdrant-backed workflows.
296
- Never store secrets in memory or Qdrant.
297
- Prefer concise, stable facts over task-progress logs.
298
299
## GitHub / code hosting
300
301
- Stay on GitHub. Sean decided not to migrate Git hosting.
302
- Host-side `gh` is authenticated on atom as the working GitHub identity.
303
- For coding work on atom, use `/home/hermes/workspace`.
304
- For agents that need reusable shared-memory behavior, install the skill repo:
305
306
```bash
307
npx skills add dixie-rom/agent-shared-memory-skill --all
308
```
309
310
## 1Password
311
312
| Field | Value |
313
|---|---|
314
| Hermes-accessible vault name | `Dixie` |
315
| Preferred access | 1Password MCP tools when present |
316
317
Do not dump secret values into chat/wiki/logs. If a secret must be referenced, document only its vault/item/field or local file path.
318
319
## Current Portainer stack inventory
320
321
Status codes are Portainer status values from live inspection. `1` generally means active; `2` means inactive/stopped/limited depending on stack state.
322
323
| ID | Stack | Status | Agent relevance |
324
|---:|---|---:|---|
325
| 11 | `caddy` | 1 | Public reverse proxy/site host |
326
| 38 | `ntfy` | 1 | Notifications/alerts |
327
| 63 | `ollama` | 1 | Local model serving / Open WebUI |
328
| 66 | `searxng` | 1 | Search endpoint |
329
| 79 | `otter` | 1 | Wiki/docs hosting |
330
| 96 | `openclaw` | 1 | Specialized agent/browser gateway |
331
| 97 | `kasm-ubuntu` | 1 | GUI desktop/browser |
332
| 98 | `kasm-claw` | 1 | GUI desktop/browser |
333
| 99 | `mcp-memory` | 1 | Shared agent memory |
334
| 100 | `hermes` | 1 | Active assistant/gateway |
335
| 101 | `n8n` | 1 | Workflow automation |
336
| 102 | `qdrant` | 1 | Vector DB/RAG |
337
| 103 | `uptime-kuma` | 1 | Monitoring |
338
339
Other stacks exist on atom. Query Portainer before making assumptions.
340
341
## Verification commands
342
343
### Check Portainer stacks from atom
344
345
```bash
346
ssh atom.tail6a522.ts.net 'python3 - <<"PY"
347
import json, ssl, urllib.request
348
base = "https://localhost:9443/api"
349
token = open("/home/hermes/.config/portainer/api_token").read().strip()
350
ctx = ssl.create_default_context(); ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
351
req = urllib.request.Request(base + "/stacks", headers={"X-API-Key": token})
352
with urllib.request.urlopen(req, context=ctx) as r:
353
for s in json.load(r):
354
print(s["Id"], s["Name"], s["EndpointId"], s.get("Status"))
355
PY'
356
```
357
358
### Check Qdrant
359
360
```bash
361
ssh atom.tail6a522.ts.net 'curl -fsS http://100.81.104.62:6333/readyz'
362
```
363
364
### Check n8n
365
366
```bash
367
ssh atom.tail6a522.ts.net 'curl -fsS https://n8n.tail6a522.ts.net/healthz'
368
```
369
370
### Check ntfy
371
372
```bash
373
ssh atom.tail6a522.ts.net 'curl -fsS https://ntfy.tail6a522.ts.net/v1/health'
374
```
375
376
## Pitfalls
377
378
- `atom.tail6a522.ts.net` is the host. Service-specific Tailscale names like `n8n.tail6a522.ts.net` or `aichat.tail6a522.ts.net` may belong to sidecars.
379
- Tailscale Docker env var is usually `TS_AUTHKEY`, not `TS_AUTH_KEY`; old stacks may still show historical variants.
380
- Secret gists are unlisted, not private. Do not use them as a vault.
381
- Portainer stack files may contain secret values in environment fields. Redact before quoting.
382
- Container state `running` is not enough. Hit the health/API endpoint.
383
- The OtterWiki repository on disk is owned by the wiki container user, so host writes may require container/Portainer-side file updates.