engineering/helm-chart-builder/skills/helm-chart-builder/SKILL.md
Helm chart development agent skill and plugin for Claude Code, Codex, Gemini CLI, Cursor, OpenClaw — chart scaffolding, values design, template patterns, dependency management, security hardening, and chart testing. Use when: user wants to create or improve Helm charts, design values.yaml files, implement template helpers, audit chart security (RBAC, network policies, pod security), manage subcharts, or run helm lint/test.
npx skillsauth add alirezarezvani/claude-skills helm-chart-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Production-grade Helm charts. Sensible defaults. Secure by design. No cargo-culting.
Opinionated Helm workflow that turns ad-hoc Kubernetes manifests into maintainable, testable, reusable charts. Covers chart structure, values design, template patterns, dependency management, and security hardening.
Not a Helm tutorial — a set of concrete decisions about how to build charts that operators trust and developers don't fight.
| Command | What it does |
|---------|-------------|
| /helm:create | Scaffold a production-ready Helm chart with best-practice structure |
| /helm:review | Analyze an existing chart for issues — missing labels, hardcoded values, template anti-patterns |
| /helm:security | Audit chart for security issues — RBAC, network policies, pod security, secrets handling |
Recognize these patterns from the user:
If the user has a Helm chart or wants to package Kubernetes resources → this skill applies.
/helm:create — Chart ScaffoldingIdentify workload type
Scaffold chart structure
mychart/
├── Chart.yaml # Chart metadata and dependencies
├── values.yaml # Default configuration
├── values.schema.json # Optional: JSON Schema for values validation
├── .helmignore # Files to exclude from packaging
├── templates/
│ ├── _helpers.tpl # Named templates and helper functions
│ ├── deployment.yaml # Workload resource
│ ├── service.yaml # Service exposure
│ ├── ingress.yaml # Ingress (if applicable)
│ ├── serviceaccount.yaml # ServiceAccount
│ ├── hpa.yaml # HorizontalPodAutoscaler
│ ├── pdb.yaml # PodDisruptionBudget
│ ├── networkpolicy.yaml # NetworkPolicy
│ ├── configmap.yaml # ConfigMap (if needed)
│ ├── secret.yaml # Secret (if needed)
│ ├── NOTES.txt # Post-install usage instructions
│ └── tests/
│ └── test-connection.yaml
└── charts/ # Subcharts (dependencies)
Apply Chart.yaml best practices
METADATA
├── apiVersion: v2 (Helm 3 only — never v1)
├── name: matches directory name exactly
├── version: semver (chart version, not app version)
├── appVersion: application version string
├── description: one-line summary of what the chart deploys
└── type: application (or library for shared helpers)
DEPENDENCIES
├── Pin dependency versions with ~X.Y.Z (patch-level float)
├── Use condition field to make subcharts optional
├── Use alias for multiple instances of same subchart
└── Run helm dependency update after changes
Generate values.yaml with documentation
Validate
python3 scripts/chart_analyzer.py mychart/
helm lint mychart/
helm template mychart/ --debug
/helm:review — Chart AnalysisCheck chart structure
| Check | Severity | Fix | |-------|----------|-----| | Missing _helpers.tpl | High | Create helpers for common labels and selectors | | No NOTES.txt | Medium | Add post-install instructions | | No .helmignore | Low | Create one to exclude .git, CI files, tests | | Missing Chart.yaml fields | Medium | Add description, appVersion, maintainers | | Hardcoded values in templates | High | Extract to values.yaml with defaults |
Check template quality
| Check | Severity | Fix |
|-------|----------|-----|
| Missing standard labels | High | Use app.kubernetes.io/* labels via _helpers.tpl |
| No resource requests/limits | Critical | Add resources section with defaults in values.yaml |
| Hardcoded image tag | High | Use {{ .Values.image.repository }}:{{ .Values.image.tag }} |
| No imagePullPolicy | Medium | Default to IfNotPresent, overridable |
| Missing liveness/readiness probes | High | Add probes with configurable paths and ports |
| No pod anti-affinity | Medium | Add preferred anti-affinity for HA |
| Duplicate template code | Medium | Extract into named templates in _helpers.tpl |
Check values.yaml quality
python3 scripts/values_validator.py mychart/values.yaml
Generate review report
HELM CHART REVIEW — [chart name]
Date: [timestamp]
CRITICAL: [count]
HIGH: [count]
MEDIUM: [count]
LOW: [count]
[Detailed findings with fix recommendations]
/helm:security — Security AuditPod security audit
| Check | Severity | Fix |
|-------|----------|-----|
| No securityContext | Critical | Add runAsNonRoot, readOnlyRootFilesystem |
| Running as root | Critical | Set runAsNonRoot: true, runAsUser: 1000 |
| Writable root filesystem | High | Set readOnlyRootFilesystem: true + emptyDir for tmp |
| All capabilities retained | High | Drop ALL, add only specific needed caps |
| Privileged container | Critical | Set privileged: false, use specific capabilities |
| No seccomp profile | Medium | Set seccompProfile.type: RuntimeDefault |
| allowPrivilegeEscalation true | High | Set allowPrivilegeEscalation: false |
RBAC audit
| Check | Severity | Fix | |-------|----------|-----| | No ServiceAccount | Medium | Create dedicated SA, don't use default | | automountServiceAccountToken true | Medium | Set to false unless pod needs K8s API access | | ClusterRole instead of Role | Medium | Use namespace-scoped Role unless cluster-wide needed | | Wildcard permissions | Critical | Use specific resource names and verbs | | No RBAC at all | Low | Acceptable if pod doesn't need K8s API access |
Network and secrets audit
| Check | Severity | Fix | |-------|----------|-----| | No NetworkPolicy | Medium | Add default-deny ingress + explicit allow rules | | Secrets in values.yaml | Critical | Use external secrets operator or sealed-secrets | | No PodDisruptionBudget | Medium | Add PDB with minAvailable for HA workloads | | hostNetwork: true | High | Remove unless absolutely required (e.g., CNI plugin) | | hostPID or hostIPC | Critical | Never use in application charts |
Generate security report
SECURITY AUDIT — [chart name]
Date: [timestamp]
CRITICAL: [count]
HIGH: [count]
MEDIUM: [count]
LOW: [count]
[Detailed findings with remediation steps]
scripts/chart_analyzer.pyCLI utility for static analysis of Helm chart directories.
Features:
Usage:
# Analyze a chart directory
python3 scripts/chart_analyzer.py mychart/
# JSON output
python3 scripts/chart_analyzer.py mychart/ --output json
# Security-focused analysis
python3 scripts/chart_analyzer.py mychart/ --security
scripts/values_validator.pyCLI utility for validating values.yaml against best practices.
Features:
Usage:
# Validate values.yaml
python3 scripts/values_validator.py values.yaml
# JSON output
python3 scripts/values_validator.py values.yaml --output json
# Strict mode (fail on warnings)
python3 scripts/values_validator.py values.yaml --strict
{{/*
Common labels for all resources.
*/}}
{{- define "mychart.labels" -}}
helm.sh/chart: {{ include "mychart.chart" . }}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels (subset of common labels — must be immutable).
*/}}
{{- define "mychart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "mychart.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
spec:
serviceAccountName: {{ include "mychart.serviceAccountName" . }}
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: {{ .Chart.Name }}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
resources:
{{- toYaml .Values.resources | nindent 8 }}
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
STRUCTURE
├── Flat over nested (image.tag > container.spec.image.tag)
├── Group by resource (service.*, ingress.*, resources.*)
├── Use enabled: true/false for optional resources
├── Document every key with inline YAML comments
└── Provide sensible development defaults
NAMING
├── camelCase for keys (replicaCount, not replica_count)
├── Boolean keys: use adjectives (enabled, required) not verbs
├── Nested keys: max 3 levels deep
└── Match upstream conventions (image.repository, image.tag, image.pullPolicy)
ANTI-PATTERNS
├── Hardcoded cluster URLs or domains
├── Secrets as default values
├── Empty strings where null is correct
├── Deeply nested structures (>3 levels)
├── Undocumented values
└── values.yaml that doesn't work without overrides
SUBCHARTS
├── Use Chart.yaml dependencies (not requirements.yaml — Helm 3)
├── Pin versions: version: ~15.x.x (patch float)
├── Use condition: to make optional: condition: postgresql.enabled
├── Use alias: for multiple instances of same chart
├── Override subchart values under subchart name key in values.yaml
└── Run helm dependency update before packaging
LIBRARY CHARTS
├── type: library in Chart.yaml — no templates directory
├── Export named templates only — no rendered resources
├── Use for shared labels, annotations, security contexts
└── Version independently from application charts
Flag these without being asked:
git clone https://github.com/alirezarezvani/claude-skills.git
cp -r claude-skills/engineering/helm-chart-builder ~/.claude/skills/
./scripts/convert.sh --skill helm-chart-builder --tool codex|gemini|cursor|windsurf|openclaw
clawhub install cs-helm-chart-builder
development
Use when someone wants to run a weekly review, close open loops, audit stalled projects and commitments, get their system back to trusted, restart a lapsed review habit, or says "/cs:weekly-review". Walks David Allen's three-phase loop — GET CLEAR, GET CURRENT, GET CREATIVE — with deterministic scripts that inventory open loops, gate the checklist with named gaps, and score commitment health 0-100.
development
Use when someone wants to decide whether a meeting is worth calling, price a meeting in dollars, build a timeboxed agenda with desired outcomes, or turn messy meeting notes into owned action items — or says "should this be a meeting", "/cs:meeting-prep", or "/cs:meeting-actions". Runs a cost gate (ASYNC / NOT-READY / MEET), builds a decision-first agenda, and extracts an owner + due-date checklist that flags every orphan.
development
Convert a rambling description of a desired outcome into one polished, autonomous /goal prompt ready to paste into a fresh session. Use when the user says "/fable-goal", "turn this into a goal prompt", "write me a fable prompt", "write the prompt that builds X", or rambles about something they want made and asks for the prompt that makes it happen. The output is a single copy-paste prompt, never the build itself. Do NOT use when the user wants the thing built right now in this session — only when they want the PROMPT that will make it happen in a fresh session.
development
Use when someone wants to plan a deep work day, time-block their calendar or task list, budget or cut shallow work, protect focus hours, track deep-work sessions and streaks, run an end-of-day shutdown ritual, or says "/deep-work" or "/time-block". Classifies tasks deep vs shallow, builds an energy-first time-blocked schedule that refuses deep demand past the 4-hour ceiling, batches shallow work into at most two windows, and logs focus sessions against a weekly target.