| name | add-flux-app |
| description | Scaffold a new Helm or raw Kustomize Flux app for Anton. Use to add an app, add a chart, add a raw manifest app, create a namespace, or create an ExternalSecret. Stops after repository validation and an explicit Git/rollout handoff. |
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash |
Add a Flux app
Task skill that scaffolds the 3-file Flux pattern for a new application in kubernetes/apps/<namespace>/<app>/. For the WHY behind every field — the 3-file pattern, postBuild substitution, OCI vs Helm vs Git sources, the SOPS vs ExternalSecret decision — read the anton-repo-conventions skill first; this skill assumes you already know it.
What this skill produces
Field reference for every file's shape: anton-repo-conventions skill.
| File | Path |
|---|
| Flux Kustomization (Tier 1) | kubernetes/apps/<ns>/<app>/ks.yaml |
| Plain Kustomize (Tier 2) | kubernetes/apps/<ns>/<app>/app/kustomization.yaml |
| Helm resources (Tier 3, Helm mode) | app/helmrelease.yaml plus exactly one chart source |
| Raw resources (Tier 3, raw mode) | manifests, components, patches, or generators listed by app/kustomization.yaml |
| Optional Namespace + namespace kustomization | kubernetes/apps/<ns>/namespace.yaml |
| Optional ExternalSecret | kubernetes/apps/<ns>/<app>/app/externalsecret.yaml |
Workflow A — add an app to an existing namespace
- Pick the namespace. Confirm it already exists:
ls kubernetes/apps/<ns>/. If not, jump to Workflow B.
- Choose Helm or raw mode. Match the closest sibling. For Helm, verify the chart first with
mise exec -- helm search repo <repo>/<chart> --versions | head -5 or mise exec -- crane ls ghcr.io/<org>/charts/<chart>. For raw mode, identify the exact manifests, components, patches, or generators that app/kustomization.yaml will own.
- Create the app directory:
mkdir -p kubernetes/apps/<ns>/<app>/app
- Author the app shape directly. Every app gets
ks.yaml and app/kustomization.yaml. Helm mode adds app/helmrelease.yaml and exactly one chart source. Raw mode lists at least one manifest, component, patch, or generator and does not invent a HelmRelease. Use anton-repo-conventions for the field contract and copy the closest in-tree sibling.
- Register the app in the namespace kustomization. Add one line:
$EDITOR kubernetes/apps/<ns>/kustomization.yaml
Apps are NOT auto-discovered. Skipping this means Flux silently never deploys the app.
- Validate dependency readiness: run
python3 scripts/validate-flux-contract.py. If the app authors a custom
resource, add the ADR 0027 dependsOn edge reported by the validator; if it
is a provider, add wait: true, healthChecks, or healthCheckExprs.
- If any
*.sops.* files: mise exec -- sops -e -i <file> to encrypt in place. Verify with mise exec -- sops filestatus <file> → encrypted.
- Stop after repository validation. Report the validated diff and hand off commit, push, and Flux reconciliation as separate operator actions. Perform none of them unless the user explicitly authorizes that boundary.
Workflow B — add an app in a new namespace
- Create the namespace dir:
mkdir -p kubernetes/apps/<ns>
- Author
kubernetes/apps/<ns>/namespace.yaml directly. The annotation kustomize.toolkit.fluxcd.io/prune: disabled is required — it stops Flux from deleting the namespace. Copy the shape from a neighbor namespace.
- Create the namespace kustomization at
kubernetes/apps/<ns>/kustomization.yaml:
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./namespace.yaml
components:
- ../../components/sops
The components: [../../components/sops] line is mandatory — it injects cluster-secrets so ${VAR} substitution works for every app in this namespace.
- Continue from step 2 of Workflow A to add the first app.
Variant — chart source other than OCIRepository
OCIRepository is the default. Two alternatives, only when the chart is not on OCI:
HelmRepository (classic Helm repo). Replace the OCIRepository file with a HelmRepository, and replace the HelmRelease's chartRef: block with chart.spec.sourceRef:
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: {{APP_NAME}}
spec:
interval: 15m
url: https://example.helm.repo
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: {{APP_NAME}}
spec:
interval: 1h
chart:
spec:
chart: {{CHART_NAME}}
version: {{CHART_VERSION}}
sourceRef:
kind: HelmRepository
name: {{APP_NAME}}
values: {}
GitRepository (rare). Use only when the chart lives in a git tree (a fork or unreleased chart). See anton-repo-conventions/references/helmrelease-sources.md for the exact shape.
Variant — the app needs a secret
Pick one path; do not mix for the same secret.
Path 1 — ExternalSecret (default for new apps, pulls from 1Password).
- Hand off creation of the item in the
anton 1Password vault unless that external mutation was explicitly authorized. Field names are case-sensitive.
- Author
app/externalsecret.yaml directly. Template shape and field-mapping rules: anton-repo-conventions/references/secrets.md. Copy from an in-tree ExternalSecret (e.g. kubernetes/apps/network/cloudflare-tunnel/app/externalsecret.yaml).
- Register the approved references and target keys in
scripts/data/external-secret-contract.json.
- Add
- ./externalsecret.yaml to the app's kustomization.yaml.
- Run
mise exec -- task contracts:validate.
- No encryption step. Verify after deploy:
mise exec -- kubectl get externalsecret -n <ns> <name>
mise exec -- kubectl get secret -n <ns> <name>
mise exec -- kubectl describe externalsecret -n <ns> <name> | grep -A5 Status:
Path 2 — SOPS Secret (only for static infra credentials that must exist before ESO).
- Author
app/secret.sops.yaml in plaintext with data or stringData.
- Encrypt in place:
mise exec -- sops -e -i app/secret.sops.yaml.
- Verify:
SOPS_AGE_KEY_FILE=./age.key mise exec -- sops filestatus app/secret.sops.yaml → encrypted.
- Add
- ./secret.sops.yaml to the app's kustomization.yaml.
Full templates and field-mapping rules: anton-repo-conventions/references/secrets.md.
Variant — the app needs an HTTPRoute
That belongs to a different skill. Use expose-service for HTTPRoute, gateway choice, secondary-domain DNSEndpoint, and certificate sourcing.
Pre-commit checklist
Related skills
- Pattern reference (the WHY for every field) →
anton-repo-conventions
- Exposing the app on a gateway →
expose-service
- App not deploying after commit →
debug-flux-reconciliation