Skip to main content
This guide covers the contribution workflow for the homelab project, following trunk-based development with an issue-first policy.

Development Philosophy

We follow:
  • Trunk-Based Development: Short-lived branches merged frequently to main
  • Issue-First Policy: Every change maps to a GitHub issue
  • Conventional Commits: Standardized commit messages
  • Automated Validation: Pre-commit hooks and flake checks

Getting Started

1

Fork and Clone

git clone https://github.com/yourusername/homelab.git
cd homelab
2

Enter Development Environment

nix develop
This activates:
  • Pre-commit hooks
  • Development tools
  • Secret management (agenix-shell)
3

Verify Setup

nix flake check
Ensures your environment is correctly configured.

Contribution Workflow

1

Create an Issue

Every change must map to a GitHub issue for project tracking.Bug Report Example:
Title: fix: zsh configuration causes errors on fresh install

Description:
- What's broken: zsh fails to start
- Expected behavior: zsh starts normally
- How to reproduce: Fresh install on system X
Feature Request Example:
Title: feat: add Kubernetes cluster module

Description:
- What: Add k3s clustering support
- Why: Enable multi-node container orchestration
- Scope: NixOS module in modules/nixos/hosting/
2

Create Feature Branch

Create a short-lived branch from main:
git checkout -b dev-<issue-name>
Branch Naming Examples:
  • dev-fix-zsh-typo
  • dev-add-k8s-cluster
  • dev-update-nvidia-drivers
Keep branches short-lived (1-3 days) and focused on a single issue.
3

Make Changes

Follow the appropriate guide for your change:
4

Validate Changes

Before committing, ensure everything compiles:
nix flake check
Pre-commit hooks will automatically run this, but manual validation catches issues early.
Pre-commit hooks are configured via git-hooks.nix in the flake and run automatically on commit.
5

Commit with Conventional Commits

Use conventional commit format:
git add <files>
git commit -m "<type>: <description>"
See Commit Types below for the full list.
6

Push and Create PR

git push origin dev-<issue-name>
Create a pull request on GitHub:
  • Reference the issue number
  • Describe what changed and why
  • Include testing steps if applicable
7

Address Review Feedback

Make requested changes and push:
git add <files>
git commit -m "fix: address review feedback"
git push
8

Merge to Main

Once approved, squash and merge to main.Delete your feature branch after merging:
git branch -d dev-<issue-name>

Commit Types

Use these conventional commit types:
TypeDescriptionExample
feat:A new featurefeat: add sunshine module for gaming VM
fix:A bug fixfix: resolve zsh startup error
docs:Documentation only changesdocs: update installation instructions
style:Code style changes (formatting, whitespace)style: format bluetooth module with treefmt
refactor:Code change that neither fixes a bug nor adds a featurerefactor: simplify secret management logic
perf:Performance improvementsperf: optimize flake evaluation time
test:Adding or correcting teststest: add unit tests for networking module
chore:Build process or tooling changeschore: update flake inputs

Commit Message Examples

Good:
feat: add k3s clustering backend module
fix: correct bluetooth powerOnBoot default
docs: document secret rotation workflow
refactor: reorganize desktop environment modules
Bad:
Updated stuff
fixes
WIP
changed files

Validation and Testing

Pre-commit Hooks

Automatically run on every commit:
  • Formatting checks (treefmt)
  • Flake validation
  • Nix syntax checking
Configured in pre-commit.nix:
{
  lib,
  pkgs,
  ...
}: {
  settings.hooks = {
    treefmt.enable = true;
    flake-checker.enable = true;
  };
}

Manual Validation

# Check flake validity
nix flake check

# Build specific system
nix build .#nixosConfigurations.<system>.config.system.build.toplevel

# Format code
treefmt

Testing Changes

Deploy to your test system:
nixos-rebuild switch --flake .#test-system
Build and test in a virtual machine:
nixos-rebuild build-vm --flake .#test-system
./result/bin/run-*-vm
Create a minimal test configuration:
test.nix
{
  imports = [ ./modules/nixos/core/hardware/bluetooth.nix ];
  core.hardware.bluetooth.enable = true;
}

Code Style Guidelines

Nix Code

  • Use 2 spaces for indentation
  • Format with treefmt (alejandra formatter)
  • Use let ... in for computed values
  • Keep lines under 100 characters where reasonable
  • Use descriptive variable names

Module Structure

{
  lib,
  config,
  pkgs,
  ...
}: let
  cfg = config.category.subcategory.module;
in {
  # Options first
  options.category.subcategory.module = {
    enable = lib.mkEnableOption "Description";
    
    # Additional options...
  };

  # Config second
  config = lib.mkIf cfg.enable {
    # Configuration...
  };
}

File Organization

  • Group related modules in directories
  • Use default.nix to expose module imports
  • Keep files focused on a single concern
  • Place shared utilities in lib/

Project Structure

.
├── flake.nix              # Main flake configuration
├── flake.lock             # Locked dependencies
├── secrets.nix            # Secret access configuration
├── modules/
│   ├── nixos/            # NixOS modules
│   ├── home/             # Home Manager modules
│   └── droid/            # Nix-on-Droid modules
├── systems/              # System configurations
│   ├── desktop/
│   ├── server/
│   └── container/
├── templates/            # Flake templates
│   └── empty/
├── lib/                  # Shared utilities
└── tests/                # Test suites

Using Templates

Scaffold new projects or components:
# List available templates
nix flake show templates

# Initialize a template
nix flake init -t .#empty
The empty template includes:
  • Basic flake structure
  • Pre-commit hooks
  • Secret management (agenix)
  • Development shell
  • Testing framework (nixtest)

Common Tasks

# Update all inputs
nix flake update

# Update specific input
nix flake lock --update-input nixpkgs

# Commit
git add flake.lock
git commit -m "chore: update flake inputs"
  1. Create issue
  2. Create branch: dev-add-<module>-module
  3. Write module in appropriate directory
  4. Add to default.nix imports
  5. Test with nix flake check
  6. Commit: feat: add <module> module
  1. Create issue describing bug
  2. Create branch: dev-fix-<bug>
  3. Make fix
  4. Test thoroughly
  5. Commit: fix: <description>
  6. Reference issue in PR
git checkout -b dev-update-docs
# Edit documentation files
git add docs/
git commit -m "docs: update <topic> documentation"
git push

Troubleshooting

Flake Check Fails

# Get detailed error output
nix flake check --show-trace

# Check specific system
nix build .#nixosConfigurations.system.config.system.build.toplevel --show-trace

Pre-commit Hook Failures

# Run hooks manually
pre-commit run --all-files

# Skip hooks (only if necessary)
git commit --no-verify

Build Errors

# Clean build cache
nix store gc

# Rebuild flake
nix flake update
nix develop --refresh

Getting Help

  • Check existing issues for similar problems
  • Review documentation and guides
  • Ask questions in discussions
  • Reference NixOS documentation: https://nixos.org/manual/

Best Practices

  • Keep changes small and focused
  • Write descriptive commit messages
  • Test before pushing
  • Respond to review feedback promptly
  • Update documentation with code changes
  • Delete branches after merging
  • Never commit secrets unencrypted
  • Don’t skip validation checks
  • Avoid long-lived branches
  • Don’t commit without an issue
  • Never force-push to main

Next Steps

Build docs developers (and LLMs) love