Files
felhom-agent/CLAUDE.md
T
admin aa74294a7d
gates / gates (push) Successful in 8s
docs: felhom-agent CLAUDE.md becomes a core plus path-scoped rules (R-229 leg b)
175 -> 99 effective lines. New .claude/rules/{proxmox,localapi,backup,storage}.md alongside the
existing health-checks.md. The release section points at the felhom-build-deploy skill rather than
restating a table that drifts from the script; the layout section's per-package annotations moved
into the rule file for their area instead of being deleted.

Kept in the core because it is the only part re-injected after /compact: the root-CLI fence and its
three exceptions, the destructive-op gate, prove-ownership (audit A1), the gate entry point, the F9
live-validation fence, and the checklist.

health-checks.md overlaps localapi.md and storage.md on three globs -- deliberate, both load,
stated in each file. Go build/vet/test green and unchanged.
2026-08-06 11:28:27 +02:00

6.1 KiB

CLAUDE.md — felhom-agent

Stable orientation only — current state lives in CONTEXT.md and the top of CHANGELOG.md, never here. Cross-repo conventions (artifact taxonomy, access, clean-tree gate, secrets, CHANGELOG/REPORT): workspace-root /mnt/5_hdd/felhom.eu/git/CLAUDE.md. Path-scoped detail: .claude/rules/.

What this repo is

The operator-tier host agent, one per Proxmox host, owning all Proxmox interaction: provision/restore guests, host storage, backup/restore orchestration, the hub control loop, and a narrow per-guest local API. It is the most privilege-sensitive component in the system.

  • Renamed from proxmox-controller.
  • Distinct from felhom-controller — that is the in-guest controller, Docker-only, holding no Proxmox credentials. Do not confuse them.
  • Control plane, not data plane: if the agent dies, apps keep serving; only management degrades.
  • Pure Go stdlib + golang.org/x/crypto. No web frameworks.

Doing X → read Y

Doing Read
writing any new code REUSE.md — helpers, format-safety guards, traps, seams
needing current state / open threads CONTEXT.md + the top CHANGELOG.md entry
Proxmox, reconcile or signed jobs loads itself: .claude/rules/proxmox.md
local API, authz or guest hooks loads itself: .claude/rules/localapi.md
backup, PBS or DR loads itself: .claude/rules/backup.md
storage or escrow loads itself: .claude/rules/storage.md
writing a health check loads itself: .claude/rules/health-checks.md
release, build, publish, deploy, verify a version the felhom-build-deploy skill — never hand-roll it
writing or reviewing a test, fixing a bug the felhom-testing skill
host addresses, break-glass, node facts felhom.eu/documentation/operations/nodes.md — never restate them
which box may I break felhom.eu/documentation/runbooks/target-selection.md
what version is live anywhere ask the hub (/hosts, /configs) or the box — never a doc
the authoritative design felhom.eu/documentation/architecture/03-host-agent.md (locked)

The root-CLI fence — API-first, exactly three exceptions

This is in the core because breaching it is how this component stops being auditable.

  • API-first via a scoped FelhomAgent token. Raw root-CLI is fenced to exactly 3 exceptions: keyctl pct create (golden image), USB mount/fstab, SMART/sensors.
  • Client never shells out; Privileged never makes HTTP calls — asserted by routing_test.go. Adding a method to proxmox.Privileged breaks the fence; use proxmox.Runner plus a new sudoers Cmnd_Alias and validate.go-style checks (REUSE.md §3).
  • Destructive ops go through the reconcile gate / signed-jobs path. Never call Client.DestroyLXC / Vzdump / SetConfig ad-hoc — that skips classification, signature, per-guest serialization and crash recovery.
  • Ownership must be PROVEN, never assumed. A raw ListLXC list is not "guests the agent owns"; intersect with Client.Pool membership and fail safe on a read failure (audit A1).

Gates — ONE entry point

Run python3 scripts/agent_gates.py from the repo root after ANY change here. It runs this repo's gates — reuse_refs_check and instructions_gate, both the shared copies in felhom.eu/scripts/, never copied into this repo (a copy recreates the drift they detect; an absent sibling clone FAILS). --fast selects the gates touching no network and no container runtime; today that is all of them. A missing gate is a FAILURE, never a skip.

The pre-push hook (.githooks/pre-push) runs it with --fast and refuses a failing push. It is per-clone — switch it on once with git config core.hooksPath .githooks, and a manual run WARNS when this clone is unarmed. git push --no-verify bypasses it deliberately; say so in the session report when you use it — CI re-runs the same entry point on every push and emails the operator on failure, so a bypass is noticed even though it is not blocked (R-168, CLOSED 2026-08-02).

Live validation — the fence

Exercise the SERVER-SIDE PIPELINE a real user triggers, end-to-end. The forbidden shortcut is BYPASSING it — the F9 episode was a raw guest-attach with hand-set state, and it proved nothing.

claude-in-chrome is NOT available on DooPlex. Invoking the exact endpoint the UI invokes is an acceptable proxy — say which method was used. Low-level mechanism tests where the direct call IS the mechanism are exempt.

Conventions

  • Trunk-based — no branches. All shippable work commits directly to main; main equals what is deployed. Report-only artifacts (audits, findings, fixspecs) go to felhom.eu/documentation/.
  • Unattended escape hatch: if a fix cannot be cleanly verified and shipped, revert and report — never park it on a branch.
  • Logging: the slog logger fans out to journald (configured level) plus the always-DEBUG applog.Ring (remote pulls). English, keys-never-values, durations on outcomes. Full rules: felhom.eu/documentation/runbooks/logging-conventions.md.
  • Update REUSE.md in the same commit that adds, changes or deprecates a shared helper or pattern.

End-of-session checklist

  • CHANGELOG.md (cumulative, newest on top) and REPORT.md (overwritten with this run only) — in every repo touched.
  • CONTEXT.md — decisions, state, what is next.
  • REUSE.md — if a shared helper or pattern moved.
  • A finding goes in felhom.eu/documentation/backlog/OPEN-ITEMS.md first, never only in a report or an audit.
  • Confirm your own last push's CI run went green, by run ID — CI mails on failure, which is a PUSH signal; this is the PULL check that catches a lost or unread mail. An unchecked green is an assumption, not an observation.