diff --git a/argocd/applications/woodpecker.yaml b/argocd/applications/woodpecker.yaml
index d55e20a..54a1ac5 100644
--- a/argocd/applications/woodpecker.yaml
+++ b/argocd/applications/woodpecker.yaml
@@ -6,10 +6,13 @@ metadata:
   namespace: argocd
 spec:
   project: k-space.ee
-  source:
-    repoURL: 'git@git.k-space.ee:k-space/kube.git'
-    path: woodpecker
-    targetRevision: HEAD
+  sources:
+    - repoURL: git@git.k-space.ee:k-space/kube.git
+      targetRevision: HEAD
+      path: woodpecker
+    - repoURL: 'git@git.k-space.ee:secretspace/kube.git'
+      targetRevision: HEAD
+      path: woodpecker
   destination:
     server: 'https://kubernetes.default.svc'
     namespace: woodpecker
diff --git a/woodpecker/.gitignore b/woodpecker/.gitignore
new file mode 100644
index 0000000..2faa846
--- /dev/null
+++ b/woodpecker/.gitignore
@@ -0,0 +1,2 @@
+charts/
+*.env
diff --git a/woodpecker/README.md b/woodpecker/README.md
index 0367159..0627425 100644
--- a/woodpecker/README.md
+++ b/woodpecker/README.md
@@ -1,17 +1,26 @@
-# Woodpecker CI
-Woodpecker CI obsoletes Drone CI which has confusing licensing conditions.
+First kustomize helm chart thing.
 
-Deployment steps:
+As of commit time, woodpecker chart does not support agents in separate namespace.
 
+Render it locally:
+
+```sh
+kustomize build . --enable-helm
 ```
-kubectl create namespace woodpecker
-kubectl create namespace woodpecker-execution
-kubectl create secret generic -n woodpecker woodpecker-secret \
-  --from-literal=WOODPECKER_AGENT_SECRET=$(openssl rand -hex 32) \
-  --from-literal=WOODPECKER_GITEA_CLIENT=... \
-  --from-literal=WOODPECKER_GITEA_SECRET=...
-kubectl create secret generic -n woodpecker-execution woodpecker-secret \
-  --from-literal=WOODPECKER_AGENT_SECRET=$(kubectl get secret -n woodpecker woodpecker-secret -o jsonpath="{.data.WOODPECKER_AGENT_SECRET}" | base64 -d)
-kubectl apply -n woodpecker -f woodpecker-server.yml
-kubectl apply -n woodpecker-execution -f woodpecker-agent.yml
+
+If upstream chart does not have `extraSecretNamesForEnvFrom`, patch instead:
+
+```yaml
+patches:
+- target:
+  version: v1
+  kind: StatefulSet
+  name: release-name-server
+  # or: labelSelector: app.kubernetes.io/name=server
+  patch: |-
+   - op: add
+     path: /spec/template/spec/containers/0/envFrom/-
+     value:
+       secretRef:
+         name: woodpecker-gitea-oauth2
 ```
diff --git a/woodpecker/kustomization.yaml b/woodpecker/kustomization.yaml
new file mode 100644
index 0000000..7d8b122
--- /dev/null
+++ b/woodpecker/kustomization.yaml
@@ -0,0 +1,61 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+namespace: woodpecker
+
+# spec: https://kubectl.docs.kubernetes.io/references/kustomize/builtins/#_helmchartinflationgenerator_
+helmCharts:
+- includeCRDs: true
+  name: &name woodpecker
+  releaseName: *name
+  repo: oci://ghcr.io/woodpecker-ci/helm
+  valuesInline:
+    agent:
+      image:
+        registry: mirror.gcr.io
+      env:
+        WOODPECKER_BACKEND_K8S_STORAGE_CLASS: woodpecker
+        WOODPECKER_BACKEND_K8S_VOLUME_SIZE: 100Mi
+      persistence:
+        enabled: false
+    server:
+      ingress:
+        enabled: true
+        ingressClassName: treafik
+        annotations:
+          external-dns.alpha.kubernetes.io/target: traefik.k-space.ee
+          traefik.ingress.kubernetes.io/router.entrypoints: websecure
+        hosts:
+        - host: woodpecker.k-space.ee
+          paths:
+          - backend:
+              serviceName: woodpecker-server # *name-server (from releaseName)
+            path: "/"
+        tls:
+        - hosts: ["*.k-space.ee"]
+
+      env:
+        WOODPECKER_ADMIN: eaas,rasmus
+        WOODPECKER_DATABASE_DRIVER: mysql
+        WOODPECKER_GITEA: true
+        WOODPECKER_GITEA_URL: https://git.k-space.ee
+        WOODPECKER_HOST: https://woodpecker.k-space.ee
+        WOODPECKER_OPEN: true
+      extraSecretNamesForEnvFrom:
+        - woodpecker-gitea-oauth2
+        - woodpecker-db
+      image:
+        registry: mirror.gcr.io
+      # persistentVolume:
+      #   enabled: false
+  version: 3.0.7
+
+secretGenerator:
+  - name: woodpecker-gitea-oauth2
+    envs:
+      - woodpecker-gitea.env
+  - name: woodpecker-db
+    literals:
+      - WOODPECKER_DATABASE_DRIVER=mysql
+    envs:
+      - woodpecker-db.env
diff --git a/woodpecker/woodpecker-agent.yml b/woodpecker/woodpecker-agent.yml
deleted file mode 100644
index 700b723..0000000
--- a/woodpecker/woodpecker-agent.yml
+++ /dev/null
@@ -1,99 +0,0 @@
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: woodpecker-agent
-  namespace: woodpecker-execution
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  name: woodpecker-agent
-  namespace: woodpecker-execution
-rules:
-  - apiGroups:
-      - ''
-    resources:
-      - persistentvolumeclaims
-    verbs:
-      - create
-      - delete
-  - apiGroups:
-      - ''
-    resources:
-      - services
-    verbs:
-      - create
-      - delete
-  - apiGroups:
-      - ''
-    resources:
-      - pods
-      - pods/log
-    verbs:
-      - watch
-      - create
-      - delete
-      - get
-      - list
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  name: woodpecker-agent
-  namespace: woodpecker-execution
-subjects:
-  - kind: ServiceAccount
-    name: woodpecker-agent
-    namespace: woodpecker-execution
-roleRef:
-  kind: Role
-  name: woodpecker-agent
-  apiGroup: rbac.authorization.k8s.io
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: woodpecker-agent
-  namespace: woodpecker-execution
-spec:
-  replicas: 2
-  selector:
-    matchLabels:
-      app: woodpecker-agent
-  template:
-    metadata:
-      labels:
-        app: woodpecker-agent
-    spec:
-      serviceAccountName: woodpecker-agent
-      securityContext:
-        runAsNonRoot: true
-        runAsUser: 1000
-      containers:
-        - name: agent
-          securityContext:
-            readOnlyRootFilesystem: false
-          image: woodpeckerci/woodpecker-agent:v2.7.0
-          ports:
-            - name: http
-              containerPort: 3000
-              protocol: TCP
-          env:
-            - name: WOODPECKER_BACKEND
-              value: kubernetes
-            - name: WOODPECKER_BACKEND_K8S_NAMESPACE
-              value: woodpecker-execution
-            - name: WOODPECKER_BACKEND_K8S_STORAGE_CLASS
-              value: woodpecker
-            - name: WOODPECKER_BACKEND_K8S_STORAGE_RWX
-              value: "true"
-            - name: WOODPECKER_BACKEND_K8S_VOLUME_SIZE
-              value: 100Mi
-            - name: WOODPECKER_SERVER
-              value: "woodpecker-grpc.woodpecker.svc.cluster.local:9000"
-            - name: WOODPECKER_AGENT_SECRET
-              valueFrom:
-                secretKeyRef:
-                  name: woodpecker-secret
-                  key: WOODPECKER_AGENT_SECRET
diff --git a/woodpecker/woodpecker-db.env.example b/woodpecker/woodpecker-db.env.example
new file mode 100644
index 0000000..64fe99c
--- /dev/null
+++ b/woodpecker/woodpecker-db.env.example
@@ -0,0 +1,2 @@
+# Don't be a dummy by commiting renders with secrets
+WOODPECKER_DATABASE_DATASOURCE=kspace_woodpecker:<SECRET>@tcp(172.20.36.1:3306)/kspace_woodpecker?parseTime=true
diff --git a/woodpecker/woodpecker-gitea.env.example b/woodpecker/woodpecker-gitea.env.example
new file mode 100644
index 0000000..360fc70
--- /dev/null
+++ b/woodpecker/woodpecker-gitea.env.example
@@ -0,0 +1,5 @@
+# Don't be a dummy by commiting renders with secrets
+#
+# https://woodpecker-ci.org/docs/administration/configuration/forges/gitea#registration
+WOODPECKER_GITEA_CLIENT=
+WOODPECKER_GITEA_SECRET=
diff --git a/woodpecker/woodpecker-server.yml b/woodpecker/woodpecker-server.yml
deleted file mode 100644
index 205b206..0000000
--- a/woodpecker/woodpecker-server.yml
+++ /dev/null
@@ -1,118 +0,0 @@
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: woodpecker
-spec:
-  type: ClusterIP
-  ports:
-    - port: 80
-      targetPort: http
-      protocol: TCP
-      name: http
-  selector:
-    app: woodpecker
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: woodpecker-grpc
-spec:
-  type: ClusterIP
-  ports:
-    - port: 9000
-      targetPort: grpc
-      protocol: TCP
-      name: grpc
-  selector:
-    app: woodpecker
----
-apiVersion: apps/v1
-kind: StatefulSet
-metadata:
-  name: woodpecker
-spec:
-  serviceName: woodpecker
-  replicas: 1
-  selector:
-    matchLabels:
-      app: woodpecker
-  template:
-    metadata:
-      labels:
-        app: woodpecker
-    spec:
-      automountServiceAccountToken: false
-      securityContext:
-        {}
-      containers:
-        - name: server
-          image: woodpeckerci/woodpecker-server:v2.7.0
-          ports:
-            - name: http
-              containerPort: 8000
-            - name: grpc
-              containerPort: 9000
-          env:
-            - name: WOODPECKER_ADMIN
-              value: eaas
-            - name: WOODPECKER_OPEN
-              value: "true"
-            - name: WOODPECKER_HOST
-              value: "https://woodpecker.k-space.ee"
-            - name: WOODPECKER_GITEA
-              value: "true"
-            - name: WOODPECKER_GITEA_URL
-              value: "https://git.k-space.ee/"
-            - name: WOODPECKER_GITEA_CLIENT
-              valueFrom:
-                secretKeyRef:
-                  name: woodpecker-secret
-                  key: WOODPECKER_GITEA_CLIENT
-            - name: WOODPECKER_GITEA_SECRET
-              valueFrom:
-                secretKeyRef:
-                  name: woodpecker-secret
-                  key: WOODPECKER_GITEA_SECRET
-            - name: "WOODPECKER_AGENT_SECRET"
-              valueFrom:
-                secretKeyRef:
-                  name: woodpecker-secret
-                  key: WOODPECKER_AGENT_SECRET
-            - name: "WOODPECKER_DATABASE_DRIVER"
-              value: "mysql"
-          envFrom:
-            - secretRef:
-                name: woodpecker-mysql
-          volumeMounts:
-            - name: woodpecker-data
-              mountPath: /var/lib/woodpecker
-      volumes:
-        - name: woodpecker-data
-          persistentVolumeClaim:
-            claimName: woodpecker-data-woodpecker-0
----
-apiVersion: networking.k8s.io/v1
-kind: Ingress
-metadata:
-  name: woodpecker
-  annotations:
-    external-dns.alpha.kubernetes.io/target: traefik.k-space.ee
-    kubernetes.io/ingress.class: traefik
-    traefik.ingress.kubernetes.io/router.entrypoints: websecure
-    traefik.ingress.kubernetes.io/router.tls: "true"
-spec:
-  tls:
-    - hosts:
-        - "*.k-space.ee"
-  rules:
-    - host: "woodpecker.k-space.ee"
-      http:
-        paths:
-          - pathType: Prefix
-            path: /
-            backend:
-              service:
-                name: woodpecker
-                port:
-                  number: 80