Compare commits

...

68 Commits

Author SHA1 Message Date
94198293ff merge: floo host 2026-03-28 00:50:52 +01:00
16eb3dcf00 feat: add floo hardware configuration 2026-03-28 00:50:24 +01:00
21a757232d feat: add provision and deploy just recipes 2026-03-28 00:49:57 +01:00
99fea4e9db feat: prepare initial floo host 2026-03-28 00:49:37 +01:00
dc2e7bf1aa feat: add disko input 2026-03-27 23:11:27 +01:00
baeb10a48e chore: use features in iso 2026-03-27 22:12:19 +01:00
315de3696a fix: ephvm setup 2026-03-27 22:11:50 +01:00
38cdcebddd feat: dev-registry for dev environments 2026-03-27 15:05:09 +01:00
c40fbaec57 feat: enable nix-ld and steam for tower 2026-03-26 23:37:03 +01:00
4b43196c0e merge: dendritic pattern with flake-parts 2026-03-26 23:34:45 +01:00
404b6431ce feat: update flake and hosts for new structure 2026-03-26 23:23:52 +01:00
8c6fefb95b feat: migrate from modules to features 2026-03-26 23:10:56 +01:00
76e74f4939 feat: switch from flake-utils to flake-parts 2026-03-26 22:35:23 +01:00
6208614f30 chore: bump lockfile 2026-03-26 19:29:05 +01:00
ded1963dd7 feat: add calibre+kindle setup 2026-03-22 12:05:15 +01:00
90312f4c8b chore: bump lockfile 2026-03-22 00:09:03 +01:00
fae966b17e feat: generate ggman completions during build 2026-03-22 00:01:29 +01:00
59270fdcd5 chore: remove deprecated todo-mcp 2026-03-22 00:01:06 +01:00
d8ab6207d5 feat: improve scripts setup (lint, format, refactor) 2026-03-21 17:38:19 +01:00
7fcd8b2ec8 feat: start ephvm with 30gb disk space 2026-03-21 17:38:00 +01:00
9f7728a95c feat: add osc 2026-03-19 16:05:39 +01:00
ad2c79e113 feat: add presenterm 2026-03-18 00:50:39 +01:00
b19305f198 chore: bump lockfile 2026-03-17 11:28:39 +01:00
1975659715 feat: ephvm improvements 2026-03-16 09:49:55 +01:00
b2ad5a8be5 feat: add power-efficiency settings for fw16 2026-03-15 09:27:38 +01:00
c964d42635 feat: drop eww and swaync 2026-03-14 13:51:53 +01:00
e49a91b7c8 feat: migrate to regreet from tuigreet 2026-03-13 09:37:19 +01:00
3011898b28 feat: add sway runtime dependencies 2026-03-12 18:30:39 +01:00
760a0d367e feat: add wl-mirror, wf-recorder, ffmpeg and mpv 2026-03-09 20:32:01 +01:00
db9e82119d chore: bump lockfile 2026-03-09 00:18:17 +01:00
a6cc138507 feat: optimize ephvm image size 2026-03-08 20:40:41 +01:00
1543878dda feat: use claude-code from nixpkgs master 2026-03-08 20:17:35 +01:00
9575e785fa feat: enable nix-ld in workstation module 2026-03-08 01:42:22 +01:00
38ba80c08b feat: add completion flags to ahab 2026-03-08 01:42:04 +01:00
d0413239cd feat: enable binfmt aarch64-linux on tower 2026-03-07 23:29:08 +01:00
36684b93ef merge: ephemeral vm setup 2026-03-07 23:18:32 +01:00
c5afcb10f7 feat: add ephvm related scripts 2026-03-07 23:17:45 +01:00
53ddba4457 feat: add ephvm host 2026-03-07 23:17:33 +01:00
aaee9558a7 feat: add vm-guest and vm-9p-automount modules 2026-03-07 22:16:14 +01:00
842479d4e7 feat: add option for dotfile linking for neovim 2026-03-07 22:15:46 +01:00
552196c3f9 feat: add optional argument to just switch 2026-03-07 20:12:03 +01:00
95bd3dc30a merge: host renames 2026-03-07 17:28:34 +01:00
501606665c chore: blame ignore 258902d409 2026-03-07 17:28:21 +01:00
258902d409 chore: rename live-iso to iso 2026-03-07 17:28:12 +01:00
c834f65f47 chore: blame ignore bebb7c42bb 2026-03-07 17:24:43 +01:00
bebb7c42bb chore: rename matej-tower to tower 2026-03-07 17:24:34 +01:00
19766372b8 chore: blame ignore cfe4c43887 2026-03-07 17:21:42 +01:00
cfe4c43887 chore: rename matej-nixos to fw16 2026-03-07 17:20:41 +01:00
45c6a6ff2d merge: home manager refactor 2026-03-07 16:29:58 +01:00
648d16affa feat: refactor matej/homeManager.nix with new modules 2026-03-07 16:29:51 +01:00
48a68d0130 feat: create initial home manager modules 2026-03-07 16:24:51 +01:00
0f52308b95 merge: profiles and improved mkHost 2026-03-07 16:00:28 +01:00
78dd75ec88 feat: auto import modules and simplify configs 2026-03-07 15:59:07 +01:00
f9706b2958 feat: export profiles in flake 2026-03-07 15:50:15 +01:00
d60721f955 feat: setup initial profiles 2026-03-07 15:48:46 +01:00
f3aa4847c5 chore: remove gorazd user 2026-03-07 15:46:28 +01:00
2afc3dd068 feat: migrate matej-nixos to framework16 amd-ai series 2026-03-07 13:54:37 +01:00
786748caeb feat: add claude home-manager module 2026-03-06 00:36:11 +01:00
d182532b34 feat: add check to justfile 2026-03-02 15:32:28 +01:00
f743082fd4 chore: bump lockfile 2026-03-02 15:31:06 +01:00
d813060f1e fix: autoDir for packages and flat directories 2026-03-02 15:30:34 +01:00
2ae02f0441 feat: bump ahab to v0.4.2 2026-03-02 14:53:58 +01:00
8e749c9fff feat: bump todo-mcp to v0.3.1 2026-03-02 14:48:54 +01:00
7f24c46ee2 feat: bump ggman to v1.27.1 2026-03-02 14:48:49 +01:00
0af754704e feat: refactor packages and add update scripts 2026-03-02 14:48:13 +01:00
2de3bcb56b feat: add git.janezic.dev/janezicmatej/todo-mcp 2026-03-01 11:31:05 +01:00
10f6da3b6d feat: add ryoppippi/claude-code-overlay 2026-02-27 14:04:42 +01:00
ad9b4e91e8 feat: bump ahab to v0.4.1 2026-02-27 03:40:31 -05:00
72 changed files with 1837 additions and 1116 deletions

View File

@@ -1,3 +1,8 @@
# nix fmt & statix # nix fmt & statix
f011c8d71ba09bd94ab04b8d771858b90a03fbf9 f011c8d71ba09bd94ab04b8d771858b90a03fbf9
3aff25b4486a143cd6282f8845c16216598e1c7e 3aff25b4486a143cd6282f8845c16216598e1c7e
# host rename
cfe4c43887a41e52be4e6472474c0fc3788f86e8
bebb7c42bbe87fe041b53189e78a4553e8c08666
258902d409e68b47f781451e6d306a8e47198d75

View File

@@ -12,3 +12,13 @@ repos:
language: system language: system
files: \.nix$ files: \.nix$
pass_filenames: false pass_filenames: false
- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.11.0
hooks:
- id: shellcheck
args: [-x, -P, scripts]
- repo: https://github.com/scop/pre-commit-shfmt
rev: v3.12.0-2
hooks:
- id: shfmt
args: [-d]

22
features/calibre.nix Normal file
View File

@@ -0,0 +1,22 @@
{
nixos =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.calibre ];
# udev rules for kindle and mtp device access
# NOTE:(@janezicmatej) uses services.udev.packages instead of extraRules
# because extraRules writes to 99-local.rules which is too late for uaccess
# see https://github.com/NixOS/nixpkgs/issues/308681
services.udev.packages = [
pkgs.libmtp
(pkgs.writeTextFile {
name = "kindle-udev-rules";
text = ''
ACTION!="remove", SUBSYSTEM=="usb", ATTRS{idVendor}=="1949", TAG+="uaccess"
'';
destination = "/etc/udev/rules.d/70-kindle.rules";
})
];
};
}

10
features/claude.nix Normal file
View File

@@ -0,0 +1,10 @@
{
home =
{ pkgs, ... }:
{
home.packages = [
pkgs.claude-code
pkgs.mcp-nixos
];
};
}

85
features/desktop.nix Normal file
View File

@@ -0,0 +1,85 @@
{
nixos =
{ pkgs, inputs, ... }:
{
imports = [ inputs.stylix.nixosModules.stylix ];
# audio
services.pipewire = {
enable = true;
pulse.enable = true;
};
# bluetooth
hardware.bluetooth.enable = true;
services.blueman.enable = true;
security.polkit.enable = true;
services.dbus.enable = true;
services.playerctld.enable = true;
xdg.portal = {
enable = true;
xdgOpenUsePortal = true;
extraPortals = [
pkgs.xdg-desktop-portal-wlr
pkgs.xdg-desktop-portal-gtk
];
};
fonts.packages = with pkgs; [
font-awesome
nerd-fonts.jetbrains-mono
];
# theming
stylix = {
enable = true;
polarity = "dark";
image = "${inputs.assets}/wallpaper.png";
base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-material-dark-medium.yaml";
};
programs.thunderbird.enable = true;
programs._1password.enable = true;
programs._1password-gui.enable = true;
environment.systemPackages = with pkgs; [
easyeffects
ghostty
google-chrome
zathura
pavucontrol
bolt-launcher
libnotify
bibata-cursors
vesktop
rocketchat-desktop
telegram-desktop
slack
jellyfin-media-player
cider-2
mpv
ffmpeg
wf-recorder
wl-mirror
protonmail-bridge
ledger-live-desktop
];
# internal CA
security.pki.certificateFiles = [
inputs.self.outputs.packages.${pkgs.stdenv.hostPlatform.system}.ca-matheo-si
];
xdg.mime.defaultApplications = {
"application/pdf" = "org.pwmt.zathura.desktop";
};
};
home =
{ inputs, ... }:
{
home.file.".assets".source = inputs.assets;
};
}

16
features/dev-registry.nix Normal file
View File

@@ -0,0 +1,16 @@
{
nixos =
{ inputs, ... }:
{
nix.registry.dev = {
from = {
type = "indirect";
id = "dev";
};
to = {
type = "path";
path = inputs.self.outPath;
};
};
};
}

30
features/dev.nix Normal file
View File

@@ -0,0 +1,30 @@
{
home =
{ pkgs, inputs, ... }:
let
packages = inputs.self.outputs.packages.${pkgs.stdenv.hostPlatform.system};
in
{
home.packages = [
pkgs.git
packages.git-linearize
packages.ggman
pkgs.go
pkgs.python3
pkgs.mdbook
pkgs.marksman
pkgs.mdformat
pkgs.google-cloud-sdk
pkgs.google-cloud-sql-proxy
packages.ahab
pkgs.just
pkgs.presenterm
pkgs.osc
];
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
};
}

12
features/docker.nix Normal file
View File

@@ -0,0 +1,12 @@
{
nixos =
{ user, ... }:
{
virtualisation.docker = {
enable = true;
logDriver = "json-file";
};
users.users.${user}.extraGroups = [ "docker" ];
};
}

9
features/gnupg.nix Normal file
View File

@@ -0,0 +1,9 @@
{
nixos = _: {
programs.gnupg.agent = {
enable = true;
enableSSHSupport = true;
enableExtraSocket = true;
};
};
}

28
features/greeter.nix Normal file
View File

@@ -0,0 +1,28 @@
{
nixos =
{ lib, inputs, ... }:
{
programs.regreet = {
enable = true;
# single output to avoid stretching across monitors
cageArgs = [
"-s"
"-m"
"last"
];
font = {
name = lib.mkForce "JetBrainsMono Nerd Font";
size = lib.mkForce 14;
};
settings = {
background = {
path = lib.mkForce "${inputs.assets}/wallpaper.png";
fit = lib.mkForce "Cover";
};
GTK = {
application_prefer_dark_theme = lib.mkForce true;
};
};
};
};
}

75
features/initrd-ssh.nix Normal file
View File

@@ -0,0 +1,75 @@
{
nixos =
{ lib, config, ... }:
let
keyDir = "/etc/secrets/initrd";
mkIpString =
{
address,
gateway,
netmask,
interface,
...
}:
"${address}::${gateway}:${netmask}::${interface}:none";
in
{
options = {
initrd-ssh = {
ip = {
enable = lib.mkEnableOption "static IP for initrd (otherwise DHCP)";
address = lib.mkOption {
type = lib.types.str;
};
gateway = lib.mkOption {
type = lib.types.str;
};
netmask = lib.mkOption {
type = lib.types.str;
default = "255.255.255.0";
};
interface = lib.mkOption {
type = lib.types.str;
};
};
authorizedKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
networkModule = lib.mkOption {
type = lib.types.str;
};
};
};
config = {
boot.initrd.kernelModules = [ config.initrd-ssh.networkModule ];
boot.kernelParams = lib.mkIf config.initrd-ssh.ip.enable [
"ip=${mkIpString config.initrd-ssh.ip}"
];
boot.initrd.network = {
enable = true;
ssh = {
enable = true;
port = 22;
hostKeys = [
"${keyDir}/ssh_host_rsa_key"
"${keyDir}/ssh_host_ed25519_key"
];
inherit (config.initrd-ssh) authorizedKeys;
};
postCommands = ''
echo 'cryptsetup-askpass' >> /root/.profile
'';
};
};
};
}

25
features/localisation.nix Normal file
View File

@@ -0,0 +1,25 @@
{
nixos =
{ lib, config, ... }:
{
options = {
localisation = {
timeZone = lib.mkOption {
type = lib.types.str;
};
defaultLocale = lib.mkOption {
type = lib.types.str;
};
};
};
config = {
time.timeZone = config.localisation.timeZone;
i18n.defaultLocale = config.localisation.defaultLocale;
# NOTE:(@janezicmatej) some apps (e.g. java) need TZ env var explicitly
environment.variables.TZ = config.localisation.timeZone;
};
};
}

69
features/neovim.nix Normal file
View File

@@ -0,0 +1,69 @@
{
home =
{
config,
options,
lib,
pkgs,
inputs,
...
}:
{
options = {
neovim.dotfiles = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
};
};
config = lib.mkMerge [
(lib.optionalAttrs (options ? stylix) {
# disable stylix neovim target when stylix is present (loaded by desktop feature)
stylix.targets.neovim.enable = false;
})
{
xdg.configFile."nvim" = lib.mkIf (config.neovim.dotfiles != null) {
source = config.neovim.dotfiles;
};
programs.neovim = {
enable = true;
vimAlias = true;
defaultEditor = true;
package = inputs.neovim-nightly-overlay.packages.${pkgs.stdenv.hostPlatform.system}.default;
extraPackages = with pkgs; [
gcc
luajit
nodejs_22
tree-sitter
gnumake
osc
fd
ripgrep
bat
delta
pyright
typescript-language-server
lua-language-server
gopls
nil
nixd
nixpkgs-fmt
stylua
];
extraWrapperArgs = [
"--suffix"
"LD_LIBRARY_PATH"
":"
"${lib.makeLibraryPath [ pkgs.stdenv.cc.cc.lib ]}"
];
};
}
];
};
}

View File

@@ -0,0 +1,9 @@
{
nixos = _: {
networking.networkmanager.enable = true;
networking.nameservers = [
"1.1.1.1"
"8.8.8.8"
];
};
}

5
features/nix-ld.nix Normal file
View File

@@ -0,0 +1,5 @@
{
nixos = _: {
programs.nix-ld.enable = true;
};
}

25
features/openssh.nix Normal file
View File

@@ -0,0 +1,25 @@
{
nixos =
{ lib, config, ... }:
{
options = {
openssh.port = lib.mkOption {
type = lib.types.port;
default = 22;
};
};
config = {
services.openssh = {
enable = true;
ports = [ config.openssh.port ];
settings = {
PasswordAuthentication = false;
AllowUsers = null;
PermitRootLogin = "no";
StreamLocalBindUnlink = "yes";
};
};
};
};
}

10
features/printing.nix Normal file
View File

@@ -0,0 +1,10 @@
{
nixos = _: {
services.printing.enable = true;
services.avahi = {
enable = true;
nssmdns4 = true;
openFirewall = true;
};
};
}

25
features/shell.nix Normal file
View File

@@ -0,0 +1,25 @@
{
nixos = _: {
programs.zsh.enable = true;
environment.etc."zshenv".text = ''
export ZDOTDIR=$HOME/.config/zsh
'';
};
home =
{ pkgs, ... }:
{
home.packages = with pkgs; [
starship
fzf
htop
jc
jq
openssl
pv
ripgrep
fd
tmux
];
};
}

10
features/steam.nix Normal file
View File

@@ -0,0 +1,10 @@
{
nixos = _: {
programs.steam = {
enable = true;
remotePlay.openFirewall = true;
dedicatedServer.openFirewall = true;
localNetworkGameTransfers.openFirewall = true;
};
};
}

38
features/sway.nix Normal file
View File

@@ -0,0 +1,38 @@
{
nixos =
{ pkgs, ... }:
{
programs.sway = {
enable = true;
package = pkgs.swayfx;
wrapperFeatures.gtk = true;
extraSessionCommands = ''
# fix for java awt apps not rendering
export _JAVA_AWT_WM_NONREPARENTING=1
'';
};
environment.systemPackages = with pkgs; [
waybar
mako
wob
playerctl
brightnessctl
foot
grim
pulseaudio
swayidle
swaylock-effects
jq
slurp
wl-clipboard
pamixer
wlsunset
satty
wayland-pipewire-idle-inhibit
fuzzel
cliphist
zenity
];
};
}

8
features/tailscale.nix Normal file
View File

@@ -0,0 +1,8 @@
{
nixos = _: {
services.tailscale = {
enable = true;
useRoutingFeatures = "both";
};
};
}

35
features/user-matej.nix Normal file
View File

@@ -0,0 +1,35 @@
let
sshKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQGLdINKzs+sEy62Pefng0bcedgU396+OryFgeH99/c janezicmatej"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDk00+Km03epQXQs+xEwwH3zcurACzkEH+kDOPBw6RQe openpgp:0xB095D449"
];
in
{
keys = {
sshAuthorizedKeys = sshKeys;
};
nixos =
{ pkgs, ... }:
{
programs.zsh.enable = true;
users.users.matej = {
uid = 1000;
isNormalUser = true;
home = "/home/matej";
shell = pkgs.zsh;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = sshKeys;
};
users.groups.matej = {
gid = 1000;
members = [ "matej" ];
};
};
home = _: {
home.stateVersion = "24.11";
};
}

View File

@@ -0,0 +1,72 @@
{
nixos =
{
pkgs,
lib,
config,
...
}:
let
inherit (config.vm-9p-automount) user;
inherit (config.users.users.${user}) home group;
in
{
options = {
vm-9p-automount = {
user = lib.mkOption {
type = lib.types.str;
};
prefix = lib.mkOption {
type = lib.types.str;
default = "m_";
};
basePath = lib.mkOption {
type = lib.types.str;
default = "${home}/mnt";
};
};
};
config = {
systemd.services.vm-9p-automount = {
description = "Auto-discover and mount 9p shares";
after = [
"local-fs.target"
"nss-user-lookup.target"
"systemd-modules-load.service"
];
wants = [ "systemd-modules-load.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = pkgs.writeShellScript "vm-9p-automount" ''
BASE="${config.vm-9p-automount.basePath}"
PREFIX="${config.vm-9p-automount.prefix}"
mkdir -p "$BASE"
chown ${user}:${group} "$BASE"
for tagfile in $(find /sys/devices -name mount_tag 2>/dev/null); do
[ -f "$tagfile" ] || continue
tag=$(tr -d '\0' < "$tagfile")
case "$tag" in
"$PREFIX"*) ;;
*) continue ;;
esac
name="''${tag#"$PREFIX"}"
target="$BASE/$name"
mkdir -p "$target"
${pkgs.util-linux}/bin/mount -t 9p "$tag" "$target" \
-o trans=virtio,version=9p2000.L || continue
done
'';
};
};
};
};
}

47
features/vm-guest.nix Normal file
View File

@@ -0,0 +1,47 @@
{
nixos =
{
pkgs,
lib,
config,
...
}:
{
options = {
vm-guest.headless = lib.mkOption {
type = lib.types.bool;
default = false;
};
};
config = {
services.qemuGuest.enable = true;
services.spice-vdagentd.enable = lib.mkIf (!config.vm-guest.headless) true;
boot.kernelParams = lib.mkIf config.vm-guest.headless [ "console=ttyS0,115200" ];
boot.initrd.availableKernelModules = [
"9p"
"9pnet_virtio"
];
boot.kernelModules = [
"9p"
"9pnet_virtio"
];
networking = {
useDHCP = true;
firewall.allowedTCPPorts = [ 22 ];
};
security.sudo.wheelNeedsPassword = false;
environment.systemPackages = with pkgs; [
curl
wget
htop
sshfs
];
};
};
}

12
features/yubikey.nix Normal file
View File

@@ -0,0 +1,12 @@
{
nixos =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
yubikey-personalization
yubikey-manager
];
services.pcscd.enable = true;
};
}

191
flake.lock generated
View File

@@ -99,6 +99,26 @@
"type": "github" "type": "github"
} }
}, },
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1773889306,
"narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=",
"owner": "nix-community",
"repo": "disko",
"rev": "5ad85c82cc52264f4beddc934ba57f3789f28347",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"firefox-gnome-theme": { "firefox-gnome-theme": {
"flake": false, "flake": false,
"locked": { "locked": {
@@ -133,17 +153,14 @@
}, },
"flake-parts": { "flake-parts": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": "nixpkgs-lib"
"neovim-nightly-overlay",
"nixpkgs"
]
}, },
"locked": { "locked": {
"lastModified": 1769996383, "lastModified": 1772408722,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381", "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -153,6 +170,27 @@
} }
}, },
"flake-parts_2": { "flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"neovim-nightly-overlay",
"nixpkgs"
]
},
"locked": {
"lastModified": 1772408722,
"narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_3": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"stylix", "stylix",
@@ -173,24 +211,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"fromYaml": { "fromYaml": {
"flake": false, "flake": false,
"locked": { "locked": {
@@ -255,11 +275,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1771744638, "lastModified": 1774274588,
"narHash": "sha256-EDLi+YAsEEAmMeZe1v6GccuGRbCkpSZp/+A6g+pivR8=", "narHash": "sha256-dnHvv5EMUgTzGZmA+3diYjQU2O6BEpGLEOgJ1Qe9LaY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "cb6c151f5c9db4df0b69d06894dc8484de1f16a0", "rev": "cf9686ba26f5ef788226843bc31fda4cf72e373b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -295,16 +315,16 @@
}, },
"neovim-nightly-overlay": { "neovim-nightly-overlay": {
"inputs": { "inputs": {
"flake-parts": "flake-parts", "flake-parts": "flake-parts_2",
"neovim-src": "neovim-src", "neovim-src": "neovim-src",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1771891493, "lastModified": 1774483626,
"narHash": "sha256-L0OCnG8rsWJYZ3mzHSz0iENtlBXQjjcGgvMgsBqN14U=", "narHash": "sha256-8VAX9GXNfv4eBj0qBEf/Rc2/E6G0SBEpuo2A5plw34I=",
"owner": "nix-community", "owner": "nix-community",
"repo": "neovim-nightly-overlay", "repo": "neovim-nightly-overlay",
"rev": "7db85d094c68697fc36801bccdf015b4c2bdb274", "rev": "5deaa19e80e1c0695f7fa8a16e13a704fd08f96e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -316,11 +336,11 @@
"neovim-src": { "neovim-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1771885993, "lastModified": 1774472446,
"narHash": "sha256-2c4H+5f0qhsp13Vx8pbsGiSRTHBJIfQaRAAUSHGEpgo=", "narHash": "sha256-Hp4A0llEmBvvNuw5uKOz+BA86X7TmXZ1vUK0StiMdVs=",
"owner": "neovim", "owner": "neovim",
"repo": "neovim", "repo": "neovim",
"rev": "d9d8c660fd5559d928c8870a21970a375674e310", "rev": "c9e961994b16ed841be43541ef550bf3d3f043ec",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -329,13 +349,29 @@
"type": "github" "type": "github"
} }
}, },
"nixos-hardware": {
"locked": {
"lastModified": 1774465523,
"narHash": "sha256-4v7HPm63Q90nNn4fgkgKsjW1AH2Klw7XzPtHJr562nM=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "de895be946ad1d8aafa0bb6dfc7e7e0e9e466a29",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixos-hardware",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1771423170, "lastModified": 1774273680,
"narHash": "sha256-K7Dg9TQ0mOcAtWTO/FX/FaprtWQ8BmEXTpLIaNRhEwU=", "narHash": "sha256-a++tZ1RQsDb1I0NHrFwdGuRlR5TORvCEUksM459wKUA=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "bcc4a9d9533c033d806a46b37dc444f9b0da49dd", "rev": "fdc7b8f7b30fdbedec91b71ed82f36e1637483ed",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -345,13 +381,28 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-lib": {
"locked": {
"lastModified": 1772328832,
"narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-master": { "nixpkgs-master": {
"locked": { "locked": {
"lastModified": 1771932323, "lastModified": 1774515149,
"narHash": "sha256-3PadsTzuMJT/x0KmiD/Me1GG6rW8kaHoWVduSs0ue7o=", "narHash": "sha256-avcNAzwJC2lOyMNKVro2u5d6RLGiquXXxQVVmAEQ2+U=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "89bb5c5da7a857869cc88ef9b856bffdff8af264", "rev": "01fcaaa08a9a44ec63c52bf0ee8d9a29593fee07",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -363,11 +414,11 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1771482645, "lastModified": 1774273680,
"narHash": "sha256-MpAKyXfJRDTgRU33Hja+G+3h9ywLAJJNRq4Pjbb4dQs=", "narHash": "sha256-a++tZ1RQsDb1I0NHrFwdGuRlR5TORvCEUksM459wKUA=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "724cf38d99ba81fbb4a347081db93e2e3a9bc2ae", "rev": "fdc7b8f7b30fdbedec91b71ed82f36e1637483ed",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -379,11 +430,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1771714954, "lastModified": 1774244481,
"narHash": "sha256-nhZJPnBavtu40/L2aqpljrfUNb2rxmWTmSjK2c9UKds=", "narHash": "sha256-4XfMXU0DjN83o6HWZoKG9PegCvKvIhNUnRUI19vzTcQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "afbbf774e2087c3d734266c22f96fca2e78d3620", "rev": "4590696c8693fea477850fe379a01544293ca4e2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -418,6 +469,22 @@
"type": "github" "type": "github"
} }
}, },
"nvim": {
"flake": false,
"locked": {
"lastModified": 1773783263,
"narHash": "sha256-lZG4VERlfCwEJpW6C5irkwUxB+JoPVmuV3qOYD9WNYY=",
"ref": "refs/heads/main",
"rev": "a95f1be85c858cb7d1bc0a8506dc9cb01161a3e7",
"revCount": 93,
"type": "git",
"url": "https://git.janezic.dev/janezicmatej/nvim.git"
},
"original": {
"type": "git",
"url": "https://git.janezic.dev/janezicmatej/nvim.git"
}
},
"pre-commit": { "pre-commit": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
@@ -444,13 +511,16 @@
"root": { "root": {
"inputs": { "inputs": {
"assets": "assets", "assets": "assets",
"flake-utils": "flake-utils", "disko": "disko",
"flake-parts": "flake-parts",
"home-manager": "home-manager", "home-manager": "home-manager",
"lanzaboote": "lanzaboote", "lanzaboote": "lanzaboote",
"neovim-nightly-overlay": "neovim-nightly-overlay", "neovim-nightly-overlay": "neovim-nightly-overlay",
"nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"nixpkgs-master": "nixpkgs-master", "nixpkgs-master": "nixpkgs-master",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
"nvim": "nvim",
"stylix": "stylix" "stylix": "stylix"
} }
}, },
@@ -482,13 +552,13 @@
"base16-helix": "base16-helix", "base16-helix": "base16-helix",
"base16-vim": "base16-vim", "base16-vim": "base16-vim",
"firefox-gnome-theme": "firefox-gnome-theme", "firefox-gnome-theme": "firefox-gnome-theme",
"flake-parts": "flake-parts_2", "flake-parts": "flake-parts_3",
"gnome-shell": "gnome-shell", "gnome-shell": "gnome-shell",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
"nur": "nur", "nur": "nur",
"systems": "systems_2", "systems": "systems",
"tinted-foot": "tinted-foot", "tinted-foot": "tinted-foot",
"tinted-kitty": "tinted-kitty", "tinted-kitty": "tinted-kitty",
"tinted-schemes": "tinted-schemes", "tinted-schemes": "tinted-schemes",
@@ -496,11 +566,11 @@
"tinted-zed": "tinted-zed" "tinted-zed": "tinted-zed"
}, },
"locked": { "locked": {
"lastModified": 1771788390, "lastModified": 1774194089,
"narHash": "sha256-RzBpBwn93GWxLjacTte+ngwwg0L/BVOg4G/sSIeK3Rw=", "narHash": "sha256-SCczWhr8y8aaXVHG+gOGcRahNb0BU1Z5zYZuv9W/nA8=",
"owner": "danth", "owner": "danth",
"repo": "stylix", "repo": "stylix",
"rev": "ebb238f14d6f930068be4718472da3105fd5d3bf", "rev": "7c34241d80ea64dd2039bb3a786fb66b4c6261d9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -525,21 +595,6 @@
"type": "github" "type": "github"
} }
}, },
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"tinted-foot": { "tinted-foot": {
"flake": false, "flake": false,
"locked": { "locked": {

120
flake.nix
View File

@@ -6,16 +6,14 @@
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable";
nixpkgs-master.url = "github:nixos/nixpkgs/master"; nixpkgs-master.url = "github:nixos/nixpkgs/master";
# dotfiles = { nvim = {
# url = "git+https://git.janezic.dev/janezicmatej/.dotfiles.git"; url = "git+https://git.janezic.dev/janezicmatej/nvim.git";
# flake = false; flake = false;
# }; };
# nvim = {
# url = "git+https://git.janezic.dev/janezicmatej/nvim.git?ref=rewrite";
# flake = false;
# };
flake-utils.url = "github:numtide/flake-utils"; nixos-hardware.url = "github:NixOS/nixos-hardware/master";
flake-parts.url = "github:hercules-ci/flake-parts";
home-manager = { home-manager = {
url = "github:nix-community/home-manager/release-25.11"; url = "github:nix-community/home-manager/release-25.11";
@@ -27,10 +25,6 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
neovim-nightly-overlay = {
url = "github:nix-community/neovim-nightly-overlay";
};
lanzaboote = { lanzaboote = {
url = "github:nix-community/lanzaboote/v1.0.0"; url = "github:nix-community/lanzaboote/v1.0.0";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -40,93 +34,45 @@
url = "git+https://git.janezic.dev/janezicmatej/assets.git"; url = "git+https://git.janezic.dev/janezicmatej/assets.git";
flake = false; flake = false;
}; };
neovim-nightly-overlay.url = "github:nix-community/neovim-nightly-overlay";
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = outputs =
inputs@{ inputs@{
flake-parts,
nixpkgs, nixpkgs,
flake-utils, self,
... ...
}: }:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
./flake/overlays.nix
./flake/packages.nix
./flake/devshell.nix
./flake/hosts.nix
];
let systems = [ "x86_64-linux" ];
my-lib = import ./lib { inherit (nixpkgs) lib; };
overlays = [ perSystem =
(_: prev: { { system, ... }:
inherit {
( _module.args.pkgs = import nixpkgs {
(import inputs.nixpkgs-unstable { inherit system;
inherit (prev.stdenv.hostPlatform) system; overlays = [ self.overlays.default ];
config.allowUnfree = true; config.allowUnfree = true;
})
)
claude-code
;
})
];
mkHost = my-lib.mkHost {
inherit
nixpkgs
overlays
inputs
;
};
in
{
lib = my-lib;
nixosConfigurations = {
matej-nixos = mkHost "matej-nixos" {
system = "x86_64-linux";
users = [ "matej" ];
};
matej-tower = mkHost "matej-tower" {
system = "x86_64-linux";
users = [ "matej" ];
};
# nixos-rebuild build-image --image-variant install-iso --flake .#live-iso
live-iso = mkHost "live-iso" {
system = "x86_64-linux";
users = [ ];
}; };
}; };
nixosModules = import ./modules/nixos { flake = {
inherit my-lib; lib = import ./lib { inherit (nixpkgs) lib; };
inherit (nixpkgs) lib;
} { };
}
// flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages =
import ./packages
{
inherit my-lib;
inherit (nixpkgs) lib;
}
{
pkgs = nixpkgs.legacyPackages.${system};
pkgs-unstable = inputs.nixpkgs-unstable.legacyPackages.${system};
pkgs-master = inputs.nixpkgs-master.legacyPackages.${system};
}; };
formatter = pkgs.nixfmt-tree;
devShells.default = pkgs.mkShell {
packages = [
pkgs.pre-commit
pkgs.statix
];
}; };
}
);
} }

107
flake/devshell.nix Normal file
View File

@@ -0,0 +1,107 @@
_: {
perSystem =
{ pkgs, lib, ... }:
let
# libraries needed by python native extensions
pythonLibraries = [
pkgs.stdenv.cc.cc.lib
pkgs.zlib
pkgs.openssl
pkgs.curl
];
mkUv = python: {
packages = [
python
pkgs.uv
];
libraries = pythonLibraries;
env = {
UV_PYTHON_DOWNLOADS = "never";
UV_PYTHON_PREFERENCE = "only-system";
UV_PYTHON = "${python}/bin/python";
};
shellHook = ''
unset PYTHONPATH
export UV_PROJECT_ENVIRONMENT="$HOME/.venvs/$(basename "$PWD")-$(echo "$PWD" | md5sum | cut -c1-8)"
'';
};
# composable dev environment components
# each is exposed as its own devShell, layered via `use dev` in .envrc
components = {
uv_10 = mkUv pkgs.python310;
uv_11 = mkUv pkgs.python311;
uv_12 = mkUv pkgs.python312;
uv_13 = mkUv pkgs.python313;
uv_14 = mkUv pkgs.python314;
pg_15 = {
packages = [ pkgs.postgresql_15 ];
};
pg_16 = {
packages = [ pkgs.postgresql_16 ];
};
pg_17 = {
packages = [ pkgs.postgresql_17 ];
};
pg_18 = {
packages = [ pkgs.postgresql_18 ];
};
rust = {
packages = [
pkgs.rustc
pkgs.cargo
pkgs.rust-analyzer
pkgs.openssl
pkgs.pkg-config
];
};
cmake = {
packages = [
pkgs.cmake
pkgs.ninja
];
};
};
mkComponentShell =
component:
let
c = components.${component};
libraries = c.libraries or [ ];
libPath = lib.makeLibraryPath libraries;
in
pkgs.mkShell (
{
packages = c.packages or [ ];
shellHook =
(lib.optionalString (libraries != [ ]) ''
export LD_LIBRARY_PATH="${libPath}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
'')
+ (c.shellHook or "");
}
// lib.optionalAttrs (c ? env) { inherit (c) env; }
);
componentShells = lib.mapAttrs (name: _: mkComponentShell name) components;
in
{
formatter = pkgs.nixfmt-tree;
devShells = {
default = pkgs.mkShell {
packages = [
pkgs.pre-commit
pkgs.statix
pkgs.shellcheck
pkgs.shfmt
pkgs.qemu
];
};
}
// componentShells;
};
}

105
flake/hosts.nix Normal file
View File

@@ -0,0 +1,105 @@
{ inputs, self, ... }:
let
inherit (inputs) nixpkgs;
my-lib = import ../lib { inherit (nixpkgs) lib; };
mkHost = my-lib.mkHost {
inherit nixpkgs inputs;
overlays = [ self.overlays.default ];
};
in
{
flake.nixosConfigurations = {
fw16 = mkHost "fw16" {
system = "x86_64-linux";
user = "matej";
features = [
"openssh"
"localisation"
"gnupg"
"shell"
"desktop"
"sway"
"greeter"
"printing"
"networkmanager"
"docker"
"tailscale"
"nix-ld"
"yubikey"
"calibre"
"steam"
"dev-registry"
"neovim"
"dev"
"claude"
];
};
tower = mkHost "tower" {
system = "x86_64-linux";
user = "matej";
features = [
"openssh"
"localisation"
"gnupg"
"shell"
"desktop"
"sway"
"greeter"
"printing"
"networkmanager"
"docker"
"tailscale"
"nix-ld"
"yubikey"
"calibre"
"steam"
"initrd-ssh"
"dev-registry"
"neovim"
"dev"
"claude"
];
};
# nixos-rebuild build-image --image-variant install-iso --flake .#iso
iso = mkHost "iso" {
system = "x86_64-linux";
user = "matej";
features = [
"openssh"
];
};
# nix run github:nix-community/nixos-anywhere -- --flake .#floo root@<ip>
floo = mkHost "floo" {
system = "x86_64-linux";
user = "matej";
features = [
"openssh"
"localisation"
"shell"
"tailscale"
];
};
ephvm = mkHost "ephvm" {
system = "x86_64-linux";
user = "matej";
features = [
"openssh"
"localisation"
"gnupg"
"shell"
"vm-guest"
"vm-9p-automount"
"docker"
"neovim"
"claude"
"dev"
];
};
};
}

21
flake/overlays.nix Normal file
View File

@@ -0,0 +1,21 @@
{ inputs, ... }:
{
flake.overlays.default =
_: prev:
let
pkgs-unstable = import inputs.nixpkgs-unstable {
inherit (prev.stdenv.hostPlatform) system;
inherit (prev) config;
};
pkgs-master = import inputs.nixpkgs-master {
inherit (prev.stdenv.hostPlatform) system;
inherit (prev) config;
};
in
{
inherit (pkgs-master) claude-code;
# TODO:(@janezicmatej) 2026-03-09 error with stable for telegram-desktop
inherit (pkgs-unstable) telegram-desktop;
};
}

22
flake/packages.nix Normal file
View File

@@ -0,0 +1,22 @@
{ inputs, ... }:
let
my-lib = import ../lib { inherit (inputs.nixpkgs) lib; };
in
{
perSystem =
{ pkgs, system, ... }:
{
packages =
import ../packages
{
inherit my-lib;
inherit (inputs.nixpkgs) lib;
}
{
inherit pkgs;
pkgs-unstable = inputs.nixpkgs-unstable.legacyPackages.${system};
pkgs-master = inputs.nixpkgs-master.legacyPackages.${system};
};
};
}

View File

@@ -0,0 +1,62 @@
{
pkgs,
lib,
inputs,
...
}:
{
# no hardware firmware needed in a VM
hardware.enableRedistributableFirmware = lib.mkForce false;
hardware.wirelessRegulatoryDatabase = lib.mkForce false;
documentation.enable = false;
environment.defaultPackages = [ ];
# compressed qcow2, no channel copy
image.modules.qemu =
{ config, modulesPath, ... }:
{
system.build.image = lib.mkForce (
import (modulesPath + "/../lib/make-disk-image.nix") {
inherit lib config pkgs;
inherit (config.virtualisation) diskSize;
inherit (config.image) baseName;
format = "qcow2-compressed";
copyChannel = false;
partitionTableType = "legacy";
}
);
};
vm-guest.headless = true;
vm-9p-automount.user = "matej";
localisation = {
timeZone = "UTC";
defaultLocale = "en_US.UTF-8";
};
home-manager.users.matej = {
neovim.dotfiles = inputs.nvim;
};
# ensure .config exists with correct ownership before automount
systemd.tmpfiles.rules = [ "d /home/matej/.config 0755 matej users -" ];
# writable claude config via 9p
fileSystems."/home/matej/.config/claude" = {
device = "claude";
fsType = "9p";
options = [
"trans=virtio"
"version=9p2000.L"
"nofail"
"x-systemd.automount"
];
};
environment.sessionVariables.CLAUDE_CONFIG_DIR = "/home/matej/.config/claude";
system.stateVersion = "25.11";
}

View File

@@ -0,0 +1,22 @@
{
lib,
pkgs,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
virtualisation.diskSize = 30720; # 30G
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
autoResize = true;
fsType = "ext4";
};
# image.modules (disk-image.nix) overrides boot loader per variant
boot.loader.grub.device = lib.mkDefault "/dev/vda";
}

View File

@@ -0,0 +1,37 @@
{ inputs, ... }:
{
imports = [ inputs.disko.nixosModules.disko ];
boot.loader.grub.enable = true;
disko.devices.disk.main = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
boot = {
size = "1M";
type = "EF02";
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
users.users.matej.hashedPassword = "$6$59Z5NIkOYZ3eSElX$FehMGGXQlC040G8eoO42JQDScb7hI04NbdVMAkKYKqVOLTO/.MJxfk8fHypQHrCdtAs67N1bnU2s5H/3zLWhC1";
localisation = {
timeZone = "Europe/Ljubljana";
defaultLocale = "en_US.UTF-8";
};
system.stateVersion = "25.11";
}

View File

@@ -0,0 +1,37 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"ahci"
"xhci_pci"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp1s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View File

@@ -0,0 +1,57 @@
{
lib,
pkgs,
inputs,
options,
...
}:
{
imports = [
inputs.nixos-hardware.nixosModules.framework-16-amd-ai-300-series
];
localisation = {
timeZone = "Europe/Ljubljana";
defaultLocale = "en_US.UTF-8";
};
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.kernelParams = [ "pcie_aspm.policy=powersupersave" ];
boot.resumeDevice = "/dev/disk/by-uuid/ff4750e7-3a9f-42c2-bb68-c458a6560540";
services.logind.settings.Login = {
HandleLidSwitch = "suspend-then-hibernate";
HandlePowerKey = "suspend-then-hibernate";
IdleAction = "suspend-then-hibernate";
IdleActionSec = "15min";
};
systemd.sleep.extraConfig = ''
HibernateDelaySec=30min
'';
programs.nix-ld.libraries = options.programs.nix-ld.libraries.default;
services.gnome.gnome-keyring.enable = true;
services.teamviewer.enable = true;
services.hardware.bolt.enable = true;
hardware.keyboard.zsa.enable = true;
hardware.ledger.enable = true;
hardware.bluetooth.powerOnBoot = true;
hardware.inputmodule.enable = true;
# NOTE:(@janezicmatej) disable wakeup for framework input modules to prevent spurious wakes
services.udev.extraRules = lib.mkAfter ''
SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0012", ATTR{power/wakeup}="disabled"
SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0014", ATTR{power/wakeup}="disabled"
'';
networking.firewall.enable = false;
system.stateVersion = "24.11";
}

View File

@@ -17,8 +17,10 @@
boot.initrd.availableKernelModules = [ boot.initrd.availableKernelModules = [
"nvme" "nvme"
"xhci_pci" "xhci_pci"
"ahci" "thunderbolt"
"usbhid" "usbhid"
"uas"
"sd_mod"
]; ];
boot.initrd.kernelModules = [ "dm-snapshot" ]; boot.initrd.kernelModules = [ "dm-snapshot" ];
boot.kernelModules = [ "kvm-amd" ]; boot.kernelModules = [ "kvm-amd" ];
@@ -33,7 +35,7 @@
}; };
fileSystems."/boot" = { fileSystems."/boot" = {
device = "/dev/disk/by-uuid/7151-CE52"; device = "/dev/disk/by-uuid/42D9-FAFD";
fsType = "vfat"; fsType = "vfat";
options = [ options = [
"fmask=0022" "fmask=0022"

View File

@@ -0,0 +1,11 @@
_: {
image.modules.iso-installer = {
isoImage.squashfsCompression = "zstd -Xcompression-level 6";
};
# live iso: passwordless login and sudo
users.users.matej.initialHashedPassword = "";
security.sudo.wheelNeedsPassword = false;
system.stateVersion = "25.05";
}

View File

@@ -1,49 +0,0 @@
{
pkgs,
lib,
inputs,
...
}:
let
keys = import ../../users/matej/keys.nix;
in
{
imports = [
inputs.self.nixosModules.openssh
];
openssh.enable = true;
image.modules.iso-installer = {
isoImage.squashfsCompression = "zstd -Xcompression-level 6";
};
fileSystems."/" = lib.mkDefault {
device = "/dev/disk/by-label/nixos";
fsType = "ext4";
};
boot.loader.grub.device = lib.mkDefault "/dev/sda";
networking.firewall.allowedTCPPorts = [ 22 ];
users = {
groups.matej = {
gid = 1000;
};
users.matej = {
group = "matej";
uid = 1000;
isNormalUser = true;
home = "/home/matej";
createHome = true;
password = "burek123";
extraGroups = [
"wheel"
"users"
];
openssh.authorizedKeys.keys = keys.sshAuthorizedKeys;
};
};
system.stateVersion = "25.05";
}

View File

@@ -1,124 +0,0 @@
{
config,
lib,
pkgs,
inputs,
options,
...
}:
let
packages = inputs.self.outputs.packages.${pkgs.stdenv.hostPlatform.system};
in
{
imports = [
inputs.stylix.nixosModules.stylix
inputs.self.nixosModules.yubikey
inputs.self.nixosModules.sway
inputs.self.nixosModules.openssh
inputs.self.nixosModules.desktop
inputs.self.nixosModules.printing
inputs.self.nixosModules.zsh
inputs.self.nixosModules.gnupg
inputs.self.nixosModules.tuigreet
inputs.self.nixosModules.workstation
inputs.self.nixosModules.nvidia
inputs.self.nixosModules.initrd-ssh
inputs.self.nixosModules.localisation
];
yubikey.enable = true;
openssh.enable = true;
desktop.enable = true;
printing.enable = true;
zsh.enable = true;
gnupg.enable = true;
workstation.enable = true;
tuigreet = {
enable = true;
command = "sway";
};
sway = {
enable = true;
cmdFlags = [ "--unsupported-gpu" ];
};
nvidia.enable = true;
initrd-ssh = {
enable = true;
networkModule = "r8169";
ip = {
enable = true;
address = "10.222.0.247";
gateway = "10.222.0.1";
interface = "enp5s0";
};
};
stylix = {
enable = true;
polarity = "dark";
image = "${inputs.assets}/wallpaper.png";
base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-material-dark-medium.yaml";
};
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
localisation = {
enable = true;
timeZone = "Europe/Ljubljana";
defaultLocale = "en_US.UTF-8";
};
# WARN:(@janezicmatej) nix-ld for running pip-installed binaries outside nix, probably want to drop this
programs.nix-ld.enable = true;
programs.nix-ld.libraries = options.programs.nix-ld.libraries.default;
security.pki.certificateFiles = [ packages.ca-matheo-si ];
services.gnome.gnome-keyring.enable = true;
services.teamviewer.enable = true;
programs.thunderbird.enable = true;
programs._1password.enable = true;
programs._1password-gui.enable = true;
programs.firefox.enable = true;
programs.steam = {
enable = true;
remotePlay.openFirewall = true;
dedicatedServer.openFirewall = true;
localNetworkGameTransfers.openFirewall = true;
};
hardware.keyboard.zsa.enable = true;
hardware.ledger.enable = true;
hardware.bluetooth.powerOnBoot = true;
networking = {
hostName = "matej-nixos";
useDHCP = false;
networkmanager.enable = true;
interfaces.enp5s0.ipv4.addresses = [
{
address = "10.222.0.247";
prefixLength = 24;
}
];
firewall.enable = false;
defaultGateway = "10.222.0.1";
nameservers = [
"1.1.1.1"
"8.8.8.8"
];
};
xdg.mime.defaultApplications = {
"application/pdf" = "org.pwmt.zathura.desktop";
};
system.stateVersion = "24.11";
}

View File

@@ -1,91 +0,0 @@
{
config,
lib,
pkgs,
inputs,
options,
...
}:
{
networking.hostName = "matej-tower";
imports = [
inputs.stylix.nixosModules.stylix
inputs.lanzaboote.nixosModules.lanzaboote
inputs.self.nixosModules.yubikey
inputs.self.nixosModules.sway
inputs.self.nixosModules.openssh
inputs.self.nixosModules.desktop
inputs.self.nixosModules.printing
inputs.self.nixosModules.zsh
inputs.self.nixosModules.gnupg
inputs.self.nixosModules.tuigreet
inputs.self.nixosModules.workstation
inputs.self.nixosModules.initrd-ssh
inputs.self.nixosModules.localisation
];
yubikey.enable = true;
openssh.enable = true;
desktop.enable = true;
printing.enable = true;
zsh.enable = true;
gnupg.enable = true;
workstation.enable = true;
tuigreet = {
enable = true;
command = "sway";
};
sway.enable = true;
initrd-ssh = {
enable = true;
networkModule = "r8169";
};
stylix = {
enable = true;
polarity = "dark";
image = "${inputs.assets}/wallpaper.png";
base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-material-dark-medium.yaml";
};
# lanzaboote secure boot
boot.kernelParams = [ "btusb.reset=1" ];
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.lanzaboote = {
enable = true;
pkiBundle = "/var/lib/sbctl";
};
localisation = {
enable = true;
timeZone = "Europe/Ljubljana";
defaultLocale = "en_US.UTF-8";
};
services.udisks2.enable = true;
programs._1password.enable = true;
programs._1password-gui.enable = true;
# higher sample rate for audio equipment
services.pipewire.extraConfig.pipewire.adjust-sample-rate = {
"context.properties" = {
"default.clock.rate" = 192000;
"default.allowed-rates" = [ 192000 ];
};
};
environment.systemPackages = with pkgs; [
easyeffects
];
xdg.mime.defaultApplications = {
"application/pdf" = "org.pwmt.zathura.desktop";
};
system.stateVersion = "25.05";
}

View File

@@ -0,0 +1,43 @@
{
lib,
inputs,
userKeys,
...
}:
{
imports = [
inputs.lanzaboote.nixosModules.lanzaboote
];
localisation = {
timeZone = "Europe/Ljubljana";
defaultLocale = "en_US.UTF-8";
};
initrd-ssh = {
networkModule = "r8169";
authorizedKeys = userKeys.sshAuthorizedKeys;
};
# lanzaboote secure boot
boot.kernelParams = [ "btusb.reset=1" ];
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.lanzaboote = {
enable = true;
pkiBundle = "/var/lib/sbctl";
};
services.udisks2.enable = true;
# higher sample rate for audio equipment
services.pipewire.extraConfig.pipewire.adjust-sample-rate = {
"context.properties" = {
"default.clock.rate" = 192000;
"default.allowed-rates" = [ 192000 ];
};
};
system.stateVersion = "25.05";
}

View File

@@ -3,8 +3,8 @@ default:
@just --list @just --list
# rebuild and switch # rebuild and switch
switch: switch config="":
nixos-rebuild switch --flake . --sudo nixos-rebuild switch --flake .{{ if config != "" { "#" + config } else { "" } }} --sudo
# fetch flake inputs # fetch flake inputs
sync: sync:
@@ -17,9 +17,37 @@ update:
# update flake inputs, rebuild and switch # update flake inputs, rebuild and switch
bump: update switch bump: update switch
# update a package to latest version
update-package pkg:
bash packages/{{pkg}}/update.sh
# update all packages with update scripts
update-package-all:
@for script in packages/*/update.sh; do bash "$script"; done
# build all packages and hosts
build:
nix flake check
# build installation iso # build installation iso
iso: iso:
nixos-rebuild build-image --image-variant iso-installer --flake .#live-iso nixos-rebuild build-image --image-variant iso-installer --flake .#iso
# run ephemeral VM
ephvm *ARGS:
bash scripts/ephvm-run.sh {{ARGS}}
# ssh into running ephemeral VM
ephvm-ssh port="2222":
ssh -p {{port}} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null matej@localhost
# provision a host with nixos-anywhere
provision host ip:
nix run github:nix-community/nixos-anywhere -- --flake .#{{host}} --generate-hardware-config nixos-generate-config ./hosts/{{host}}/hardware-configuration.nix root@{{ip}}
# deploy config to a remote host
deploy host remote=host:
nixos-rebuild switch --flake .#{{host}} --target-host {{remote}} --sudo --ask-sudo-password
# garbage collect old generations # garbage collect old generations
clean: clean:

View File

@@ -1,15 +1,21 @@
lib: lib:
# import all .nix files in dir as attribute set # auto-discover nix modules from a directory
# - flat .nix files (excluding default.nix) are imported directly
# - subdirectories containing package.nix are imported via package.nix
dir: dir:
let let
readDir = builtins.readDir dir; readDir = builtins.readDir dir;
files = lib.attrNames (
lib.filterAttrs (
name: type: type == "regular" && lib.hasSuffix ".nix" name && name != "default.nix"
) readDir
);
packages = builtins.map (name: lib.removeSuffix ".nix" name) files; files = lib.filterAttrs (
name: type: type == "regular" && lib.hasSuffix ".nix" name && name != "default.nix"
) readDir;
dirs = lib.filterAttrs (
name: type: type == "directory" && builtins.pathExists (dir + "/${name}/package.nix")
) readDir;
in in
lib.genAttrs packages (name: import (dir + "/${name}.nix")) lib.mapAttrs' (
name: _: lib.nameValuePair (lib.removeSuffix ".nix" name) (import (dir + "/${name}"))
) files
// lib.mapAttrs (name: _: import (dir + "/${name}/package.nix")) dirs

View File

@@ -7,20 +7,48 @@
name: name:
{ {
system, system,
users ? [ ], user ? null,
features ? [ ],
}: }:
let let
inherit (nixpkgs) lib;
hasUser = user != null;
# path helpers
featurePath = f: ../features/${f}.nix;
userFeaturePath = u: ../features/user-${u}.nix;
hostConfig = ../hosts/${name}/configuration.nix; hostConfig = ../hosts/${name}/configuration.nix;
hostHWConfig = ../hosts/${name}/hardware-configuration.nix; hostHWConfig = ../hosts/${name}/hardware-configuration.nix;
hasHWConfig = builtins.pathExists hostHWConfig;
userNixosConfigs = map (user: ../users/${user}/nixos.nix) ( # load feature with path check
builtins.filter (user: builtins.pathExists ../users/${user}/nixos.nix) users loadFeature =
); f:
assert
builtins.pathExists (featurePath f)
|| throw "feature '${f}' not found at ${toString (featurePath f)}";
import (featurePath f);
userHMConfigs = nixpkgs.lib.genAttrs users (user: import ../users/${user}/home-manager.nix); loadedFeatures = map loadFeature features;
# load user feature with path check
userFeature =
if hasUser then
assert
builtins.pathExists (userFeaturePath user)
|| throw "user feature 'user-${user}' not found at ${toString (userFeaturePath user)}";
import (userFeaturePath user)
else
null;
allFeatures = loadedFeatures ++ lib.optional (userFeature != null) userFeature;
# extract keys from user feature for specialArgs
userKeys = if userFeature != null then (userFeature.keys or { }) else { };
# collect nixos and home modules from all features
nixosMods = map (f: f.nixos) (builtins.filter (f: f ? nixos) allFeatures);
homeMods = map (f: f.home) (builtins.filter (f: f ? home) allFeatures);
in in
nixpkgs.lib.nixosSystem { nixpkgs.lib.nixosSystem {
inherit system; inherit system;
@@ -29,20 +57,23 @@ nixpkgs.lib.nixosSystem {
{ nixpkgs.overlays = overlays; } { nixpkgs.overlays = overlays; }
{ nixpkgs.config.allowUnfree = true; } { nixpkgs.config.allowUnfree = true; }
{ networking.hostName = name; }
hostConfig hostConfig
] ]
++ nixpkgs.lib.optional hasHWConfig hostHWConfig ++ lib.optional (builtins.pathExists hostHWConfig) hostHWConfig
++ userNixosConfigs ++ nixosMods
++ [ ++ lib.optionals hasUser [
inputs.home-manager.nixosModules.home-manager inputs.home-manager.nixosModules.home-manager
{ {
home-manager.useGlobalPkgs = true; home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true; home-manager.useUserPackages = true;
home-manager.backupFileExtension = "backup"; home-manager.backupFileExtension = "backup";
home-manager.users = userHMConfigs; home-manager.users.${user}.imports = homeMods;
home-manager.extraSpecialArgs = { inherit inputs; }; home-manager.extraSpecialArgs = { inherit inputs; };
} }
]; ];
specialArgs = { inherit inputs; }; specialArgs = {
inherit inputs userKeys user;
};
} }

View File

@@ -1 +0,0 @@
{ lib, my-lib }: args: (my-lib.autoDir ./.)

View File

@@ -1,44 +0,0 @@
{
lib,
config,
pkgs,
...
}:
{
options = {
desktop = {
enable = lib.mkEnableOption "base desktop environment";
};
};
config = lib.mkIf config.desktop.enable {
services.pipewire = {
enable = true;
pulse.enable = true;
};
hardware.bluetooth.enable = true;
services.blueman.enable = true;
security.polkit.enable = true;
services.dbus.enable = true;
services.playerctld.enable = true;
xdg.portal = {
enable = true;
xdgOpenUsePortal = true;
extraPortals = [
pkgs.xdg-desktop-portal-wlr
pkgs.xdg-desktop-portal-gtk
];
};
fonts.packages = with pkgs; [
font-awesome
nerd-fonts.jetbrains-mono
maple-mono.NF
];
};
}

View File

@@ -1,20 +0,0 @@
{
lib,
config,
...
}:
{
options = {
gnupg = {
enable = lib.mkEnableOption "GnuPG agent with SSH support";
};
};
config = lib.mkIf config.gnupg.enable {
programs.gnupg.agent = {
enable = true;
enableSSHSupport = true;
enableExtraSocket = true;
};
};
}

View File

@@ -1,86 +0,0 @@
{
lib,
config,
...
}:
let
# TODO:(@janezicmatej) restructure keys import
keys = import ../../users/matej/keys.nix;
# generate host keys for new machines: ./scripts/initrd-ssh-keygen.sh
keyDir = "/etc/secrets/initrd";
mkIpString =
{
address,
gateway,
netmask,
interface,
...
}:
"${address}::${gateway}:${netmask}::${interface}:none";
in
{
options = {
initrd-ssh = {
enable = lib.mkEnableOption "SSH in initrd for remote LUKS unlock";
ip = {
enable = lib.mkEnableOption "static IP for initrd (otherwise DHCP)";
address = lib.mkOption {
type = lib.types.str;
example = "10.222.0.247";
};
gateway = lib.mkOption {
type = lib.types.str;
example = "10.222.0.1";
};
netmask = lib.mkOption {
type = lib.types.str;
default = "255.255.255.0";
};
interface = lib.mkOption {
type = lib.types.str;
example = "enp5s0";
};
};
authorizedKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = keys.sshAuthorizedKeys;
};
networkModule = lib.mkOption {
type = lib.types.str;
example = "r8169";
};
};
};
config = lib.mkIf config.initrd-ssh.enable {
boot.initrd.kernelModules = [ config.initrd-ssh.networkModule ];
boot.kernelParams = lib.mkIf config.initrd-ssh.ip.enable [
"ip=${mkIpString config.initrd-ssh.ip}"
];
boot.initrd.network = {
enable = true;
ssh = {
enable = true;
port = 22;
hostKeys = [
"${keyDir}/ssh_host_rsa_key"
"${keyDir}/ssh_host_ed25519_key"
];
inherit (config.initrd-ssh) authorizedKeys;
};
postCommands = ''
echo 'cryptsetup-askpass' >> /root/.profile
'';
};
};
}

View File

@@ -1,28 +0,0 @@
{
lib,
config,
...
}:
{
options = {
localisation = {
enable = lib.mkEnableOption "localisation defaults";
timeZone = lib.mkOption {
type = lib.types.str;
};
defaultLocale = lib.mkOption {
type = lib.types.str;
};
};
};
config = lib.mkIf config.localisation.enable {
time.timeZone = config.localisation.timeZone;
i18n.defaultLocale = config.localisation.defaultLocale;
# NOTE:(@janezicmatej) some apps (e.g. java) need TZ env var explicitly
environment.variables.TZ = config.localisation.timeZone;
};
}

View File

@@ -1,23 +0,0 @@
{
lib,
config,
...
}:
{
options = {
nvidia.enable = lib.mkEnableOption "NVIDIA GPU support";
};
config = lib.mkIf config.nvidia.enable {
hardware.graphics.enable = true;
services.xserver.videoDrivers = [ "nvidia" ];
hardware.nvidia = {
modesetting.enable = true;
open = true;
nvidiaSettings = true;
package = config.boot.kernelPackages.nvidiaPackages.stable;
};
};
}

View File

@@ -1,29 +0,0 @@
{
lib,
config,
...
}:
{
options = {
openssh = {
enable = lib.mkEnableOption "hardened SSH server";
port = lib.mkOption {
type = lib.types.port;
default = 22;
};
};
};
config = lib.mkIf config.openssh.enable {
services.openssh = {
enable = true;
ports = [ config.openssh.port ];
settings = {
PasswordAuthentication = false;
AllowUsers = null;
PermitRootLogin = "no";
StreamLocalBindUnlink = "yes";
};
};
};
}

View File

@@ -1,21 +0,0 @@
{
lib,
config,
...
}:
{
options = {
printing = {
enable = lib.mkEnableOption "CUPS printing with Avahi discovery";
};
};
config = lib.mkIf config.printing.enable {
services.printing.enable = true;
services.avahi = {
enable = true;
nssmdns4 = true;
openFirewall = true;
};
};
}

View File

@@ -1,51 +0,0 @@
{
pkgs,
lib,
config,
...
}:
{
options = {
sway = {
enable = lib.mkEnableOption "enable sway module";
cmdFlags = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
};
};
config = lib.mkIf config.sway.enable {
programs.sway = {
enable = true;
package = pkgs.swayfx;
wrapperFeatures.gtk = true;
extraOptions = config.sway.cmdFlags;
extraSessionCommands = ''
# fix for java awt apps not rendering
export _JAVA_AWT_WM_NONREPARENTING=1
'';
};
environment.systemPackages = with pkgs; [
brightnessctl
foot
grim
pulseaudio
swayidle
# use swaylock-effects instead of swaylock
swaylock-effects
wmenu
slurp
wofi
wl-clipboard
wob
pamixer
wlsunset
flameshot
waybar
wayland-pipewire-idle-inhibit
];
};
}

View File

@@ -1,33 +0,0 @@
{
lib,
config,
pkgs,
...
}:
{
options = {
tuigreet = {
enable = lib.mkEnableOption "greetd with tuigreet";
command = lib.mkOption {
type = lib.types.str;
};
};
};
config = lib.mkIf config.tuigreet.enable {
services.greetd = {
enable = true;
useTextGreeter = true;
settings = {
default_session = {
command = pkgs.writeShellScript "tuigreet-session" ''
${pkgs.util-linux}/bin/setterm --blank 1 --powersave powerdown --powerdown 1
exec ${pkgs.tuigreet}/bin/tuigreet --time --remember --cmd ${config.tuigreet.command}
'';
user = "greeter";
};
};
};
};
}

View File

@@ -1,29 +0,0 @@
{
lib,
config,
pkgs,
...
}:
{
options = {
workstation = {
enable = lib.mkEnableOption "workstation utilities";
};
};
config = lib.mkIf config.workstation.enable {
virtualisation.docker = {
enable = true;
logDriver = "json-file";
};
services.tailscale = {
enable = true;
useRoutingFeatures = "both";
};
environment.systemPackages = with pkgs; [
smartmontools
];
};
}

View File

@@ -1,23 +0,0 @@
{
pkgs,
lib,
config,
...
}:
{
options = {
yubikey = {
enable = lib.mkEnableOption "enable yubikey module";
};
};
config = lib.mkIf config.yubikey.enable {
environment.systemPackages = with pkgs; [
yubikey-personalization
yubikey-manager
];
services.pcscd.enable = true;
};
}

View File

@@ -1,19 +0,0 @@
{
lib,
config,
...
}:
{
options = {
zsh = {
enable = lib.mkEnableOption "zsh with ZDOTDIR in ~/.config/zsh";
};
};
config = lib.mkIf config.zsh.enable {
programs.zsh.enable = true;
environment.etc."zshenv".text = ''
export ZDOTDIR=$HOME/.config/zsh
'';
};
}

View File

@@ -1,28 +0,0 @@
{ pkgs, ... }:
let
version = "v0.3.2";
in
pkgs.rustPlatform.buildRustPackage {
pname = "ahab";
inherit version;
src = pkgs.fetchFromGitea {
domain = "git.janezic.dev";
owner = "janezicmatej";
repo = "ahab";
rev = version;
sha256 = "sha256-bL8LPpD5k97XPYftXhPr7V/LNOB71pcBlsfBjJUIeG8";
};
cargoHash = "sha256-f8omNtjLF5gMJGgxdzWifStcs8d4fu++EegR2auObXE";
buildType = "debug";
meta = {
description = "ahab";
homepage = "https://git.janezic.dev/janezicmatej/ahab";
license = pkgs.lib.licenses.mit;
maintainers = [ ];
};
}

42
packages/ahab/package.nix Normal file
View File

@@ -0,0 +1,42 @@
{ pkgs, ... }:
let
version = "v0.4.2";
in
pkgs.rustPlatform.buildRustPackage {
pname = "ahab";
inherit version;
src = pkgs.fetchFromGitea {
domain = "git.janezic.dev";
owner = "janezicmatej";
repo = "ahab";
rev = version;
sha256 = "sha256-hJg6vRaqTu9a3fua2J/e6akdJQffAk6TBAzJRBD5qHQ=";
};
cargoHash = "sha256-T/2+kxa5X2fmMQs023JN9ZDihExfYvPnunJ8b2Irwoo=";
buildType = "debug";
nativeBuildInputs = [ pkgs.installShellFiles ];
preBuild = ''
mkdir -p completions
'';
SHELL_COMPLETIONS_DIR = "completions";
postInstall = ''
installShellCompletion --bash completions/ahab.bash
installShellCompletion --zsh completions/_ahab
installShellCompletion --fish completions/ahab.fish
'';
meta = {
description = "ahab";
homepage = "https://git.janezic.dev/janezicmatej/ahab";
license = pkgs.lib.licenses.mit;
maintainers = [ ];
};
}

71
packages/ahab/update.sh Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl jq nix-prefetch
# shellcheck shell=bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
PKG_FILE="$SCRIPT_DIR/package.nix"
cd "$ROOT_DIR"
extract_hash() {
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
}
main() {
echo "fetching latest version..."
local latest current
latest=$(curl -sf "https://git.janezic.dev/api/v1/repos/janezicmatej/ahab/tags?limit=1" | jq -r '.[0].name')
current=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [[ "$current" == "$latest" ]]; then
echo "ahab already at $latest"
return 0
fi
echo "updating ahab: $current -> $latest"
echo " prefetching source..."
local base32 src_hash
base32=$(nix-prefetch-url --unpack "https://git.janezic.dev/janezicmatej/ahab/archive/${latest}.tar.gz" 2>/dev/null)
src_hash=$(nix hash convert --to sri "sha256:$base32")
echo " source: $src_hash"
echo " computing cargo hash..."
local build_output cargo_hash
build_output=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs.legacyPackages.\${builtins.currentSystem};
in pkgs.rustPlatform.fetchCargoVendor {
src = pkgs.fetchFromGitea {
domain = \"git.janezic.dev\";
owner = \"janezicmatej\";
repo = \"ahab\";
rev = \"$latest\";
hash = \"$src_hash\";
};
hash = \"\";
}
" 2>&1) || true
cargo_hash=$(echo "$build_output" | extract_hash) || true
if [[ -z "$cargo_hash" ]]; then
echo "error: failed to compute cargo hash" >&2
echo "$build_output" >&2
exit 1
fi
echo " cargo: $cargo_hash"
local old_src old_cargo
old_src=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
old_cargo=$(grep 'cargoHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
sed -i "s|version = \"$current\"|version = \"$latest\"|" "$PKG_FILE"
sed -i "s|$old_src|$src_hash|" "$PKG_FILE"
sed -i "s|$old_cargo|$cargo_hash|" "$PKG_FILE"
echo "ahab updated to $latest"
}
main "$@"

View File

@@ -2,7 +2,7 @@
let let
pkgs = pkgs-master; pkgs = pkgs-master;
version = "e24855c"; version = "v1.27.1";
in in
pkgs.buildGoModule.override pkgs.buildGoModule.override
{ {
@@ -16,16 +16,25 @@ pkgs.buildGoModule.override
owner = "tkw1536"; owner = "tkw1536";
repo = "ggman"; repo = "ggman";
rev = version; rev = version;
sha256 = "sha256-H78xtF7l5joX3/qDFaRIT4LyZpHmm6DMR4JIKzNO7c0="; sha256 = "sha256-z7zqV69rPYwtkm4ieF+FIssBsFbREvaYQzSF648DHK0=";
}; };
vendorHash = "sha256-w8NrOt0xtn+/gugJ4amzdJP70Y5KHe5DlhsEprycm3U="; vendorHash = "sha256-5c5EgYjZXfexWMrUDS4fo46GCJBmFuWkw0cVqqGT7Ik=";
subPackages = [ "cmd/ggman" ]; subPackages = [ "cmd/ggman" ];
ldflags = [ ldflags = [
"-X go.tkw01536.de/ggman.buildVersion=${version}" "-X go.tkw01536.de/ggman.buildVersion=${version}"
]; ];
nativeBuildInputs = [ pkgs.installShellFiles ];
postInstall = ''
installShellCompletion --cmd ggman \
--bash <($out/bin/ggman completion bash) \
--zsh <($out/bin/ggman completion zsh) \
--fish <($out/bin/ggman completion fish)
'';
meta = { meta = {
description = "Manager for all your local git repositories"; description = "Manager for all your local git repositories";
homepage = "https://github.com/tkw1536/ggman"; homepage = "https://github.com/tkw1536/ggman";

72
packages/ggman/update.sh Executable file
View File

@@ -0,0 +1,72 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl jq nix-prefetch
# shellcheck shell=bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
PKG_FILE="$SCRIPT_DIR/package.nix"
cd "$ROOT_DIR"
extract_hash() {
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
}
main() {
echo "fetching latest tag..."
local latest current
latest=$(curl -sf "https://api.github.com/repos/tkw1536/ggman/tags?per_page=1" | jq -r '.[0].name')
current=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [[ "$current" == "$latest" ]]; then
echo "ggman already at $latest"
return 0
fi
echo "updating ggman: $current -> $latest"
echo " prefetching source..."
local base32 src_hash
base32=$(nix-prefetch-url --unpack "https://github.com/tkw1536/ggman/archive/${latest}.tar.gz" 2>/dev/null)
src_hash=$(nix hash convert --to sri "sha256:$base32")
echo " source: $src_hash"
echo " computing vendor hash..."
local build_output vendor_hash
build_output=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs-master.legacyPackages.\${builtins.currentSystem};
in (pkgs.buildGoModule.override { go = pkgs.go_1_26; } {
pname = \"ggman\";
version = \"$latest\";
src = pkgs.fetchFromGitHub {
owner = \"tkw1536\";
repo = \"ggman\";
rev = \"$latest\";
hash = \"$src_hash\";
};
vendorHash = \"\";
}).goModules
" 2>&1) || true
vendor_hash=$(echo "$build_output" | extract_hash) || true
if [[ -z "$vendor_hash" ]]; then
echo "error: failed to compute vendor hash" >&2
echo "$build_output" >&2
exit 1
fi
echo " vendor: $vendor_hash"
local old_src old_vendor
old_src=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
old_vendor=$(grep 'vendorHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
sed -i "s|version = \"$current\"|version = \"$latest\"|" "$PKG_FILE"
sed -i "s|$old_src|$src_hash|" "$PKG_FILE"
sed -i "s|$old_vendor|$vendor_hash|" "$PKG_FILE"
echo "ggman updated to $latest"
}
main "$@"

156
scripts/ephvm-run.sh Executable file
View File

@@ -0,0 +1,156 @@
#!/usr/bin/env bash
set -euo pipefail
setup_colors() {
if [ -t 2 ]; then
red=$'\033[31m'
yellow=$'\033[33m'
cyan=$'\033[36m'
reset=$'\033[0m'
else
red="" yellow="" cyan="" reset=""
fi
}
die() {
echo "${red}error:${reset} $*" >&2
exit 1
}
warn() {
echo "${yellow}warning:${reset} $*" >&2
}
info() {
echo "${cyan}$*${reset}" >&2
}
# globals for cleanup trap
CLEANUP_OVERLAY=""
cleanup() {
[ -n "$CLEANUP_OVERLAY" ] && rm -rf "$CLEANUP_OVERLAY"
return 0
}
trap cleanup EXIT
usage() {
cat <<EOF
Usage: ephvm-run.sh [options]
Options:
--mount <path> Mount host directory into VM (repeatable)
--claude Mount claude config dir (requires CLAUDE_CONFIG_DIR)
--disk-size <size> Resize guest disk (e.g. 50G)
--memory <size> VM memory (default: 8G)
--cpus <n> VM CPUs (default: 4)
--ssh-port <port> SSH port forward (default: 2222)
-h, --help Show usage
EOF
exit "${1:-0}"
}
main() {
setup_colors
local ssh_port=2222 memory=8G cpus=4 claude=false disk_size=""
local -a mounts=()
while [ $# -gt 0 ]; do
case "$1" in
--mount)
mounts+=("$2")
shift 2
;;
--claude)
claude=true
shift
;;
--disk-size)
disk_size="$2"
shift 2
;;
--memory)
memory="$2"
shift 2
;;
--cpus)
cpus="$2"
shift 2
;;
--ssh-port)
ssh_port="$2"
shift 2
;;
-h | --help) usage ;;
*)
echo "${red}error:${reset} unknown option: $1" >&2
usage 1
;;
esac
done
info "building ephvm image..."
local image_dir image
image_dir=$(nix build --no-link --print-out-paths .#nixosConfigurations.ephvm.config.system.build.images.qemu)
image=$(find "$image_dir" -name '*.qcow2' -print -quit)
[ -n "$image" ] || die "no qcow2 image found in $image_dir"
# create resized overlay when --disk-size is given
local drive_arg
if [ -n "$disk_size" ]; then
CLEANUP_OVERLAY=$(mktemp -d)
local overlay="$CLEANUP_OVERLAY/overlay.qcow2"
qemu-img create -f qcow2 -b "$(realpath "$image")" -F qcow2 "$overlay" "$disk_size"
drive_arg="file=$overlay,format=qcow2"
else
drive_arg="file=$image,format=qcow2,snapshot=on"
fi
local accel="tcg"
[ -r /dev/kvm ] && accel="kvm"
local -a qemu_args=(
qemu-system-x86_64
-accel "$accel"
-m "$memory"
-smp "$cpus"
-drive "$drive_arg"
-nic "user,hostfwd=tcp::${ssh_port}-:22"
-nographic
)
if [ "$accel" != "tcg" ]; then
qemu_args+=(-cpu host)
fi
local fs_id=0 mount_path name tag
for mount_path in "${mounts[@]}"; do
mount_path=$(realpath "$mount_path")
name=$(basename "$mount_path")
tag="m_${name:0:29}"
qemu_args+=(
-virtfs "local,path=$mount_path,mount_tag=$tag,security_model=none,id=fs${fs_id}"
)
fs_id=$((fs_id + 1))
done
if [ "$claude" = true ]; then
[ -n "${CLAUDE_CONFIG_DIR:-}" ] || die "--claude requires CLAUDE_CONFIG_DIR to be set"
mkdir -p "$CLAUDE_CONFIG_DIR"
local claude_dir
claude_dir=$(realpath "$CLAUDE_CONFIG_DIR")
qemu_args+=(
-virtfs "local,path=$claude_dir,mount_tag=claude,security_model=none,id=fs${fs_id}"
)
fs_id=$((fs_id + 1))
fi
info "---"
info "Accel: $accel | SSH: ssh -p $ssh_port matej@localhost"
info "---"
exec "${qemu_args[@]}"
}
main "$@"

View File

@@ -3,22 +3,22 @@ set -euo pipefail
KEY_DIR="/etc/secrets/initrd" KEY_DIR="/etc/secrets/initrd"
echo "Generating initrd SSH host keys in $KEY_DIR" main() {
echo "generating initrd SSH host keys in $KEY_DIR"
sudo mkdir -p "$KEY_DIR"
sudo mkdir -p "$KEY_DIR" local key_type
for key_type in rsa ed25519; do
local key_file="$KEY_DIR/ssh_host_${key_type}_key"
if [[ ! -f "$key_file" ]]; then
sudo ssh-keygen -t "$key_type" -N "" -f "$key_file"
echo "generated: $key_file"
else
echo "exists: $key_file"
fi
done
if [[ ! -f "$KEY_DIR/ssh_host_rsa_key" ]]; then echo "done. now run nixos-rebuild."
sudo ssh-keygen -t rsa -N "" -f "$KEY_DIR/ssh_host_rsa_key" }
echo "Generated: $KEY_DIR/ssh_host_rsa_key"
else
echo "Exists: $KEY_DIR/ssh_host_rsa_key"
fi
if [[ ! -f "$KEY_DIR/ssh_host_ed25519_key" ]]; then main "$@"
sudo ssh-keygen -t ed25519 -N "" -f "$KEY_DIR/ssh_host_ed25519_key"
echo "Generated: $KEY_DIR/ssh_host_ed25519_key"
else
echo "Exists: $KEY_DIR/ssh_host_ed25519_key"
fi
echo "Done. Now run nixos-rebuild."

View File

@@ -1,52 +0,0 @@
{
config,
lib,
pkgs,
inputs,
...
}:
let
packages = inputs.self.outputs.packages.${pkgs.stdenv.hostPlatform.system};
in
{
home.stateVersion = "24.11";
home.packages = [
pkgs.git
];
programs.neovim = {
enable = true;
vimAlias = true;
defaultEditor = true;
package = inputs.neovim-nightly-overlay.packages.${pkgs.stdenv.hostPlatform.system}.default;
extraPackages = with pkgs; [
# runtime deps
fzf
ripgrep
gnumake
gcc
luajit
lua-language-server
nil
nixd
nixpkgs-fmt
stylua
];
extraWrapperArgs = [
"--suffix"
"LD_LIBRARY_PATH"
":"
"${lib.makeLibraryPath [ pkgs.stdenv.cc.cc.lib ]}"
];
};
}

View File

@@ -1,129 +0,0 @@
{
config,
lib,
pkgs,
inputs,
...
}:
let
packages = inputs.self.outputs.packages.${pkgs.stdenv.hostPlatform.system};
in
{
home.stateVersion = "24.11";
# TODO:(@janezicmatej) do i need this here?
services.dunst.enable = true;
home.packages = [
pkgs.bibata-cursors
pkgs.starship
pkgs.claude-code
# git and co
pkgs.git
packages.git-linearize
packages.ggman
# cli utils
packages.ahab
pkgs.fzf
pkgs.htop
pkgs.jc
pkgs.jq
pkgs.openssl
pkgs.pv
pkgs.python3
pkgs.ripgrep
pkgs.fd
pkgs.tmux
pkgs.osc
pkgs.just
# compilers, toolchains, ...
pkgs.go
# pkgs.gcc
# pkgs.clang
# need for gcp stuff
pkgs.google-cloud-sdk
pkgs.google-cloud-sql-proxy
# desktop apps
pkgs.vesktop
pkgs.rocketchat-desktop
pkgs.telegram-desktop
pkgs.slack
pkgs.ghostty
pkgs.google-chrome
pkgs.zathura
pkgs.pavucontrol
pkgs.jellyfin-media-player
pkgs.cider-2
pkgs.protonmail-bridge
pkgs.ledger-live-desktop
pkgs.bolt-launcher
pkgs.libnotify
# writing/docs
pkgs.mdbook
pkgs.marksman
pkgs.mdformat
# security
pkgs.gnupg
pkgs.pass
];
home.file.".assets".source = inputs.assets;
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
stylix.targets.neovim.enable = false;
programs.neovim = {
enable = true;
vimAlias = true;
defaultEditor = true;
package = inputs.neovim-nightly-overlay.packages.${pkgs.stdenv.hostPlatform.system}.default;
extraPackages = with pkgs; [
# runtime deps
gcc
luajit
nodejs_22 # copilot
tree-sitter
# lua_fzf
fd
ripgrep
bat
gnumake
delta
pyright
typescript-language-server
lua-language-server
gopls
nil
nixd
nixpkgs-fmt
stylua
];
extraWrapperArgs = [
"--suffix"
"LD_LIBRARY_PATH"
":"
"${lib.makeLibraryPath [ pkgs.stdenv.cc.cc.lib ]}"
];
};
}

View File

@@ -1,6 +0,0 @@
{
sshAuthorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQGLdINKzs+sEy62Pefng0bcedgU396+OryFgeH99/c janezicmatej"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDk00+Km03epQXQs+xEwwH3zcurACzkEH+kDOPBw6RQe openpgp:0xB095D449"
];
}

View File

@@ -1,27 +0,0 @@
{
lib,
config,
pkgs,
...
}:
let
keys = import ./keys.nix;
in
{
users.users.matej = {
uid = 1000;
isNormalUser = true;
home = "/home/matej";
shell = pkgs.zsh;
extraGroups = [
"wheel"
"docker"
];
openssh.authorizedKeys.keys = keys.sshAuthorizedKeys;
};
users.groups.matej = {
gid = 1000;
members = [ "matej" ];
};
}