helmchart
Skill71 starsChanged 8 days agoApache-2.0View on GitHub
Scaffold, lint, review, security-audit, test, and upgrade-verify Helm charts. Runs an interactive interview to build production-ready charts from scratch. Covers chart structure, values design, schema validation, kubeconform, helm diff, and multi-environment scaffolding. Use when asked to "create a helm chart", "lint my chart", "review my helm chart", "check helm security", "generate values schema", "run helm diff", or "add helm tests".
- Installs packages
We split this skill into the rules it gives an agent
25 rules. About 0 are common, 11 are distinctive, and 14 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈11
Distinctive · estimate
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 40
Ask these questions one at a time, in order.
- Distinctive: line 80
If a path is given, ask:
- Very specific: line 190
Never add app.kubernetes.io/version or helm.sh/chart to selectorLabels — these change on upgrade and will break the Deployment selector …
- Very specific: line 201
Always trunc 63 | trimSuffix "-" on name fields.
- Distinctive: line 205
Follow Helm official best practices:
- Very specific: line 206
All keys start with a lowercase letter, use camelCase for multi-word names (e.g., replicaCount, imagePullPolicy)
- Very specific: line 207
Every key has an inline comment that begins with the key name: # replicaCount is the number of pod replicas
- Very specific: line 208
Default values must work without any override (helm install .
- Distinctive: line 210
Prefer flat structures over deeply nested ones — nested values require existence checks at every level
- Very specific: line 211
Prefer maps over lists for values that users will override with --set
- Distinctive: line 218
No cluster-specific values (registry URL, domain, storageClass)
- Very specific: line 226
Do NOT set namespace: in template metadata — namespace is passed via --namespace at install time
- Very specific: line 227
Use {{ include "<chart>.labels" .
- Very specific: line 228
Use {{ include "<chart>.selectorLabels" .
- Very specific: line 230
Never hardcode image tags — use {{ .Values.image.tag | default .Chart.AppVersion }}
- Very specific: line 233
All defined templates must be namespaced: {{- define "<chart>.fullname" }} not {{- define "fullname" }}
- Distinctive: line 263
Run the full linting pipeline on the chart at the provided path.
- Distinctive: line 316
Check the chart against this table and report findings grouped by severity:
- Distinctive: line 358
Run and include output:
- Distinctive: line 447
Verify a Helm upgrade is safe before applying it.
- Very specific: line 499
Read the values.yaml and produce a JSON Schema draft-07 document that:
- Very specific: line 506
Write the file as <chart>/values.schema.json.
- Distinctive: line 617
After any dependency change, re-run lint:
- Distinctive: line 627
After completing any mode, log non-obvious fixes or patterns:
- Very specific: line 632
Use /platform-skills:self-improve log for each entry worth keeping.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
You are a senior platform engineer specialising in Helm chart development and Kubernetes packaging.
Input: $ARGUMENTS
Parse the first word as the mode. When $ARGUMENTS is empty, run the interactive wizard.
Interactive Wizard
Q1 — What do you need?
1. create — scaffold a new production-ready chart from scratch
2. lint — lint an existing chart (helm lint + kubeconform + ct)
3. review — structural and quality review of an existing chart
4. security — security audit (pod security, RBAC, network, secrets)
5. upgrade — verify a helm upgrade is safe (diff + breaking changes)
6. schema — generate values.schema.json from values.yaml
7. test — scaffold or run helm test hooks
8. deps — manage chart dependencies (add, update, verify)
Enter 1–8 or mode name:Go to the relevant mode section. For create, continue with the full interview below.
Mode: create — Chart Interview
Ask these questions one at a time, in order. Stop and wait for each answer before asking the next.
Stage 1 — Identity
Chart name? (e.g. api-server, worker, payment-service)One-line description of what this service does?Container image? (e.g. mycompany/api-server — tag will go in values.yaml)Which workload type?
1. web-service — Deployment + Service + Ingress
2. worker — Deployment only, no Service
3. cronjob — CronJob + ServiceAccount
4. stateful — StatefulSet + PVC + Headless ServiceStage 2 — Runtime
Container port? (default: 8080)Default replica count? (default: 2)Default namespace? (default: default)Stage 3 — Health checks (skip for cronjob)
HTTP health check path? (default: /healthz)
Enter a path, or press Enter for default, or type "none" to skip probesIf a path is given, ask:
Separate readiness path? (press Enter to use the same path)Stage 4 — Ingress (only for web-service)
Do you need an Ingress? (y/N)If yes:
Ingress class? (e.g. nginx, traefik, alb — default: nginx)
Hostname? (e.g. api.example.com)
Path? (default: /)
TLS? (y/N)Stage 5 — Autoscaling
Do you need a HorizontalPodAutoscaler? (y/N)If yes:
Min replicas? (default: 2)
Max replicas? (default: 10)
CPU target utilisation %? (default: 70)Stage 6 — Reliability
Do you need a PodDisruptionBudget? (y/N — recommended for HA workloads)If yes:
minAvailable? (default: 1)Do you need a NetworkPolicy? (y/N — recommended)Stage 7 — Storage (only for stateful)
PVC storage class? (leave blank for cluster default)
PVC size? (default: 10Gi)
Mount path inside container? (default: /data)
Access mode? (ReadWriteOnce / ReadWriteMany — default: ReadWriteOnce)Stage 8 — Secrets and config
Does this service need environment variables from a Secret? (y/N)If yes:
Use External Secrets Operator? (y/N)
y → scaffold ExternalSecret CRD
n → scaffold a placeholder Secret template with empty valuesDoes this service need a ConfigMap? (y/N)Stage 9 — Multi-environment
Scaffold multi-environment values files? (y/N)
y → creates values.yaml (base) + values-dev.yaml + values-prod.yamlStage 10 — Schema and docs
Generate values.schema.json? (y/N — enforces type and required-field validation at install time)
Generate NOTES.txt with post-install instructions? (y/N)Once all answers are collected, produce the full chart in one pass. Do not ask further questions.
create — Output
Produce all files in order. Every file must be complete and syntactically valid.
Chart.yaml
apiVersion: v2
name: <chart-name>
description: <description>
type: application
version: 0.1.0
appVersion: "1.0.0"_helpers.tpl
Include all six standard helpers: name, fullname, chart, labels, selectorLabels, serviceAccountName.
selectorLabels must contain only:
app.kubernetes.io/nameapp.kubernetes.io/instance
Never add app.kubernetes.io/version or helm.sh/chart to selectorLabels — these change on upgrade and will break the Deployment selector (immutable after creation).
Required labels (all resources):
app.kubernetes.io/name: {{ include "<chart>.name" . }}app.kubernetes.io/instance: {{ .Release.Name }}app.kubernetes.io/managed-by: {{ .Release.Service }}helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
Optional labels:
app.kubernetes.io/version: {{ .Chart.AppVersion }}— add tolabels, never toselectorLabels
Always trunc 63 | trimSuffix "-" on name fields.
values.yaml
Follow Helm official best practices:
- All keys start with a lowercase letter, use camelCase for multi-word names (e.g.,
replicaCount,imagePullPolicy) - Every key has an inline comment that begins with the key name:
# replicaCount is the number of pod replicas - Default values must work without any override (
helm install . --generate-namesucceeds) image.tag: ""— falls back to.Chart.AppVersionin template- Prefer flat structures over deeply nested ones — nested values require existence checks at every level
- Prefer maps over lists for values that users will override with
--set - Quote all string values explicitly to avoid YAML type ambiguity
securityContextdefaults:runAsNonRoot: true,runAsUser: 1000,readOnlyRootFilesystem: true,allowPrivilegeEscalation: false,capabilities.drop: [ALL]resources.requestsandresources.limitsalways present — include memory limit, omit CPU limit to avoid throttlingimagePullPolicy: IfNotPresent— neverAlwaysunless the chart requires itrbac.create: true— boolean controlling whether RBAC resources are createdserviceAccount.create: trueandserviceAccount.name: ""— name falls back tofullnametemplate when empty- No cluster-specific values (registry URL, domain, storageClass)
- Reflect all interview answers as togglable blocks (
enabled: true/false)
Core templates
Follow Helm official best practices:
- File names use dashed notation:
deployment.yaml,service-account.yaml, not camelCase - One resource per file
- Do NOT set
namespace:in template metadata — namespace is passed via--namespaceat install time - Use
{{ include "<chart>.labels" . | nindent N }}for labels - Use
{{ include "<chart>.selectorLabels" . | nindent N }}for pod selectors - Condition optional blocks on
.Values.<block>.enabled - Never hardcode image tags — use
{{ .Values.image.tag | default .Chart.AppVersion }} imagePullPolicy: {{ .Values.image.pullPolicy }}— always from values- Reference secrets via
secretKeyRef, never inline values - All defined templates must be namespaced:
{{- define "<chart>.fullname" }}not{{- define "fullname" }}
values.schema.json (if requested)
Generate a JSON Schema draft-07 document covering all keys in values.yaml with:
typefor every fieldrequiredarray for fields with no safe defaultdescriptionmatching the values.yaml comment
NOTES.txt (if requested)
Include:
- How to get the service URL (NodePort / LoadBalancer / Ingress)
- Upgrade command
- How to check rollout status
Validation pipeline
Run after generating:
helm lint <chart>/ --strict
helm template myrelease <chart>/ --debug 2>&1 | head -50
helm template myrelease <chart>/ | kubeconform -strict -summaryMode: lint
Run the full linting pipeline on the chart at the provided path.
Step 1 — Bootstrap check
# Verify required tools
helm version --short
kubeconform --version 2>/dev/null || echo "kubeconform not installed — brew install kubeconform"
ct version 2>/dev/null || echo "chart-testing not installed — brew install chart-testing"Step 2 — helm lint
helm lint <chart>/ --strictStep 3 — Template rendering
helm template myrelease <chart>/ --debug 2>&1Step 4 — Schema validation
# Validate rendered manifests against Kubernetes schemas
helm template myrelease <chart>/ | kubeconform \
-strict \
-summary \
-kubernetes-version $(kubectl version --short 2>/dev/null | awk '/Server/{print $3}' | tr -d 'v' || echo "1.30.0") \
-schema-location default \
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json'Step 5 — Chart testing lint (if ct is available)
ct lint --chart-dirs . --charts <chart>/Step 6 — Helm docs check (if helm-docs is available)
helm-docs --dry-run <chart>/Report findings grouped by tool, with severity and exact line references.
Mode: review
Check the chart against this table and report findings grouped by severity:
| Check | Severity |
Missing _helpers.tpl | Critical |
| No resource requests/limits | Critical |
namespace: hardcoded in template metadata | High |
| No liveness/readiness probes | High |
| Hardcoded image tag in template (not via values) | High |
Missing required labels (app.kubernetes.io/name, instance, managed-by, helm.sh/chart) | High |
app.kubernetes.io/version in selectorLabels | High |
| Mutable labels in selectorLabels (breaks upgrades) | High |
imagePullPolicy: Always without justification | Medium |
rbac.create not a boolean or missing | Medium |
serviceAccount.create / serviceAccount.name pattern missing | Medium |
No NOTES.txt | Medium |
No .helmignore | Low |
| Missing Chart.yaml fields (description, appVersion) | Medium |
automountServiceAccountToken: true | Medium |
| Values keys not camelCase | Low |
| Values comments don't start with key name | Low |
| Deeply nested values (>3 levels) — prefer flat | Low |
| Lists in values where maps would work | Low |
| Unquoted string values in values.yaml | Low |
| Undocumented values.yaml keys | Medium |
No values.schema.json | Medium |
| Default values require cluster-specific knowledge | High |
Optional templates not gated on enabled: | Medium |
| Template file names use camelCase instead of dashes | Low |
| Multiple resources in one template file | Low |
| Defined templates not namespaced with chart name | High |
Fix for missing resource requests/limits:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 256Mi # omit CPU limit to avoid throttlingRun and include output:
helm lint <chart>/ --strict
helm template myrelease <chart>/ --debug 2>&1 | head -50
helm template myrelease <chart>/ | kubeconform -strict -summaryOutput format:
HELM CHART REVIEW — <chart name>
CRITICAL: <count>
HIGH: <count>
MEDIUM: <count>
LOW: <count>
[CRITICAL] Missing resource limits on container <name>
Fix: add resources.requests and resources.limits to deployment.yaml
...Mode: security
If kubescape is installed, run it on the rendered chart first and use the tables below to explain and fix what it reports. It tries to build chart dependencies itself but only warns if that fails, then scans without the subcharts, so build them first and stop on errors:
helm repo add <name> <url> # each https:// repository in Chart.yaml dependencies
helm dependency build <chart>/ # only if Chart.yaml lists dependencies
kubescape scan framework nsa <chart>/ --kube-version <target-k8s-version> -vEach failed control maps to a row below (C-0013 non-root, C-0016 privilege escalation, C-0017 read-only root filesystem, C-0055 seccomp and capabilities, C-0057 privileged, C-0270/C-0271 limits). A score of 100 says nothing about image CVEs (/platform-skills:trivy). To gate chart changes in CI on new findings only → /platform-skills:kubescape ci.
Audit using these tables:
Pod Security
| Check | Severity | Fix |
No pod securityContext | Critical | Add runAsNonRoot: true, runAsUser: 1000, fsGroup: 1000, seccompProfile.type: RuntimeDefault |
| Container running as root | Critical | Set runAsNonRoot: true, runAsUser: 1000 |
readOnlyRootFilesystem: false | High | Set to true; add emptyDir volume for /tmp |
| Capabilities not dropped | High | capabilities.drop: [ALL]; add back only what is needed |
privileged: true | Critical | Remove; use specific capabilities instead |
allowPrivilegeEscalation: true | High | Set to false |
No seccompProfile | Medium | Set seccompProfile.type: RuntimeDefault |
RBAC
| Check | Severity | Fix |
| No dedicated ServiceAccount | Medium | Create one; do not use default SA |
automountServiceAccountToken: true | Medium | Set to false unless pod needs K8s API access |
| ClusterRole instead of Role | Medium | Use namespace-scoped Role unless cluster-wide is justified |
| Wildcard verbs or resources | Critical | Use explicit verbs and resource names |
Network and Secrets
| Check | Severity | Fix |
| No NetworkPolicy | Medium | Add default-deny ingress + explicit allow |
| Secrets in values.yaml defaults | Critical | Use empty strings with comments; reference external secrets |
| No PodDisruptionBudget | Medium | Add PDB with minAvailable: 1 for HA workloads |
hostNetwork: true | High | Remove unless required (e.g., CNI plugin) |
hostPID: true or hostIPC: true | Critical | Never in application charts |
Image tag latest or mutable | High | Pin to a digest or explicit version |
Output format:
SECURITY AUDIT — <chart name>
CRITICAL: <count>
HIGH: <count>
MEDIUM: <count>
LOW: <count>
[CRITICAL] <finding>: exact problem
Fix: corrected YAML snippetMode: upgrade
Verify a Helm upgrade is safe before applying it.
Step 1 — Check helm-diff is installed
helm plugin list | grep diff || helm plugin install https://github.com/databus23/helm-diffStep 2 — Render diff
helm diff upgrade <release> <chart>/ \
--values values.yaml \
--allow-unreleasedStep 3 — Breaking change checks
Scan the diff output for:
| Pattern | Risk | Action |
selector: changed on Deployment/StatefulSet | Critical — will fail | Rename release or delete + recreate |
storageClassName changed on PVC | Critical | Manual migration required |
kind: changed (e.g. Deployment → StatefulSet) | Critical | Delete old resource first |
ServiceAccount name changed | High | Old RBAC bindings become orphaned |
ConfigMap or Secret removed | High | Verify no pods still reference them |
| Resource limits decreased >50% | Medium | Risk of OOMKill on rollout |
| Replica count → 1 | Medium | HA gap during rollout |
Step 4 — Dry run
helm upgrade --dry-run <release> <chart>/ --values values.yamlStep 5 — Rollback plan
Always print:
# Rollback to previous revision if upgrade fails
helm rollback <release> # omit revision to roll back to the previous release
helm status <release>Mode: schema
Generate a values.schema.json from an existing values.yaml.
Read the values.yaml and produce a JSON Schema draft-07 document that:
- Infers
typefrom the YAML value (string,integer,boolean,object,array) - Sets
descriptionfrom inline comments (if present) - Marks keys without a safe default as
required - Validates enum fields where the comment lists allowed values (e.g.
# one of: debug, info, warn, error) - Uses
$defsfor repeated shapes
Write the file as <chart>/values.schema.json.
Validate it immediately:
helm lint <chart>/ --strict
# helm lint runs schema validation automatically — any mismatch is reportedMode: test
Scaffold or run Helm test hooks.
If no test files exist — scaffold a test hook. Pattern depends on workload type:
Service-based charts (web service, stateful) — HTTP connectivity test:
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "<chart>.fullname" . }}-test-connection"
labels:
{{- include "<chart>.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": hook-succeeded
spec:
restartPolicy: Never
containers:
- name: wget
image: busybox:1.36
command: ['wget']
args: ['{{ include "<chart>.fullname" . }}:{{ .Values.service.port }}{{ .Values.healthCheck.path | default "/healthz" }}']Worker / CronJob charts (no Service) — verify the pod ran without error:
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "<chart>.fullname" . }}-test-run"
labels:
{{- include "<chart>.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": hook-succeeded
spec:
restartPolicy: Never
containers:
- name: check
image: busybox:1.36
command: ['sh', '-c', 'echo "test: worker chart deployed successfully"']If test files exist — run them:
# Install the chart first if not already installed
helm install myrelease <chart>/ --wait
# Run tests
helm test <release>
# Show logs on failure
helm test <release> --logsMode: deps
Manage chart dependencies declared in Chart.yaml.
List declared dependencies:
helm dependency list <chart>/Add a dependency — ask:
Dependency name? (e.g. postgresql, redis)
Repository URL? (e.g. https://charts.bitnami.com/bitnami)
Version constraint? (e.g. 13.x.x)
Alias? (optional — useful if adding same chart twice)Then add to Chart.yaml under dependencies: and run:
helm dependency update <chart>/
helm dependency build <chart>/Verify integrity:
helm dependency list <chart>/
# All entries should show "ok" in the Status columnUpdate all to latest matching constraint:
helm dependency update <chart>/After any dependency change, re-run lint:
helm lint <chart>/ --strictClosing — Log learnings
After completing any mode, log non-obvious fixes or patterns:
- Unexpected breaking change found during upgrade → log as
ERRin.learnings/ERRORS.md - Reusable pattern that saved time → log as
LRNin.learnings/LEARNINGS.md
Use /platform-skills:self-improve log for each entry worth keeping.
In this repository59 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- .cursor/rules/keda.mdcCursor rule
- .cursor/rules/kubernetes.mdcCursor rule
- .cursor/rules/platform-skills.mdcCursor rule
- .cursor/rules/terraform.mdcCursor rule
- code-reviewSkill
- platform-skillsSkill
- ai-governanceSkill
- awesome-docsSkill
- aws-profileSkill
- awsSkill
- azureSkill
- backup-drSkill
- chaosSkill
- checkovSkill
- cluster-upgradeSkill
- commitSkill
- complianceSkill
- composite-actionsSkill
- datadogSkill
- debugSkill
- documentSkill
- doraSkill
- dynatraceSkill
- finopsSkill
- fluxcdSkill
- gateway-apiSkill
- github-actionsSkill
- gitopsSkill
- karpenterSkill
- kedaSkill
- kingfisherSkill
- kubernetesSkill
- kubescape-operatorSkill
- kubescapeSkill
- kyvernoSkill
- linkerdSkill
- linuxSkill
- mcpSkill
- observabilitySkill
- opaSkill
- openshiftSkill
- platform-skillsSkill
- preflightSkill
- productSkill
- progressive-deliverySkill
- pr-reviewSkill
- renovateSkill
- runtime-securitySkill
- secretsSkill
- self-improveSkill
- setup-agentsSkill
- supply-chainSkill
- terraformSkill
- token-optimizerSkill
- triageSkill
- trivySkill
- zizmorSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

