# Oikos ontology seed — the systems model of the homelab. # # Bootstraps entity_types / relationship_types / lifecycle_defs on first # deploy (migration 001). After ingest the DB is authoritative; this file # is regenerated by `GET /api/v1/export` for DR + version control. # # Conventions: # - entity type names are kebab-case # - `parent:` builds the is-a hierarchy; `abstract: true` types cannot be # instantiated (validation walks the hierarchy for relationship # endpoints and policy rules — plan R3-1) # - `layer:` one of meta | infrastructure | governance | cognition # - relationship `cardinality:` describes source→target multiplicity: # one-to-one | one-to-many | many-to-one | many-to-many # - relationship endpoints may name abstract types # - lifecycle transition `requires:` entries are NAMED CHECKS implemented # in Go (internal/ontology); the DB stores which checks gate a # transition, the code implements them # - mount details (mount_point, options) live as ATTRIBUTES on `mounts` # edges, not as a separate entity type # # Rule of completeness: if something can break, be changed, or hold data, # it has an entity type here and edges to the things it touches. version: 1 # ─── Lifecycles ──────────────────────────────────────────────────────── lifecycles: infrastructure: states: [planned, provisioning, active, migrating, failed, deprecated, destroyed] default_state: active # legacy inventory entries without state are active terminal_states: [destroyed] transitions: planned: provisioning: {requires: [inventory-entry, ip-reserved, storage-pool-chosen, doc-page-stub]} destroyed: {requires: [cancelled-note]} provisioning: active: {requires: [age-key-enrolled-if-needed, mesh-joined-if-needed, ingress-live-if-public, health-check-answering, doc-page-complete]} failed: {requires: []} active: migrating: {requires: [preflight, backup-verified]} deprecated: {requires: [replacement-live-or-role-retired]} failed: {requires: []} migrating: active: {requires: [post-verify, caddy-backends-checked, mounts-checked, docs-updated]} failed: {requires: []} failed: active: {requires: [recovery-verified]} deprecated: {requires: [write-off-note]} deprecated: active: {requires: [un-deprecate-note]} destroyed: {requires: [backups-verified, secrets-revoked-and-rekeyed, ingress-and-dns-removed, no-inbound-edges, archaeology-entry]} signal: states: [raised, acknowledged, acting, muted, resolved, failed] default_state: raised terminal_states: [resolved] transitions: raised: acknowledged: {requires: []} muted: {requires: [mute-ttl-set]} resolved: {requires: [condition-cleared]} acknowledged: acting: {requires: [classification-exists]} resolved: {requires: []} muted: {requires: [mute-ttl-set]} acting: resolved: {requires: [verification-passed]} raised: {requires: [retry-budget-remaining]} failed: {requires: []} failed: acknowledged: {requires: [operator-retry]} muted: raised: {requires: [mute-ttl-expired]} execution: states: [proposed, approved, auto_approved, denied, expired, executing, verifying, verified, failed, timed_out, cancelled, rolled_back, rollback_failed] default_state: proposed terminal_states: [verified, failed, denied, expired, cancelled, rolled_back, rollback_failed] transitions: proposed: approved: {requires: [operator-approval]} auto_approved: {requires: [autonomy-allows]} denied: {requires: []} approved: executing: {requires: [approval-token-valid]} expired: {requires: [approval-ttl-elapsed]} auto_approved: executing: {requires: []} executing: verified: {requires: [verification-passed]} failed: {requires: []} timed_out: {requires: []} cancelled: {requires: [operator-abort]} timed_out: verifying: {requires: []} # check if the command completed anyway verifying: verified: {requires: [verification-passed]} failed: {requires: []} failed: rolled_back: {requires: [rollback-procedure-exists]} rollback_failed: {requires: []} approval: states: [pending, approved, denied, expired, revoked] default_state: pending terminal_states: [denied, expired, revoked] transitions: pending: approved: {requires: [token-verified]} denied: {requires: []} expired: {requires: [ttl-elapsed]} approved: revoked: {requires: [not-yet-executing]} pattern: states: [hypothesized, validated, active, deprecated, invalidated] default_state: hypothesized terminal_states: [deprecated, invalidated] transitions: hypothesized: validated: {requires: [evidence-count-5plus, confidence-0.7plus]} invalidated: {requires: []} validated: active: {requires: [operator-approval]} # S4: never automatic invalidated: {requires: []} active: deprecated: {requires: []} invalidated: {requires: [contradicting-evidence]} skill: states: [drafted, tested, active, refined, failed, deprecated] default_state: drafted terminal_states: [deprecated] transitions: drafted: tested: {requires: [test-execution-recorded]} deprecated: {requires: []} tested: active: {requires: [operator-approval]} failed: {requires: []} failed: drafted: {requires: []} active: refined: {requires: [new-version-created]} deprecated: {requires: []} refined: active: {requires: [operator-approval]} # ─── Entity types ────────────────────────────────────────────────────── # domain: physical | compute | network | storage | software | external | # identity | cognition entity_types: # Root entity: abstract: true domain: meta layer: meta description: Root abstract type. Relationship endpoints that accept any entity (documented-by, procedure-for, checks) reference this. # ── Infrastructure / physical ── site: parent: entity domain: physical layer: infrastructure lifecycle: infrastructure description: Physical location (home, VPS datacenter). monitoring: none # topological — health is its members' attributes: {type: object, properties: {address: {type: string}}} ups: parent: entity domain: physical layer: infrastructure lifecycle: infrastructure description: Uninterruptible power supply. monitoring: none # warranted, but no SNMP/NUT checker exists yet attributes: {type: object, properties: {vendor: {type: string}, va: {type: integer}}} sensor: parent: entity domain: physical layer: infrastructure lifecycle: infrastructure description: Environmental sensor. monitoring: none # readings are metrics, not health peripheral: parent: entity domain: physical layer: infrastructure lifecycle: infrastructure description: Attached hardware (GPU, e-ink display, dongle). monitoring: none # visible only through its host # ── Infrastructure / compute ── compute-entity: parent: entity abstract: true domain: compute layer: infrastructure description: Anything that executes workloads (machine, VM, container). machine: parent: compute-entity abstract: true domain: compute layer: infrastructure description: Physical machine. Always instantiated as a subtype. monitoring: [ping, resource, updates] # inherited by proxmox-host / # standalone-server / workstation / appliance attributes: type: object properties: cpu_arch: {type: string} ram_gb: {type: number} os: {type: string, enum: [linux, macos]} lan_ip: {type: string} mesh: {type: object} ssh: {type: object} age_pubkey: {type: string} proxmox-host: parent: machine domain: compute layer: infrastructure lifecycle: infrastructure description: Machine running Proxmox VE. attributes: type: object properties: {pve_version: {type: string}} standalone-server: parent: machine domain: compute layer: infrastructure lifecycle: infrastructure description: Machine outside PVE management (e.g. external VPS). attributes: type: object properties: hypervisor: {type: string} provider: {type: string} control_level: {type: string, enum: [full, partial, none]} public_ipv4: {type: string} workstation: parent: machine domain: compute layer: infrastructure lifecycle: infrastructure description: Operator machine (may also host services, e.g. mac-mini). attributes: type: object properties: {user: {type: string}} appliance: parent: machine domain: compute layer: infrastructure lifecycle: infrastructure description: Vendor appliance with limited management access. attributes: type: object properties: {vendor: {type: string}, model: {type: string}} vm: parent: compute-entity domain: compute layer: infrastructure lifecycle: infrastructure description: Virtual machine. monitoring: [ping] # no guest agent assumed; reachability only attributes: type: object properties: pve_id: {type: integer} vcpus: {type: integer} memory_mb: {type: integer} lan_ip: {type: string} public_host: {type: string} role: {type: string} container: parent: compute-entity abstract: true domain: compute layer: infrastructure description: OS-level container (LXC or Docker). monitoring: [resource] # inherited by lxc / docker-container attributes: type: object properties: {runtime: {type: string}} lxc: parent: container domain: compute layer: infrastructure lifecycle: infrastructure description: Proxmox LXC container. attributes: type: object properties: pve_id: {type: integer} lan_ip: {type: string} public_host: {type: string} public_hosts: {type: array, items: {type: string}} role: {type: string} mesh: {type: object} age_pubkey: {type: string} destroyed: {type: string} reason: {type: string} docker-container: parent: container domain: compute layer: infrastructure lifecycle: infrastructure description: Docker container (the OS models its own stack with these). attributes: type: object properties: {image: {type: string}} hypervisor: parent: entity domain: compute layer: infrastructure lifecycle: infrastructure description: Hypervisor software running on a machine (PVE, KVM, OrbStack). monitoring: none # the hosting machine's checks cover it attributes: type: object properties: {type: {type: string}, version: {type: string}} # ── Infrastructure / network ── network: parent: entity abstract: true domain: network layer: infrastructure description: A network things connect to. monitoring: none # inherited by lan / mesh / vlan — a network's # reachability is a property of its members lan: parent: network domain: network layer: infrastructure lifecycle: infrastructure description: Local area network. attributes: {type: object, properties: {subnet: {type: string}}} mesh: parent: network domain: network layer: infrastructure lifecycle: infrastructure description: Overlay mesh network (NetBird, Tailscale). attributes: type: object properties: provider: {type: string} subnet: {type: string} domain: {type: string} vlan: parent: network domain: network layer: infrastructure lifecycle: infrastructure description: Tagged VLAN. attributes: {type: object, properties: {tag: {type: integer}}} network-interface: parent: entity domain: network layer: infrastructure description: Optional per-interface refinement (mac, ip). The seed uses coarse connects-via edges; interfaces can be backfilled later. monitoring: none # covered by its machine's ping/resource checks attributes: {type: object, properties: {mac: {type: string}, ip: {type: string}}} dns-zone: parent: entity domain: network layer: infrastructure lifecycle: infrastructure description: DNS zone (e.g. split-horizon hubris.network). monitoring: [dns] # NOTE: no `dns` checker exists yet — this is a # real gap and coverageSweep will report it attributes: {type: object, properties: {zone: {type: string}, authority: {type: string}}} dns-record: parent: entity domain: network layer: infrastructure description: Individual DNS record. monitoring: none # the zone is the unit of monitoring attributes: type: object properties: {name: {type: string}, record_type: {type: string}, value: {type: string}} ingress-route: parent: entity domain: network layer: infrastructure lifecycle: infrastructure description: Public hostname → upstream mapping (Caddy). monitoring: [http] # end-to-end: exercises Caddy + DNS + TLS + upstream attributes: type: object properties: pattern: {type: string} upstream: {type: string} forward_auth: {type: boolean} certificate: parent: entity domain: network layer: infrastructure description: TLS certificate. monitoring: [cert-expiry] attributes: {type: object, properties: {issuer: {type: string}, expires: {type: string}}} firewall-rule: parent: entity domain: network layer: infrastructure description: Firewall / port-forward rule. monitoring: none # declarative config, not a running thing # ── Infrastructure / storage ── storage-pool: parent: entity domain: storage layer: infrastructure lifecycle: infrastructure description: Storage pool (LVM, ZFS, NFS). monitoring: [capacity] attributes: type: object properties: type: {type: string} capacity_gb: {type: number} volume: parent: entity domain: storage layer: infrastructure lifecycle: infrastructure description: Named volume / dataset within a pool. Mount details live as attributes on `mounts` edges. monitoring: [capacity] attributes: {type: object, properties: {size_gb: {type: number}, path: {type: string}}} backup-target: parent: entity domain: storage layer: infrastructure lifecycle: infrastructure description: Where backups land (Proton Drive, PBS). monitoring: [backup-freshness] # checker lands in Phase 4 attributes: {type: object, properties: {provider: {type: string}, encrypted: {type: boolean}}} dataset: parent: entity domain: storage layer: infrastructure description: Logical data collection worth tracking independently of its volume (e.g. paperless documents). monitoring: none # its volume and owning service carry the checks # ── Infrastructure / software ── service: parent: entity domain: software layer: infrastructure lifecycle: infrastructure description: A running service with consumers. monitoring: [http, process] # http when it has a `url`, else a process check # on the host resolved through its hosting edge attributes: type: object properties: url: {type: string} port: {type: integer} health: {type: string} endpoint: {type: string} systemd_unit: {type: string} doc_page: {type: string} risk_notes: {type: string} note: {type: string} application: parent: entity domain: software layer: infrastructure description: Deployed application/package a service runs. monitoring: none # the service in front of it is the probe target attributes: {type: object, properties: {version: {type: string}}} config-repo: parent: entity domain: software layer: infrastructure description: Git repo holding tracked configuration. monitoring: none # its Gitea service carries the checks attributes: type: object properties: {url: {type: string}, branch: {type: string}} deploy-pipeline: parent: entity domain: software layer: infrastructure description: Automated deploy path (webhook → script). monitoring: none # health is per-deploy, tracked as executions attributes: type: object properties: {trigger: {type: string}, target_path: {type: string}} package-set: parent: entity domain: software layer: infrastructure description: Managed package baseline for a host class. monitoring: none # drift shows up via each host's updates check cluster: parent: entity domain: software layer: infrastructure lifecycle: infrastructure description: Proxmox cluster. monitoring: none # topological — its member hosts carry the checks attributes: {type: object, properties: {quorum: {type: string}}} compose-stack: parent: entity domain: software layer: infrastructure lifecycle: infrastructure description: Docker Compose stack (the Oikos OS itself is one). monitoring: [process] attributes: {type: object, properties: {path: {type: string}}} # ── Infrastructure / external ── domain-registration: parent: entity domain: external layer: infrastructure description: Registered public domain. monitoring: none # expiry is a calendar concern, not a probe attributes: {type: object, properties: {registrar: {type: string}, expires: {type: string}}} cloud-service: parent: entity domain: external layer: infrastructure description: External SaaS/cloud dependency. monitoring: [http] # only when the entity carries a `url` isp-link: parent: entity domain: external layer: infrastructure description: Internet uplink. monitoring: none # no probe target; reachability shows up fleet-wide vendor-dependency: parent: entity domain: external layer: infrastructure description: Vendor the lab depends on (registrar, IONOS, Proton). monitoring: none # a commercial relationship, not a running thing # ── Governance / identity ── person: parent: entity domain: identity layer: governance description: Human actor (operator). attributes: type: object properties: {matrix_id: {type: string}, oidc_sub: {type: string}, email: {type: string}} agent: parent: entity domain: identity layer: governance lifecycle: infrastructure # agents are deployed/retired like infrastructure description: Software agent actor (Nomos, the Oikos control loop). monitoring: [http] # governance layer, but genuinely probeable — # Nomos serves a gateway on :8092 attributes: type: object properties: provider: {type: string} model: {type: string} gateway_port: {type: integer} identity-provider: parent: entity domain: identity layer: governance description: OIDC / forward-auth provider (Authentik). attributes: type: object properties: issuer: {type: string} client_id: {type: string} auth_mode: {type: string, enum: [oidc, forward-auth, both]} account: parent: entity domain: identity layer: governance description: An account a person/agent holds on a service. secret: parent: entity domain: identity layer: governance description: Managed secret (Infisical path). attributes: type: object properties: {path: {type: string}, rotation_days: {type: integer}} key: parent: entity domain: identity layer: governance description: Cryptographic key (SSH, age). access-grant: parent: entity domain: identity layer: governance description: Grant of access to a secret/scope. attributes: {type: object, properties: {scope: {type: string}, expires: {type: string}}} # ── Cognition ── check: parent: entity domain: cognition layer: cognition description: Probe definition (checks-as-data, R3-7). Typed row in check_defs. signal: parent: entity domain: cognition layer: cognition lifecycle: signal description: Something needing attention. Typed row in signals. classification: parent: entity domain: cognition layer: cognition description: A classifier decision with full reasoning. Typed row in classifications. execution: parent: entity domain: cognition layer: cognition lifecycle: execution description: An action the OS performed. Typed row in executions. feedback: parent: entity domain: cognition layer: cognition description: What was learned from an execution. Typed row in feedback. pattern: parent: entity domain: cognition layer: cognition lifecycle: pattern description: Generalized rule extracted from feedback. Typed row in patterns. skill: parent: entity domain: cognition layer: cognition lifecycle: skill description: Codified, versioned procedure. Typed rows in skills. approval: parent: entity domain: cognition layer: cognition lifecycle: approval description: Operator approval request/decision. Typed row in approvals. document: parent: entity domain: cognition layer: cognition description: Knowledge document ingested from docs/. attributes: type: object properties: {title: {type: string}, source_path: {type: string}, content_hash: {type: string}} runbook: parent: entity domain: cognition layer: cognition description: Step-by-step procedure for an entity/action. attributes: type: object properties: {risk_class: {type: string}, source_path: {type: string}} investigation: parent: entity domain: cognition layer: cognition description: Recorded investigation/postmortem. task: parent: entity domain: cognition layer: cognition description: A goal-structured unit of agent work — one chat/session elevated to a task with a plan, lifecycle status, and outcome. Anchors the knowledge and involved-entity relationships for the task so future tasks can learn from it. Typed rows in agent_sessions. # ─── Relationship types ──────────────────────────────────────────────── # cardinality is source→target: e.g. `hosts` one-to-many = one machine # hosts many compute entities; each hosted entity has one hosting machine. relationship_types: # Infrastructure topology hosts: inverse: runs-on source: machine target: compute-entity cardinality: one-to-many description: Machine hosts a VM/container (hubris hosts lxc:apps). blast_direction: forward runs-hypervisor: inverse: hypervisor-on source: machine target: hypervisor cardinality: one-to-one description: Machine runs hypervisor software. blast_direction: forward member-of: inverse: has-member source: proxmox-host target: cluster cardinality: many-to-one description: PVE host belongs to a cluster. blast_direction: backward part-of: inverse: comprises source: docker-container target: compose-stack cardinality: many-to-one description: Docker container belongs to a compose stack. blast_direction: backward provides: inverse: provided-by source: compute-entity target: service cardinality: one-to-many description: Compute entity provides a service (lxc:gitea provides service:gitea). blast_direction: forward runs: inverse: run-by source: service target: application cardinality: one-to-many description: Service runs an application. blast_direction: backward configured-by: inverse: configures source: entity target: config-repo cardinality: many-to-one description: Entity's config is tracked in a repo (mutations = commit+push). deploys-to: inverse: deployed-by source: deploy-pipeline target: entity cardinality: many-to-one description: Pipeline deploys to a service/host. blast_direction: forward routes-to: inverse: routed-via source: ingress-route target: service cardinality: many-to-one description: Public hostname routes to a service. blast_direction: backward served-by: inverse: serves source: ingress-route target: service cardinality: many-to-one description: Ingress route is terminated by this reverse proxy. Distinct from routes-to, which names the BACKEND the route forwards to — without this edge the proxy's blast radius is invisible, and lxc:caddy reported one affected entity despite terminating every *.hubris.network route. blast_direction: backward secured-by: inverse: secures source: ingress-route target: identity-provider cardinality: many-to-one description: Route gated by forward-auth. blast_direction: backward uses-certificate: inverse: certifies source: ingress-route target: certificate cardinality: many-to-one description: Route served with this certificate. blast_direction: backward authenticates-via: inverse: authenticates-service source: service target: identity-provider cardinality: many-to-one description: Service uses native OIDC (jellyfin authenticates-via authentik). blast_direction: backward in-zone: inverse: contains-record source: dns-record target: dns-zone cardinality: many-to-one description: Record belongs to a zone. blast_direction: backward resolves-to: inverse: resolved-from source: dns-record target: entity cardinality: many-to-one description: Record points at an ingress route or host. depends-on: inverse: dependency-of source: service target: service cardinality: many-to-many description: Runtime dependency (blast-radius edge). blast_direction: backward connects-via: inverse: connects source: compute-entity target: network cardinality: many-to-many description: Coarse network membership (host on LAN / mesh). blast_direction: backward has-interface: inverse: interface-of source: compute-entity target: network-interface cardinality: one-to-many description: Optional per-interface refinement. blast_direction: backward interface-on: inverse: has-endpoint source: network-interface target: network cardinality: many-to-one description: Interface attaches to a network. blast_direction: backward # Storage mounts: inverse: mounted-by source: compute-entity target: volume cardinality: many-to-many description: Compute entity mounts a volume. Edge attributes carry mount_point and options. blast_direction: backward stores-on: inverse: stores-for source: compute-entity target: storage-pool cardinality: many-to-many description: Rootfs/data lives on a pool. blast_direction: backward contains: inverse: contained-in source: storage-pool target: volume cardinality: one-to-many description: Pool contains a volume. blast_direction: forward holds-dataset: inverse: dataset-on source: volume target: dataset cardinality: one-to-many description: Volume holds a tracked dataset. blast_direction: backward backs-up-to: inverse: backup-of source: entity target: backup-target cardinality: many-to-many description: Entity's data is backed up to a target. # Physical / external powered-by: inverse: powers source: machine target: ups cardinality: many-to-one description: Machine on UPS power. blast_direction: backward located-at: inverse: location-of source: machine target: site cardinality: many-to-one description: Machine's physical site. blast_direction: backward registered-with: inverse: registrar-of source: domain-registration target: vendor-dependency cardinality: many-to-one description: Domain registered with a registrar. # Governance owns: inverse: owned-by source: person target: agent cardinality: one-to-many description: Person owns/controls an agent. authenticates: inverse: authenticated-by source: identity-provider target: person cardinality: one-to-many description: IdP authenticates a person. holds-grant: inverse: granted-to source: agent target: access-grant cardinality: one-to-many description: Agent holds an access grant. grants: inverse: granted-by source: access-grant target: secret cardinality: many-to-one description: Grant covers a secret. blast_direction: forward can-decrypt: inverse: readable-by source: compute-entity target: secret cardinality: many-to-many description: Host can decrypt a secret (legacy SOPS; Infisical grants later). blast_direction: backward # Cognition checks: inverse: checked-by source: check target: entity cardinality: many-to-one description: Check probes an entity. raises: inverse: raised-by source: check target: signal cardinality: one-to-many description: Check raised a signal. about: inverse: subject-of source: entity target: entity cardinality: many-to-many description: Entity concerns (or is about) another entity. classifies: inverse: classified-as source: classification target: signal cardinality: many-to-one description: Classification of a signal. precedes: inverse: follows source: classification target: execution cardinality: one-to-one description: Classification that led to an execution. targets: inverse: targeted-by source: execution target: entity cardinality: many-to-one description: Execution acts on an entity. requires-approval: inverse: approves source: execution target: approval cardinality: one-to-one description: Execution gated by an approval. performs: inverse: performed-by source: agent target: execution cardinality: one-to-many description: Agent performed an execution. decides: inverse: decided-by source: person target: approval cardinality: one-to-many description: Person decided an approval. produces: inverse: produced-by source: execution target: feedback cardinality: one-to-one description: Execution produced feedback. contributes-to: inverse: built-from source: feedback target: pattern cardinality: many-to-many description: Feedback supports a pattern. informs: inverse: informed-by source: pattern target: skill cardinality: many-to-one description: Pattern informs a skill. guides: inverse: guided-by source: skill target: classification cardinality: one-to-many description: Skill guided a classification. documents: inverse: documented-by source: document target: entity # many-to-many, not many-to-one: a single investigation routinely covers # several entities (a fleet-wide apt audit documents every host it # touched), and Nomos has been writing such edges for months. The stricter # declaration made ~40 of them cardinality violations, which only surfaced # once the seed could complete far enough to run ValidateCardinality. cardinality: many-to-many description: Document describes an entity. involves: inverse: involved-in source: task target: entity cardinality: many-to-many description: Task explored or acted on an entity (captured from its tool calls). A task's involved-entity set is its graph neighborhood, so future tasks on the same entities can surface this task's knowledge and outcome. procedure-for: inverse: has-procedure source: runbook target: entity cardinality: many-to-many description: Runbook applies to an entity.