# AGENTS.md This is a Helm chart for deploying a self-hosted home environment (Homey) on Kubernetes. ## Project Overview - **Type**: Helm Chart (Kubernetes package manager) - **Language**: YAML + Go template syntax (Helm templating) - **Key Files**: - `Chart.yaml` - Chart metadata - `values.yaml` - Default configuration values - `templates/` - Kubernetes manifest templates (auth.yaml, media.yaml, phpldapadmin.yaml, _definitions.yaml) - `files/` - Configuration file templates (processed by Helm with `tpl` function) ## Build/Lint/Test Commands ### Helm Validation ```bash # Lint the Helm chart for errors helm lint . # Template rendering (dry-run install) helm template test-release . --debug # Install/upgrade in cluster helm upgrade --install homey . -n homey # Verify chart against Kubernetes API helm kubeval . # Check schema validation of values.yaml helm schema generate ``` ### Manual Template Testing ```bash # Render templates locally with custom values helm template homey . -f values.yaml --set homey.url=example.com # Template with debug output helm template homey . --debug 2>&1 | less ``` ### Kubectl Validation ```bash # Dry-run apply to validate manifests kubectl apply -f templates/auth.yaml --dry-run=server # Get rendered template directly helm template homey . | kubectl apply --dry-run=server -f - ``` ## Code Style Guidelines ### YAML Structure 1. **Document Separators**: Use `---` at the start of each YAML document ```yaml --- apiVersion: v1 kind: ConfigMap ``` 2. **Indentation**: Use 2 spaces (not tabs) ```yaml spec: containers: - name: app image: nginx ``` 3. **Trailing Commas**: Optional but preferred for multi-line lists ```yaml accessModes: - ReadWriteMany - ReadOnlyMany ``` 4. **Quotes**: Use quotes for strings that might be interpreted as other types - Always quote: `.Values.homey.url | quote` - Optional for simple strings like names ### Kubernetes Resources 1. **Labels**: Use Kubernetes recommended labels ```yaml labels: app.kubernetes.io/name: openldap app.kubernetes.io/component: auth ``` 2. **Naming**: Use kebab-case for resource names ```yaml name: openldap-admin name: nextcloud-postgres ``` 3. **Storage**: Always specify `storageClassName: longhorn` ```yaml spec: storageClassName: longhorn ``` ### Helm Template Syntax 1. **Variable Assignment**: Use `$_ := set` for complex assignments ```yaml {{- $_ := set $ "varname" (include "homey.lookuporgensecret" (merge (dict "secretname" "secret-name") $)) }} ``` 2. **Include with Merge**: Always pass `$` as the last argument ```yaml {{ include "homey.randomsecret" (merge (dict "secretname" "secret-name" "secretval" $secretval) $) }} ``` 3. **Quote Values from .Values**: Use `quote` filter ```yaml value: {{ .Values.homey.url | quote }} ``` 4. **Template Definitions**: Define reusable templates in `_definitions.yaml` - `homey.lookuporgensecret` - Look up existing secrets or generate random - `homey.randomsecret` - Generate a random secret - `homey.randHex` - Generate random hex string 5. **Template Spacing**: Use whitespace control to avoid extra newlines ```yaml {{- "leading minus" -}} # No newline before {{ "trailing minus" -}} # No newline after ``` ### Secret Management 1. **Annotations**: Always annotate managed secrets to prevent deletion ```yaml annotations: "helm.sh/resource-policy": "keep" ``` 2. **Secret Generation Pattern**: ```yaml # Check for existing secret, create if not exists {{- $secretObj := (lookup "v1" "Secret" .Release.Namespace "secret-name") | default dict -}} {{- $secretData := (get $secretObj "data") | default dict -}} {{- $pass := (get $secretData "password") | default (randAlphaNum 32 | b64enc) -}} ``` 3. **Never hardcode secrets** - Use the secret lookup pattern above ### Config Files (files/ directory) 1. **Go Templates in Configs**: Use `tpl` function to process config files ```yaml data: config.yml: |- {{ tpl (.Files.Get "files/authelia-config.yaml" | indent 4) . }} ``` 2. **Accessing Variables**: Config files can access `.Values.*` and custom variables set in templates ### Ingress Configuration 1. **TLS**: Always specify TLS with proper hosts and secret ```yaml spec: ingressClassName: {{ .Values.homey.ingress_class }} tls: - hosts: - auth.{{ .Values.homey.url }} secretName: {{ .Values.homey.certname }} ``` 2. **Authelia Integration**: Use auth snippets for protected ingresses ```yaml annotations: nginx.ingress.kubernetes.io/auth-url: http://authelia.{{ .Release.Namespace }}.svc.cluster.local:9091/api/verify nginx.ingress.kubernetes.io/auth-signin: https://auth.{{ .Values.homey.url }}?rm=$request_method ``` ### Resource Organization 1. **File Structure**: - `templates/_definitions.yaml` - Helper templates (secrets, utilities) - `templates/auth.yaml` - Authentication services (OpenLDAP, Authelia, Gitea, Nextcloud, Radicale) - `templates/media.yaml` - Media services (Jellyfin, Transmission) - `templates/phpldapadmin.yaml` - LDAP admin interface 2. **Manifest Order** (within a file): - PersistentVolumeClaim - Secrets - ConfigMaps - Deployments - Services - Ingress 3. **Unused Resources**: Keep deprecated manifests in `unused/` directory ### Environment Variables 1. **Naming**: Use uppercase with underscores ```yaml - name: LDAP_ORGANISATION value: {{ .Values.homey.organization }} ``` 2. **Value Sources**: Prefer `valueFrom.secretKeyRef` over inline values ```yaml - name: PASSWORD valueFrom: secretKeyRef: name: secret-name key: password ``` ### Volume Mounts 1. **subPath**: Use `subPath` for shared PVCs ```yaml volumeMounts: - mountPath: /data subPath: service-name/data ``` 2. **Read-only ConfigMaps**: Mark config mounts as read-only ```yaml readOnly: true ``` ## Common Operations ### Adding a New Service 1. Add values to `values.yaml` 2. Create/extend template in `templates/` 3. Add PVC if persistent storage needed 4. Add Ingress with appropriate annotations 5. Test with `helm template .` ### Updating Secrets Secrets are generated on first install. To regenerate: ```bash kubectl delete secret -n homey helm upgrade --install homey . -n homey ``` ### Debugging Templates ```bash # Show all template variables available helm template . --show-only templates/_helpers.tpl # Render single template helm template . --show-only templates/auth.yaml ```