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)
This commit is contained in:
m3tm3re
2025-12-30 15:42:52 +01:00
parent 744b6a8243
commit 44485c4c72
28 changed files with 8096 additions and 24 deletions

View File

@@ -0,0 +1,493 @@
# Adding Packages Guide
How to add new packages to m3ta-nixpkgs.
## Overview
Packages in m3ta-nixpkgs are organized using a `callPackage` registry pattern. Each package lives in its own directory and is registered centrally.
## Quick Start
### Using Templates
Use the package template for quick setup:
```bash
nix flake init -t .#package my-new-package
```
This creates a template structure in `templates/package/` that you can copy.
### Manual Setup
1. Create directory: `pkgs/your-package/`
2. Write `default.nix` with package definition
3. Register in `pkgs/default.nix`
## Package Structure
```
pkgs/your-package/
├── default.nix # Package definition (required)
├── source.py # Optional: additional source files
├── wrapper.sh # Optional: wrapper scripts
└── README.md # Optional: package documentation
```
## Common Patterns
### Rust Package
```nix
{
lib,
rustPlatform,
fetchFromGitHub,
}:
rustPlatform.buildRustPackage rec {
pname = "my-rust-app";
version = "1.0.0";
src = fetchFromGitHub {
owner = "author";
repo = "my-rust-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
cargoLock.lockFile = src + "/Cargo.lock";
buildInputs = [openssl];
nativeBuildInputs = [pkg-config];
meta = with lib; {
description = "My Rust application";
homepage = "https://github.com/author/my-rust-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-rust-app";
};
}
```
### Python Package
```nix
{
lib,
python3,
fetchFromGitHub,
}:
python3.pkgs.buildPythonPackage rec {
pname = "my-python-app";
version = "1.0.0";
pyproject = true;
src = fetchFromGitHub {
owner = "author";
repo = "my-python-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
build-system = with python3.pkgs; [setuptools];
dependencies = with python3.pkgs; [
requests
click
];
optional-dependencies = with python3.pkgs; {
extras = [pyyaml];
};
doCheck = true;
pythonImportsCheck = ["myapp"];
meta = with lib; {
description = "My Python application";
homepage = "https://github.com/author/my-python-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-app";
};
}
```
### Shell Script Package
```nix
{
lib,
writeShellScriptBin,
}:
writeShellScriptBin "my-script" ''
#!/usr/bin/env bash
set -euo pipefail
echo "Hello from my script!"
# Your script logic here
''
# If you need to add dependencies
{
lib,
writeShellApplication,
bash,
curl,
}:
writeShellApplication {
name = "my-script";
runtimeInputs = [bash curl];
text = ''
#!/usr/bin/env bash
set -euo pipefail
curl -s https://example.com
'';
}
```
### AppImage Package
```nix
{
lib,
appimageTools,
fetchurl,
}:
appimageTools.wrapType2 rec {
name = "my-app";
version = "1.0.0";
src = fetchurl {
url = "https://github.com/author/my-app/releases/download/v${version}/My-App-${version}.AppImage";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
meta = with lib; {
description = "My AppImage application";
homepage = "https://github.com/author/my-app";
license = licenses.unfree;
platforms = platforms.linux;
mainProgram = name;
};
}
```
### Custom Source with Patch
```nix
{
lib,
stdenv,
fetchFromGitHub,
fetchpatch,
buildGoModule,
}:
buildGoModule rec {
pname = "my-go-app";
version = "1.0.0";
src = fetchFromGitHub {
owner = "author";
repo = "my-go-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
patches = [
# Add local patch
./fix-build.patch
# Add patch from URL
(fetchpatch {
url = "https://github.com/author/my-app/pull/123.patch";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
})
];
vendorHash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
meta = with lib; {
description = "My Go application";
homepage = "https://github.com/author/my-go-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-app";
};
}
```
### Package with Custom Installation
```nix
{
lib,
stdenv,
fetchFromGitHub,
makeWrapper,
}:
stdenv.mkDerivation rec {
pname = "my-app";
version = "1.0.0";
src = fetchFromGitHub {
owner = "author";
repo = "my-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
nativeBuildInputs = [makeWrapper];
buildPhase = ''
make build
'';
installPhase = ''
install -Dm755 my-app $out/bin/my-app
# Wrap with runtime dependencies
wrapProgram $out/bin/my-app \
--prefix PATH : ${lib.makeBinPath [some-dep]}
'';
meta = with lib; {
description = "My custom application";
homepage = "https://github.com/author/my-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-app";
};
}
```
## Registration
### Register in `pkgs/default.nix`
Add your package to the registry:
```nix
{
inherit (pkgs) callPackage;
} rec {
# Existing packages
code2prompt = callPackage ./code2prompt {};
zellij-ps = callPackage ./zellij-ps {};
# Your new package
my-new-package = callPackage ./my-new-package {};
}
```
### With Custom Arguments
If your package needs custom arguments:
```nix
# pkgs/default.nix
{
inherit (pkgs) callPackage;
} rec {
my-new-package = callPackage ./my-new-package {
customArg = "value";
};
}
# pkgs/my-new-package/default.nix
{
lib,
stdenv,
fetchurl,
customArg, # This will be passed from the registry
}:
stdenv.mkDerivation {
# ...
}
```
## Getting Hashes
### Using `lib.fakeHash`
During development, use `lib.fakeHash` to get the real hash:
```nix
src = fetchFromGitHub {
owner = "author";
repo = "my-app";
rev = "v${version}";
hash = lib.fakeHash; # Temporary placeholder
};
```
Build the package:
```bash
nix build .#my-new-package
```
Copy the actual hash from the error message and update the package:
```nix
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Real hash
```
**Important**: Never commit `lib.fakeHash` to the repository.
## Testing
### Build Package
```bash
nix build .#my-new-package
```
### Test Execution
```bash
nix run .#my-new-package -- --help
```
### Run in Shell
```bash
nix shell .#my-new-package
my-new-app --version
```
### Linting
```bash
nix develop
statix check pkgs/my-new-package/
```
## Best Practices
### Meta Fields
Always include complete `meta` information:
```nix
meta = with lib; {
description = "Short one-line description";
longDescription = ''
Longer description explaining what the package does,
its features, and use cases.
'';
homepage = "https://github.com/author/repo";
changelog = "https://github.com/author/repo/releases/tag/v${version}";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "program-name";
};
```
### Dependencies
Explicitly declare all dependencies:
```nix
{
lib,
stdenv,
fetchFromGitHub,
# Runtime dependencies
openssl,
curl,
# Native build dependencies
pkg-config,
cmake,
}:
```
### Versioning
Use `rec` to reference `version` in multiple places:
```nix
rec {
pname = "my-app";
version = "1.0.0";
src = fetchFromGitHub {
rev = "v${version}";
# ...
};
}
```
### Platform Restrictions
If package is platform-specific:
```nix
meta = with lib; {
# Linux only
platforms = platforms.linux;
# Or specific platforms
platforms = ["x86_64-linux" "aarch64-linux"];
# Or exclude platforms
broken = stdenv.isDarwin;
};
```
## Troubleshooting
### Hash Mismatch
Error: `got: sha256-AAAAAAAA... expected: sha256-BBBBBB...`
Solution: Copy `got` hash and update package definition.
### Dependency Not Found
Error: `error: undefined variable 'somedep'`
Solution: Add dependency to function arguments and build inputs:
```nix
{
lib,
somedep, # Add here
}:
stdenv.mkDerivation {
buildInputs = [somedep]; # Add here
}
```
### Import Check Failure
Error: `error: Python module 'mymodule' not found`
Solution: Disable or fix imports check:
```nix
pythonImportsCheck = ["mymodule"]; # Check this is correct
# Or if importing creates side effects:
pythonImportsCheck = [];
```
## Examples
See existing packages in the repository:
- `pkgs/code2prompt/` - Rust package
- `pkgs/mem0/` - Python package
- `pkgs/hyprpaper-random/` - Shell script
- `pkgs/msty-studio/` - AppImage
- `pkgs/zellij-ps/` - Fetch from Gitea
## Next Steps
- [Architecture](../ARCHITECTURE.md) - Understanding package organization
- [Using Modules](./using-modules.md) - If you need to create modules
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines

View File

@@ -0,0 +1,527 @@
# Development Workflow Guide
Development, testing, and contribution workflow for m3ta-nixpkgs.
## Initial Setup
### Clone Repository
```bash
git clone https://code.m3ta.dev/m3tam3re/nixpkgs.git
cd nixpkgs
```
### Enter Development Shell
```bash
# Default shell (includes linting tools)
nix develop
# Python shell
nix develop .#python
# DevOps shell
nix develop .#devops
```
### Development Shell Tools
The default dev shell includes:
- `statix` - Nix linter
- `deadnix` - Find dead code
- `alejandra` - Code formatter
## Workflow
### 1. Create Feature Branch
```bash
# Checkout main and pull latest
git checkout main
git pull
# Create feature branch
git checkout -b feature/my-new-package
```
### 2. Make Changes
```bash
# Create new package
mkdir -p pkgs/my-package
vim pkgs/my-package/default.nix
# Or modify existing package
vim pkgs/existing-package/default.nix
# Or add module
vim modules/nixos/my-module.nix
```
### 3. Format Code
```bash
# Format all files
nix fmt
# Format specific file
alejandra path/to/file.nix
```
**Always format before committing.**
### 4. Test Changes
#### Build Package
```bash
# Build specific package
nix build .#my-package
# Build all packages
nix build .#packages.x86_64-linux
```
#### Run Package
```bash
# Test if package runs
nix run .#my-package -- --help
# Or enter shell with package
nix shell .#my-package
my-package --version
```
#### Validate Flake
```bash
# Validate all outputs
nix flake check
# Show all outputs
nix flake show
```
#### Test Module
```bash
# Test NixOS configuration
sudo nixos-rebuild test --flake .#hostname
# Test Home Manager configuration
home-manager switch --flake .#username@hostname
```
### 5. Lint Code
```bash
# Enter dev shell for linting tools
nix develop
# Run statix
statix check .
# Run deadnix
deadnix .
# Fix auto-fixable issues
statix fix .
```
### 6. Commit Changes
```bash
# Stage changes
git add .
# Commit with conventional format
git commit -m "feat: add my-package for doing X"
# Commit types: feat, fix, docs, style, refactor, chore, test
```
### 7. Push and Create PR
```bash
# Push branch
git push origin feature/my-new-package
# Create PR via web interface or CLI
gh pr create --title "feat: add my-package" --body "Description of changes"
```
## Testing Strategies
### Local Testing
#### Test Package Build
```bash
# Build for current system
nix build .#my-package
# Build for specific system
nix build .#my-package --system aarch64-linux
# Build for macOS
nix build .#my-package --system x86_64-darwin
```
#### Test Package Functionality
```bash
# Enter shell with package
nix shell .#my-package
# Run the program
my-package --help
my-package --version
# Test with sample data
echo "test" | my-package
```
#### Test Configuration
```bash
# Test NixOS configuration
sudo nixos-rebuild test --flake .#hostname
# Test Home Manager configuration
home-manager switch --flake .#username@hostname
# Check configuration syntax
nix eval .#nixosConfigurations.hostname.config --apply builtins.attrNames
```
### Integration Testing
#### Test with Real Services
```bash
# If package is a service
# 1. Add to configuration
# 2. Apply configuration
sudo nixos-rebuild switch
# 3. Test service
systemctl status my-service
journalctl -u my-service -f
# 4. Test functionality
curl http://localhost:8080
```
#### Test with Dependencies
```bash
# Build dependency chain
nix build .#my-package \
--rebuild \
--keep-going
# Check if dependencies are satisfied
nix path-info .#my-package --references
```
## Continuous Integration
### Pre-Commit Hook
Create `.git/hooks/pre-commit`:
```bash
#!/usr/bin/env bash
set -euo pipefail
# Format code
nix fmt
# Lint
statix check .
deadnix .
# Validate
nix flake check
# Test build
nix build .#your-package
```
Make executable:
```bash
chmod +x .git/hooks/pre-commit
```
### Pre-Push Hook
Create `.git/hooks/pre-push`:
```bash
#!/usr/bin/env bash
set -euo pipefail
# Validate flake
nix flake check
# Run tests if they exist
# make test
```
## Debugging
### Build Failures
#### Hash Mismatch
Error: `got: sha256-AAAAAAAA... expected: sha256-BBBBBB...`
Solution: Copy the `got` hash and update package:
```nix
src = fetchFromGitHub {
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Use actual hash
};
```
#### Dependency Not Found
Error: `error: undefined variable 'somelib'`
Solution: Check function arguments:
```nix
{
lib,
stdenv,
fetchFromGitHub,
somelib, # Add this if missing
}:
```
#### Build Failed
Error: `builder for '/nix/store/...' failed`
Solution:
```bash
# Build with verbose output
nix build .#my-package -v --show-trace
# Check build logs
nix log .#my-package
# Enter build environment for debugging
nix shell -f .#my-package .bashInteractive
```
### Runtime Failures
#### Package Not Executable
Error: `error: operation not permitted`
Solution: Check `mainProgram` in meta:
```nix
meta = with lib; {
mainProgram = "my-app"; # Must match executable name
};
```
#### Library Not Found
Error: `error while loading shared libraries: libfoo.so`
Solution: Add to build inputs:
```nix
buildInputs = [someLib];
```
### Configuration Failures
#### Option Not Found
Error: `error: The option 'm3ta.mymodule' does not exist`
Solution: Import the module:
```nix
imports = [
m3ta-nixpkgs.nixosModules.default
];
```
## Common Tasks
### Update Package Version
```bash
# 1. Update version in package definition
vim pkgs/my-package/default.nix
# 2. Build to get new hash
nix build .#my-package
# 3. Update hash from error message
# 4. Test new version
nix run .#my-package -- --version
# 5. Commit
git commit -m "chore: update my-package to v2.0.0"
```
### Update Dependencies
```bash
# 1. Update fetcher version/rev
vim pkgs/my-package/default.nix
# 2. Update dependencies if needed
vim pkgs/my-package/default.nix
# 3. Build and test
nix build .#my-package
nix run .#my-package -- --help
# 4. Commit
git commit -m "fix: update dependencies for my-package"
```
### Add Tests
```bash
# 1. Add test to package
vim pkgs/my-package/default.nix
# 2. Run tests
nix build .#my-package
# 3. Verify tests pass
# 4. Commit
git commit -m "test: add tests for my-package"
```
### Fix Linting Issues
```bash
# 1. Run linter
nix develop
statix check .
# 2. Fix issues manually or auto-fix
statix fix .
# 3. Check again
statix check .
# 4. Commit
git commit -m "style: fix linting issues"
```
## Performance Optimization
### Use Caching
```bash
# Use binary cache (if available)
nix build .#my-package --substituters https://cache.nixos.org https://your-cache.example.com
# Use local cache
nix build .#my-package --max-jobs 4
```
### Parallel Builds
```bash
# Build multiple packages in parallel
nix build .#package1 .#package2 .#package3
```
### Incremental Builds
```bash
# Only rebuild changed packages
nix build .#my-package --check
# Don't rebuild dependencies
nix build .#my-package --no-link
```
## Release Process
### Version Bump
```bash
# 1. Update versions as needed
vim pkgs/*/default.nix
# 2. Update CHANGELOG.md
vim CHANGELOG.md
# 3. Test all packages
nix flake check
# 4. Commit
git commit -m "chore: prepare release v1.0.0"
```
### Tag Release
```bash
# Create tag
git tag -a v1.0.0 -m "Release v1.0.0"
# Push tag
git push origin v1.0.0
# Push with tags
git push --follow-tags
```
### Update Flakes
Update flake lock after release:
```bash
# Update lock file
nix flake update
# Commit
git commit -m "chore: update flake lock"
```
## Checklist
### Before Committing
- [ ] Code formatted with `nix fmt`
- [ ] Passes `statix check .`
- [ ] Passes `deadnix .`
- [ ] Passes `nix flake check`
- [ ] Package builds successfully
- [ ] Package runs as expected
- [ ] Documentation updated (if needed)
- [ ] Commit message follows convention
### Before Merging PR
- [ ] All tests pass
- [ ] Code review approved
- [ ] No merge conflicts
- [ ] Documentation complete
- [ ] Breaking changes documented
## Resources
- [Contributing Guide](../CONTRIBUTING.md) - Code style and guidelines
- [Architecture](../ARCHITECTURE.md) - Understanding repository structure
- [Adding Packages](./adding-packages.md) - Package creation guide
- [Quick Start](../QUICKSTART.md) - Getting started guide

View File

@@ -0,0 +1,402 @@
# Getting Started Guide
Initial setup and basic usage of m3ta-nixpkgs.
## Installation
### Prerequisites
Make sure you have Nix installed with flakes enabled:
```bash
# Check Nix version (need 2.4+)
nix --version
# Enable flakes (in /etc/nixos/configuration.nix)
nix.settings.experimental-features = ["nix-command" "flakes"]
# Rebuild NixOS
sudo nixos-rebuild switch
```
### Adding to Your Flake
#### Option 1: NixOS Configuration
Add to your `flake.nix`:
```nix
{
description = "My NixOS configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
home-manager,
m3ta-nixpkgs,
...
}: {
nixosConfigurations = {
myhost = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./hardware-configuration.nix
# Import m3ta-nixpkgs modules
m3ta-nixpkgs.nixosModules.default
# Apply overlay
({pkgs, ...}: {
nixpkgs.overlays = [m3ta-nixpkgs.overlays.default];
# Packages from m3ta-nixpkgs are now available
environment.systemPackages = with pkgs; [
code2prompt
zellij-ps
];
})
# Home Manager integration
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.myusername = {
imports = [m3ta-nixpkgs.homeManagerModules.default];
home.packages = with pkgs; [
launch-webapp
];
};
}
];
};
};
};
}
```
#### Option 2: Standalone Home Manager
```nix
{
description = "My Home Manager configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
home-manager,
m3ta-nixpkgs,
}: let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
overlays = [m3ta-nixpkgs.overlays.default];
};
in {
homeConfigurations.myusername = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
modules = [
m3ta-nixpkgs.homeManagerModules.default
{
home.username = "myusername";
home.homeDirectory = "/home/myusername";
home.packages = with pkgs; [
code2prompt
zellij-ps
];
programs.home-manager.enable = true;
}
];
};
};
}
```
## Quick Usage
### Using Packages Directly
Without adding to your configuration:
```bash
# Build a package
nix build git+https://code.m3ta.dev/m3tam3re/nixpkgs#code2prompt
# Run a package
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
# List all available packages
nix flake show git+https://code.m3ta.dev/m3tam3re/nixpkgs
```
### Using Packages in Configuration
After applying overlay:
```nix
# System-wide (NixOS)
environment.systemPackages = with pkgs; [
code2prompt
zellij-ps
];
# User-only (Home Manager)
home.packages = with pkgs; [
launch-webapp
];
```
### Using Modules
```nix
# Import all modules
imports = [
m3ta-nixpkgs.nixosModules.default
];
# Or import specific module
imports = [
m3ta-nixpkgs.nixosModules.mem0
];
# Configure module
m3ta.mem0 = {
enable = true;
port = 8000;
};
```
## Common Tasks
### Install a Package System-Wide
```nix
# /etc/nixos/configuration.nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
code2prompt
hyprpaper-random
];
}
# Apply
sudo nixos-rebuild switch
```
### Install a Package for Your User
```nix
# home.nix
{pkgs, ...}: {
home.packages = with pkgs; [
launch-webapp
zellij-ps
];
}
# Apply
home-manager switch
```
### Enable a NixOS Module
```nix
# /etc/nixos/configuration.nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
m3ta.mem0 = {
enable = true;
port = 8000;
};
# Apply
# sudo nixos-rebuild switch
}
```
### Enable a Home Manager Module
```nix
# home.nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
m3ta.cli.zellij-ps = {
enable = true;
};
# Apply
# home-manager switch
}
```
### Use Port Management
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
hostOverrides.laptop = {
nginx = 8080;
};
currentHost = config.networking.hostName;
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
}
```
## Available Packages
| Package | Description |
| ------------------ | ------------------------------------- |
| `code2prompt` | Convert code to prompts |
| `hyprpaper-random` | Random wallpaper setter for Hyprpaper |
| `launch-webapp` | Launch web applications |
| `mem0` | AI memory assistant with vector storage |
| `msty-studio` | Msty Studio application |
| `pomodoro-timer` | Pomodoro timer utility |
| `tuxedo-backlight` | Backlight control for Tuxedo laptops |
| `zellij-ps` | Project switcher for Zellij |
## Available Modules
### NixOS Modules
- `ports` - Port management across hosts
- `mem0` - Mem0 REST API server
### Home Manager Modules
- `ports` - Port management (with `generateEnvVars`)
- `cli.zellij-ps` - Zellij project switcher
- `coding.editors` - Editor configurations
## Development
### Development Shells
```bash
# Default dev shell
nix develop
# Python dev shell
nix develop .#python
# DevOps dev shell
nix develop .#devops
```
### Building and Testing
```bash
# Build package
nix build .#code2prompt
# Validate flake
nix flake check
# List outputs
nix flake show
# Format code
nix fmt
```
### Linting (in dev shell)
```bash
nix develop
# Run linter
statix check .
# Find dead code
deadnix .
```
## Troubleshooting
### Package Not Found
**Error**: `error: undefined variable 'code2prompt'`
**Solution**: Make sure you applied the overlay:
```nix
nixpkgs.overlays = [m3ta-nixpkgs.overlays.default];
```
### Module Not Found
**Error**: `error: The option 'm3ta.mem0' does not exist`
**Solution**: Make sure you imported the module:
```nix
imports = [
m3ta-nixpkgs.nixosModules.default
# or
m3ta-nixpkgs.nixosModules.mem0
];
```
### Hash Mismatch
**Error**: `got: sha256-AAAAAAAA... expected: sha256-BBBBBB...`
**Solution**: Copy the `got` hash from the error and update the package definition.
### Building for Different System
```bash
# Build for aarch64-linux
nix build .#code2prompt --system aarch64-linux
# Build for macOS
nix build .#code2prompt --system x86_64-darwin
```
## Next Steps
- [Adding Packages](./adding-packages.md) - How to add new packages
- [Using Modules](./using-modules.md) - Deep dive into modules
- [Port Management](./port-management.md) - Managing service ports
- [Architecture](../ARCHITECTURE.md) - Understanding the repository structure

View File

@@ -0,0 +1,525 @@
# Port Management Guide
Managing service ports across multiple hosts with the `m3ta.ports` module.
## Overview
The port management module provides a centralized way to define service ports that can have host-specific overrides. This prevents port conflicts and makes it easy to manage services across multiple machines.
## Basic Usage
### Enable Port Management
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
# Define default ports
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
homepage = 8080;
};
# Define host-specific overrides
hostOverrides = {
laptop = {
nginx = 8080; # Override on laptop
homepage = 3001; # Override on laptop
};
server = {
homepage = 3002; # Override on server
};
};
# Set current host (determines which overrides to use)
currentHost = config.networking.hostName;
};
}
```
### Using Ports
```nix
{config, ...}: {
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
}
```
## Module Options
### `m3ta.ports.enable`
Enable port management module.
- Type: `boolean`
- Default: `false`
### `m3ta.ports.definitions`
Default port definitions.
- Type: `attrsOf int`
- Default: `{}`
```nix
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
};
```
### `m3ta.ports.hostOverrides`
Host-specific port overrides.
- Type: `attrsOf (attrsOf int)`
- Default: `{}`
```nix
hostOverrides = {
laptop = {
nginx = 8080;
grafana = 3001;
};
server = {
grafana = 3002;
};
};
```
### `m3ta.ports.currentHost`
Current hostname. Determines which overrides to apply.
- Type: `string`
- Example: `config.networking.hostName`
```nix
currentHost = "laptop"; # Use laptop overrides
```
### `m3ta.ports.generateEnvVars` (Home Manager only)
Generate environment variables from ports.
- Type: `boolean`
- Default: `false` (Home Manager)
- NixOS: Not available
When enabled, generates environment variables like:
- `PORT_NGINX=8080`
- `PORT_GRAFANA=3000`
## Functions
### `config.m3ta.ports.get "service"`
Get port for a service with host-specific override.
```nix
services.nginx = {
port = config.m3ta.ports.get "nginx";
};
```
If current host is `laptop` and `hostOverrides.laptop.nginx = 8080`, returns `8080`.
If no override, returns default `80`.
### `config.m3ta.ports.getHostPorts "hostname"`
Get all ports for a specific host.
```nix
# Get all ports for laptop
laptopPorts = config.m3ta.ports.getHostPorts "laptop";
# Returns: { nginx = 8080; grafana = 3000; ... }
```
### `config.m3ta.ports.listServices`
List all defined service names.
```nix
allServices = config.m3ta.ports.listServices;
# Returns: ["nginx" "grafana" "prometheus" "homepage"]
```
## Examples
### NixOS Configuration
```nix
{config, ...}: {
# Define ports
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
loki = 3100;
promtail = 9080;
};
hostOverrides.laptop = {
nginx = 8080;
grafana = 3001;
};
currentHost = config.networking.hostName;
};
# Use ports
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
services.prometheus = {
enable = true;
port = config.m3ta.ports.get "prometheus";
};
services.loki = {
enable = true;
configuration.http_listen_port = config.m3ta.ports.get "loki";
};
}
```
### Home Manager Configuration
```nix
{config, ...}: {
# Define ports
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
nextjs = 3001;
vite = 5173;
};
hostOverrides.desktop = {
vite = 5174;
};
currentHost = "desktop";
generateEnvVars = true; # Generate env vars
};
# Ports are now available as env vars
# PORT_DEV_SERVER=3000
# PORT_NEXTJS=3001
# PORT_VITE=5174
home.sessionVariables = {
DEV_PORT = toString (config.m3ta.ports.get "dev-server");
};
}
```
### With Custom Modules
Using ports with custom modules (e.g., `m3ta.mem0`):
```nix
{config, ...}: {
# Define ports
m3ta.ports = {
enable = true;
definitions = {
mem0 = 8000;
qdrant = 6333;
};
hostOverrides.laptop = {
mem0 = 8080;
};
currentHost = config.networking.hostName;
};
# Use with mem0 module
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0"; # 8000 or 8080 on laptop
};
# Use with qdrant service
services.qdrant = {
enable = true;
port = config.m3ta.ports.get "qdrant";
};
}
```
### Port File Generation
Generate a JSON file with all ports:
```nix
{config, pkgs, ...}: {
m3ta.ports = {
enable = true;
definitions = {
service1 = 80;
service2 = 443;
};
currentHost = config.networking.hostName;
};
# Generate port file
environment.etc."m3ta/ports.json".text = builtins.toJSON (
config.m3ta.ports.getHostPorts config.networking.hostName
);
}
```
## Advanced Usage
### Conditional Configuration
```nix
{config, ...}: {
services.nginx = {
enable = true;
# Only open firewall if binding to non-localhost
httpConfig = let
port = config.m3ta.ports.get "nginx";
in ''
server {
listen ${toString port};
}
'';
};
networking.firewall.allowedTCPPorts =
if config.m3ta.ports.get "nginx" == 80
then [80]
else [];
}
```
### Port Ranges
```nix
definitions = {
service-start = 8000;
service-end = 8999;
};
# Use in config
services.my-app = {
portRange = [
config.m3ta.ports.get "service-start"
config.m3ta.ports.get "service-end"
];
};
```
### Dynamic Port Allocation
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
# Reserve port ranges
app-range-start = 9000;
app-range-end = 9999;
};
currentHost = config.networking.hostName;
};
# Calculate next available port
services.my-app = {
port = config.m3ta.ports.get "app-range-start" + 0;
};
services.my-other-app = {
port = config.m3ta.ports.get "app-range-start" + 1;
};
}
```
## Best Practices
### Use Descriptive Service Names
```nix
# Good
definitions = {
nginx = 80;
grafana = 3000;
prometheus-ui = 9090;
prometheus-push = 9091;
};
# Avoid
definitions = {
p1 = 80;
p2 = 3000;
p3 = 9090;
};
```
### Group Related Services
```nix
definitions = {
# Monitoring stack
grafana = 3000;
prometheus = 9090;
loki = 3100;
promtail = 9080;
# Web services
nginx = 80;
homepage = 8080;
# Databases
postgres = 5432;
redis = 6379;
qdrant = 6333;
};
```
### Document Overrides
```nix
hostOverrides = {
# Laptop: Running multiple dev servers, use higher ports
laptop = {
nginx = 8080;
dev-server = 3000;
};
# Server: Production, use standard ports
server = {
nginx = 80;
dev-server = null; # Disable on server
};
};
```
### Handle Missing Ports
```nix
services.some-service = {
enable = true;
port = config.m3ta.ports.get "some-service" or 8080;
};
```
## Troubleshooting
### Service Not Found
Error: `Service "foo" not defined`
Solution: Add service to `definitions`:
```nix
definitions = {
foo = 8080;
};
```
### Current Host Not Set
Error: `currentHost not set`
Solution: Set `currentHost`:
```nix
currentHost = config.networking.hostName;
```
### Port Conflict
Issue: Two services trying to use same port.
Solution: Define both in port management:
```nix
definitions = {
service1 = 8080;
service2 = 8081; # Different port
};
```
## Migration from Hardcoded Ports
### Before
```nix
services.nginx = {
enable = true;
httpConfig = ''
server {
listen 80;
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = 3000;
};
```
### After
```nix
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
currentHost = config.networking.hostName;
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
```
## Next Steps
- [Architecture](../ARCHITECTURE.md) - Understanding the library functions
- [Using Modules](./using-modules.md) - Using modules with port management
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines

View File

@@ -0,0 +1,605 @@
# Using Modules Guide
How to use NixOS and Home Manager modules from m3ta-nixpkgs.
## Overview
Modules in m3ta-nixpkgs provide reusable configuration for NixOS (system-level) and Home Manager (user-level) settings. All modules use the `m3ta.*` namespace.
## Module Organization
### NixOS Modules
Located in `modules/nixos/`:
```
modules/nixos/
├── default.nix # Aggregates all NixOS modules
├── ports.nix # Port management
└── mem0.nix # Mem0 REST API server
```
### Home Manager Modules
Located in `modules/home-manager/` with categories:
```
modules/home-manager/
├── default.nix # Aggregates all HM modules
├── ports.nix # Port management
├── cli/ # CLI tools
│ ├── default.nix # Aggregates CLI modules
│ └── zellij-ps.nix
└── coding/ # Development tools
├── default.nix # Aggregates coding modules
└── editors.nix
```
## Importing Modules
### NixOS Modules
#### Import All Modules
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
}
```
#### Import Specific Module
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.mem0
];
}
```
#### Import from Local Path
```nix
{config, ...}: {
imports = [
./modules/nixos/mem0.nix
];
}
```
### Home Manager Modules
#### Import All Modules
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
}
```
#### Import Specific Module
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.ports
];
}
```
#### Import Category
```nix
{config, ...}: {
imports = [
# Import all CLI modules
m3ta-nixpkgs.homeManagerModules.cli.zellij-ps
];
}
```
## Available Modules
### NixOS Modules
#### `m3ta.ports`
Port management across hosts.
```nix
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
hostOverrides.laptop = {
nginx = 8080;
};
currentHost = config.networking.hostName;
};
```
**Documentation**: [Port Management Guide](./port-management.md)
#### `m3ta.mem0`
Mem0 REST API server for AI memory.
```nix
m3ta.mem0 = {
enable = true;
port = 8000;
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
model = "gpt-4o-mini";
};
vectorStore = {
provider = "qdrant";
config = {
host = "localhost";
port = 6333;
};
};
};
```
**Documentation**: [mem0 Module](../modules/nixos/mem0.md)
### Home Manager Modules
#### `m3ta.ports`
Port management (similar to NixOS, with `generateEnvVars`).
```nix
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
generateEnvVars = true;
currentHost = config.networking.hostName;
};
```
**Documentation**: [Port Management Guide](./port-management.md)
#### `m3ta.cli.zellij-ps`
Zellij project switcher for quickly navigating between project folders.
```nix
m3ta.cli.zellij-ps = {
enable = true;
package = pkgs.zellij-ps;
};
```
**Documentation**: [zellij-ps Module](../modules/home-manager/cli/zellij-ps.md)
#### `m3ta.coding.editors`
Editor configurations.
```nix
m3ta.coding.editors = {
enable = true;
neovim.enable = true;
zed.enable = true;
};
```
**Documentation**: [Editors Module](../modules/home-manager/coding/editors.md)
## Common Patterns
### Module Configuration
All modules follow this pattern:
```nix
{ config, lib, pkgs, ... }:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "description";
# ... other options
};
config = mkIf cfg.enable {
# ... configuration
};
}
```
### Conditional Configuration
Use `mkIf` to conditionally apply config:
```nix
config = mkIf cfg.enable {
# Only applied when cfg.enable = true
services.my-service = {
enable = true;
};
}
```
### Multiple Conditions
Use `mkMerge` for multiple conditions:
```nix
config = mkMerge [
(mkIf cfg.feature1.enable {
# Applied when feature1 is enabled
})
(mkIf cfg.feature2.enable {
# Applied when feature2 is enabled
})
];
```
### Optional Dependencies
```nix
options.m3ta.myModule = {
enable = mkEnableOption "my module";
package = mkOption {
type = types.package;
default = pkgs.defaultPackage;
};
};
config = mkIf cfg.enable {
services.my-service = {
package = cfg.package;
};
};
```
## Configuration Examples
### Minimal NixOS Configuration
```nix
{pkgs, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
m3ta.ports = {
enable = true;
definitions = {
my-service = 8080;
};
currentHost = "laptop";
};
services.my-custom-service = {
enable = true;
port = config.m3ta.ports.get "my-service";
};
}
```
### Full NixOS Configuration
```nix
{config, pkgs, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
# Port management
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
mem0 = 8000;
};
hostOverrides.laptop = {
nginx = 8080;
mem0 = 8081;
};
currentHost = config.networking.hostName;
};
# Mem0 service
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0";
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
};
vectorStore = {
provider = "qdrant";
config = {
host = "localhost";
port = 6333;
};
};
};
# Nginx
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
# Grafana
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
}
```
### Minimal Home Manager Configuration
```nix
{pkgs, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
currentHost = "desktop";
};
home.sessionVariables = {
DEV_PORT = toString (config.m3ta.ports.get "dev-server");
};
}
```
### Full Home Manager Configuration
```nix
{config, pkgs, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
# Port management
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
nextjs = 3001;
vite = 5173;
};
hostOverrides.laptop = {
vite = 5174;
};
currentHost = config.networking.hostName;
};
# CLI tools
m3ta.cli.zellij-ps = {
enable = true;
};
# Coding tools
m3ta.coding.editors = {
enable = true;
neovim.enable = true;
};
# Packages
home.packages = with pkgs; [
code2prompt
zellij-ps
];
# Environment variables
home.sessionVariables = {
EDITOR = "nvim";
DEV_SERVER_PORT = toString (config.m3ta.ports.get "dev-server");
};
}
```
## Module Options Reference
### Standard Options
All modules typically include:
| Option | Type | Description |
|---------|-------|-------------|
| `enable` | `boolean` | Enable the module |
| `package` | `package` | Custom package to use |
| `extraConfig` | `attrs` | Additional configuration |
### Port Management Options
| Option | Type | Description |
|---------|-------|-------------|
| `definitions` | `attrsOf int` | Default port definitions |
| `hostOverrides` | `attrsOf attrs` | Host-specific overrides |
| `currentHost` | `string` | Current hostname |
| `generateEnvVars` | `boolean` | Generate environment variables (HM only) |
## Combining with Other Flakes
### Using Multiple Module Sources
```nix
{config, ...}: {
imports = [
# m3ta-nixpkgs modules
m3ta-nixpkgs.nixosModules.default
# Other flake modules
inputs.impermanence.nixosModules.impermanence
inputs.sops-nix.nixosModules.sops
];
# Configure all modules
m3ta.ports = {
enable = true;
definitions = {nginx = 80;};
currentHost = config.networking.hostName;
};
environment.persistence = {
"/persist" = {
directories = ["/var/lib/mem0"];
};
};
}
```
### Using with Secrets
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
inputs.sops-nix.nixosModules.sops
];
sops.secrets = {
openai-api-key = {};
};
m3ta.mem0 = {
enable = true;
llm = {
apiKeyFile = config.sops.secrets.openai-api-key.path;
};
};
}
```
## Troubleshooting
### Module Not Found
Error: `error: The option 'm3ta.mymodule' does not exist`
**Solutions**:
1. Make sure you imported the module:
```nix
imports = [
m3ta-nixpkgs.nixosModules.default
];
```
2. Check module name is correct
```nix
# Correct
m3ta.mem0.enable = true;
# Wrong
m3ta.mymodule.enable = true; # Doesn't exist
```
### Option Type Mismatch
Error: `type mismatch at 'm3ta.mymodule.enable', expected a boolean but got a list`
**Solution**: Check option types in documentation
```nix
# Correct
m3ta.mymodule.enable = true;
# Wrong
m3ta.mymodule.enable = [true]; # Should be boolean
```
### Port Not Defined
Error: `Service "foo" not defined`
**Solution**: Add to port definitions
```nix
m3ta.ports = {
definitions = {
foo = 8080; # Add this
};
};
```
## Best Practices
### Use Namespaces
Always use the `m3ta.*` namespace:
```nix
# Good
m3ta.mem0.enable = true;
# Bad (potential conflicts)
mem0.enable = true;
```
### Document Your Configuration
Add comments explaining module usage:
```nix
# Port management for multi-host setup
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
hostOverrides.laptop = {
nginx = 8080; # Use different port on laptop
};
currentHost = config.networking.hostName;
};
# Mem0 AI memory service
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0";
};
```
### Test Configuration
```bash
# Test NixOS configuration without applying
sudo nixos-rebuild test --flake .#hostname
# Check configuration
nix flake check
# Show all options
nix eval .#nixosConfigurations.hostname.config.m3ta --apply builtins.attrNames
```
## Next Steps
- [Port Management](./port-management.md) - Detailed port management guide
- [Adding Packages](./adding-packages.md) - How to add new packages
- [Architecture](../ARCHITECTURE.md) - Understanding module structure
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines