| name | helm-chart-developer |
| description | Helm chart authoring, values.yaml design, GitOps with Flux HelmRelease,
External Secrets Operator integration. Use for creating and debugging Helm charts.
|
Helm Chart Developer
Purpose / When to Use
Use this skill when:
- Creating new Helm charts from scratch
- Converting raw Kubernetes manifests to Helm
- Designing values.yaml API and schema
- Setting up GitOps deployment with Flux HelmRelease
- Integrating External Secrets Operator (ESO)
- Debugging
helm template, helm lint, helm install --dry-run
- Setting up multi-environment overlays (dev/prod)
Version & API Compatibility
Always use these API versions:
| Component | API Version | Notes |
|---|
| Helm Chart | apiVersion: v2 | Helm 3+ charts |
| Flux HelmRelease | helm.toolkit.fluxcd.io/v2 | Current stable |
| Flux HelmRepository | source.toolkit.fluxcd.io/v1 | Current stable |
| Flux Kustomization | kustomize.toolkit.fluxcd.io/v1 | Current stable |
| ExternalSecret | external-secrets.io/v1 | ESO v1 API |
| ClusterSecretStore | external-secrets.io/v1 | With spec.conditions[].namespaceSelector |
Target baseline: Kubernetes 1.29+, Helm 3.14+, Flux v2.3+, ESO 0.10+
Rule: If adding manifests, ALWAYS use these API versions.
If CRD/apiVersion mismatch detected in repo, STOP and propose migration plan.
See VERSIONS.md for full compatibility matrix.
Definition of Done (DoD)
Before completing any Helm chart work:
- Linting:
helm lint . passes
- Template rendering:
helm template <release> . succeeds
- Schema validation (optional):
helm template . | kubeconform -strict
- Dry-run:
helm install <release> . --dry-run --debug works
- Two secrets modes validated:
- GitOps mode:
--set secrets.existingSecretName=<name>
- Chart-managed ESO:
--set secrets.externalSecret.enabled=true
- API versions match the compatibility table above
Run /helm-validate to execute all checks.
Step-by-Step Workflow
1. Chart Structure
charts/app/
├── Chart.yaml
├── values.yaml
├── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── externalsecret.yaml # optional, gated
│ ├── hpa.yaml
│ ├── pdb.yaml
│ └── serviceaccount.yaml
2. Values API Contract
See reference-gitops-eso.md for full details.
Key sections:
image: repository, tag, pullPolicy
secrets: existingSecretName, externalSecret.*, inject.envFrom
service: enabled, type, port
ingress: enabled, className, hosts, tls
resources: requests, limits
autoscaling: enabled, minReplicas, maxReplicas
3. Secrets Integration
Mode A: ExternalSecret in Overlay (Recommended)
Chart only references secret by name:
secrets:
existingSecretName: "app-secrets"
inject:
envFrom: true
ExternalSecret lives in GitOps overlay, not in chart.
Mode B: Chart-Managed ExternalSecret (Optional)
Chart renders ExternalSecret when enabled:
secrets:
externalSecret:
enabled: true
refreshInterval: 1h
refreshPolicy: OnChange
secretStoreRef:
kind: ClusterSecretStore
name: aws-secrets-manager
dataFrom:
extractKey: "fce/dev/app"
target:
name: "app-secrets"
creationPolicy: Owner
Secrets Determinism (ESO)
refreshPolicy options:
| Policy | Behavior | Use Case |
|---|
OnChange | Updates when ExternalSecret manifest changes | GitOps (default, recommended) |
CreatedOnce | Never updates after creation | Immutable credentials |
Periodic | Updates on interval (refreshInterval) | Legacy, auto-rotation |
Default rule: Use refreshPolicy: OnChange for predictable GitOps-driven updates.
Manual refresh (debug/runbook):
kubectl annotate es <name> force-sync=$(date +%s) --overwrite
4. Flux + Kustomize Recipe
Values Composition Order (important!):
- Chart defaults (
charts/app/values.yaml)
- Environment values (
apps/dev/app/values.yaml)
- ConfigMap via Kustomize generator
- HelmRelease
valuesFrom references ConfigMap
- HelmRelease
spec.values patches (highest priority)
See snippets:
Critical Kustomize settings:
generatorOptions:
disableNameSuffixHash: true
Flux Ordering
Use spec.dependsOn in HelmRelease when app depends on:
- CRDs (external-secrets, cert-manager)
- ExternalSecrets/SecretStores
- Ingress controllers, databases
Example:
spec:
dependsOn:
- name: external-secrets
namespace: external-secrets
5. ESO Patterns
ClusterSecretStore (cluster-wide):
apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
name: aws-secrets-manager
spec:
conditions:
- namespaceSelector:
matchLabels:
eso.fce.global/enabled: "true"
provider:
aws:
service: SecretsManager
region: me-central-1
ExternalSecret (per app/env):
apiVersion: external-secrets.io/v1
kind: ExternalSecret
spec:
refreshPolicy: OnChange
secretStoreRef:
kind: ClusterSecretStore
name: aws-secrets-manager
dataFrom:
- extract:
key: fce/dev/app
target:
name: app-secrets
creationPolicy: Owner
6. Pitfalls
- CRD ordering: ESO CRDs must exist before ExternalSecret. Use Flux Kustomization
dependsOn.
- OpenAPI validation: Use
install.disableOpenAPIValidation: true in HelmRelease if needed.
- NEVER put secrets in values.yaml: No passwords, tokens, API keys, credentials.
Only references to Secret/ExternalSecret names. This is non-negotiable.
Examples
Prompts that should activate this skill:
- "Create a Helm chart for my Node.js app"
- "Convert these Kubernetes manifests to Helm"
- "Add External Secrets integration to my chart"
- "Set up Flux HelmRelease for my app"
- "Debug why helm template is failing"
- "Design values.yaml schema for multi-environment deployment"
- "Add ingress with TLS to my Helm chart"
- "Integrate AWS Secrets Manager with my chart"
- "Set up Kustomize overlays for dev and prod"
- "Fix helm lint errors in my chart"
Anti-Patterns
| ❌ Avoid | ✅ Instead |
|---|
| Hardcode secrets in values.yaml | Use ExternalSecret with secretStoreRef |
| Single values.yaml for all envs | Kustomize overlays per environment |
HelmRelease v2beta1 / v2beta2 API | Use helm.toolkit.fluxcd.io/v2 |
| Manual Secret creation | ESO with ClusterSecretStore |
| Inline helm values in HelmRelease | External values.yaml + patches via valuesFrom |
Skip helm lint / helm template | Always validate with /helm-validate |
refreshPolicy: Periodic for GitOps | Use refreshPolicy: OnChange for determinism |
Kustomize namesSuffixHash: true | Always disableNameSuffixHash: true for ConfigMaps |
| Put ExternalSecret in Helm chart | Put ExternalSecret in GitOps overlay (Mode A) |
Skip dependsOn for CRDs | Use spec.dependsOn for external-secrets, cert-manager |
Related Files
Version History
- 1.1.0 — Add version compatibility, secrets determinism, Flux ordering
- 1.0.0 — Initial release with Flux + ESO patterns