GitOps & the app-of-apps
Project Loom runs on one idea: Git is the desired state, and a controller continuously makes the cluster match it.
You almost never kubectl apply by hand — you commit YAML, push, and Argo CD reconciles. (The one
exception is the one-time root-app bootstrap — see App-of-apps below.) This is
GitOps, and it applies the same way to every app on the platform.
The reconcile loop
Section titled “The reconcile loop”flowchart LR Dev([You]) -->|git push| Repo[(webb1es/loom)] Repo -->|polls / webhook| Argo[Argo CD] Argo -->|diff desired vs live| K8s[(Kubernetes)] K8s -->|actual state| Argo Argo -->|apply changes| K8s Argo -.->|out of sync? self-heal| K8s
Argo CD compares the manifests in Git against what’s live in the cluster. If they differ, it applies the difference (and
with selfHeal, it reverts any manual drift).
App-of-apps
Section titled “App-of-apps”A single root Application points at the apps/ directory. Platform files there are Argo CD Applications
(operators, Infisical). apps/workloads.yaml is an ApplicationSet that generates one Application per app×env
(penvoice-staging, penvoice-prod, …). Bootstrap the platform by applying one manifest; everything else cascades.
flowchart TD Root[root Application] --> A[apps/cnpg-operator] Root --> B[apps/keycloak-operator] Root --> C[apps/workloads ApplicationSet] C --> C1[penvoice-staging / penvoice-prod] C --> C2[keycloak-staging / keycloak-prod] A --> A1[CloudNativePG operator] C1 --> C1b[API Rollout + Postgres + Redis + ingress] C2 --> C2b[Keycloak instance + Postgres]
Why it matters: adding a new app is a workloads/<app>/{base,overlays} copy plus two list entries in
apps/workloads.yaml. Standing up a node is Provision (Helm, then the root app).
See Onboard an app for the next product.