Skip to content

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 codeapi, app, admin, worker, and these documents
Kubernetes objectstwo 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
Terraformterraform/ — 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
Secretsnone. The api reads its configuration out of the environment it is givenVault, and the External Secrets objects that turn a Vault path into an ordinary Kubernetes Secret
Deploysa 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.

WhatDeclared inWhat that file actually says
The rootbootstrap/root-app.yamlone Application named root, watching gitops-apps/control on main. Applied by hand, once; everything below is reached from it
Argo CD itselfgitops-apps/control/argocd.yamlhelm chart argo-cd 10.3.2, managing itself, server.insecure: true (TLS ends at Traefik)
Vaultgitops-apps/control/vault.yamlhelm 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
Ranchergitops-apps/control/rancher.yamlchart rancher 2.15.0 on rancher.agentfy.ai
cert-managergitops-apps/control/cert-manager.yaml, and one per contour under gitops-apps/{dev,prod}/v1.21.1, CRDs on
External Secrets Operatorgitops-apps/dev/external-secrets.yaml and gitops-apps/prod/external-secrets.yamlchart external-secrets 2.9.0, in both contours, ServiceAccount external-secrets
The Vault storegitops-apps/{dev,prod}/manifests/external-secret*/clustersecretstore.yamla 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 productiongitops-apps/prod/manifests/external-secrets/externalsecret-external-dns.yamlpulls prod/external-dns into the cluster Secret external-dns-aws, refreshInterval: 1h
ExternalDNSgitops-apps/{dev,prod}/external-dns.yamlchart 1.21.1, Route53, domainFilters: [agentfy.ai], policy: sync, one txtOwnerId per contour
Reloadergitops-apps/dev/reloader.yamlstakater reloader 2.2.14
The productagentfy-apps/dev/agentfy-{api,app,admin,redis}.yamlhelm/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, the runtime-controller / runtime-worker RBAC and the ExternalSecret that fills the api's environment out of Vault (values.dev.yamlsecrets.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/gitopsterraform/mgmt.tf, terraform/db.tf, terraform/loadbalancer.tf for the Hetzner network, the management node, the two PostgreSQL nodes and the load balancers; ansible/k3s.yml for the single-node k3s control cluster on the management node. The dev and prod workload clusters are provisioned through Rancher, which is why loadbalancer.tf says the lb-target label is applied by Rancher and why every workload Application targets https://10.0.1.3:6443 (dev) or https://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 with kube-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 by ansible/roles/postgres, and Redis is a plain Deployment from helm/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.yaml pins ghcr.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 are ansible-lint and two manual Ansible runs.
  • app has no Dockerfile in this repositoryapi, admin and worker do — yet helm/agentfy-app/values.dev.yaml pins an agentfy-app image. Where that image comes from is recorded in neither repository.
  • The prod contour has no product. gitops-apps/control/ declares agentfy-dev-services and no prod equivalent, and agentfy-apps/ has only a dev/ 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/gitops at main. 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