# Code Patterns and Anti-Patterns Common code patterns and anti-patterns used in m3ta-nixpkgs. ## Overview This document outlines recommended patterns and common pitfalls when working with m3ta-nixpkgs. ## Code Patterns ### Package Pattern #### CallPackage Registry Use `callPackage` for lazy evaluation: ```nix # Good - pkgs/default.nix { inherit (pkgs) callPackage; } rec { code2prompt = callPackage ./code2prompt {}; mem0 = callPackage ./mem0 {}; } ``` #### Meta Fields Always include complete `meta` information: ```nix # Good meta = with lib; { description = "My awesome package"; homepage = "https://github.com/author/package"; changelog = "https://github.com/author/package/releases/tag/v${version}"; license = licenses.mit; platforms = platforms.linux; mainProgram = "program-name"; }; ``` ### Module Pattern #### Standard Module Structure ```nix # Good { config, lib, pkgs, ... }: with lib; let cfg = config.m3ta.myModule; in { options.m3ta.myModule = { enable = mkEnableOption "my module"; # ... options }; config = mkIf cfg.enable { # ... configuration }; } ``` #### mkEnableOption Always use `mkEnableOption` for enable flags: ```nix # Good options.m3ta.myModule = { enable = mkEnableOption "my module"; }; # Bad options.m3ta.myModule.enable = mkOption { type = types.bool; default = false; }; ``` #### Conditional Configuration Use `mkIf` for conditional config: ```nix # Good config = mkIf cfg.enable { services.my-service.enable = true; }; ``` #### Multiple Conditions Use `mkMerge` for multiple conditions: ```nix # Good config = mkMerge [ (mkIf cfg.feature1.enable { # config for feature1 }) (mkIf cfg.feature2.enable { # config for feature2 }) ]; ``` ### Import Pattern #### Multi-line Imports Multi-line, trailing commas: ```nix # Good { lib, stdenv, fetchFromGitHub, }: ``` #### Explicit Dependencies ```nix # Good { lib, stdenv, openssl, pkg-config, }: stdenv.mkDerivation { buildInputs = [openssl pkg-config]; } ``` ## Anti-Patterns ### lib.fakeHash in Commits **Bad**: Committing `lib.fakeHash` ```nix # Bad - Never commit this! src = fetchFromGitHub { hash = lib.fakeHash; }; ``` **Solution**: Build to get real hash: ```bash nix build .#your-package # Copy actual hash from error message ``` ### Flat Module Files **Bad**: All modules in one file ```nix # Bad - Hard to maintain {config, lib, pkgs, ...}: { options.m3ta.cli = { tool1 = mkEnableOption "tool1"; tool2 = mkEnableOption "tool2"; # ... many more }; config = mkMerge [ (mkIf config.m3ta.cli.tool1.enable {...}) (mkIf config.m3ta.cli.tool2.enable {...}) # ... many more ]; } ``` **Solution**: Organize by category ```nix # Good - modules/home-manager/cli/ # modules/home-manager/cli/default.nix { imports = [ ./tool1.nix ./tool2.nix ]; } ``` ### Hardcoded Ports **Bad**: Hardcoding ports in services ```nix # Bad services.nginx = { enable = true; httpConfig = '' server { listen 80; } ''; }; ``` **Solution**: Use port management ```nix # Good m3ta.ports = { enable = true; definitions = {nginx = 80;}; }; services.nginx = { enable = true; httpConfig = '' server { listen ${toString (config.m3ta.ports.get "nginx")}; } ''; }; ``` ### Skipping Meta Fields **Bad**: Incomplete meta information ```nix # Bad meta = { description = "My package"; }; ``` **Solution**: Include all fields ```nix # Good meta = with lib; { description = "My awesome package"; homepage = "https://github.com/author/package"; license = licenses.mit; platforms = platforms.linux; mainProgram = "program-name"; }; ``` ### with pkgs; in Modules **Bad**: Using `with pkgs;` at module level ```nix # Bad {config, lib, pkgs, ...}: with pkgs; { config.environment.systemPackages = [ vim git ]; } ``` **Solution**: Explicit package references or limited with ```nix # Good - Explicit references {config, lib, pkgs, ...}: { config.environment.systemPackages = with pkgs; [ vim git ]; } # Or - Full references {config, lib, pkgs, ...}: { config.environment.systemPackages = [ pkgs.vim pkgs.git ]; } ``` ### Orphaned Package Directories **Bad**: Creating directory without registering ```nix # Bad - Package not visible # pkgs/my-package/default.nix exists # But pkgs/default.nix doesn't reference it ``` **Solution**: Register in `pkgs/default.nix` ```nix # Good { inherit (pkgs) callPackage; } rec { my-package = callPackage ./my-package {}; } ``` ## Type Safety ### No Type Suppression **Bad**: Using `as any` ```nix # Bad let value = someFunction config as any; in # ... ``` **Solution**: Fix underlying type issues ```nix # Good let value = someFunction config; in # Ensure value has correct type ``` ### Proper Type Definitions ```nix # Good options.m3ta.myModule = { enable = mkEnableOption "my module"; port = mkOption { type = types.port; default = 8080; description = "Port to run on"; }; }; ``` ## Naming Conventions ### Package Names **Good**: `lowercase-hyphen` ```nix code2prompt hyprpaper-random launch-webapp ``` **Bad**: CamelCase or underscores ```nix code2Prompt # Bad hyprpaper_random # Bad ``` ### Variables **Good**: `camelCase` ```nix portHelpers configFile serviceName ``` **Bad**: Snake_case or kebab-case ```nix port_helpers # Bad port-helpers # Bad ``` ### Module Options **Good**: `m3ta.*` namespace ```nix m3ta.ports.enable = true; m3ta.cli.zellij-ps.enable = true; ``` **Bad**: Flat namespace ```nix ports.enable = true; # Potential conflict cli.zellij-ps.enable = true; # Hard to find ``` ## Performance ### Lazy Evaluation **Good**: Use `callPackage` ```nix # Good - Only builds requested package code2prompt = callPackage ./code2prompt {}; ``` **Bad**: Building all packages ```nix # Bad - Builds everything even if not used code2prompt = import ./code2prompt {}; ``` ### Selective Imports **Good**: Import only needed modules ```nix # Good imports = [ m3ta-nixpkgs.nixosModules.mem0 ]; ``` **Bad**: Importing all modules ```nix # Bad - Imports and evaluates all modules imports = [ m3ta-nixpkgs.nixosModules.default ]; ``` ## Security ### No Secrets in Store **Bad**: Putting secrets in configuration ```nix # Bad - Secret in Nix store m3ta.mem0.llm.apiKey = "sk-xxx"; ``` **Solution**: Use secret files ```nix # Good - Secret from file m3ta.mem0.llm.apiKeyFile = "/run/secrets/openai-api-key"; ``` ### Proper User/Group **Good**: Dedicated users for services ```nix # Good users.users.mem0 = { isSystemUser = true; group = "mem0"; }; ``` ### Service Hardening **Good**: Enable systemd hardening ```nix # Good systemd.services.mem0.serviceConfig = { NoNewPrivileges = true; PrivateTmp = true; ProtectSystem = "strict"; ProtectHome = true; }; ``` ## Best Practices Summary | Practice | Do | Don't | |----------|-----|--------| | Hash fetching | Get real hash from build error | Commit `lib.fakeHash` | | Module organization | Categorize by function | Put all in one file | | Port management | Use `m3ta.ports` module | Hardcode ports | | Meta fields | Include all fields | Skip fields | | Type safety | Fix type errors | Use `as any` | | Dependencies | Explicit declarations | Implicit deps | | Imports | Multi-line, trailing comma | Single-line, no comma | | Naming | Follow conventions | Mix styles | | Secrets | Use file-based | Put in config | | Evaluation | Lazy (`callPackage`) | Import everything | ## Related - [Contributing Guide](../CONTRIBUTING.md) - Code style and guidelines - [Architecture](../ARCHITECTURE.md) - Understanding repository structure - [Adding Packages](../guides/adding-packages.md) - Package creation patterns