Date: 2026-07-03 Status: Accepted
Context
Phase 5c landed LocalDocker (OSS parity). Redesign spec docs/specs/2026-05-02-rocky-system-redesign.md §SS-08 lists three drivers; the two remaining are Kustomize (self-hosters running their own k8s) and DevarnoCloud (managed). Phase 6a ships Kustomize. Phase 6b (DevarnoCloud) is deferred until cloud creds + product SKUs are wired.
Decision
Kustomize driver lands as an emit-only target. Provision writes a kustomization.yaml + three resource manifests under $ROCKY_HEARTH_KUSTOMIZE_OUTDIR/<slug>/; the operator applies + deletes out-of-band via kubectl {apply,delete} -k <dir>. No client-go at this stage.
Locked semantics (mirror the LocalDocker contract):
Provision(slug, profile)— idempotent on(slug, tier)via the tier marker in the emittedkustomization.yamlheader. Same tier → returns existingDeploymentRef, no file writes. Different tier →ErrTierMismatch. Slug validated against DNS-1123. Rolls back the workspace dir on partial-write failure.Status(ref)— filesystem-only. Missing dir →StatusTierTornDown(D8 terminal). Four files present →StatusReady. Partial →StatusProvisioning.Upgrade(ref, profile)— re-emits all files with new profile values, preservesWorkspaceSlug+Created.Teardown(ref)—os.RemoveAll(<outdir>/<slug>). Idempotent.DeploymentRef.Endpoint—kustomize://<abs-outdir>/<slug>(opaque locator; operator's cluster DNS is unknown at emit time).
Wired into cmd/hearth/main.go as ROCKY_HEARTH_DRIVER=kustomize. Reuses ROCKY_HEARTH_IMAGE_CAIRNET / ROCKY_HEARTH_IMAGE_LORE. New env: ROCKY_HEARTH_KUSTOMIZE_OUTDIR (default /var/lib/rocky-hearth/manifests).
No console-side changes — driver name is opaque to console/src/lib/hearth/.
Non-goals (deferred to 6a-followup)
- Cluster-truth
Statusviaclient-gowhenKUBECONFIGis set. - Overlay support (
base/+overlays/<env>/). - Multi-namespace / cross-cluster emit.
- Helm variant.
Evidence
- Hearth PR:
rocky-hq/hearth#7 - Plan:
docs/plans/2026-07-03-phase-6a-kustomize.md - Tests:
hearth/internal/driver/kustomize/kustomize_test.go— contract (idempotence, ctx cancel, teardown terminal, upgrade preserves slug/created), tier mismatch, invalid slug, driver-flag image overrides. - Full hearth
go test ./... -race -count=1green (7 packages, 8 test binaries). - Smoke via unix socket: RPC
/v1/provisionreturnsready+ emits four expected YAML files.
Consequences
- Phase 6 status flips from
not-startedtoopen(6a landed, 6b still open). - No Polar entitlement gate changes — kustomize is a driver, not a tier; Phase 7 gate logic already runs orthogonally at invocation time.
- Self-hosters can now target k8s clusters without running the LocalDocker path on the operator's box.