Lesson 7 of 28
Module 2 · Skill — Codify `helm-chart-scaffold`
Why this becomes a skill
You just wrote a Helm chart that parameterises an image, replicas, and a service port — then you watched a single value override silently break the deployment. Both halves matter. Scaffolding charts is one of the most-repeated tasks in platform work; doing it correctly (including the sanity checks) every time is what the skill is for.
The skill is valuable because you just hit the nodePort mismatch yourself. You know what that class of failure looks like. You can teach the skill to catch it. If you hadn't run the probe, you wouldn't know the failure existed and the skill would only work on the happy path.
Codify
Send Claude:
"Codify the session we just had as a skill at
.claude/skills/helm-chart-scaffold/SKILL.md. Scope: scaffold a Helm chart for a stateless HTTP service. Parameterise: chart name, image repository, image tag, replica count, service port, service nodePort, container port, healthz path. Steps:helm create, editvalues.yaml, wirenodePort/targetPort/containerPortthrough the templates, setingress.enabled: falseandautoscaling.enabled: false,helm install --wait,curlthe healthz. Include ahelm lintstep before install. Keep SKILL.md under 140 lines."
Open .claude/skills/helm-chart-scaffold/SKILL.md and read it top to bottom. Every templated value should have a reason you can articulate. If any step is opaque, ask Claude to expand it in place.
Refine
"Add a post-install sanity check: render the chart with
helm get manifest <release> -n <ns>and verify the Service'snodePort/targetPortand the Deployment'scontainerPortare all consistent with the values used. Fail with a clear message if they drift.""Remember the Break-it-on-purpose probe: we overrode
service.nodePort=31080andcurl localhost:9898/healthzsilently failed because the kind config forwards port 9898 to node port 30080, not 31080. Add a pre-install check that compares the override'snodePortagainst the cluster's kind config (when the context iskind-*) and warns before applying.""Name the three most common ways this goes wrong in a
Known failuressection: (a)Error: UPGRADE FAILED: another operation ... in progressfrom a previous crashed apply, (b) chart installs but traffic doesn't land because of nodePort / kind-config drift, (c) install appears successful buthelm get manifestshows the Service'sselectordoesn't match the Deployment's labels (the selector footgun you met in module 1). For each, say what command surfaces the root cause."
Validate in a fresh context — happy path AND adversarial
4a — Happy path
New Claude session, no history:
"Read
.claude/skills/helm-chart-scaffold/SKILL.mdand scaffold a chart callednginx-chartfornginx:1.27-alpineon port 80,nodePort: 30090, host port 8090, one replica. Install it into namespacenginx-demoand confirmcurl http://localhost:8090/returns the nginx welcome page. The cluster already hasextraPortMappings: [{ containerPort: 30090, hostPort: 8090 }]in its kind config."
If the skill produces a working chart + install + curl without your intervention, it's passing happy path.
4b — Adversarial
In the same fresh session, feed it broken inputs:
- Override for a non-existent field:
"Install mynginx-chartwith --set image.tag.version=latest --set serivce.port=80"(note the typo —serivcenotservice). Does the skill catch that Helm will silently accept this and do nothing with the override, or does it validate the values against the chart'svalues.yamlschema first? - nodePort conflict: "Install the chart with
--set service.nodePort=30080into a cluster where another Service is already using nodePort 30080." Does the skill pre-check for port conflicts, or does it try to install and fail halfway? - Mid-crashed prior release: Deliberately leave a prior release in a failed state (
helm install my-failing-chart . -n ns && killmid-install). Ask the skill to install over it. Does it recognise the stuck state and suggesthelm rollback/helm uninstall, or does it bang its head onUPGRADE FAILED: another operation in progress?
Promote deterministic commands to scripts/
The repetitive block is the install/upgrade invocation + the post-install sanity check. Prompt:
"Extract the deterministic commands into
.claude/skills/helm-chart-scaffold/scripts/install.shtaking arguments (release name, chart path, namespace, and a values-override string). Includehelm lintbefore install,helm upgrade --install --wait --timeout=5m, and a post-install diff between.spec.template.spec.containers[0].ports[0].containerPortand.spec.ports[0].targetPort. Setset -euo pipefail."
Read install.sh before you commit it. Any kubectl/helm invocation that doesn't quote its arguments is a bug waiting for a namespace with a space in it.
Know the boundary
At the top of .claude/skills/helm-chart-scaffold/SKILL.md, two sentences:
- This skill handles: stateless HTTP services, parameterised image/replicas/port/nodePort, a single-cluster deployment, helm lint + install + post-install sanity check for port-mapping drift.
- This skill does NOT handle: stateful workloads (no PVC templating), Ingress/TLS (explicitly disabled in values), HorizontalPodAutoscaler, chart dependencies (
dependencies:block in Chart.yaml), private chart repositories, release rollback logic beyond a cleanhelm uninstall, RBAC scaffolding (seerbac-iam-scaffoldin module 7), or cloud-native IAM-authenticated registries (GAR/ECR — IAM required).
You're done when
A fresh Claude session reads the skill and, from one prompt, produces a working chart + install + sanity-checked acceptance test for a new service — AND when fed the adversarial inputs in 4b, the skill fails loudly with an actionable message rather than silently doing the wrong thing.