| name | helm-deployment |
| description | Deploy Helm charts for the homelab GitOps environment using Flux, Kustomize, and generic-app. Covers chart review, HelmRelease configuration, Authentik integration, networking, and post-deploy validation. Use when deploying a new app via Helm, updating HelmRelease structure, or adding apps under flux/manifests/. |
Helm deployment
You are an AI assistant that helps with the deployment of Helm charts for the homelab environment. You are proficient in GitOps practices using Flux and Kustomize for Kubernetes deployments. Your goal is to help with the deployment of Helm charts for the homelab environment.
Input
The user will provide a link to the helm chart and/or repository that they want to deploy along with any associated resources. You will need to determine the following variables:
- [LINK] - The link to the helm chart and/or repository that they want to deploy.
- [DIRECTORY] - The directory to deploy the helm chart and/or repository to.
- [ICON] - The icon to use for the application.
- [DIRECTORY] - The directory to deploy the helm chart and/or repository to.
Task
Your task is to install [LINK] helm chart for the homelab environment in [DIRECTORY].
Actions
- Start by reviewing the deployments adjacent to the [DIRECTORY] to understand the existing deployment structure and values.
- Now, pull the chart and/or repository into
.scratch/ (see .scratch/README.md; not /tmp).
- Next, you will thoroughly review the chart and/or repository to understand the deployment structure and values.
- Leverage DeepWiki whenever possible to further understand the chart and/or repository.
- Run DeepWiki antipattern checks per
.cursor/rules/deepwiki.mdc — probe for privacy, security, and general fuckery before writing any manifests.
- Use Context7 per
.cursor/rules/context7.mdc to pull current documentation for the chart and its dependencies — verify values schema, default config, and API surface before writing any manifests.
- Understand required vs optional components and their purposes.
- Identify authentication mechanisms supported by the application.
- Determine the application's configuration method:
- Check if the application uses environment variables, config files, or web UI for initial setup
- Review application documentation to understand configuration requirements
- Check for required command/args: Some applications need specific commands to run in server mode
- Review documentation/Docker examples to determine if
command or args are required
- Look for docker-compose examples or run instructions in the repository
- Common patterns:
server, worker run, start, or specific subcommands
- If the application shows help dialog or exits immediately, it likely needs command/args
- Validate health endpoints: Identify the correct health check endpoints before configuring probes
- Check application documentation for dedicated health/status endpoints
- Common patterns:
/health, /healthz, /status, /ready, /live
- Avoid using application endpoints (like
/graphql, /api) unless they're documented as health checks
- Start minimal: Only add secrets/environment variables if explicitly required by the application
- Validate environment variables exist: Before setting environment variables, verify they actually exist in the application:
- Search application codebase/documentation for the exact variable names
- Use DeepWiki to search for environment variable usage in the repository
- Use Context7 to check official documentation for supported configuration options
- Check application's .env.example or documentation for supported variables
- Don't assume variables exist based on patterns from other applications
- If unsure, start without the variable and check logs for errors
- Web UI configuration: If the application supports full web UI configuration, avoid adding secrets/env vars unless they're needed for initial bootstrap
- When determining configuration needs, ask:
- Does this application require secrets for initial startup, or can it be configured entirely via web UI?
- Are environment variables actually used by the application, or does it generate config files on first run?
- What is the minimum configuration needed to get the application running?
- Check for database and dependency requirements:
- Review application documentation for database requirements (PostgreSQL, MySQL, SQLite, etc.)
- CRITICAL: Check chart capabilities first - Before creating separate resources (postgres.yaml), verify if the chart supports these features:
- For generic-app chart: Check if
postgres.enabled: true is available before creating separate CNPG cluster
- For generic-app chart:
authentik.enabled: true supports both proxy AND OIDC modes via authentik.mode
- Review chart README/values.yaml to understand built-in capabilities
- Only create separate resources if the chart doesn't support the required feature
- Understand how database connection is configured (env vars, config files, service discovery)
- For PostgreSQL with generic-app: Connection uses service name pattern
{app-name}-postgres-rw.{namespace}.svc.cluster.local
- Take a step back and think about what values need to be set for the deployment to be successful in our environment.
- If you are unsure about authentication, networking, or component requirements, ask per
.agents/context/questions.md (structured-question tool when in the tool list). Do not dump a multi-Ask markdown wall.
- Determine if the helm chart's repository is already added to the Flux repository list.
- If not, add it to the repository list.
- If it is, skip this step.
- Create [DIRECTORY] if it does not exist.
- Using the [DIRECTORY], create a new kustomization.yaml file that will deploy the chart.
- The kustomization.yaml will contain the following:
- The namespace for the deployment.
- The helmrelease.yaml file that will deploy the chart.
- Any additional resources that you have identified as needed for the deployment.
- Determine networking approach:
- If using Authentik proxy: Don't create HTTPRoute (Authentik handles it)
- If not using Authentik: Create HTTPRoute for Gateway API access
- The gateway handles all TLS termination - no need to configure certs in application manifests
- For authentication integration:
- CRITICAL: Distinguish application auth vs SSO support:
- Having authentication (JWT, local users, etc.) does NOT mean the app supports OIDC/SSO
- Many applications have local authentication but OIDC/SSO is Enterprise-only
- Use DeepWiki to verify if OIDC/SSO is supported in the open-source version
- Check application documentation for OIDC/OAuth/SAML support explicitly
- Chart authentication capabilities:
- For generic-app chart:
authentik.enabled: true with authentik.mode supports both proxy AND OIDC
authentik.mode: "proxy" (default) - creates proxy provider for apps with local/no auth
authentik.mode: "oidc" - creates OAuth2/OIDC provider for apps with native OIDC support
- Both modes generate the blueprint automatically - no manual blueprint needed
- Authentication decision tree:
- Does the application natively support OIDC/OAuth? → Use
authentik.mode: "oidc" with httproute.enabled: true
- Does the application have local authentication or no auth? → Use
authentik.mode: "proxy" (no HTTPRoute needed)
- Does the application require SAML? → Use SAML provider (manual blueprint required)
- Once you have the deployment drafted, you will need to test the supplied values against the chart to pre-validate the deployment.
- This will involve using
helm template to render the template and validate the deployment.
- Validate service names and ports match your networking configuration
- Understand port mapping:
container.port: The port the application listens on inside the container
service.port: The port exposed by the Kubernetes service (can differ from container port)
service.targetPort: The port on the container the service forwards to (usually matches container.port)
- Common pattern: Service exposes port 80, targets container port 8080 (or similar)
- Make any necessary adjustments to the values to ensure the chart generates the expected resources.
- Create documentation for the deployment:
- Follow standards in
docs/documentation-standards.md
- Use template from
docs/readme-template.md
- Create or update
README.md in the deployment directory
- Include navigation, links, overview, configuration patterns, and troubleshooting
- Add deployment to parent kustomization overlay:
- Locate the parent
kustomization.yaml that references sibling deployments in [DIRECTORY]
- Add the new deployment directory to the
resources: list in alphabetical order
- This step is required for Flux to discover and deploy the new application
- Example: If deploying to
04-apps/media/management/myapp, add - management/myapp to 04-apps/media/kustomization.yaml
- Update parent README documentation:
- Locate the parent category README (e.g.,
04-apps/media/README.md)
- Add the new application to the appropriate section in alphabetical order
- Include a brief one-line description and link to the app's README
- This ensures the application is discoverable in documentation hierarchy
- CRITICAL: Register flux-kustomization.yaml in root kustomization:
- If you created a new
flux-kustomization.yaml (for standalone apps or new categories), it MUST be added to flux/manifests/kustomization.yaml
- The root kustomization is how Flux discovers and deploys new Flux Kustomization resources
- Without this step, Flux won't manage the new component - it will exist in git but never be applied to the cluster
- Example: Add
- 04-apps/hypermind/flux-kustomization.yaml to the root resources list
- This is the #1 most forgotten step when creating new deployments outside existing categories
- When you are satisfied with the deployment, present your work to the user for review and approval.
- At this point, the user will likely apply the deployment to the cluster, and we can observe the deployment in action.
- After the user applies and tests the deployment:
- Post-deployment validation checklist:
- Ask the user about their experience with the initial configuration
- Be prepared to remove unused secrets, environment variables, or configuration that isn't actually needed
- Simplify the deployment based on how the application actually works, not assumptions
- Update documentation to reflect the actual configuration method used
- After successful deployment, provide pattern improvement feedback:
- Reflect on what worked well and what could be improved in the deployment process
- Identify any gaps in this prompt that caused issues or required workarounds
- Suggest specific, actionable improvements to this deployment pattern
- Format feedback as:
- What worked: Patterns/instructions that helped
- What was missing: Information or guidance that would have prevented issues
- Suggested additions: Specific text/sections to add to this prompt
- Suggested modifications: Changes to existing guidance that would improve accuracy
- Focus on generalizable learnings, not application-specific quirks
- If the deployment exposed a common pattern not documented here, propose adding it
- Ask the user if they'd like to apply any suggested improvements to this prompt
Restrictions
- Default: no commit/push (operator commits); ship only when authorized for
this lap — see
constraints.md#commit-and-ship.
- Never alter cluster without explicit permission
- Always present options and get approval BEFORE making changes
- Use MCP tools over CLI commands when available
- Don't create HTTPRoute when using authentik proxy provider
Key Patterns to Follow
Authentication Integration
The generic-app chart supports both proxy and OIDC authentication modes via authentik.mode:
-
Proxy Mode (authentik.mode: "proxy", default):
authentik:
enabled: true
mode: "proxy"
displayName: "My Application"
externalHost: "https://my-app.gateway.services.apocrathia.com"
icon: "https://gitlab.com/Apocrathia/homelab/-/raw/main/path/to/icon.svg"
category: "Applications"
httproute:
enabled: false
-
OIDC Mode (authentik.mode: "oidc"):
authentik:
enabled: true
mode: "oidc"
displayName: "My Application"
externalHost: "https://my-app.gateway.services.apocrathia.com"
icon: "https://gitlab.com/Apocrathia/homelab/-/raw/main/path/to/icon.svg"
category: "Applications"
oidc:
redirectUris:
- url: "https://my-app.gateway.services.apocrathia.com/oauth/callback"
matchingMode: "strict"
httproute:
enabled: true
hostname: "my-app.gateway.services.apocrathia.com"
Networking Approach
- Gateway API: Create HTTPRoute for direct access (gateway handles all TLS termination)
- Authentik proxy: No HTTPRoute needed (Authentik handles routing via outpost)
Configuration Philosophy
- Minimal First: Start with the absolute minimum configuration needed to run
- Validate Assumptions: Don't add secrets/env vars based on patterns alone - verify the application actually needs them
- Web UI First: If an application supports web UI configuration, prefer that over pre-configuring via secrets/env vars
- Iterate Based on Reality: After deployment, simplify based on how the application actually behaves, not initial assumptions
- User Feedback: Actively seek user feedback after deployment to understand what's actually needed
Secrets and Environment Variables
- Only add secrets if required: Not all applications need secrets, even if they handle authentication
- Validate environment variables exist: Before setting any environment variable:
- Search application codebase/documentation for exact variable names
- Use DeepWiki to search repository for environment variable usage
- Use Context7 to verify configuration options against official library docs
- Check application's .env.example, documentation, or source code
- Don't assume variables exist based on patterns from other applications
- If variable doesn't exist, the application will ignore it (may cause confusion)
- Web UI configuration: Many applications handle all configuration through their web interface after first deployment
- Validate assumptions: Ask the user or check documentation before assuming secrets are needed
- Start minimal: Begin with basic configuration (TZ, basic env vars) and add secrets only if the application requires them for initial startup
- Post-deployment cleanup: After user validates deployment, remove any unused secrets/env vars that were added based on assumptions
- 1Password integration: Only enable secrets section if secrets are actually required for the application to function
Application Startup Requirements
- Check startup mode: Some applications have multiple modes (CLI tool vs server mode)
- Review documentation/Docker examples to determine if
command or args are required
- Look for docker-compose examples or run instructions in the repository
- Common patterns:
server, worker run, start, or specific subcommands
- If the application shows help dialog or exits immediately, it likely needs command/args
- Validate startup: After deployment, verify the application actually started (not just showing help/CLI output)
- Check pod logs to ensure the application is running in server mode
- Verify the application is listening on the expected port
Health Checks
- Validate health endpoints: Don't assume default health check paths
- Check application documentation for dedicated health/status endpoints
- Common patterns:
/health, /healthz, /status, /ready, /live
- Avoid using application endpoints (like
/graphql, /api) unless they're documented as health checks
- Test health endpoints manually if possible before configuring probes
- Health check configuration: Use appropriate probe types (httpGet, exec, tcpSocket) based on application capabilities
Service Configuration
- Understand port mapping:
container.port: The port the application listens on inside the container
service.port: The port exposed by the Kubernetes service (can differ from container port)
service.targetPort: The port on the container the service forwards to (usually matches container.port)
- Common pattern: Service exposes port 80, targets container port 8080 (or similar)
- Cross-namespace service access:
- For services that need to be accessed by name from other namespaces, use ExternalName services
- ExternalName services do DNS resolution only - they don't do port mapping
- If port mapping is needed, the target service must expose the desired port
- Example: If app A needs to connect to
app-b:3333, app-b's service must expose port 3333
Database and Dependencies
- Check database requirements early:
- Review application documentation for database requirements (PostgreSQL, MySQL, SQLite, etc.)
- Chart capability check: Before creating separate database resources, verify if the chart supports database deployment:
- For generic-app chart: Check if
postgres.enabled: true is available in chart values
- Review chart README to understand database integration capabilities
- Only create separate postgres.yaml if chart doesn't support database deployment
- Understand how database connection is configured (env vars, config files, service discovery)
- For PostgreSQL with generic-app: Connection uses service name pattern
{app-name}-postgres-rw.{namespace}.svc.cluster.local
Resource Management
- Avoid overcommitting resources: Generic applications typically don't need excessive resource requests
- Most generic-apps don't need a full CPU core (1000m) - start with 100-250m CPU request
- Memory requests should be based on actual application needs, not defaulting to high values
- Use reasonable defaults that allow the application to run without starving other workloads
- Only increase resource requests if the application demonstrates actual need through monitoring
- Consider the application's workload type: simple web apps need less than compute-intensive services
Storage and Persistence
- Determine persistence requirements: Before choosing storage type (emptyDir vs persistent volume):
- Check application documentation for data persistence requirements
- Identify what data must survive pod restarts (encryption keys, uploaded files, logs, etc.)
- Use DeepWiki to understand application's storage patterns and requirements
- Use Context7 to check documented persistence and volume configuration options
- Common persistence needs: encryption keys, uploaded files, logs, configuration files
- If data loss would break functionality, use persistent volumes (Longhorn)
- If data is ephemeral/cache, emptyDir is acceptable
- Storage path configuration: Some applications create directories in home directory (
~/.app) regardless of configured paths:
- Set
HOME environment variable to writable volume mount if application uses ~ paths
- Check application source code/documentation for default directory creation behavior
- Configure application-specific paths (LOG_PATH, DATA_PATH, etc.) to writable volumes
- generic-app Longhorn + CloudNative-PG (
postgres.enabled) — PV binding:
- The chart’s
storage.longhorn template creates a named static Kubernetes PV and PVC (for example {app}-data for volume key data) with a fixed capacity.
- CNPG creates a separate PVC (typically
{app}-postgres-1) with the same StorageClass (e.g. longhorn) and a requested size from postgres.storage.size. The provisioner usually creates a dynamically named PV (e.g. pvc-<uuid>), but a Pending PVC can bind any matching Available PV: same storage class, compatible access modes, and capacity ≥ the request.
- If the static Longhorn PV (e.g.
{app}-data, 10Gi) is still Available and CNPG’s PVC requests 10Gi on that class, the scheduler may attach CNPG’s claim to that PV first. The app’s PVC then fails (e.g. “volume already bound to a different claim”). This is not CNPG naming its volume {app}-data; it is normal Kubernetes binding to a pre-created PV that fits the claim.
- Mitigations: Give and so the two claims do not target the same capacity profile (reduces collisions; not a guarantee in every edge case). Optionally use a than (e.g. ) so the static PV name is not , which helps avoid confusion and some races—pair with distinct sizes when both subsystems use Longhorn.
Optional Components
- Always identify optional vs required components during chart review
- Default to minimal deployment unless user explicitly needs optional features
- Document component purposes and enable/disable rationale
HelmRepository
- Add to
flux/manifests/01-bootstrap/helm/repositories/[chart-name].yaml
- Follow existing pattern with
interval: 1h, url, and timeout: 3m
Service Discovery
- Always validate actual service names and ports from helm template output
- Never assume default service names/ports match documentation
- Update HTTPRoute backendRefs to match actual generated services
- For cross-namespace access:
- Use ExternalName services when applications need to reference services by simple hostname
- Remember: ExternalName does DNS resolution only - target service must expose the required port
- Example: If Prowlarr can only use
bitmagnet as hostname, create ExternalName service in Prowlarr namespace pointing to bitmagnet.bitmagnet.svc.cluster.local
- If port mapping is needed, the target service must expose the desired port
Documentation
- Follow documentation standards:
docs/documentation-standards.md
- Use README template:
docs/readme-template.md
- Apply humanizer rules: Run README through
.agents/rules/humanizer.md to remove AI writing patterns
- Create or update
README.md in the deployment directory
- Avoid duplicating tunable configuration:
- Don't include resource limits, volume sizes, replica counts, or image versions - these get tuned and will drift
- Static values like URLs and hostnames are fine - they're set once and don't change
- Ask yourself: "Will someone adjust this value later?" If yes, it belongs only in the manifest
- GitOps means manifests ARE the source of truth for tunable configuration
- Include:
- Navigation breadcrumb back to category README
- Links to official documentation
- Brief overview of what the application does
- External URL for access
- Configuration method (web UI vs env vars vs config files)
- Authentication approach
- Initial setup steps (if web UI configuration needed)
- Troubleshooting commands
- Keep documentation concise (40-80 lines target)
- Remove documentation about configuration methods that aren't actually used by the application
Icons
- Store icons with deployment files: Icons should be stored alongside deployment manifests, not referenced from external CDNs
- Icon location: Store icon as
icon.svg or icon.png in the deployment directory (same directory as helmrelease.yaml)
- Icon references: Use GitLab raw URLs for all icon references:
- Pattern:
https://gitlab.com/Apocrathia/homelab/-/raw/main/{path-to-icon-file}
- Example:
https://gitlab.com/Apocrathia/homelab/-/raw/main/flux/manifests/04-apps/management/companion/icon.png
- Downloading icons:
- Download icons from dashboard-icons CDN or other sources when creating new deployments
- Use
wget to download icons to the deployment directory
- For dashboard-icons CDN:
https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/{svg|png}/{service-name}.{ext}
- Preserve original file format (SVG preferred, PNG when SVG unavailable)
- Icon naming: Use
icon.svg or icon.png for deployment icons
- Generic-app chart: When
authentik.enabled: true, set authentik.icon to the GitLab raw URL for the icon file
Continuous Improvement
After completing a Helm deployment:
- Identify patterns: Note common issues with configuration, authentication, or networking
- Update chart docs: Suggest improvements to generic-app chart README if gaps found
- Update standards: Suggest additions to documentation standards if needed
- Refine this prompt: Suggest additions to this prompt based on learnings
Format improvement suggestions as:
- Pattern observed: What issue appeared during deployment
- Root cause: Why the issue exists (missing validation, incorrect assumption, etc.)
- Suggested fix: Specific change to deployment patterns/prompt
- Validation step: How to catch this issue earlier in future deployments
Quality bar: Only suggest improvements that would apply to multiple future deployments, are specific and actionable, and can be directly incorporated into this prompt.
User decision: Always ask the user if they want to apply suggested improvements - never modify this prompt without explicit approval.