Skip to content

Argo CD Composites

Argo CD’s Application, ApplicationSet, and AppProject are Kubernetes CRDs (argoproj.io). The k8s lexicon registers them via codegen — the same precedent as KubeRay — so you get typed K8s::Argo::* resources, the serializer, LSP, hover, and MCP for free. The value-add ships as composites, lint rules, and a skill.

The three-layer model: Argo vs Temporal vs CI

Section titled “The three-layer model: Argo vs Temporal vs CI”

Chant authors typed infra into manifests. From there, who applies them?

LayerOwnsReach for it when
Argo CDContinuously reconciling declarative manifeststhe desired state lives in git and converges — Deployments, CRs, Helm releases
TemporalProcedural steps with ordering, signals, human gates, one-shot RPCsthe step is a procedure, not a state — DNS delegation, cert generation, db init
CIOne-shot, fire-and-forget applya simple pipeline with no reconciliation or long-running orchestration need

Rule of thumb: if it’s declarative and converges, let Argo reconcile it; if it’s a procedure with ordering or gates, orchestrate it in Temporal. Prefer Argo CD over Argo Workflows — the procedural layer stays Temporal. See the temporal-crdb-deploy tutorial for a deployment that uses both.

Pinned to Argo CD v2.13.3, the codegen produces:

TypeapiVersion / kind
Applicationargoproj.io/v1alpha1 / Application
ApplicationSetargoproj.io/v1alpha1 / ApplicationSet
AppProjectargoproj.io/v1alpha1 / AppProject

Install the operator with:

Terminal window
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.13.3/manifests/install.yaml

ArgoAppFor — one Application from a build target

Section titled “ArgoAppFor — one Application from a build target”
import { ArgoAppFor } from "@intentius/chant-lexicon-k8s";
export const api = ArgoAppFor("api", {
repo: "https://github.com/acme/infra",
path: "dist/api",
destination: { server: "https://kubernetes.default.svc", namespace: "api" },
});

One call replaces ~30 lines of hand-written Application YAML. Defaults are production-friendly:

  • destination — the in-cluster target (https://kubernetes.default.svc, namespace = target name) when omitted.
  • projectdefault. Pass project to scope to a declared AppProject.
  • syncPolicy — automated, non-pruning, self-healing, with CreateNamespace=true. Pass syncPolicy: {} for manual sync.

ArgoAppSetForRegions — fan out across clusters

Section titled “ArgoAppSetForRegions — fan out across clusters”
import { ArgoAppSetForRegions } from "@intentius/chant-lexicon-k8s";
export const crdb = ArgoAppSetForRegions(
["east", "central", "west"],
(region) => ({ server: servers[region], namespace: `crdb-${region}`, path: `dist/${region}` }),
{ name: "crdb", repo: "https://github.com/acme/infra", project: "crdb" },
);

Emits one ApplicationSet with a list generator — Argo expands it into one synced Application per region (east-crdb, central-crdb, west-crdb). The template scopes to a single static AppProject.

The in-cluster target needs no registration. For any other cluster:

import { registerArgoCluster } from "@intentius/chant-lexicon-k8s";
export const east = registerArgoCluster({
name: "east",
server: "https://east.example.com",
config: { tlsClientConfig: { insecure: false } },
});

Produces a Secret labelled argocd.argoproj.io/secret-type: cluster. Applications can then target it by destination.server or destination.name: "east".

The k8s lexicon ships five Argo-specific checks (see Lint Rules):

RuleKindWhat it catches
ARGO001declarativeProduction Application with automated prune: true and no argocd.chant.dev/allow-prune override
ARGO002post-synthApplication.spec.project references an undeclared AppProject
ARGO003post-synthApplication.spec.destination references an unregistered cluster
ARGO004declarativeApplicationSet template doesn’t scope to a single static AppProject
ARGO005post-synthApplication source.path doesn’t resolve to a directory (warn)