diff --git a/hosts/lustro/services.yaml b/hosts/lustro/services.yaml index 519b685..55e5b20 100644 --- a/hosts/lustro/services.yaml +++ b/hosts/lustro/services.yaml @@ -13,3 +13,30 @@ services: config_path: /opt/homelab/config/node-agent data_path: /opt/homelab/state logs_path: /opt/homelab/events + + node-exporter: + # Keyed node-exporter (hyphen) — that is the container / world-state name + # on lustro; a node_exporter entry would drift as missing_service. + role: metrics-exporter + deployment_model: docker-compose + exposure: local-only + offline_required: true + depends_on: + local: [] + external: [] + + piper-tts: + # TTS engine for the MagicMirror. No services/piper-tts dir in the repo — + # deployed locally on the Pi; verified running 2026-07-30 via world state + # (lustro/piper-tts healthy) and its service_healthy event stream + # (recon F20.11). + role: tts-engine + deployment_model: docker-compose + exposure: local-only + offline_required: true + depends_on: + local: [] + external: [] + + # watchtower also runs on lustro (world state: lustro/watchtower) — a + # container auto-updater, left unmanaged deliberately; not desired state. diff --git a/hosts/piha/services.yaml b/hosts/piha/services.yaml index b5851f6..b5abaed 100644 --- a/hosts/piha/services.yaml +++ b/hosts/piha/services.yaml @@ -144,3 +144,17 @@ services: runtime: # .env (KB_DSN, LAN_BIND_IP) lives alongside the compose file; stateless, no data path config_path: services/kb-query + + # --- Known unmanaged containers on piha (recon B5/B6, 2026-07-27) ---------- + # ~28 running containers have no entry above and are deliberately NOT being + # added piecemeal — bringing them under desired state is a later stage + # (recon open question 5). The set: agent-system ×4 (webui, + # runtime-materializer, telegram-bot, redis — these STAY, decision + # 2026-07-28), stability-agent, paperless ×3, immich ×4, forgejo ×3, + # zigbee2mqtt, audiobookshelf, grafana, wikijs ×2, code-server, portainer, + # prometheus, homepage, actual-budget, mqtt-exporter, owntracks ×3, + # vaultwarden, pihole-exporter (unlabelled), fail2ban-exporter, + # nginxproxymanager — plus the HOST systemd mosquitto (OS package, no repo + # definition at all, recon C8). When adding any of these later, match the + # entry key to the world-state service key (supervisor does exact + # / matching) or it will drift as missing_service. diff --git a/hosts/saturn/services.yaml b/hosts/saturn/services.yaml new file mode 100644 index 0000000..e2d293c --- /dev/null +++ b/hosts/saturn/services.yaml @@ -0,0 +1,9 @@ +host: saturn + +# Dev workstation and deploy orchestrator (topology roles: control, +# development). Nothing here is monitored or remediated by the control plane: +# no node-agent, no stability-agent, no desired services. This file exists so +# every node in inventory/topology.yaml has an authoritative +# hosts//services.yaml (recon F20.4) — the empty list is an explicit +# decision, not an omission. +services: {} diff --git a/hosts/vps/services.yaml b/hosts/vps/services.yaml index 186465d..ea9f4d5 100644 --- a/hosts/vps/services.yaml +++ b/hosts/vps/services.yaml @@ -76,3 +76,96 @@ services: config_path: /opt/homelab/config/gokapi data_path: /opt/homelab/data/gokapi logs_path: /opt/homelab/logs/gokapi + + stability-agent: + role: node-watchdog # read-only docker.sock watchdog, emits filesystem events + # Deploys via its own deploy-local.sh, outside the declarative pipeline + # (recon B7) — entry added 2026-07 truth cleanup so desired state matches + # what actually runs here. + deployment_model: docker-compose + exposure: local-only + offline_required: true + depends_on: + local: [] + external: [] + runtime: + data_path: /opt/homelab/state + logs_path: /opt/homelab/events + + npm: + role: reverse-proxy # public ingress on the VPS (separate from npm-piha) + deployment_model: docker-compose + exposure: public + offline_required: false + depends_on: + local: [] + external: [] + ports: + - name: http + container_port: 80 + protocol: tcp + - name: https + container_port: 443 + protocol: tcp + runtime: + # Data stays at the pre-GitOps bind mounts (CLAUDE.md data migration rule): + # /home/dockeruser/docker/npm/{data,letsencrypt} + config_path: services/npm + + outline: + # Runs on vps but has NO services/outline dir on master (recon F20.2) — the + # containers predate GitOps management. Companion containers + # outline-postgres-1 / outline-redis-1 are visible in world state but are + # not separate desired-state entries. + role: knowledge-base + deployment_model: docker-compose + exposure: public + offline_required: false + depends_on: + local: [] + external: [] + + joplin-server: + # Keyed joplin-server (not "joplin") to match the compose service name the + # world state tracks — an aggregate "joplin" entry would sit in + # missing_service drift forever. No services/joplin dir on master (recon + # F20.2). Companion joplin-db is tracked in world state, not desired here. + role: notes-sync + deployment_model: docker-compose + exposure: public + offline_required: false + depends_on: + local: [] + external: [] + + umami: + # Web analytics; compose-labelled but no services/umami dir in the repo — + # pre-GitOps deployment (recon B5). Companion umami-db not desired here. + role: web-analytics + deployment_model: docker-compose + exposure: public + offline_required: false + depends_on: + local: [] + external: [] + + # humanai-mailer / humanai-landing: hand-run containers with NO compose + # labels (recon B5/B7). Documented here as unmanaged so the truth map is + # complete. monitor: false keeps the supervisor from generating (dead-end + # redeploy) actions for containers the pipeline cannot manage; `unmanaged` + # itself is documentation only — no code reads it. + humanai-mailer: + unmanaged: true + monitor: false + role: mailer + humanai-landing: + unmanaged: true + monitor: false + role: landing-page + + # ai-cluster (openclaw, codex-worker, planner-worker, service-ops-worker, + # redis, mosquitto): legacy stack, runs UNMANAGED on vps and is scheduled + # for retirement — its codex/* bus has been idle since 2026-06-09. + # Deliberately NO entry here: legacy is not pulled into desired state. + # See docs/architecture/ai-cluster-LEGACY.md and + # docs/architecture/RECON-multiagent-2026-07-27.md (C9).