Claude Code with Argo CD: GitOps for Kubernetes
Argo CD made GitOps the default deploy pattern for Kubernetes. Your cluster state lives in a Git repo, Argo CD watches the repo, and any drift between Git and the cluster gets reconciled. The pattern is simple. The execution is fiddly. There are Applications, ApplicationSets, sync waves, hooks, projects, sources, and overlays, and getting them wrong means your deploy fails silently or thrashes the cluster. Claude Code is well-suited to this kind of structured YAML work because it can read the existing application tree and make consistent edits.
This post is a working developer's guide to using Claude Code with Argo CD: how to scaffold a repo, how to write applications, and the patterns that actually scale beyond a single team.
Why Argo CD over scripted kubectl
A Helm chart with helm upgrade from CI works fine until it does not. The failure modes show up at scale:
- The cluster gradually diverges from what is in Git because someone ran
kubectl edit. - A failed deploy leaves the cluster in a half-state and no one knows.
- Multi-cluster deploys require duplicate CI pipelines.
- There is no easy "what is running where" view.
Argo CD addresses all of these. The cluster is owned by Argo. Drift is detected automatically. Multi-cluster is one application per cluster. The UI shows you the live state. You get a real audit trail.
For Claude Code users specifically, GitOps is a natural fit because Claude reads and writes the same Git repo Argo is watching. There is no separate deploy step. Claude commits a change, Argo picks it up, the cluster converges. The feedback loop is fast.
Installing Argo CD
Argo CD installs into a cluster with one command:
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Then port-forward the UI:
kubectl port-forward svc/argocd-server -n argocd 8080:443
Get the initial admin password:
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
Log in at https://localhost:8080. The username is admin. You can also install the argocd CLI for scripted interactions:
brew install argocd
argocd login localhost:8080
For Helm-based installs and production hardening, see our guide to Claude Code with Kubernetes.
Repo structure that works
The single most important Argo CD decision is your repo structure. Get this wrong and every change becomes painful.
The pattern that holds up:
gitops-repo/
├── apps/
│ ├── production/
│ │ ├── frontend.yaml
│ │ ├── backend.yaml
│ │ └── redis.yaml
│ └── staging/
│ ├── frontend.yaml
│ ├── backend.yaml
│ └── redis.yaml
├── manifests/
│ ├── frontend/
│ │ ├── base/
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ └── kustomization.yaml
│ │ └── overlays/
│ │ ├── production/
│ │ │ ├── kustomization.yaml
│ │ │ └── values.yaml
│ │ └── staging/
│ │ ├── kustomization.yaml
│ │ └── values.yaml
│ └── backend/
│ └── ... (same shape)
└── argocd/
└── projects/
├── production.yaml
└── staging.yaml
apps/ holds Argo CD Application resources. manifests/ holds the Kubernetes manifests using Kustomize overlays. argocd/projects/ holds Argo CD AppProject definitions that constrain what each app can deploy.
In CLAUDE.md:
## Argo CD Conventions
- New service: add a base/ + overlays/{env}/ under manifests/{service}/.
- New environment: add overlay folder + Application yaml under apps/{env}/.
- Never edit cluster state directly. All changes go through Git.
- Image tags are pinned by SHA in overlays, never `:latest`.
- AppProjects restrict source repos, target namespaces, and resource kinds.
Claude Code will follow this structure for every new service. The repo stays predictable.
A working Application manifest
The Application resource is what tells Argo CD what to deploy and where:
# apps/production/frontend.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend-production
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: production
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: manifests/frontend/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: frontend
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
Key things to notice:
prune: truedeletes resources removed from Git.selfHeal: truereverts manual cluster changes.- The
finalizerensures Argo cleans up resources when you delete the Application. - The
retryblock handles transient sync failures.
When Claude Code generates a new Application, it should follow this template exactly. If you want different policies for staging (less aggressive self-heal, for example), document that in CLAUDE.md and Claude will branch correctly.
Sync waves for ordered deploys
Most apps have ordering constraints. The database must come up before the API. Migrations must run before the new deployment. CRDs must be installed before the controllers that use them.
Argo CD handles this with sync-wave annotations:
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1" # CRDs first
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0" # Controllers
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # Application workloads
Lower numbers go first. You can mix waves and resource hooks (PreSync, Sync, PostSync) to handle migrations:
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
This runs the migration before each sync. If it fails, the sync fails and the new deployment never rolls out. That is the behaviour you want.
Get Claudify. A Claude Code starter kit with GitOps templates and a CLAUDE.md tuned for production Kubernetes ops.
ApplicationSets for fleet management
When you have ten services across five environments, fifty Application files becomes painful. ApplicationSets generate Applications from a template:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: services
namespace: argocd
spec:
generators:
- matrix:
generators:
- list:
elements:
- service: frontend
- service: backend
- service: worker
- list:
elements:
- env: production
cluster: https://prod.example.com
- env: staging
cluster: https://staging.example.com
template:
metadata:
name: '{{service}}-{{env}}'
spec:
project: '{{env}}'
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: 'manifests/{{service}}/overlays/{{env}}'
destination:
server: '{{cluster}}'
namespace: '{{service}}'
syncPolicy:
automated:
prune: true
selfHeal: true
This one resource creates six Applications (three services x two envs). Adding a new service means one line in the list generator. Adding a new env is one element in the env list. Claude Code is excellent at maintaining ApplicationSets because the pattern is so regular.
Image automation
The remaining manual step in GitOps is updating image tags after a build. Argo CD Image Updater closes that loop:
metadata:
annotations:
argocd-image-updater.argoproj.io/image-list: app=ghcr.io/your-org/app
argocd-image-updater.argoproj.io/app.update-strategy: digest
argocd-image-updater.argoproj.io/write-back-method: git
The updater watches your registry, finds new images matching your policy, and commits a tag bump back to the GitOps repo. Argo CD picks up the commit and syncs. Your CI no longer needs to write to the GitOps repo.
If you prefer to keep image bumps in CI for visibility, that is fine too. The pattern that works is CI commits a single-line change to the overlay file. See our guide on Claude Code with GitHub Actions for the workflow.
Progressive delivery with Argo Rollouts
Argo CD handles deploys. Argo Rollouts handles deployment strategies. Together you get canary, blue-green, and analysis-based rollouts:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: frontend
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 5m }
- setWeight: 25
- pause: { duration: 5m }
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
analysis:
templates:
- templateName: error-rate
startingStep: 2
args:
- name: service-name
value: frontend
The rollout sends 10% of traffic to the new version, pauses, then 25%, then 50%, then full. The analysis block runs a Prometheus query at step 2 and beyond. If the error rate is above threshold, the rollout aborts and reverts.
This combines well with Claude Code observability tools for the analysis side.
Common pitfalls
Out-of-sync forever. Usually a default value (server-side) does not match what is in Git. Use ignoreDifferences on the Application to ignore specific fields like spec.replicas if you autoscale.
Pruning the wrong thing. prune: true deletes anything in the cluster that is not in Git, within the Application's scope. If your namespace has resources created outside the Application, they will get deleted. Use AppProjects to constrain the blast radius.
Massive sync diffs. If your repo has a big restructure pending, the first sync after the merge can rewrite half the cluster. Always do a dry-run sync (argocd app sync APP --dry-run) before applying.
Authentication for private repos. Argo CD needs read access to your GitOps repo. The right pattern is a deploy key (read-only SSH key) stored as a Kubernetes Secret. SSO to the UI is a separate matter, see our Claude Code Keycloak guide for that.
Conclusion
Argo CD is the right deploy tool for any Kubernetes setup big enough to have a "platform team" or aspirations to one. The combination with Claude Code is particularly strong because Claude operates on the same Git artefacts that Argo reads. You describe what you want, Claude writes the YAML, Argo deploys it. The pipeline is short and the audit trail is the Git log.
If you want a Claude Code project that already knows GitOps conventions, with example ApplicationSets and a CLAUDE.md tuned for Kubernetes ops, that is what Claudify packages.
Get Claudify. The official Claude Code starter kit for platform engineers and senior developers.
More like this
Ready to upgrade your Claude Code setup?
Get Claudify