feat(packs): opt-in package packs — media/office/dev/gaming/containers/compat

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-28 06:48:37 +02:00
commit 095f2ccf29
8 changed files with 449 additions and 0 deletions

46
modules/packs/README.md Normal file
View file

@ -0,0 +1,46 @@
# modules/packs
Opt-in **packs** — bundles of (packages + services + config) toggled with
`omni.packs.<name>.enable`. This is the "core + goodies" layer: core is
always on; packs are off until you ask for them.
Full guide (enabling, standalone import, authoring, bitcoin specifics,
verification): **[`docs/packs.md`](../../docs/packs.md)**.
## Pattern
Each pack is one self-contained module, **always imported but inert** until
enabled (hlissner-style enable-gate):
```nix
{ config, lib, pkgs, ... }:
let cfg = config.omni.packs.media; in {
options.omni.packs.media.enable = lib.mkEnableOption "Media pack";
config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs; [ … ]; };
}
```
## Files
| File | Purpose |
|---|---|
| `default.nix` | Aggregator — imports every pack + `compat.nix`. Wired into the build once, via `lib/mksystem.nix`. The ISO bypasses mksystem, so it stays pack-free. |
| `compat.nix` | Back-compat bridge: maps legacy `omni.features.*``omni.packs.*.enable` (mkDefault). Aggregator-only, so standalone imports don't pull in `omni.features`. |
| `media.nix`, `development.nix`, `gaming.nix`, `office.nix`, `containers.nix` | Desktop-bundle packs (migrated from `packages.nix` categories + the feature-gated bits of `core.nix`/`development.nix`). Omnixient-coupled (use `omni.lib.filterPackages`). |
| `lnbits.nix` | Wraps `../dev-env` and enables it. **Standalone-importable** (dev-env is decoupled from `omni.*`). |
| `aiolabs.nix` | Imports the gated aiolabs preset (`../dev-env/presets/aiolabs.nix`) and pulls in `lnbits`. **Standalone-importable.** |
| `bitcoin.nix` | nix-bitcoin node (bitcoind + clightning). **NOT in the aggregator** — nix-bitcoin's module asserts on import even when disabled; exposed as `nixosModules.bitcoin` for explicit per-host import. |
## Exposed as flake outputs
`flake.nixosModules.{media,development,gaming,office,containers,lnbits,
aiolabs,bitcoin}` — reusable across a second host (`gizmo`) and third
parties. `lnbits`/`aiolabs`/`bitcoin` work on a non-Omnixient NixOS.
## Adding a pack
See [`docs/packs.md` → Authoring a new pack](../../docs/packs.md#authoring-a-new-pack).
In short: copy the template, register in `default.nix` (unless it has
import-time side effects), expose in `flake.nix`, keep it
`config.omni.<core>`-free if it should be standalone, and verify the
omni closure is unchanged with `nix store diff-closures`.

25
modules/packs/compat.nix Normal file
View file

@ -0,0 +1,25 @@
# Back-compat bridge — maps the legacy omni.features.* booleans onto the
# new omni.packs.*.enable toggles via mkDefault, so existing hosts and
# the `preset` enum keep working unchanged through (and after) the
# migration. A host can still override any omni.packs.<name>.enable
# explicitly because these are mkDefault.
#
# Lives in the packs aggregator (modules/packs/default.nix), which is only
# loaded as part of a full omni system via lib/mksystem.nix — so a
# standalone consumer importing a single pack module (e.g.
# nixosModules.lnbits) never pulls in this omni.features dependency.
{ config, lib, ... }:
let
cfg = config.omni;
in
{
config = lib.mkIf (cfg.enable or false) {
omni.packs = {
media.enable = lib.mkDefault (cfg.features.media or false);
gaming.enable = lib.mkDefault (cfg.features.gaming or false);
office.enable = lib.mkDefault ((cfg.features.office or false) || (cfg.features.communication or false));
containers.enable = lib.mkDefault (cfg.features.containers or false);
development.enable = lib.mkDefault (cfg.features.coding or false);
};
};
}

View file

@ -0,0 +1,43 @@
# Containers pack — Docker + Podman.
#
# Unifies the docker config that was previously split between core.nix
# (basic enable + weekly autoPrune) and development.nix (daemon.settings
# buildkit + registry-mirror + autoPrune --all), plus the podman block
# that lived coding-gated in development.nix. Now a single source of truth
# gated on omni.packs.containers.enable. (The merged result is the union
# of the two old blocks — identical on any host that had both features on,
# e.g. omni.)
{ config, lib, ... }:
let
cfg = config.omni.packs.containers;
in
{
options.omni.packs.containers.enable =
lib.mkEnableOption "Containers pack (Docker + Podman)";
config = lib.mkIf cfg.enable {
virtualisation.docker = {
enable = true;
enableOnBoot = true;
daemon.settings = {
features = {
buildkit = true;
};
registry-mirrors = [ "https://mirror.gcr.io" ];
};
autoPrune = {
enable = true;
dates = "weekly";
flags = [ "--all" ];
};
};
# Podman as Docker alternative (dockerCompat off to avoid conflict).
virtualisation.podman = {
enable = true;
dockerCompat = false;
defaultNetwork.settings.dns_enabled = true;
};
};
}

33
modules/packs/default.nix Normal file
View file

@ -0,0 +1,33 @@
# omni packs — opt-in bundles of (packages + services + config).
#
# Every pack module is ALWAYS imported but inert until
# `omni.packs.<name>.enable = true` (hlissner-style enable-gate), so
# the option namespace is always declared and discoverable while nothing
# is built unless asked for. This aggregator is wired into the build at a
# single point — lib/mksystem.nix — so the ISO path (a direct nixosSystem
# call that bypasses mksystem) stays pack-free.
#
# The lnbits / aiolabs / bitcoin packs are standalone-importable: they
# declare their own option namespace and touch only standard NixOS
# options + their own bundled modules, so a third party can import e.g.
# `nixosModules.lnbits` on their own NixOS without enabling omni core.
{ ... }:
{
imports = [
./compat.nix
./media.nix
./development.nix
./gaming.nix
./office.nix
./containers.nix
./lnbits.nix
./aiolabs.nix
# bitcoin.nix is deliberately NOT in this always-loaded aggregator:
# nix-bitcoin's default module fires a secrets assertion just from
# being imported (even with no services enabled), so importing it
# inert on every host breaks eval. It's exposed as
# `nixosModules.bitcoin` instead — a host that wants a node imports it
# explicitly and sets omni.packs.bitcoin.enable. (inputs.nix-bitcoin
# is provided to such hosts via mksystem specialArgs.)
];
}

View file

@ -0,0 +1,109 @@
# Development pack — editors, language servers, compilers, build tools,
# container CLIs, DB clients, cloud tooling, plus git/npm programs and dev
# manpages.
#
# Migrated from packages.nix `development` category + the coding-gated
# bits of core.nix (programs.git/npm, documentation.dev, gcc/gnumake).
# The richer dev module (modules/development.nix: shells, services,
# helper scripts) is re-gated onto omni.packs.development.enable.
{ config, lib, pkgs, ... }:
let
cfg = config.omni.packs.development;
in
{
options.omni.packs.development.enable =
lib.mkEnableOption "Development pack (editors, LSPs, compilers, build tools, container CLIs)";
config = lib.mkIf cfg.enable {
documentation.dev.enable = true;
programs.git = {
enable = true;
lfs.enable = true;
};
programs.npm.enable = true;
environment.systemPackages = config.omni.lib.filterPackages (
with pkgs;
[
# Editors and IDEs
# neovim (configured via home-manager programs.neovim)
emacs
vscode
jetbrains.idea-oss
# Language servers
typescript-language-server
vscode-langservers-extracted
rust-analyzer
gopls
pyright
lua-language-server
clang-tools
# Debuggers
gdb
lldb
delve
# Build tools
gnumake
cmake
meson
ninja
autoconf
automake
libtool
pkg-config
# Compilers and interpreters
gcc
clang
rustc
cargo
go
python3
nodejs
deno
bun
# Container tools
docker
docker-compose
podman
buildah
skopeo
kind
kubectl
kubernetes-helm
k9s
# Database clients
postgresql
mariadb
sqlite
redis
mongodb-tools
dbeaver-bin
# API testing
httpie
curl
postman
insomnia
# Cloud tools
awscli2
google-cloud-sdk
azure-cli
terraform
ansible
# Documentation
mdbook
hugo
zola
]
);
};
}

33
modules/packs/gaming.nix Normal file
View file

@ -0,0 +1,33 @@
# Gaming pack — Steam, Lutris, Wine, performance tools.
# Migrated from packages.nix `gaming` category + the steam block in core.nix.
{ config, lib, pkgs, ... }:
let
cfg = config.omni.packs.gaming;
in
{
options.omni.packs.gaming.enable =
lib.mkEnableOption "Gaming pack (Steam, Lutris, Wine, performance tools)";
config = lib.mkIf cfg.enable {
programs.steam = {
enable = true;
remotePlay.openFirewall = true;
dedicatedServer.openFirewall = true;
};
environment.systemPackages = config.omni.lib.filterPackages (
with pkgs;
[
steam
lutris
wine
winetricks
protonup-rs
mangohud
gamemode
discord
obs-studio
]
);
};
}

84
modules/packs/media.nix Normal file
View file

@ -0,0 +1,84 @@
# Media pack — players, image/video editing, screen capture.
#
# Migrated from packages.nix `multimedia` category. Runs the list through
# omni.lib.filterPackages so the omni.packages.exclude mechanism still
# applies — this is a desktop-bundle pack (omni-coupled by design), not
# one of the standalone-importable packs.
{ config, lib, pkgs, ... }:
let
cfg = config.omni.packs.media;
in
{
options.omni.packs.media.enable =
lib.mkEnableOption "Media pack (players, image/video editing, screen capture)";
config = lib.mkIf cfg.enable {
environment.systemPackages = config.omni.lib.filterPackages (
with pkgs;
[
# Audio
pipewire
pulseaudio
pavucontrol
easyeffects
spotify
spotifyd
cmus
mpd
ncmpcpp
# Video
mpv
vlc
obs-studio
kdePackages.kdenlive
handbrake
ffmpeg-full
# Images
imv
feh
gimp
inkscape
krita
imagemagick
graphicsmagick
drawio
# Image morphing (python + opencv + dlib for landmark-based morphing).
# Exposed as `morph-py` so it doesn't collide with the bare `python3`
# pulled in by the development category.
(writeShellScriptBin "morph-py" ''
exec ${
python3.withPackages (
ps: with ps; [
opencv4
dlib
face-recognition-models
numpy
scipy
]
)
}/bin/python3 "$@"
'')
# 3D / CAD — bare `openscad` is pinned to 2021.01 which no
# longer builds against current toolchains in nixpkgs-unstable.
openscad-unstable
# Screen capture
grim
slurp
wf-recorder
flameshot
peek
# PDF
zathura
evince
kdePackages.okular
mupdf
]
);
};
}

76
modules/packs/office.nix Normal file
View file

@ -0,0 +1,76 @@
# Office pack — browsers, communication, office suite, notes, password
# managers, sync/backup.
#
# Migrated from packages.nix `productivity` category, which is gated on
# features.office OR features.communication today; this pack reproduces
# the whole list to preserve parity (splitting office vs communication is
# a follow-up). Run through omni.lib.filterPackages so exclude applies.
{ config, lib, pkgs, ... }:
let
cfg = config.omni.packs.office;
in
{
options.omni.packs.office.enable =
lib.mkEnableOption "Office pack (browsers, comms, office suite, notes, backup)";
config = lib.mkIf cfg.enable {
environment.systemPackages = config.omni.lib.filterPackages (
with pkgs;
[
# Browsers
firefox
chromium
brave
qutebrowser
# Communication
# discord
# slack
# telegram-desktop
signal-desktop
element-desktop
ferdium
# zoom-us
# teams-for-linux
# Bitcoin
sparrow
# Office
libreoffice
onlyoffice-desktopeditors
wpsoffice
# Note taking
obsidian
# logseq
# joplin-desktop
# zettlr
# Spaced repetition / learning
anki
# Email
# thunderbird
# aerc
# neomutt
# Calendar
calcurse
khal
# Password managers
bitwarden-desktop
keepassxc
pass
# Sync and backup
syncthing
nextcloud-client
rclone
restic
borgbackup
]
);
};
}