omnixient/flake.nix
Padreug fa467a346a feat(mksystem): inject home-manager sharedModules OmniXY home needs
home.nix depends on nix-colors (colorScheme), lazyvim, and walker HM
modules; previously every host wired them by hand via `modules`, which
external consumers couldn't know to do. Inject them in mkSystem so any
host built through it gets them; re-importing from a host is a no-op.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 10:40:55 +02:00

585 lines
21 KiB
Nix
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
description = "Omnixient - NixOS configuration for modern development";
inputs = {
# Nixpkgs
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05";
# True bleeding-edge nixpkgs-unstable channel. omni's primary
# `nixpkgs` is nixos-unstable (tested unstable); this is the
# untested channel used by lib/overlays.nix to pin a handful of
# fast-moving packages (claude-code, gh, direnv). Unused until
# mkSystem is wired in (phase D).
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
# Unified server-deploy flake. Source of truth for which refs
# ship to which host; dev-env walks this flake's inputs to
# auto-populate the project list (see modules/dev-env/config.nix)
# and resolves --override-input targets for `dev-deploy --local`.
# Named after the forgejo repo so DEVENV_DEPLOY_FLAKE_INPUT and
# the on-disk clone directory match.
server-deploy.url = "git+ssh://forgejo@git.atitlan.io/aiolabs/server-deploy";
# Home manager
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
# nixos-hardware — per-model NixOS modules (kernel pins, GPU/CPU
# defaults, firmware tooling) for common hardware. bohm is a
# Framework Desktop (AMD Ryzen AI Max 300 series), so we import
# `nixosModules.framework-desktop-amd-ai-max-300-series` in
# hosts/omni/default.nix. gizmo is a Framework Laptop 12, but
# runs Arch — if it ever migrates to NixOS, the matching module
# is `nixosModules.framework-12-13th-gen-intel`.
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
# Hyprland
# Pinned to v0.54.3 — v0.55.0 (rev 70fd412) crashes on `togglegroup`
# teardown: CGroup::destroy() throws an uncaught std::out_of_range.
# Remove the tag to track latest once the upstream group regression is fixed.
hyprland = {
url = "github:hyprwm/Hyprland/v0.54.3";
inputs.nixpkgs.follows = "nixpkgs";
};
# Hyprland plugins
hyprland-plugins = {
url = "github:hyprwm/hyprland-plugins";
inputs.hyprland.follows = "hyprland";
};
# Nix colors for automatic color scheme generation
nix-colors = {
url = "github:misterio77/nix-colors";
};
# Stylix for theming
stylix = {
url = "github:danth/stylix";
inputs.nixpkgs.follows = "nixpkgs";
};
# NUR for additional packages
nur.url = "github:nix-community/NUR";
# Walker app launcher + Elephant backend
elephant = {
url = "github:abenz1267/elephant";
inputs.nixpkgs.follows = "nixpkgs";
};
walker = {
url = "github:abenz1267/walker";
inputs.nixpkgs.follows = "nixpkgs";
inputs.elephant.follows = "elephant";
};
# sops-nix — declarative secrets via age-encrypted YAML files.
# Decryption happens at activation time on the target host; secret
# values are exposed to services as files under /run/secrets/.
# The omni host's age key lives at
# ~/.config/sops/age/keys.txt (same `admin` recipient as
# ~/dev/deploy/server-deploy/.sops.yaml). See .sops.yaml +
# modules/secrets.nix for wiring.
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
# LazyVim packaged as a home-manager module. Tracks LazyVim
# releases upstream and pins every plugin via the nix store
# ("dev mode" symlinks) so there is no runtime download. We
# pin to a specific tag rather than tracking `main` so a
# broken upstream release can never silently break a fresh
# install. Bump intentionally on each LazyVim release.
lazyvim = {
url = "github:pfassina/lazyvim-nix/v15.15.0";
inputs.nixpkgs.follows = "nixpkgs";
};
# nix-bitcoin — hardened Bitcoin/Lightning node modules, consumed by
# the default-disabled bitcoin pack. Follows our nixpkgs for a single
# package set; nix-bitcoin pins its own nixpkgs upstream for tested
# builds, so if a service fails to build once the pack is enabled,
# consider dropping this `follows`.
nix-bitcoin = {
url = "github:fort-nix/nix-bitcoin/release";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{
self,
nixpkgs,
home-manager,
...
}@inputs:
let
system = "x86_64-linux";
settings = import ./settings.nix;
# Overlays applied uniformly to every host built via mkSystem.
# Combines the lib/overlays.nix nixpkgs-unstable pins with the
# nur overlay omni already used. The neovim-nightly-overlay
# was dropped because it cascade-rebuilds every neovim plugin
# from source (cache miss on cache.nixos.org), which surfaced
# broken upstream tests (fzf-lua screenshot test) and balloons
# build time. LazyVim is provided declaratively via the
# `lazyvim` flake input (a home-manager module) — see
# home.nix `programs.lazyvim` — so we don't need a system
# neovim with the full plugin set baked in.
overlays = (import ./lib/overlays.nix { inherit inputs; }) ++ [
inputs.nur.overlays.default
];
# Uniform host constructor. See lib/mksystem.nix for the shape.
mkSystem = import ./lib/mksystem.nix { inherit nixpkgs overlays inputs; };
# pkgs used for devShells, packages, and apps outputs below.
# The nixosConfigurations get their own pkgs via mksystem's
# `{ nixpkgs.overlays = overlays; }` module injection.
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
inherit overlays;
};
# Interactive regtest dev VM (`nix run .#regtest`). Shares the node
# config with the CI test (tests/regtest-node.nix); the interactive
# layer (SSH, operator login, helpers) is tests/regtest-interactive.nix.
regtestVm = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs settings; };
modules = [
{ nixpkgs.hostPlatform = system; }
{ nixpkgs.config.allowUnfree = true; }
# qemu-vm.nix provides `system.build.vm` plus the virtualisation.*
# options (cores/memorySize/graphics/forwardPorts) that the node
# and interactive modules set. The nixosTest framework imports it
# automatically; a plain nixosSystem must do so explicitly.
(
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];
}
)
inputs.nix-bitcoin.nixosModules.default
./tests/regtest-node.nix
./tests/regtest-interactive.nix
];
};
# `nix run .#regtest` — boot the VM headless, drop into an operator
# SSH shell, tear the VM down on exit. Ephemeral disk in a tmp file.
regtestRunner = pkgs.writeShellApplication {
name = "regtest";
runtimeInputs = with pkgs; [
sshpass
openssh
coreutils
];
text = ''
vm_script=${regtestVm.config.system.build.vm}/bin/run-regtest-vm
img=$(mktemp -u --suffix=.qcow2)
log=$(mktemp)
export NIX_DISK_IMAGE="$img"
ssh_opts=(-p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR)
cleanup() {
if [ -n "''${vm_pid:-}" ]; then kill "$vm_pid" 2>/dev/null || true; fi
rm -f "$img" "$log"
}
trap cleanup EXIT INT TERM
echo "🥾 booting regtest VM (headless) first boot generates node secrets + mines 110 blocks"
"$vm_script" >"$log" 2>&1 &
vm_pid=$!
echo " waiting for SSH on localhost:2222"
ready=
for _ in $(seq 1 120); do
if ! kill -0 "$vm_pid" 2>/dev/null; then
echo " VM exited early; last log lines:"; tail -n 20 "$log"; exit 1
fi
if sshpass -p password ssh "''${ssh_opts[@]}" -o ConnectTimeout=2 operator@localhost true 2>/dev/null; then
ready=1; break
fi
sleep 2
done
if [ "$ready" != 1 ]; then
echo " SSH never came up; last log lines:"; tail -n 20 "$log"; exit 1
fi
echo " connected run 'regtest-fund' to set up a channel; 'exit' to shut down."
sshpass -p password ssh "''${ssh_opts[@]}" operator@localhost || true
'';
};
in
{
# Reusable library for external consumers. Use this flake as an
# input and build a host with the Omnixient conventions from your own
# repo, without forking:
#
# omni.lib.mkSystem "myhost" {
# settings = { ... }; # your identity (see settings.nix)
# modules = [ ./hosts/myhost ];
# };
#
# mkSystem bakes in Omnixient's nixpkgs, overlays, and inputs
# (home-manager, sops-nix, …), so you don't redeclare them.
lib.mkSystem = mkSystem;
# NixOS configurations.
#
# This public template ships the `example` host (copy-me starter) and
# the live ISO. The maintainer's personal host (`omni`, a real
# machine with secrets + private hardware/VPN) is NOT here — it lives
# on the private `omni-private` branch, which adds it back alongside
# the real secret files. Forkers define their own host like `example`.
nixosConfigurations = {
# Copy-me template host (hosts/example/). Kept as a real,
# build-checked target so the template can't silently rot — its
# placeholder hardware-configuration.nix uses by-label devices
# that won't match real hardware, so don't `switch` to it. Adopters
# copy hosts/example → hosts/<name> and rename this block. See
# hosts/example/default.nix and docs/getting-started.md.
# nix-colors/lazyvim/walker home-manager modules are injected by
# mkSystem now, so hosts no longer wire them by hand.
example = mkSystem "example" {
inherit system;
user = settings.user;
extraSpecialArgs = { inherit settings; };
extraHmArgs = { inherit settings; };
};
# ISO image for live USB/DVD. This is a variant rather than a
# normal host, so it stays as a direct nixosSystem call — we
# don't force every variant through mksystem. It reuses
# omni's home.nix but under a "nixos" user that only exists
# in the ISO context.
omni-iso = nixpkgs.lib.nixosSystem {
specialArgs = {
inherit inputs;
settings = settings // {
user = "nixos";
};
currentSystemName = "omni-iso";
currentSystemUser = "nixos";
};
modules = [
{ nixpkgs.hostPlatform = system; }
{ nixpkgs.overlays = overlays; }
{ nixpkgs.config.allowUnfree = true; }
./iso.nix
home-manager.nixosModules.home-manager
{
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = {
inherit inputs;
settings = settings // {
user = "nixos";
};
currentSystemName = "omni-iso";
currentSystemUser = "nixos";
};
users.nixos = import ./home.nix;
sharedModules = [
inputs.nix-colors.homeManagerModules.default
inputs.lazyvim.homeManagerModules.default
inputs.walker.homeManagerModules.default
];
};
}
];
};
};
# Reusable packs as importable NixOS modules (Misterio77-style,
# framework-free). A second host (gizmo) and third parties consume
# the same definitions with different subsets. The lnbits / aiolabs
# / bitcoin packs are standalone-importable — usable on a non-omni
# NixOS without enabling omni core.
nixosModules = {
# Omnixient core, as a single importable module. A consumer using
# this flake as an input builds a host with:
# omni.lib.mkSystem "myhost" {
# settings = { ... };
# modules = [ omni.nixosModules.omni ./hosts/myhost ];
# };
# mkSystem also injects packs + home-manager; this provides the
# desktop/system core (option namespace + behavior). Theme is
# chosen from settings.theme.
omni = import ./modules;
default = import ./modules;
lnbits = import ./modules/packs/lnbits.nix;
aiolabs = import ./modules/packs/aiolabs.nix;
bitcoin = import ./modules/packs/bitcoin.nix;
media = import ./modules/packs/media.nix;
development = import ./modules/packs/development.nix;
gaming = import ./modules/packs/gaming.nix;
office = import ./modules/packs/office.nix;
containers = import ./modules/packs/containers.nix;
};
# Starter config for adopters: `nix flake init -t github:<org>/omni`
# scaffolds a consumer flake that uses Omnixient as an input (dependency
# model) — see templates/default/README.md.
templates.default = {
path = ./templates/default;
description = "Starter Omnixient consumer config (Omnixient as a flake input)";
};
templates.omni = self.templates.default;
# Flake checks — run by `nix flake check`. Lightweight targets
# that exercise the dev-env module schema end-to-end without
# loading the full omni system. Each check renders a small
# file (JSON or bash), so they build in a second or two even
# without a binary cache. See modules/dev-env/tests/smoke.nix
# for what is exercised.
checks.${system} =
let
devEnvSmoke = import ./modules/dev-env/tests/smoke.nix {
inherit nixpkgs;
home-manager = inputs.home-manager;
};
in
{
dev-env-projects-json = devEnvSmoke.config.environment.etc."dev-env/projects.json".source;
dev-env-config-sh = devEnvSmoke.config.environment.etc."dev-env/config.sh".source;
dev-env-tmux-sessions = devEnvSmoke.config.environment.etc."dev-env/tmux-sessions.json".source;
# Headless VM boot test — pass/fail signal for autonomous refactor
# runs in ~/nixos-refactor/. See tests/refactor-smoke.nix.
refactor-smoke = import ./tests/refactor-smoke.nix {
inherit nixpkgs system;
};
# NixOS-native Lightning regtest suite (aiolabs/omnixient#27):
# bitcoind(regtest) + Core Lightning + LND in one VM, driving a
# real fund → open-channel → pay → settle flow. See
# tests/regtest-core.nix.
regtest-core = import ./tests/regtest-core.nix {
inherit nixpkgs system;
nix-bitcoin = inputs.nix-bitcoin;
};
};
# Development shells
devShells.${system} = {
default = pkgs.mkShell {
packages = with pkgs; [
# Development tools
git
# neovim (configured via home-manager)
ripgrep
fd
bat
eza
fzf
zoxide
starship
lazygit
gh
# Language servers and formatters
nil # Nix LSP
nixfmt
statix
deadnix
# Build tools
gnumake
gcc
nodejs
python3
rustc
cargo
go
];
shellHook = ''
echo "🚀 Welcome to Omnixient development environment!"
echo ""
echo "Available commands:"
echo " omni-rebuild - Rebuild system configuration"
echo " omni-update - Update flake inputs"
echo " omni-clean - Garbage collect nix store"
echo ""
# Setup aliases
alias omni-rebuild="sudo nixos-rebuild switch --flake .#omni"
alias omni-update="nix flake update"
alias omni-clean="nix-collect-garbage -d"
# Initialize starship prompt
eval "$(starship init bash)"
'';
};
# Python development
python = pkgs.mkShell {
packages = with pkgs; [
python3
python3Packages.pip
python3Packages.virtualenv
python3Packages.ipython
python3Packages.black
python3Packages.pylint
python3Packages.pytest
ruff
];
};
# Node.js development
node = pkgs.mkShell {
packages = with pkgs; [
nodejs
pnpm
yarn
typescript
eslint
prettier
];
};
# Rust development
rust = pkgs.mkShell {
packages = with pkgs; [
rustc
cargo
rustfmt
rust-analyzer
clippy
];
};
};
# Packages that can be built
packages.${system} = {
# Omnixient scripts as packages
omni-scripts = pkgs.callPackage ./packages/scripts.nix { };
# Plymouth theme package
plymouth-theme-omni = pkgs.callPackage ./packages/plymouth-theme.nix { };
# ISO image
iso = self.nixosConfigurations.omni-iso.config.system.build.isoImage;
# Interactive regtest dev VM run-script (booted by `nix run .#regtest`).
regtest-vm = regtestVm.config.system.build.vm;
# Default package points to ISO
default = self.packages.${system}.iso;
};
# Apps that can be run
apps.${system} = {
# Interactive Lightning regtest dev VM — boots the stack headless
# and drops you into an operator SSH shell. See docs/regtest.md.
regtest = {
type = "app";
program = "${regtestRunner}/bin/regtest";
};
# Installer
installer = {
type = "app";
program = "${pkgs.writeShellScriptBin "omni-install" ''
#!/usr/bin/env bash
set -e
echo "🚀 Omnixient NixOS Installer"
echo "========================"
echo ""
# Check if running on NixOS
if [ ! -f /etc/nixos/configuration.nix ]; then
echo "Error: This installer must be run on a NixOS system"
exit 1
fi
echo "This will install Omnixient configuration to your NixOS system."
read -p "Continue? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
# Backup existing configuration
echo "📦 Backing up existing configuration..."
sudo cp -r /etc/nixos /etc/nixos.backup.$(date +%Y%m%d-%H%M%S)
# Copy new configuration
echo "📝 Installing Omnixient configuration..."
sudo cp -r ${self}/* /etc/nixos/
# Initialize flake
echo "🔧 Initializing flake..."
cd /etc/nixos
sudo git init
sudo git add -A
# Rebuild
echo "🏗 Rebuilding system..."
sudo nixos-rebuild switch --flake /etc/nixos#omni
echo ""
echo " Installation complete!"
echo "🎉 Welcome to Omnixient!"
''}/bin/omni-install";
};
# ISO builder
build-iso = {
type = "app";
program = "${pkgs.writeShellScriptBin "omni-build-iso" ''
#!/usr/bin/env bash
set -e
echo "🏗 Building Omnixient ISO Image"
echo "============================"
echo ""
echo "📦 Building ISO image..."
echo " This may take a while depending on your system..."
echo ""
# Build the ISO
nix build .#iso
# Check if build was successful
if [ -L "./result" ]; then
iso_path=$(readlink -f ./result)
iso_file=$(find "$iso_path" -name "*.iso" | head -1)
if [ -n "$iso_file" ]; then
iso_size=$(du -h "$iso_file" | cut -f1)
echo ""
echo " ISO build complete!"
echo "📁 Location: $iso_file"
echo "📏 Size: $iso_size"
echo ""
echo "🚀 You can now:"
echo " Flash to USB: dd if='$iso_file' of=/dev/sdX bs=4M status=progress"
echo " Burn to DVD: Use your favorite burning software"
echo " Test in VM: qemu-system-x86_64 -cdrom '$iso_file' -m 4G -enable-kvm"
echo ""
else
echo " ISO file not found in build result"
exit 1
fi
else
echo " Build failed - result symlink not found"
exit 1
fi
''}/bin/omni-build-iso";
};
};
};
}