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>
585 lines
21 KiB
Nix
585 lines
21 KiB
Nix
{
|
||
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";
|
||
};
|
||
};
|
||
};
|
||
}
|