If My Chart Has Hooks, What Happens?

A repository document, rendered for the site. View source markdown.

Generated at: 2026-07-30T12:38:02.000Z UTC · source: committed helm-expt evidence for this rendered repository document.

UNOFFICIAL/EXPERIMENTAL.

Short answer: the catalog renders your chart's objects without running its Helm hooks. Then, for each chart, it records what still has to happen.

That may be a setup step, a CRD ownership choice, a GitOps action where evidence exists, a target-specific decision, a blocker, or a refusal. The answer is chart-specific because Helm hooks are chart-specific.

A recorded route is not the same as automatic execution. The Kube Prometheus Stack direct example now runs seven fresh-install steps in the recorded order, including its certificate Jobs and CRDs. Its Argo CD, Flux, and upgrade paths have not run, so the chart's top-level routes remain automatic: false.

The Practical Choices

For a supported chart preset, the catalog should say which of these choices applies:

ChoiceMeaning
Keep it in the presetThe rendered objects and checks are enough for this supported path.
Split the presetFor example, provide both default and no-crds so users can choose who owns CRDs.
Run a setup stepThe chart needs work before or after apply, and the step has evidence for this chart.
Use a GitOps actionArgo, Flux, or another delivery tool can run the work where we have tested that path.
Require a target factThe user must provide a Secret, StorageClass, hosted zone, CRD owner, cloud account, or similar input.
Block or refuseThe catalog does not claim the path works until the missing evidence or unsafe behavior is resolved.

These choices are how the catalog handles most real cases. It does not need one generic hook mechanism that treats every chart the same way. It needs accurate chart-specific answers, recorded inputs, generated output, and receipts where support is claimed.

What a route tells you

Each behavior carries a disposition: observed (route plus a live receipt), routed (route known, not run), per-target (a target decision is required), blocked (a prerequisite or evidence is missing), or refused (deliberately not run).

The machine-readable form is data/lifecycle-route-actions/: an agent reads actions.json and turns a row into a preflight/action/observe plan. The route contract behind it is data/lifecycle-routes/. The per-chart view - each chart's routes, disposition, automatic: false, and whether a skill applies - is data/per-chart-hooks/ (colored cards in by-chart.html).

What You Actually Do

  1. Choose the chart preset. Start from the chart page, not a generated package folder.
  2. Read the chart extras. Look for hooks, CRDs, setup jobs, webhooks, generated Secrets, and target facts.
  3. Check the disposition. observed has a receipt for the supported scope. routed, blocked, or per-target means the work is named but still needs setup, target input, or more evidence.
  4. Supply the required target facts such as Secrets, CRDs, storage, hosted zones, or cloud accounts.
  5. Run only the actions that are supported for that chart and target. A placeholder command is not a support claim.
  6. The behavior becomes observed for your scope once there is a receipt.

Worked examples

Kube Prometheus Stack - direct install and controller upgrade

Kube Prometheus Stack 85.3.3 renders 124 ordinary objects, ten CRDs, and seven Helm hook objects. The direct example applies the CRDs first, runs the chart's certificate creation Job, checks the resulting Secret, applies the ordinary objects, runs the webhook patch Job, checks the webhook and six workloads, and removes the temporary hook objects.

Run the guarded example with:

HELM_EXPT_ALLOW_LIVE_KPS_LIFECYCLE_PROOF=1 npm run kps:lifecycle-route:run

The human guide, summary, and receipt show the order, objects, checks, and limits. This proves one fresh direct install on kind.

The no-crds preset also has a separate controller receipt. Argo CD and Flux installed 85.3.3, upgraded to 86.1.0, replaced both completed setup Jobs, and passed the runtime checks. ConfigHub does not yet select that route automatically, and the receipt does not prove rollback or long-running soak.

cert-manager / External Secrets - observed

cert-manager's startupapicheck post-install hook becomes a post-apply API dry-run / readiness check, and CRD ownership is a per-target decision (a base ships the CRDs, or the cluster owns them). External Secrets has no Helm hook, but its controller populates Secret data and a webhook CA bundle after apply - a post-apply observation. Both are observed, with receipts, in the cert-manager / ESO lifecycle lane. (These are not in the hook-disposition source yet, so they do not have action packets - they are shown here until that source is folded in.)

Consul UI Ingress - per-target

Exposing the Consul UI is a per-target decision, not an automatic step: whether and how to route ingress depends on your platform, and Consul's controller health is still a watch item. The catalog names the decision rather than guessing or claiming it is done.

A hook that stays routed, not automatic

bitnami/kafka's provisioning Job is a post-install / post-upgrade hook routed as a managed action - but its live status is blocked (pinned image tags no longer resolve upstream), so its action packet is blocked, automatic: false. The route is known; it is not run for you. The packet says exactly that, with the blocker and the evidence required to advance.

The honest boundary

A known route is not an executed one. automatic is false for every route today. The value now is clear chart-specific guidance: you, a reviewer, or an agent can see where each hidden behavior goes and what it needs, instead of reverse-engineering Helm during an install.

Making the product execute observed or routed steps is separate, continuing work (#688).

See also