diff --git a/AGENTS.md b/AGENTS.md index 77fbb73..2da6459 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,85 +1,85 @@ # AGENTS.md Guidance for coding agents working in this repository. Project type: Ansible-driven infrastructure, workstation/server provisioning, and user dotfiles. + ## Repository Map - Entry playbook: `ansible/site.yml` - Inventory: `ansible/inventory/hosts.yml` -- Shared vars: `ansible/inventory/group_vars/*.yml` -- Host overrides: `ansible/inventory/host_vars/*.yml` +- Group vars: `ansible/inventory/group_vars/*.yml` +- Host vars: `ansible/inventory/host_vars/*.yml` - Roles: `ansible/roles/*` +- Role assets: `ansible/roles/*/{tasks,templates,files,handlers}/` - Templates: `ansible/templates/**/*.j2` - Dotfiles: `dotfiles/` - Scripts: `scripts/` -- Local secrets area: `secrets/` -## Active Topology +- Secrets: `secrets/` + +## Topology And Orchestration - Void desktops: `ikaros`, `nymph` - Ubuntu workstation: `deadalus` - Ubuntu server: `prometheus` -- Most hosts currently use `ansible_connection: local` -## Active Orchestration -`ansible/site.yml` currently applies: +- Most hosts use `ansible_connection: local` - `all -> dotfiles_common` - `void -> packages_void, services_runit, profile_desktop_i3` - `ubuntu_workstation -> packages_ubuntu, services_systemd, profile_workstation_gnome` - `ubuntu_server -> packages_ubuntu, services_systemd, profile_server` +- Present but unwired roles: `base`, `dotfiles` -Roles present but not wired into `ansible/site.yml`: -- `base` -- `dotfiles` ## Local Instruction Files Checked when this file was updated: - `.cursorrules`: not present - `.cursor/rules/`: not present - `.github/copilot-instructions.md`: not present If any appear later, treat them as higher-priority repo-local instructions. + ## Working Principles - Preserve the layering: `all -> OS -> profile -> host` -- Prefer minimal, targeted edits over cleanup refactors +- Prefer minimal, targeted edits over broad cleanup - Preserve idempotency and reproducibility - Validate on one limited host before broad rollout -- Treat `secrets/` as sensitive and never print secret values +- Treat `secrets/` as sensitive; never print secret values - Avoid editing vendored code under `dotfiles/common/.tmux/plugins/` unless explicitly asked +- Keep `ansible/site.yml` small; orchestration belongs there, implementation belongs in roles + ## Build, Lint, And Test Commands There is no compile/build pipeline. Confidence comes from syntax checks, dry runs, linting, and targeted script validation. + Install tooling if needed: ```bash python3 -m pip install ansible ansible-lint yamllint ansible-galaxy collection install community.general ``` + Core validation: ```bash ansible-playbook ansible/site.yml --syntax-check -ansible-playbook ansible/site.yml --limit deadalus --check --diff -ansible-playbook ansible/site.yml --limit prometheus --check --diff ansible-playbook ansible/site.yml --limit ikaros --check --diff ansible-playbook ansible/site.yml --limit nymph --check --diff -``` -Linting and script checks: -```bash +ansible-playbook ansible/site.yml --limit deadalus --check --diff +ansible-playbook ansible/site.yml --limit prometheus --check --diff ansible-lint ansible/site.yml ansible-lint ansible/roles yamllint ansible/ -sh -n scripts/bootstrap_mail.sh -shellcheck scripts/bootstrap_mail.sh ``` + Useful execution commands: ```bash ansible-playbook ansible/site.yml +ansible-playbook ansible/site.yml --limit ikaros +ansible-playbook ansible/site.yml --limit nymph ansible-playbook ansible/site.yml --limit deadalus scripts/bootstrap_mail.sh ``` + ## Single-Test Equivalents There is no pytest, Molecule, or unit-test suite. Use the narrowest command matching the changed area. -- Single playbook syntax test: `ansible-playbook ansible/site.yml --syntax-check` -- Single host check: `ansible-playbook ansible/site.yml --limit --check --diff` +- Playbook syntax only: `ansible-playbook ansible/site.yml --syntax-check` +- Single host dry run: `ansible-playbook ansible/site.yml --limit --check --diff` - Single task restart point: `ansible-playbook ansible/site.yml --limit --start-at-task "" --check --diff` -- Single script syntax test: `sh -n scripts/bootstrap_mail.sh` -- Single script lint: `shellcheck scripts/bootstrap_mail.sh` -When changing one area, prefer: -- vars or inventory: one limited host dry run -- one role: one limited host dry run, plus `ansible-lint ansible/roles/` if available -- one template: one limited host dry run with `--diff` -- one script: `sh -n` and `shellcheck` on that script +- Single role lint: `ansible-lint ansible/roles/` +- Script syntax/lint: `sh -n scripts/bootstrap_mail.sh` and `shellcheck scripts/bootstrap_mail.sh` +- Prefer one limited-host dry run for vars, templates, dotfiles, packages, services, PAM, display manager, and firewall changes + ## Code Style Guidelines ### General - Keep orchestration in playbooks and implementation in roles @@ -87,42 +87,42 @@ When changing one area, prefer: - Make state transitions explicit - Avoid unrelated refactors in the same change - Keep comments sparse and only for non-obvious behavior + ### YAML And Formatting - Start YAML files with `---` - Use 2-space indentation; never use tabs - Keep existing ordering stable when editing lists and maps - Quote file modes as strings such as `"0644"`, `"0755"`, `"0600"`, `"0700"` - Avoid formatting-only churn in untouched sections -### Imports, Modules, And Task Structure -- Use FQCN module names such as `ansible.builtin.copy` and `community.general.ufw` + +### Modules And Task Structure +- Use FQCN module names such as `ansible.builtin.copy` and `community.general.xbps` - Prefer dedicated modules over `ansible.builtin.command` or `ansible.builtin.shell` - Use `command` only when no module fits; use `shell` only for shell features - When using `command` or `shell`, set `changed_when` and `failed_when` when defaults are misleading - Keep task names imperative, descriptive, and stable enough for `--start-at-task` -- Tag tasks consistently with existing families such as `packages`, `services`, `dotfiles`, `gnome`, and `dotfiles:*` +- Tag tasks consistently with existing families such as `packages`, `services`, `dotfiles`, `gnome`, `nvidia`, `emptty`, and `dotfiles:*` - Prefer `loop` with `loop_control.label` for multi-item tasks +- Use handlers for service restarts when configuration changes should trigger them + ### Variables, Types, And Naming - Use `snake_case` for vars, facts, and registered values -- Follow existing families such as `common_packages`, `ubuntu_packages_base`, `profile_packages`, `host_packages`, `workstation_dotfiles`, and `host_enabled_services` +- Follow existing families such as `common_packages`, `profile_packages`, `host_packages`, `desktop_dotfiles`, `host_dotfiles`, `enabled_services`, and `host_enabled_services` - Keep booleans as booleans, not quoted strings - Keep structured values as YAML lists/maps, not comma-separated strings - Guard optional lists with `default([])`, mappings with `default({})`, and strings with `default('')` -- Build managed-user paths from `{{ user_home }}` +- Build managed-user paths from `{{ user_home }}` where applicable - Put host-specific overrides in `host_vars`, not shared `group_vars` -### Templates And Dotfiles + +### Templates, Dotfiles, And Shell - Keep secrets parameterized through vars; never hardcode them in templates +- Prefer role `templates/` for variable-driven config and role `files/` for static payloads - Preserve destination paths and permissions unless the task requires a change -- For workstation-only files, prefer `group_vars/workstation.yml` and the workstation role -- For server-only changes, keep them out of workstation profiles -- Do not modify Git templates unless the task explicitly concerns Git behavior -### Area-Specific Guidance -- `ansible/site.yml`: orchestration only; keep it small -- `ansible/inventory/group_vars/*.yml`: shared defaults by scope -- `ansible/inventory/host_vars/*.yml`: host-specific deltas only -- `ansible/roles/*/tasks/main.yml`: implementation details and ordered steps -- `ansible/templates/**/*.j2`: parameterized config files -- `dotfiles/`: deployed user config and session scripts -- `scripts/`: local helper scripts that should remain safe for manual execution +- Dotfiles should stay deployable on real machines; avoid repo-only hacks in `dotfiles/` +- Prefer POSIX `sh` for simple scripts; use Bash only when needed +- Use `set -eu` in POSIX shell scripts unless there is a clear reason not to +- Quote variable expansions unless intentional splitting is required + ### Error Handling And Safety - Fail early with `ansible.builtin.fail` when prerequisites are missing - Guard OS-specific, DE-specific, and host-specific behavior with `when` @@ -131,30 +131,29 @@ When changing one area, prefer: - Keep tasks non-interactive unless explicitly user-driven - Avoid destructive changes in user homes unless clearly required - For firewall changes, allow required access before enabling the firewall -### Shell Script Style -- Prefer POSIX `sh` for simple scripts; use Bash only when needed -- Use `set -eu` in POSIX shell scripts unless there is a reason not to -- Quote variable expansions unless intentional splitting is required -- Use helper functions for repeated checks and cleanup +- Be careful with display-manager/session changes on desktop hosts; validate on one host first + +## Area-Specific Notes +- `profile_desktop_i3` now manages `emptty` on Void desktops; keep session changes coordinated with `.xinitrc` +- `dotfiles/desktop/.xinitrc` is part of the X11 session bootstrap path; changes there affect login behavior +- `nymph` has special NVIDIA/PRIME handling; keep host-specific logic guarded by hostname or host vars +- `ikaros` is treated as the more stable personal desktop; prefer validating risky desktop changes elsewhere first + ## Validation Expectations Before Finishing -Run the narrowest useful checks for the files you changed. Default minimum: ```bash ansible-playbook ansible/site.yml --syntax-check ``` -Preferred for vars, templates, roles, packages, services, PAM, GNOME, mail, firewall, or dotfile changes: -```bash -ansible-playbook ansible/site.yml --limit --check --diff -``` If you touched `scripts/bootstrap_mail.sh`, also run: ```bash sh -n scripts/bootstrap_mail.sh shellcheck scripts/bootstrap_mail.sh ``` + ## Agent Workflow Expectations -- Read the relevant inventory, vars, role tasks, templates, and dotfiles before editing +- Read the relevant inventory, vars, role tasks, templates, files, handlers, and dotfiles before editing - Do not revert unrelated worktree changes made by the user - Keep `README.md` and `AGENTS.md` aligned when workflows materially change - If you add a new operational area, also add the validation command agents should run -- Prefer host-limited validation first, especially `deadalus` for workstation work and `prometheus` for server work +- Prefer host-limited validation first, especially `ikaros` or `nymph` for Void desktop work, `deadalus` for Ubuntu workstation work, and `prometheus` for server work - Call out checks you could not run and any follow-up verification needed