- 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)
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
callPackagepattern 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 nixpkgsadditions: Individual package additionsmodifications: 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
callPackagefor dependencies - Always include
metawith 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 utilitiescoding/: 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 targetaarch64-linux- ARM Linuxx86_64-darwin- macOS Intelaarch64-darwin- macOS Apple Silicon
Note: Some packages may be Linux-only (check meta.platforms).