diff --git a/AGENTS.md b/AGENTS.md index eb3dd7c1..848b33d7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,212 +1,67 @@ -# AGENTS.md - Guidelines for AI Coding Agents +# Repository Agent Guide -This file defines the default operating guide for AI agents working in this Nix Flake repository. -Keep changes minimal, verifiable, and safe for multi-host deployments. +This flake manages NixOS hosts, macOS via nix-darwin, shared Home Manager profiles, and Colmena +deployments. Keep repository guidance here; reusable global rules live in `agents/AGENTS.md`. See +[agents/README.md](./agents/README.md) for their scope and symlink installation targets. -## Scope and Repository Model +## Where Changes Belong -This repository manages: +- `flake.nix` defines inputs; `outputs/default.nix` composes outputs for `x86_64-linux`, + `aarch64-linux`, and `aarch64-darwin`. +- `modules/` contains system modules; `home/` contains Home Manager modules. Put shared behavior + here rather than duplicating it in host configurations. +- `hosts/` contains host-specific configuration; `outputs//src/` wires hosts into outputs. +- `vars/` and `lib/` provide shared values and helpers. Use `myvars` and existing abstractions + instead of hardcoding usernames or paths. +- `secrets/` contains agenix definitions; secret material also comes from a private external repo. -- NixOS hosts (desktop + servers) -- macOS hosts via nix-darwin -- Home Manager profiles shared across platforms -- Remote deployments via colmena +## Commands and Platforms -High-level layout: +- Prefer recipes in [Justfile](./Justfile); use `just --list` to discover available commands and + `just --show ` to inspect behavior before running them. +- The Justfile uses Nushell. Preserve `[linux]` / `[macos]` guards and host naming conventions. +- `just local` uses `nixos-switch` on Linux and `darwin-build` / `darwin-switch` on macOS; their + arguments differ. Check both platforms when changing shared behavior. +- `nix develop` provides formatters and linters. If needed, `nix shell nixpkgs#just nixpkgs#nushell` + provides the task runner and its shell. -```text -. -├── flake.nix # Flake entry; outputs composed in ./outputs -├── Justfile # Primary command entrypoint (uses nushell) -├── outputs/ -│ ├── default.nix -│ ├── x86_64-linux/ -│ ├── aarch64-linux/ -│ └── aarch64-darwin/ -├── modules/ # NixOS + darwin modules -├── home/ # Home Manager modules -├── hosts/ # Host-specific config -├── vars/ # Shared variables -├── lib/ # Helper functions -├── agents/ # Reusable cross-project agent files and installer -└── secrets/ # Agenix secret definitions -``` +## Validation -## Ground Rules for Agents +- For Nix changes, run `just fmt` and inspect the diff: it formats all Nix files. Nix style is + `nixfmt` with width 100. +- For supported non-Nix files, use `prettier --write ` and `prettier --check `; + configuration lives in `.prettierrc.yaml`. Spelling checks use `typos` and `.typos.toml`. +- Run `just test` for configuration changes. It evaluates `.#evalTests` across Linux and Darwin; the + output must be `true`. Exit code zero with `false` is a failed suite. +- Eval tests are `expr.nix` / `expected.nix` pairs under `outputs//tests/`. Update focused + cases when changing behavior covered by those tests. +- Use `nix flake check` for broader flake checks. A host build can validate changes beyond eval: + `nix build .#nixosConfigurations..config.system.build.toplevel`. +- Documentation-only changes need formatting checks and `git diff --check`; Nix tests may be + skipped. Report checks run, skipped, or blocked, including the command and reason for failures. -- Prefer `just` tasks over ad-hoc commands when an equivalent task exists. -- Make the smallest reasonable change; avoid drive-by refactors. -- Do not commit secrets, generated credentials, or private keys. -- Preserve platform guards (`[linux]`, `[macos]`) and host naming conventions. -- Run formatting and evaluation checks for touched areas before finishing. +## Nix Conventions -## Quick Start Workflow (Recommended) - -1. Inspect context: - -```bash -just --list -rg -n "" modules home hosts outputs -``` - -2. Implement the change. -3. Format: - -```bash -just fmt -``` - -4. Validate: - -```bash -just test -``` - -5. If deployment behavior changed, provide the exact `just` command the user should run (do not run - remote deploys unless explicitly requested). - -## Canonical Commands - -### Core quality loop - -```bash -just fmt # format Nix files -just test # run eval tests: nix eval .#evalTests ... -nix flake check # run flake checks + pre-commit style checks -``` - -### Dependency/input updates - -```bash -just up # update all inputs and commit lock file -just upp # update one input and commit lock file -just up-nix # update nixpkgs-related inputs -``` - -### Local deploy commands - -```bash -just local # Linux: switch config for current hostname -just local boot # Linux: set the next boot config without switching -just local switch debug # Linux: switch with detailed output -just local boot debug # Linux: boot mode with detailed output -just niri # Linux: switch "-niri" -just niri boot # Linux: set "-niri" for the next boot -just niri switch debug # Linux: switch niri config with detailed output -just local debug # macOS: switch with detailed output -``` - -### Remote deploy commands (colmena) - -```bash -just col # switch nodes matching tag -just col boot # set matching nodes' next boot configuration -just lab # switch all kubevirt nodes -just lab boot # set all kubevirt nodes for the next boot -just k3s-prod # switch k3s production nodes -just k3s-prod boot # set k3s production nodes for the next boot -just k3s-test # switch k3s test nodes -just k3s-test boot # set k3s test nodes for the next boot -``` - -### Useful direct commands - -```bash -nix eval .#evalTests --show-trace --print-build-logs --verbose -nix build .#nixosConfigurations..config.system.build.toplevel -nixos-rebuild switch --flake .# -``` - -## Test Structure and Expectations - -Eval tests live under: - -- `outputs/x86_64-linux/tests/` -- `outputs/aarch64-linux/tests/` -- `outputs/aarch64-darwin/tests/` - -Typical test pair: - -- `expr.nix` -- `expected.nix` - -Agent expectations: - -- If logic changes affect shared modules, run `just test`. -- If only docs/comments changed, tests may be skipped, but say so explicitly. -- If tests cannot run, report why and include the exact failing command. - -## Formatting and Style - -### Formatting tools - -- Nix: `nixfmt` (RFC style, width 100) -- Non-Nix: `prettier` (see `.prettierrc.yaml`) -- Spelling: `typos` (see `.typos.toml`) - -### Nix style conventions - -- Files use `kebab-case.nix`. -- Prefer `inherit (...)` for attribute imports. -- Prefer `lib.mkIf`, `lib.optional`, `lib.optionals` for conditional config. +- Use `kebab-case.nix` filenames and `inherit (...)` for attribute imports. +- Prefer `lib.mkIf`, `lib.optional`, and `lib.optionals` for conditional configuration. - Use `lib.mkDefault` for defaults and `lib.mkForce` only when necessary. -- Keep module options documented with `description`. +- Give module options a `description` and preserve platform-specific conditions. -Module pattern: +## Command Hazards -```nix -{ lib, config, ... }: -{ - options.myFeature = { - enable = lib.mkEnableOption "my feature"; - }; +- `just up`, `just upp`, and `just up-nix` use `--commit-lock-file`. When a commit is not + authorized, use `nix flake update ` for a scoped input update without committing. +- Deployment and upload recipes change systems; use eval/build commands for validation. Remote + deployment requires an explicit request. When deployment behavior changes, report the exact `just` + command to run. +- `just clean`, `just gc`, `just ggc`, and `just game` remove history or amend commits; they are not + validation steps and require explicit authorization for their target and scope. +- Do not use `just penvof` for process inspection: it can expose secret values. - config = lib.mkIf config.myFeature.enable { - # ... - }; -} -``` +## Further Context -## Platform Notes - -- `Justfile` uses `nu` (`set shell := ["nu", "-c"]`). -- Some tasks exist only on Linux or macOS via `[linux]` / `[macos]` guards. -- `just local` has different implementations per platform: - - Linux: `nixos-switch` - - macOS: `darwin-build` + `darwin-switch` - -## Secrets and Safety - -- Secrets are managed with agenix and an external private secrets repo. -- Never inline secret values in Nix files, tests, or docs. -- Do not run broad remote deploy commands unless requested. -- Prefer build/eval validation first, deploy second. - -## Change Review Checklist (for agents) - -Before finishing, verify: - -1. Change is scoped to requested behavior. -2. `just fmt` applied (or not needed, stated explicitly). -3. `just test` run for config changes (or limitation explained). -4. No secrets or machine-specific artifacts added. -5. User-facing summary includes what changed and what was validated. - -## Common Pitfalls - -- Editing host-specific files when the change belongs in shared module layers (`modules/` or - `home/`). -- Forgetting to update both Linux and darwin paths when touching shared abstractions. -- Running deployment commands to validate syntax when `nix eval`/`nix build` would be safer. -- Introducing hardcoded usernames/paths instead of using `myvars` and existing abstractions. - -## References - -- [README.md](./README.md) -- [agents/README.md](./agents/README.md) -- [Justfile](./Justfile) -- [outputs/README.md](./outputs/README.md) -- [hosts/README.md](./hosts/README.md) -- [home/README.md](./home/README.md) -- [modules/README.md](./modules/README.md) -- [secrets/README.md](./secrets/README.md) +- [Repository overview](./README.md) +- [Outputs and tests](./outputs/README.md) +- [Hosts](./hosts/README.md), [system modules](./modules/README.md), and + [Home Manager](./home/README.md) +- [Secrets](./secrets/README.md) diff --git a/agents/README.md b/agents/README.md index bc780f04..e1f61390 100644 --- a/agents/README.md +++ b/agents/README.md @@ -9,7 +9,6 @@ The primary workflow is to symlink files from here into each agent runtime/confi - `AGENTS.md`: global baseline rules for coding agents. - `evals/global-rules.md`: behavioral scenarios for validating changes to the global rules. -- `permissions.md`: permission policies for agent tool access. - `install-rules.py`: installs the baseline by creating symlinks in supported agent config dirs. - `install-cli.md`: curated CLI install/update command snippets. - `install-skills.md`: curated `npx skills` command snippets. @@ -17,7 +16,7 @@ The primary workflow is to symlink files from here into each agent runtime/confi ## Core workflow 1. Maintain shared rules in `agents/AGENTS.md`. -2. Define permission policies in `agents/permissions.md`. +2. Configure permissions directly in the agent runtime; auto-approval is generally used. 3. Run `install-rules.py` to refresh symlinks in local agent homes. 4. Use `install-cli.md` and `install-skills.md` as reference snippets when needed. @@ -42,6 +41,13 @@ Behavior: - Missing destination directories are skipped. - Existing destination file/symlink is replaced with a symlink to this repo source file. +The installer links only `AGENTS.md`; it does not install permission configuration, skills, or CLIs. +The repository-root `AGENTS.md` contains guidance for this Nix configuration repository. It is not +the global rules source and is not installed by this script. + +Auto-approval controls tool prompting. The global rules still define task authorization, safety, and +secret handling. + ## About `install-cli.md` and `install-skills.md` Use them as snippet libraries: diff --git a/agents/opencode-permission-tmpl.json b/agents/opencode-permission-tmpl.json deleted file mode 100644 index 585b973f..00000000 --- a/agents/opencode-permission-tmpl.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "read": { - "*": "allow", - "*.env": "deny", - "*.env.*": "deny", - "*.env.example": "allow", - "*.pem": "deny", - "*.key": "deny", - "*kubeconfig*": "deny", - ".ssh/**": "deny", - ".aws/**": "deny", - ".kube/**": "deny", - ".gnupg/**": "deny" - }, - "edit": "allow", - "glob": "allow", - "grep": "allow", - "task": "allow", - "lsp": "allow", - "skill": "allow", - "question": "allow", - "todowrite": "allow", - "webfetch": "allow", - "websearch": "allow", - "external_directory": "ask", - "doom_loop": "deny", - "bash": { - "*": "ask", - "git status *": "allow", - "git diff *": "allow", - "git log *": "allow", - "git show *": "allow", - "git branch *": "allow", - "git remote *": "allow", - "git tag *": "allow", - "git blame *": "allow", - "git reflog *": "allow", - "git stash list *": "allow", - "git lfs *": "allow", - "kubectl get *": "allow", - "kubectl describe *": "allow", - "kubectl logs *": "allow", - "kubectl top *": "allow", - "kubectl api-*": "allow", - "kubectl config *": "allow", - "kubectl explain *": "allow", - "kubectl kustomize *": "allow", - "kustomize *": "allow", - "terraform plan *": "allow", - "terraform show *": "allow", - "terraform state *": "allow", - "terraform output *": "allow", - "terraform version *": "allow", - "terraform providers *": "allow", - "terraform fmt *": "allow", - "gh repo view *": "allow", - "gh repo list *": "allow", - "gh issue view *": "allow", - "gh issue list *": "allow", - "gh pr view *": "allow", - "gh pr list *": "allow", - "gh pr diff *": "allow", - "gh pr checks *": "allow", - "gh api *": "allow", - "gh search *": "allow", - "gh gist list *": "allow", - "gh gist view *": "allow", - "gh release view *": "allow", - "gh release list *": "allow", - "gh workflow list *": "allow", - "gh workflow view *": "allow", - "gh run list *": "allow", - "gh run view *": "allow", - "gh status *": "allow", - "gh auth status *": "allow", - "helm list *": "allow", - "helm get *": "allow", - "helm show *": "allow", - "helm search *": "allow", - "helm repo *": "allow", - "helm status *": "allow", - "helm version *": "allow", - "helm template *": "allow", - "gcloud * list *": "allow", - "gcloud * describe *": "allow", - "gcloud * get-iam-policy *": "allow", - "gcloud config *": "allow", - "gcloud auth *": "allow", - "gcloud version *": "allow", - "nix eval *": "allow", - "nix build *": "allow", - "nix flake *": "allow", - "nix profile *": "allow", - "nix store *": "allow", - "nix search *": "allow", - "nix doctor *": "allow", - "nixos-rebuild build *": "allow", - "darwin-rebuild build *": "allow", - "nom build *": "allow", - "just --list *": "allow", - "just --show *": "allow", - "just --dry-run *": "allow", - "statix check *": "allow", - "deadnix *": "allow", - "nixfmt *": "allow", - "shellcheck *": "allow", - "hadolint *": "allow", - "actionlint *": "allow", - "ruff check *": "allow", - "clippy *": "allow", - "prettier --check *": "allow", - "tokei *": "allow", - "systemctl status *": "allow", - "systemctl list-*": "allow", - "systemctl show *": "allow", - "journalctl *": "allow", - "lspci *": "allow", - "lsusb *": "allow", - "lsblk *": "allow", - "df *": "allow", - "free *": "allow", - "uptime *": "allow", - "uname *": "allow", - "sensors *": "allow", - "lsof *": "allow", - "go version *": "allow", - "go env *": "allow", - "go list *": "allow", - "go doc *": "allow", - "go vet *": "allow", - "cargo --version *": "allow", - "cargo tree *": "allow", - "cargo metadata *": "allow", - "python3 --version *": "allow", - "python3 -m py_compile *": "allow", - "node --version *": "allow", - "pnpm list *": "allow", - "uv pip list *": "allow", - "rg *": "allow", - "fd *": "allow", - "cp *": "allow", - "mv *": "allow", - "chmod *": "allow", - "ls *": "allow", - "cat *": "allow", - "head *": "allow", - "tail *": "allow", - "wc *": "allow", - "find *": "allow", - "which *": "allow", - "echo *": "allow", - "pwd *": "allow", - "date *": "allow", - "env *": "allow", - "printenv *": "allow", - "file *": "allow", - "stat *": "allow", - "du *": "allow", - "tree *": "allow", - "bat *": "allow", - "eza *": "allow", - "jq *": "allow", - "yq *": "allow", - "tldr *": "allow", - "mkdir *": "allow", - "rmdir *": "allow", - "grep *": "allow", - "rm *": "ask", - "rm -rf *": "ask", - "sudo *": "deny" - } - } -} diff --git a/agents/permissions.md b/agents/permissions.md deleted file mode 100644 index e65364aa..00000000 --- a/agents/permissions.md +++ /dev/null @@ -1,190 +0,0 @@ -# Permissions Configuration - -This document records the current permission requirements for AI agents operating in this -repository. - -## Scope - -| Environment | Policy | -| ------------------------ | ------------------------------------------- | -| **Personal workstation** | Restrictive - protect user's daily workflow | -| **Homelab VMs** | Permissive - agents have full autonomy | - -The permissions below apply to **personal workstation** only. For homelab VMs, almost everything is -allowed except destructive operations on production systems. - -## Default Policy - -| Tool | Permission | -| ---------------- | ---------- | -| `*` (all others) | ask | - -## File Read Permissions - -| Pattern | Permission | -| --------------- | ---------- | -| `*` (all files) | allow | -| `*.env` | deny | -| `*.env.*` | deny | -| `*.env.example` | allow | -| `*.pem` | deny | -| `*.key` | deny | -| `*kubeconfig*` | deny | -| `.ssh/**` | deny | -| `.aws/**` | deny | -| `.kube/**` | deny | -| `.gnupg/**` | deny | - -## Always Allowed Tools - -These tools run without prompting: - -- `glob` -- `grep` -- `lsp` -- `question` -- `skill` -- `todowrite` -- `webfetch` -- `websearch` -- `codesearch` -- `edit` (covers `write` and `apply_patch`) - -## Bash Command Permissions - -### Always Allowed (Read-only operations) - -**Git:** - -- `git status`, `git diff`, `git log`, `git show`, `git branch`, `git remote` - -**Kubernetes:** - -- `kubectl get`, `kubectl describe`, `kubectl logs`, `kubectl top` -- `kubectl api-resources`, `kubectl api-versions` -- `kubectl config view`, `kubectl config get-contexts` -- `kubectl explain` -- `kubectl kustomize`, `kustomize build`, `kustomize version` - -**Terraform:** - -- `terraform plan`, `terraform show`, `terraform state list`, `terraform state show` -- `terraform output`, `terraform version`, `terraform providers`, `terraform fmt` - -**GitHub CLI:** - -- `gh repo view/list`, `gh issue view/list`, `gh pr view/list/diff/checks` -- `gh api`, `gh search`, `gh gist list/view` -- `gh release view/list`, `gh workflow list/view`, `gh run list/view` -- `gh status`, `gh auth status` - -**Helm:** - -- `helm list`, `helm get`, `helm show`, `helm search` -- `helm repo list`, `helm status`, `helm version`, `helm template` - -**Google Cloud:** - -- `gcloud * list`, `gcloud * describe`, `gcloud * get-iam-policy` -- `gcloud config list`, `gcloud auth list`, `gcloud version` - -**Nix:** - -- `nix eval`, `nix build`, `nix flake show`, `nix flake metadata` -- `nix flake check`, `nix flake lock` -- `nix profile list`, `nix profile history` -- `nix store verify`, `nix store ls`, `nix store path-info` -- `nix search`, `nix doctor`, `nix --version` -- `nixos-rebuild build`, `darwin-rebuild build` -- `nom build` - -**Just:** - -- `just --list`, `just --show`, `just --dry-run` - -**Linters & Formatters:** - -- `statix check`, `deadnix`, `nixfmt --check` -- `shellcheck`, `hadolint`, `actionlint` -- `ruff check`, `clippy`, `prettier --check` -- `tokei` - -**System diagnostics:** - -- `systemctl status`, `systemctl list-units`, `systemctl show` -- `journalctl -u`, `journalctl --since` -- `lspci`, `lsusb`, `lsblk`, `df`, `free`, `uptime`, `uname -a` -- `sensors`, `lsof` - -**Git (extended):** - -- `git tag`, `git blame`, `git reflog`, `git stash list` -- `git lfs status`, `git lfs ls-files` - -**Development tools:** - -- `go version`, `go env`, `go list`, `go doc`, `go vet` -- `cargo --version`, `cargo tree`, `cargo metadata` -- `python3 --version`, `python3 -m py_compile` -- `node --version`, `pnpm list`, `uv pip list` - -**General utilities:** - -- `rg`, `fd`, `cp`, `mv`, `chmod` -- `ls`, `cat`, `head`, `tail`, `wc`, `find`, `which` -- `echo`, `pwd`, `date`, `env`, `printenv` -- `file`, `stat`, `du`, `tree`, `bat`, `eza` -- `jq`, `yq`, `tldr` -- `mkdir`, `rmdir`, `grep` - -### Requires Confirmation - -| Command | Permission | -| ---------- | ---------- | -| `rm *` | ask | -| `rm -rf *` | ask | - -### Always Denied - -| Command | Permission | -| -------- | ---------- | -| `sudo *` | deny | - -## Homelab VM Permissions - -For agents running in dedicated homelab VMs, permissions are significantly relaxed: - -| Category | Permission | -| -------------------- | --------------------- | -| `bash` | allow (most commands) | -| `edit` | allow | -| `write` | allow | -| `task` | allow | -| `external_directory` | allow | -| `rm` | allow | - -**Still restricted in homelab VMs:** - -- Production cluster destructive operations (`kubectl delete`, `helm uninstall`) -- Infrastructure teardown (`terraform destroy`) -- Secret exposure in logs - -## Other Tool Permissions - -| Tool | Permission | -| -------------------- | ---------- | -| `edit` | allow | -| `task` | ask | -| `external_directory` | ask | -| `doom_loop` | deny | - -## Summary - -- **Default policy**: All tools `ask` — only explicitly whitelisted tools auto-allow -- **File operations**: `read`, `glob`, `grep`, `edit`, `write` all allowed in workspace -- **Nix operations**: Build/eval/flake commands auto-allowed (writes to store only) -- **Linting & formatting**: All check commands auto-allowed -- **System diagnostics**: Read-only system info auto-allowed -- **Sensitive files**: Credentials, keys, and cloud configs are blocked -- **Bash commands**: Read-only ops auto-allowed; `rm` requires confirmation; `sudo` blocked -- **Scope control**: `task` and `external_directory` require approval