This commit is contained in:
TheK0tYaRa 2026-02-12 16:11:22 +02:00
commit ce26fcb59c
22 changed files with 2899 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.old/

241
configuration.nix Normal file
View file

@ -0,0 +1,241 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page, on
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
{
config,
# lib,
pkgs,
# inputs,
...
}:
{
nixpkgs.config.allowUnfree = true;
imports = [
./hardware-configuration.nix
];
fileSystems = {
"/mnt/gentoo" = {
device = "/dev/disk/by-label/NVME_GENTOO";
fsType = "xfs";
};
"/mnt/HDD_A_DATA" = {
device = "/dev/disk/by-label/HDD_A_DATA";
fsType = "ext4";
};
"/mnt/HDD_B_1TB" = {
device = "/dev/disk/by-label/HDD_B_1TB";
fsType = "ext4";
};
# dirmounts
"/home/thek0tyara/Documents" = {
depends = [ "/mnt/HDD_B_1TB" ];
device = "/mnt/HDD_B_1TB/home-backup/Documents";
fsType = "none";
options = [ "bind" ];
};
"/home/thek0tyara/Downloads" = {
depends = [ "/mnt/HDD_B_1TB" ];
device = "/mnt/HDD_B_1TB/home-backup/Downloads";
fsType = "none";
options = [ "bind" ];
};
"/home/thek0tyara/.cache" = {
depends = [ "/mnt/HDD_A_DATA" ];
device = "/mnt/HDD_A_DATA/_CACHE";
fsType = "none";
options = [ "bind" ];
};
"/home/thek0tyara/.lmstudio" = {
depends = [ "/mnt/HDD_A_DATA" ];
device = "/mnt/HDD_A_DATA/_LMSTUDIO";
fsType = "none";
options = [ "bind" ];
};
};
nix = {
settings = {
experimental-features = [
"nix-command"
"flakes"
];
auto-optimise-store = true;
substituters = [
"https://nix-community.cachix.org"
"https://cache.nixos.org"
];
trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
};
extraOptions = "!include ${config.age.secrets."github/token.ro.age".path}";
};
boot = {
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = false;
};
kernelPackages = pkgs.linuxPackages_latest;
extraModulePackages = with config.boot.kernelPackages; [
v4l2loopback
amneziawg
];
};
networking = {
hostName = "testenv";
nameservers = [ "10.20.0.1" ];
enableIPv6 = false;
hosts."127.0.0.1" = [ "domain.local" ];
};
systemd.network.networks."enp5s0" = {
matchConfig.Name = "enp5s0";
address = [ "10.20.0.201/24" ];
routes = [ { Gateway = "10.20.0.1"; } ];
linkConfig.RequiredForOnline = "no";
};
# networking.wireguard = {
# interfaces = {
# # wg200 = {
# # ips = [
# # "10.20.0.201/32"
# # ];
# # peers = [
# # {
# # allowedIPs = [
# # "10.20.0.0/24"
# # ];
# # endpoint = "10.20.0.1:51821";
# # persistentKeepalive = 15;
# # publicKey = "EskQEQkC/5t/RyYzrmHLj0HpaiDTEOPgBkbqRcC2d1g=";
# # }
# # ];
# # privateKeyFile = config.age.secrets."wg/syscon0.key".path;
# # };
# # syscon0 = {
# # ips = [
# # "10.1.1.200/32"
# # ];
# # peers = [
# # {
# # allowedIPs = [
# # "10.0.0.0/16"
# # "100.0.0.0/24"
# # "10.1.1.0/24"
# # ];
# # endpoint = "87.251.77.150:60886";
# # persistentKeepalive = 15;
# # publicKey = "uWoxsevoib1+mX3qAtogSxX2M3R6hSu4AfG+nEFgh2I=";
# # #publicKeyFile = ""; # why not you stupid bastard?
# # }
# # ];
# # privateKeyFile = config.age.secrets."wg/syscon0.key".path;
# # };
# };
# };
time.timeZone = "Europe/Kiev";
i18n.defaultLocale = "en_US.UTF-8";
fonts.packages = with pkgs; [
noto-fonts
noto-fonts-cjk-sans
noto-fonts-color-emoji
liberation_ttf
font-awesome
];
# users.defaultUserShell = pkgs.fish;
users.users.thek0tyara = {
isNormalUser = true;
extraGroups = [
"wheel"
"disk"
"dialout"
"video"
"render"
"docker"
"kvm"
"libvirt"
"input"
"users"
"plugdev"
"lxc"
"pipewire"
];
packages = with pkgs; [
# swaylock
swaybg
# swayimg
swayidle
fuzzel
xwayland-satellite
gamescope
telegram-desktop
ladybird
krita
meld
pavucontrol
pwvucontrol
ffmpegthumbnailer
libsForQt5.qt5.qtwayland
qt6Packages.qt6ct
lxappearance
ncdu
ffmpeg-full
mpv
xdotool
tree
hyperfine
unrar
unzip
xarchiver
nmap
];
};
programs = {
niri.enable = true;
gnome-terminal.enable = true;
thunar.enable = true;
winbox = {
enable = true;
package = pkgs.winbox4;
};
gnupg.agent = {
enable = true;
enableSSHSupport = true;
};
};
services = {
openssh.enable = true;
tor = {
enable = true;
torsocks = {
enable = true;
};
xrdp = {
# enable = true;
audio.enable = true;
sslKey = "/secrets/xrdp/key.pem"; # TODO move those
sslCert = "/secrets/xrdp/cert.pem"; # TODO move those
};
};
};
networking.firewall.enable = false;
# Copy the NixOS configuration file and link it from the resulting system
# (/run/current-system/configuration.nix). This is useful in case you
# accidentally delete configuration.nix.
# system.copySystemConfiguration = true;
system.stateVersion = "25.11";
}

6
custom/default.nix Normal file
View file

@ -0,0 +1,6 @@
{ ... }:
{
imports = [
./hm
];
}

7
custom/hm/default.nix Normal file
View file

@ -0,0 +1,7 @@
{ ... }:
{
imports = [
./programs
./services
];
}

View file

@ -0,0 +1,23 @@
{ lib, ... }:
let
here = ./.;
entries = builtins.readDir here;
names = lib.attrNames entries;
nixFiles =
builtins.filter
(n: entries.${n} == "regular" && lib.hasSuffix ".nix" n && n != "default.nix")
names;
subdirDefaultNix =
builtins.filter
(d: entries.${d} == "directory"
&& builtins.pathExists (here + "/${d}/default.nix"))
names;
in
{
imports =
(map (n: here + "/${n}") nixFiles)
++ (map (d: here + "/${d}/default.nix") subdirDefaultNix);
}

View file

@ -0,0 +1,84 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.llama-cpp;
defaultArgsBash =
lib.concatStringsSep " " (map lib.escapeShellArg cfg.defaultArgs);
globalEosTextBash =
lib.escapeShellArg (lib.concatStringsSep "\n" cfg.eosStrings);
presetBash =
lib.concatMapStringsSep "\n" (p: ''
PRESET_PATHS[${lib.escapeShellArg p.name}]=${lib.escapeShellArg p.path}
PRESET_ALIAS[${lib.escapeShellArg p.name}]=${lib.escapeShellArg (p.alias or p.name)}
PRESET_EOS_TEXT[${lib.escapeShellArg p.name}]=${lib.escapeShellArg (lib.concatStringsSep "\n" (p.eosStrings or []))}
'') cfg.presets;
template = builtins.readFile ./llama-serve.sh;
scriptText = lib.replaceStrings
[
"@server_bin@"
"@default_args@"
"@global_eos_text@"
"@preset_bash@"
]
[
"${cfg.package}/bin/${cfg.serverBinary}"
defaultArgsBash
globalEosTextBash
presetBash
]
template;
wrapper = pkgs.writeShellScriptBin cfg.wrapperName scriptText;
in {
options.programs.llama-cpp = {
enable = lib.mkEnableOption "llama.cpp wrapper for llama-server";
package = lib.mkPackageOption pkgs "llama-cpp" { };
serverBinary = lib.mkOption {
type = lib.types.str;
default = "llama-server";
};
wrapperName = lib.mkOption {
type = lib.types.str;
default = "llama-serve";
};
defaultArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Args always passed to llama-server before user args.";
};
eosStrings = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
presets = lib.mkOption {
type = lib.types.listOf (lib.types.submodule ({ ... }: {
options = {
name = lib.mkOption { type = lib.types.str; };
path = lib.mkOption { type = lib.types.str; };
alias = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; };
eosStrings = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; };
};
}));
default = [ ];
};
};
config = lib.mkIf cfg.enable {
home.packages = [
cfg.package
wrapper
];
};
}

View file

@ -0,0 +1,87 @@
#!/usr/bin/env bash
set -euo pipefail
SERVER_BIN="@server_bin@"
DEFAULT_ARGS=( @default_args@ )
GLOBAL_EOS_TEXT=@global_eos_text@
declare -A PRESET_PATHS
declare -A PRESET_ALIAS
declare -A PRESET_EOS_TEXT
@preset_bash@
usage() {
cat >&2 <<'EOF'
Usage:
llama-serve <preset-name|/path/to/model.gguf> [llama-server args...]
If <preset-name> matches programs.llama-cpp.presets[].name, its path/alias/eosStrings are used.
Global eosStrings + preset eosStrings are appended as repeated --reverse-prompt entries.
EOF
if ((${#PRESET_PATHS[@]})); then
echo >&2
echo "Presets:" >&2
for k in "${!PRESET_PATHS[@]}"; do
echo " $k -> ${PRESET_PATHS[$k]}" >&2
done
fi
exit 2
}
((${#} >= 1)) || usage
spec="$1"
shift || true
model_path=""
model_alias=""
preset_eos=""
if [[ -n "${PRESET_PATHS[$spec]+x}" ]]; then
model_path="${PRESET_PATHS[$spec]}"
model_alias="${PRESET_ALIAS[$spec]:-$spec}"
preset_eos="${PRESET_EOS_TEXT[$spec]:-}"
else
model_path="$spec"
model_alias=""
preset_eos=""
fi
# expand ~/...
if [[ "$model_path" == "~/"* ]]; then
model_path="$HOME/${model_path#~/}"
fi
# if [[ ! -f "$model_path" ]]; then
# echo "Model not found: $model_path" >&2
# exit 1
# fi
model_flag="-m"
model_spec="$model_path"
# If arg1 doesn't resolve to an existing local file, treat it as a Hugging Face repo spec.
if [[ ! -f "$model_path" ]]; then
model_flag="-hf"
fi
args=( "${DEFAULT_ARGS[@]}" )
add_reverse_prompts_from_text() {
local text="$1"
[[ -n "$text" ]] || return 0
while IFS= read -r line; do
[[ -n "$line" ]] || continue
args+=( "--reverse-prompt" "$line" )
done <<<"$text"
}
add_reverse_prompts_from_text "$GLOBAL_EOS_TEXT"
add_reverse_prompts_from_text "$preset_eos"
# Optional: set REST API alias when preset provides one (llama-server supports --alias). :contentReference[oaicite:3]{index=3}
if [[ -n "$model_alias" ]]; then
args+=( "--alias" "$model_alias" )
fi
# exec "$SERVER_BIN" -m "$model_path" "${args[@]}" "$@"
exec "$SERVER_BIN" "$model_flag" "$model_spec" "${args[@]}" "$@"

114
custom/hm/programs/n8n.nix Normal file
View file

@ -0,0 +1,114 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.n8n;
valToString = v:
if builtins.isBool v then (if v then "true" else "false")
else if builtins.isInt v then builtins.toString v
else if builtins.isPath v then builtins.toString v
else v;
envList =
lib.mapAttrsToList (k: v: "${k}=${valToString v}") cfg.settings;
extraArgsStr =
lib.optionalString (cfg.extraArgs != [ ]) (" " + lib.escapeShellArgs cfg.extraArgs);
in
{
options.programs.n8n = {
enable = lib.mkEnableOption "n8n (user-level)";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.n8n;
defaultText = "pkgs.n8n";
description = "n8n package to run.";
};
dataDir = lib.mkOption {
type = lib.types.str;
default = "${config.xdg.dataHome}/n8n";
description = "Working/data directory for n8n (contains sqlite and config state).";
};
settings = lib.mkOption {
type = lib.types.attrsOf (lib.types.oneOf [
lib.types.str
lib.types.int
lib.types.bool
lib.types.path
]);
default = { };
description = ''
Environment variables for n8n, e.g. {
N8N_HOST = "127.0.0.1";
N8N_PORT = 5678;
N8N_PROTOCOL = "http";
}
'';
};
environmentFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = "Optional EnvironmentFile (systemd) for secrets, e.g. ~/.config/n8n/secrets.env";
};
extraArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra CLI args passed to `n8n`.";
};
service = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to create a systemd user service for n8n.";
};
wantedBy = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "default.target" ];
description = "Systemd user targets to hook the service into.";
};
};
};
config = lib.mkIf cfg.enable {
home.packages = [ cfg.package ];
# Ensure data dir exists (user tmpfiles)
systemd.user.tmpfiles.rules = [
"d ${cfg.dataDir} 0700 - - -"
];
systemd.user.services.n8n = lib.mkIf cfg.service.enable {
Unit = {
Description = "n8n automation (user)";
After = [ "network-online.target" ];
Wants = [ "network-online.target" ];
};
Service = {
Type = "simple";
WorkingDirectory = cfg.dataDir;
ExecStart = "${cfg.package}/bin/n8n${extraArgsStr}";
# Env vars (non-secret)
Environment = envList;
# Secrets via file (optional)
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
Restart = "on-failure";
RestartSec = "5s";
};
Install = {
WantedBy = cfg.service.wantedBy;
};
};
};
}

View file

@ -0,0 +1,23 @@
{ lib, ... }:
let
here = ./.;
entries = builtins.readDir here;
names = lib.attrNames entries;
nixFiles =
builtins.filter
(n: entries.${n} == "regular" && lib.hasSuffix ".nix" n && n != "default.nix")
names;
subdirDefaultNix =
builtins.filter
(d: entries.${d} == "directory"
&& builtins.pathExists (here + "/${d}/default.nix"))
names;
in
{
imports =
(map (n: here + "/${n}") nixFiles)
++ (map (d: here + "/${d}/default.nix") subdirDefaultNix);
}

View file

@ -0,0 +1,96 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.qdrant;
configRelPath = ".config/qdrant/config.yaml";
configPath = "${config.home.homeDirectory}/${configRelPath}";
defaultSettings = {
log_level = "INFO";
service = {
host = "127.0.0.1";
http_port = 6333;
grpc_port = 6334;
};
storage = {
storage_path = "${cfg.dataDir}/storage";
snapshots_path = "${cfg.dataDir}/snapshots";
};
};
effectiveSettings = lib.recursiveUpdate defaultSettings cfg.settings;
yaml = pkgs.formats.yaml {};
configFile = yaml.generate "qdrant-config.yaml" effectiveSettings;
envList = lib.mapAttrsToList (k: v: "${k}=${toString v}") cfg.environment;
extraArgsStr =
lib.concatStringsSep " " (map lib.escapeShellArg cfg.extraArgs);
in
{
options.services.qdrant = {
enable = lib.mkEnableOption "Qdrant (user-level)";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.qdrant;
};
dataDir = lib.mkOption {
type = lib.types.str;
default = "${config.home.homeDirectory}/.local/share/qdrant";
};
# Мержится поверх defaultSettings
settings = lib.mkOption {
type = lib.types.attrs;
default = {};
};
# Если нужно прокинуть QDRANT__... переменные (они имеют максимальный приоритет)
environment = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = {};
};
extraArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
};
};
config = lib.mkIf cfg.enable {
home.packages = [ cfg.package ];
# symlink в ~/.config/qdrant/config.yaml -> nix store
home.file."${configRelPath}".source = configFile;
# автоматический start/stop/restart при home-manager switch
systemd.user.startServices = "sd-switch"; # default true, но фиксируем явно :contentReference[oaicite:1]{index=1}
systemd.user.services.qdrant = {
Unit = {
Description = "Qdrant (user)";
After = [ "default.target" ];
};
Service = {
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/storage ${cfg.dataDir}/snapshots";
ExecStart = "${cfg.package}/bin/qdrant --config-path ${configPath} ${extraArgsStr}";
# WorkingDirectory = cfg.dataDir;
Restart = "on-failure";
RestartSec = 3;
# ENV в формате ["K=V" ...]
Environment = envList;
};
Install = {
WantedBy = [ "default.target" ];
};
};
};
}

View file

@ -0,0 +1 @@
final: prev: (import ../pkgs { pkgs = final; lib = prev.lib; })

View file

@ -0,0 +1,114 @@
{
lib,
stdenv,
fetchFromGitHub,
nodejs_20,
yarn,
fetchYarnDeps,
fixup-yarn-lock,
python3,
pkg-config,
# makeWrapper,
# openssl,
# sqlite,
vips,
vite,
}:
let
pname = "anything-llm";
version = "1.10.0";
src = fetchFromGitHub {
owner = "Mintplex-Labs";
repo = "anything-llm";
rev = "v${version}";
hash = "sha256-W7wpgEJxo+IfIVRAWJNTmJL4RezO4NdlQEpV6dJp5IA=";
fetchSubmodules = true;
};
offlineCacheFrontend = fetchYarnDeps {
yarnLock = "${src}/frontend/yarn.lock";
hash = "sha256-ebAV+1Ux4aL6hIodfaRVjEUFSWQplI7c7sybTEzucdw=";
};
offlineCacheServer = fetchYarnDeps {
yarnLock = "${src}/server/yarn.lock";
hash = "sha256-+agJhFItPGLBUGLhhdNATiHuId51sDWQbG/Z1FyIVWM=";
};
in
stdenv.mkDerivation {
inherit pname version src;
nativeBuildInputs = [
nodejs_20
yarn
python3
pkg-config
stdenv.cc # чтобы был компилятор/линкер
fixup-yarn-lock
vite
];
buildInputs = [
vips
nodejs_20.dev
];
# важно: чтобы sharp не пытался скачать vendor-libvips и не игнорировал системный
SHARP_FORCE_GLOBAL_LIBVIPS = "1"; # всегда пытаться использовать global libvips :contentReference[oaicite:0]{index=0}
npm_config_build_from_source = "sharp"; # просим sharp собираться из исходников :contentReference[oaicite:1]{index=1}
configurePhase = ''
export HOME="$(mktemp -d)"
pushd server
fixup-yarn-lock yarn.lock
yarn config --offline set yarn-offline-mirror "${offlineCacheServer}"
# 1) ставим deps без postinstall'ов (иначе sharp полезет в сеть)
yarn install --offline --frozen-lockfile --ignore-scripts --no-progress
# 2) теперь собираем sharp из исходников против system libvips
export PKG_CONFIG_PATH="${vips.dev}/lib/pkgconfig:${vips}/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="${vips}/lib:$LD_LIBRARY_PATH"
export npm_config_nodedir="${nodejs_20.dev}"
# yarn v1: rebuild прогоняет lifecycle для native-модулей
${nodejs_20}/bin/npm rebuild sharp --build-from-source --nodedir="${nodejs_20.dev}"
popd
'';
postPatch = ''
# frontend: build without Qt/X11 postbuild
substituteInPlace frontend/package.json \
--replace '"build": "vite build && node scripts/postbuild.js"' '"build": "vite build"'
'';
buildPhase = ''
runHook preBuild
(export QT_QPA_PLATFORM=offscreen QTWEBENGINE_DISABLE_SANDBOX=1 QTWEBENGINE_CHROMIUM_FLAGS="--headless --disable-gpu --no-sandbox"
cd frontend && yarn build) # --offline
# server/collector build steps, если нужны, добавите отдельно
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/lib/${pname} $out/bin
cp -r frontend server collector $out/lib/${pname}/
makeWrapper ${nodejs_20}/bin/node $out/bin/anything-llm-server \
--chdir $out/lib/${pname}/server \
--set NODE_ENV production \
--set-default PORT 3001 \
--add-flags "index.js"
runHook postInstall
'';
meta = with lib; {
description = "AnythingLLM (server + frontend + collector)";
homepage = "https://github.com/Mintplex-Labs/anything-llm";
license = licenses.mit;
platforms = platforms.linux;
};
}

View file

@ -0,0 +1,82 @@
{
lib,
fetchurl,
appimageTools,
imagemagick,
}:
let
pname = "lmstudio";
version = "0.4.2-2";
url = "https://installers.lmstudio.ai/linux/x64/${version}/LM-Studio-${version}-x64.AppImage";
src = fetchurl {
inherit url;
hash = "sha256-JxGlqgsuLcW81mOIcntVFSHv19zSFouIChgz/egc+J0=";
};
contents = appimageTools.extractType2 { inherit pname version src; };
in
appimageTools.wrapType2 {
inherit pname version src;
nativeBuildInputs = [ imagemagick ];
extraInstallCommands = ''
set -euo pipefail
mkdir -p "$out/share/applications"
mkdir -p "$out/share/icons/hicolor/256x256/apps"
# ---- desktop: create fresh, never edit in place ----
desktopSrc="$(find "${contents}" -type f -name '*.desktop' | head -n1 || true)"
if [ -n "$desktopSrc" ]; then
tmp="$(mktemp)"
# Rewrite keys deterministically; keep everything else.
awk -v exec="${pname}" -v icon="${pname}" '
BEGIN{hasExec=0;hasTry=0;hasIcon=0}
/^Exec=/{print "Exec="exec; hasExec=1; next}
/^TryExec=/{print "TryExec="exec; hasTry=1; next}
/^Icon=/{print "Icon="icon; hasIcon=1; next}
{print}
END{
if(!hasExec) print "Exec="exec
if(!hasTry) print "TryExec="exec
if(!hasIcon) print "Icon="icon
}
' "$desktopSrc" > "$tmp"
rm -f "$out/share/applications/${pname}.desktop"
install -m444 "$tmp" "$out/share/applications/${pname}.desktop"
rm -f "$tmp"
fi
# ---- icon: pick one, convert to canonical name ----
icon=""
for cand in \
"${contents}/.DirIcon" \
"${contents}/AppIcon.png" \
"${contents}/usr/share/icons/hicolor/512x512/apps/"*.png \
"${contents}/usr/share/icons/hicolor/256x256/apps/"*.png \
; do
if [ -f "$cand" ]; then icon="$cand"; break; fi
done
if [ -z "$icon" ]; then
icon="$(find "${contents}" -type f -name '*.png' | head -n1 || true)"
fi
if [ -n "$icon" ]; then
magick "$icon" -resize 256x256 "$out/share/icons/hicolor/256x256/apps/${pname}.png"
fi
'';
meta = with lib; {
description = "LM Studio (AppImage)";
homepage = "https://lmstudio.ai/";
license = licenses.unfreeRedistributable;
platforms = [ "x86_64-linux" ];
mainProgram = pname;
};
}

View file

@ -0,0 +1,120 @@
{
description = "stable-diffusion.cpp as a NixOS programs.* module (system nixpkgs)";
outputs = { self, ... }: {
nixosModules.default = { config, lib, pkgs, ... }:
let
cfg = config.programs.stable-diffusion-cpp;
builtPackage =
pkgs.stdenv.mkDerivation {
pname = "stable-diffusion-cpp";
version = "git";
src = pkgs.fetchFromGitHub {
owner = "leejet";
repo = "stable-diffusion.cpp";
rev = "master-453-4ff2c8c"; # pin to a commit for reproducibility
hash = "sha256-0Hl3M6NQK1ZfIH4eIdy/XiPZTeBCnRCtode88NipPp4=";
fetchSubmodules = true;
};
nativeBuildInputs = with pkgs; [ cmake ninja pkg-config ];
buildInputs =
(lib.optionals cfg.vulkan.enable (with pkgs; [
vulkan-headers
vulkan-loader
shaderc
]));
cmakeFlags = [
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
"-DSD_VULKAN=${if cfg.vulkan.enable then "ON" else "OFF"}"
];
installPhase = ''
runHook preInstall
mkdir -p $out/bin
cp -v bin/sd $out/bin/ || cp -v sd $out/bin/
runHook postInstall
'';
};
selectedPackage = if cfg.package != null then cfg.package else builtPackage;
extraEnvArgs =
lib.concatStringsSep " \\\n "
(lib.mapAttrsToList (k: v:
"--set ${lib.escapeShellArg k} ${lib.escapeShellArg v}"
) cfg.extraEnv);
wrappedPackage =
pkgs.symlinkJoin {
name = "${selectedPackage.pname or "stable-diffusion-cpp"}";
paths = [ selectedPackage ];
nativeBuildInputs = [ pkgs.makeWrapper ];
postBuild = ''
if [ -x "$out/bin/sd" ]; then
wrapProgram "$out/bin/sd" \
${lib.optionalString (cfg.vulkan.enable && cfg.vulkan.icdFile != null)
"--set-default VK_ICD_FILENAMES ${lib.escapeShellArg (toString cfg.vulkan.icdFile)}"} \
${lib.optionalString (cfg.vulkan.enable && cfg.vulkan.prefixOpenGLXdgDataDirs)
"--prefix XDG_DATA_DIRS : /run/opengl-driver/share"} \
${extraEnvArgs}
fi
'';
};
finalPackage = if cfg.wrap then wrappedPackage else selectedPackage;
in {
options.programs.stable-diffusion-cpp = {
enable = lib.mkEnableOption "stable-diffusion.cpp";
package = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "Override the package used (otherwise build from upstream source).";
};
wrap = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Wrap the sd binary to inject environment variables.";
};
extraEnv = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
description = "Extra environment variables added to the sd wrapper.";
};
vulkan = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Build with Vulkan support (toggles -DSD_VULKAN and Vulkan deps).";
};
icdFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = /run/opengl-driver/share/vulkan/icd.d/intel_icd.x86_64.json;
description = "Optional VK_ICD_FILENAMES value to select a Vulkan ICD.";
};
prefixOpenGLXdgDataDirs = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Prefix XDG_DATA_DIRS with /run/opengl-driver/share (useful for Vulkan layers/ICDs on NixOS).";
};
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ finalPackage ];
};
};
};
}

25
custom/pkgs/default.nix Normal file
View file

@ -0,0 +1,25 @@
{ pkgs, lib, ... }:
let
byName = ./by-name;
dirs = path:
lib.attrNames (lib.filterAttrs (_: t: t == "directory") (builtins.readDir path));
packagesFromByName = base:
lib.foldl' (acc: shorthand:
let
shorthandDir = base + "/${shorthand}";
names = dirs shorthandDir;
addOne = name:
let
pkgDir = shorthandDir + "/${name}";
def = pkgDir + "/default.nix";
in
if builtins.pathExists def
then { ${name} = pkgs.callPackage pkgDir { }; }
else { };
in
acc // lib.foldl' (a: n: a // addOne n) { } names
) { } (dirs base);
in
packagesFromByName byName

1110
flake.lock generated Normal file

File diff suppressed because it is too large Load diff

260
flake.nix Normal file
View file

@ -0,0 +1,260 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
ragenix.url = "github:yaxitech/ragenix/2025.03.09";
niri.url = "github:YaLTeR/niri/v25.11";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
ghostty.url = "github:ghostty-org/ghostty/tip";
# ghostty.url = [
# "github:ghostty-org/ghostty/1.3.0"
# "github:ghostty-org/ghostty/tip"
# ];
dw-proton.url = "github:imaviso/dwproton-flake";
intel-hw.url = "github:MordragT/nixos";
#
};
outputs =
inputs@{
# self,
nixpkgs,
ragenix,
home-manager,
ghostty,
intel-hw,
...
}:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShells.${system}.default = pkgs.mkShell {
packages = [
ragenix.packages.x86_64-linux.default
];
};
nixosConfigurations.testenv = nixpkgs.lib.nixosSystem {
inherit system;
#
specialArgs = { inherit inputs; };
modules = [
ragenix.nixosModules.default
(
{
pkgs,
pkgdefault,
...
}:
{
_module.args = {
pkgdefault = pkg: pkg.packages.${pkgs.stdenv.hostPlatform.system}.default;
};
nixpkgs.overlays = [
intel-hw.overlays.default
(import ./custom/overlays)
(final: prev: {
llama-cpp = prev.llama-cpp.overrideAttrs (old: {
src = prev.fetchFromGitHub {
owner = "ggml-org";
repo = "llama.cpp";
tag = "b7897";
hash = "sha256-cc2tqEQEZCBEOQ+xJzmVK8ROjfsWOi6T2iX3KjpaAIU=";
};
nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.curl ];
});
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
(pyFinal: pyPrev: {
haystack-ai = pyPrev.haystack-ai.overridePythonAttrs (old: rec {
version = "2.23.0";
src = final.fetchFromGitHub {
owner = "deepset-ai";
repo = "haystack";
rev = "v${version}";
hash = "sha256-KFgRKdhbHgjtpiuAeFq+0t0EUKKLOavbVplb0QnI/r8=";
};
propagatedBuildInputs =
old.propagatedBuildInputs
++ (with pyPrev; [
docstring-parser
filetype
haystack-experimental # ./custom/pkgs/by-category/python3Packages/ha/haystack-experimental/default.nix
jinja2
openai
]);
meta = (old.meta or { }) // {
broken = false;
};
});
})
];
winetricks = prev.winetricks.overrideAttrs (
old:
let
version = "20260125";
in
{
inherit version;
src = final.fetchurl {
url = "https://github.com/Winetricks/winetricks/archive/refs/tags/${version}.tar.gz";
hash = "sha256-KJC9n7ut5GOOWLSZmiNycxkt8DtYUWrnuHceCcItL1Y=";
};
}
);
})
];
hardware = {
graphics = {
enable = true;
extraPackages = (
with pkgs;
[
intel-media-driver
intel-ocl
vpl-gpu-rt
intel-compute-runtime
]
);
# ++ (with inputs.intel-hw.packages."${system}"; [
# # oneapi-dal
# # oneapi-dpl
# # oneapi-ccl
# ]);
# enable32Bit = true;
};
enableRedistributableFirmware = true;
};
nix.settings = {
# keep-logs = true;
trusted-users = [
"root"
"thek0tyara"
];
download-buffer-size = 160000000;
};
age = {
secrets = {
"wg/syscon0.key".file = ./secrets/wg/syscon0.key.age;
"github/token.ro.age" = {
file = ./secrets/github/token.ro.age;
owner = "root";
group = "wheel";
mode = "0440";
};
};
identityPaths = [ "/root/.ssh/id_ed25519" ];
};
environment = {
sessionVariables = {
LIBVA_DRIVER_NAME = "iHD";
LLAMA_CACHE = "/home/thek0tyara/Downloads/llm";
CCACHE_DIR = "/mnt/HDD_A_DATA/ccache";
# LLVM = "1";
# UV_CACHE_DIR = "";
# PIP_CACHE_DIR = "";
# PYTHONPYCACHEPREFIX = "";
};
systemPackages = with pkgs; [
ccache
sccache
(pkgdefault inputs.ragenix)
devenv
htop
# gpu
vulkan-tools
libva-utils
intel-gpu-tools
pciutils
inxi
mesa-demos
# xwayland
xhost
# llm
# llama-cpp-vulkan
git
nixpkgs-fmt
nixd
nil # apple-cursor
android-tools
];
};
security.polkit = {
enable = true;
};
programs = {
# amnezia-vpn.enable = true;
ccache.enable = true;
nix-ld = {
enable = true;
libraries = with pkgs; [
stdenv.cc.cc.lib
];
};
obs-studio.enableVirtualCamera = true;
steam = {
enable = true;
extraCompatPackages = [
inputs.dw-proton.packages.${system}.dw-proton
];
};
traceroute.enable = true;
ydotool = {
enable = true;
group = "wheel";
};
};
services = {
displayManager = {
enable = true;
defaultSession = "niri";
};
locate.enable = true;
pipewire = {
enable = true;
pulse.enable = true;
};
xserver = {
enable = true;
displayManager.lightdm.enable = true;
xkb = {
layout = "us,ru";
options = "grp:alt_shift_toggle";
};
};
};
}
)
./configuration.nix
#
home-manager.nixosModules.default
{
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = {
inherit system;
inherit ghostty;
};
users.thek0tyara = ./home.nix;
};
}
];
};
};
}

View file

@ -0,0 +1,33 @@
# 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 + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-label/NVME_NIXOS";
fsType = "ext4";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-label/NVME_ESP";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};
swapDevices =
[{ device = "/dev/disk/by-label/NVME_SWAP"; }
];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

454
home.nix Normal file
View file

@ -0,0 +1,454 @@
{
config,
pkgs,
system,
ghostty,
...
}:
# let
# vesktopNoFuses = pkgs.vesktop.overrideAttrs (old: {
# nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.jq ];
# postPatch = (old.postPatch or "") + ''
# tmp="$(mktemp)"
# jq 'del(.build.electronFuses)' package.json > "$tmp"
# mv "$tmp" package.json
# '';
# });
# in
{
imports = [
./custom/hm
];
gtk = {
enable = true;
colorScheme = "dark";
theme = {
name = "Adwaita-dark";
package = pkgs.gnome-themes-extra;
};
iconTheme = {
name = "Papirus-Dark";
package = pkgs.papirus-icon-theme;
};
cursorTheme = {
name = "macOS";
package = pkgs.apple-cursor;
size = 28;
};
};
home = {
stateVersion = "25.11";
pointerCursor = {
enable = true;
gtk.enable = true;
x11 = {
enable = true;
# defaultCursor = "";
};
dotIcons.enable = true;
package = pkgs.apple-cursor;
name = "macOS";
size = 26;
};
shell = {
enableFishIntegration = true;
};
packages = with pkgs; [
vlc
prismlauncher
jq
xfce4-taskmanager
gparted
python312Packages.huggingface-hub
tor-browser
winetricks
wineWowPackages.full
iperf
sshuttle
lmstudio
dig
libnotify
# kdePackages.kdenlive
python312
# python314Packages.haystack-ai # TODO
# anything-llm
### NEVER USE THIS GARBAGE
# flowblade pitivi koboldcpp
];
sessionVariables = {
DESKTOP = ":0";
OLLAMA_HOST = "10.20.0.201:11434";
};
};
xdg = {
mimeApps = {
enable = true;
defaultApplications = {
"text/html" = "firefox.desktop";
"x-scheme-handler/http" = "firefox.desktop";
"x-scheme-handler/https" = "firefox.desktop";
"x-scheme-handler/tg" = "org.telegram.desktop.desktop";
"x-scheme-handler/discord" = "vesktop.desktop";
"image/jpeg" = "swayimg.desktop";
"image/png" = "swayimg.desktop";
"image/webp" = "swayimg.desktop";
};
};
configFile."obsidian/.keep".text = "";
};
systemd.user = {
startServices = "sd-switch";
services = {
prepare2watch = {
Unit = {
Description = "prepare videos to get later";
};
Service = {
Type = "oneshot";
WorkingDirectory = "${config.home.homeDirectory}/Downloads/1/";
ExecStart = ''
${pkgs.util-linux}/bin/flock -n %t/prepare2watch.lock ${pkgs.fish}/bin/fish ./prepare2watch.fish
'';
};
};
};
paths = {
prepare2watch = {
Unit = {
Description = "Watch ${config.home.homeDirectory}/Downloads/1/list";
};
Path = {
PathChanged = "${config.home.homeDirectory}/Downloads/1/list";
PathModified = "${config.home.homeDirectory}/Downloads/1/list";
Unit = "prepare2watch.service";
};
Install = {
WantedBy = [ "default.target" ];
};
};
};
};
services = {
ollama = {
# enable = true;
# acceleration = vulkan;
package = pkgs.ollama-vulkan;
host = "10.20.0.201";
environmentVariables = {
OLLAMA_MAX_LOADED_MODELS = "1";
OLLAMA_NUM_PARALLEL = "1";
OLLAMA_FLASH_ATTENTION = "1";
OLLAMA_KV_CACHE_TYPE = "q8_0";
# OLLAMA_CONTEXT_LENGTH = "16000";
OLLAMA_MODELS = "/home/thek0tyara/Downloads/llm/ollama";
};
};
polkit-gnome.enable = true;
qdrant = {
enable = true;
dataDir = "/mnt/HDD_A_DATA/services/lib/qdrant";
settings = {
storage = {
# storage_path = "/mnt/HDD_A_DATA/services/lib/qdrant/storage";
# snapshots_path = "/mnt/HDD_A_DATA/services/lib/qdrant/snapshots";
hnsw_index = {
on_disk = true;
};
};
service = {
host = "127.0.0.1";
http_port = 6333;
grpc_port = 6334;
};
telemetry_disabled = true;
};
};
};
programs = {
### custom
n8n = {
# enable = true;
settings = {
N8N_HOST = "127.0.0.1";
N8N_PORT = 5678;
N8N_PROTOCOL = "http";
};
# environmentFile = ~/.config/n8n/secrets.env;
# extraArgs = [ ];
};
llama-cpp = {
# enable = true;
package = pkgs.llama-cpp.override {
vulkanSupport = true;
rpcSupport = true;
};
defaultArgs = [
"--host"
"127.0.0.1"
"--port"
"8080"
"--jinja"
"-fa"
"on"
];
# eosStrings = [ "<|im_end|>" ];
presets = [
{
name = "codegeex4";
path = "/home/thek0tyara/Downloads/llm/codegeex4-all-9b.Q8_0.gguf";
eosStrings = [ "<|im_end|>" ];
}
];
};
opencode = {
enable = true;
settings = {
compaction = {
auto = true;
prune = true;
};
watcher = {
ignore = [
".git/**"
];
};
plugin = [
"@zenobius/opencode-skillful" # lazy load
];
default_agent = "plan";
tools = {
skill = false;
"qdrant_*" = false;
};
mcp = {
qdrant = {
type = "local";
command = [
"${pkgs.uv}/bin/uvx"
"-qq"
"mcp-server-qdrant"
];
enabled = true;
timeout = 5000;
environment = {
QDRANT_URL = "http://127.0.0.1:6333";
COLLECTION_NAME = "opencode_memory";
# Debug only:
# FASTMCP_LOG_LEVEL = "DEBUG";
# FASTMCP_DEBUG = "true";
};
};
};
# Agents: features retained, but only injected when invoked
agent = {
plan = {
mode = "primary";
tools = {
write = false;
edit = false;
bash = false;
skill = false;
"qdrant_*" = false;
};
};
build = {
mode = "primary";
tools = {
write = true;
edit = true;
bash = true;
skill = false;
"qdrant_*" = false;
};
};
memory = {
mode = "subagent";
description = "Opt-in semantic memory via Qdrant MCP";
tools = {
"qdrant_*" = true;
};
};
skills = {
mode = "subagent";
description = "Opt-in skills tool";
tools = {
skill = true;
};
};
};
theme = "opencode";
autoupdate = false;
share = "manual";
server = {
port = 4096;
hostname = "127.0.0.1";
};
provider = {
"ollama" = {
npm = "@ai-sdk/openai-compatible";
name = "Ollama (local)";
options = {
baseURL = "http://10.20.0.201:11434/v1";
};
models = {
"qwen2.5-coder:7b" = {
name = "qwen2.5-coder";
};
"qwen3:8b" = {
name = "qwen3";
};
};
};
};
};
rules = ''
# Global rules (thin)
- Prefer on-demand file loading over preloading large docs.
- Use MCP/skills only via dedicated subagents.
'';
};
### default
aria2.enable = true;
btop.enable = true;
command-not-found.enable = true;
direnv.enable = true;
eza = {
enable = true;
git = true;
icons = "auto";
};
fastfetch.enable = true;
firefox = {
enable = true;
package = pkgs.firefox;
languagePacks = [ "en-US" ];
};
fish = {
enable = true;
functions = {
fish_greeting = "";
};
};
#
ghostty = {
enable = true;
package = ghostty.packages.${system}.default;
settings = {
theme = "dark";
term = "xterm-256color";
scrollback-limit = 1000000;
};
themes = {
dark = {
background = "171421";
# cursor-color = "f5e0dc";
foreground = "D0CFCC";
palette = [
"0=#171421"
"1=#C01C28"
"2=#26A269"
"3=#A2734C"
"4=#12488B"
"5=#A347BA"
"6=#2AA1B3"
"7=#D0CFCC"
"8=#5E5C64"
"9=#F66151"
"10=#33D17A"
"11=#E9AD0C"
"12=#2A7BDE"
"13=#C061CB"
"14=#33C7DE"
"15=#FFFFFF"
];
# selection-background = "171421";
# selection-foreground = "D0CFCC";
};
};
};
#
lutris = {
# enable = true;
# defaultWinePackage = pkgs.wineWowPackages.full;
runners = {
wine = {
settings = {
runner = {
# runner_executable = "${pkgs.wineWowPackages.full}/bin/wine";
};
system = {
game_path = "/home/thek0tyara/Documents/lutris";
disable_runtime = false;
prefer_system_libs = true;
};
};
};
};
};
nix-your-shell.enable = true;
obs-studio = {
enable = true;
plugins = with pkgs.obs-studio-plugins; [
wlrobs
obs-pipewire-audio-capture
];
};
obsidian.enable = true;
starship.enable = true;
swayimg.enable = true;
swaylock.enable = true;
uv = {
enable = true; # TODO move to nativeBuildInputs of needing
settings = {
python-downloads = "never";
python-preference = "only-system";
# pip.index-url = "https://pypi.org/simple";
};
};
vesktop = {
enable = true;
# package = vesktopNoFuses;
# settings = { TODO };
};
vscode.enable = true;
waybar.enable = true;
yt-dlp = {
enable = true;
package = pkgs.yt-dlp;
settings = {
embed-thumbnail = true;
downloader = "aria2c";
};
# extraConfig = ''
# --extractor-args "youtube:player_client=default,ios,-android_sdkless"
# '';
};
zed-editor = {
enable = true;
themes = {
"name" = "Ayu Dark";
};
};
};
}

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 7NTRpQ lXccnDI4sBAGeSu6yndyzRcf+VtdlKx61bbpHOQPXAQ
VI0/OLgIskzCLnF6zPxdgeawiE86A0jUoyryPjiXtf8
--- I2kD2ndIYOk5EikyVgCE3LKT4sGEQ3J6aC0odY9r1eg
ãÀ"Æ'Ìçç;=—ÑäÍ4 DuÂÔÜôä~Šb( ám´ÜŽy§^Ÿó©ë vk·.Ñ™¹déyfŒMDåíþª3¸|Øã_£ÀØ›Œ[üÅéìáñ„@ì²Ty

8
secrets/secrets.nix Normal file
View file

@ -0,0 +1,8 @@
let
thek0tyara = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDb6p1jwL8lemLf1SwhmuA/WSkQ2zG/xp7Aa9t6CLL23";
users = [ thek0tyara ];
in
{
"wg/syscon0.key.age".publicKeys = [ thek0tyara ];
"github/token.ro.age".publicKeys = [ thek0tyara ];
}

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 7NTRpQ WII0w2ms+1pqCbh4VgBw1f0ORw6+p0HBYLCy0t2sujs
kVRyWFFJo/d9RlMDZsr9S+Ue9+IO3ysU0ytZFjJZszs
--- yq9NNt4S1FuQ6r8NPWON7J5DErJq/2RZBHMkBOse4rI
FTPãê{hWûÎË¥Í|§:ç±ëZ×b\ 릘)öU²Þp2 ¹ <C2B9>DzÏ…¿ây³²Y¦<59>φ_eèÏú <20>häg+í-³…