Compare commits

...

47 Commits

Author SHA1 Message Date
kiri 9df7bfd825 chore: remove outdated AGENTS.md 2026-06-12 15:46:06 +02:00
kiri 9f565b85db feat: remove global git ignores 2026-06-12 11:33:56 +02:00
kiri 562a65a714 feat: make escape exit menuselect in zsh 2026-06-12 11:33:36 +02:00
kiri beabcabb60 feat: add work repo to trusted codex folders 2026-06-08 10:04:02 +02:00
kiri 709e89c017 fix: nix-wrapper-modules warning 2026-06-08 10:02:36 +02:00
kiri b35c95b4c8 feat: remove uv 2026-06-08 10:02:05 +02:00
kiri 5a1f5a9894 feat: move to limine 2026-06-08 10:01:59 +02:00
kiri d6a3587a89 feat: set notifcation density to compact 2026-06-06 11:35:10 +02:00
kiri ed1c94735c chore: update inputs 2026-06-05 14:54:05 +02:00
kiri 239febf3e0 feat: move notifications to bottom right 2026-05-29 13:15:15 +02:00
kiri e7c0a084a0 chore: update inputs 2026-05-29 10:07:46 +02:00
kiri 30564171f0 chore: update inputs and devenv 2026-05-27 19:23:01 +02:00
kiri 1d591c4f4a feat: add vps-insights to orion 2026-05-07 01:52:25 +02:00
kiri b204e48509 chore: update nix-wrapper-modules call 2026-05-07 00:59:18 +02:00
kiri 86dcf5ce4b fix: transmission failing because of non-existing directory 2026-05-07 00:58:52 +02:00
kiri 8453447f90 feat: switch torrent client to transmission 2026-05-07 00:45:23 +02:00
kiri 2c2276c9b8 feat: always approve nixos mcp requests in codex 2026-05-07 00:37:15 +02:00
kiri c4146eaae0 feat: reduce number of nixpkgs revisions 2026-05-07 00:24:32 +02:00
kiri f193c02f4a feat: better zsh completion 2026-05-06 23:51:54 +02:00
kiri d84fec1a82 feat: enable bitwarden for walker 2026-05-06 22:56:34 +02:00
kiri 1458dd1ae6 feat: use sops for radicale password 2026-05-06 22:56:23 +02:00
kiri c501097e4c feat: enable khal 2026-05-06 22:11:30 +02:00
kiri 4b6e05212c refactor: schema 2026-05-06 21:57:58 +02:00
kiri c01c13aa50 feat: enable walker 2026-05-06 21:21:15 +02:00
kiri e33602e879 refactor: dendritic principles 2026-05-06 19:45:03 +02:00
kiri d6878abc61 refactor default apps and add walker 2026-05-06 19:32:37 +02:00
kiri be1a9b7852 feat: use upstream walker and elephant flakes 2026-05-06 16:03:33 +02:00
kiri 7299f5bb79 fix: walker and gtk4 2026-05-05 21:05:24 +02:00
kiri c2082e942e feat: add walker and general launcher config 2026-05-05 20:56:09 +02:00
kiri fdf6ac5e08 feat: add discord 2026-05-05 17:52:56 +02:00
kiri fdc269483e feat: add phone to syncthing 2026-05-05 16:28:49 +02:00
kiri e8d1f58ed5 chore: update inputs 2026-05-01 18:34:04 +02:00
kiri 5bc37c7009 refactor: niri config 2026-04-29 15:49:32 +02:00
kiri efb0179344 feat: improve config UX 2026-04-29 13:50:20 +02:00
kiri a18d405ea7 feat: make shift+enter newline 2026-04-29 12:26:38 +02:00
kiri 9b3db93dbd feat: disable command-not-found for nix-index 2026-04-29 12:19:49 +02:00
kiri cacb6c01e9 feat: make YUNZII keyboard accessible 2026-04-28 16:16:46 +02:00
kiri f4ac94c65c feat: change font weights on foot 2026-04-28 00:21:42 +02:00
kiri 85cf1d92ca feat: make kitty boot in single instance mode 2026-04-27 23:15:08 +02:00
kiri 61971e2b37 feat: change font rendering 2026-04-27 22:15:12 +02:00
kiri 783bd9958d feat: improve foot font rendering 2026-04-27 20:35:48 +02:00
kiri 44fe4552ef refactor: desktop default applications 2026-04-27 17:57:39 +02:00
kiri 93624900ad refactor: reorganize features 2026-04-27 16:47:12 +02:00
kiri 0b2ecd31b0 refactor: restructure config files 2026-04-27 15:59:20 +02:00
kiri bac6e4997b feat: add foot and clean up config 2026-04-27 15:27:27 +02:00
kiri 8b31e1ca9f feat: replace dust with dua 2026-04-27 01:17:53 +02:00
kiri 4cd2d1addd feat: install github-cli 2026-04-27 01:15:34 +02:00
80 changed files with 2091 additions and 1393 deletions
-74
View File
@@ -1,74 +0,0 @@
# AGENTS.md
## Purpose
This repo uses the Dendritic Pattern with `flake-parts`.
Design and change the configuration as a composition of **features**, not as a host-first tree.
For deeper design rationale and pattern descriptions, refer to `.agents/dendritic-design-with-flake-parts.wiki`.
## Core Terms
- **Feature**: a flake-parts module under `modules/` that defines one coherent concern.
- **Aspect**: a reusable module published at `flake.modules.<module class>.<aspect name>`.
- **Module class**: the configuration context of an aspect. This repo primarily uses `nixos` and `homeManager`.
- **Feature module**: the flake-parts module that defines aspects, flake outputs, options, or shared helpers.
In this repo, `flake.nix` imports `./modules` recursively via `inputs.import-tree`. Any non-private `.nix` file under `modules/` is therefore treated as a feature module.
## Design Principles
- Work bottom-up. Define features first; assemble hosts from features.
- Keep semantic ownership local. A feature should contain the configuration for that concern across all relevant module classes.
- Name aspects semantically. The aspect name should usually match the file or directory name that defines it.
- Prefer small, composable aspects. Build larger configurations with `imports`.
- Import aspects unconditionally and only within the same module class.
- Put conditions inside module content with `lib.mkIf` or `lib.mkMerge`, never around `imports`.
- Avoid importing the same aspect multiple times along one import path.
- Keep private helper files next to the feature that uses them and prefix them with `_` so `import-tree` does not import them as feature modules.
- Put shared schemas and constructors in dedicated shared modules, not ad hoc host files.
## Repo Structure
- `modules/features/`: reusable features and most aspect definitions.
- `modules/hosts/<name>/default.nix`: host features that assemble NixOS aspects into `flake.modules.nixos.<name>`.
- `modules/secrets/`: secret-related features shared by hosts.
- `modules/flake-parts.nix`: flake-parts entrypoint; defines systems, formatter, and `flake.nixosConfigurations`.
- `modules/lib/`: shared schemas, constructors, and helpers exposed through `repo.helpers`, especially `mkHost` and `mkCaddyReverseProxy`.
- `modules/data.nix`: canonical shared repo data, including the single `repo.account`, machine inventory, desktop preferences, services, and theme data.
- `modules/lib/schema.nix`: shared metadata schema for `repo.*` and NixOS `meta.machine`.
## How Features Are Applied Here
- Reusable NixOS concerns are published as `flake.modules.nixos.<name>`.
- Reusable Home Manager concerns are published as `flake.modules.homeManager.<name>`.
- Hosts are aspects too. `orion`, `polaris`, and `zenith` are `nixos` aspects assembled from smaller aspects.
- `flake.nixosConfigurations` instantiates every entry in `repo.machines` with `config.repo.helpers.mkHost`.
- Hosts define machine data under `repo.machines.<name>` and host-specific NixOS composition under `flake.modules.nixos.<name>`.
- `mkHost` wires the single `repo.account` into `users.users.<name>` and `home-manager.users.<name>`.
- NixOS modules may read `config.meta.machine`; Home Manager modules should read host facts through `osConfig.meta.machine` and user facts through `config.home` or `repo.account`.
## Preferred Aspect Patterns
- **Simple Aspect**: use for one self-contained concern in one or more module classes.
- **Multi Context Aspect**: use when one concern must configure both `nixos` and `homeManager`.
- **Inheritance Aspect**: use by importing a parent aspect and extending it.
- **Conditional Aspect**: use `lib.mkMerge` plus `lib.mkIf` for conditional content.
Use **Collector Aspect** only when composition through imports or shared library helpers is insufficient.
## Change Rules
- When adding a feature, add or extend aspects under `modules/features/` and let hosts opt into them explicitly.
- When adding a host, create `modules/hosts/<name>/default.nix` and keep host-local generated files private as `_hardware.nix`, `_disk.nix`, or similar.
- When a feature needs local data or helper code, keep it inside that feature directory and prefix non-feature files with `_` when they live under `modules/`.
- Do not place arbitrary non-feature `.nix` files under `modules/` unless they are intentionally private and excluded from recursive import.
- If a concern is shared across hosts, it belongs in a reusable feature, not inline in one host unless it is truly host-specific.
## Practical Heuristics
- If you are about to edit a host because of a reusable concern, that concern probably wants its own feature.
- If a Home Manager module needs host facts, prefer `osConfig.meta.machine`; for user facts, prefer `config.home` or `repo.account` instead of duplicating literals.
- If a concern spans system and user space, keep both aspects in one feature so the behavior stays coherent.
- If imports would need to be conditional, redesign the aspect boundary instead.
Generated
+490 -268
View File
File diff suppressed because it is too large Load Diff
+34 -8
View File
@@ -2,21 +2,47 @@
description = "NixOS Configuration";
inputs = {
disko.url = "github:nix-community/disko";
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
devenv.url = "github:cachix/devenv";
flake-parts.follows = "lux-pkgs/flake-parts";
home-manager.url = "github:nix-community/home-manager";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
import-tree.url = "github:vic/import-tree";
llm-agents.url = "github:numtide/llm-agents.nix";
llm-agents = {
url = "github:numtide/llm-agents.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
niri.url = "github:sodiboo/niri-flake";
nix-wrapper-modules.url = "github:BirdeeHub/nix-wrapper-modules";
nix-wrapper-modules = {
url = "github:BirdeeHub/nix-wrapper-modules";
inputs.nixpkgs.follows = "nixpkgs";
};
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz";
noctalia.url = "github:noctalia-dev/noctalia-shell";
sops-nix.url = "github:Mic92/sops-nix";
nix-index-database.url = "github:nix-community/nix-index-database";
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-index-database = {
url = "github:nix-community/nix-index-database";
inputs.nixpkgs.follows = "nixpkgs";
};
#vicinae.url = "github:vicinaehq/vicinae";
vicinae-extensions.url = "github:vicinaehq/extensions";
elephant = {
url = "github:abenz1267/elephant";
inputs.nixpkgs.follows = "nixpkgs";
};
walker = {
url = "github:abenz1267/walker";
inputs.elephant.follows = "elephant";
inputs.nixpkgs.follows = "nixpkgs";
};
lux-pkgs.url = "git+ssh://gitea@orion/kiri/lux-pkgs";
};
+69
View File
@@ -0,0 +1,69 @@
{
cursor = {
name = "phinger-cursors-light";
packagePath = [ "phinger-cursors" ];
size = 24;
};
kanagawa = {
displayName = "Kanagawa Wave";
name = "kanagawa-wave";
gtkThemeName = "Kanagawa-BL-LB";
iconThemeName = "Kanagawa";
owner = "Fausto-Korpsvart";
repo = "Kanagawa-GKT-Theme";
rev = "55ca4ba249eba21f861b9866b71ab41bb8930318";
hash = "sha256-UdMoMx2DoovcxSp/zBZ3PRv/Qpj+prd0uPm1gmdak2E=";
version = "unstable-2025-10-23";
palette = {
background = "#1F1F28";
foreground = "#DCD7BA";
secondaryBackground = "#16161D";
border = "#2A2A37";
selectionBackground = "#2D4F67";
selectionForeground = "#C8C093";
url = "#72A7BC";
cursor = "#C8C093";
muted = "#727169";
accents = {
blue = "#7E9CD8";
green = "#98BB6C";
magenta = "#D27E99";
orange = "#FFA066";
purple = "#957FB8";
red = "#E82424";
yellow = "#E6C384";
cyan = "#7AA89F";
};
niri.border = {
active = "#7E9CD8";
inactive = "#54546D";
urgent = "#E82424";
};
terminal = {
color0 = "#16161D";
color1 = "#C34043";
color2 = "#76946A";
color3 = "#C0A36E";
color4 = "#7E9CD8";
color5 = "#957FB8";
color6 = "#6A9589";
color7 = "#C8C093";
color8 = "#727169";
color9 = "#E82424";
color10 = "#98BB6C";
color11 = "#E6C384";
color12 = "#7FB4CA";
color13 = "#938AA9";
color14 = "#7AA89F";
color15 = "#DCD7BA";
color16 = "#FFA066";
color17 = "#FF5D62";
};
};
};
}
@@ -1,6 +1,7 @@
{ inputs, config, ... }:
let
account = config.repo.account;
hmModules = config.flake.modules.homeManager;
sharedContext = ''
# Global Agent Context
@@ -21,6 +22,8 @@ let
in
{
flake.modules.nixos.ai = {
home-manager.sharedModules = [ hmModules.ai ];
nixpkgs.overlays = [ inputs.llm-agents.overlays.default ];
nix.settings = {
@@ -83,9 +86,14 @@ in
"five-hour-limit"
];
projects.${account.nixosConfigurationPath}.trust_level = "trusted";
projects."${config.home.homeDirectory}/work/repos/yookr_data_science".trust_level = "trusted";
sandbox_mode = "workspace-write";
personality = "pragmatic";
features.undo = true;
mcp_servers.nixos = config.programs.mcp.servers.nixos // {
enabled = true;
default_tools_approval_mode = "approve";
};
};
};
};
+115
View File
@@ -0,0 +1,115 @@
{ config, ... }:
let
homeModules = config.flake.modules.homeManager;
vivaldiPackage = pkgs: pkgs.vivaldi;
nautilusPackage = pkgs: pkgs.nautilus;
in
{
flake.modules.homeManager.browser-vivaldi =
{ pkgs, ... }:
{
home.packages = [ (vivaldiPackage pkgs) ];
};
flake.modules.homeManager.primary-browser-vivaldi =
{ lib, pkgs, ... }:
{
imports = [ homeModules.browser-vivaldi ];
facts.desktop.browserCommand = lib.getExe (vivaldiPackage pkgs);
home.sessionVariables.BROWSER = lib.getExe (vivaldiPackage pkgs);
xdg.mimeApps.defaultApplicationPackages = [ (vivaldiPackage pkgs) ];
};
flake.modules.homeManager.file-manager-nautilus =
{ pkgs, ... }:
{
home.packages = [ (nautilusPackage pkgs) ];
};
flake.modules.homeManager.primary-file-manager-nautilus =
{ lib, pkgs, ... }:
{
imports = [ homeModules.file-manager-nautilus ];
xdg.mimeApps.defaultApplicationPackages = [ (nautilusPackage pkgs) ];
};
flake.modules.homeManager.image-viewer-imv = {
programs.imv.enable = true;
};
flake.modules.homeManager.default-image-viewer-imv =
{ pkgs, ... }:
{
imports = [ homeModules.image-viewer-imv ];
xdg.mimeApps.defaultApplicationPackages = [ pkgs.imv ];
};
flake.modules.homeManager.document-viewer-sioyek = {
programs.sioyek.enable = true;
};
flake.modules.homeManager.default-document-viewer-sioyek =
{ pkgs, ... }:
{
imports = [ homeModules.document-viewer-sioyek ];
xdg.mimeApps.defaultApplicationPackages = [ pkgs.sioyek ];
};
flake.modules.homeManager.workstation-apps =
{ pkgs, ... }:
{
home.packages = with pkgs; [
postman
spotify
calcure
planify
unzip
gimp
dbeaver-bin
];
};
flake.modules.homeManager.xdg =
{ config, ... }:
let
homeDir = config.home.homeDirectory;
localDir = "${homeDir}/.local";
mediaDir = "${homeDir}/media";
in
{
home.preferXdgDirectories = true;
xdg = {
enable = true;
cacheHome = "${localDir}/cache";
configHome = "${homeDir}/.config";
dataHome = "${localDir}/share";
stateHome = "${localDir}/state";
userDirs = {
enable = true;
createDirectories = true;
setSessionVariables = true;
download = "${homeDir}/downloads";
documents = "${homeDir}/documents";
projects = "${homeDir}/dev";
music = "${mediaDir}/music";
pictures = "${mediaDir}/images";
videos = "${mediaDir}/videos";
desktop = "${localDir}/desktop";
publicShare = "${localDir}/public";
templates = "${localDir}/templates";
};
mimeApps = {
enable = true;
};
};
};
}
@@ -1,22 +1,27 @@
{ inputs, ... }:
{
flake.modules.homeManager.dev-tools =
{ config, pkgs, ... }:
{
home.sessionVariables.CARGO_HOME = "${config.xdg.dataHome}/cargo";
home.packages = with pkgs; [
devenv
httpie
bruno
usql
posting
resterm
inputs.devenv.packages.${pkgs.stdenv.hostPlatform.system}.default
];
programs.direnv = {
enable = true;
enableZshIntegration = true;
nix-direnv.enable = true;
};
# programs.direnv = {
# enable = true;
# enableZshIntegration = true;
# nix-direnv.enable = true;
# };
programs.zsh.initContent = ''
eval "$(devenv hook zsh)"
'';
programs.lazygit = {
enable = true;
@@ -27,14 +32,6 @@
programs.jq.enable = true;
programs.bun.enable = true;
programs.ripgrep.enable = true;
programs.uv.enable = true;
programs.git.ignores = [
"devenv.*"
".devenv*"
".direnv"
"pre-commit-config.yaml"
".envrc"
];
#programs.uv.enable = true;
};
}
@@ -21,6 +21,24 @@
source-sans-pro
source-serif-pro
];
fontconfig = {
enable = true;
antialias = true;
allowBitmaps = false;
useEmbeddedBitmaps = false;
hinting = {
enable = true;
autohint = false;
style = "slight";
};
subpixel = {
rgba = "none";
lcdfilter = "none";
};
};
};
};
}
@@ -10,7 +10,7 @@ in
...
}:
let
machine = osConfig.meta.machine;
machine = osConfig.facts.machine;
allowedSignersFile = "${config.xdg.configHome}/git/allowed_signers";
mkScope =
@@ -19,6 +19,7 @@ in
email = account.emails.${scope}.address;
key = lib.attrByPath [ scope ] null machine.sshKeys;
hasSigningKey = key != null;
privateKeyPath = key.privateKeyPath or "~/.ssh/id_${scope}";
in
{
allowedSigners = lib.optional hasSigningKey "${email} ${key.publicKey}";
@@ -28,7 +29,7 @@ in
inherit email;
}
// lib.optionalAttrs hasSigningKey {
signingKey = "${key.privateKeyPath}.pub";
signingKey = "${privateKeyPath}.pub";
};
}
// lib.optionalAttrs hasSigningKey {
@@ -73,5 +74,10 @@ in
}
];
};
programs.gh = {
enable = true;
settings.git_protocol = "ssh";
};
};
}
+8
View File
@@ -0,0 +1,8 @@
{
flake.modules.nixos.hidraw-access = {
services.udev.extraRules = ''
# ROYUAN YUNZII B75 PRO
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="3151", ATTRS{idProduct}=="4015", MODE="0660", GROUP="users"
'';
};
}
+75
View File
@@ -0,0 +1,75 @@
{ config, lib, ... }:
let
palette = config.repo.theme.kanagawa.palette;
hex = lib.removePrefix "#";
terminalPalette = palette.terminal;
mkPalette = colors: lib.concatStringsSep ";" (map hex colors);
in
{
flake.modules.nixos.limine =
{ config, lib, ... }:
let
displayValues = builtins.attrValues (config.facts.machine.displays or { });
primaryDisplays = lib.filter (display: display.primary or false) displayValues;
primaryDisplay = if primaryDisplays == [ ] then null else builtins.head primaryDisplays;
interfaceResolution =
if primaryDisplay != null && primaryDisplay ? width && primaryDisplay ? height then
"${toString primaryDisplay.width}x${toString primaryDisplay.height}"
else
null;
in
{
boot.loader = {
efi.canTouchEfiVariables = true;
limine = {
enable = true;
maxGenerations = 10;
resolution = "2560x1440";
style = {
backdrop = hex palette.secondaryBackground;
graphicalTerminal = {
background = "00${hex palette.background}";
foreground = hex palette.foreground;
brightForeground = hex palette.selectionForeground;
brightBackground = hex palette.selectionBackground;
palette = mkPalette [
terminalPalette.color0
terminalPalette.color1
terminalPalette.color2
terminalPalette.color3
terminalPalette.color4
terminalPalette.color5
terminalPalette.color6
terminalPalette.color7
];
brightPalette = mkPalette [
terminalPalette.color8
terminalPalette.color9
terminalPalette.color10
terminalPalette.color11
terminalPalette.color12
terminalPalette.color13
terminalPalette.color14
terminalPalette.color15
];
font = {
scale = "2x2";
spacing = 1;
};
margin = 64;
marginGradient = 24;
};
interface = {
branding = config.networking.hostName;
brandingColor = hex palette.accents.blue;
helpHidden = false;
resolution = interfaceResolution;
};
};
};
};
};
}
@@ -1,6 +1,6 @@
{ ... }:
{
flake.modules.nixos.region-nl = {
flake.modules.nixos.locale-nl = {
time.timeZone = "Europe/Amsterdam";
i18n.defaultLocale = "en_US.UTF-8";
@@ -4,6 +4,12 @@ let
repoTheme = config.repo.theme.kanagawa;
in
{
flake.modules.homeManager.default-editor-neovim =
{ pkgs, ... }:
{
xdg.mimeApps.defaultApplicationPackages = [ pkgs.neovim ];
};
flake.modules.homeManager.neovim =
{
pkgs,
@@ -19,13 +25,9 @@ in
};
imports = [
(inputs.nix-wrapper-modules.lib.mkInstallModule {
(inputs.nix-wrapper-modules.lib.getInstallModule {
name = "neovim";
value = inputs.nix-wrapper-modules.lib.wrapperModules.neovim;
loc = [
"home"
"packages"
];
})
];
@@ -37,7 +39,7 @@ in
# 2. Runtime Dependencies (from lspsAndRuntimeDeps)
# These are added to the PATH of the wrapper
extraPackages = with pkgs; [
runtimePkgs = with pkgs; [
# Tools
universal-ctags
ripgrep
@@ -154,8 +156,8 @@ in
# Hostname/ConfigDir needed for nixd
nixdExtras = {
nixpkgs = "import ${pkgs.path} {}";
nixos_options = ''(builtins.getFlake "path://${account.nixosConfigurationPath}").nixosConfigurations.${osConfig.meta.machine.name}.options'';
home_manager_options = ''(builtins.getFlake "path://${account.nixosConfigurationPath}").nixosConfigurations.${osConfig.meta.machine.name}.options.home-manager.users.type.getSubOptions []'';
nixos_options = ''(builtins.getFlake "path://${account.nixosConfigurationPath}").nixosConfigurations.${osConfig.facts.machine.name}.options'';
home_manager_options = ''(builtins.getFlake "path://${account.nixosConfigurationPath}").nixosConfigurations.${osConfig.facts.machine.name}.options.home-manager.users.type.getSubOptions []'';
};
themeSetup = import ./_kanagawa-theme.nix {
+23
View File
@@ -0,0 +1,23 @@
{ config, ... }:
let
nixosModules = config.flake.modules.nixos;
in
{
flake.modules.nixos.nftables-firewall = {
networking.nftables.enable = true;
};
flake.modules.nixos.network-manager = {
networking.networkmanager.enable = true;
};
flake.modules.nixos.server-firewall =
{ ... }:
{
imports = [
nixosModules.nftables-firewall
];
networking.firewall.allowPing = false;
};
}
@@ -1,11 +1,13 @@
{
browserCommand,
lib,
terminalPackage,
launcherCommand,
shortcutCommands,
terminalCommand,
}:
{
# Application and utility launchers
"Mod+Return" = {
action.spawn = "${lib.getExe terminalPackage}";
action.spawn = terminalCommand;
hotkey-overlay.title = "Terminal";
};
"Mod+B" = {
@@ -14,13 +16,36 @@
};
"Mod+Space" = {
repeat = false;
action.spawn = [
"vicinae"
"toggle"
];
action.spawn = launcherCommand;
hotkey-overlay.title = "App Launcher";
};
"Mod+E" = {
repeat = false;
action.spawn = shortcutCommands.neovimProjects;
hotkey-overlay.title = "Neovim Projects";
};
"Mod+Ctrl+Return" = {
repeat = false;
action.spawn = shortcutCommands.nixosTerminal;
hotkey-overlay.title = "NixOS Config Terminal";
};
"Mod+Ctrl+Shift+Return" = {
repeat = false;
action.spawn = shortcutCommands.nixosSwitch;
hotkey-overlay.title = "NixOS Switch";
};
"Mod+Ctrl+E" = {
repeat = false;
action.spawn = shortcutCommands.editSecrets;
hotkey-overlay.title = "Edit Secrets";
};
"Mod+Ctrl+C" = {
repeat = false;
action.spawn = shortcutCommands.pickColor;
hotkey-overlay.title = "Pick Color";
};
# Hardware media, volume, and brightness keys
"XF86AudioPlay" = {
action.spawn-sh = "playerctl play-pause";
allow-when-locked = true;
@@ -62,23 +87,26 @@
allow-when-locked = true;
};
# Screenshots
"Mod+S".action.screenshot = [ ];
"Mod+Ctrl+S".action.screenshot-screen = [ ];
"Mod+Alt+S".action.screenshot-window = [ ];
# Session and compositor controls
"Mod+Shift+Slash".action.show-hotkey-overlay = [ ];
"Mod+Escape" = {
action.toggle-keyboard-shortcuts-inhibit = [ ];
allow-inhibiting = false;
};
"Mod+Alt+L" = {
"Mod+Ctrl+L" = {
action.spawn-sh = "loginctl lock-session";
hotkey-overlay.title = "Lock Screen";
};
"Mod+Shift+E".action.quit = [ ];
"Mod+Ctrl+Shift+Q".action.quit = [ ];
"Ctrl+Alt+Delete".action.quit = [ ];
"Mod+Shift+P".action.power-off-monitors = [ ];
# Overview and window close
"Mod+O" = {
action.toggle-overview = [ ];
repeat = false;
@@ -88,58 +116,66 @@
repeat = false;
};
# Keyboard focus movement
"Mod+Left".action.focus-column-or-monitor-left = [ ];
"Mod+Down".action.focus-window-down = [ ];
"Mod+Up".action.focus-window-up = [ ];
"Mod+Right".action.focus-column-or-monitor-right = [ ];
"Mod+H".action.focus-column-or-monitor-left = [ ];
"Mod+J".action.focus-window-down = [ ];
"Mod+K".action.focus-window-up = [ ];
"Mod+L".action.focus-column-or-monitor-right = [ ];
"Mod+Ctrl+Left".action.move-column-left = [ ];
"Mod+Ctrl+Down".action.move-window-down = [ ];
"Mod+Ctrl+Up".action.move-window-up = [ ];
"Mod+Ctrl+Right".action.move-column-right = [ ];
"Mod+Ctrl+H".action.move-column-left = [ ];
"Mod+Ctrl+J".action.move-window-down = [ ];
"Mod+Ctrl+K".action.move-window-up = [ ];
"Mod+Ctrl+L".action.move-column-right = [ ];
# Keyboard window and column movement
"Mod+Alt+Left".action.move-column-left-or-to-monitor-left = [ ];
"Mod+Alt+Down".action.move-window-down-or-to-workspace-down = [ ];
"Mod+Alt+Up".action.move-window-up-or-to-workspace-up = [ ];
"Mod+Alt+Right".action.move-column-right-or-to-monitor-right = [ ];
"Mod+Alt+H".action.move-column-left-or-to-monitor-left = [ ];
"Mod+Alt+J".action.move-window-down-or-to-workspace-down = [ ];
"Mod+Alt+K".action.move-window-up-or-to-workspace-up = [ ];
"Mod+Alt+L".action.move-column-right-or-to-monitor-right = [ ];
# First and last column navigation
"Mod+Home".action.focus-column-first = [ ];
"Mod+End".action.focus-column-last = [ ];
"Mod+Ctrl+Home".action.move-column-to-first = [ ];
"Mod+Ctrl+End".action.move-column-to-last = [ ];
"Mod+Alt+Home".action.move-column-to-first = [ ];
"Mod+Alt+End".action.move-column-to-last = [ ];
# Move focus, columns, and workspaces across monitors
"Mod+Tab".action.focus-monitor-next = [ ];
"Mod+A" = {
repeat = false;
action.spawn = shortcutCommands.swapMonitorWorkspaces;
hotkey-overlay.title = "Swap Monitor Workspaces";
};
"Mod+Alt+Tab".action.move-column-to-monitor-next = [ ];
"Mod+Shift+Tab".action.move-workspace-to-monitor-next = [ ];
"Mod+Shift+Left".action.focus-monitor-left = [ ];
"Mod+Shift+Down".action.focus-monitor-down = [ ];
"Mod+Shift+Up".action.focus-monitor-up = [ ];
"Mod+Shift+Right".action.focus-monitor-right = [ ];
"Mod+Shift+H".action.focus-monitor-left = [ ];
"Mod+Shift+J".action.focus-monitor-down = [ ];
"Mod+Shift+K".action.focus-monitor-up = [ ];
"Mod+Shift+L".action.focus-monitor-right = [ ];
"Mod+Shift+Ctrl+Left".action.move-column-to-monitor-left = [ ];
"Mod+Shift+Ctrl+Down".action.move-column-to-monitor-down = [ ];
"Mod+Shift+Ctrl+Up".action.move-column-to-monitor-up = [ ];
"Mod+Shift+Ctrl+Right".action.move-column-to-monitor-right = [ ];
"Mod+Shift+Ctrl+H".action.move-column-to-monitor-left = [ ];
"Mod+Shift+Ctrl+J".action.move-column-to-monitor-down = [ ];
"Mod+Shift+Ctrl+K".action.move-column-to-monitor-up = [ ];
"Mod+Shift+Ctrl+L".action.move-column-to-monitor-right = [ ];
# Linear workspace navigation
"Mod+Page_Down".action.focus-workspace-down = [ ];
"Mod+Page_Up".action.focus-workspace-up = [ ];
"Mod+U".action.focus-workspace-down = [ ];
"Mod+I".action.focus-workspace-up = [ ];
"Mod+Ctrl+Page_Down".action.move-column-to-workspace-down = [ ];
"Mod+Ctrl+Page_Up".action.move-column-to-workspace-up = [ ];
"Mod+Ctrl+U".action.move-column-to-workspace-down = [ ];
"Mod+Ctrl+I".action.move-column-to-workspace-up = [ ];
# Move columns between adjacent workspaces
"Mod+Alt+Page_Down".action.move-column-to-workspace-down = [ ];
"Mod+Alt+Page_Up".action.move-column-to-workspace-up = [ ];
"Mod+Alt+U".action.move-column-to-workspace-down = [ ];
"Mod+Alt+I".action.move-column-to-workspace-up = [ ];
# Reorder workspaces
"Mod+Shift+Page_Down".action.move-workspace-down = [ ];
"Mod+Shift+Page_Up".action.move-workspace-up = [ ];
"Mod+Shift+U".action.move-workspace-down = [ ];
"Mod+Shift+I".action.move-workspace-up = [ ];
# Mouse workspace navigation
"Mod+WheelScrollDown" = {
action.focus-workspace-down = [ ];
cooldown-ms = 150;
@@ -148,24 +184,24 @@
action.focus-workspace-up = [ ];
cooldown-ms = 150;
};
"Mod+Ctrl+WheelScrollDown" = {
"Mod+Alt+WheelScrollDown" = {
action.move-column-to-workspace-down = [ ];
cooldown-ms = 150;
};
"Mod+Ctrl+WheelScrollUp" = {
"Mod+Alt+WheelScrollUp" = {
action.move-column-to-workspace-up = [ ];
cooldown-ms = 150;
};
"Mod+WheelScrollRight".action.focus-column-right = [ ];
"Mod+WheelScrollLeft".action.focus-column-left = [ ];
"Mod+Ctrl+WheelScrollRight".action.move-column-right = [ ];
"Mod+Ctrl+WheelScrollLeft".action.move-column-left = [ ];
"Mod+Shift+WheelScrollDown".action.focus-column-right = [ ];
"Mod+Shift+WheelScrollUp".action.focus-column-left = [ ];
"Mod+Ctrl+Shift+WheelScrollDown".action.move-column-right = [ ];
"Mod+Ctrl+Shift+WheelScrollUp".action.move-column-left = [ ];
# Mouse column navigation and movement
"Mod+WheelScrollRight".action.focus-column-or-monitor-right = [ ];
"Mod+WheelScrollLeft".action.focus-column-or-monitor-left = [ ];
"Mod+Alt+WheelScrollRight".action.move-column-right-or-to-monitor-right = [ ];
"Mod+Alt+WheelScrollLeft".action.move-column-left-or-to-monitor-left = [ ];
"Mod+Shift+WheelScrollDown".action.focus-column-or-monitor-right = [ ];
"Mod+Shift+WheelScrollUp".action.focus-column-or-monitor-left = [ ];
# Direct workspace focus
"Mod+1".action.focus-workspace = 1;
"Mod+2".action.focus-workspace = 2;
"Mod+3".action.focus-workspace = 3;
@@ -176,6 +212,7 @@
"Mod+8".action.focus-workspace = 8;
"Mod+9".action.focus-workspace = 9;
# Move columns to numbered workspaces
"Mod+Ctrl+1".action.move-column-to-workspace = 1;
"Mod+Ctrl+2".action.move-column-to-workspace = 2;
"Mod+Ctrl+3".action.move-column-to-workspace = 3;
@@ -186,27 +223,34 @@
"Mod+Ctrl+8".action.move-column-to-workspace = 8;
"Mod+Ctrl+9".action.move-column-to-workspace = 9;
# Add and remove windows from columns
"Mod+BracketLeft".action.consume-or-expel-window-left = [ ];
"Mod+BracketRight".action.consume-or-expel-window-right = [ ];
"Mod+Comma".action.consume-window-into-column = [ ];
"Mod+Period".action.expel-window-from-column = [ ];
# Column and window presentation modes
"Mod+R".action.switch-preset-column-width = [ ];
"Mod+Shift+R".action.switch-preset-window-height = [ ];
"Mod+Shift+R".action.switch-preset-column-width-back = [ ];
"Mod+Ctrl+R".action.reset-window-height = [ ];
"Mod+Ctrl+Shift+R".action.switch-preset-window-height = [ ];
"Mod+F".action.maximize-column = [ ];
"Mod+Shift+F".action.fullscreen-window = [ ];
"Mod+M".action.maximize-window-to-edges = [ ];
"Mod+Ctrl+F".action.expand-column-to-available-width = [ ];
"Mod+C".action.center-column = [ ];
"Mod+Ctrl+C".action.center-visible-columns = [ ];
# Manual column width and window height adjustments
"Mod+Shift+H".action.set-column-width = "-10%";
"Mod+Shift+L".action.set-column-width = "+10%";
"Mod+Shift+J".action.set-window-height = "+10%";
"Mod+Shift+K".action.set-window-height = "-10%";
"Mod+Minus".action.set-column-width = "-10%";
"Mod+Equal".action.set-column-width = "+10%";
"Mod+Shift+Minus".action.set-window-height = "-10%";
"Mod+Shift+Equal".action.set-window-height = "+10%";
"Mod+V".action.toggle-window-floating = [ ];
# Floating and tabbed layout toggles
"Mod+Alt+V".action.toggle-window-floating = [ ];
"Mod+Shift+V".action.switch-focus-between-floating-and-tiling = [ ];
"Mod+W".action.toggle-column-tabbed-display = [ ];
}
+146
View File
@@ -0,0 +1,146 @@
{
config,
lib,
pkgs,
repo,
}:
let
nixosConfigDir = repo.account.nixosConfigurationPath;
mkTerminalScript =
{
name,
workdir ? nixosConfigDir,
command ? null,
runtimeInputs ? [ ],
}:
let
args = lib.optionals (command != null) [
"--"
"${pkgs.bash}/bin/bash"
"-lc"
command
];
argString = lib.concatMapStringsSep " " lib.escapeShellArg args;
in
pkgs.writeShellApplication {
inherit name runtimeInputs;
checkPhase = "";
text = lib.concatStringsSep "\n" [
"# shellcheck disable=SC2016"
"cd ${lib.escapeShellArg workdir}"
"exec ${lib.escapeShellArg config.facts.desktop.terminalCommand} ${argString}"
];
};
in
rec {
scripts = {
nixosTerminal = mkTerminalScript {
name = "niri-shortcut-nixos-terminal";
};
nixosSwitch = mkTerminalScript {
name = "niri-shortcut-nixos-switch";
runtimeInputs = [
pkgs.coreutils
pkgs.nh
];
command = ''
set -o pipefail
log_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/nixos-switch"
mkdir -p "$log_dir"
log="$log_dir/$(date +%Y%m%d-%H%M%S).log"
status_file="$(mktemp)"
printf 'Running nh os switch in %s\n\n' ${lib.escapeShellArg nixosConfigDir}
(
cd ${lib.escapeShellArg nixosConfigDir}
nh os switch
printf '%s' "$?" > "$status_file"
) 2>&1 | tee "$log"
status="$(cat "$status_file")"
rm -f "$status_file"
printf '\nLog: %s\n' "$log"
if [ "$status" -eq 0 ]; then
printf 'NixOS switch completed successfully.\n'
else
printf 'NixOS switch failed with exit code %s.\n' "$status"
fi
printf 'Press Enter to close...'
read -r _
exit "$status"
'';
};
editSecrets = mkTerminalScript {
name = "niri-shortcut-edit-secrets";
runtimeInputs = [ pkgs.sops ];
command = ''
sops edit ${lib.escapeShellArg "${nixosConfigDir}/modules/secrets/secrets.yaml"}
'';
};
neovimProjects = mkTerminalScript {
name = "niri-shortcut-neovim-projects";
command = ''
nvim -c 'Telescope projects'
'';
};
pickColor = pkgs.writeShellApplication {
name = "niri-shortcut-pick-color";
runtimeInputs = [
pkgs.libnotify
pkgs.niri
pkgs.wl-clipboard
];
text = ''
color="$(niri msg pick-color)"
printf '%s' "$color" | wl-copy
notify-send 'Color picked' "$color"
'';
};
swapMonitorWorkspaces = pkgs.writeShellApplication {
name = "niri-shortcut-swap-monitor-workspaces";
runtimeInputs = [
pkgs.jq
pkgs.niri
];
text = ''
focused_output="$(niri msg --json focused-output | jq -r '.name // empty')"
if [ -z "$focused_output" ]; then
exit 0
fi
niri msg action focus-monitor-next
target_output="$(niri msg --json focused-output | jq -r '.name // empty')"
if [ -z "$target_output" ] || [ "$target_output" = "$focused_output" ]; then
exit 0
fi
target_workspace_idx="$(
niri msg --json workspaces \
| jq -r --arg output "$target_output" '
first(.[] | select(.output == $output and .is_active) | .idx) // empty
'
)"
if [ -z "$target_workspace_idx" ]; then
niri msg action focus-monitor "$focused_output"
exit 0
fi
niri msg action focus-monitor "$focused_output"
niri msg action move-workspace-to-monitor "$target_output"
niri msg action focus-workspace "$target_workspace_idx"
niri msg action move-workspace-to-monitor "$focused_output"
'';
};
};
commands = lib.mapAttrs (_: lib.getExe) scripts;
}
+174
View File
@@ -0,0 +1,174 @@
{
inputs,
config,
...
}:
let
repo = config.repo;
hmModules = config.flake.modules.homeManager;
in
{
flake.modules.nixos.niri =
{ pkgs, ... }:
{
imports = [ inputs.niri.nixosModules.niri ];
home-manager.sharedModules = [ hmModules.niri ];
nixpkgs.overlays = [ inputs.niri.overlays.niri ];
programs = {
dconf.enable = true;
niri = {
enable = true;
package = pkgs.niri-unstable;
};
};
services = {
gvfs.enable = true;
udisks2.enable = true;
};
xdg.portal.enable = true;
};
flake.modules.homeManager.niri =
{
config,
lib,
osConfig,
pkgs,
...
}:
let
borderPalette = repo.theme.kanagawa.palette.niri.border;
shortcuts = import ./_shortcuts.nix {
inherit
config
lib
pkgs
repo
;
};
machine = osConfig.facts.machine;
in
{
home = {
sessionVariables.NIXOS_OZONE_WL = "1";
packages =
with pkgs;
[
playerctl
brightnessctl
xwayland-satellite
]
++ lib.attrValues shortcuts.scripts;
};
dconf.settings."org/gnome/desktop/interface".color-scheme = "prefer-dark";
programs.niri.settings = {
outputs = lib.mapAttrs (
_: display:
let
scale = display.scale or null;
width = display.width or null;
height = display.height or null;
refresh = display.refresh or null;
in
{
position = {
x = display.x or 0;
y = display.y or 0;
};
}
// lib.optionalAttrs (display.primary or false) {
"focus-at-startup" = true;
}
// lib.optionalAttrs (scale != null) {
inherit scale;
}
// lib.optionalAttrs (width != null && height != null && refresh != null) {
mode = {
inherit
width
height
refresh
;
};
}
) (machine.displays or { });
environment.DISPLAY = ":0";
spawn-at-startup = [
{ command = [ "xwayland-satellite" ]; }
{ command = [ "noctalia-shell" ]; }
];
prefer-no-csd = true;
hotkey-overlay.skip-at-startup = true;
screenshot-path = "${config.xdg.userDirs.pictures}/screenshots/%Y-%m-%dT%H:%M:%S.png";
animations.slowdown = 0.6;
cursor = {
inherit (config.home.pointerCursor) size;
theme = config.home.pointerCursor.name;
hide-after-inactive-ms = 3000;
hide-when-typing = true;
};
layout = {
always-center-single-column = true;
gaps = 14;
focus-ring.enable = false;
default-column-width.proportion = 1. / 2.;
border = {
enable = true;
width = 3;
active.color = borderPalette.active;
inactive.color = borderPalette.inactive;
urgent.color = borderPalette.urgent;
};
};
window-rules = [
{
geometry-corner-radius =
let
radius = 10.0;
in
{
bottom-left = radius;
bottom-right = radius;
top-left = radius;
top-right = radius;
};
clip-to-geometry = true;
}
];
debug.honor-xdg-activation-with-invalid-serial = true;
gestures.hot-corners.enable = false;
input = {
focus-follows-mouse.enable = true;
mouse."accel-speed" = 0.4;
keyboard = {
repeat-delay = 300;
repeat-rate = 50;
xkb.options = "caps:escape";
};
touchpad.dwt = true;
};
binds = import ./_bindings.nix {
browserCommand = config.facts.desktop.browserCommand;
launcherCommand = config.facts.desktop.launcherCommand;
terminalCommand = config.facts.desktop.terminalCommand;
shortcutCommands = shortcuts.commands;
};
};
};
}
@@ -1,4 +1,7 @@
{ inputs, ... }:
{ inputs, config, ... }:
let
account = config.repo.account;
in
{
flake.modules.nixos.nix =
{ ... }:
@@ -42,6 +45,7 @@
})
];
programs.nix-index.enableZshIntegration = false;
programs.nix-index-database.comma.enable = true;
programs.television = {
@@ -53,5 +57,10 @@
enable = true;
enableTelevisionIntegration = true;
};
programs.nh = {
enable = true;
flake = account.nixosConfigurationPath;
};
};
}
@@ -1,7 +1,7 @@
{
homeDirectory,
lib,
terminalPackage,
terminalCommand,
}:
{
settingsVersion = 53;
@@ -260,7 +260,7 @@
pinnedApps = [ ];
useApp2Unit = false;
sortByMostUsed = true;
terminalCommand = "${lib.getExe terminalPackage} -e";
inherit terminalCommand;
customLaunchPrefixEnabled = false;
customLaunchPrefix = "";
viewMode = "grid";
@@ -458,9 +458,9 @@
notifications = {
enabled = true;
enableMarkdown = false;
density = "default";
density = "compact";
monitors = [ ];
location = "top_right";
location = "bottom_right";
overlayLayer = true;
backgroundOpacity = 1;
respectExpireTimeout = false;
@@ -4,20 +4,17 @@
...
}:
let
repo = config.repo;
repoHelpers = repo.helpers;
mkNoctaliaSettings =
{
homeDirectory,
lib,
terminalPackage,
terminalCommand,
}:
import ./_noctalia-config.nix {
inherit
homeDirectory
lib
terminalPackage
terminalCommand
;
};
@@ -25,22 +22,13 @@ let
{
homeDirectory,
lib,
pkgs,
terminalCommand,
}:
let
terminalPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.terminal.packagePath;
};
in
if terminalPackage == null then
{ }
else
mkNoctaliaSettings {
inherit
homeDirectory
lib
terminalPackage
terminalCommand
;
};
@@ -78,11 +66,12 @@ in
}:
let
baseSettings = mkBaseSettings {
inherit lib pkgs;
inherit lib;
homeDirectory = config.home.homeDirectory;
terminalCommand = lib.getExe pkgs.xdg-terminal-exec;
};
settings =
if baseSettings == { } || !osConfig.meta.machine.portable then
if baseSettings == { } || !(osConfig.facts.machine.portable or false) then
baseSettings
else
mkPortableSettings baseSettings;
@@ -7,19 +7,21 @@ let
account = repo.account;
in
{
flake.modules.homeManager.bitwarden =
flake.modules.homeManager.passwords =
{
config,
pkgs,
...
}:
let
pinentryPackage = pkgs.pinentry-gnome3;
in
{
programs.rbw = {
enable = true;
settings = {
base_url = repo.services.vaultwarden.url;
email = account.primaryEmail.address;
pinentry = pkgs.pinentry-gnome3;
pinentry = pinentryPackage;
};
};
};
@@ -1,6 +1,10 @@
{ config, ... }:
{
config,
...
}:
let
account = config.repo.account;
repo = config.repo;
account = repo.account;
in
{
flake.modules.homeManager.email =
@@ -13,7 +17,7 @@ in
mkOffice365Account =
{
address,
primary,
primary ? false,
...
}:
{
@@ -33,7 +37,7 @@ in
mkMxrouteAccount =
{
address,
primary,
primary ? false,
...
}:
{
@@ -85,4 +89,80 @@ in
accounts.email.accounts = lib.mapAttrs (_: mkEmailAccount) account.emails;
};
flake.modules.homeManager.calendar-tasks =
{
config,
pkgs,
...
}:
let
calendarsPath = "${config.xdg.dataHome}/calendars";
in
{
programs.pimsync.enable = true;
services.pimsync.enable = true;
sops.secrets."radicale-pass" = { };
programs.khal = {
enable = true;
locale = {
timeformat = "%H:%M";
dateformat = "$m-$d";
};
};
programs.todoman = {
enable = true;
glob = "*/*";
extraConfig = ''
date_format = "%Y-%m-%d"
time_format = "%H:%M"
default_list = "personal"
default_due = 0
default_command = "list --sort priority,due"
humanize = True
'';
};
accounts.calendar = {
basePath = calendarsPath;
accounts.radicale = {
primary = true;
primaryCollection = "personal";
local = {
type = "filesystem";
fileExt = ".ics";
};
remote = {
url = repo.services.radicale.url;
type = "caldav";
userName = config.home.username;
passwordCommand = [
"${pkgs.coreutils}/bin/cat"
config.sops.secrets."radicale-pass".path
];
};
pimsync = {
enable = true;
extraPairDirectives = [
{
name = "collections";
params = [ "from b" ];
}
];
};
khal = {
enable = true;
type = "discover";
color = "light blue";
};
};
};
};
}
@@ -5,6 +5,13 @@ let
service = repo.services.actual;
in
{
repo.services.actual = {
domain = "finance.jelles.net";
host = "127.0.0.1";
port = 3000;
url = "https://finance.jelles.net";
};
flake.modules.nixos.actual =
{ lib, ... }:
lib.mkMerge [
@@ -5,6 +5,13 @@ let
service = repo.services.gitea;
in
{
repo.services.gitea = {
domain = "git.jelles.net";
host = "127.0.0.1";
port = 3001;
url = "https://git.jelles.net/";
};
flake.modules.nixos.gitea =
{ lib, ... }:
lib.mkMerge [
@@ -3,12 +3,12 @@ let
account = config.repo.account;
personalPublicKeys =
machines:
map (machine: machine.sshKeys.personal.publicKey) (
lib.filter (machine: machine.sshKeys ? personal) (builtins.attrValues machines)
map (machine: (machine.sshKeys or { }).personal.publicKey) (
lib.filter (machine: (machine.sshKeys or { }) ? personal) (builtins.attrValues machines)
);
in
{
flake.modules.nixos.ssh-agent-auth = {
flake.modules.nixos.sudo-ssh-agent-auth = {
security.pam = {
rssh.enable = true;
services.sudo.rssh = true;
@@ -5,6 +5,13 @@ let
service = repo.services.radicale;
in
{
repo.services.radicale = {
domain = "radicale.jelles.net";
host = "127.0.0.1";
port = 5232;
url = "https://radicale.jelles.net/";
};
flake.modules.nixos.radicale =
{ lib, ... }:
lib.mkMerge [
@@ -0,0 +1,28 @@
{ config, ... }:
let
account = config.repo.account;
in
{
flake.modules.nixos.transmission =
{ config, pkgs, ... }:
{
services.transmission = {
enable = true;
package = pkgs.transmission_4;
openPeerPorts = true;
downloadDirPermissions = "775";
settings = {
download-dir = "${account.homeDirectory}/torrents";
incomplete-dir = "${account.homeDirectory}/torrents/.incomplete";
peer-port = 43864;
umask = "002";
};
};
# NOTE: Upstream bug?
systemd.services.transmission-setup.requiredBy = [ "transmission.service" ];
users.users.${account.name}.extraGroups = [ config.services.transmission.group ];
};
}
@@ -5,6 +5,13 @@ let
service = repo.services.vaultwarden;
in
{
repo.services.vaultwarden = {
domain = "vault.jelles.net";
host = "127.0.0.1";
port = 8100;
url = "https://vault.jelles.net";
};
flake.modules.nixos.vaultwarden =
{ lib, ... }:
lib.mkMerge [
@@ -0,0 +1,215 @@
{ ... }:
{
flake.modules.nixos.vps-insights =
{ config, pkgs, ... }:
let
localAddress = "127.0.0.1";
grafanaDataDir = config.services.grafana.dataDir;
lokiDataDir = config.services.loki.dataDir;
lokiUrl = "http://${localAddress}:3100";
prometheusUrl = "http://${localAddress}:9090";
in
{
environment = {
etc."alloy/config.alloy".text = ''
loki.relabel "journal" {
forward_to = []
rule {
source_labels = ["__journal__systemd_unit"]
target_label = "unit"
}
rule {
source_labels = ["__journal_syslog_identifier"]
target_label = "syslog_identifier"
}
rule {
source_labels = ["__journal_priority_keyword"]
target_label = "level"
}
}
loki.source.journal "system" {
forward_to = [loki.write.local.receiver]
relabel_rules = loki.relabel.journal.rules
max_age = "24h"
labels = {
host = "${config.networking.hostName}",
}
}
loki.write "local" {
endpoint {
url = "${lokiUrl}/loki/api/v1/push"
}
}
'';
systemPackages = with pkgs; [
goaccess
lynis
];
};
services = {
# Keep local system logs available for Loki and manual inspection.
journald.extraConfig = ''
Storage=persistent
SystemMaxUse=1G
MaxRetentionSec=30day
'';
# Detect and block common attacks against SSH and Caddy.
crowdsec = {
enable = true;
hub.collections = [
"crowdsecurity/linux"
"crowdsecurity/caddy"
];
localConfig.acquisitions = [
{
source = "journalctl";
journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ];
labels.type = "syslog";
}
{
filenames = [ "/var/log/caddy/*.log" ];
labels.type = "caddy";
}
];
};
crowdsec-firewall-bouncer = {
enable = true;
registerBouncer.bouncerName = "${config.networking.hostName}-firewall-bouncer";
};
# Grafana defaults to 127.0.0.1:3000; add secrets and datasources only.
grafana = {
enable = true;
settings = {
analytics.reporting_enabled = false;
security = {
admin_password = "$__file{${grafanaDataDir}/admin-password}";
secret_key = "$__file{${grafanaDataDir}/secret-key}";
};
};
provision.datasources.settings = {
prune = true;
datasources = [
{
name = "Prometheus";
type = "prometheus";
uid = "prometheus";
url = prometheusUrl;
isDefault = true;
}
{
name = "Loki";
type = "loki";
uid = "loki";
url = lokiUrl;
}
];
};
};
# Store local logs in Loki and feed them from journald through Alloy.
loki = {
enable = true;
configuration = {
analytics.reporting_enabled = false;
auth_enabled = false;
server = {
http_listen_address = localAddress;
http_listen_port = 3100;
grpc_listen_address = localAddress;
grpc_listen_port = 9096;
};
common = {
path_prefix = lokiDataDir;
replication_factor = 1;
instance_interface_names = [ "lo" ];
ring = {
instance_addr = localAddress;
kvstore.store = "inmemory";
};
};
schema_config.configs = [
{
from = "2025-01-01";
store = "tsdb";
object_store = "filesystem";
schema = "v13";
index = {
prefix = "index_";
period = "24h";
};
}
];
storage_config.filesystem.directory = "${lokiDataDir}/chunks";
compactor = {
working_directory = "${lokiDataDir}/compactor";
retention_enabled = true;
delete_request_store = "filesystem";
};
limits_config.retention_period = "720h";
};
};
alloy = {
enable = true;
extraFlags = [ "--server.http.listen-addr=${localAddress}:12345" ];
};
# Collect basic VPS health metrics for Grafana.
prometheus = {
enable = true;
listenAddress = localAddress;
retentionTime = "30d";
scrapeConfigs = [
{
job_name = "prometheus";
static_configs = [
{
targets = [ "${localAddress}:9090" ];
}
];
}
{
job_name = "node";
static_configs = [
{
targets = [ "${localAddress}:9100" ];
}
];
}
];
exporters.node = {
enable = true;
listenAddress = localAddress;
};
};
};
systemd.services.grafana.preStart = ''
umask 077
if [ ! -s ${grafanaDataDir}/admin-password ]; then
${pkgs.openssl}/bin/openssl rand -base64 32 > ${grafanaDataDir}/admin-password
fi
if [ ! -s ${grafanaDataDir}/secret-key ]; then
${pkgs.openssl}/bin/openssl rand -hex 32 > ${grafanaDataDir}/secret-key
fi
'';
};
}
@@ -65,12 +65,21 @@
bindkey -v
export KEYTIMEOUT=1
setopt MENU_COMPLETE
zmodload zsh/complist
autoload -U history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^[OA" history-beginning-search-backward-end
bindkey "^[OB" history-beginning-search-forward-end
if [[ -n "''${terminfo[kcbt]}" ]]; then
bindkey "''${terminfo[kcbt]}" reverse-menu-complete
bindkey -M menuselect "''${terminfo[kcbt]}" reverse-menu-complete
fi
bindkey "^[[Z" reverse-menu-complete
bindkey -M menuselect "^[[Z" reverse-menu-complete
bindkey -M menuselect "^[" send-break
zstyle ':completion:*' completer _extensions _complete _approximate
zstyle ':completion:*' use-cache on
@@ -79,7 +88,7 @@
zstyle ':completion:*' complete-options true
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'
zstyle ':completion:*' keep-prefix true
zstyle ':completion:*' menu select
zstyle ':completion:*' menu yes select=1
zstyle ':completion:*' list-grouped false
zstyle ':completion:*' list-separator '''
zstyle ':completion:*' group-name '''
@@ -169,7 +178,7 @@
pkgs.tlrc
pkgs.sd
pkgs.procs
pkgs.dust
pkgs.dua
pkgs.duf
pkgs.systemctl-tui
pkgs.xh
+66
View File
@@ -0,0 +1,66 @@
{
config,
lib,
...
}:
let
syncMachines = lib.listToAttrs (
lib.concatLists (
lib.mapAttrsToList (
machineName: machine:
let
syncthingId = machine.syncthingId or null;
in
lib.optional (syncthingId != null) (
let
name = "${config.repo.account.name}@${machineName}";
in
{
inherit name;
value = {
inherit name;
id = syncthingId;
};
}
)
) config.repo.machines
)
);
syncPhones = {
"pixel-10" = {
name = "pixel-10";
id = "MTJHEHA-UMZDQZ7-BTMRRLQ-Y7BFPUJ-ZTY6LZX-PDXV3IS-XVJCU7B-EPETBQZ";
};
};
syncDevices = syncMachines // syncPhones;
in
{
flake.modules.homeManager.syncthing =
{ ... }:
{
services.syncthing = {
enable = true;
overrideDevices = true;
overrideFolders = true;
settings = {
folders = {
sync = {
path = "~/sync";
label = "sync";
devices = builtins.attrNames syncDevices;
};
calibre = {
path = "~/calibre";
label = "calibre";
devices = builtins.attrNames syncMachines;
};
};
devices = syncDevices;
};
};
};
}
@@ -1,6 +1,6 @@
{ ... }:
{
flake.modules.nixos.standard-boot =
flake.modules.nixos.systemd-boot =
{ config, pkgs, ... }:
{
boot = {
+198
View File
@@ -0,0 +1,198 @@
{ lib, config, ... }:
let
repo = config.repo;
kittySingleInstance =
pkgs:
pkgs.symlinkJoin {
name = "kitty-single";
paths = [ pkgs.kitty ];
meta = pkgs.kitty.meta;
buildInputs = [ pkgs.makeWrapper ];
postBuild = ''
# Wrap the binary to always launch as a single instance
wrapProgram $out/bin/kitty --add-flags "-1"
# Patch the .desktop file for strict app launchers like Vicinae
rm $out/share/applications/kitty.desktop
sed 's/Exec=kitty/Exec=kitty -1/g' ${pkgs.kitty}/share/applications/kitty.desktop > $out/share/applications/kitty.desktop
'';
};
in
{
flake.modules.homeManager.terminal-foot =
{
lib,
pkgs,
...
}:
let
repoTheme = repo.theme.kanagawa;
palette = repoTheme.palette;
hex = lib.removePrefix "#";
in
{
programs.foot = {
enable = true;
package = pkgs.foot;
settings = {
main = {
font = "JetBrains Mono:style=Medium:size=11:fontfeatures=-liga:fontfeatures=-calt";
font-bold = "JetBrains Mono:style=Bold:size=11:fontfeatures=-liga:fontfeatures=-calt";
font-italic = "JetBrains Mono:style=Medium Italic:size=11:fontfeatures=-liga:fontfeatures=-calt";
font-bold-italic = "JetBrains Mono:style=Bold Italic:size=11:fontfeatures=-liga:fontfeatures=-calt";
gamma-correct-blending = "yes";
pad = "3x3";
# vertical-letter-offset = -1;
# letter-spacing = -0.2;
};
tweak.box-drawing-base-thickness = 0.1;
bell.system = "no";
scrollback.lines = 10000;
text-bindings."\\x0a" = "Shift+Return Shift+KP_Enter";
colors-dark = {
background = hex palette.background;
foreground = hex palette.foreground;
selection-background = hex palette.selectionBackground;
selection-foreground = hex palette.selectionForeground;
urls = hex palette.url;
cursor = "${hex palette.background} ${hex palette.cursor}";
regular0 = hex palette.terminal.color0;
regular1 = hex palette.terminal.color1;
regular2 = hex palette.terminal.color2;
regular3 = hex palette.terminal.color3;
regular4 = hex palette.terminal.color4;
regular5 = hex palette.terminal.color5;
regular6 = hex palette.terminal.color6;
regular7 = hex palette.terminal.color7;
bright0 = hex palette.terminal.color8;
bright1 = hex palette.terminal.color9;
bright2 = hex palette.terminal.color10;
bright3 = hex palette.terminal.color11;
bright4 = hex palette.terminal.color12;
bright5 = hex palette.terminal.color13;
bright6 = hex palette.terminal.color14;
bright7 = hex palette.terminal.color15;
"16" = hex palette.terminal.color16;
"17" = hex palette.terminal.color17;
};
};
};
};
flake.modules.homeManager.terminal-kitty =
{ pkgs, ... }:
let
repoTheme = repo.theme.kanagawa;
palette = repoTheme.palette;
in
{
programs.kitty = {
enable = true;
package = kittySingleInstance pkgs;
font = {
name = "JetBrains Mono";
size = 11;
};
settings = {
disable_ligatures = "always";
scrollback_lines = 10000;
enable_audio_bell = false;
confirm_os_window_close = 0;
window_padding_width = 3;
update_check_interval = 0;
};
keybindings."shift+enter" = "send_text all \\x0a";
extraConfig = ''
## name: ${repoTheme.displayName}
## license: MIT
## author: Tommaso Laurenzi
## upstream: https://github.com/rebelot/kanagawa.nvim/
background ${palette.background}
foreground ${palette.foreground}
selection_background ${palette.selectionBackground}
selection_foreground ${palette.selectionForeground}
url_color ${palette.url}
cursor ${palette.cursor}
active_tab_background ${palette.background}
active_tab_foreground ${palette.selectionForeground}
inactive_tab_background ${palette.background}
inactive_tab_foreground ${palette.muted}
color0 ${palette.terminal.color0}
color1 ${palette.terminal.color1}
color2 ${palette.terminal.color2}
color3 ${palette.terminal.color3}
color4 ${palette.terminal.color4}
color5 ${palette.terminal.color5}
color6 ${palette.terminal.color6}
color7 ${palette.terminal.color7}
color8 ${palette.terminal.color8}
color9 ${palette.terminal.color9}
color10 ${palette.terminal.color10}
color11 ${palette.terminal.color11}
color12 ${palette.terminal.color12}
color13 ${palette.terminal.color13}
color14 ${palette.terminal.color14}
color15 ${palette.terminal.color15}
color16 ${palette.terminal.color16}
color17 ${palette.terminal.color17}
'';
};
systemd.user.services.kitty-daemon = {
Unit = {
Description = "Kitty Terminal Daemon";
PartOf = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
};
Install = {
WantedBy = [ "graphical-session.target" ];
};
Service = {
# Use the wrapped package (which already includes -1)
# Start it hidden and run an infinite dummy process so the instance stays alive
ExecStart = "${lib.getExe (kittySingleInstance pkgs)} --start-as=hidden ${pkgs.coreutils}/bin/tail -f /dev/null";
Restart = "on-failure";
};
};
};
flake.modules.homeManager.primary-terminal-foot =
{ lib, pkgs, ... }:
{
imports = [ config.flake.modules.homeManager.terminal-foot ];
facts.desktop.terminalCommand = lib.getExe pkgs.foot;
xdg.terminal-exec = {
enable = true;
settings.default = [ "foot.desktop" ];
};
};
flake.modules.homeManager.primary-terminal-kitty =
{ lib, pkgs, ... }:
{
imports = [ config.flake.modules.homeManager.terminal-kitty ];
facts.desktop.terminalCommand = lib.getExe (kittySingleInstance pkgs);
xdg.terminal-exec = {
enable = true;
settings.default = [ "kitty.desktop" ];
};
};
}
@@ -5,8 +5,11 @@
let
repo = config.repo;
repoHelpers = repo.helpers;
hmModules = config.flake.modules.homeManager;
in
{
repo.theme = import ./_theme.nix;
flake.modules.nixos.theme =
{
pkgs,
@@ -22,6 +25,8 @@ in
};
in
{
home-manager.sharedModules = [ hmModules.theme ];
environment.systemPackages = [ cursorTheme.package ];
services.displayManager.sddm.settings = {
@@ -77,9 +82,7 @@ in
name = repoTheme.kanagawa.gtkThemeName;
package = pkgs.kanagawa-gtk-theme.overrideAttrs (_: kanagawaOverride);
};
gtk4.theme = {
inherit (config.gtk.theme) name package;
};
gtk4.theme = null;
iconTheme = {
name = repoTheme.kanagawa.iconThemeName;
package = pkgs.kanagawa-icon-theme.overrideAttrs (_: kanagawaOverride);
@@ -5,8 +5,10 @@ in
{
flake.modules.homeManager.vicinae =
{
config,
pkgs,
inputs,
lib,
...
}:
let
@@ -70,5 +72,7 @@ in
ssh
];
};
facts.desktop.launcherCommand = lib.getExe config.programs.vicinae.package;
};
}
+47
View File
@@ -0,0 +1,47 @@
{ config, inputs, ... }:
let
homeModules = config.flake.modules.homeManager;
in
{
flake.modules.nixos.walker-cache = {
nix.settings = {
extra-substituters = [
"https://walker.cachix.org"
"https://walker-git.cachix.org"
];
extra-trusted-public-keys = [
"walker.cachix.org-1:fG8q+uAaMqhsMxWjwvk0IMb4mFPFLqHjuvfwQxE4oJM="
"walker-git.cachix.org-1:vmC0ocfPWh0S/vRAQGtChuiZBTAe4wiKDeyyXM0/7pM="
];
};
};
flake.modules.homeManager.walker-base =
{
config,
...
}:
{
imports = [ inputs.walker.homeManagerModules.default ];
programs.walker = {
enable = true;
runAsService = true;
config.providers.prefixes = [
{
provider = "bitwarden";
prefix = "?";
}
];
};
};
flake.modules.homeManager.primary-launcher-walker =
{ config, lib, ... }:
{
imports = [ homeModules.walker-base ];
facts.desktop.launcherCommand = lib.getExe config.programs.walker.package;
};
}
+5 -118
View File
@@ -1,8 +1,11 @@
{
repo = {
account = {
account = rec {
name = "kiri";
realName = "Jelle Spreeuwenberg";
homeDirectory = "/home/${name}";
nixosConfigurationPath = "${homeDirectory}/.config/nixos";
emails = {
personal = {
address = "mail@jelles.net";
@@ -22,124 +25,8 @@
type = "office365";
};
};
};
desktop = {
browser = {
command = "vivaldi";
packagePath = [ "vivaldi" ];
};
fileManager = {
command = "nautilus";
packagePath = [ "nautilus" ];
};
terminal = {
command = "kitty";
desktopId = "kitty.desktop";
packagePath = [ "kitty" ];
};
};
services = {
actual = {
domain = "finance.jelles.net";
host = "127.0.0.1";
port = 3000;
url = "https://finance.jelles.net";
};
gitea = {
domain = "git.jelles.net";
host = "127.0.0.1";
port = 3001;
url = "https://git.jelles.net/";
};
radicale = {
domain = "radicale.jelles.net";
host = "127.0.0.1";
port = 5232;
url = "https://radicale.jelles.net/";
};
vaultwarden = {
domain = "vault.jelles.net";
host = "127.0.0.1";
port = 8100;
url = "https://vault.jelles.net";
};
};
theme = {
cursor = {
name = "phinger-cursors-light";
packagePath = [ "phinger-cursors" ];
size = 24;
};
kanagawa = {
displayName = "Kanagawa Wave";
name = "kanagawa-wave";
gtkThemeName = "Kanagawa-BL-LB";
iconThemeName = "Kanagawa";
owner = "Fausto-Korpsvart";
repo = "Kanagawa-GKT-Theme";
rev = "55ca4ba249eba21f861b9866b71ab41bb8930318";
hash = "sha256-UdMoMx2DoovcxSp/zBZ3PRv/Qpj+prd0uPm1gmdak2E=";
version = "unstable-2025-10-23";
palette = {
background = "#1F1F28";
foreground = "#DCD7BA";
secondaryBackground = "#16161D";
border = "#2A2A37";
selectionBackground = "#2D4F67";
selectionForeground = "#C8C093";
url = "#72A7BC";
cursor = "#C8C093";
muted = "#727169";
accents = {
blue = "#7E9CD8";
green = "#98BB6C";
magenta = "#D27E99";
orange = "#FFA066";
purple = "#957FB8";
red = "#E82424";
yellow = "#E6C384";
cyan = "#7AA89F";
};
niri.border = {
active = "#7E9CD8";
inactive = "#54546D";
urgent = "#E82424";
};
terminal = {
color0 = "#16161D";
color1 = "#C34043";
color2 = "#76946A";
color3 = "#C0A36E";
color4 = "#7E9CD8";
color5 = "#957FB8";
color6 = "#6A9589";
color7 = "#C8C093";
color8 = "#727169";
color9 = "#E82424";
color10 = "#98BB6C";
color11 = "#E6C384";
color12 = "#7FB4CA";
color13 = "#938AA9";
color14 = "#7AA89F";
color15 = "#DCD7BA";
color16 = "#FFA066";
color17 = "#FF5D62";
};
};
};
primaryEmail = emails.personal;
};
};
}
-34
View File
@@ -1,34 +0,0 @@
{ config, ... }:
let
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.homeManager.local-apps =
{ pkgs, ... }:
let
browserPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.browser.packagePath;
};
in
{
home.sessionVariables.BROWSER = repo.desktop.browser.command;
home.packages =
with pkgs;
[
postman
spotify
calcure
planify
unzip
gimp
dbeaver-bin
]
++ [ browserPackage ];
programs.imv.enable = true;
programs.sioyek.enable = true;
};
}
-15
View File
@@ -1,15 +0,0 @@
{
flake.modules.nixos.server-firewall = {
networking = {
firewall.enable = true;
firewall.allowPing = false;
};
};
flake.modules.nixos.networking = {
networking = {
nftables.enable = true;
networkmanager.enable = true;
};
};
}
-14
View File
@@ -1,14 +0,0 @@
{ config, ... }:
let
account = config.repo.account;
in
{
flake.modules.homeManager.nh =
{ ... }:
{
programs.nh = {
enable = true;
flake = account.nixosConfigurationPath;
};
};
}
-176
View File
@@ -1,176 +0,0 @@
{
inputs,
config,
...
}:
let
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.nixos.niri =
{ pkgs, ... }:
{
imports = [ inputs.niri.nixosModules.niri ];
nixpkgs.overlays = [ inputs.niri.overlays.niri ];
programs.niri.enable = true;
programs.niri.package = pkgs.niri-unstable;
programs.dconf.enable = true;
services.gvfs.enable = true;
services.udisks2.enable = true;
xdg.portal.enable = true;
};
flake.modules.homeManager.niri =
{
config,
lib,
osConfig,
pkgs,
...
}:
let
repoTheme = repo.theme.kanagawa;
browserCommand = repo.desktop.browser.command;
fileManagerPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.fileManager.packagePath;
};
terminalPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.terminal.packagePath;
};
outputs = lib.mapAttrs (
_: display:
{
position = {
x = display.x;
y = display.y;
};
}
// lib.optionalAttrs (display.primary or false) {
"focus-at-startup" = true;
}
// lib.optionalAttrs (display.scale != null) {
inherit (display) scale;
}
// lib.optionalAttrs (display.width != null && display.height != null && display.refresh != null) {
mode = {
inherit (display)
width
height
refresh
;
};
}
) osConfig.meta.machine.displays;
in
{
assertions = [
{
assertion = fileManagerPackage != null;
message = "Unknown file manager package `${lib.showAttrPath repo.desktop.fileManager.packagePath}`.";
}
];
home.sessionVariables.NIXOS_OZONE_WL = "1";
dconf.settings = {
"org/gnome/desktop/interface" = {
color-scheme = "prefer-dark";
};
};
home.packages =
with pkgs;
[
playerctl
brightnessctl
xwayland-satellite
]
++ [ fileManagerPackage ];
programs.niri.settings = {
inherit outputs;
environment.DISPLAY = ":0";
spawn-at-startup = [
{ command = [ "xwayland-satellite" ]; }
{ command = [ "noctalia-shell" ]; }
];
prefer-no-csd = true;
hotkey-overlay.skip-at-startup = true;
screenshot-path = "${config.xdg.userDirs.pictures}/screenshots/%Y-%m-%dT%H:%M:%S.png";
animations.slowdown = 0.6;
cursor = with config.home.pointerCursor; {
size = size;
theme = name;
hide-after-inactive-ms = 3000;
hide-when-typing = true;
};
layout = {
always-center-single-column = true;
gaps = 14;
focus-ring.enable = false;
default-column-width.proportion = 1. / 2.;
border = {
enable = true;
width = 3;
active.color = repoTheme.palette.niri.border.active;
inactive.color = repoTheme.palette.niri.border.inactive;
urgent.color = repoTheme.palette.niri.border.urgent;
};
};
window-rules = [
{
geometry-corner-radius =
let
radius = 10.0;
in
{
bottom-left = radius;
bottom-right = radius;
top-left = radius;
top-right = radius;
};
clip-to-geometry = true;
}
];
debug.honor-xdg-activation-with-invalid-serial = true;
input = {
focus-follows-mouse.enable = true;
mouse."accel-speed" = 0.4;
keyboard = {
repeat-delay = 300;
repeat-rate = 50;
xkb.options = "caps:escape";
};
touchpad = {
dwt = true;
};
};
binds =
if terminalPackage != null then
import ./_bindings.nix {
inherit
browserCommand
lib
;
terminalPackage = terminalPackage;
}
else
{ };
};
};
}
-82
View File
@@ -1,82 +0,0 @@
{
config,
...
}:
let
repo = config.repo;
in
{
flake.modules.homeManager.pim =
{
config,
...
}:
let
calendarsPath = "${config.xdg.dataHome}/calendars";
in
{
programs.pimsync.enable = true;
services.pimsync.enable = true;
programs.khal = {
enable = false;
locale = {
timeformat = "%H:%M";
dateformat = "$m-$d";
};
};
programs.todoman = {
enable = true;
glob = "*/*";
extraConfig = ''
date_format = "%Y-%m-%d"
time_format = "%H:%M"
default_list = "personal"
default_due = 0
default_command = "list --sort priority,due"
humanize = True
'';
};
accounts.calendar = {
basePath = calendarsPath;
accounts.radicale = {
primary = true;
primaryCollection = "personal";
local = {
type = "filesystem";
fileExt = ".ics";
};
remote = {
url = repo.services.radicale.url;
type = "caldav";
userName = config.home.username;
passwordCommand = [
"rbw"
"get"
"Radicale"
];
};
pimsync = {
enable = true;
extraPairDirectives = [
{
name = "collections";
params = [ "from b" ];
}
];
};
khal = {
enable = true;
type = "discover";
color = "light blue";
};
};
};
};
}
-22
View File
@@ -1,22 +0,0 @@
{
flake.modules.nixos.qbittorrent-client = {
networking.firewall = {
allowedTCPPorts = [ 43864 ];
allowedUDPPorts = [ 43864 ];
};
};
flake.modules.homeManager.qbittorrent-client =
{
lib,
pkgs,
...
}:
{
home.packages = [ pkgs.qbittorrent ];
programs.niri.settings.spawn-at-startup = lib.mkAfter [
{ command = [ "qbittorrent" ]; }
];
};
}
-52
View File
@@ -1,52 +0,0 @@
{
config,
lib,
...
}:
let
syncthingMesh = lib.listToAttrs (
lib.concatMap (
machine:
lib.optional (machine.syncthingId != null) (
let
name = "${config.repo.account.name}@${machine.name}";
in
{
inherit name;
value = {
inherit name;
id = machine.syncthingId;
};
}
)
) (builtins.attrValues config.repo.machines)
);
in
{
flake.modules.homeManager.syncthing =
{ ... }:
{
services.syncthing = {
enable = true;
overrideDevices = true;
overrideFolders = true;
settings = {
folders = {
sync = {
path = "~/sync";
label = "sync";
devices = builtins.attrNames syncthingMesh;
};
calibre = {
path = "~/calibre";
label = "calibre";
devices = builtins.attrNames syncthingMesh;
};
};
devices = syncthingMesh;
};
};
};
}
-115
View File
@@ -1,115 +0,0 @@
{ config, ... }:
let
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.nixos.terminfo =
{ pkgs, ... }:
let
terminalPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.terminal.packagePath;
};
in
{
environment.systemPackages = [
terminalPackage.terminfo
];
};
flake.modules.homeManager.terminal =
{
lib,
pkgs,
...
}:
let
repoTheme = repo.theme.kanagawa;
palette = repoTheme.palette;
terminalPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.terminal.packagePath;
};
terminalDesktopId = repo.desktop.terminal.desktopId;
in
{
assertions = [
{
assertion = terminalPackage != null;
message = "Unknown terminal package `${lib.showAttrPath repo.desktop.terminal.packagePath}`.";
}
{
assertion = repo.desktop.terminal.command == "kitty";
message = "The terminal feature currently only supports kitty.";
}
{
assertion =
terminalPackage == null
|| terminalDesktopId == null
|| builtins.pathExists "${terminalPackage}/share/applications/${terminalDesktopId}";
message = "Terminal package `${lib.showAttrPath repo.desktop.terminal.packagePath}` must provide `${terminalDesktopId}`.";
}
];
xdg.terminal-exec = {
enable = true;
settings.default = lib.optional (terminalDesktopId != null) terminalDesktopId;
};
programs.kitty = {
enable = true;
font = {
name = "JetBrains Mono";
size = 11;
};
settings = {
disable_ligatures = "always";
scrollback_lines = 10000;
enable_audio_bell = false;
confirm_os_window_close = 0;
window_padding_width = 3;
update_check_interval = 0;
};
extraConfig = ''
## name: ${repoTheme.displayName}
## license: MIT
## author: Tommaso Laurenzi
## upstream: https://github.com/rebelot/kanagawa.nvim/
background ${palette.background}
foreground ${palette.foreground}
selection_background ${palette.selectionBackground}
selection_foreground ${palette.selectionForeground}
url_color ${palette.url}
cursor ${palette.cursor}
active_tab_background ${palette.background}
active_tab_foreground ${palette.selectionForeground}
inactive_tab_background ${palette.background}
inactive_tab_foreground ${palette.muted}
color0 ${palette.terminal.color0}
color1 ${palette.terminal.color1}
color2 ${palette.terminal.color2}
color3 ${palette.terminal.color3}
color4 ${palette.terminal.color4}
color5 ${palette.terminal.color5}
color6 ${palette.terminal.color6}
color7 ${palette.terminal.color7}
color8 ${palette.terminal.color8}
color9 ${palette.terminal.color9}
color10 ${palette.terminal.color10}
color11 ${palette.terminal.color11}
color12 ${palette.terminal.color12}
color13 ${palette.terminal.color13}
color14 ${palette.terminal.color14}
color15 ${palette.terminal.color15}
color16 ${palette.terminal.color16}
color17 ${palette.terminal.color17}
'';
};
};
}
-65
View File
@@ -1,65 +0,0 @@
{ config, ... }:
let
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.homeManager.xdg =
{ config, pkgs, ... }:
let
browserPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.browser.packagePath;
};
fileManagerPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.fileManager.packagePath;
};
homeDir = config.home.homeDirectory;
localDir = "${homeDir}/.local";
mediaDir = "${homeDir}/media";
in
{
home.preferXdgDirectories = true;
xdg = {
enable = true;
cacheHome = "${localDir}/cache";
configHome = "${homeDir}/.config";
dataHome = "${localDir}/share";
stateHome = "${localDir}/state";
userDirs = {
enable = true;
createDirectories = true;
setSessionVariables = true;
download = "${homeDir}/downloads";
documents = "${homeDir}/documents";
projects = "${homeDir}/dev";
music = "${mediaDir}/music";
pictures = "${mediaDir}/images";
videos = "${mediaDir}/videos";
desktop = "${localDir}/desktop";
publicShare = "${localDir}/public";
templates = "${localDir}/templates";
};
mimeApps = {
enable = true;
defaultApplicationPackages =
with pkgs;
[
sioyek
imv
neovim
]
++ [
browserPackage
fileManagerPackage
];
};
};
};
}
+2 -2
View File
@@ -12,10 +12,10 @@
systems = [ "x86_64-linux" ];
flake.nixosConfigurations = builtins.mapAttrs (
_: machine:
name: machine:
inputs.nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ (config.repo.helpers.mkHost machine) ];
modules = [ (config.repo.helpers.mkHost name machine) ];
}
) config.repo.machines;
+4 -3
View File
@@ -12,7 +12,6 @@ in
syncthingId = "NNRNQKZ-OWPHSVA-B6KKBHE-SDYLSTV-7SVHGPR-NEWLKPL-4MWNJG4-G5FHUAI";
stateVersion = "24.05";
hmStateVersion = "24.05";
};
flake.modules.nixos.orion =
@@ -21,12 +20,12 @@ in
imports = [
nixosModules.host-base
nixosModules.terminfo
nixosModules.sops-host-ssh-key
nixosModules.openssh
nixosModules.caddy
nixosModules.server-firewall
nixosModules.ssh-agent-auth
nixosModules.sudo-ssh-agent-auth
nixosModules.vps-insights
nixosModules.vaultwarden
nixosModules.radicale
nixosModules.actual
@@ -35,6 +34,8 @@ in
./_disk.nix
];
environment.enableAllTerminfo = true;
users.users.${account.name}.linger = true;
};
}
+1 -2
View File
@@ -16,7 +16,6 @@ in
syncthingId = "6HBAKXB-DB3B4H2-BODCAXF-KD23H5W-6X5LGLC-ZJHZHLG-7U7YMGO-BB6IXQ3";
stateVersion = "24.05";
hmStateVersion = "24.05";
displays = {
"LG Electronics LG ULTRAGEAR 103NTYT8R290" = {
@@ -37,7 +36,7 @@ in
{
imports = [
nixosModules.workstation-base
nixosModules.qbittorrent-client
nixosModules.transmission
nixosModules.steam
./_hardware.nix
]
+1 -2
View File
@@ -28,7 +28,6 @@ in
};
stateVersion = "24.05";
hmStateVersion = "24.05";
};
flake.modules.nixos.zenith =
@@ -36,7 +35,7 @@ in
{
imports = [
nixosModules.workstation-base
nixosModules.qbittorrent-client
nixosModules.transmission
nixosModules.laptop-power
{
hardware.enableRedistributableFirmware = true;
+16 -13
View File
@@ -37,26 +37,35 @@ let
};
mkHost =
machine:
name: machine:
{ pkgs, ... }:
let
account = config.repo.account;
accountHome = account.homeDirectory or "/home/${account.name}";
normalizedMachine = machine // {
inherit name;
displays = machine.displays or { };
hmStateVersion = machine.hmStateVersion or machine.stateVersion;
portable = machine.portable or false;
sshKeys = machine.sshKeys or { };
syncthingId = machine.syncthingId or null;
};
in
{
imports = [
nixosModules.${machine.name}
nixosModules.${name}
];
meta.machine = machine;
facts.machine = normalizedMachine;
networking.hostName = machine.name;
networking.hostName = name;
system.stateVersion = machine.stateVersion;
programs.zsh.enable = true;
users.users.${account.name} = {
isNormalUser = true;
home = account.homeDirectory;
home = accountHome;
extraGroups = [
"wheel"
"networkmanager"
@@ -67,19 +76,13 @@ let
home-manager.users.${account.name} = {
home = {
username = account.name;
homeDirectory = account.homeDirectory;
stateVersion = machine.hmStateVersion;
homeDirectory = accountHome;
stateVersion = normalizedMachine.hmStateVersion;
};
};
};
in
{
options.repo.helpers = lib.mkOption {
type = lib.types.attrsOf lib.types.raw;
internal = true;
readOnly = true;
};
config.repo.helpers = {
inherit
mkCaddyReverseProxy
+24 -193
View File
@@ -1,202 +1,33 @@
{ lib, ... }:
let
emailProviderType = lib.types.enum [
"mxrouting"
"office365"
];
emailType = lib.types.submodule (
{ ... }:
{
options = {
address = lib.mkOption {
type = lib.types.str;
options.repo = lib.mkOption {
type = lib.types.submodule {
freeformType = lib.types.attrsOf lib.types.anything;
options.helpers = lib.mkOption {
type = lib.types.attrsOf lib.types.raw;
default = { };
internal = true;
};
};
default = { };
};
primary = lib.mkOption {
type = lib.types.bool;
default = false;
config.flake.modules.nixos.facts =
{ lib, ... }:
{
options.facts.machine = lib.mkOption {
type = lib.types.attrsOf lib.types.anything;
default = { };
};
};
type = lib.mkOption {
type = emailProviderType;
config.flake.modules.homeManager.facts =
{ lib, ... }:
{
options.facts.desktop = lib.mkOption {
type = lib.types.attrsOf lib.types.anything;
default = { };
};
};
}
);
sshKeyType = lib.types.submodule (
{ name, ... }:
{
options = {
publicKey = lib.mkOption {
type = lib.types.str;
};
privateKeyPath = lib.mkOption {
type = lib.types.str;
default = "~/.ssh/id_${name}";
};
};
}
);
accountType = lib.types.submodule (
{ config, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
};
realName = lib.mkOption {
type = lib.types.str;
};
homeDirectory = lib.mkOption {
type = lib.types.str;
default = "/home/${config.name}";
};
nixosConfigurationPath = lib.mkOption {
type = lib.types.str;
default = "${config.homeDirectory}/.config/nixos";
};
emails = lib.mkOption {
type = lib.types.attrsOf emailType;
default = { };
};
primaryEmail = lib.mkOption {
type = lib.types.nullOr emailType;
description = "Derived primary email entry for this user.";
default =
let
emails = builtins.attrValues config.emails;
in
lib.findFirst (email: email.primary) null emails;
};
};
}
);
displayType = lib.types.submodule (
{ ... }:
{
options = {
primary = lib.mkOption {
type = lib.types.bool;
default = false;
};
x = lib.mkOption {
type = lib.types.int;
default = 0;
};
y = lib.mkOption {
type = lib.types.int;
default = 0;
};
scale = lib.mkOption {
type = lib.types.nullOr lib.types.float;
default = null;
};
width = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
};
height = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
};
refresh = lib.mkOption {
type = lib.types.nullOr lib.types.float;
default = null;
};
};
}
);
machineType = lib.types.submodule (
{ name, config, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
};
stateVersion = lib.mkOption {
type = lib.types.str;
};
hmStateVersion = lib.mkOption {
type = lib.types.str;
default = config.stateVersion;
};
displays = lib.mkOption {
type = lib.types.attrsOf displayType;
default = { };
};
sshKeys = lib.mkOption {
type = lib.types.attrsOf sshKeyType;
default = { };
};
syncthingId = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
portable = lib.mkOption {
type = lib.types.bool;
default = false;
};
};
}
);
in
{
options.repo = {
account = lib.mkOption {
type = accountType;
};
machines = lib.mkOption {
type = lib.types.attrsOf machineType;
default = { };
};
desktop = lib.mkOption {
type = lib.types.raw;
default = { };
};
services = lib.mkOption {
type = lib.types.raw;
default = { };
};
theme = lib.mkOption {
type = lib.types.raw;
default = { };
};
};
config.flake.modules.nixos.meta =
{ ... }:
{
options.meta.machine = lib.mkOption {
type = machineType;
};
};
}
@@ -10,10 +10,10 @@ in
{
flake.modules.nixos.host-base = {
imports = [
nixosModules.meta
nixosModules.facts
inputs.home-manager.nixosModules.home-manager
nixosModules.nix
nixosModules.region-nl
nixosModules.locale-nl
nixosModules.sops-password
];
@@ -22,6 +22,7 @@ in
backupFileExtension = "bak";
extraSpecialArgs = { inherit inputs; };
sharedModules = [
hmModules.facts
hmModules.syncthing
hmModules.shell
hmModules.neovim
@@ -13,15 +13,18 @@ in
nixosModules.bluetooth
nixosModules.flatpak
nixosModules.fonts
nixosModules.networking
nixosModules.network-manager
nixosModules.nftables-firewall
nixosModules.niri
nixosModules.plymouth
nixosModules.printing
nixosModules.sddm
nixosModules.sops-admin-key-file
nixosModules.standard-boot
nixosModules.limine
nixosModules.theme
nixosModules.ai
nixosModules.hidraw-access
nixosModules.walker-cache
];
services.dbus.implementation = "broker";
@@ -36,27 +39,33 @@ in
flake.modules.homeManager.workstation-base = {
imports = [
homeModules.ai
homeModules.bitwarden
homeModules.passwords
homeModules.clipboard
homeModules.dev-tools
homeModules.xdg
homeModules.workstation-apps
homeModules.primary-browser-vivaldi
homeModules.primary-file-manager-nautilus
homeModules.primary-launcher-walker
homeModules.default-image-viewer-imv
homeModules.default-document-viewer-sioyek
homeModules.default-editor-neovim
homeModules.email
homeModules.local-apps
homeModules.mpv
homeModules.nh
homeModules.niri
homeModules.nix
homeModules.pim
homeModules.calendar-tasks
homeModules.podman
homeModules.qbittorrent-client
homeModules.sops
homeModules.git
homeModules.ssh-client
homeModules.terminal
homeModules.theme
homeModules.vicinae
homeModules.xdg
homeModules.primary-terminal-kitty
homeModules.terminal-foot
homeModules.noctalia
{
programs.discord = {
enable = true;
settings.SKIP_HOST_UPDATE = true;
};
}
];
};
}
@@ -1,11 +1,14 @@
{ config, ... }:
let
account = config.repo.account;
nixosModules = config.flake.modules.nixos;
in
{
flake.modules.nixos.sops-password =
{ config, ... }:
{
imports = [ nixosModules.sops ];
sops.secrets.hashed-password.neededForUsers = true;
users.users.${account.name}.hashedPasswordFile = config.sops.secrets.hashed-password.path;
+3
View File
@@ -5,6 +5,7 @@
}:
let
nixosModules = config.flake.modules.nixos;
hmModules = config.flake.modules.homeManager;
sopsAdminKeyPath = "/var/lib/sops/keys.txt";
in
{
@@ -22,6 +23,8 @@ in
{
imports = [ nixosModules.sops ];
home-manager.sharedModules = [ hmModules.sops ];
sops.age.keyFile = sopsAdminKeyPath;
systemd.tmpfiles.rules = [