Plan: executing hook lifecycle routes (closing automatic: false)

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

New to cub? Install the cub CLI first. You can pull and render public catalog packages without an account. Commands that save or change ConfigHub data require you to sign in.

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

UNOFFICIAL/EXPERIMENTAL planning brief. Scope for the real answer to "are we really going to ask people to run these by hand?" - No. The routing work (visible, named, receipted lifecycle steps) is the prerequisite; this brief scopes making them executed - by your delivery pipeline or by the product - with a receipt, so a hook is automated and auditable, never manual toil and never a hidden Helm Job.

Where we are

What "execute" means per route class

Route class (action_kind)Can the product/pipeline run it?How
run-job / run-preflight / run-checkYesApply the Job + wait, write an execution receipt; or emit a GitOps PreSync/PostSync the controller runs.
run-testYes, opt-incub test / a CI step runs the check on demand, writes a receipt. Tests stay explicit by design.
install-crdYesApply CRDs server-side as a managed step + receipt (already proven shape for observed bases).
gitops-sync-hookYesEmit the route as the controller's native hook (Argo PreSync/PostSync, Flux).
accept-target-policy / preserve-ordering / observe-webhook (target-owned)Already automaticThe cluster/applier does it - no product execution needed; just observed.
stage-target-factsNo (stays prerequisite)These are your inputs (Secrets/CRDs/storage). The product can't invent them; it states the requirement. The one honest "you supply it" - but it's setup, like values, not per-deploy toil.

So almost everything is executable; the only permanent "you provide it" is target facts, which are inputs, not toil.

Two execution surfaces (not mutually exclusive)

  1. GitOps-native emission (lowest risk, ship first). Generate the route as the user's existing controller's native step - an Argo CD PreSync/PostSync hook or a Flux equivalent - from the route-action packet. The controller runs it on every sync; it's visible in the controller UI and receipted. No new product runtime.
  2. Product-direct execution (cub). A cub/cub-scout capability that, given a route-action, executes it against the target and writes an execution receipt. This is what flips automatic: true (per the schema rule: product executes + committed evidence). Mostly cub/cub-scout work, not helm-expt.

The receipt (the audit trail that keeps it honest)

Extend the observation/route receipt to record an execution: who ran it (product | gitops-controller | user), when, the command/route, and the result. automatic: true is set only when an execution receipt with executor: product exists. "Visible" is preserved: execution is logged and receipted, never hidden. (Schema touch: add an execution block to schemas/observation-receipt.schema.json or a new route-execution-receipt.)

Phasing

Honest boundaries / acceptance

Decision needed before building

Which surface to lead with - (1) GitOps-native emission (ship in helm-expt, controller runs it, no new runtime) or (3) product-direct cub execution (the automatic: true endgame, cross-repo). Recommendation: Phase 1 (prove receipted execution in-repo) → Phase 2 (GitOps emission) first; treat Phase 3 as the cub roadmap item it already is (#688).

Selecting a route (the user-facing affordance) - REQUIRED

The default is "deliver everything except the hook," so a separated hook does not run on its own. That is only acceptable if choosing the hook's execution path is a first-class operation, reachable through ConfigHub's surfaces (CLI · AI/agent · function · GUI). Otherwise we have made the hidden step visible but not actionable. (Product requirement, 2026-06-20.)

The menu already exists. Every route carries a default_route, alternatives (off-ramps), and a machine-readable agent_inputs block (data/lifecycle-route-actions/). Example - kyverno's migration Job (hook-phase / run-job): default upgrade-action-with-receipt · alternatives argocd-or-flux-lifecycle-hook | target-facts-or-preflight | refuse. The choices are authored; the gap is the selector that lets someone pick and applies it.

The selection contract (one contract; every surface drives it):

This is a runtime module - not a catalog feature. The selector + executor runs at deploy/operate time and writes runtime receipts, so it belongs in the cub / cub-scout runtime, kept self-contained - NOT in helm-expt (a static proof/catalog harness with no runtime). Building it here would contaminate the catalog with runtime concerns. helm-expt's lasting contribution is the static contract + evidence the runtime module consumes: the per-hook menu (default_route + alternatives + agent_inputs), the GitOps emission templates (Phase 2), and the live execution proofs (Phase 1). Stop there in helm-expt.

Surfaces (all part of the runtime module; one shared contract):

SurfaceWhere it livesWhat it is
CLIcub runtime (cub ...)list the menu, select → execute/emit + receipt
AI / agentcub-scout / agent runtime; reads helm-expt's agent_inputspicks a route with a rationale, executes + receipts
functioncub runtime (cub function)sets the chosen route on a Unit, like set-image
GUIproduct UIper-hook control to pick + preview + apply

helm-expt may, at most, host a static contract-conformance check (does each route expose a valid menu + agent_inputs?) - never the live selector/executor.

Status: the menu + the contract exist; the selector mechanism is unbuilt. helm-expt can ship the reference CLI + the agent path + surface the menu; the productized cub CLI / function / GUI implement the same contract. The choice of which surface first does not block the contract - build the contract once.