Files
oikos/seeds/inventory.yaml
dtoro a3914a1d41
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
fix(checks): process check is opt-in for url-fronted services
The ontology's stated intent was "http when it has a url, else a process
check", but the implementation emitted BOTH for every url-service — so ~17
fronted services carried a redundant process check that, under worst-of
aggregation, let a fragile supplementary probe (wrong unit name, unreachable
host, no guest agent) veto two healthy http checks and report the service
"down" while it was up (authentik, zimaos, house, matrix, ...).

buildKind now emits a process check only for services WITHOUT a url, or when
an explicit probe_unit opts into binary-level depth. http is the canonical
service-liveness probe (tests the real endpoint through the TLS terminator);
the redundant process checks were removed.
2026-07-29 23:03:27 +02:00

644 lines
44 KiB
YAML

# Oikos inventory seed — entity instances + relationships.
#
# Translated from the legacy /inventory.yaml (2026-07-07). Bootstraps the
# entities/relationships tables (migration 002); after ingest the DB is
# authoritative and this file is regenerated by `GET /api/v1/export`.
#
# Slug conventions: <prefix>:<name> —
# host: (proxmox-host, standalone-server) · ws: (workstation) · lxc: · vm:
# service: · ingress: · repo: (config-repo) · pool: · volume: · mesh: · lan:
# zone: (dns-zone) · idp: · person: · agent: · cluster: · backup:
#
# `state:` omitted = the type's lifecycle default (active).
# Mount details (mount_point) are attributes on `mounts` edges.
# Known thin spots are marked # THIN: backfill later.
version: 1
entities:
# ─── Sites, networks ───────────────────────────────────────────────
- {slug: "site:home", type: site, name: home}
- {slug: "site:ionos-dc", type: site, name: ionos-dc,
attributes: {address: IONOS datacenter (VPS)}}
- slug: "lan:lab"
type: lan
name: lab
attributes: {subnet: 192.168.8.0/24}
- slug: "lan:household"
type: lan
name: household
attributes: {subnet: 192.168.178.0/24} # Fritz LAN; static route to lab subnet
- slug: "mesh:netbird"
type: mesh
name: netbird
attributes:
provider: netbird
subnet: 100.122.0.0/16
domain: netbird.selfhosted
- slug: "mesh:tailscale"
type: mesh
name: tailscale
state: deprecated # migration to netbird in progress (infrastructure/mesh.md)
attributes: {provider: tailscale}
- slug: "zone:hubris.network"
type: dns-zone
name: hubris.network
attributes: {zone: hubris.network, authority: "Technitium (LXC 107), split-horizon"}
- slug: "zone:netbird.selfhosted"
type: dns-zone
name: netbird.selfhosted
attributes: {zone: netbird.selfhosted, authority: netbird-mgmt}
# ─── Machines ──────────────────────────────────────────────────────
- slug: "cluster:homelab"
type: cluster
name: Homelab
attributes: {quorum: "2-node, no QDevice tiebreaker yet"}
- slug: "host:hubris"
type: proxmox-host
name: hubris
attributes:
os: linux
lan_ip: 192.168.8.77
mesh: {netbird: {ip: 100.122.38.109, fqdn: proxmox-server.netbird.selfhosted}}
ssh: {port: 22, netbird_port: 22022, user: root}
age_pubkey: age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6
- slug: "host:strong"
type: proxmox-host
name: strong
attributes:
os: linux
lan_ip: 192.168.178.181
ssh: {user: root}
age_pubkey: age1rtwvdct6avjkr3cyxv3vue3vqx4d524fjfr3vk7xrnvyrylnry5sm54sn4
note: >-
PVE 9.2.3 since 2026-07-01 (formerly workstation ludo-mini). Joined
Homelab cluster same day. Not yet netbird-enrolled — reachable via
household LAN / Fritz static route only.
- slug: "host:netbird-vps"
type: standalone-server
name: netbird-vps
attributes:
os: linux
provider: ionos
control_level: partial # managed via ssh from hubris; not a homelab client
public_ipv4: 82.165.190.79
mesh: {netbird: {ip: 100.122.165.149, fqdn: netbird-ionos.netbird.selfhosted}}
ssh: {user: root}
note: netbird mgmt+signal+relay+dashboard + coturn; sshd locked to hubris pubkey
- slug: "ws:mac-mini"
type: workstation
name: mac-mini
attributes:
os: macos
user: dtoro
lan_ip: 192.168.178.182
mesh: {netbird: {fqdn: mac-mini-234-17.netbird.selfhosted}}
age_pubkey: age169104ee1a9e1577d493820830560197f0adf56bf8f1c369d57c152c03f9437ae
note: only macOS in fleet; Oikos Docker host. Enrolled 2026-07-08.
enrolled_at: "2026-07-08T09:49:03Z"
mesh_ip: 192.168.178.182
hostname: mac-mini
- slug: "ws:republic-laptop"
type: workstation
name: republic-laptop
attributes:
os: linux
user: dtoro
mesh: {netbird: {fqdn: republic-laptop.netbird.selfhosted}}
# ─── LXCs ──────────────────────────────────────────────────────────
- {slug: "lxc:jellyfin", type: lxc, name: jellyfin,
attributes: {pve_id: 101, role: media-server, lan_ip: 192.168.8.246,
public_host: media.hubris.network,
note: "VAAPI transcode via Radeon 680M passthrough; migrated hubris→strong 2026-07-05"}}
- {slug: "lxc:nfs-export", type: lxc, name: nfs-export,
attributes: {pve_id: 102, role: storage-export, lan_ip: 192.168.8.200}}
- {slug: "lxc:paperless", type: lxc, name: paperless,
attributes: {pve_id: 103, role: document-archive, lan_ip: 192.168.8.130,
public_host: paperless.hubris.network}}
- {slug: "lxc:gitea", type: lxc, name: gitea,
attributes: {pve_id: 104, role: git-server, lan_ip: 192.168.8.121,
public_host: git.hubris.network,
note: "bare repos at /mnt/library/repos/dtoro/*.git"}}
- {slug: "lxc:apps", type: lxc, name: apps,
attributes: {pve_id: 105, role: docker-apps, lan_ip: 192.168.8.205,
age_pubkey: age1duyl8mkpgu80uv934dy8q7enqjms6yvdz264hme8uryuxmvvqesq6rusq0,
note: "legacy Oikos host; fallback during cutover (plan A6)"}}
- {slug: "lxc:auth-outpost", type: lxc, name: auth-outpost,
attributes: {pve_id: 106, role: authentik-gateway, lan_ip: 192.168.8.6}}
- {slug: "lxc:dns", type: lxc, name: dns,
attributes: {pve_id: 107, role: dns-server, lan_ip: 192.168.8.2}}
- {slug: "lxc:nextcloud", type: lxc, name: nextcloud,
attributes: {pve_id: 114, role: file-sync, lan_ip: 192.168.8.224,
public_host: cloud.hubris.network}}
- {slug: "lxc:elementsynapse", type: lxc, name: elementsynapse,
attributes: {pve_id: 118, role: matrix-server, lan_ip: 192.168.8.242,
public_host: matrix.hubris.network,
note: "migrated hubris→strong 2026-07-05"}}
- {slug: "lxc:sophia", type: lxc, name: sophia,
attributes: {pve_id: 119, role: workshop, lan_ip: 192.168.8.109}}
- {slug: "lxc:mule-images", type: lxc, name: mule-images,
attributes: {pve_id: 120, role: photo-management, lan_ip: 192.168.8.136,
public_host: photos.hubris.network}}
- {slug: "lxc:caddy", type: lxc, name: caddy,
attributes: {pve_id: 121, role: reverse-proxy, lan_ip: 192.168.8.175,
note: "terminates all *.hubris.network; /etc/caddy is a checkout of dtoro/caddy-conf"}}
- {slug: "lxc:arriman", type: lxc, name: arriman,
attributes: {pve_id: 122, role: arr-stack, lan_ip: 192.168.8.245,
public_hosts: [jellyseerr.hubris.network, qbit.hubris.network, sab.hubris.network],
note: "homarr/radarr/sonarr/lidarr/sab/qbit/bazarr/flaresolverr/prowlarr/jellyseerr; migrated to strong 2026-07-05"}}
- {slug: "lxc:trmnl", type: lxc, name: trmnl,
attributes: {pve_id: 128, role: trmnl-middleware, lan_ip: 192.168.8.211,
public_host: trmnl.hubris.network,
note: "not yet mesh/SOPS-enrolled"}}
- {slug: "lxc:house", type: lxc, name: house,
attributes: {pve_id: 129, role: family-planner, lan_ip: 192.168.8.244,
public_host: house.hubris.network,
age_pubkey: age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h,
note: "Yuvomi + WebDAV bridge to paperless; migrated to strong 2026-07-05"}}
- {slug: "lxc:grimmory", type: lxc, name: grimmory,
attributes: {pve_id: 130, role: book-library, lan_ip: 192.168.8.247,
public_host: books.hubris.network,
age_pubkey: age1uellsemnjrzgfg9fxw4jefpy05laxzggwnwhh6ny3wl7alyp6v8q0muxet}}
- {slug: "lxc:teddycloud", type: lxc, name: teddycloud,
attributes: {pve_id: 131, role: teddycloud, lan_ip: 192.168.8.150,
public_host: teddy.hubris.network,
note: "drift-caught 2026-07-06; no forward-auth gate on route; not a homelab client"}}
- {slug: "lxc:rclone", type: lxc, name: rclone,
attributes: {pve_id: 132, role: backup,
mesh: {netbird: {fqdn: rclone.netbird.selfhosted}},
age_pubkey: age1pwtdws2thdh7vzp2dzttl3zxgcs2tgpcsjsqgw3q04nyml4kvuqq467u4x}}
# verified live on hubris 2026-07-07 (pct list via MCP)
- {slug: "lxc:seanime", type: lxc, name: seanime,
attributes: {pve_id: 133, role: anime-media-server, lan_ip: 192.168.8.248,
public_host: seanime.hubris.network,
note: "systemd service at /opt/seanime; uses qbittorrent on arriman"}}
- {slug: "lxc:romm", type: lxc, name: romm,
attributes: {pve_id: 134, role: rom-manager, lan_ip: 192.168.8.249,
public_host: roms.hubris.network,
note: "docker compose + MariaDB sidecar at /opt/romm"}}
# ─── VMs ───────────────────────────────────────────────────────────
- {slug: "vm:zimaos", type: vm, name: zimaos,
attributes: {pve_id: 100, role: nas-frontend-eval, lan_ip: 192.168.8.195,
public_host: zimaos.hubris.network}}
- {slug: "vm:haos", type: vm, name: haos,
attributes: {pve_id: 108, role: home-automation, lan_ip: 192.168.8.101}}
# ─── Storage ───────────────────────────────────────────────────────
- {slug: "pool:local-lvm-hubris", type: storage-pool, name: local-lvm (hubris),
attributes: {type: lvm}}
- {slug: "pool:library-hubris", type: storage-pool, name: library (hubris),
attributes: {type: lvmthin, capacity_gb: 3700}}
# 2nd Samsung 990 EVO Plus NVMe; backs /mnt/library ext4 via
# /dev/mapper/library-library (knowledge/wiki/hosts/hubris.md)
- {slug: "pool:ludo-lvm", type: storage-pool, name: ludo-lvm (strong),
attributes: {type: lvm}}
- {slug: "volume:library", type: volume, name: library,
attributes: {path: /mnt/library, size_gb: 3700}}
- {slug: "volume:media-local", type: volume, name: media-local,
attributes: {path: /mnt/media_local}}
- {slug: "backup:proton-drive", type: backup-target, name: proton-drive,
attributes: {provider: proton, encrypted: true,
path: /mnt/backup,
note: "rclone stages here before pushing to Proton; freshness is checked on lxc:rclone via the backs-up-to edge"}}
# The pre-deploy pg_dump written by scripts/deploy.sh on every push to main.
# It was the lab's only untracked backup: its failure path is `|| echo
# WARNING` inside the deploy script, so a broken dump was invisible until a
# rollback needed it.
- {slug: "backup:oikos-predeploy", type: backup-target, name: oikos-predeploy,
attributes: {provider: local, encrypted: false,
path: /opt/oikos/backups,
note: "pre-deploy pg_dump on the mac-mini; one per deployed SHA"}}
# ─── Services ──────────────────────────────────────────────────────
- {slug: "service:proxmox-ui", type: service, name: proxmox_ui,
attributes: {url: "https://proxmox.hubris.network", port: 8006,
doc_page: knowledge/wiki/hosts/hubris.md,
risk_notes: "hypervisor UI — changes affect every guest on the node"}}
- {slug: "service:gitea", type: service, name: gitea,
attributes: {url: "https://git.hubris.network", port: 3000,
doc_page: knowledge/wiki/containers/104-gitea.md,
risk_notes: "hosts all config repos + deploy webhooks; outage blocks auto-deploy and sync"}}
- {slug: "service:caddy", type: service, name: caddy,
attributes: {doc_page: knowledge/wiki/containers/121-caddy.md,
risk_notes: "wide blast radius — every *.hubris.network route rides on it"}}
- {slug: "service:authentik", type: service, name: authentik,
attributes: {url: "https://auth.hubris.network",
doc_page: knowledge/wiki/containers/106-auth-outpost.md,
note: "core on VPS since 2026-05-31; LAN outpost = auth-outpost (LXC 106) 192.168.8.6:9000",
risk_notes: "SSO provider — outage locks login to OIDC/forward-auth services"}}
- {slug: "service:dns", type: service, name: dns,
attributes: {doc_page: knowledge/wiki/containers/107-dns.md,
risk_notes: "LAN-wide resolver — misconfig breaks name resolution for every client"}}
- {slug: "service:jellyfin", type: service, name: jellyfin,
attributes: {url: "https://media.hubris.network",
doc_page: knowledge/wiki/containers/101-jellyfin.md,
risk_notes: "native Authentik OIDC (no forward-auth gate); VAAPI depends on GPU passthrough on strong"}}
- {slug: "service:nextcloud", type: service, name: nextcloud,
attributes: {url: "https://cloud.hubris.network",
doc_page: knowledge/wiki/containers/114-nextcloud.md}}
- {slug: "service:paperless", type: service, name: paperless,
attributes: {url: "https://paperless.hubris.network",
doc_page: knowledge/wiki/containers/103-paperless.md,
risk_notes: "document archive — data irreplaceable; DB operations are destructive-class"}}
- {slug: "service:matrix", type: service, name: matrix,
attributes: {url: "https://matrix.hubris.network",
doc_page: knowledge/wiki/containers/118-elementsynapse.md,
risk_notes: "alert/approval channel for Oikos — outage silences agent escalation"}}
- {slug: "service:photos", type: service, name: photos,
attributes: {url: "https://photos.hubris.network",
doc_page: knowledge/wiki/containers/120-mule-images.md}}
- {slug: "service:arr-stack", type: service, name: arr_stack,
attributes: {doc_page: knowledge/wiki/containers/122-arriman.md,
note: "jellyseerr / qbit / sab on docker compose"}}
- {slug: "service:artifacto", type: service, name: artifacto,
attributes: {url: "https://artifacto.hubris.network",
doc_page: knowledge/wiki/containers/105-apps.md}}
- {slug: "service:trmnl", type: service, name: trmnl,
attributes: {url: "https://trmnl.hubris.network",
doc_page: knowledge/wiki/containers/128-trmnl.md,
note: "TRMNL e-ink plugin middleware (polled by TRMNL cloud)"}}
- {slug: "service:zimaos", type: service, name: zimaos,
attributes: {url: "https://zimaos.hubris.network",
doc_page: knowledge/wiki/vms/100-zimaos.md}}
- {slug: "service:haos", type: service, name: haos,
attributes: {doc_page: knowledge/wiki/vms/108-haos.md}}
- {slug: "service:teddycloud", type: service, name: teddycloud,
attributes: {url: "https://teddy.hubris.network",
doc_page: knowledge/wiki/containers/131-teddycloud.md,
risk_notes: "no forward-auth gate — reachable by anyone on LAN/mesh"}}
# The Go control plane itself: api/scheduler/notifier/web on the mac-mini,
# and what mcp.hubris.network fronts since the cutover. It existed in the
# database (created outside the seed) but was never declared here, so a
# fresh seed could not resolve the routes-to edge below.
- {slug: "service:oikos", type: service, name: oikos,
attributes: {url: "https://oikos.hubris.network",
host: "ws:mac-mini",
ports: {api: 8090, web: 8091, nomos_gateway: 8092},
note: "homelab automation platform — api/scheduler/notifier/web on mac-mini docker compose (project name oikos)"}}
- {slug: "service:homelab-mcp", type: service, name: homelab_mcp,
attributes: {port: 9810, systemd_unit: homelab-mcp,
endpoint: "https://mcp.hubris.network/mcp",
doc_page: knowledge/wiki/infrastructure/homelab-context.md,
risk_notes: "agents' primary read surface — outage degrades every agent to grepping the clone"}}
- {slug: "service:secrets-issuance", type: service, name: secrets_issuance,
attributes: {port: 9820, systemd_unit: secrets-issuance,
endpoint: "https://secrets.hubris.network/issue",
doc_page: .agents/operations/agent-enrollment.md,
risk_notes: "identity issuance — security-sensitive; key operations are destructive-class"}}
# Services derived from hosts.public_host (no legacy services entry):
- {slug: "service:house", type: service, name: house,
attributes: {url: "https://house.hubris.network", note: "Yuvomi family planner (derived)"}}
- {slug: "service:grimmory", type: service, name: grimmory,
attributes: {url: "https://books.hubris.network", note: derived}}
- {slug: "service:seanime", type: service, name: seanime,
attributes: {url: "https://seanime.hubris.network", port: 43211, note: derived}}
- {slug: "service:romm", type: service, name: romm,
attributes: {url: "https://roms.hubris.network", note: derived}}
- {slug: "service:jellyseerr", type: service, name: jellyseerr,
attributes: {url: "https://jellyseerr.hubris.network", note: derived (arriman)}}
- {slug: "service:qbit", type: service, name: qbit,
attributes: {url: "https://qbit.hubris.network", note: derived (arriman)}}
- {slug: "service:sab", type: service, name: sab,
attributes: {url: "https://sab.hubris.network", note: "derived (arriman); forward-auth gated"}}
# ─── Config repos ──────────────────────────────────────────────────
- {slug: "repo:caddy-conf", type: config-repo, name: dtoro/caddy-conf}
- {slug: "repo:gitea-customizations", type: config-repo, name: dtoro/gitea-customizations}
- {slug: "repo:mule-image", type: config-repo, name: dtoro/mule-image}
- {slug: "repo:artifacto", type: config-repo, name: dtoro/Artifacto}
- {slug: "repo:terminalito", type: config-repo, name: dtoro/terminalito}
- {slug: "repo:homelab-docs", type: config-repo, name: dtoro/oikos}
# ─── Ingress routes (Caddy, *.hubris.network) ──────────────────────
- {slug: "ingress:proxmox.hubris.network", type: ingress-route, name: proxmox.hubris.network}
- {slug: "ingress:git.hubris.network", type: ingress-route, name: git.hubris.network}
- {slug: "ingress:auth.hubris.network", type: ingress-route, name: auth.hubris.network}
- {slug: "ingress:media.hubris.network", type: ingress-route, name: media.hubris.network}
- {slug: "ingress:cloud.hubris.network", type: ingress-route, name: cloud.hubris.network}
- {slug: "ingress:paperless.hubris.network", type: ingress-route, name: paperless.hubris.network,
attributes: {forward_auth: true}}
- {slug: "ingress:matrix.hubris.network", type: ingress-route, name: matrix.hubris.network}
- {slug: "ingress:photos.hubris.network", type: ingress-route, name: photos.hubris.network}
- {slug: "ingress:artifacto.hubris.network", type: ingress-route, name: artifacto.hubris.network}
- {slug: "ingress:trmnl.hubris.network", type: ingress-route, name: trmnl.hubris.network}
- {slug: "ingress:zimaos.hubris.network", type: ingress-route, name: zimaos.hubris.network}
- {slug: "ingress:teddy.hubris.network", type: ingress-route, name: teddy.hubris.network,
attributes: {forward_auth: false}}
- {slug: "ingress:mcp.hubris.network", type: ingress-route, name: mcp.hubris.network}
- {slug: "ingress:secrets.hubris.network", type: ingress-route, name: secrets.hubris.network}
- {slug: "ingress:house.hubris.network", type: ingress-route, name: house.hubris.network}
- {slug: "ingress:books.hubris.network", type: ingress-route, name: books.hubris.network}
- {slug: "ingress:seanime.hubris.network", type: ingress-route, name: seanime.hubris.network}
- {slug: "ingress:roms.hubris.network", type: ingress-route, name: roms.hubris.network}
- {slug: "ingress:jellyseerr.hubris.network", type: ingress-route, name: jellyseerr.hubris.network}
- {slug: "ingress:qbit.hubris.network", type: ingress-route, name: qbit.hubris.network}
- {slug: "ingress:sab.hubris.network", type: ingress-route, name: sab.hubris.network,
attributes: {forward_auth: true}}
# ─── TLS certificates (Caddy-managed, *.hubris.network) ───────────
# Each cert's expiry is probed by dialing Caddy's lab IP (`dial`) with SNI
# set to the hostname — the scheduler container has no mesh/split-horizon
# DNS, so it can't resolve *.hubris.network, but it CAN reach Caddy on the
# lab LAN.
- {slug: "cert:proxmox.hubris.network", type: certificate, name: proxmox.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:git.hubris.network", type: certificate, name: git.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:auth.hubris.network", type: certificate, name: auth.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:media.hubris.network", type: certificate, name: media.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:cloud.hubris.network", type: certificate, name: cloud.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:paperless.hubris.network", type: certificate, name: paperless.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:matrix.hubris.network", type: certificate, name: matrix.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:photos.hubris.network", type: certificate, name: photos.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:artifacto.hubris.network", type: certificate, name: artifacto.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:trmnl.hubris.network", type: certificate, name: trmnl.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:zimaos.hubris.network", type: certificate, name: zimaos.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:teddy.hubris.network", type: certificate, name: teddy.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:mcp.hubris.network", type: certificate, name: mcp.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:house.hubris.network", type: certificate, name: house.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:books.hubris.network", type: certificate, name: books.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:seanime.hubris.network", type: certificate, name: seanime.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:roms.hubris.network", type: certificate, name: roms.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:jellyseerr.hubris.network", type: certificate, name: jellyseerr.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:qbit.hubris.network", type: certificate, name: qbit.hubris.network, attributes: {dial: "192.168.8.175"}}
- {slug: "cert:sab.hubris.network", type: certificate, name: sab.hubris.network, attributes: {dial: "192.168.8.175"}}
# ─── Governance ────────────────────────────────────────────────────
- {slug: "person:dtoro", type: person, name: dtoro,
attributes: {matrix_id: "@dtoro:avispero"}}
- {slug: "idp:authentik", type: identity-provider, name: authentik,
attributes: {issuer: "https://auth.hubris.network", auth_mode: both}}
- {slug: "agent:nomos", type: agent, name: nomos,
state: active,
attributes: {gateway_port: 8092, session_mode: smart_approve, note: "Phase 4 — Docker gateway mode"}}
- {slug: "agent:oikos", type: agent, name: oikos,
state: planned,
attributes: {note: "the OS control loop itself (scheduler/actuator) as an actor"}}
# ─── Archaeology (state: destroyed — kept for "what happened to X?") ─
- {slug: "lxc:claudio-bot", type: lxc, name: claudio-bot, state: destroyed,
attributes: {pve_id: 123, destroyed: "2026-06-04", reason: "replaced by Nomos Agent on mac-mini"}}
- {slug: "lxc:plato", type: lxc, name: plato, state: destroyed,
attributes: {pve_id: 126, destroyed: "2026-06-28", reason: "notes workspace decommissioned; data at /mnt/library/documents/plato"}}
- {slug: "lxc:mule-photos-new", type: lxc, name: mule-photos-new, state: destroyed,
attributes: {pve_id: 127, destroyed: "2026-05-22", reason: "PhotoPrism test stack promoted to LXC 120"}}
- {slug: "lxc:heaper", type: lxc, name: heaper, state: destroyed,
attributes: {pve_id: 116, destroyed: "2026-05-14", reason: "decommissioned; data at /mnt/library/heaper"}}
- {slug: "lxc:syncthing", type: lxc, name: syncthing, state: destroyed,
attributes: {pve_id: 109, destroyed: "2026-05-14", reason: "decommissioned; library subtree was empty"}}
- {slug: "lxc:seafile", type: lxc, name: seafile, state: destroyed,
attributes: {pve_id: 125, destroyed: "2026-05-13", reason: "Seafile Pro evaluation rejected"}}
- {slug: "lxc:arr-yunohost", type: lxc, name: arr-yunohost, state: destroyed,
attributes: {pve_id: 100, destroyed: "2026-04-28", reason: "migrated to docker stack on arriman (LXC 122)"}}
- {slug: "lxc:flaresolverr", type: lxc, name: flaresolverr, state: destroyed,
attributes: {pve_id: 106, destroyed: "2026-04-28", reason: "folded into the arriman docker compose"}}
- {slug: "lxc:marimo", type: lxc, name: marimo, state: destroyed,
attributes: {pve_id: 107, destroyed: "2026-04-28", reason: decommissioned}}
- {slug: "lxc:photoprism", type: lxc, name: photoprism, state: destroyed,
attributes: {pve_id: 110, destroyed: "2026-04-28", reason: "replaced by mule-images (LXC 120)"}}
- {slug: "lxc:karakeep", type: lxc, name: karakeep, state: destroyed,
attributes: {pve_id: 111, destroyed: "2026-04-28", reason: decommissioned}}
- {slug: "lxc:immich", type: lxc, name: immich, state: destroyed,
attributes: {pve_id: 112, destroyed: "2026-04-28", reason: "replaced by mule-images (LXC 120)"}}
- {slug: "lxc:reticulum", type: lxc, name: reticulum, state: destroyed,
attributes: {pve_id: 115, destroyed: "2026-04-28", reason: decommissioned}}
relationships:
# ─── Cluster membership ────────────────────────────────────────────
- {source: "host:hubris", target: "cluster:homelab", type: member-of}
- {source: "host:strong", target: "cluster:homelab", type: member-of}
# ─── Location ──────────────────────────────────────────────────────
- {source: "host:hubris", target: "site:home", type: located-at}
- {source: "host:strong", target: "site:home", type: located-at}
- {source: "ws:mac-mini", target: "site:home", type: located-at}
- {source: "host:netbird-vps", target: "site:ionos-dc", type: located-at}
# ─── Hosting (machine → guest) ─────────────────────────────────────
- {source: "host:hubris", target: "lxc:nfs-export", type: hosts}
- {source: "host:hubris", target: "lxc:paperless", type: hosts}
- {source: "host:hubris", target: "lxc:gitea", type: hosts}
- {source: "host:hubris", target: "lxc:apps", type: hosts}
- {source: "host:hubris", target: "lxc:auth-outpost", type: hosts}
- {source: "host:hubris", target: "lxc:dns", type: hosts}
- {source: "host:hubris", target: "lxc:nextcloud", type: hosts}
- {source: "host:hubris", target: "lxc:sophia", type: hosts}
- {source: "host:hubris", target: "lxc:mule-images", type: hosts}
- {source: "host:hubris", target: "lxc:caddy", type: hosts}
- {source: "host:hubris", target: "lxc:trmnl", type: hosts}
- {source: "host:hubris", target: "lxc:teddycloud", type: hosts}
- {source: "host:hubris", target: "vm:zimaos", type: hosts}
- {source: "host:hubris", target: "vm:haos", type: hosts}
- {source: "host:strong", target: "lxc:jellyfin", type: hosts}
- {source: "host:strong", target: "lxc:elementsynapse", type: hosts}
- {source: "host:strong", target: "lxc:arriman", type: hosts}
- {source: "host:strong", target: "lxc:house", type: hosts}
- {source: "host:strong", target: "lxc:grimmory", type: hosts}
- {source: "host:strong", target: "lxc:seanime", type: hosts}
- {source: "host:strong", target: "lxc:romm", type: hosts}
- {source: "host:hubris", target: "lxc:rclone", type: hosts}
# ─── Service provision (compute → service) ─────────────────────────
- {source: "host:hubris", target: "service:proxmox-ui", type: provides}
- {source: "lxc:gitea", target: "service:gitea", type: provides}
- {source: "lxc:caddy", target: "service:caddy", type: provides}
- {source: "host:netbird-vps", target: "service:authentik", type: provides}
- {source: "lxc:dns", target: "service:dns", type: provides}
- {source: "lxc:jellyfin", target: "service:jellyfin", type: provides}
- {source: "lxc:nextcloud", target: "service:nextcloud", type: provides}
- {source: "lxc:paperless", target: "service:paperless", type: provides}
- {source: "lxc:elementsynapse", target: "service:matrix", type: provides}
- {source: "lxc:mule-images", target: "service:photos", type: provides}
- {source: "lxc:arriman", target: "service:arr-stack", type: provides}
- {source: "lxc:arriman", target: "service:jellyseerr", type: provides}
- {source: "lxc:arriman", target: "service:qbit", type: provides}
- {source: "lxc:arriman", target: "service:sab", type: provides}
- {source: "lxc:apps", target: "service:artifacto", type: provides}
- {source: "lxc:apps", target: "service:homelab-mcp", type: provides}
- {source: "lxc:apps", target: "service:secrets-issuance", type: provides}
- {source: "lxc:trmnl", target: "service:trmnl", type: provides}
- {source: "vm:zimaos", target: "service:zimaos", type: provides}
- {source: "vm:haos", target: "service:haos", type: provides}
- {source: "lxc:teddycloud", target: "service:teddycloud", type: provides}
- {source: "lxc:house", target: "service:house", type: provides}
- {source: "lxc:grimmory", target: "service:grimmory", type: provides}
- {source: "lxc:seanime", target: "service:seanime", type: provides}
- {source: "lxc:romm", target: "service:romm", type: provides}
# ─── Ingress → service ─────────────────────────────────────────────
- {source: "ingress:proxmox.hubris.network", target: "service:proxmox-ui", type: routes-to}
- {source: "ingress:git.hubris.network", target: "service:gitea", type: routes-to}
- {source: "ingress:auth.hubris.network", target: "service:authentik", type: routes-to}
- {source: "ingress:media.hubris.network", target: "service:jellyfin", type: routes-to}
- {source: "ingress:cloud.hubris.network", target: "service:nextcloud", type: routes-to}
- {source: "ingress:paperless.hubris.network", target: "service:paperless", type: routes-to}
- {source: "ingress:matrix.hubris.network", target: "service:matrix", type: routes-to}
- {source: "ingress:photos.hubris.network", target: "service:photos", type: routes-to}
- {source: "ingress:artifacto.hubris.network", target: "service:artifacto", type: routes-to}
- {source: "ingress:trmnl.hubris.network", target: "service:trmnl", type: routes-to}
- {source: "ingress:zimaos.hubris.network", target: "service:zimaos", type: routes-to}
- {source: "ingress:teddy.hubris.network", target: "service:teddycloud", type: routes-to}
# Re-pointed from service:homelab-mcp, which is deprecated — the Python MCP
# server on apps/105 was stopped at the Go cutover and mcp.hubris.network now
# fronts the Go api. Nomos recorded this correctly on 2026-07-12; the seed
# was the stale one, and re-asserting the old edge alongside it is what made
# ingress:mcp a cardinality violation.
- {source: "ws:mac-mini", target: "service:oikos", type: provides}
- {source: "ingress:mcp.hubris.network", target: "service:oikos", type: routes-to}
# Every public hostname is terminated by caddy. Without these the
# reverse proxy — the single widest point of failure in the lab —
# had a blast radius of one.
- {source: "ingress:proxmox.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:git.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:auth.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:media.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:cloud.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:paperless.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:matrix.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:photos.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:artifacto.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:trmnl.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:zimaos.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:teddy.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:mcp.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:secrets.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:house.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:books.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:seanime.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:roms.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:jellyseerr.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:qbit.hubris.network", target: "service:caddy", type: served-by}
- {source: "ingress:sab.hubris.network", target: "service:caddy", type: served-by}
# Each public route is served with its TLS certificate.
- {source: "ingress:proxmox.hubris.network", target: "cert:proxmox.hubris.network", type: uses-certificate}
- {source: "ingress:git.hubris.network", target: "cert:git.hubris.network", type: uses-certificate}
- {source: "ingress:auth.hubris.network", target: "cert:auth.hubris.network", type: uses-certificate}
- {source: "ingress:media.hubris.network", target: "cert:media.hubris.network", type: uses-certificate}
- {source: "ingress:cloud.hubris.network", target: "cert:cloud.hubris.network", type: uses-certificate}
- {source: "ingress:paperless.hubris.network", target: "cert:paperless.hubris.network", type: uses-certificate}
- {source: "ingress:matrix.hubris.network", target: "cert:matrix.hubris.network", type: uses-certificate}
- {source: "ingress:photos.hubris.network", target: "cert:photos.hubris.network", type: uses-certificate}
- {source: "ingress:artifacto.hubris.network", target: "cert:artifacto.hubris.network", type: uses-certificate}
- {source: "ingress:trmnl.hubris.network", target: "cert:trmnl.hubris.network", type: uses-certificate}
- {source: "ingress:zimaos.hubris.network", target: "cert:zimaos.hubris.network", type: uses-certificate}
- {source: "ingress:teddy.hubris.network", target: "cert:teddy.hubris.network", type: uses-certificate}
- {source: "ingress:mcp.hubris.network", target: "cert:mcp.hubris.network", type: uses-certificate}
- {source: "ingress:house.hubris.network", target: "cert:house.hubris.network", type: uses-certificate}
- {source: "ingress:books.hubris.network", target: "cert:books.hubris.network", type: uses-certificate}
- {source: "ingress:seanime.hubris.network", target: "cert:seanime.hubris.network", type: uses-certificate}
- {source: "ingress:roms.hubris.network", target: "cert:roms.hubris.network", type: uses-certificate}
- {source: "ingress:jellyseerr.hubris.network", target: "cert:jellyseerr.hubris.network", type: uses-certificate}
- {source: "ingress:qbit.hubris.network", target: "cert:qbit.hubris.network", type: uses-certificate}
- {source: "ingress:sab.hubris.network", target: "cert:sab.hubris.network", type: uses-certificate}
- {source: "ingress:secrets.hubris.network", target: "service:secrets-issuance", type: routes-to}
- {source: "ingress:house.hubris.network", target: "service:house", type: routes-to}
- {source: "ingress:books.hubris.network", target: "service:grimmory", type: routes-to}
- {source: "ingress:seanime.hubris.network", target: "service:seanime", type: routes-to}
- {source: "ingress:roms.hubris.network", target: "service:romm", type: routes-to}
- {source: "ingress:jellyseerr.hubris.network", target: "service:jellyseerr", type: routes-to}
- {source: "ingress:qbit.hubris.network", target: "service:qbit", type: routes-to}
- {source: "ingress:sab.hubris.network", target: "service:sab", type: routes-to}
# ─── Auth edges ────────────────────────────────────────────────────
- {source: "ingress:paperless.hubris.network", target: "idp:authentik", type: secured-by}
- {source: "ingress:sab.hubris.network", target: "idp:authentik", type: secured-by}
- {source: "service:jellyfin", target: "idp:authentik", type: authenticates-via}
- {source: "idp:authentik", target: "person:dtoro", type: authenticates}
# ─── Config repos ──────────────────────────────────────────────────
- {source: "service:caddy", target: "repo:caddy-conf", type: configured-by}
- {source: "service:gitea", target: "repo:gitea-customizations", type: configured-by}
- {source: "service:photos", target: "repo:mule-image", type: configured-by}
- {source: "service:artifacto", target: "repo:artifacto", type: configured-by}
- {source: "service:trmnl", target: "repo:terminalito", type: configured-by}
- {source: "service:homelab-mcp", target: "repo:homelab-docs", type: configured-by}
- {source: "service:secrets-issuance", target: "repo:homelab-docs", type: configured-by}
# ─── Service dependencies (blast-radius edges; grow over time) ─────
- {source: "service:paperless", target: "service:authentik", type: depends-on}
- {source: "service:homelab-mcp", target: "service:gitea", type: depends-on}
- {source: "service:jellyseerr", target: "service:jellyfin", type: depends-on}
- {source: "service:seanime", target: "service:qbit", type: depends-on}
- {source: "service:house", target: "service:paperless", type: depends-on}
- {source: "service:sab", target: "service:authentik", type: depends-on}
# ─── Network membership ────────────────────────────────────────────
- {source: "host:hubris", target: "lan:lab", type: connects-via}
- {source: "host:hubris", target: "mesh:netbird", type: connects-via}
- {source: "host:strong", target: "lan:household", type: connects-via}
- {source: "ws:mac-mini", target: "lan:household", type: connects-via}
- {source: "ws:mac-mini", target: "mesh:netbird", type: connects-via}
- {source: "ws:republic-laptop", target: "mesh:netbird", type: connects-via}
- {source: "host:netbird-vps", target: "mesh:netbird", type: connects-via}
- {source: "lxc:rclone", target: "mesh:netbird", type: connects-via}
- {source: "lxc:jellyfin", target: "lan:lab", type: connects-via}
- {source: "lxc:nfs-export", target: "lan:lab", type: connects-via}
- {source: "lxc:paperless", target: "lan:lab", type: connects-via}
- {source: "lxc:gitea", target: "lan:lab", type: connects-via}
- {source: "lxc:apps", target: "lan:lab", type: connects-via}
- {source: "lxc:apps", target: "mesh:tailscale", type: connects-via}
- {source: "lxc:auth-outpost", target: "lan:lab", type: connects-via}
- {source: "lxc:dns", target: "lan:lab", type: connects-via}
- {source: "lxc:nextcloud", target: "lan:lab", type: connects-via}
- {source: "lxc:elementsynapse", target: "lan:lab", type: connects-via}
- {source: "lxc:sophia", target: "lan:lab", type: connects-via}
- {source: "lxc:mule-images", target: "lan:lab", type: connects-via}
- {source: "lxc:caddy", target: "lan:lab", type: connects-via}
- {source: "lxc:arriman", target: "lan:lab", type: connects-via}
- {source: "lxc:trmnl", target: "lan:lab", type: connects-via}
- {source: "lxc:house", target: "lan:lab", type: connects-via}
- {source: "lxc:grimmory", target: "lan:lab", type: connects-via}
- {source: "lxc:teddycloud", target: "lan:lab", type: connects-via}
- {source: "lxc:seanime", target: "lan:lab", type: connects-via}
- {source: "lxc:romm", target: "lan:lab", type: connects-via}
- {source: "vm:zimaos", target: "lan:lab", type: connects-via}
- {source: "vm:haos", target: "lan:lab", type: connects-via}
# ─── Storage ───────────────────────────────────────────────────────
- {source: "pool:ludo-lvm", target: "volume:media-local", type: contains}
- {source: "pool:library-hubris", target: "volume:library", type: contains}
- {source: "host:hubris", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:jellyfin", target: "volume:media-local", type: mounts,
attributes: {mount_point: /mnt/media_local}}
- {source: "lxc:paperless", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:gitea", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:apps", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:nextcloud", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:sophia", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:mule-images", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:arriman", target: "volume:media-local", type: mounts,
attributes: {mount_point: /mnt/media_local}}
- {source: "lxc:grimmory", target: "volume:media-local", type: mounts,
attributes: {mount_point: /mnt/media_local}}
- {source: "lxc:teddycloud", target: "volume:library", type: mounts,
attributes: {mount_point: /mnt/library}}
- {source: "lxc:seanime", target: "volume:media-local", type: mounts,
attributes: {mount_point: /mnt/media_local/anime}}
- {source: "lxc:romm", target: "volume:media-local", type: mounts,
attributes: {mount_point: /mnt/media_local}}
- {source: "lxc:jellyfin", target: "pool:ludo-lvm", type: stores-on}
- {source: "lxc:arriman", target: "pool:ludo-lvm", type: stores-on}
- {source: "lxc:grimmory", target: "pool:ludo-lvm", type: stores-on}
- {source: "lxc:romm", target: "pool:ludo-lvm", type: stores-on}
- {source: "lxc:teddycloud", target: "pool:local-lvm-hubris", type: stores-on}
- {source: "lxc:rclone", target: "backup:proton-drive", type: backs-up-to}
# The mac-mini writes the pre-deploy dumps, so it is also where the freshness
# check runs — checkdefaults resolves a backup-target's host by walking this
# edge backwards.
- {source: "ws:mac-mini", target: "backup:oikos-predeploy", type: backs-up-to}
# ─── Governance ────────────────────────────────────────────────────
- {source: "person:dtoro", target: "agent:nomos", type: owns}
- {source: "person:dtoro", target: "agent:oikos", type: owns}