Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
docs: Update HIP chart-defined plugins specification
- Fix storage locations table (remove incorrect install cache row)
- Add SDK considerations section for controller/platform use cases
- Add note about gotemplate plugin handling Template built-in
- Clarify helm plugin list --status=all shows separate rows
- Note --from-download flag as future enhancement

Signed-off-by: Scott Rigby <scott@r6by.com>
  • Loading branch information
scottrigby committed Feb 25, 2026
commit 3886fe2205eb1b04cdaa9fe4db629d7abf555f18
107 changes: 58 additions & 49 deletions hips/hip-9999.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ Plugins can exist in two states:
| Type | Path | Purpose |
| -------------------------- | ------------------------------------------ | --------------------------------------------- |
| Global install destination | `$PLUGINS_DIR/<name>/` | Final location for installed plugins |
| Global install cache | `$HELM_CACHE_HOME/plugins/{oci-key}/` | Temporary extraction during installation |
| Chart-defined tarball | `$HELM_CACHE_HOME/content/{digest}.plugin` | Content-addressable cache (loaded at runtime) |
| Chart-defined extracted | `$PLUGINS_DIR/versions/<name>/<version>/` | Versioned plugin files for execution |

Chart-defined plugins are loaded directly from the cached tarball at runtime, matching how charts are loaded. There is no persistent extracted directory - the `plugin.yaml` and `.wasm` files are read into memory when needed.
Chart-defined plugins are cached as tarballs in the content-addressable cache and extracted to versioned directories for execution. This enables efficient storage and deduplication while supporting Wasm compilation which requires file paths.

**Content-addressable caching:** Chart-defined plugin tarballs are stored using their SHA256 digest, enabling:

Expand All @@ -210,16 +210,18 @@ Chart-defined plugins are loaded directly from the cached tarball at runtime, ma
- Downloaded plugins can be "installed" (promoted to global) via `helm plugin install` which creates a symlink
- The same plugin can exist in both states (e.g., v1.0.0 installed globally, v2.0.0 downloaded for a specific chart)

**Installing a downloaded plugin globally:**
**Installing a downloaded plugin globally (future enhancement):**

```bash
# After downloading via helm dependency update, install globally:
helm plugin install --from-download pkl-render 0.2.0

# This creates a symlink:
# This would create a symlink:
# $PLUGINS_DIR/pkl-render -> versions/pkl-render/0.2.0
```

> **Note**: The `--from-download` flag is a proposed enhancement, not yet implemented. It would allow users to promote a downloaded (chart-defined) plugin to a globally installed plugin.

**Plugin loading precedence:**

When a chart specifies a plugin, Helm looks in this order:
Expand Down Expand Up @@ -249,10 +251,13 @@ Example output with `--status=all`:
```
NAME VERSION STATUS TYPE DESCRIPTION
pkl-render 0.1.0 installed render/v1 Pkl template renderer
pkl-render 0.1.0 downloaded render/v1 Pkl template renderer
pkl-render 0.2.0 downloaded render/v1 Pkl template renderer
s3-getter 1.0.0 installed getter/v1 S3 protocol support
```

> **Note**: A plugin version can appear twice if it exists in both installed and downloaded states (stored in different locations). Each row represents a distinct physical location.

## Backwards compatibility

Requirements for chart-defined plugins:
Expand Down Expand Up @@ -313,8 +318,8 @@ This work is dependent on, and will be in conjunction with, [H4HIP: Charts v3 En
A reference implementation has been developed to validate this design:

- **Helm core changes**: [scottrigby/helm@chart-defined-plugins](https://github.com/scottrigby/helm/tree/chart-defined-plugins) - Adds render/v1 schema, plugin metadata fields, render plugin invoker, versioned storage, and dependency command updates
- **Pkl render/v1 plugin**: [scottrigby/ref-hip-chart-defined-plugins](https://github.com/scottrigby/ref-hip-chart-defined-plugins) - A Wasm plugin using Extism Go PDK that processes `.pkl` files
- **Example Pkl chart**: [scottrigby/ref-hip-chart-defined-plugins/charts/pkl-chart](https://github.com/scottrigby/ref-hip-chart-defined-plugins/tree/main/charts/pkl-chart) - Demonstrates Chart.yaml with plugins list and Pkl templates
- **Reference plugins**: [scottrigby/ref-hip-chart-defined-plugins](https://github.com/scottrigby/ref-hip-chart-defined-plugins) - Wasm render/v1 plugins using Extism Go PDK
- **Example charts**: [scottrigby/ref-hip-chart-defined-plugins/charts](https://github.com/scottrigby/ref-hip-chart-defined-plugins/tree/main/charts) - Demonstrates Chart.yaml with plugins list

## Reference Links

Expand Down Expand Up @@ -371,63 +376,65 @@ How should chart-defined plugins be discovered and listed on ArtifactHub?

**Decision needed:** ArtifactHub schema for chart-defined plugins?

### 3. Flux Integration Architecture
### 3. SDK Considerations

For GitOps deployments using Flux, helm-controller has unique constraints:
The Helm SDK is used by various tools and platforms beyond the CLI, including:

- **No disk access**: helm-controller fetches artifacts via HTTP into memory
- **Long-running process**: Keeping all compiled Wasm modules in memory could exhaust resources
- **Performance requirements**: Pre-compiled machine code matches native Go; in-memory JIT has overhead
- **Kubernetes controllers** (e.g., Flux helm-controller)
- **CI/CD pipelines**
- **Custom automation tools**
- **Platform-as-a-Service offerings**

**Proposed solution**: HelmPlugin controller
These SDK users have unique constraints that the plugin system must address:

A dedicated Flux controller that:
#### Long-Running Processes

1. Watches HelmPlugin CRs referencing OCI plugin artifacts
2. Compiles Wasm to native machine code for cluster architecture
3. Publishes compiled artifacts via ExternalArtifact API
4. helm-controller fetches pre-compiled code via existing artifact mechanism
Controllers and servers keep the Helm SDK loaded in memory continuously. Considerations:

```yaml
apiVersion: helm.toolkit.fluxcd.io/v1
kind: HelmPlugin
metadata:
name: varsubst-render
spec:
type: render/v1
ref:
oci: oci://ghcr.io/helm/plugins/varsubst-render
tag: v1.0.0
status:
artifact:
url: http://helmplugin-controller/artifacts/varsubst-render.tar.gz
digest: sha256:...
```
- **Memory management**: Compiled Wasm modules consume memory; need lifecycle hooks to release
- **Cache eviction**: LRU or time-based eviction for compilation cache
- **Plugin instance reuse**: Share compiled modules across multiple Helm operations

#### Memory-Constrained Environments

Some deployments have strict memory limits. The SDK should support:

**Benefits:**
- **Bounded compilation cache**: Configurable maximum size
- **Lazy loading**: Only load plugins when needed
- **Cleanup callbacks**: Explicit memory release after operations

- Decouples compilation from execution
- Fits Flux's ExternalArtifact extensibility pattern
- Memory-efficient: load-execute-release pattern
- Version coupling acceptable (Flux controllers released together)
#### Non-Writable Filesystems

**SDK Implementation Requirement:**
Some environments run with read-only filesystems. The SDK should support:

To support SDK users like Flux who need filesystem-independent plugin loading, the internal `plugin.Invoke()` must be abstracted to not assume direct filesystem access:
- **In-memory cache option**: Alternative to disk-based compilation cache
- **Pre-compiled plugin loading**: Accept pre-compiled Wasm modules
- **HTTP-based plugin fetching**: Load plugins from URLs without local extraction

- Pre-loading: Disk loading, HTTP fetching, or other acquisition happens in advance
- Invocation: Compiled machine code is passed as an in-memory object (e.g., `[]byte` or `wazero.CompiledModule`)
- Benefit: SDK users control how/where plugins are sourced without Helm assuming disk access
#### SDK API Requirements

**Phased rollout:**
To support these use cases, the SDK must abstract plugin loading:

1. Helm CLI: Disk-cached compilation (implemented, enabled by default)
2. SDK API: Abstract `Invoke()` to accept pre-loaded compiled modules
3. Flux MVP: LRU compilation cache in helm-controller (bounded memory)
4. Flux Scale: HelmPlugin controller + ExternalArtifact
5. Enterprise: Multi-arch OCI distribution
```go
// SDK users can customize caching behavior
type RenderOptions struct {
// CompilationCache allows custom Wasm compilation cache
// Default: disk-based at $HELM_CACHE_HOME/wazero-build/
CompilationCache wazero.CompilationCache

See [FLUX-WASM-INTEGRATION.md](../docs/FLUX-WASM-INTEGRATION.md) for detailed Flux architecture.
// ContentCache allows custom plugin tarball cache
// Default: disk-based at $HELM_CACHE_HOME/content/
ContentCache downloader.Cache

// PreloadedPlugins allows passing pre-compiled plugins
// Useful for non-writable filesystems or pre-warmed caches
PreloadedPlugins map[string]wazero.CompiledModule
}
```

#### Native Go Plugin Runtime (SDK Only)

For SDK users who want to bypass Wasm entirely, a separate HIP proposes a `go/v1` runtime that allows registering native Go implementations for plugin types. This is SDK-only (CLI always uses Wasm for sandboxing) and covered in a dedicated HIP.

### 4. Template Built-in Object

Expand All @@ -443,6 +450,8 @@ The current `Template` built-in object (providing template name and base path) m

**Question:** With `SourceFiles` available to `render/v1` plugins containing all source file metadata, is `Template` still needed? Or is it only relevant for gotemplate's `include`/`tpl` functions?

**Potential resolution:** If gotemplate becomes a render/v1 plugin for Charts v3 (see Open Issue #1), it could retrieve and handle the current file properly from the `SourceFiles` object and assign that to a `Template` object internally to maintain backwards compatibility with existing gotemplate functionality. This would make `Template` an implementation detail of the gotemplate plugin rather than a Helm built-in.

**Decision needed:** Keep, rename, or deprecate `Template` built-in for render plugins?

### 5. Airgap Support: Download Command vs Registry Mirroring
Expand Down