with one click
add-app
Scaffold a new app-template Helm chart application
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Scaffold a new app-template Helm chart application
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | add-app |
| description | Scaffold a new app-template Helm chart application |
This skill scaffolds a new application in your home-ops repository based on the app-template Helm chart.
Use the question tool to gather:
radarr, sonarr)default, ai, networking)ghcr.io/autobrr/autobrr)v1.76.0)7474)volsync)radarr_main)radarr)pg_user and pg_password fields (e.g., 133e1c1d-894d-4fc7-a69c-d44bd3fe090f)Create the directory: kubernetes/apps/<namespace>/<app-name>/app/
Create these files with templated values:
kubernetes/apps/<namespace>/<app-name>/ks.yaml
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: &appname <app-name>
namespace: &namespace <namespace>
spec:
targetNamespace: *namespace
commonMetadata:
labels:
app.kubernetes.io/name: *appname
components:
- ../../../../components/volsync/local
- ../../../../components/postgres-db # only if app needs a database
path: ./kubernetes/apps/<namespace>/<app-name>/app
prune: true
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
interval: 30m
retryInterval: 1m
timeout: 3m
postBuild:
substitute:
APP: *appname
Only include dependsOn if user specified dependencies. The list should include:
external-secrets-stores (always, if the app has secrets or uses postgres-db)cloudnative-pg-cluster (only if app uses postgres-db component)volsync, rook-ceph-cluster, etc.)Example:
dependsOn:
- name: external-secrets-stores
namespace: external-secrets
- name: cloudnative-pg-cluster
namespace: databases
For the postBuild.substitute block, add database variables when applicable:
postBuild:
substitute:
APP: *appname
DB_NAME: <db-name> # only if app needs a database
DB_USER: <db-user> # only if app needs a database
DB_BITWARDEN_ID: <uuid> # only if app needs a database
kubernetes/apps/<namespace>/<app-name>/app/kustomization.yaml
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./helmrelease.yaml
Include ./externalsecret.yaml only if secrets are needed.
If the app needs a configMapGenerator (e.g., for config files), add it:
configMapGenerator:
- name: <app-name>-configmap
files:
- ./resources/config.yaml
generatorOptions:
disableNameSuffixHash: true
Note: This repo uses a global
app-templateOCIRepository in theflux-systemnamespace. Do NOT create a localocirepository.yaml. The HelmRelease'schartRefshould referencenamespace: flux-system.
kubernetes/apps/<namespace>/<app-name>/app/helmrelease.yaml
---
# yaml-language-server: $schema=https://raw.githubusercontent.com/bjw-s-labs/helm-charts/main/charts/other/app-template/schemas/helmrelease-helm-v2.schema.json
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: &app <app-name>
spec:
interval: 1h
chartRef:
kind: OCIRepository
name: app-template
namespace: flux-system
install:
remediation:
retries: -1
upgrade:
cleanupOnFail: true
remediation:
retries: 3
values:
controllers:
<app-name>:
pod:
securityContext:
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
containers:
app:
image:
repository: <image-repo>
tag: <image-tag>
probes:
liveness:
enabled: true
spec:
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 5
readiness:
enabled: true
spec:
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
startup:
enabled: true
spec:
failureThreshold: 30
periodSeconds: 10
resources:
requests:
cpu: 10m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
service:
app:
ports:
http:
port: <port>
If the app needs a database: The app needs env vars for the DB connection. Add them under
controllers.<app-name>.containers.app.env(or viaenvFromreferencing the app's secret). The DB host is alwayspostgres-rw.databases.svc.cluster.local, port5432. The DB credentials (user, password) come from the same Bitwarden item as the app's other secrets. Fetch them in theexternalsecret.yamlunderpg_userandpg_passwordproperties, and map them to the app's expected env var names.
kubernetes/apps/<namespace>/<app-name>/app/externalsecret.yaml (only if secrets needed)
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: <app-name>-secret
spec:
target:
deletionPolicy: Delete
template:
type: Opaque
data:
data:
- secretKey: SECRET_KEY
sourceRef:
storeRef:
name: bitwarden-fields
kind: ClusterSecretStore
remoteRef:
key: <bitwarden-uuid>
property: secret_key
Update the data section with actual secret keys based on the app's needs. The name must follow the <app-name>-secret convention. The remoteRef.key must be a valid Bitwarden item UUID (not the app name).
If the app needs a database: The same Bitwarden item typically contains
pg_userandpg_passwordfields. Add them to the ExternalSecret template, mapped to the app's DB credential env vars. Example:data: APP_DB_USER: "{{ .pg_user }}" APP_DB_PASSWORD: "{{ .pg_password }}"Then reference these in the HelmRelease via
envFrom:envFrom: - secretRef: name: <app-name>-secretThe DB host and port (
postgres-rw.databases.svc.cluster.local:5432) and database name are typically static and set directly in the HelmRelease env, not in the secret.
Read kubernetes/apps/<namespace>/kustomization.yaml and add the new app's ks.yaml to the resources array:
resources:
- ./namespace.yaml
- ./<app-name>/ks.yaml
# ... existing apps
Run find kubernetes/apps/<namespace>/<app-name> -type f to confirm all files were created correctly.
app-template OCIRepository lives in flux-system namespace — never create a local ocirepository.yaml&app, &appname, &namespace) in ks.yaml and helmrelease.yaml like existing apps<app-name>-secret (not just <app-name>)remoteRef.key must be a valid Bitwarden item UUIDvolsync/local component, interval: 30m, retryInterval: 1m, timeout: 3mdatabases namespace. The app must not include init-db containers or any other database provisioning logic.DB_BITWARDEN_ID should reference a Bitwarden item that has pg_user and pg_password custom fields with the dedicated role credentials for the apppg_monitor role to the dedicated DB roleexternalsecret.yamlpostgres-rw.databases.svc.cluster.local, port 5432<app>_main for the primary database, <app> for the role name