# CLAUDE.md — Project Instructions for Claude Code (`felhom.eu`) > Read automatically when Claude Code works in this repo. Stable orientation only — **current state > lives in `CONTEXT.md` and the tops of `hub/CHANGELOG.md` / `scripts/CHANGELOG.md` / > `website/CHANGELOG.md`**, never here. Cross-repo orientation (the felhom system, artifact > taxonomy, access): workspace-root `e:\git\CLAUDE.md`; this file is `felhom.eu`-specific. ## Project overview This repo contains: - **Website** (`website/`) — static HTML at felhom.eu, served via k3s nginx + git-sync sidecar. - **Hub** (`hub/`) — Go application (felhom-hub), the **operator backend**, on k3s at `hub.felhom.eu`. - **K8s manifests** (`manifests/`) — k3s deployment manifests for felhom-system services. - **Architecture docs** (`documentation/`) — the **authoritative design home for the whole Felhom system**: `architecture/01..05-*.md`, `proxmox-platform.md`, `tests/phase*-findings.md`, runbooks, audits. Read these before designing. - **Skills** (`skills/`) — the versioned source of the Claude Code skills (`felhom-build-deploy`, `felhom-ui-design`, `felhom-testing`); install/update with `python scripts/install_skills.py` (junction into `~/.claude/skills/`). See `README.md` for full architecture/DNS/email/SEO docs. See `TASK.md` for the current task (if any). See `REUSE.md` before writing new code. ## The Felhom system (so the hub's role is in context) Felhom is **Proxmox-based**, with a locked **three-component model**: - **Hub** (this repo, `hub/`) — operator backend. Authors operator *intent*; mirrors box *reality*; holds **no data-plane role** and never connects inbound to a box. - **Host agent** (repo `felhom-agent/`) — one per Proxmox host; owns all Proxmox interaction. - **In-guest controller** (repo `felhom-controller/`) — one per customer LXC; Docker-only. ## Hub — architecture (version-free; current version = `manifests/hub.yaml` image tag) The hub ingests two report streams — the agent's host-domain report (`POST /api/v1/host-report`, the heartbeat/dead-man's-switch) and the legacy controller report (`POST /api/v1/report`, **frozen until the slice-10 cutover — do not modify**) — plus structured controller events (`POST /api/v1/event`, gated by `allowedEventTypes`). Around them: staleness/disk/storage-fill/leaf/capability monitor checkers, the two-tier notification dispatcher (operator English / customer Hungarian, Resend, cooldowns), the app-mail relay, customer-config + Day-0 artifact-manifest management (the checksum trust root the host bootstrap verifies against), assets serving, and the password-gated operator web UI. Package map, helpers, seams, extension points: **`REUSE.md`** (e.g. new event types must enter `allowedEventTypes` + `customerMessages` together). ## Code quality rules - Always double-check generated code for bugs, logic issues, syntax errors. - Handle edge cases without overcomplicating. - Add debug capabilities (logging, verbose output). - If you need more input or troubleshooting output, **ask first — don't guess**. - Testing doctrine (non-hollow tests, red-proofs, seams): use the `felhom-testing` skill. - UI/design work (tokens, gates, copy rules): use the `felhom-ui-design` skill. ## Workflow & artifacts The planning/architecture assistant ("project Claude", in claude.ai) writes specs and validates pushes; **you (Claude Code) implement**. A file being open in the editor is NOT an instruction. - **`TASK.md` / `TASK-*.md`** — a spec for you to implement. Then push and update `hub/CHANGELOG.md` and root `REPORT.md` per the convention below. - **`RUNBOOK-*.md`** — an operational procedure. CC executes the steps it has access and capability for, including live validation on the demo nodes and the demo Proxmox host (CC has root@felhom-pve SSH + the felhom-agent token). Mark a step HUMAN only when it genuinely needs physical presence, a real-world decision, or credentials CC truly lacks. - Validation of a push against a spec's criteria is project Claude's job, not yours, unless asked. - **Browser automation available** (`claude-in-chrome`): CC can drive `hub.felhom.eu`, the website, or any `*.demo-felhom.eu` UI for live validation + screenshots. Caveat: tools attach only to a session STARTED AFTER the bridge connected. Note: the hub UI is operator-password-gated — CC cannot log in; verify UI changes via render tests instead. > **In every repository where you make a change, update both files in that repo:** > - **`CHANGELOG.md`** — cumulative log, newest on top (here: per-area `hub/`, `scripts/`, `website/`). > - **`REPORT.md`** — **overwrite** with the most recent implementation/validation summary only. > > **Never write secrets** into any committed file — reference them as "stored out-of-band". - Update `REUSE.md` if you added/changed/deprecated a shared helper or pattern (same commit). ## Tech stack (Hub) - **Language:** Go (stdlib `net/http` + `html/template`, no frameworks). **DB:** SQLite via `modernc.org/sqlite` (pure Go). **Auth:** bcrypt + Bearer tokens + session cookies + CSRF. - **Deploy:** Docker on k3s (`felhom-system` ns). **Storage:** Longhorn PVC at `/data/` (SQLite DB). - **Config:** YAML via ConfigMap at `/etc/felhom-hub/hub.yaml`. Secrets via out-of-band `secretKeyRef` (never inline stringData — REUSE.md §3). ## SSH access Use the Windows OpenSSH binary (Git Bash's ssh fails silently): `SSH=/c/Windows/System32/OpenSSH/ssh.exe`. | Host | IP | User | Role | |------|----|------|------| | Build server (k3s node) | 192.168.0.180 | kisfenyo | Build + push images, `sudo kubectl` | | Demo Proxmox host | 192.168.0.162 | root@pam (SSH alias `felhom-pve`) | pveum/pct + live Proxmox validation | ## Build & deploy — Hub (GitOps via ArgoCD) **Full runbook: use the `felhom-build-deploy` skill.** The load-bearing rules: The whole cluster is GitOps via a **single ArgoCD app `felhom`** syncing this repo's `manifests/` to `felhom-system`. **Auto-sync is OFF** — deploys are a deliberate manual sync. ArgoCD's source of truth is the **manifest**: - **A code change + CHANGELOG bump deploys NOTHING.** The running image changes only when `manifests/hub.yaml`'s `image:` tag changes in git and the app is synced. - **Pin explicit versions, never `:latest`.** Never bare `kubectl set image`/`kubectl apply` (reverted on next sync). - **The live image can lag the CHANGELOG** when a bump was committed but the manifest/sync step never happened — reconcile via the manifest, not the changelog. - Green gate before any hub commit: `go build ./... && go vet ./... && go test ./...` in `hub/`. Steps: commit+push code → `./build.sh --push` on 180 (`~/build/felhom-hub`) → bump `manifests/hub.yaml` tag + push → ArgoCD hard-refresh + sync (kubectl-patch method in the skill) → verify Synced/Healthy + rollout + image + startup log. ## Build & deploy — Website / Manifests - **Website** auto-deploys via git-sync; just push to `main` (live in 1–2 min). **Run `python scripts/site_gates.py` after ANY website change**; new pages go into its `PAGES` list. Emergency edits: https://files.felhom.eu. All `website/` HTML is **UTF-8 with BOM** — preserve it. - **Manifests** are GitOps via the `felhom` app — commit to `main`, then deliberate sync. ## Key patterns - Hub status logic: OK (report < 30m), WARN (30m–1h or health=warn), DOWN (> 1h or health=fail); host liveness thresholds shared between UI and checker (never invent a second definition). - SQLite timestamps vary in format — always `parseSQLiteTime()`. - Dashboard/detail auto-refresh every 60s via meta refresh. Geo-restricted to Hungary via nginx ingress annotation. - Helpers, seams, extension points, traps: **`REUSE.md`** — the map is maintained same-commit.