# Agent Instructions This file is the entry point for AI agents working in this repository. It mirrors the HomeLab skill at [SKILL.md](SKILL.md). Read both before acting. ## TL;DR - This repo manages a bare-metal **OKD** cluster (3 control-plane + workers + GPU node) and an edge **MicroShift** node (Raspberry Pi). - Applications are deployed via **ArgoCD GitOps** from [kubernetes/](kubernetes/). - Bare-metal and VM provisioning is via **Ansible** ([ansible/](ansible/)) and the **OKD agent-based installer** ([okd/](okd/)). - The wrapper script [main.bash](main.bash) is the primary developer entry point for Ansible, VM provisioning, and OKD cluster management. - Kubernetes manifest, Helm, and Kustomize tasks must follow the [Kubernetes (KubeShark) skill](.agents/skills/kubernetes-skill/SKILL.md). ## Repository Map | Path | Purpose | | ------------------------------------------------------------------ | ----------------------------------------------------------------------- | | [ansible/](ansible/) | Playbooks for servers, MicroShift, desktops, and VS Code hosts | | [containers/](containers/) | Custom container images (`toolbox`, `gpu-toolbox`, `udi`, `apache-php`) | | [kubernetes/](kubernetes/) | All cluster apps; GitOps source for ArgoCD | | [kubernetes/argocd/applications/](kubernetes/argocd/applications/) | ArgoCD `Application` registrations (one YAML per app) | | [machineConfigs/](machineConfigs/) | Ignition / preseed configs for OS provisioning | | [okd/](okd/) | OKD agent-based installer configs (`agent-config`, `install-config`) | | [tekton/](tekton/) | Tekton pipelines and tasks (base + overlays) | | [terraform/](terraform/) | GCP + KVM Terraform modules; integrates with Vault | | [vms/](vms/) | KubeVirt VM definitions | | [scripts/](scripts/) | One-off helper scripts | | [notes/](notes/) | Scratchpad and manual procedures — **not** authoritative | | [sandbox/](sandbox/) | Throwaway experiments | | [main.bash](main.bash) | Wrapper for Ansible, cluster state management, and OKD provisioning | ## Cluster Authentication Always set `KUBECONFIG` explicitly before any `kubectl`, `oc`, `helm`, or `kustomize` invocation: - OKD: `export KUBECONFIG=$HOME/.kube/okd` - MicroShift: `export KUBECONFIG=$HOME/.kube/microshift` Default to `kubectl`; use `oc` only for `oc adm` and `oc debug node/`. Both kubeconfigs grant **cluster-admin**. Default to read-only commands (`get`, `describe`, `--dry-run=client`, `kustomize build`) when exploring. Confirm with the user before any `apply`, `delete`, `patch`, `scale`, `drain`, or `cordon`. ### Debug and ad-hoc pods Every pod you create by hand (`kubectl run`, `kubectl debug`, throwaway `kubectl apply`) must satisfy the OpenShift `restricted-v2` SCC and the `restricted` PodSecurity profile. Most namespaces audit or enforce `restricted`, so a non-compliant pod triggers the "workload did not match the PodSecurity restricted profile" alert or is rejected. Required settings: - Pod level: `runAsNonRoot: true` and `seccompProfile.type: RuntimeDefault`. - Every container (including init containers): `allowPrivilegeEscalation: false` and `capabilities.drop: ["ALL"]`. - Do **not** set `runAsUser`, `runAsGroup`, `fsGroup`, or `seLinuxOptions`. `restricted-v2` assigns them from the namespace UID range, and values outside that range are rejected. - No `privileged`, `hostNetwork`, `hostPID`, `hostIPC`, `hostPath`, host ports, or added capabilities. Use an image that runs as an arbitrary non-root UID (for example the `toolbox` image from [containers/](containers/)), not one that needs root. - Name the pod `debug-`, use `--rm` and `--restart=Never`, and delete it when done. Template (the container name must equal the pod name so `--overrides` merges into the generated container; set the command inside the override because `--overrides` drops a trailing `-- sh`): ```bash kubectl run debug- -n --rm -it --restart=Never \ --image= \ --overrides='{"spec":{"securityContext":{"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}},"containers":[{"name":"debug-","image":"","command":["sh"],"stdin":true,"tty":true,"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]}}}]}}' ``` After creating a pod, check `kubectl get pod -o jsonpath='{.metadata.annotations.openshift\.io/scc}'` returns `restricted-v2`. If it is anything else, delete the pod and fix the spec. Only use `oc debug node/` when node access is genuinely required, and confirm with the user first. ## Conventions ### Kubernetes manifests - Layout per app: `kubernetes//{base,overlays/}` with a `kustomization.yaml` at each level. Some apps add `components/` for reusable patches. - Active overlays: `okd`, `okd-sandbox`, `okd-unas`, `sandbox`, `sno`, `microshift`, `microshift-unas`, `old`, `operator` (all OpenShift/OKD-based) and `k3s` (legacy, the only non-OpenShift target). Pick the one matching the target cluster. - Register new apps in [kubernetes/argocd/applications/](kubernetes/argocd/applications/) as `.yaml` and include them in the local `kustomization.yaml`. - After editing any `kustomization.yaml`, run `k8s-gitops-ci kustomize-fix -dir kubernetes/` (or `-all`) to normalize field ordering. - Secrets: prefer **External Secrets Operator** (`ExternalSecret` pulling from Vault via the cluster `ClusterSecretStore` — see [kubernetes/external-secrets-operator/](kubernetes/external-secrets-operator/)). Fall back to **argocd-vault-plugin** placeholders (``) only when ESO cannot express the requirement. Never commit plaintext secrets. Overlay validation still requires `VAULT_ADDR` and `VAULT_TOKEN` for AVP placeholders that remain. - See [CI Validation (k8s-gitops-ci)](#ci-validation-k8s-gitops-ci) for local iteration, scoped validation, and full-repo scans. ### Manifest authoring rules When writing or reviewing Kubernetes resources, follow the [Kubernetes (KubeShark) skill](.agents/skills/kubernetes-skill/SKILL.md). Its failure-mode workflow and Conditional Reference Retrieval take precedence over generic Kubernetes guidance. OKD-specific patterns (SecurityContextConstraints, `Route`, arbitrary UID images) apply here — load the `openshift-patterns` CRR reference when touching them. ### Ansible - Inventory: [ansible/inventory](ansible/inventory). Config: [ansible/server.cfg](ansible/server.cfg). Galaxy deps: [ansible/requirements.yml](ansible/requirements.yml). - Entry points: `servers.yaml`, `microshift.yaml`, `desktop.yaml`, `laptop.yaml`, `vscode-server.yaml`. - Standard invocation: `ansible-playbook -i ansible/inventory --ask-become-pass --ask-pass ansible/.yaml` (or `./main.bash ansible` for the default servers run). - `ansible-lint` runs in pre-commit; keep playbooks passing. ### CI Validation (k8s-gitops-ci) - Real CI runs via `.tekton/gitops-ci.yaml`'s `gitops-ci` Task, invoking `k8s-gitops-ci pipeline --dirs "kubernetes/,tekton/,.tekton/,okd/" --assume-openshift` from the sibling `../k8s-gitops-ci` repo (see `tekton/base/gitops-ci.yaml`). - **Local iteration** defaults to the working-tree git diff — only changed files are validated. Use `--all` for a full repo scan, or `--dirs` to scope to specific paths: `k8s-gitops-ci test --dirs kubernetes/,tekton/,.tekton/,okd/ --assume-openshift --disable-checks avp` - **Always pass `--assume-openshift`** when validating locally — it matches real CI and tells the sync-options check that OpenShift/OKD built-in API groups are guaranteed present at first sync, so those resources do **not** need the `SkipDryRunOnMissingResource=true` annotation. Without it you get spurious sync-options findings for cluster-native CRDs. (This is why `--assume-openshift` is required — it makes the check skip third-party CRDs that only exist on clusters where those operators are installed.) - For local iteration also pass `--disable-checks avp` unless you have `VAULT_ADDR`/`VAULT_TOKEN` exported — otherwise AVP placeholder resolution fails the overlay build with unrelated "could not replace all placeholders" noise. - **Scoped validation:** `k8s-gitops-ci test --app kubernetes/ --cluster --assume-openshift --disable-checks avp` (repeatable flags; `--app` alone validates every overlay of that app, `--cluster` alone validates every app targeting that cluster). - Before pushing, confirm the full CI scope still passes (mirrors real CI; defaults to reading local `test.sh` automatically — no PR needed). - Avoid `test --all` for full-repo scans that include ansible/, machineConfigs/, notes/, sandbox/ — these are outside CI's actual `--dirs` scope and produce irrelevant noise. - After changing `../k8s-gitops-ci` source, rebuild before testing: `cd ../k8s-gitops-ci && task build`. - Some fixes require changes in **both** repos (e.g., adjusting a check's behavior, adding a new exemption mechanism) — check `../k8s-gitops-ci`'s own `AGENTS.md`/`docs/` when validation behavior itself needs to change. - Exemptions: `test.sh` with `export EXEMPTIONS=(...)` at an app root or any directory with non-Kubernetes YAML — see `okd/test.sh` for a working example and the [exemptions skill](https://github.com/ArthurVardevanyan/k8s-gitops-ci/blob/main/.agents/skills/exemptions/SKILL.md) for the full reference. ### Shell, YAML, Markdown - pre-commit hooks are authoritative ([.pre-commit-config.yaml](.pre-commit-config.yaml)): `gitleaks`, `shellcheck`, `yamllint`, `markdownlint`, `prettier`, `ansible-lint`, `checkov_diff`, and conventional-commit messages. - Shell scripts use `set -o errexit -o nounset -o pipefail` and `shopt -s failglob` (see [main.bash](main.bash) for the template). - YAML indent is 2 spaces; `---` document marker required at top of files (enforced by `kustomize-fix`). - Commit messages must follow Conventional Commits (`feat:`, `fix:`, `chore:`, `build(deps):`, `docs:`, ...). - **All markdown files must use spaces** (not tabs) for indentation. - **Markdown files with multiple headings must include a Table of Contents** under `## Table of Contents` immediately after the file title and before any other content. This is generated and maintained automatically by the VS Code extension [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) (`yzhang.markdown-all-in-one`). The initial structure looks like: ```markdown ## Table of Contents - [File Title](#file-title) - [Table of Contents](#table-of-contents) - [Section One](#section-one) - [Section Two](#section-two) ``` ### Renovate Pinned versions in shell scripts, pre-commit hooks, manifests, and Helm/Kustomize inputs are kept up to date by Renovate. Preserve the `# renovate: datasource=...` comments above pinned versions. ## Common Tasks - Add a Kubernetes app — see [README.md](README.md#deploying-a-new-app). - Run the central wrapper — `./main.bash ` (`ansible`, `stateful_workload_stop`, ...). - Validate manifests — see [CI Validation](#ci-validation-k8s-gitops-ci). - Drain a node — `oc adm drain --delete-emptydir-data --ignore-daemonsets --force` (confirm with the user first). - Suspend stateful workloads for maintenance — `./main.bash stateful_workload_stop`. ### PR Submission - All PRs for this repository must be submitted to GitHub: `github.com/ArthurVardevanyan/HomeLab`. - Use `gh pr create --repo ArthurVardevanyan/HomeLab` (NOT `gt pr create`). - The default git remote for development/testing is the `gitea` remote, but all final PRs go to GitHub. ## Before Committing - Validate changed files — see [CI Validation](#ci-validation-k8s-gitops-ci). - For individual file linting, run k8s-gitops-ci linters directly: `k8s-gitops-ci markdownlint`, `k8s-gitops-ci prettier`, `k8s-gitops-ci shellcheck`, etc. ## Related Skills - [Kubernetes (KubeShark)](.agents/skills/kubernetes-skill/SKILL.md) — production-grade Kubernetes manifest, Helm, and Kustomize guidance with a failure-mode workflow and Conditional Reference Retrieval. Activate for any Kubernetes resource design or review. - [HomeLab SKILL](SKILL.md) — canonical version of this document, also surfaced under [.agents/skills/homelab/SKILL.md](.agents/skills/homelab/SKILL.md). ## Out of Scope - [notes/](notes/) and [sandbox/](sandbox/) are scratch areas. Read for context if helpful, but never treat their YAML as the source of truth and do not deploy from them. - `.git/`, `img/`, `CHANGELOG.md` (auto-maintained) — do not edit unless explicitly requested.