8.6 KiB
AGENTS.md - Guide for Coding Agents
This file provides essential information for AI coding agents working with this Kubernetes cluster project.
Project Overview
This repository contains Kubernetes manifests for a K3s cluster running self-hosted services on the rogi.casa domain. The cluster is managed via GitOps using ArgoCD - all changes to the cluster are deployed automatically from this Git repository.
⚠️ CRITICAL: Permission Model
You DO NOT have permission to push changes to this repository. Before applying any changes to the cluster:
- Make the necessary code changes to the manifests
- Clearly present the changes to the user
- Ask the user to review and push the changes
- Wait for confirmation that changes have been pushed
- Only then will ArgoCD automatically deploy the changes to the cluster
Architecture & GitOps Workflow
ArgoCD App-of-Apps Pattern
This project uses ArgoCD's "app-of-apps" pattern:
argocd-bootstrap.yaml (root Application)
↓
argocd/apps/ (directory containing all Application manifests)
↓
Individual Applications (one per service directory)
↓
Kubernetes manifests in each service directory (e.g., pihole/, homeassistant/)
Deployment Flow
- You make changes to Kubernetes manifests in the repository
- User reviews and pushes changes to the
mainbranch - ArgoCD detects changes (automatically or on sync)
- ArgoCD applies changes to the cluster with
prune: trueandselfHeal: true - Cluster state converges to match the Git state
Key Files
argocd-bootstrap.yaml: The root Application that bootstraps ArgoCD. Points toargocd/apps/directory. This is the only file that needs manualkubectl applyduring initial setup.argocd/apps/project.yaml: ArgoCD AppProject defining permissions for all applicationsargocd/apps/*.yaml: Individual ArgoCD Application manifests (one per service)argocd/gen-apps.sh: Script to regenerate all ArgoCD manifests from theAPPSarray
Repository Structure
k3s-cluster/
├── argocd-bootstrap.yaml # Root ArgoCD Application (app-of-apps)
├── argocd/
│ ├── apps/ # Individual ArgoCD Application manifests
│ │ ├── project.yaml # AppProject definition
│ │ ├── pihole.yaml # Application for pihole/
│ │ ├── homeassistant.yaml # Application for homeassistant/
│ │ └── ... # One per service
│ ├── gen-apps.sh # Generates argocd/apps/* manifests
│ └── ingress.yaml # ArgoCD's own ingress
├── <service-name>/ # Each service has its own directory
│ ├── namespace.yaml # (Optional) Namespace definition
│ ├── deployment.yaml # Main deployment/statefulset
│ ├── service.yaml # Service definition
│ ├── ingress.yaml # Ingress configuration
│ ├── configmap.yaml # (Optional) ConfigMaps
│ ├── pvc.yaml # (Optional) PersistentVolumeClaims
│ └── secret.yaml # (Optional) Secrets (rarely committed)
├── cert-manager/ # cert-manager installation manifests
├── nas/ # External NAS service configuration
├── monitoring/ # Prometheus + Grafana stack
└── README.md # Comprehensive project documentation
Current Services
The cluster runs these services (each in its own directory):
- argocd - GitOps continuous delivery platform
- cert-manager - SSL certificate management (Let's Encrypt)
- fava - Beancount accounting web interface
- gitea - Self-hosted Git server
- glance - Personal dashboard
- gym-tracker - Workout tracking application
- homeassistant - Home automation
- jellyfin - Media server
- litellm - LLM proxy
- minecraft-server - Minecraft server
- monitoring - Prometheus + Grafana
- myorg-assistant - Organization assistant
- n8n - Workflow automation
- nas - External NAS proxy
- openwebui - Web UI for LLMs
- phoenix - AI observability platform
- pihole - Network-wide ad blocking
- platform-engineer - Platform engineering tools
- qbittorrent - Torrent client
- searxng - Meta search engine
- vaultwarden - Password manager (Bitwarden compatible)
How to Make Changes
Adding a New Service
- Create a new directory:
mkdir new-service - Create Kubernetes manifests in
new-service/:namespace.yaml(if dedicated namespace needed)deployment.yamlorstatefulset.yamlservice.yamlingress.yaml- Any ConfigMaps, Secrets, PVCs needed
- Add the service to
argocd/gen-apps.sh:- Add a line to the
APPSarray:"new-service|namespace|new-service|true|true" - Format:
name|namespace|path|recurse|validate
- Add a line to the
- Run
./argocd/gen-apps.shto regenerate ArgoCD manifests - Present changes to user for review and push
Modifying an Existing Service
- Edit the relevant manifest(s) in the service directory
- If changing ArgoCD configuration, also update
argocd/gen-apps.shand regenerate - Present changes to user for review and push
Removing a Service
- Remove the service directory:
rm -rf service-name/ - Remove from
APPSarray inargocd/gen-apps.sh - Run
./argocd/gen-apps.shto regenerate - Present changes to user for review and push
- ArgoCD will automatically prune the resources from the cluster
Common Patterns
Ingress Configuration
Each service has its own ingress.yaml with:
ingressClassName: traefik(K3s default)- TLS configured with
cert-manager.io/cluster-issuer: letsencrypt-prod - Host-based routing (e.g.,
pihole.rogi.casa)
Example:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: pihole
namespace: pihole
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: traefik
tls:
- hosts:
- pihole.rogi.casa
secretName: pihole-tls
rules:
- host: pihole.rogi.casa
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: pihole-web
port:
number: 80
Resource Management
- Each service typically has its own namespace
- Use ResourceRequests and Limits for all containers
- PVCs for persistent data
- ConfigMaps for configuration files
Important Notes
What You CAN Do
- Read and understand all manifests
- Create new manifest files
- Modify existing manifest files
- Run
./argocd/gen-apps.shto regenerate ArgoCD manifests - Explain how the cluster works
- Troubleshoot issues by reading manifests
What You CANNOT Do
- Push changes to the Git repository (no push permissions)
- Directly apply manifests with
kubectl apply(unless explicitly asked) - Access the Kubernetes cluster directly (unless explicitly configured)
- Create secrets that should remain private (those are managed manually)
Secrets Management
Secrets are generally not committed to the repository. They must be created manually in the cluster:
kubectl create secret docker-registry gitea-registry \
--docker-server=gitea.rogi.casa \
--docker-username=<user> \
--docker-password=<token> \
-n <namespace>
Workflow Summary
When asked to make changes:
- Understand the current state by reading relevant files
- Modify the manifests (create/edit files)
- Regenerate ArgoCD manifests if needed (
./argocd/gen-apps.sh) - Present the changes clearly to the user:
I've made the following changes: - Modified pihole/deployment.yaml to update image version - Regenerated argocd/apps/pihole.yaml Please review and push these changes to deploy them. - Wait for user confirmation that changes are pushed
- Verify (if possible) that ArgoCD has synced the changes
Useful Commands (for reference)
# Regenerate ArgoCD manifests after modifying gen-apps.sh
./argocd/gen-apps.sh
# Check ArgoCD applications status (requires kubectl access)
kubectl get applications -n argocd
# View logs of a pod (requires kubectl access)
kubectl logs -n <namespace> <pod-name>
# Check ingress status (requires kubectl access)
kubectl get ingress -n <namespace>
Questions?
If you're unsure about anything:
- Read the comprehensive
README.mdin the repository root - Check existing service directories for examples
- Ask the user for clarification before making changes
- Remember: never push without explicit user review and approval