m3ta-home — Portable User Profiles for NixOS

Centralized, portable Home-Manager configurations. Manages user identities, preferences, feature sets, and assets across multiple NixOS hosts — from desktops and laptops to headless servers.

One repo, all your machines. Change once, deploy everywhere.

Architecture

m3ta-home/
├── flake.nix              ← Entry point: inputs, lib, homeManagerModules
├── lib/
│   ├── default.nix        ← Re-exports mkHome
│   └── mkHome.nix         ← Composition engine (WHO + WHERE + WHAT)
├── modules/
│   ├── default.nix        ← Module aggregation for flake export
│   └── paths.nix          ← "m3ta-home".paths.srcRoot (pure eval compatibility)
├── profiles/
│   ├── base/              ← Always loaded: shell, CLI tools, secrets, nix settings
│   ├── contexts/
│   │   ├── desktop/       ← GUI host: WM, apps, theme, terminal, XDG
│   │   └── server/        ← Headless: minimal
│   └── sets/              ← Optional feature bundles
│       ├── coding/        ← core, editors, languages, LSP, agents
│       ├── gaming/        ← Steam, Gamescope, GPU tools
│       └── media/         ← OBS, ffmpeg, kdenlive, yt-dlp
├── users/
│   └── m3tam3re/
│       ├── identities/
│       │   ├── private.nix ← Personal: git (m3tm3re), SSH, JJ
│       │   └── work.nix   ← Work: git (sascha.koenig), SSH, JJ
│       └── preferences/   ← Identity-independent: cliphist, difftastic
└── assets/
    └── wallpapers/        ← Wallpaper collection (referenced via srcRoot)

The Three Dimensions

mkHome composes a complete Home-Manager configuration from three axes:

Dimension Options Description
WHO user + identity Which user, which identity (private/work)
WHERE context desktop or server — mutually exclusive
WHAT sets coding, gaming, media — freely combinable
mkHome {
  user = "m3tam3re";
  identity = "private";     # ← "private" or "work"
  context = "desktop";      # ← "desktop" or "server"
  sets = ["coding" "gaming" "media"];
}

How it Works

  1. Base is always imported (shell, CLI tools, nix settings, nix-colors/dracula theme)
  2. Context is loaded based on context — exactly one of desktop or server
  3. Sets are loaded on top — any combination of coding, gaming, media
  4. Identity overrides git username/email, SSH match blocks, and Jujutsu config
  5. Feature flags in the consuming host selectively enable/disable individual modules

Assertions

  • gaming and media sets require desktop context (enforced via Nix assertions)
  • coding works in both desktop and server contexts

Usage

In nixos-config (flake.nix)

inputs.m3ta-home = {
  url = "git+ssh://gitea@code.m3ta.dev/m3tam3re/m3ta-home";
  inputs.nixpkgs.follows = "nixpkgs";
};

Per-Host Configuration

The consuming repo (nixos-config) maps hosts to profiles:

# hosts/common/users/m3tam3re.nix
hostProfiles = {
  m3-kratos = { context = "desktop"; sets = ["coding" "gaming" "media"]; };
  m3-atlas  = { context = "server";  sets = ["coding"]; };
  m3-helios = { context = "server";  sets = []; };
};

Then enables specific feature flags per host:

home-manager.users.m3tam3re = {
  imports = [
    (m3ta-lib.mkHome {
      user = "m3tam3re";
      identity = "private";
      inherit (profile) context sets;
    })
    hostFlags  # ← per-host enable/disable of individual modules
  ];
};

Host-Specific Overrides

Monitor layouts, window rules, and XDG/MIME settings stay in nixos-config:

  • hosts/m3-kratos/home.nix — dual DP monitors, Hyprland workspaces
  • hosts/m3-ares/home.nix — laptop eDP + HDMI, tuxedo-backlight
  • Server hosts need no home.nix (no desktop config)

Identity System: Private vs. Work

The identity system allows switching between personal and work contexts on any machine — same dotfiles, different git identity, SSH config, and Jujutsu settings.

How Identities Work

Private Work
Git user m3tm3re sascha.koenig
Git email p@m3ta.dev sascha.koenig@azintec.com
JJ email m@m3tam3re.com sascha.koenig@azintec.com
SSH hosts code.m3ta.dev, github.com, private infra git.az-gruppe.com, AZ servers

Use Case: Work Laptop

If you bring a work NixOS machine into your fleet, you can use the same m3ta-home repo with a different identity:

# On the work machine's nixos-config:
(m3ta-lib.mkHome {
  user = "m3tam3re";
  identity = "work";       # ← switches git, SSH, JJ to work profile
  context = "desktop";
  sets = ["coding"];
})

This gives you:

  • Your familiar shell setup (fish, starship, nushell)
  • Your CLI tools (fzf, bat, eza, zoxide, etc.)
  • Your editor configs (neovim, zed)
  • Work git identity and SSH configuration automatically
  • No gaming, media, or personal apps

Adding a New Identity

  1. Create users/<username>/identities/<identity>.nix
  2. Define git, SSH, and JJ settings for that identity
  3. Reference it via identity = "<identity>" in mkHome

Feature Flags

Every module in m3ta-home has an enable option. Base modules default to true, everything else defaults to false. Flags are set per-host in the consuming repo.

Available Flags

base.shell.fish.enable          # Fish shell
base.shell.nushell.enable       # Nushell
base.shell.starship.enable      # Starship prompt
base.cliTools.fzf.enable        # Fuzzy finder
base.cliTools.bat.enable        # Cat replacement
base.cliTools.eza.enable        # Ls replacement
base.cliTools.zellij.enable     # Terminal multiplexer
base.cliTools.zoxide.enable     # Smarter cd
base.cliTools.direnv.enable     # Directory-based env
base.cliTools.television.enable # TV fuzzy finder
base.cliTools.nitch.enable      # System info
base.secrets.enable             # pass-wayland, pinentry

desktop.wm.hyprland.enable      # Hyprland window manager
desktop.wm.rofi.enable          # Rofi launcher
desktop.wm.wayland.enable       # Wayland tools (grim, slurp, etc.)
desktop.apps.obsidian.enable    # Obsidian
desktop.apps.office.enable      # LibreOffice
desktop.apps.crypto.enable      # Bisq2, Monero, Trezor
desktop.theme.fonts.enable      # Desktop fonts
desktop.theme.wallpapers.enable # Wallpaper collection

coding.editors.neovim.enable    # Neovim
coding.editors.zed.enable       # Zed editor (desktop only)
coding.lsp.enable               # Language servers
coding.packages.enable          # Bruno, Insomnia
coding.languages.python.enable
coding.languages.javascript.enable
coding.languages.typescript.enable
coding.languages.rustToolchain.enable
coding.languages.go.enable

profiles.gaming.steam.enable
profiles.gaming.gamescope.enable
profiles.gaming.gpu.enable

profiles.media.obs.enable
profiles.media.ffmpeg.enable
profiles.media.kdenlive.enable
profiles.media.ytDlp.enable
profiles.media.handbrake.enable

Adding a New Module

  1. Create the .nix file in the appropriate directory under profiles/
  2. Define an options block with mkEnableOption
  3. Define a config block with mkIf cfg.enable
  4. Add the import to the parent default.nix

Example:

# profiles/sets/coding/languages/elixir.nix
{ config, lib, pkgs, ... }:
with lib; let
  cfg = config.coding.languages.elixir;
in {
  options.coding.languages.elixir.enable = mkEnableOption "Elixir language support";

  config = mkIf cfg.enable {
    home.packages = with pkgs; [ elixir ];
  };
}

Then add ./elixir to profiles/sets/coding/languages/default.nix.

Assets

Static assets (wallpapers, etc.) live in assets/. They are referenced via the "m3ta-home".paths.srcRoot option, which points to the flake source root and works in pure evaluation mode:

source = "${config."m3ta-home".paths.srcRoot}/assets/wallpapers";

Dependencies

Input Purpose
nixpkgs Package set (follows nixos-config's nixpkgs)
home-manager Home-Manager modules
nix-colors Dracula theme palette (used everywhere)
m3ta-nixpkgs Custom packages (zellij-ps, rofi-project-opener) and HM modules
agenix Secret management
NUR Additional packages

Important Notes

  • Overlays are managed at the NixOS level in nixos-config, not here. home-manager.useGlobalPkgs = true ensures HM sees them.
  • Host-specific config (monitor layouts, window rules, XDG/MIME) belongs in nixos-config/hosts/<name>/home.nix, not here.
  • Pure evaluation: All file references use "m3ta-home".paths.srcRoot instead of relative ../.. paths.
Description
No description provided
Readme 26 MiB
Languages
Nix 100%