# RULES For service implementation, CI configuration, or deployment work, also read that service's `services//AGENTS.md`, including when editing related files outside its directory. ## Infrastructure - Use `tofu`, never `terraform`. - Run OpenTofu only through repository `just` recipes; never invoke `tofu` directly. - Run `just check` after OpenTofu edits. - Run `just check read` before planning. - Agents may run `just tofu plan` without separate approval. - Review every plan result before apply. - Run `just apply` only after explicit human approval and only for the reviewed saved `tfplan`. - Treat apply as remote deployment: provisioners copy files to klops and restart services. - Do not upgrade providers or `.terraform.lock.hcl` incidentally. - Keep relay input and forwarding default-deny. - Declare every public relay exposure in both the Hetzner firewall and nftables. - Do not expose mail, DNS, or arbitrary ports without an architecture change. `just check` mutates files because it runs formatters. Use `just check read [PATH...]` for read-only checks. ## Local automation - Keep the `justfile` as a thin task dispatcher; put complex logic in `scripts/local`. - Write repository scripts in Bash; do not add Python. - Prefer a few action-oriented tasks that accept scopes over many narrow recipes. - Manage Go dev tools as pinned tool dependencies in the owning module using `go get -tool @`; invoke via `go tool `, not global binaries or mise shims. ## OpenTofu style - Use two-space formatting from `just check`. - Use `snake_case` resource, variable, and output names. - Give every variable and output an explicit type and description. - Mark secret inputs `sensitive = true`. - Set `nullable = false` when null is not handled. - Prefer relative local modules and pinned external module revisions. ## Secrets and state - Never commit or publish secret values, variable-value files, saved plans, state, or generated sensitive files. - Treat OpenTofu state as plaintext secret storage. - Let operator SSH configuration and agents resolve authentication; never hard-code private-key paths. ## Services - Define long-running klops containers as repository-managed Quadlets unless a spec says otherwise. - Keep host changes under root and application lifecycle under the designated unprivileged user. - Do not claim a revision is deployed without live deployment evidence. - Prefer registry auto-updates for deployed upstream containers until replacement update management exists. - Preserve selected release tracks; do not silently switch major versions. - Do not disable updates or pin image digests merely to avoid compatibility risk; require explicit approval and an update path. - Keep locally built images and Toad-managed digest rollouts explicit. ## Verification - Regenerate Nugu assets with `just nugu`; do not hand-edit generated palette outputs. - Validate public-site changes with `just verify sites ` at desktop and mobile viewports.