# CLAUDE.md Home-lab research project: cluster-autoscaler + Cluster API on Proxmox VE (phase 1), then a KVM/libvirt provider (phase 2) and Kamaji hosted control planes / "poor man's KaaS" (phase 3). Start with README.md; details live in docs/. ## Owner context Experienced SRE. Be concise and technical; skip basics (k8s internals, Go, Linux, distributed systems). ## Lab facts (don't re-derive) - PVE node `pv1-1`, API `https://192.168.0.8:8006`, token `capmox@pve!capi` (privsep 0). - VM network: `vmbr0` is VLAN-aware, VMs in **VLAN 4** → always `bridge=vmbr0` + tag/`vlan: 4`, never `vmbr0.4@vmbr0` (that is an `ip link` name, not a bridge). - Storage: `local` (iso, dir) and `local-lvm` (LVM-thin) → disks are **raw**, never qcow2. - Build host for image-builder: 192.168.4.181 (VLAN 4 must reach it on 8000–9000 during builds). - Node template: `ubuntu-2404-kube-v1.35.9` (image-builder v0.1.55). Login only via cloud-init. - Management cluster: VM 201 `lab-mgmt`, 192.168.4.21 (`ssh ubuntu@`), built by the idempotent `ansible/mgmt.yml` (re-run must be `changed=0`); admin kubeconfig `~/.kube/lab-mgmt.kubeconfig`. - Required PVE ACLs: PVEVMAdmin + PVEAuditor on `/`, PVEDatastoreAdmin on `/storage`, PVESDNUser on `/sdn/zones/localnetwork`. ## Version rules - `docs/versions.md` is the source of truth. Any version change updates it in the same change. - Before proposing any deployment or upgrade, verify versions are current (use the `k8s-version-check` skill if available). Go module proxy / git ls-remote / Helm index.yaml work even when the GitHub API is unavailable. - CAPI core is pinned to **v1.12.x** because CAPMOX v0.9 is only tested on CAPI 1.11/1.12. This caps workload Kubernetes at 1.35 and cluster-autoscaler at 1.35.x. Don't bump CAPI unless the CAPMOX compatibility table allows it. - Always pin versions explicitly (management cluster: `ansible/group_vars/all.yml`; `helm install --version`); never rely on "latest". - CAPI providers are managed by cluster-api-operator (Provider CRs from `ansible/mgmt.yml`). Never run `clusterctl init/upgrade/move/delete` against the management cluster; `clusterctl` is only for `generate cluster` (always with `--infrastructure proxmox:v0.9.1`), `describe`, `get kubeconfig`. - Check a provider's `metadata.yaml` contract and CAPI version (go.mod) before adding it to the management cluster — all providers share one CAPI core (known skew: Kamaji CP provider v0.21.0 is on CAPI 1.13). ## Facts about providers: verify in source READMEs lag. For "does provider X support Y" read the API types and templates of the exact tagged release (Go proxy zip: `https://proxy.golang.org//@v/.zip`). Delegate to the `upstream-researcher` agent for anything non-trivial. ## Safety - Never commit secrets: PVE token secret, kubeconfigs, `clusterctl.yaml` (see .gitignore). - Cluster inspection is read-only via the `cluster-inspector` agent and read-only kubeconfigs (`.claude/cluster-inspector/`, see its README). Mutations (`kubectl apply/delete/scale`, `qm`, `pveum`) are proposed as commands for the owner to run unless explicitly asked to execute them. - Don't delete Proxmox VMs/templates or CAPI objects on your own initiative. ## Conventions - Docs in English, Markdown, Mermaid for diagrams (Gitea renders it). - Troubleshooting findings go into the relevant doc's troubleshooting/fixes table: symptom → root cause → fix. - Example configs live in `configs/` as `*.example` or non-secret values files. ## Project history Research repo: plans, conversations and decisions are kept in the repo, dated. Timestamps always come from `date` (`+%Y-%m-%d-%H%M` for file names, `+%Y-%m-%d %H:%M %Z` for headings), never guessed. Summaries only, never raw transcripts; mask secrets and check the staged diff before committing. | What | Where | When | | --- | --- | --- | | Plans | `docs/plans/YYYY-MM-DD-HHMM-.md` | every plan-mode plan | | Execution logs | `docs/plans-executions/` | after each step of an approved plan | | Session notes | `docs/sessions/YYYY-MM-DD-HHMM-.md` | research/design/debugging conversations without a plan | | Decisions | `docs/decisions.md` (one table) | a direction chosen, rejected or reversed | | Prompts | `docs/prompts/YYYY-MM-DD-HHMM-.md` | long crafted prompts/specs that kick off work (verbatim) | | Reviews | `docs/reviews/YYYY-MM-DD-HHMM-.md` | review findings, most severe first, `- [ ]` ticked as processed | | Changelog | `CHANGELOG.md`, newest on top | lab milestone, version change, design direction, new runbook/config — after the owner confirms it works | - **Plans:** header `# Plan: ` + `**Created:** <timestamp>`. Plan mode can only write to `~/.claude/plans/`, so right after `ExitPlanMode` the first action is copying the plan into `docs/plans/` and committing it on its own, before any work starts. - **Execution logs:** a `- [ ] Step N — <title>` checklist on top (the authoritative status; a new session resumes from this file alone), then one section per step in chronological order, committed with that step's work. Light prose; exact commands as fenced blocks (`clusterctl`, `helm`, `kubectl apply`, `qm`, Packer), each with one line on why it was run that way, including commands the owner reports running on the lab and outputs that mattered (VM IDs, IPs, resolved versions, errors). Call out deviations from the plan; end with "Worth noting". Problems also go into the relevant fixes table, linked from the log. - **Session notes:** write one unprompted when a conversation produced a finding worth keeping (option compared or rejected, compatibility check, root cause, open question) that no plan covers; mention it in the reply. Sections: Question, What was checked (sources, versions with date checked), Findings, Open questions, Follow-ups. Extend the note if the topic continues. - **Decisions:** never rewrite a row; a reversal is a new row and the old one becomes `superseded by #N`. Design-doc suggestions are `proposed` until lab work confirms them. Link the plan/session/doc with the reasoning. README "Key decisions so far" stays the short summary. ## Git - Remote: Gitea `gitea.home.hrajfrisbee.cz/kacerr/cluster-autoscaler-with-capi`. - Docs, configs and history files go straight to `main`. Phase-3 Go code or anything the owner calls a feature: `feat/<slug>` branch, `git push -u`, MR via `tea pr create --title … --description … --base main --head <branch>` (fallback: print `…/compare/main...<branch>`). Never merge or delete branches from the CLI. - Commit messages end with a `Co-Authored-By:` trailer for Claude. `/ship` commits and pushes.