Files
nixpkgs/docs/ARCHITECTURE.md
m3tm3re 44485c4c72 docs: update zellij-ps to reflect project switcher functionality
- Update package description and fix mainProgram typo
- Rewrite documentation to describe project switching, not process viewing
- Add PROJECT_FOLDERS configuration and usage examples
- Update all references across docs (README, guides, module overviews)
2025-12-30 15:42:52 +01:00

10 KiB

Architecture

Understanding the design and structure of m3ta-nixpkgs.

Overview

m3ta-nixpkgs is organized as a modern Nix flake with a focus on reusability, consistency, and maintainability. The repository follows clear conventions and patterns to make it easy to understand, extend, and contribute to.

Repository Structure

m3ta-nixpkgs/
├── flake.nix              # Main entry point, defines all outputs
├── pkgs/                  # Custom packages (callPackage registry)
│   ├── default.nix        # Package registry (entry point)
│   ├── code2prompt/       # Individual packages
│   ├── hyprpaper-random/
│   ├── mem0/
│   └── ...
├── modules/
│   ├── nixos/             # NixOS modules
│   │   ├── default.nix    # Module aggregator
│   │   ├── mem0.nix
│   │   └── ports.nix
│   └── home-manager/      # Home Manager modules
│       ├── default.nix    # Module aggregator
│       ├── ports.nix
│       ├── cli/           # Categorized modules
│       │   ├── default.nix
│       │   └── zellij-ps.nix
│       └── coding/
│           ├── default.nix
│           └── editors.nix
├── lib/                   # Shared utilities
│   ├── default.nix        # Library aggregator
│   └── ports.nix          # Port management functions
├── shells/                # Development environments
│   ├── default.nix        # Shell registry
│   ├── python.nix
│   └── devops.nix
├── overlays/              # Package modifications
│   ├── default.nix        # Overlay aggregator
│   └── mods/
│       └── default.nix    # Individual overlays
├── templates/             # Boilerplate for new items
│   ├── package/
│   ├── nixos-module/
│   └── home-manager-module/
├── examples/              # Usage examples
│   ├── nixos-configuration.nix
│   └── home-manager-standalone.nix
└── docs/                  # Documentation

Flake Outputs

flake.nix is the entry point that defines all outputs:

Packages

packages = forAllSystems (system: let
  pkgs = pkgsFor system;
in
  import ./pkgs {inherit pkgs;});
  • Built for all supported systems
  • Uses callPackage pattern for lazy evaluation
  • Available via nix build .#<package-name>

Overlays

overlays = {
  # Default overlay: adds all custom packages
  default = final: prev: import ./pkgs {pkgs = final;};

  # Additions overlay: same as default
  additions = final: prev: import ./pkgs {pkgs = final;};

  # Modifications overlay: modifies existing nixpkgs packages
  modifications = final: prev: import ./overlays/mods {inherit prev;};
};
  • default: Adds all custom packages to nixpkgs
  • additions: Individual package additions
  • modifications: Overrides existing packages

NixOS Modules

nixosModules = {
  default = ./modules/nixos;  # Import all modules
  ports = ./modules/nixos/ports.nix;  # Specific module
  mem0 = ./modules/nixos/mem0.nix;
};
  • System-level configuration modules
  • Use m3ta.* namespace
  • Can import all modules or individual ones

Home Manager Modules

homeManagerModules = {
  default = import ./modules/home-manager;
  ports = import ./modules/home-manager/ports.nix;
  zellij-ps = import ./modules/home-manager/zellij-ps.nix;
};
  • User-level configuration modules
  • Categorized by function (cli, coding)
  • Use m3ta.* namespace

Library Functions

lib = forAllSystems (system: let
  pkgs = pkgsFor system;
in
  import ./lib {lib = pkgs.lib;});
  • Helper functions for configuration
  • Port management utilities
  • Can be used in your configurations

Development Shells

devShells = forAllSystems (system: let
  pkgs = pkgsFor system;
in
  import ./shells {inherit pkgs;});
  • Pre-configured development environments
  • Available: default, python, devops
  • Usage: nix develop .#<shell-name>

Templates

templates = {
  package = {
    path = ./templates/package;
    description = "Template for a new package";
  };
  nixos-module = {
    path = ./templates/nixos-module;
    description = "Template for a new NixOS module";
  };
  home-manager-module = {
    path = ./templates/home-manager-module;
    description = "Template for a new Home Manager module";
  };
};
  • Boilerplate for quick start
  • Usage: nix flake init -t .#template-name

Package Organization

Registry Pattern

pkgs/default.nix acts as a central registry:

{
  inherit (pkgs) callPackage;
} rec {
  code2prompt = callPackage ./code2prompt {};
  hyprpaper-random = callPackage ./hyprpaper-random {};
  mem0 = callPackage ./mem0 {};
  # ...
}

Benefits:

  • Lazy evaluation: only builds requested packages
  • Consistent interface: all packages use callPackage
  • Easy discovery: one file lists all packages

Package Structure

Each package lives in its own directory:

pkgs/your-package/
├── default.nix    # Package definition
├── source.py      # Optional: source files
└── README.md      # Optional: package documentation

Conventions:

  • Directory name matches registry attribute
  • Use callPackage for dependencies
  • Always include meta with all fields

Common Package Patterns

Rust Packages

rustPlatform.buildRustPackage rec {
  pname = "myapp";
  version = "1.0.0";
  src = fetchFromGitHub { ... };
  cargoLock.lockFile = src + "/Cargo.lock";
  # ...
}

Python Packages

python3.pkgs.buildPythonPackage rec {
  pname = "mypythonapp";
  version = "1.0.0";
  src = fetchFromGitHub { ... };
  dependencies = with python3.pkgs; [requests click];
  # ...
}

Shell Scripts

writeShellScriptBin "myscript" ''
  #!/usr/bin/env bash
  echo "Hello World"
''

AppImage

appimageTools.wrapType2 rec {
  name = "myapp";
  src = fetchurl { ... };
  # ...
}

Module Organization

NixOS Modules

Located in modules/nixos/:

modules/nixos/
├── default.nix    # Imports all modules
├── ports.nix      # Port management
├── mem0.nx        # Individual module

Pattern:

{config, lib, pkgs, ...}:
with lib; let
  cfg = config.m3ta.myModule;
in {
  options.m3ta.myModule = {
    enable = mkEnableOption "description";
    # ... options
  };

  config = mkIf cfg.enable {
    # ... configuration
  };
}

Home Manager Modules

Located in modules/home-manager/ with categories:

modules/home-manager/
├── default.nix      # Imports all modules
├── ports.nix       # Port management
├── cli/
│   ├── default.nix # Aggregates CLI modules
│   └── zellij-ps.nix
└── coding/
    ├── default.nix # Aggregates coding modules
    └── editors.nix

Categories:

  • cli/: Command-line tools and utilities
  • coding/: Development tools and editors

Pattern (same as NixOS):

{config, lib, pkgs, ...}:
with lib; let
  cfg = config.m3ta.coding.editors;
in {
  options.m3ta.coding.editors = {
    enable = mkEnableOption "editor configuration";
    # ... options
  };

  config = mkIf cfg.enable {
    # ... configuration
  };
}

Library Functions

Located in lib/:

{lib}: {
  # Port management utilities
  ports = import ./ports.nix {inherit lib;};
}

Port Management

Centralized port management across hosts:

# Usage in configuration
portHelpers = inputs.m3ta-nixpkgs.lib.${system}.ports.mkPortHelpers myPorts;

# Get port with host override
services.nginx.port = portHelpers.getPort "nginx" "laptop";

# Get all ports for host
allLaptopPorts = portHelpers.getHostPorts "laptop";

Benefits:

  • Single source of truth for ports
  • Host-specific overrides
  • Avoid port conflicts

Naming Conventions

Context Convention Example
Packages lowercase-hyphen hyprpaper-random
Variables camelCase portHelpers
Module options m3ta.* m3ta.ports.enable
Files lowercase-hyphen my-module.nix
Directories lowercase-hyphen cli/, coding/

Code Patterns

Module Options

Always use mkEnableOption for enable flags:

options.m3ta.myModule = {
  enable = mkEnableOption "description";
};

Conditional Configuration

Use mkIf for conditional config:

config = mkIf cfg.enable {
  # Only applied when cfg.enable is true
};

Multiple Conditions

Use mkMerge for multiple conditions:

config = mkMerge [
  (mkIf cfg.feature1.enable { ... })
  (mkIf cfg.feature2.enable { ... })
];

Imports

Multi-line, trailing commas:

{
  lib,
  stdenv,
  fetchFromGitHub,
}:

Meta Fields

Always include all fields:

meta = with lib; {
  description = "...";
  homepage = "...";
  license = licenses.mit;
  platforms = platforms.linux;
  mainProgram = "program-name";
};

Design Decisions

Flakes-Only

Decision: Use flakes exclusively, no channels.

Rationale:

  • Reproducible builds
  • Explicit dependencies
  • Better integration with modern Nix tooling

CallPackage Pattern

Decision: Use callPackage for all packages.

Rationale:

  • Lazy evaluation
  • Clear dependency graph
  • Consistent interface

Module Categorization

Decision: Categorize Home Manager modules by function.

Rationale:

  • Easier to find related modules
  • Logical organization
  • Follows user mental model

Port Management

Decision: Centralized port management with host overrides.

Rationale:

  • Avoid port conflicts
  • Easy to manage multiple hosts
  • Single source of truth

Namespace Convention

Decision: Use m3ta.* namespace for all modules.

Rationale:

  • Avoid conflicts
  • Clear attribution
  • Easy to discover

Supported Systems

  • x86_64-linux - Primary development target
  • aarch64-linux - ARM Linux
  • x86_64-darwin - macOS Intel
  • aarch64-darwin - macOS Apple Silicon

Note: Some packages may be Linux-only (check meta.platforms).