Files
oikos/seeds/inventory.yaml
dtoro 8eb1ca2bac
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(seed): probe_unit for proxmox-ui/nextcloud/photos (real unit/container names)
2026-07-29 22:45:25 +02:00

647 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",
probe_unit: pveproxy.service}}
- {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,
probe_unit: apache2.service}}
- {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,
probe_unit: pp-app}}
- {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}