| name | argo-cd-apps |
| description | Author and maintain Argo CD `Application` and `ApplicationSet` manifests as a GitOps consumer (publisher), targeting Argo CD v3.3 / v3.4 (May 2026). Covers source types (Helm, Kustomize, OCI, multi-source, plugin), sync policies + options + waves + hooks, ApplicationSet generators (List, Cluster, Git, Matrix, Merge, SCMProvider, PullRequest, Plugin, ClusterDecisionResource), Progressive Sync (Beta), Source Hydrator (still Alpha), AppProjects, RBAC, sync impersonation (`destinationServiceAccounts`), GPG/cosign signature verification, GitOps repo layout (mono vs poly, app-of-apps vs ApplicationSet — Argo recommends ApplicationSet first), troubleshooting drift / OutOfSync / sync loops / stuck-deletion / hook failures, and v3.0→v3.4 changes (annotation tracking default, SSA-migration regression, CVE-2026-42880 Secret leak). NOT for installing or operating the Argo CD control plane (HA, Dex, repo-server tuning, UI customization). |
| when_to_use | Use whenever the user mentions Argo CD, ArgoCD, GitOps, Application CR, ApplicationSet, app-of-apps, sync policy, sync wave, AppProject, GitOps repo, publishing apps to Kubernetes via Argo, or migrating from Flux to Argo CD — even if they don't say "Argo CD" explicitly. |
Argo CD application authoring
For developers and platform teams who publish Argo CD Application and
ApplicationSet manifests in git. Targets Argo CD v3.3.9 (latest stable) and
v3.4 (RC). Cited file paths in references/ are relative to a local clone
of argoproj/argo-cd (e.g. docs/user-guide/best_practices.md). Without
a local clone, fetch the same content via gh api repos/argoproj/argo-cd/contents/<path>
or read https://github.com/argoproj/argo-cd at the matching path.
Quick decision guide
| Task | Go to |
|---|
Write a new Application from scratch | § Canonical Application below |
Pick source vs sources (multi-source); choose Helm/Kustomize/OCI | references/application.md |
Write an ApplicationSet (any generator) | § Canonical ApplicationSet + references/applicationset.md |
| Pick the right ApplicationSet generator | references/applicationset.md § Generator Picker |
Set sync policy / syncOptions / retry / selfHeal | § Sync policy below + references/sync.md |
| Add sync waves / hooks / health checks | references/sync.md § Waves, Hooks, Health |
| Stop drift fights (HPA, webhooks, kubectl edits) | references/troubleshooting.md § OutOfSync drivers |
| Lay out the GitOps repo (mono vs poly, app-of-apps) | references/repo-layout.md |
Write/audit an AppProject for multi-tenancy | references/projects-rbac.md § AppProject |
| Configure sync impersonation (per-app SA) | references/projects-rbac.md § Impersonation |
| Verify signed commits / OCI artefacts | references/projects-rbac.md § Signature verification |
App stuck deleting / ComparisonError / SyncFailed | references/troubleshooting.md |
| Upgrading 3.x → 3.y, deprecations, "what to drop" | references/version-changes.md |
Critical gotchas (May 2026)
1. CVE-2026-42880 — IncludeMutationWebhook=true leaks Secrets
Patched v3.3.8 / v3.2.10 / v3.1.15 (2026-04-21 batch). ServerSideDiff +
argocd.argoproj.io/compare-options: IncludeMutationWebhook=true exfiltrates
plaintext Secret data to anyone with applications, get. Clusters that handle
Secrets at all MUST be on a patched build.
When immediate upgrade isn't possible: strip IncludeMutationWebhook=true from
every Application. Block the value in CI with kubeconform/conftest.
2. Argo CD v3.0 flipped seven defaults — don't write apps as if on v2
In May 2026 assume v3.x semantics:
- Resource tracking is annotation-based by default, not labels. Don't add
app.kubernetes.io/instance overrides expecting them to track ownership.
.status is ignored on all resources by default (was: only CRDs).
ServerSideDiff respects this; mutation-webhook drift in .status no longer
shows up as OutOfSync.
- Default
resource.exclusions ships with the install (Endpoints,
EndpointSlice, Lease, *SubjectAccessReview, TokenReview, CSR,
CertificateRequest, Kyverno reports, Cilium endpoints, PolicyReports).
- Logs RBAC is enforced: roles need explicit
logs, get to view pod logs.
update/delete RBAC no longer inherits to managed resources.
spec.preserveUnknownFields: false on CRDs causes drift now — drop the
field; use x-kubernetes-preserve-unknown-fields: true on schemas.
- In-cluster destination disabled (
cluster.inClusterEnabled: "false") hard-blocks new apps to that cluster.
Full list with PRs: references/version-changes.md § v3.0.
3. Skip Argo CD 3.3.0 and 3.3.1 — SSA migration regression
3.3.0 forced the kubectl-client-side-apply → SSA field-manager rewrite, broke
many real apps, and required ClientSideApplyMigration=false as a temp
workaround. 3.3.2 fixed it (2026-02). Operators should be on 3.3.2+ before
publishing on this cluster.
When Argo CD manages itself, the meta-Application needs
ServerSideApply=true in syncOptions because the ApplicationSet CRD
exceeds the 262 144-byte client-side-apply annotation limit.
4. Source Hydrator is still Alpha in v3.4
Despite three minor versions of feature work, schema can break in v3.5. Don't
build long-lived automation on spec.sourceHydrator yet. Cosign-verified
manifest signing still requires the GnuPG path (signatureKeys) — Argo CD
doesn't ship a first-class cosign integration.
5. The default AppProject is a footgun in any multi-tenant cluster
default permits every repo, every destination, every cluster-scoped
resource. Production app authors should never set spec.project: default. Make
a project-per-team or project-per-environment, set sourceRepos, destinations,
clusterResourceWhitelist, signatureKeys. See references/projects-rbac.md.
6. Templated project: in ApplicationSet bypasses tenancy
spec.template.spec.project: "{{path.basename}}" lets an attacker who controls
the source git path elevate to any project they can name. Hard-code the project
in the ApplicationSet template. Argo CD warns about this in
docs/operator-manual/applicationset/Generators-Git.md lines 5-11.
7. ApplicationSets are recommended over app-of-apps
The official guidance — docs/operator-manual/cluster-bootstrapping.md line 7
— is now ApplicationSet first. App-of-apps still works for the bootstrap
(root → ApplicationSets), but for app fan-out, prefer an ApplicationSet with a
Git directory generator over a parent Application that points at child
Applications.
Canonical Application
Smallest sensible production Application:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payments-api
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: team-payments
source:
repoURL: https://github.com/example/config-repo.git
targetRevision: main
path: apps/prod/payments-api
helm:
releaseName: payments-api
valueFiles:
- values.yaml
- values-prod.yaml
destination:
name: prod-eu-1
namespace: payments-api
syncPolicy:
automated:
enabled: true
prune:
The single most important field for production hygiene: targetRevision —
pin to a SHA or tag, not HEAD / main. Floating revisions cause
non-deterministic syncs and break audit. Argo's own best_practices.md makes
this explicit (docs/user-guide/best_practices.md lines 57-79).
Canonical ApplicationSet
One Application per directory under apps/<env>/ in the config repo:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: prod-apps
namespace: argocd
spec:
goTemplate: true
goTemplateOptions:
- missingkey=error
generators:
- git:
repoURL: https://github.com/example/config-repo.git
revision: main
directories:
- path: apps/prod/*
template:
metadata:
name: '{{ .path.basename }}'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: team-platform
source:
repoURL: https://github.com/example/config-repo.git
targetRevision: '{{ .metadata.commitSHA }}'
path:
Hard rules:
goTemplate: true always. The default is false (legacy fasttemplate),
which silently mishandles nested objects, ranges, and if. The new pattern
uses Go templates with .path.basename, .path.path, .cluster.name, etc.
goTemplateOptions: ["missingkey=error"] always. Without it, typos in
template paths render as the empty string and the bug ships.
project: is hard-coded, never templated. Templated project lets a git
PR author change spec.template.spec.project to a privileged project.
finalizers: go in the template, not the AppSet itself. Adding the
finalizer to the AppSet metadata won't propagate to children.
applicationsSync: sync is what most teams want. create-only /
create-update / create-delete are escape hatches for migrations.
- For Git directory generators,
path: <dir>/* matches one level.
<dir>/** doesn't recurse — use <dir>/*/* for two-deep, etc.
ApplicationSet generator picker, all generator schemas, Progressive Sync (Beta
in v3.3), and the preservedFields / templatePatch knobs live in
references/applicationset.md.
Sync policy decision shortcut
Default policy for a typical workload:
automated.enabled: true, prune: true, selfHeal: true when no controller
mutates the spec. When one does (HPA, cert-manager, sidecar injectors),
keep selfHeal: false OR add precise ignoreDifferences and
RespectIgnoreDifferences=true.
syncOptions to set on every app:
CreateNamespace=true, ServerSideApply=true, ApplyOutOfSyncOnly=true,
RespectIgnoreDifferences=true. PrunePropagationPolicy=foreground for
synchronous child-cleanup pruning; background for fast pruning.
retry defaults are fine; raise limit to 10 only for apps with PreSync
hooks that legitimately flake (DB migrations on shared infra).
- For apps with destructive operations (delete Namespaces, PVCs):
Prune=confirm and/or Delete=confirm (v3.3+) — UI prompts before the op.
For the full syncOptions table, sync waves, hooks, health checks, and the
diff strategy reference (Server-Side Diff is Stable since v3.2 but not
default), see references/sync.md.
CLI quick reference for app authors
The 12 most-used commands:
argocd app diff <name>
argocd app diff <name> --server-side-generate
argocd app get <name> --refresh
argocd app get <name> --hard-refresh
argocd app manifests <name>
argocd app manifests <name> --source live
argocd app sync <name>
argocd app sync <name> --resource <gk>:<name>
argocd app sync <name> --prune --dry-run
argocd app terminate-op <name>
argocd app delete <name> --cascade
argocd app delete <name> --no-cascade
argocd appset get <name>
argocd appset create -f appset.yaml --dry-run
The --core mode (no API server, talk straight to k8s) is useful for CI:
argocd --core app diff <name> skips the gRPC server entirely. Set
KUBECTL_EXTERNAL_DIFF=delta for nicer output.
Annotations cheat sheet
The argocd.argoproj.io/* annotations app authors use most:
| Annotation | On | Effect |
|---|
sync-wave: "<int>" | any resource | order: lower runs first; default 0; negatives run before 0 |
hook: PreSync|Sync|PostSync|SyncFail|Skip|PreDelete|PostDelete | Job/Pod/etc. | run as a hook in that phase |
hook-delete-policy: HookSucceeded|HookFailed|BeforeHookCreation | hook resource | when to GC the hook |
sync-options: <opt>=<val>,<opt>=<val> | any resource | per-resource override of syncPolicy.syncOptions |
compare-options: IgnoreExtraneous | any resource | hide extraneous resources from diff |
compare-options: IncludeMutationWebhook=true | any resource | DO NOT USE unless on patched 3.x — see CVE-2026-42880 |
manifest-generate-paths: ".;../base" | Application | only re-render if these git paths change (huge perf win) |
refresh: "hard" | Application | trigger one hard-refresh (Argo deletes the annotation after) |
skip-reconcile: "true" | Application | freeze reconcile (Alpha; intended for OCM) |
Full table including tracking-id, sync-statuses, finalizer variants:
references/sync.md § Annotations.
Reference files — when to load
| File | Read when |
|---|
references/application.md | Authoring a non-trivial Application: source types (Helm/Kustomize/directory/jsonnet/OCI/plugin), multi-source $values pattern, finalizers, Source Hydrator, OCI digest pinning |
references/applicationset.md | Any ApplicationSet authoring: all 9 generators with examples, Progressive Sync (Beta v3.3), templatePatch, preservedFields, ignoreApplicationDifferences, applicationsSync, the goTemplate gotcha tree |
references/sync.md | Anything sync- or drift-related: every syncOption with default + flip-reason, sync waves + phase ordering + kind-order, all 7 hook types, all 3 delete policies, Lua health checks, diff strategies, selective sync, sync windows |
references/repo-layout.md | Designing or restructuring a GitOps repo: config-repo separation, directory-per-env vs branch-per-env, app-of-apps vs ApplicationSet, tool choice + umbrella-chart anti-pattern, Source Hydrator, OCI sources, private repos + OpenSSH 8.9 ssh-rsa gotcha |
references/projects-rbac.md | Multi-tenancy, security, or supply-chain: every AppProject field, app/appset-in-any-namespace (Stable v3.4), sync impersonation (Beta v3.4), GPG signature verification, secrets hygiene (ESO/SealedSecrets/SOPS/CSI), trusted vs untrusted repos |
references/troubleshooting.md | Anything broken: OutOfSync drivers (HPA, webhooks, field-manager wars, etc.), SyncFailed/hook leaks, ComparisonError, stuck deletion, ApplicationSet generation issues, auto-sync looping, performance, "deleted from git but still there" checklist |
references/version-changes.md | Upgrading 3.x→3.y or auditing old manifests: per-minor highlights v3.0→v3.4, breaking changes, maturity table, CVEs, 22 "things to drop now" patterns |
references/sources.md | Verifying citation freshness: dated index of every URL/repo/spec used to build this skill |
Adjacent skills
helm for chart authoring questions (Helm 4 SSA, OCI digest install,
values, helpers). This skill assumes Helm chart authoring competence.
kubefwd for accessing Argo CD UI / repo-server services from a
laptop without one-port-at-a-time kubectl port-forward.
gh-cli for fetching release notes, PRs, security advisories from the
argo-cd repo (canonical changelog — CHANGELOG.md in the repo is stale
back to 2022).