Decisions
Three records explain most of the current shape of the homelab. All live in the Hill90 repository as the authority; this page summarises them.Platform primitives
Status: decided, recorded 2026-07-26. Supersedes the reasoning in A homelab platform, not an application host below. Hill90 is a deliberate open-source counterpart to the Azure platform primitives Jon works with professionally, so that operating it builds transferable skill. The mapping is on the Overview. The record exists because that intent was never written down, and the cost of not writing it down was concrete: during the July strip, Keycloak and Postgres were reasoned about as application dependencies, found to have no surviving consumer, and deleted. That conclusion was correct given what was recorded and wrong given the actual intent — and the same argument won three separate times in one day, because footprint was written down and capability was not. What follows from it, in the record’s terms: a platform primitive does not have to justify itself by naming a current consumer, “no consumer today” is evidence of an under-used platform rather than an argument for deletion, and multi-user is a real requirement because the operator count is not one. →docs/decisions/platform-primitives.md
A homelab platform, not an application host
Status: implemented. Decided 2026-07-11, implemented 2026-07-26. Hill90 is a homelab domain rather than an application host. The infrastructure repository holds infrastructure: CI checks and deploy scripting, and no application services. Keycloak, Postgres and MinIO run here as platform services — they exist to be consumed, and do not need to name an application to justify themselves; see Platform primitives above. The AI agent application is a tenant of the platform, not the reason for it. It runs on this VPS and serves hill90.com from its own repository, consuming the platform’s identity, database and storage;Verified 2026-08-03. See
AI Application.
The same decision settled kubeadm over k3s for the future Kubernetes boilerplate —
identical API and tooling either way, but kubeadm gives hands-on exposure to etcd, CNI
and certificate management, and an etcd backup/restore story that k3s’s SQLite datastore
would not provide. The generic boilerplate repositories it envisaged
(docker-infra-template, k8s-cluster-template) are a separate, parallel effort.
→ docs/decisions/infra-app-separation.md
Vault versus SOPS
Status: open. Raised 2026-07-26. The call is Jon’s. The record was written when the vault was empty, and recommended that SOPS remain the operative store until the vault had a concrete consumer. Events have since overtaken parts of it. The vault has been reinitialized and configured — policies and AppRoles exist — and the weeklyvault-sync-to-sops schedule, which the record describes as
disabled after failing every Monday since 2026-06-01, was re-enabled on 2026-07-26 once a
manual run went green.
But the recommendation has, if anything, been strengthened. Every deploy on record
falls back to SOPS, with evidence in
Secrets. The vault does
have one working consumer — the vault-sync-to-sops workflow reads from it — but no
deploy has ever taken the vault path, and the stack most likely to succeed at it has not
been deployed since before this vault existed. Tracked as
Hill90 issue 536.
The record’s own framing also needs revisiting rather than just its facts: deploy.sh
reads its AppRole credentials out of SOPS in order to log in to the vault, so the question
is not “vault or SOPS” but “SOPS alone” versus “SOPS plus a vault that SOPS bootstraps”.
The decision itself — whether the vault or SOPS is the operative store — has not been
recorded as made. The OpenBao image tag is pinned to 2.6.1, so no upgrade can arrive by
surprise.
What remains is a real constraint: OpenBao’s file storage backend is deprecated, and
the vault cannot move past 2.6.x without switching to raft. Production is still on
file — verified on the running container — even though the repository has since gained a
reinitialize-with-raft path. The record’s argument that migrating this vault was the
wrong move was made when it was empty and unconfigurable; that premise no longer holds,
which is a reason to revisit the record rather than to act on it as written.
There is no deadline, but there is a decision, and it resurfaces the first time a
security fix lands in a version the current pin cannot reach.
→ docs/decisions/vault-vs-sops.md