Two repositories
The platform is written in one repository and installed from another.
Until this page existed, the second one was named nowhere in this repository — not in a README, not in a document, not in a comment. Every infrastructure page here was therefore honest and wrong at the same time: it described exactly what is visible from here, and the installation is not visible from here. A reader who opened GitOps or Cluster & nodes in good faith would start building something that has been standing and serving traffic for weeks.
The second repository is Agentfy/gitops.
this repository (Agentfy/agentfy) | Agentfy/gitops | |
|---|---|---|
| Product code | api, app, admin, worker, and these documents | — |
| Kubernetes objects | two templates that the runtime/worker slice applies itself, at runtime, once per session (k8s/runtime/) | everything long-lived: the Argo CD Applications and the Helm charts they deliver |
| Terraform | terraform/ — a self-contained path for raising a cluster from nothing, on Hetzner or on AWS. See the caveat below. | terraform/ + ansible/ — what the servers that are actually running were raised from |
| Secrets | none. The api reads its configuration out of the environment it is given | Vault, and the External Secrets objects that turn a Vault path into an ordinary Kubernetes Secret |
| Deploys | — | a commit. Every Application runs automated: {prune: true, selfHeal: true} |
The rule that keeps them from lying to each other: link, never copy. A manifest pasted into this repository is a manifest that will disagree with the original inside a month, and that disagreement is the exact disease this page exists to treat. Name the file; the file is the truth.
What Argo CD runs today
Read out of the manifests in Agentfy/gitops, file by file — not from anyone's description of them.
| What | Declared in | What that file actually says |
|---|---|---|
| The root | bootstrap/root-app.yaml | one Application named root, watching gitops-apps/control on main. Applied by hand, once; everything below is reached from it |
| Argo CD itself | gitops-apps/control/argocd.yaml | helm chart argo-cd 10.3.2, managing itself, server.insecure: true (TLS ends at Traefik) |
| Vault | gitops-apps/control/vault.yaml | helm chart vault 0.34.0, standalone, dataStorage 5Gi, Traefik ingress on vault.agentfy.ai with cert-manager.io/cluster-issuer: letsencrypt-prod, ui.enabled: true |
| Rancher | gitops-apps/control/rancher.yaml | chart rancher 2.15.0 on rancher.agentfy.ai |
| cert-manager | gitops-apps/control/cert-manager.yaml, and one per contour under gitops-apps/{dev,prod}/ | v1.21.1, CRDs on |
| External Secrets Operator | gitops-apps/dev/external-secrets.yaml and gitops-apps/prod/external-secrets.yaml | chart external-secrets 2.9.0, in both contours, ServiceAccount external-secrets |
| The Vault store | gitops-apps/{dev,prod}/manifests/external-secret*/clustersecretstore.yaml | a ClusterSecretStore named vault: server https://vault.agentfy.ai, KV v2 at path secret, kubernetes auth, mountPath kubernetes-dev / kubernetes-prod, role eso |
| A live consumer, in production | gitops-apps/prod/manifests/external-secrets/externalsecret-external-dns.yaml | pulls prod/external-dns into the cluster Secret external-dns-aws, refreshInterval: 1h |
| ExternalDNS | gitops-apps/{dev,prod}/external-dns.yaml | chart 1.21.1, Route53, domainFilters: [agentfy.ai], policy: sync, one txtOwnerId per contour |
| Reloader | gitops-apps/dev/reloader.yaml | stakater reloader 2.2.14 |
| The product | agentfy-apps/dev/agentfy-{api,app,admin,redis}.yaml → helm/agentfy-{api,app,admin,redis}/ | four charts into namespace agentfy on the dev cluster, ordered by sync-wave: redis (0), api (1), app and admin (2) |
Two of those deserve a sentence each, because a page in this repository still says the opposite somewhere:
- The api is deployed, and by Argo CD.
helm/agentfy-api/carries the Deployment, Service, Ingress, HPA, ConfigMap, theruntime-controller/runtime-workerRBAC and theExternalSecretthat fills the api's environment out of Vault (values.dev.yaml→secrets.vaultKey: dev/agentfy-api). - Prisma migrations run, but as an initContainer on the api Deployment (
helm/agentfy-api/templates/deployment.yaml,runMigrations), not as the Argo PreSync hook these documents planned for.
Where the boundary actually falls
The clean half is easy: Argo CD and everything Argo CD deploys live in Agentfy/gitops. Nothing in this repository deploys a long-lived workload, and nothing in this repository should start.
The other half is less tidy than it looks, and it is written down here rather than smoothed over:
- The servers under the running installation were also raised from
Agentfy/gitops—terraform/mgmt.tf,terraform/db.tf,terraform/loadbalancer.tffor the Hetzner network, the management node, the two PostgreSQL nodes and the load balancers;ansible/k3s.ymlfor the single-node k3s control cluster on the management node. The dev and prod workload clusters are provisioned through Rancher, which is whyloadbalancer.tfsays thelb-targetlabel is applied by Rancher and why every workloadApplicationtargetshttps://10.0.1.3:6443(dev) orhttps://10.0.1.9:6443(prod) rather than the control cluster. - This repository's
terraform/is therefore a second path, not the one that ran. It raises a cluster withkube-hetzner(or EKS on the AWS side), in three node pools, with CloudNativePG and an in-cluster Redis. The live installation has none of that shape: Postgres is on its own Hetzner VMs configured byansible/roles/postgres, and Redis is a plain Deployment fromhelm/agentfy-redis.
Whether this repository's terraform/ is meant to replace that path, or to serve a second installation, or to be retired, is written down nowhere that could be checked — so this page does not decide it. See terraform/README.md, which now carries the same caveat at the top.
What stays here, and why it is not a duplicate
k8s/runtime/ holds two templates and neither is Argo CD's:
namespace-rbac.template.yaml— the ServiceAccount, Role and RoleBinding for one runtime namespace.worker-egress.template.yaml— default-deny egress over the worker's pods.
They are applied imperatively, at runtime, by the runtime/worker slice and by .superset/k3d.sh on a laptop, with __NAMESPACE__ and the control-channel placeholders substituted at apply time. Argo CD must never own them: it would see every session's objects as drift and prune them mid-task.
One honest wrinkle: helm/agentfy-api/templates/runtime-rbac.yaml in Agentfy/gitops is a second expression of the same RBAC, written as a Helm template rather than a placeholder file. The two are not generated from each other and can drift. That is a real cost, and it is named here rather than discovered later.
What could not be verified
Stated as gaps, because inventing a confirmation is worse than admitting one is missing:
- Where the application images are built.
helm/*/values.dev.yamlpinsghcr.io/agentfy/agentfy-{api,app,admin}at concrete tags, so images exist — but neither repository contains a workflow that builds or pushes one.Agentfy/gitops's three GitHub Actions workflows areansible-lintand two manual Ansible runs. apphas noDockerfilein this repository —api,adminandworkerdo — yethelm/agentfy-app/values.dev.yamlpins anagentfy-appimage. Where that image comes from is recorded in neither repository.- The
prodcontour has no product.gitops-apps/control/declaresagentfy-dev-servicesand no prod equivalent, andagentfy-apps/has only adev/folder. Production runs the platform (ESO, cert-manager, ExternalDNS, reloader) and, as far as the manifests go, none of the four applications. - Nothing was checked against a live cluster. Every statement on this page comes from a file in
Agentfy/gitopsatmain. A manifest is what Argo CD is told to converge to; that it has converged is a separate claim, and this page does not make it.
See also
- GitOps (ArgoCD) — the design, and which parts of it the installation took.
- Cluster & nodes · Resources · Cloud strategy — the plan, with today's state marked.