Files
AGENTS/rules/languages/nix.md
m3tm3re 8910413315 feat(rules): add initial rule files for concerns, languages, and frameworks
Concerns (6 files):
- coding-style.md (163 lines): patterns, anti-patterns, error handling, SOLID
- naming.md (105 lines): naming conventions table per language
- documentation.md (149 lines): docstrings, WHY vs WHAT, README standards
- testing.md (134 lines): AAA pattern, mocking philosophy, TDD
- git-workflow.md (118 lines): conventional commits, branch naming, PR format
- project-structure.md (82 lines): directory layout, entry points, config placement

Languages (4 files):
- python.md (224 lines): uv, ruff, pyright, pytest, pydantic, idioms, anti-patterns
- typescript.md (150 lines): strict mode, discriminated unions, satisfies, as const
- nix.md (129 lines): flake structure, module patterns, alejandra, anti-patterns
- shell.md (100 lines): set -euo pipefail, shellcheck, quoting, POSIX

Frameworks (1 file):
- n8n.md (42 lines): workflow design, node patterns, Error Trigger, security

Context budget: 975 lines (concerns + python) < 1500 limit

Refs: T6-T16 of rules-system plan
2026-02-17 19:05:45 +01:00

2.5 KiB

Nix Code Conventions

Formatting

  • Use alejandra for formatting
  • camelCase for variables, PascalCase for types
  • 2 space indentation (alejandra default)
  • No trailing whitespace

Flake Structure

{
  description = "Description here";
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in {
        packages.default = pkgs.hello;
        devShells.default = pkgs.mkShell {
          buildInputs = [ pkgs.hello ];
        };
      }
    );
}

Module Patterns

Standard module function signature:

{ config, lib, pkgs, ... }:
{
  options.myService.enable = lib.mkEnableOption "my service";
  config = lib.mkIf config.myService.enable {
    services.myService.enable = true;
  };
}

Conditionals and Merging

  • Use mkIf for conditional config
  • Use mkMerge to combine multiple config sets
  • Use mkOptionDefault for defaults that can be overridden
config = lib.mkMerge [
  (lib.mkIf cfg.enable { ... })
  (lib.mkIf cfg.extraConfig { ... })
];

Anti-Patterns (AVOID)

with pkgs;

Bad: Pollutes namespace, hard to trace origins

{ pkgs, ... }:
{
  packages = with pkgs; [ vim git ];
}

Good: Explicit references

{ pkgs, ... }:
{
  packages = [ pkgs.vim pkgs.git ];
}

builtins.fetchTarball

Use flake inputs instead. fetchTarball is non-reproducible.

Impure operations

Avoid import <nixpkgs> in flakes. Always use inputs.

builtins.getAttr / builtins.hasAttr

Use lib.attrByPath or lib.optionalAttrs instead.

Home Manager Patterns

{ config, pkgs, lib, ... }:
{
  home.packages = with pkgs; [ ripgrep fd ];
  programs.zsh.enable = true;
  xdg.configFile."myapp/config".text = "...";
}

Overlays

{ config, lib, pkgs, ... }:
let
  myOverlay = final: prev: {
    myPackage = prev.myPackage.overrideAttrs (old: { ... });
  };
in
{
  nixpkgs.overlays = [ myOverlay ];
}

Imports and References

  • Use flake inputs for dependencies
  • lib is always available in modules
  • Reference packages via pkgs.packageName
  • Use callPackage for complex package definitions

File Organization

flake.nix              # Entry point
modules/               # NixOS modules
  services/
    my-service.nix
overlays/              # Package overrides
  default.nix