Rules and guidelines for AI agents working in this repository.
omnix is a composable Nix infrastructure library. See SPEC.md for the vision and ROADMAP.md for the path.
# Check flake validity
nix flake check
# Evaluate modules
nix eval .#nixosModules
# Evaluate lib
nix eval .#lib
# Format Nix files
nixfmt **/*.nix- Use
lib.mkOptionwith proper types for all module options - Every module must be independently usable (no implicit dependencies on other omnix modules)
- Options live under the
omnix.*namespace - Use
lib.mkIf cfg.enablefor conditional configuration - Use
lib.mkDefaultfor overridable defaults - Keep modules focused on a single concern
- Every configurable value must be a module option with a type and description
- Avoid hardcoded project-specific values -- parameterize them
- Prefer
lib.types.stroverlib.types.pathfor values that may come from terraform or other dynamic sources - Group related options under a single
omnix.<module>prefix
- Functions take an attrset of required parameters
- Return an attrset of derivations or values
- Use
pkgs.writeShellApplicationfor shell scripts (not rawwriteScript) - Include
runtimeInputs-- never assume tools are on PATH - All shell scripts must use
set -eo pipefail
- Each module should evaluate without errors in isolation
- Library functions should produce derivations that build
- Template projects should pass
nix flake check - Consumer repos using devenv dev shells require
nix flake check --impure(devenv needs impure evaluation to resolve the working directory)
Never suppress Nix evaluation errors or warnings.
omnix handles infrastructure. It must never contain:
- Rust build logic
- Frontend build logic
- Dev shell configuration
- CI pipeline definitions
- Application-specific systemd timers or services
These belong in consumer repos. omnix provides the building blocks.
Every module and lib function must work independently. A consumer should be able
to use omnix.nixosModules.disko without importing any other omnix module. Test
this by evaluating modules in isolation.
When changing module option interfaces, preserve the old option with
lib.mkRenamedOptionModule or lib.mkRemovedOptionModule with a clear
migration message.