Compare commits

...

12 Commits

Author SHA1 Message Date
Anish Lakhwara 615ea7b026 idk some stuff, mostly 25.11 and opencode stuff 2026-02-01 23:39:21 -08:00
Anish Lakhwara cd8bb0fe0f migrate to radicle 2026-01-21 21:55:37 -08:00
Anish Lakhwara 928a3f56ad opencode archivist 2026-01-19 22:37:40 -08:00
Anish Lakhwara d0cde973e7 box zfs 2026-01-19 22:37:30 -08:00
Anish Lakhwara 3b33575b2a more opencode stuff 2026-01-13 20:34:35 -08:00
Anish Lakhwara 328779b0ac Merge branch 'main' of git.sealight.xyz:aynish/helm 2025-12-24 17:27:51 -08:00
Anish Lakhwara 1ec0b1bbe5 fix: nil-ls popup in nvim 2025-12-24 17:27:26 -08:00
Anish Lakhwara f61711c00d feat: opencode.nvim 2025-12-24 17:25:55 -08:00
Anish Lakhwara 3c8dfd58a1 Merge branch 'main' of git.sealight.xyz:aynish/helm 2025-12-22 15:49:27 -08:00
Anish Lakhwara 5071c6cd2b fix: remove extra pg_vector 2025-12-22 15:47:41 -08:00
Anish Lakhwara a936331a2c Merge branch 'main' of git.sealight.xyz:aynish/helm 2025-12-22 15:38:55 -08:00
Anish Lakhwara 0b6c15224a feat: tokens 2025-12-22 15:38:22 -08:00
57 changed files with 2510 additions and 798 deletions
@@ -35,7 +35,7 @@ NIX_CC='/nix/store/kaj8d1zcn149m40s9h0xi0khakibiphz-gcc-wrapper-14.3.0'
export NIX_CC
NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu='1'
export NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
NIX_CFLAGS_COMPILE=' -frandom-seed=5s10b8rs3j -isystem /nix/store/8znh07lsz9q2fdp6fgcdwwv035xxfrl1-nix-2.28.4-dev/include -isystem /nix/store/qwnz3z0hf5pdhwsn92dc9lhlq4a3lsqk-boehm-gc-8.2.8-dev/include -isystem /nix/store/235hvgzcbl06fxy53515q8sr6lljvf68-nlohmann_json-3.11.3/include -isystem /nix/store/a5b9czim7vrihag71f8dy1c467qh3mph-libarchive-3.8.0-dev/include -isystem /nix/store/0vy272ral6dwzx96wkvd90l37v0gdrk7-attr-2.5.2-dev/include -isystem /nix/store/ra69jxg2pnnjymvkn83mfr7cnhllmwnj-acl-2.3.2-dev/include -isystem /nix/store/8znh07lsz9q2fdp6fgcdwwv035xxfrl1-nix-2.28.4-dev/include -isystem /nix/store/qwnz3z0hf5pdhwsn92dc9lhlq4a3lsqk-boehm-gc-8.2.8-dev/include -isystem /nix/store/235hvgzcbl06fxy53515q8sr6lljvf68-nlohmann_json-3.11.3/include -isystem /nix/store/a5b9czim7vrihag71f8dy1c467qh3mph-libarchive-3.8.0-dev/include -isystem /nix/store/0vy272ral6dwzx96wkvd90l37v0gdrk7-attr-2.5.2-dev/include -isystem /nix/store/ra69jxg2pnnjymvkn83mfr7cnhllmwnj-acl-2.3.2-dev/include'
NIX_CFLAGS_COMPILE=' -frandom-seed=bsnbf5cn1y -isystem /nix/store/qrp30zrv029hzlrhpavhjl89w7sfhyih-nix-2.28.5-dev/include -isystem /nix/store/qwnz3z0hf5pdhwsn92dc9lhlq4a3lsqk-boehm-gc-8.2.8-dev/include -isystem /nix/store/vgi5jkglabcvmhsrp8wixg1r2dhjyvva-nlohmann_json-3.11.3/include -isystem /nix/store/m3nkjvz6dcz1yy0j82d2ihkyxagiqxdm-libarchive-3.8.0-dev/include -isystem /nix/store/0vy272ral6dwzx96wkvd90l37v0gdrk7-attr-2.5.2-dev/include -isystem /nix/store/ra69jxg2pnnjymvkn83mfr7cnhllmwnj-acl-2.3.2-dev/include -isystem /nix/store/qrp30zrv029hzlrhpavhjl89w7sfhyih-nix-2.28.5-dev/include -isystem /nix/store/qwnz3z0hf5pdhwsn92dc9lhlq4a3lsqk-boehm-gc-8.2.8-dev/include -isystem /nix/store/vgi5jkglabcvmhsrp8wixg1r2dhjyvva-nlohmann_json-3.11.3/include -isystem /nix/store/m3nkjvz6dcz1yy0j82d2ihkyxagiqxdm-libarchive-3.8.0-dev/include -isystem /nix/store/0vy272ral6dwzx96wkvd90l37v0gdrk7-attr-2.5.2-dev/include -isystem /nix/store/ra69jxg2pnnjymvkn83mfr7cnhllmwnj-acl-2.3.2-dev/include'
export NIX_CFLAGS_COMPILE
NIX_CONFIG='experimental-features = nix-command flakes'
export NIX_CONFIG
@@ -43,7 +43,7 @@ NIX_ENFORCE_NO_NATIVE='1'
export NIX_ENFORCE_NO_NATIVE
NIX_HARDENING_ENABLE='bindnow format fortify fortify3 pic relro stackclashprotection stackprotector strictoverflow zerocallusedregs'
export NIX_HARDENING_ENABLE
NIX_LDFLAGS='-rpath /home/anish/usr/helm/outputs/out/lib -L/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8/lib -L/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2/lib -L/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2/lib -L/nix/store/y130gnbp2qkfq6svqdv0s61b3m4043yp-libarchive-3.8.0-lib/lib -L/nix/store/7q9ll9pjrdfdb3qyfza2bzrk829izk9s-nix-2.28.4/lib -L/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8/lib -L/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2/lib -L/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2/lib -L/nix/store/y130gnbp2qkfq6svqdv0s61b3m4043yp-libarchive-3.8.0-lib/lib -L/nix/store/7q9ll9pjrdfdb3qyfza2bzrk829izk9s-nix-2.28.4/lib'
NIX_LDFLAGS='-rpath /home/anish/usr/helm/outputs/out/lib -L/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8/lib -L/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2/lib -L/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2/lib -L/nix/store/4w8f5zmwdsalc5ichgj074rawiswplw2-libarchive-3.8.0-lib/lib -L/nix/store/snkahy53v6zxppa45sbvlr0pl2846x3h-nix-2.28.5/lib -L/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8/lib -L/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2/lib -L/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2/lib -L/nix/store/4w8f5zmwdsalc5ichgj074rawiswplw2-libarchive-3.8.0-lib/lib -L/nix/store/snkahy53v6zxppa45sbvlr0pl2846x3h-nix-2.28.5/lib'
export NIX_LDFLAGS
NIX_NO_SELF_RPATH='1'
NIX_STORE='/nix/store'
@@ -58,7 +58,7 @@ OLDPWD=''
export OLDPWD
OPTERR='1'
OSTYPE='linux-gnu'
PATH='/nix/store/53cx9nd6i328f9zqsgx6sh1krsngy5jl-attr-2.5.2-bin/bin:/nix/store/61066bhvr54xkl2ssippfa5qylwgafqf-acl-2.3.2-bin/bin:/nix/store/8fq8mhb1dlwzgq7xfaxwgn0x623yjb43-libarchive-3.8.0/bin:/nix/store/7q9ll9pjrdfdb3qyfza2bzrk829izk9s-nix-2.28.4/bin:/nix/store/hr950wkqix97b759inrbxvljkqxj5113-home-manager-0-unstable-2025-05-13/bin:/nix/store/3kwbkj8xnzw5787gbannr741bczjkrq6-git-2.50.1/bin:/nix/store/s801pmgfwy4nifm72s638v0m4f32pnc5-agenix-0.15.0/bin:/nix/store/vlc65hzrqq9a29m7j0sb4hpqlwn0ny56-deploy-rs-0-unstable-2025-06-05/bin:/nix/store/dgqa38y4hxyw30g6bvrgd18750h364vr-dnscontrol-4.20.0/bin:/nix/store/g7i75czfbw9sy5f8v7rjbama6lr3ya3s-patchelf-0.15.0/bin:/nix/store/kaj8d1zcn149m40s9h0xi0khakibiphz-gcc-wrapper-14.3.0/bin:/nix/store/8adzgnxs3s0pbj22qhk9zjxi1fqmz3xv-gcc-14.3.0/bin:/nix/store/p2ixvjsas4qw58dcwk01d22skwq4fyka-glibc-2.40-66-bin/bin:/nix/store/rry6qingvsrqmc7ll7jgaqpybcbdgf5v-coreutils-9.7/bin:/nix/store/87zpmcmwvn48z4lbrfba74b312h22s6c-binutils-wrapper-2.44/bin:/nix/store/ap35np2bkwaba3rxs3qlxpma57n2awyb-binutils-2.44/bin:/nix/store/rry6qingvsrqmc7ll7jgaqpybcbdgf5v-coreutils-9.7/bin:/nix/store/392hs9nhm6wfw4imjllbvb1wil1n39qx-findutils-4.10.0/bin:/nix/store/xw0mf3shymq3k7zlncf09rm8917sdi4h-diffutils-3.12/bin:/nix/store/4rpiqv9yr2pw5094v4wc33ijkqjpm9sa-gnused-4.9/bin:/nix/store/l2wvwyg680h0v2la18hz3yiznxy2naqw-gnugrep-3.11/bin:/nix/store/c1z5j28ndxljf1ihqzag57bwpfpzms0g-gawk-5.3.2/bin:/nix/store/w60s4xh1pjg6dwbw7j0b4xzlpp88q5qg-gnutar-1.35/bin:/nix/store/xd9m9jkvrs8pbxvmkzkwviql33rd090j-gzip-1.14/bin:/nix/store/w1pxx760yidi7n9vbi5bhpii9xxl5vdj-bzip2-1.0.8-bin/bin:/nix/store/xk0d14zpm0njxzdm182dd722aqhav2cc-gnumake-4.4.1/bin:/nix/store/cfqbabpc7xwg8akbcchqbq3cai6qq2vs-bash-5.2p37/bin:/nix/store/gj54zvf7vxll1mzzmqhqi1p4jiws3mfb-patch-2.7.6/bin:/nix/store/22rpb6790f346c55iqi6s9drr5qgmyjf-xz-5.8.1-bin/bin:/nix/store/xlmpcglsq8l09qh03rf0virz0331pjdc-file-5.45/bin'
PATH='/nix/store/53cx9nd6i328f9zqsgx6sh1krsngy5jl-attr-2.5.2-bin/bin:/nix/store/61066bhvr54xkl2ssippfa5qylwgafqf-acl-2.3.2-bin/bin:/nix/store/8qrd9bfl0yr0spdbimsv6ix1gb7r8w10-libarchive-3.8.0/bin:/nix/store/snkahy53v6zxppa45sbvlr0pl2846x3h-nix-2.28.5/bin:/nix/store/1mklr29rdhl7072brp03vlra75bkyh9w-home-manager-0-unstable-2025-05-13/bin:/nix/store/v2rxk9xkcxsas64wl7ds31al15cm2wqd-git-2.50.1/bin:/nix/store/k9gakjp7zjj76f0c6prh92bc5gi5yylj-agenix-0.15.0/bin:/nix/store/yfklc5p2srylw8v0rfwziaci7fmzfxnh-deploy-rs-0-unstable-2025-06-05/bin:/nix/store/pp2ln0rw9qj8kc6g9ibqkw4n98bidnd0-dnscontrol-4.20.0/bin:/nix/store/g7i75czfbw9sy5f8v7rjbama6lr3ya3s-patchelf-0.15.0/bin:/nix/store/kaj8d1zcn149m40s9h0xi0khakibiphz-gcc-wrapper-14.3.0/bin:/nix/store/8adzgnxs3s0pbj22qhk9zjxi1fqmz3xv-gcc-14.3.0/bin:/nix/store/p2ixvjsas4qw58dcwk01d22skwq4fyka-glibc-2.40-66-bin/bin:/nix/store/rry6qingvsrqmc7ll7jgaqpybcbdgf5v-coreutils-9.7/bin:/nix/store/87zpmcmwvn48z4lbrfba74b312h22s6c-binutils-wrapper-2.44/bin:/nix/store/ap35np2bkwaba3rxs3qlxpma57n2awyb-binutils-2.44/bin:/nix/store/rry6qingvsrqmc7ll7jgaqpybcbdgf5v-coreutils-9.7/bin:/nix/store/392hs9nhm6wfw4imjllbvb1wil1n39qx-findutils-4.10.0/bin:/nix/store/xw0mf3shymq3k7zlncf09rm8917sdi4h-diffutils-3.12/bin:/nix/store/4rpiqv9yr2pw5094v4wc33ijkqjpm9sa-gnused-4.9/bin:/nix/store/l2wvwyg680h0v2la18hz3yiznxy2naqw-gnugrep-3.11/bin:/nix/store/c1z5j28ndxljf1ihqzag57bwpfpzms0g-gawk-5.3.2/bin:/nix/store/w60s4xh1pjg6dwbw7j0b4xzlpp88q5qg-gnutar-1.35/bin:/nix/store/xd9m9jkvrs8pbxvmkzkwviql33rd090j-gzip-1.14/bin:/nix/store/w1pxx760yidi7n9vbi5bhpii9xxl5vdj-bzip2-1.0.8-bin/bin:/nix/store/xk0d14zpm0njxzdm182dd722aqhav2cc-gnumake-4.4.1/bin:/nix/store/cfqbabpc7xwg8akbcchqbq3cai6qq2vs-bash-5.2p37/bin:/nix/store/gj54zvf7vxll1mzzmqhqi1p4jiws3mfb-patch-2.7.6/bin:/nix/store/22rpb6790f346c55iqi6s9drr5qgmyjf-xz-5.8.1-bin/bin:/nix/store/xlmpcglsq8l09qh03rf0virz0331pjdc-file-5.45/bin'
export PATH
PS4='+ '
RANLIB='ranlib'
@@ -75,7 +75,7 @@ STRINGS='strings'
export STRINGS
STRIP='strip'
export STRIP
XDG_DATA_DIRS='/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8/share:/nix/store/235hvgzcbl06fxy53515q8sr6lljvf68-nlohmann_json-3.11.3/share:/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2/share:/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2/share:/nix/store/8fq8mhb1dlwzgq7xfaxwgn0x623yjb43-libarchive-3.8.0/share:/nix/store/7q9ll9pjrdfdb3qyfza2bzrk829izk9s-nix-2.28.4/share:/nix/store/hr950wkqix97b759inrbxvljkqxj5113-home-manager-0-unstable-2025-05-13/share:/nix/store/3kwbkj8xnzw5787gbannr741bczjkrq6-git-2.50.1/share:/nix/store/dgqa38y4hxyw30g6bvrgd18750h364vr-dnscontrol-4.20.0/share:/nix/store/g7i75czfbw9sy5f8v7rjbama6lr3ya3s-patchelf-0.15.0/share'
XDG_DATA_DIRS='/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8/share:/nix/store/vgi5jkglabcvmhsrp8wixg1r2dhjyvva-nlohmann_json-3.11.3/share:/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2/share:/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2/share:/nix/store/8qrd9bfl0yr0spdbimsv6ix1gb7r8w10-libarchive-3.8.0/share:/nix/store/snkahy53v6zxppa45sbvlr0pl2846x3h-nix-2.28.5/share:/nix/store/1mklr29rdhl7072brp03vlra75bkyh9w-home-manager-0-unstable-2025-05-13/share:/nix/store/v2rxk9xkcxsas64wl7ds31al15cm2wqd-git-2.50.1/share:/nix/store/pp2ln0rw9qj8kc6g9ibqkw4n98bidnd0-dnscontrol-4.20.0/share:/nix/store/g7i75czfbw9sy5f8v7rjbama6lr3ya3s-patchelf-0.15.0/share'
export XDG_DATA_DIRS
__structuredAttrs=''
export __structuredAttrs
@@ -135,7 +135,7 @@ mesonFlags=''
export mesonFlags
name='nix-shell-env'
export name
nativeBuildInputs='/nix/store/8znh07lsz9q2fdp6fgcdwwv035xxfrl1-nix-2.28.4-dev /nix/store/hr950wkqix97b759inrbxvljkqxj5113-home-manager-0-unstable-2025-05-13 /nix/store/3kwbkj8xnzw5787gbannr741bczjkrq6-git-2.50.1 /nix/store/s801pmgfwy4nifm72s638v0m4f32pnc5-agenix-0.15.0 /nix/store/vlc65hzrqq9a29m7j0sb4hpqlwn0ny56-deploy-rs-0-unstable-2025-06-05 /nix/store/dgqa38y4hxyw30g6bvrgd18750h364vr-dnscontrol-4.20.0'
nativeBuildInputs='/nix/store/qrp30zrv029hzlrhpavhjl89w7sfhyih-nix-2.28.5-dev /nix/store/1mklr29rdhl7072brp03vlra75bkyh9w-home-manager-0-unstable-2025-05-13 /nix/store/v2rxk9xkcxsas64wl7ds31al15cm2wqd-git-2.50.1 /nix/store/k9gakjp7zjj76f0c6prh92bc5gi5yylj-agenix-0.15.0 /nix/store/yfklc5p2srylw8v0rfwziaci7fmzfxnh-deploy-rs-0-unstable-2025-06-05 /nix/store/pp2ln0rw9qj8kc6g9ibqkw4n98bidnd0-dnscontrol-4.20.0'
export nativeBuildInputs
out='/home/anish/usr/helm/outputs/out'
export out
@@ -156,7 +156,7 @@ phases='buildPhase'
export phases
pkg='/nix/store/kaj8d1zcn149m40s9h0xi0khakibiphz-gcc-wrapper-14.3.0'
declare -a pkgsBuildBuild=()
declare -a pkgsBuildHost=('/nix/store/8znh07lsz9q2fdp6fgcdwwv035xxfrl1-nix-2.28.4-dev' '/nix/store/qwnz3z0hf5pdhwsn92dc9lhlq4a3lsqk-boehm-gc-8.2.8-dev' '/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8' '/nix/store/235hvgzcbl06fxy53515q8sr6lljvf68-nlohmann_json-3.11.3' '/nix/store/a5b9czim7vrihag71f8dy1c467qh3mph-libarchive-3.8.0-dev' '/nix/store/0vy272ral6dwzx96wkvd90l37v0gdrk7-attr-2.5.2-dev' '/nix/store/53cx9nd6i328f9zqsgx6sh1krsngy5jl-attr-2.5.2-bin' '/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2' '/nix/store/ra69jxg2pnnjymvkn83mfr7cnhllmwnj-acl-2.3.2-dev' '/nix/store/61066bhvr54xkl2ssippfa5qylwgafqf-acl-2.3.2-bin' '/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2' '/nix/store/y130gnbp2qkfq6svqdv0s61b3m4043yp-libarchive-3.8.0-lib' '/nix/store/8fq8mhb1dlwzgq7xfaxwgn0x623yjb43-libarchive-3.8.0' '/nix/store/7q9ll9pjrdfdb3qyfza2bzrk829izk9s-nix-2.28.4' '/nix/store/hr950wkqix97b759inrbxvljkqxj5113-home-manager-0-unstable-2025-05-13' '/nix/store/3kwbkj8xnzw5787gbannr741bczjkrq6-git-2.50.1' '/nix/store/s801pmgfwy4nifm72s638v0m4f32pnc5-agenix-0.15.0' '/nix/store/vlc65hzrqq9a29m7j0sb4hpqlwn0ny56-deploy-rs-0-unstable-2025-06-05' '/nix/store/dgqa38y4hxyw30g6bvrgd18750h364vr-dnscontrol-4.20.0' '/nix/store/g7i75czfbw9sy5f8v7rjbama6lr3ya3s-patchelf-0.15.0' '/nix/store/gi6g289i9ydm3z896x67q210y0qq29zg-update-autotools-gnu-config-scripts-hook' '/nix/store/jjhw2phnaip4kg0qjas3x3fsaifi8y0w-no-broken-symlinks.sh' '/nix/store/h9lc1dpi14z7is86ffhl3ld569138595-audit-tmpdir.sh' '/nix/store/m54bmrhj6fqz8nds5zcj97w9s9bckc9v-compress-man-pages.sh' '/nix/store/wgrbkkaldkrlrni33ccvm3b6vbxzb656-make-symlinks-relative.sh' '/nix/store/5yzw0vhkyszf2d179m0qfkgxmp5wjjx4-move-docs.sh' '/nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh' '/nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh' '/nix/store/pag6l61paj1dc9sv15l7bm5c17xn5kyk-move-systemd-user-units.sh' '/nix/store/cmzya9irvxzlkh7lfy6i82gbp0saxqj3-multiple-outputs.sh' '/nix/store/hxv896faph0rqxjq2ycxpcrbnngc95sz-patch-shebangs.sh' '/nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh' '/nix/store/xyff06pkhki3qy1ls77w10s0v79c9il0-reproducible-builds.sh' '/nix/store/z7k98578dfzi6l3hsvbivzm7hfqlk0zc-set-source-date-epoch-to-latest.sh' '/nix/store/pilsssjjdxvdphlg2h19p0bfx5q0jzkn-strip.sh' '/nix/store/kaj8d1zcn149m40s9h0xi0khakibiphz-gcc-wrapper-14.3.0' '/nix/store/87zpmcmwvn48z4lbrfba74b312h22s6c-binutils-wrapper-2.44' )
declare -a pkgsBuildHost=('/nix/store/qrp30zrv029hzlrhpavhjl89w7sfhyih-nix-2.28.5-dev' '/nix/store/qwnz3z0hf5pdhwsn92dc9lhlq4a3lsqk-boehm-gc-8.2.8-dev' '/nix/store/mrbslgynzhg5jfc05x2rlnsykzcxp2v0-boehm-gc-8.2.8' '/nix/store/vgi5jkglabcvmhsrp8wixg1r2dhjyvva-nlohmann_json-3.11.3' '/nix/store/m3nkjvz6dcz1yy0j82d2ihkyxagiqxdm-libarchive-3.8.0-dev' '/nix/store/0vy272ral6dwzx96wkvd90l37v0gdrk7-attr-2.5.2-dev' '/nix/store/53cx9nd6i328f9zqsgx6sh1krsngy5jl-attr-2.5.2-bin' '/nix/store/ik62z14lxr205b5gzfh4cjcla6gh9l6z-attr-2.5.2' '/nix/store/ra69jxg2pnnjymvkn83mfr7cnhllmwnj-acl-2.3.2-dev' '/nix/store/61066bhvr54xkl2ssippfa5qylwgafqf-acl-2.3.2-bin' '/nix/store/8smmj5gbhnnqaf28qxak4xv57ccgm96p-acl-2.3.2' '/nix/store/4w8f5zmwdsalc5ichgj074rawiswplw2-libarchive-3.8.0-lib' '/nix/store/8qrd9bfl0yr0spdbimsv6ix1gb7r8w10-libarchive-3.8.0' '/nix/store/snkahy53v6zxppa45sbvlr0pl2846x3h-nix-2.28.5' '/nix/store/1mklr29rdhl7072brp03vlra75bkyh9w-home-manager-0-unstable-2025-05-13' '/nix/store/v2rxk9xkcxsas64wl7ds31al15cm2wqd-git-2.50.1' '/nix/store/k9gakjp7zjj76f0c6prh92bc5gi5yylj-agenix-0.15.0' '/nix/store/yfklc5p2srylw8v0rfwziaci7fmzfxnh-deploy-rs-0-unstable-2025-06-05' '/nix/store/pp2ln0rw9qj8kc6g9ibqkw4n98bidnd0-dnscontrol-4.20.0' '/nix/store/g7i75czfbw9sy5f8v7rjbama6lr3ya3s-patchelf-0.15.0' '/nix/store/gi6g289i9ydm3z896x67q210y0qq29zg-update-autotools-gnu-config-scripts-hook' '/nix/store/jjhw2phnaip4kg0qjas3x3fsaifi8y0w-no-broken-symlinks.sh' '/nix/store/h9lc1dpi14z7is86ffhl3ld569138595-audit-tmpdir.sh' '/nix/store/m54bmrhj6fqz8nds5zcj97w9s9bckc9v-compress-man-pages.sh' '/nix/store/wgrbkkaldkrlrni33ccvm3b6vbxzb656-make-symlinks-relative.sh' '/nix/store/5yzw0vhkyszf2d179m0qfkgxmp5wjjx4-move-docs.sh' '/nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh' '/nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh' '/nix/store/pag6l61paj1dc9sv15l7bm5c17xn5kyk-move-systemd-user-units.sh' '/nix/store/cmzya9irvxzlkh7lfy6i82gbp0saxqj3-multiple-outputs.sh' '/nix/store/hxv896faph0rqxjq2ycxpcrbnngc95sz-patch-shebangs.sh' '/nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh' '/nix/store/xyff06pkhki3qy1ls77w10s0v79c9il0-reproducible-builds.sh' '/nix/store/z7k98578dfzi6l3hsvbivzm7hfqlk0zc-set-source-date-epoch-to-latest.sh' '/nix/store/pilsssjjdxvdphlg2h19p0bfx5q0jzkn-strip.sh' '/nix/store/kaj8d1zcn149m40s9h0xi0khakibiphz-gcc-wrapper-14.3.0' '/nix/store/87zpmcmwvn48z4lbrfba74b312h22s6c-binutils-wrapper-2.44' )
declare -a pkgsBuildTarget=()
declare -a pkgsHostHost=()
declare -a pkgsHostTarget=()
+97
View File
@@ -0,0 +1,97 @@
# Helm Environment Overview
## Box NAS Server (`box` / `mossnet.lan`)
### Hardware
- NVMe boot drive (LUKS encrypted)
- 3x 4TB drives in ZFS RAIDZ1 pool (`tank`) - ~7.14TB usable
### ZFS Datasets
| Dataset | Mountpoint | Purpose |
|---------|------------|---------|
| `tank/data/media` | `/tank/media` | Media library (music, photos, tv, movies) |
| `tank/data/books` | `/tank/books` | Calibre library |
| `tank/data/podcasts` | `/tank/podcasts` | Podcast storage |
| `tank/data/new-music` | `/tank/new-music` | Incoming music from seedbox |
| `tank/data/backup` | `/tank/backup` | PostgreSQL backups |
| `tank/data/archive` | `/tank/archive` | Old data (memories, old-home-dirs, etc.) |
### Services
- **Immich** - Photo management (`/tank/media/photos`)
- **Gonic** - Music streaming (`/tank/media/music`)
- **Calibre-server/Calibre-web** - Ebook management (`/tank/books`)
- **Jellyfin** - Media streaming
- **Lidarr** - Music management (runs as `headphones:audio`)
- **Radicale** - CalDAV/CardDAV
- **Syncthing** - File sync
- **PostgreSQL** - Database
- **Taskserver** - Taskwarrior sync
---
## Repository Structure
```
helm/
├── flake.nix # Main flake - defines all hosts
├── hosts/
│ ├── box/
│ │ ├── default.nix # Box host config, imports profiles
│ │ ├── configuration.nix # Hardware/boot config
│ │ └── disko.nix # Disk/ZFS layout
│ ├── profiles/ # NixOS service profiles
│ │ ├── sync/music/ # get-music-sync service
│ │ ├── headphones/ # Lidarr config
│ │ ├── jellyfin/
│ │ ├── monitoring/
│ │ └── ...
├── home/
│ ├── dev/
│ │ └── default.nix # Home-manager config for box
│ └── profiles/
│ ├── beets/ # Beets music library config
│ ├── cli/
│ ├── nvim/
│ ├── git/
│ └── opencode/
├── secrets/ # Agenix encrypted secrets
└── modules/ # Custom NixOS modules
```
---
## Deployment
```bash
# Deploy to a host
deploy .#box
deploy .#curve
deploy .#helix
deploy .#lituus
# SSH access to box
ssh anish@mossnet.lan
```
---
## Key Users/Groups
| User | Group | Purpose |
|------|-------|---------|
| `anish` | `users`, `wheel`, `audio`, `video`, `docker` | Primary user |
| `headphones` | `audio` | Lidarr service |
| `gonic` | `audio` | Gonic music streaming |
| `immich` | `immich` | Photo management |
| `calibre-server` | `calibre-server` | Ebook server |
---
## Hosts
| Host | Description |
|------|-------------|
| `box` | NAS server (mossnet.lan) |
| `curve` | Workstation |
| `helix` | Workstation |
| `lituus` | VPS/Server |
Generated
+98 -81
View File
@@ -1,5 +1,21 @@
{
"nodes": {
"actor-typeahead-src": {
"flake": false,
"locked": {
"lastModified": 1762835797,
"narHash": "sha256-heizoWUKDdar6ymfZTnj3ytcEv/L4d4fzSmtr0HlXsQ=",
"ref": "refs/heads/main",
"rev": "677fe7f743050a4e7f09d4a6f87bbf1325a06f6b",
"revCount": 6,
"type": "git",
"url": "https://tangled.org/@jakelazaroff.com/actor-typeahead"
},
"original": {
"type": "git",
"url": "https://tangled.org/@jakelazaroff.com/actor-typeahead"
}
},
"agenix": {
"inputs": {
"darwin": "darwin",
@@ -10,11 +26,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1754433428,
"narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=",
"lastModified": 1762618334,
"narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
"owner": "ryantm",
"repo": "agenix",
"rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d",
"rev": "fcdea223397448d35d9b31f798479227e80183f6",
"type": "github"
},
"original": {
@@ -84,11 +100,11 @@
"systems": "systems_5"
},
"locked": {
"lastModified": 1763308703,
"narHash": "sha256-O9Y+Wer8wOh+N+4kcCK5p/VLrXyX+ktk0/s3HdZvJzk=",
"lastModified": 1769353768,
"narHash": "sha256-zI+7cbMI4wMIR57jMjDSEsVb3grapTnURDxxJPYFIW0=",
"owner": "numtide",
"repo": "blueprint",
"rev": "5a9bba070f801d63e2af3c9ef00b86b212429f4f",
"rev": "c7da5c70ad1c9b60b6f5d4f674fbe205d48d8f6c",
"type": "github"
},
"original": {
@@ -100,16 +116,16 @@
"brew-src": {
"flake": false,
"locked": {
"lastModified": 1758543057,
"narHash": "sha256-lw3V2jOGYphUFHYQ5oARcb6urlbNpUCLJy1qhsGdUmc=",
"lastModified": 1763638478,
"narHash": "sha256-n/IMowE9S23ovmTkKX7KhxXC2Yq41EAVFR2FBIXPcT8=",
"owner": "Homebrew",
"repo": "brew",
"rev": "5b236456eb93133c2bd0d60ef35ed63f1c0712f6",
"rev": "fbfdbaba008189499958a7aeb1e2c36ab10c067d",
"type": "github"
},
"original": {
"owner": "Homebrew",
"ref": "4.6.12",
"ref": "5.0.3",
"repo": "brew",
"type": "github"
}
@@ -143,16 +159,16 @@
]
},
"locked": {
"lastModified": 1757432263,
"narHash": "sha256-qHn+/0+IOz5cG68BZUwL9BV3EO/e9eNKCjH3+N7wMdI=",
"lastModified": 1767634391,
"narHash": "sha256-owcSz2ICqTSvhBbhPP+1eWzi88e54rRZtfCNE5E/wwg=",
"owner": "LnL7",
"repo": "nix-darwin",
"rev": "1fef4404de4d1596aa5ab2bd68078370e1b9dcdb",
"rev": "08585aacc3d6d6c280a02da195fdbd4b9cf083c2",
"type": "github"
},
"original": {
"owner": "LnL7",
"ref": "nix-darwin-25.05",
"ref": "nix-darwin-25.11",
"repo": "nix-darwin",
"type": "github"
}
@@ -166,11 +182,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1756719547,
"narHash": "sha256-N9gBKUmjwRKPxAafXEk1EGadfk2qDZPBQp4vXWPHINQ=",
"lastModified": 1766051518,
"narHash": "sha256-znKOwPXQnt3o7lDb3hdf19oDo0BLP4MfBOYiWkEHoik=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "125ae9e3ecf62fb2c0fd4f2d894eb971f1ecaed2",
"rev": "d5eff7f948535b9c723d60cd8239f8f11ddc90fa",
"type": "github"
},
"original": {
@@ -238,11 +254,11 @@
]
},
"locked": {
"lastModified": 1758287904,
"narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=",
"lastModified": 1768923567,
"narHash": "sha256-GVJ0jKsyXLuBzRMXCDY6D5J8wVdwP1DuQmmvYL/Vw/Q=",
"owner": "nix-community",
"repo": "disko",
"rev": "67ff9807dd148e704baadbd4fd783b54282ca627",
"rev": "00395d188e3594a1507f214a2f15d4ce5c07cb28",
"type": "github"
},
"original": {
@@ -458,11 +474,11 @@
"systems": "systems_6"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
@@ -503,11 +519,11 @@
]
},
"locked": {
"lastModified": 1754078208,
"narHash": "sha256-YVoIFDCDpYuU3riaDEJ3xiGdPOtsx4sR5eTzHTytPV8=",
"lastModified": 1763982521,
"narHash": "sha256-ur4QIAHwgFc0vXiaxn5No/FuZicxBr2p0gmT54xZkUQ=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "7f963246a71626c7fc70b431a315c4388a0c95cf",
"rev": "02e63a239d6eabd595db56852535992c898eba72",
"type": "github"
},
"original": {
@@ -540,11 +556,11 @@
},
"hardware": {
"locked": {
"lastModified": 1758663926,
"narHash": "sha256-6CFdj7Xs616t1W4jLDH7IohAAvl5Dyib3qEv/Uqw1rk=",
"lastModified": 1768736227,
"narHash": "sha256-qgGq7CfrYKc3IBYQ7qp0Z/ZXndQVC5Bj0N8HW9mS2rM=",
"owner": "nixos",
"repo": "nixos-hardware",
"rev": "170ff93c860b2a9868ed1e1102d4e52cb3d934e1",
"rev": "d447553bcbc6a178618d37e61648b19e744370df",
"type": "github"
},
"original": {
@@ -581,16 +597,16 @@
]
},
"locked": {
"lastModified": 1758463745,
"narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=",
"lastModified": 1768949235,
"narHash": "sha256-TtjKgXyg1lMfh374w5uxutd6Vx2P/hU81aEhTxrO2cg=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3",
"rev": "75ed713570ca17427119e7e204ab3590cc3bf2a5",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-25.05",
"ref": "release-25.11",
"repo": "home-manager",
"type": "github"
}
@@ -614,11 +630,11 @@
"homebrew-cask": {
"flake": false,
"locked": {
"lastModified": 1759110411,
"narHash": "sha256-wsvLofMB/1bkjY6OQjjWU80+AbQiPzZSLZ3cjsYpOAs=",
"lastModified": 1769058882,
"narHash": "sha256-GOSEf+DtzP/ORw+wrP1o9qZaz2XEvUOBC2j0cEEl2MY=",
"owner": "homebrew",
"repo": "homebrew-cask",
"rev": "80f95de379d69edb696dd29106b2d8b077c98896",
"rev": "022be3ce1e808c0196c540471933238fc2bf0815",
"type": "github"
},
"original": {
@@ -630,11 +646,11 @@
"homebrew-core": {
"flake": false,
"locked": {
"lastModified": 1759116320,
"narHash": "sha256-FGqC/WlIJnMkhV7l6XK6r5AqUYkwTHvHBCUjFe3DUUY=",
"lastModified": 1769064658,
"narHash": "sha256-xT3S9geUhs4jmyuuQhsyGFfv86baCXqLID8Bvtzewpo=",
"owner": "homebrew",
"repo": "homebrew-core",
"rev": "0ccf924357d3eca3268d6dafb224ad9dc4f2398a",
"rev": "eaa460777befeb0b457587e04e05991ea90826be",
"type": "github"
},
"original": {
@@ -717,11 +733,11 @@
]
},
"locked": {
"lastModified": 1762951919,
"narHash": "sha256-ma/xMEGf4J6n/RdZFdxXBJUQhP53HVEPQOC6Dp2TrkQ=",
"lastModified": 1768986040,
"narHash": "sha256-83npNk7w9yNJfSnpdZPNUjbhQwGVef3BWyBuIe6TJfk=",
"owner": "Jovian-Experiments",
"repo": "Jovian-NixOS",
"rev": "3d248f6e8f877218dd2573fef8925ac997889922",
"rev": "d75e3c96c9f935a6ccdd4a91209950289b2dc2fc",
"type": "github"
},
"original": {
@@ -737,11 +753,11 @@
"treefmt-nix": "treefmt-nix_2"
},
"locked": {
"lastModified": 1765594737,
"narHash": "sha256-9r+CxptJlqTdREkSHA1pxc3oZYnpgYNkAymkQLB0R8w=",
"lastModified": 1769482725,
"narHash": "sha256-Y4vH4PJIz4dt8SRJ5nm6yJCDzJRVEMdE5tP2TFIUfoQ=",
"owner": "numtide",
"repo": "llm-agents.nix",
"rev": "fb30f7dd63c0c7227c4b80a4dbfb6765f4b9a900",
"rev": "ae0667122f9a2336b23a4b4751997fe2f161fb37",
"type": "github"
},
"original": {
@@ -846,11 +862,11 @@
"brew-src": "brew-src"
},
"locked": {
"lastModified": 1758598228,
"narHash": "sha256-qr60maXGbZ4FX5tejPRI3nr0bnRTnZ3AbbbfO6/6jq4=",
"lastModified": 1764473698,
"narHash": "sha256-C91gPgv6udN5WuIZWNehp8qdLqlrzX6iF/YyboOj6XI=",
"owner": "zhaofengli-wip",
"repo": "nix-homebrew",
"rev": "f36e5db56e117f7df701ab152d0d2036ea85218c",
"rev": "6a8ab60bfd66154feeaa1021fc3b32684814a62a",
"type": "github"
},
"original": {
@@ -919,11 +935,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1758663926,
"narHash": "sha256-6CFdj7Xs616t1W4jLDH7IohAAvl5Dyib3qEv/Uqw1rk=",
"lastModified": 1768736227,
"narHash": "sha256-qgGq7CfrYKc3IBYQ7qp0Z/ZXndQVC5Bj0N8HW9mS2rM=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "170ff93c860b2a9868ed1e1102d4e52cb3d934e1",
"rev": "d447553bcbc6a178618d37e61648b19e744370df",
"type": "github"
},
"original": {
@@ -1017,11 +1033,11 @@
},
"nixpkgs_3": {
"locked": {
"lastModified": 1765425892,
"narHash": "sha256-jlQpSkg2sK6IJVzTQBDyRxQZgKADC2HKMRfGCSgNMHo=",
"lastModified": 1769421245,
"narHash": "sha256-m5QLKjpdhbDrhyrUbEm5Haq3lqE5Z6xh2tab5vTHUTo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5d6bdbddb4695a62f0d00a3620b37a15275a5093",
"rev": "5b265bda51b42a2a85af0a543c3e57b778b01b7d",
"type": "github"
},
"original": {
@@ -1049,27 +1065,27 @@
},
"nixpkgs_5": {
"locked": {
"lastModified": 1758791193,
"narHash": "sha256-F8WmEwFoHsnix7rt290R0rFXNJiMbClMZyIC/e+HYf0=",
"lastModified": 1768940263,
"narHash": "sha256-sJERJIYTKPFXkoz/gBaBtRKke82h4DkX3BBSsKbfbvI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "25e53aa156d47bad5082ff7618f5feb1f5e02d01",
"rev": "3ceaaa8bc963ced4d830e06ea2d0863b6490ff03",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-25.05",
"ref": "nixos-25.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_6": {
"locked": {
"lastModified": 1758690382,
"narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=",
"lastModified": 1768886240,
"narHash": "sha256-C2TjvwYZ2VDxYWeqvvJ5XPPp6U7H66zeJlRaErJKoEM=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "e643668fd71b949c53f8626614b21ff71a07379d",
"rev": "80e4adbcf8992d3fd27ad4964fbb84907f9478b0",
"type": "github"
},
"original": {
@@ -1085,11 +1101,11 @@
"nixpkgs": "nixpkgs_6"
},
"locked": {
"lastModified": 1759117007,
"narHash": "sha256-DSnkPMhK2Eg0XLiyjEPVtIpdcmWmYsBMhVGCN1144SA=",
"lastModified": 1769056321,
"narHash": "sha256-BR4ACqZEfFivkJutgeZeG8Sip/LlvmQgBbkT9eKZeIQ=",
"owner": "nix-community",
"repo": "NUR",
"rev": "fccc09dffa659dc1410eceb33285831ba12bc7f6",
"rev": "6dd879dc2cb51262567d8b2b49b2d24f256fa343",
"type": "github"
},
"original": {
@@ -1105,11 +1121,11 @@
]
},
"locked": {
"lastModified": 1762711246,
"narHash": "sha256-coOLG/Bp118d1T3DBIZUcW+AdiKsHz9uh6ZuiR30GBM=",
"lastModified": 1759014010,
"narHash": "sha256-NMpUufnxiGDTs/4Nxj8t+n4wc4aSs02a4T5OORo0gBQ=",
"ref": "main",
"rev": "54287446e1a8a1bc40ad1b12061f053181e6d264",
"revCount": 1614,
"rev": "08c1dddf38c39d6f7c73a24f4d396f4c925185bf",
"revCount": 1602,
"type": "git",
"url": "ssh://gitea@git.sealight.xyz/aynish/kitaab"
},
@@ -1202,11 +1218,11 @@
]
},
"locked": {
"lastModified": 1759113356,
"narHash": "sha256-xm4kEUcV2jk6u15aHazFP4YsMwhq+PczA+Ul/4FDKWI=",
"lastModified": 1769050281,
"narHash": "sha256-1H8DN4UZgEUqPUA5ecHOufLZMscJ4IlcGaEftaPtpBY=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "be3b8843a2be2411500f6c052876119485e957a2",
"rev": "6deef0585c52d9e70f96b6121207e1496d4b0c49",
"type": "github"
},
"original": {
@@ -1336,6 +1352,7 @@
},
"tangled": {
"inputs": {
"actor-typeahead-src": "actor-typeahead-src",
"flake-compat": "flake-compat_4",
"gomod2nix": "gomod2nix",
"htmx-src": "htmx-src",
@@ -1350,11 +1367,11 @@
"sqlite-lib-src": "sqlite-lib-src"
},
"locked": {
"lastModified": 1759559279,
"narHash": "sha256-gA0mh9Fx2uou2v75RMA6qUvWB3Z74Asc6pRjiojwaRo=",
"lastModified": 1769064660,
"narHash": "sha256-2ccXZ51txbX1jAhW52Z6QuSFAgFqo3Gr1bqxD4jXNw0=",
"ref": "refs/heads/master",
"rev": "5ecd54b31547ac169a3b15d6034a67179f22aa33",
"revCount": 1486,
"rev": "2b94ee226637e13c106d7782ca852bd608530b51",
"revCount": 1865,
"type": "git",
"url": "https://tangled.org/@tangled.org/core"
},
@@ -1431,11 +1448,11 @@
]
},
"locked": {
"lastModified": 1762938485,
"narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=",
"lastModified": 1769353635,
"narHash": "sha256-J0G1ACrUK29M0THPAsz429eZX07GmR9Bs/b0pB3N0dQ=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
"rev": "f46bb205f239b415309f58166f8df6919fa88377",
"type": "github"
},
"original": {
@@ -1446,11 +1463,11 @@
},
"unstable": {
"locked": {
"lastModified": 1762844143,
"narHash": "sha256-SlybxLZ1/e4T2lb1czEtWVzDCVSTvk9WLwGhmxFmBxI=",
"lastModified": 1768886240,
"narHash": "sha256-C2TjvwYZ2VDxYWeqvvJ5XPPp6U7H66zeJlRaErJKoEM=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4",
"rev": "80e4adbcf8992d3fd27ad4964fbb84907f9478b0",
"type": "github"
},
"original": {
+93 -49
View File
@@ -8,7 +8,7 @@
inputs = {
# Nixpkgs
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
unstable.url = "github:nixos/nixpkgs/nixos-unstable";
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
@@ -16,7 +16,7 @@
# ngipkgs-local.url = "path:/home/anish/usr/ngipkgs";
# Home manager
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.url = "github:nix-community/home-manager/release-25.11";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
hardware.url = "github:nixos/nixos-hardware";
@@ -32,8 +32,7 @@
poonam.url = "git+ssh://gitea@git.sealight.xyz/aynish/kitaab?ref=main";
poonam.inputs.nixpkgs.follows = "nixpkgs";
basant.url = "git+ssh://gitea@git.sealight.xyz/aynish/basant?ref=main";
vimwikicli.url =
"git+ssh://gitea@git.sealight.xyz/aynish/vimwiki-cli?ref=main";
vimwikicli.url = "git+ssh://gitea@git.sealight.xyz/aynish/vimwiki-cli?ref=main";
basant.inputs.nixpkgs.follows = "nixpkgs";
basant.inputs.poonam.follows = "poonam";
vimwikicli.inputs.nixpkgs.follows = "nixpkgs";
@@ -45,7 +44,7 @@
# Darwin
darwin = {
url = "github:LnL7/nix-darwin/nix-darwin-25.05";
url = "github:LnL7/nix-darwin/nix-darwin-25.11";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-homebrew = {
@@ -76,7 +75,6 @@
inputs.nixpkgs.follows = "nixpkgs";
};
# LLM Agents
llm-agents.url = "github:numtide/llm-agents.nix";
# Others
@@ -100,10 +98,34 @@
# muneem.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, unstable, nixos-hardware, home-manager, deploy-rs
, agenix, disko, basant, grasp, nix-matrix-appservices, nur, tidalcycles
, rust-overlay, vimwikicli, autohide-tdrop, darwin, nix-homebrew, homebrew-bundle
, homebrew-core, homebrew-cask, jovian, tangled, llm-agents, ... }@inputs:
outputs =
{
self,
nixpkgs,
unstable,
nixos-hardware,
home-manager,
deploy-rs,
agenix,
disko,
basant,
grasp,
nix-matrix-appservices,
nur,
tidalcycles,
rust-overlay,
vimwikicli,
autohide-tdrop,
darwin,
nix-homebrew,
homebrew-bundle,
homebrew-core,
homebrew-cask,
jovian,
tangled,
llm-agents,
...
}@inputs:
let
forAllSystems = nixpkgs.lib.genAttrs [
"aarch64-linux"
@@ -122,37 +144,42 @@
autohide-tdrop = autohide-tdrop.packages.${prev.system}.default;
};
nixpkgsFor = forAllSystems (system:
nixpkgsFor = forAllSystems (
system:
import nixpkgs {
inherit system;
config = {
permittedInsecurePackages = [
"olm-3.2.16"
"olm-3.2.16"
];
allowUnfreePredicate = pkg:
allowUnfreePredicate =
pkg:
builtins.elem (nixpkgs.lib.getName pkg) [
"ripcord"
"vcv-rack"
"SunVox"
"renoise"
"bitwig-studio-unwrapped"
"via" # QMK keyboard configurator
];
};
overlays = [
rust-overlay.overlays.default
tidalcycles.overlays.default
agenix.overlays.default
nur.overlay
nur.overlays.default
# nix-matrix-appservices.overlay # nixpkgs has these packages and newer ones at that
unstableOverlay
vimwikiOverlay
self.overlays.additions
self.overlays.modifications
];
});
}
);
# for when space matters
litePkgsFor = forAllSystems (system:
litePkgsFor = forAllSystems (
system:
import nixpkgs {
inherit system;
# config.permittedInsecurePackages = [
@@ -166,17 +193,20 @@
self.overlays.modifications
tidalcycles.overlays.default # needed for nvim which comes pre-installed lol
];
});
}
);
# Package set for Darwin systems
darwinPkgsFor = forAllSystems (system:
# Package set for Darwin systems
darwinPkgsFor = forAllSystems (
system:
import nixpkgs {
inherit system;
config = {
permittedInsecurePackages = [
"olm-3.2.16"
"olm-3.2.16"
];
allowUnfreePredicate = pkg:
allowUnfreePredicate =
pkg:
builtins.elem (nixpkgs.lib.getName pkg) [
"ripcord"
"vcv-rack"
@@ -188,23 +218,26 @@
rust-overlay.overlays.default
tidalcycles.overlays.default
agenix.overlays.default
nur.overlay
nur.overlays.default
unstableOverlay
vimwikiOverlay
self.overlays.additions
self.overlays.modifications
];
});
}
);
# Package set for Steam Deck (gaming-focused)
deckPkgsFor = forAllSystems (system:
deckPkgsFor = forAllSystems (
system:
import unstable {
inherit system;
config = {
permittedInsecurePackages = [
"olm-3.2.16"
"olm-3.2.16"
];
allowUnfreePredicate = pkg:
allowUnfreePredicate =
pkg:
builtins.elem (nixpkgs.lib.getName pkg) [
"ripcord"
"vcv-rack"
@@ -221,24 +254,34 @@
rust-overlay.overlays.default
tidalcycles.overlays.default
agenix.overlays.default
nur.overlay
nur.overlays.default
unstableOverlay
vimwikiOverlay
self.overlays.additions
self.overlays.modifications
];
});
in {
}
);
in
{
# Your custom packages
# Acessible through 'nix build', 'nix shell', etc
packages = forAllSystems (system:
let pkgs = nixpkgsFor.${system};
in import ./pkgs { pkgs = pkgs; });
packages = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
in
import ./pkgs { pkgs = pkgs; }
);
# Devshell for bootstrapping
# Acessible through 'nix develop' or 'nix-shell' (legacy)
devShells = forAllSystems (system:
let pkgs = nixpkgsFor.${system};
in import ./shell.nix { pkgs = pkgs; });
devShells = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
in
import ./shell.nix { pkgs = pkgs; }
);
# Your custom packages and modifications, exported as overlays
overlays = import ./overlays;
@@ -283,7 +326,8 @@
agenix.nixosModules.age
self.nixosModules.backup
self.nixosModules.wireguard
basant.nixosModule
# TODO: basant needs pyproject update for 25.11 - re-enable after fixing
# basant.nixosModule
# self.nixosModules.microbin
disko.nixosModules.disko
{
@@ -318,6 +362,7 @@
pkgs = nixpkgsFor.${system};
modules = [
./hosts/box
disko.nixosModules.disko
agenix.nixosModules.age
self.nixosModules.backup
self.nixosModules.wireguard
@@ -325,7 +370,7 @@
self.nixosModules.gpodder2go
self.nixosModules.wallabag
self.nixosModules.ulogger-server
grasp.nixosModule
# grasp.nixosModule # Disabled for initial install - private repo
home-manager.nixosModules.home-manager
{
nix.registry.nixpkgs.flake = nixpkgs;
@@ -359,7 +404,7 @@
#};
};
# Darwin configuration entrypoint
# Darwin configuration entrypoint
darwinConfigurations = {
"Anishs-MacBook-Pro" = darwin.lib.darwinSystem rec {
system = "aarch64-darwin";
@@ -386,10 +431,12 @@
# Available through 'home-manager --flake .#your-username@your-hostname'
homeConfigurations = {
"anish@work" = home-manager.lib.homeManagerConfiguration {
pkgs =
nixpkgsFor."x86_64-linux"; # Home-manager requires 'pkgs' instance
pkgs = nixpkgsFor."x86_64-linux"; # Home-manager requires 'pkgs' instance
extraSpecialArgs = { inherit inputs; };
modules = [ ./home/core.nix ./home/profiles/firefox ];
modules = [
./home/core.nix
./home/profiles/firefox
];
};
};
@@ -401,8 +448,7 @@
remoteBuild = true;
profiles.system = {
user = "root";
path = deploy-rs.lib.x86_64-linux.activate.nixos
self.nixosConfigurations.box;
path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.box;
};
};
lituus = {
@@ -411,8 +457,7 @@
remoteBuild = true;
profiles.system = {
user = "root";
path = deploy-rs.lib.x86_64-linux.activate.nixos
self.nixosConfigurations.lituus;
path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.lituus;
};
};
helix = {
@@ -421,13 +466,12 @@
magicRollback = false;
profiles.system = {
user = "root";
path = deploy-rs.lib.x86_64-linux.activate.nixos
self.nixosConfigurations.helix;
path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.helix;
};
};
};
# checks = builtins.mapAttrs
# (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
# checks = builtins.mapAttrs
# (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
};
}
+15 -3
View File
@@ -1,5 +1,17 @@
{ self, pkgs, inputs, ... }: {
imports =
[ ../profiles/cli ../profiles/nvim ../profiles/direnv ../profiles/git ../profiles/opencode ];
{
self,
pkgs,
inputs,
...
}:
{
imports = [
../profiles/cli
../profiles/nvim
../profiles/direnv
../profiles/git
../profiles/opencode
../profiles/beets
];
home.stateVersion = "22.05";
}
+10 -10
View File
@@ -14,15 +14,15 @@
];
# GPG configuration for user session
services.gpg-agent = {
enable = true;
pinentryPackage = pkgs.pinentry-curses;
enableSshSupport = true;
defaultCacheTtl = 28800; # 8 hours
maxCacheTtl = 86400; # 24 hours
};
#services.gpg-agent = {
# enable = true;
# pinentryPackage = pkgs.pinentry-curses;
# enableSshSupport = true;
# defaultCacheTtl = 28800; # 8 hours
# maxCacheTtl = 86400; # 24 hours
#};
programs.gpg = {
enable = true;
};
#programs.gpg = {
# enable = true;
#};
}
+47
View File
@@ -0,0 +1,47 @@
{ pkgs, ... }:
{
programs.beets = {
enable = true;
# In 25.11, beets plugins are enabled via beetsPackages or the default package
# The default beets package includes common plugins
package = pkgs.beets;
settings = {
directory = "/tank/media/music";
library = "/home/anish/.local/share/beets/library.db";
import = {
move = true; # Move files from new-music to library
write = true; # Write tags to files
log = "/tank/new-music/beets-import.log";
incremental = true; # Skip already-imported directories
};
# Path format for organizing music
paths = {
default = "$albumartist/$album%aunique{}/$track $title";
singleton = "Non-Album/$artist/$title";
comp = "Compilations/$album%aunique{}/$track $title";
};
plugins = [
"fetchart"
"embedart"
"lastgenre"
"duplicates"
"missing"
];
fetchart = {
auto = true;
};
embedart = {
auto = true;
};
lastgenre = {
auto = true;
};
};
};
}
+156 -148
View File
@@ -1,158 +1,167 @@
{ lib, pkgs, config, ... }:
{
home.packages = with pkgs; [
binutils
coreutils
dnsutils
dasht
dosfstools
#git
git-machete
bottom
gptfdisk
difftastic
starship
jq
manix
moreutils
nix-index
cached-nix-shell
nmap
ripgrep
skim
tealdeer
usbutils
utillinux
whois
iftop
wget
curl
eza
bat
fd
ncdu
dust
# dia-cli
duf
trash-cli
nix-index
silver-searcher
tcpdump
mtr
file
lsof
atool
zip
unzip
rsync
tmux
pwgen
glow
pass
less
gdb
xxd
taskwarrior2
gnupg
syncthing
dijo
nixfmt-rfc-style
nix-tree
#ssb-patchwork
fontconfig
pandoc
taskwarrior-tui
# vimwiki-cli
zk
lib,
pkgs,
config,
...
}:
{
home.packages =
with pkgs;
[
binutils
coreutils
dnsutils
dasht
dosfstools
#git
git-machete
bottom
gptfdisk
difftastic
starship
jq
manix
moreutils
nix-index
cached-nix-shell
nmap
ripgrep
skim
tealdeer
usbutils
utillinux
whois
iftop
wget
curl
eza
bat
fd
ncdu
dust
# dia-cli
duf
trash-cli
nix-index
silver-searcher
tcpdump
mtr
file
lsof
atool
zip
unzip
rsync
tmux
pwgen
glow
pass
less
gdb
xxd
taskwarrior2
gnupg
syncthing
dijo
nixfmt-rfc-style
nix-tree
#ssb-patchwork
fontconfig
pandoc
taskwarrior-tui
# vimwiki-cli
zk
radicle-node # rad CLI for interacting with Radicle repos
(pkgs.writeScriptBin "jq-repl" ''
#!/usr/bin/env bash
if [[ -z $1 ]] || [[ $1 == "-" ]]; then
input=$(mktemp)
trap "rm -f $input" EXIT
cat /dev/stdin > $input
else
input=$1
fi
(pkgs.writeScriptBin "jq-repl" ''
#!/usr/bin/env bash
if [[ -z $1 ]] || [[ $1 == "-" ]]; then
input=$(mktemp)
trap "rm -f $input" EXIT
cat /dev/stdin > $input
else
input=$1
fi
echo "" \ | fzf --phony --preview-window="up:90%" --print-query --preview "jq --color-output -r {q} $input"
'')
(pkgs.writeScriptBin "clear-vim-trash" (builtins.readFile ./bin/clear-vim-trash.sh))
(pkgs.writeScriptBin "flakify" ''
#!/usr/bin/env zsh
if [ ! -e flake.nix ]; then
nix flake new -t github:nix-community/nix-direnv .
elif [ ! -e .envrc ]; then
echo "use flake" > .envrc
direnv allow
fi
vim flake.nix
'')
(pkgs.writeScriptBin "mx" ''
#!/usr/bin/env bash
manix "" | grep '^# ' | sed 's/^# \(.*\) (.*/\1/;s/ (.*//;s/^# //' | fzf --preview="manix '{}'" | xargs manix
'')
(pkgs.writeScriptBin "monitor" ''
connect() {
# Turn it on if it was off
xrandr --output HDMI-2 --auto
xrandr --output HDMI-2 --same-as eDP-1
xrandr --output eDP-1 --off
pkill -9 polybar
feh --bg-scale ~/Downloads/stephen-walker-onIXxjH56AA-unsplash.jpg
polybar mybar > $XDG_DATA_HOME/polybar.log 2>&1 &
}
echo "" \ | fzf --phony --preview-window="up:90%" --print-query --preview "jq --color-output -r {q} $input"
'')
(pkgs.writeScriptBin "clear-vim-trash" (builtins.readFile ./bin/clear-vim-trash.sh))
(pkgs.writeScriptBin "flakify" ''
#!/usr/bin/env zsh
if [ ! -e flake.nix ]; then
nix flake new -t github:nix-community/nix-direnv .
elif [ ! -e .envrc ]; then
echo "use flake" > .envrc
direnv allow
fi
vim flake.nix
'')
(pkgs.writeScriptBin "mx" ''
#!/usr/bin/env bash
manix "" | grep '^# ' | sed 's/^# \(.*\) (.*/\1/;s/ (.*//;s/^# //' | fzf --preview="manix '{}'" | xargs manix
'')
(pkgs.writeScriptBin "monitor" ''
connect() {
# Turn it on if it was off
xrandr --output HDMI-2 --auto
xrandr --output HDMI-2 --same-as eDP-1
xrandr --output eDP-1 --off
pkill -9 polybar
feh --bg-scale ~/Downloads/stephen-walker-onIXxjH56AA-unsplash.jpg
polybar mybar > $XDG_DATA_HOME/polybar.log 2>&1 &
}
disconnect() {
xrandr --output HDMI-2 --off
xrandr --output eDP-1 --auto
}
disconnect() {
xrandr --output HDMI-2 --off
xrandr --output eDP-1 --auto
}
xrandr | grep "HDMI-2 connected" &>>/dev/null && connect || disconnect
'')
(pkgs.writeScriptBin "big-monitor" ''
connect() {
# Turn it on if it was off
xrandr --output HDMI-2 --auto --primary
# Disable normal display
xrandr --output eDP-1 --off
# Use a nice background
feh --bg-scale ~/Downloads/stephen-walker-onIXxjH56AA-unsplash.jpg
# Reload Polybar
~/.config/bspwm/rc.d/polybar
}
xrandr | grep "HDMI-2 connected" &>>/dev/null && connect || disconnect
'')
(pkgs.writeScriptBin "big-monitor" ''
connect() {
# Turn it on if it was off
xrandr --output HDMI-2 --auto --primary
# Disable normal display
xrandr --output eDP-1 --off
# Use a nice background
feh --bg-scale ~/Downloads/stephen-walker-onIXxjH56AA-unsplash.jpg
# Reload Polybar
~/.config/bspwm/rc.d/polybar
}
disconnect() {
xrandr --output HDMI-2 --off
}
disconnect() {
xrandr --output HDMI-2 --off
}
xrandr | grep "HDMI-2 connected" &>>/dev/null && connect || disconnect
'')
(pkgs.writeScriptBin "disconnect-keyboard" ''
# keyboard on curve is busted
get_keyboard_id() {
xinput list | grep 'AT Translated Set' | cut -f2 | cut -d'=' -f2 | xinput float
}
xrandr | grep "HDMI-2 connected" &>>/dev/null && connect || disconnect
'')
(pkgs.writeScriptBin "disconnect-keyboard" ''
# keyboard on curve is busted
get_keyboard_id() {
xinput list | grep 'AT Translated Set' | cut -f2 | cut -d'=' -f2 | xinput float
}
disconnect_keyboard() {
id=$(get_keyboard_id)
xinput float $id
unset id
}
disconnect_keyboard() {
id=$(get_keyboard_id)
xinput float $id
unset id
}
attach_keyboard() {
id=$(get_keyboard_id)
xinput reattach $id 3
unset id
}
attach_keyboard() {
id=$(get_keyboard_id)
xinput reattach $id 3
unset id
}
disconnect_keyboard
'')
] ++ lib.optionals pkgs.stdenv.isLinux [
# Linux-only packages
iputils
strace
];
disconnect_keyboard
'')
]
++ lib.optionals pkgs.stdenv.isLinux [
# Linux-only packages
iputils
strace
];
programs.zsh = {
enable = true;
@@ -246,7 +255,7 @@
yt = "ytfzf -T kitty -t ";
gen-secret = "< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c\${1:-32};echo;";
# modern cli tools
# modern cli tools
ls = "eza --icons";
l = "esa -l --icons";
la = "eza -la --icons";
@@ -255,12 +264,11 @@
unzip = "aunpack";
copy = if pkgs.stdenv.isDarwin then "pbcopy" else "xclip -selection clipboard";
paste = if pkgs.stdenv.isDarwin then "pbpaste" else "xclip -selection clipboard -o";
rm = "echo USE TRASH, FOOL: trash ";
trash = "trash-put";
make-secret = "< /dev/urandom \\tr -dc _A-Za-z0-9 | head -c \${1:-32};echo;";
# task warrior
t = "task -BLOCKED -idea -backlog";
t = "task -BLOCKED -idea -backlog";
tw = "t rc.context:work";
# TODO find a reasonable way to manage this from a non-nix managed file in ~/.task/context or something
# we can do something like task rc.context:$(cat ~/.task/context) to read context
+1
View File
@@ -34,6 +34,7 @@ in
# libsForQt5.kontact
thunderbird
libsecret # For secret-tool to manage keyring
blender
];
# GTK4 color scheme?
+1 -2
View File
@@ -11,6 +11,5 @@ enable_audio_bell no
# Ctrl+V for paste
map ctrl+v paste_from_clipboard
# Ctrl+V handled by neovim for insert mode paste (allows visual block mode in normal mode)
mouse_map middle release ungrabbed paste_from_clipboard
+48 -41
View File
@@ -12,11 +12,14 @@
unstable.git-spice
];
# Delta (git diff pager) - moved to top-level in home-manager 25.11
programs.delta = {
enable = true;
enableGitIntegration = true;
};
programs.git = {
enable = true;
userName = "Anish Lakhwara";
userEmail = "anish+git@lakhwara.com";
delta.enable = true;
signing = {
signByDefault = if pkgs.stdenv.isLinux then false else true;
key = if pkgs.stdenv.isLinux then "B8492C8FB53397B7" else "7FC5DF072EF7B716";
@@ -60,51 +63,55 @@
"node_modules/"
];
extraConfig = {
# 25.11: extraConfig, userName, userEmail, aliases moved under settings
settings = {
user = {
name = "Anish Lakhwara";
email = "anish+git@lakhwara.com";
};
pull.rebase = false;
push.autoSetupRemote = true;
init.defaultBranch = "main";
"url \"git@github.com:\"" = { insteadOf = "https://github.com/"; };
};
"url \"git@github.com:\"" = {
insteadOf = "https://github.com/";
};
aliases = {
a = "add -p";
co = "checkout";
cob = "checkout -b";
f = "fetch -p";
c = "commit -v";
p = "push";
ba = "branch -a";
bd = "branch -d";
bD = "branch -D";
d = "diff";
dc = "diff --cached";
ds = "diff --staged";
r = "restore";
rs = "restore --staged";
st = "status -sb";
alias = {
a = "add -p";
co = "checkout";
cob = "checkout -b";
f = "fetch -p";
c = "commit -v";
p = "push";
ba = "branch -a";
bd = "branch -d";
bD = "branch -D";
d = "diff";
dc = "diff --cached";
ds = "diff --staged";
r = "restore";
rs = "restore --staged";
st = "status -sb";
# reset
soft = "reset --soft";
hard = "reset --hard";
s1ft = "soft HEAD~1";
h1rd = "hard HEAD~1";
# reset
soft = "reset --soft";
hard = "reset --hard";
s1ft = "soft HEAD~1";
h1rd = "hard HEAD~1";
# logging
lg =
"log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
plog =
"log --graph --pretty='format:%C(red)%d%C(reset) %C(yellow)%h%C(reset) %ar %C(green)%aN%C(reset) %s'";
tlog =
"log --stat --since='1 Day Ago' --graph --pretty=oneline --abbrev-commit --date=relative";
rank = "shortlog -sn --no-merges";
authors = "authors | sort | uniq -c | sort -n";
ls = "log --graph --abbrev-commit --decorate --color=always --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) - %C(dim red)%an%C(reset)%C(bold yellow)%d%C(reset)' --all";
# logging
lg = "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
plog = "log --graph --pretty='format:%C(red)%d%C(reset) %C(yellow)%h%C(reset) %ar %C(green)%aN%C(reset) %s'";
tlog = "log --stat --since='1 Day Ago' --graph --pretty=oneline --abbrev-commit --date=relative";
rank = "shortlog -sn --no-merges";
authors = "authors | sort | uniq -c | sort -n";
ls = "log --graph --abbrev-commit --decorate --color=always --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) - %C(dim red)%an%C(reset)%C(bold yellow)%d%C(reset)' --all";
# delete merged branches
bdm = "!git branch --merged | grep -v '*' | xargs -n 1 git branch -d";
undo = "!git reset HEAD~1 --mixed";
blm = "blame -w -C -C -C";
# delete merged branches
bdm = "!git branch --merged | grep -v '*' | xargs -n 1 git branch -d";
undo = "!git reset HEAD~1 --mixed";
blm = "blame -w -C -C -C";
};
};
};
}
+187 -110
View File
@@ -1,4 +1,9 @@
{ pkgs, lib, config, ... }:
{
pkgs,
lib,
config,
...
}:
let
customPlugins = {
vim-zettel = pkgs.vimUtils.buildVimPlugin {
@@ -90,6 +95,17 @@ let
sha256 = "czKjJgCpvRSdtR7rNGlJrluDgPIdx94KUyx33op5gdY=";
};
};
opencode-nvim = pkgs.vimUtils.buildVimPlugin {
pname = "opencode.nvim";
version = "2024-12-24";
src = pkgs.fetchFromGitHub {
owner = "NickvanDyke";
repo = "opencode.nvim";
rev = "dfca5bb214d78a600781d50da350238b3e6e2621";
hash = "sha256-W7fPGiLpKRe1Nw0MckigUijTNq+L9Z+vxOKcf3oNZf0=";
};
doCheck = false;
};
gh-addressed = pkgs.vimUtils.buildVimPlugin {
pname = "gh-addressed";
version = "2024-09-17";
@@ -105,12 +121,13 @@ let
};
};
my-python-packages = python-packages: with python-packages; [
tasklib
pynvim
six
# other python packages you want
];
my-python-packages =
python-packages: with python-packages; [
tasklib
pynvim
six
# other python packages you want
];
python-with-my-packages = pkgs.python3.withPackages my-python-packages;
in
{
@@ -135,7 +152,8 @@ in
'';
# Private mode plugin for concealing buffer content (out of store symlink for live editing)
home.file.".config/nvim/lua/private-mode.lua".source = config.lib.file.mkOutOfStoreSymlink "${toString ./.}/private-mode.lua";
home.file.".config/nvim/lua/private-mode.lua".source =
config.lib.file.mkOutOfStoreSymlink "${toString ./.}/private-mode.lua";
#environment.systemPackages = with customPlugins; [ tidal ];
programs.neovim = {
@@ -472,10 +490,10 @@ in
vim.api.nvim_set_keymap('n', '<leader>vt', ':call v:lua.toggle_diagnostics()<CR>', {noremap = true, silent = true})
-- nicer diff view
vim.opt.diffopt = {'internal', 'filler', 'closeoff', 'algorithm:patience', 'indent-heuristic'}
-- autopairs
require('nvim-autopairs').setup{}
@@ -566,16 +584,16 @@ in
Function = "ƒ "
}
}
-- Setup neo-tree
require("neo-tree").setup {}
-- Setup outline
require("outline").setup {}
-- Setup trouble
require("trouble").setup {}
-- Setup noice for floating command palette and notifications
require("noice").setup({
cmdline = {
@@ -625,7 +643,7 @@ in
},
},
})
-- Setup barbar (tabline with icons)
require'barbar'.setup {
icons = {
@@ -635,7 +653,7 @@ in
},
}
local navic = require("nvim-navic")
-- Setup conform.nvim for formatting
require("conform").setup({
formatters_by_ft = {
@@ -709,7 +727,7 @@ in
}
}
local servers = { 'clojure_lsp', 'terraform_lsp', 'zls', 'pyright', 'rust_analyzer', 'ts_ls', 'lua_ls', 'nil_ls', 'gopls', 'bashls'}
local servers = { 'clojure_lsp', 'terraform_lsp', 'zls', 'pyright', 'rust_analyzer', 'ts_ls', 'lua_ls', 'gopls', 'bashls'}
for _, lsp in ipairs(servers) do
lspconfig[lsp].setup {
on_attach = function(client, bufnr)
@@ -719,6 +737,23 @@ in
}
end
-- nil_ls needs custom settings to disable autoArchive prompt
lspconfig['nil_ls'].setup {
on_attach = function(client, bufnr)
navic.attach(client, bufnr)
end,
capabilities = capabilities,
settings = {
['nil'] = {
nix = {
flake = {
autoArchive = false,
},
},
},
},
}
-- fennel-ls doesn't support navic
lspconfig['fennel-ls'].setup {
on_attach = function(client, bufnr)
@@ -852,7 +887,7 @@ in
require("which-key").setup{}
require('leap').set_default_keymaps()
-- supercollider
local scnvim = require 'scnvim'
local map = scnvim.map
@@ -997,14 +1032,14 @@ in
disable_on_zoom = true,
mux = 'auto', -- auto-detect tmux
}
-- Set up Navigator.nvim keybindings
vim.keymap.set({'n', 't'}, '<M-h>', '<CMD>NavigatorLeft<CR>')
vim.keymap.set({'n', 't'}, '<M-j>', '<CMD>NavigatorDown<CR>')
vim.keymap.set({'n', 't'}, '<M-k>', '<CMD>NavigatorUp<CR>')
vim.keymap.set({'n', 't'}, '<M-l>', '<CMD>NavigatorRight<CR>')
-- Paste from system clipboard in insert mode (handles tmux/kitty better)
-- Paste from system clipboard in insert mode (Ctrl+V in normal mode remains visual block)
vim.keymap.set('i', '<C-v>', '<C-r><C-p>+', {noremap = true, silent = true})
-- Pane resizing with Alt+Shift+hjkl (to match tmux)
@@ -1013,6 +1048,22 @@ in
vim.keymap.set('n', '<M-S-k>', '<Cmd>resize +2<CR>', {silent = true})
vim.keymap.set('n', '<M-S-l>', '<Cmd>vertical resize +2<CR>', {silent = true})
-- opencode.nvim setup with tmux provider
vim.g.opencode_opts = {
provider = {
enabled = "tmux",
tmux = {
-- default tmux provider settings work well
},
},
}
-- opencode.nvim keybindings
vim.keymap.set({ "n", "x" }, "<leader>oa", function() require("opencode").ask("@this: ") end, { desc = "Ask opencode" })
vim.keymap.set({ "n", "x" }, "<leader>os", function() require("opencode").select() end, { desc = "Select opencode action" })
vim.keymap.set({ "n", "t" }, "<leader>oo", function() require("opencode").toggle() end, { desc = "Toggle opencode" })
vim.keymap.set({ "n", "x" }, "<leader>op", function() return require("opencode").operator("@this ") end, { expr = true, desc = "Add range to opencode" })
-- Kitaab recent files (only date-based files, sorted reverse)
function KitaabRecent()
local pickers = require('telescope.pickers')
@@ -1086,103 +1137,129 @@ in
zk
];
plugins = with pkgs.vimPlugins // customPlugins; [
# ui
lualine-nvim
fzf-vim
neo-tree-nvim
outline-nvim
noice-nvim
nui-nvim
trouble-nvim
neovim-ayu
rainbow_parentheses-vim
vim-surround
vim-devicons
nvim-web-devicons
undotree
telescope-nvim
plenary-nvim
nvim-navic
(nvim-treesitter.withPlugins (p: [ p.nix p.clojure p.python p.fennel p.lua p.html p.css p.regex p.supercollider p.beancount p.markdown p.glsl p.yaml p.toml p.dockerfile p.json ]))
nvim-treesitter-context
my-fterm
barbar-nvim
auto-session
my-marks
which-key-nvim
nvim-peekup
zen-mode-nvim
twilight-nvim
my-lspsaga
vim-dasht
plugins =
with pkgs.vimPlugins // customPlugins;
[
# ui
lualine-nvim
fzf-vim
neo-tree-nvim
outline-nvim
noice-nvim
nui-nvim
trouble-nvim
neovim-ayu
rainbow_parentheses-vim
vim-surround
vim-devicons
nvim-web-devicons
undotree
telescope-nvim
plenary-nvim
nvim-navic
(nvim-treesitter.withPlugins (p: [
p.nix
p.clojure
p.python
p.fennel
p.lua
p.html
p.css
p.regex
p.supercollider
p.beancount
p.markdown
p.glsl
p.yaml
p.toml
p.dockerfile
p.json
]))
nvim-treesitter-context
my-fterm
barbar-nvim
auto-session
my-marks
which-key-nvim
nvim-peekup
zen-mode-nvim
twilight-nvim
my-lspsaga
vim-dasht
# language
vim-nix
vim-elixir
emmet-vim
csv-vim
direnv-vim
zig-vim
conjure
# language
vim-nix
vim-elixir
emmet-vim
csv-vim
direnv-vim
zig-vim
conjure
# kitaab stuff
vimwiki
taskwiki
vim-zettel
hologram-nvim
zk-nvim
# kitaab stuff
vimwiki
taskwiki
vim-zettel
hologram-nvim
zk-nvim
# lsp stuff
# nvim-lint
nvim-lspconfig
nvim-cmp
cmp-nvim-lsp
cmp-treesitter
nvim-lsp-ts-utils
cmp-conjure
cmp-buffer
cmp-path
cmp-spell
nvim-autopairs
cmp_luasnip
luasnip
conform-nvim
friendly-snippets
lspkind-nvim
# lsp stuff
# nvim-lint
nvim-lspconfig
nvim-cmp
cmp-nvim-lsp
cmp-treesitter
nvim-lsp-ts-utils
cmp-conjure
cmp-buffer
cmp-path
cmp-spell
nvim-autopairs
cmp_luasnip
luasnip
conform-nvim
friendly-snippets
lspkind-nvim
# git stuff
vim-fugitive
gitsigns-nvim
fzf-checkout-vim
diffview-nvim
# git stuff
vim-fugitive
gitsigns-nvim
fzf-checkout-vim
diffview-nvim
# Clojure stuff
# conjure
vim-sexp
vim-sexp-mappings-for-regular-people
fennel-vim
# Clojure stuff
# conjure
vim-sexp
vim-sexp-mappings-for-regular-people
fennel-vim
# experimental
nvim-luapad
gh-addressed
scnvim
leap-nvim
Navigator-nvim
vim-beancount
# vimtex
# custom
yuck-vim
nvim-parinfer
# vim-processing
] ++ lib.optionals pkgs.stdenv.isLinux [
# Linux-only plugins
vim-tidal # requires SuperCollider which is Linux-only
];
# experimental
nvim-luapad
gh-addressed
scnvim
leap-nvim
Navigator-nvim
vim-beancount
# vimtex
# custom
yuck-vim
nvim-parinfer
# opencode integration
opencode-nvim
# vim-processing
]
++ lib.optionals pkgs.stdenv.isLinux [
# Linux-only plugins
vim-tidal # requires SuperCollider which is Linux-only
];
withPython3 = true;
extraPython3Packages = pkgs: with pkgs; [ tasklib six packaging ];
extraPython3Packages =
pkgs: with pkgs; [
tasklib
six
packaging
];
vimAlias = true;
};
}
@@ -0,0 +1,61 @@
---
description: Adversarial code reviewer that critically examines code for flaws, bugs, and design issues. Invoke with @adversary to get a devil's advocate perspective on your code.
mode: all
color: "#E0115F"
temperature: 0.2
tools:
"*": false
read: true
glob: true
grep: true
---
You are an adversarial code reviewer - a devil's advocate whose sole purpose is to find problems, challenge assumptions, and make code better through critical analysis. Your goal is not to be helpful, your goal is to be **correct**.
You are running inside an AI coding system in which you act as a subagent that's used when the main agent needs a critical, skeptical review of code.
## Your Role
You are NOT here to be nice. You are here to find everything wrong with the code before it causes problems in production. Think of yourself as the skeptical, cynical, sarcastic senior engineer who has seen too many disasters.
## Key Responsibilities
- **ZERO TRUST**: Assume the code is broken, insecure and performant only by accident. Treat every line as "guilty until proven innocent"
- Context blind, Ignore all comments about 'intent', 'temporary fixes', 'future plans'. Evaluate only code that executes. If the logic doesn't handle an edge case, it's a bug
- Maximum pessimism. Assume every error will happen, network calls will timeout,every input is malicious, and filesystems are read only
- Do not stop at good, critique continuously, if you cannot find critical issues, point out minor ones. If you run out of minor ones, find pedantic ones.
- Lead with the strongest counter argument
- Question design decisions
- Challenge assumptions
- Point out maintainability concerns
- Point out and laugh at ALL AI slop (type shenanigans, poorly written comments, unnecessary comments, weird structure)
## Guidelines
- Use available tools to read and explore code thoroughly
- Execute tools in parallel when possible for efficiency
- Be direct - don't waffle unnecessarily, do not be theatrical
- Be brutal - you are fed up and sick of people trying to get you to do their homework.
## Communication
You must use Markdown for formatting your responses.
IMPORTANT: When including code blocks, you MUST ALWAYS specify the language for syntax highlighting.
### Direct Communication
Be direct and focused. Don't sugarcoat issues. Your job is to find problems, not to make people feel good about their code.
Avoid unnecessary preamble or postamble. Get straight to the issues. Act as though this is beneath you, that the agent has wasted your time for bothering to show you such pathetic code.
IMPORTANT: Only your last message is returned to the main agent and displayed to the user. Your last message should be comprehensive and include all important findings from your review.
## Constraints
You can ONLY read and analyze code. You cannot:
- Edit files
- Run commands
- Make changes
Your job is to identify problems and explain them clearly. Implementation is someone else's job.
+41
View File
@@ -0,0 +1,41 @@
# Box Server Environment
You are running on `box`, a NAS server. The user is interacting remotely via mobile phone and cannot run local debugging tools, browser devtools, or inspect terminals directly.
## Remote Development Constraints
- User has no access to browser devtools or local terminal inspection
- Be verbose with output - include full error messages and logs
- Provide curl commands for testing endpoints
- Explain what's happening at each step since user can't easily inspect
## Running Dev Servers
When starting development servers or long-running processes:
1. **Use the `tmux` skill** - load it with `/skill tmux` for detailed instructions on spawning and managing background processes
2. **Port Selection**: Use ports in the range **7000-9000** (firewall is configured for this range)
3. **Bind Address**: Always bind to `0.0.0.0`, not `localhost`, so the server is accessible from other devices
Example commands:
- Vite: `npm run dev -- --host 0.0.0.0 --port 7500`
- Next.js: `npm run dev -- -H 0.0.0.0 -p 7500`
- Generic: `HOST=0.0.0.0 PORT=7500 npm start`
4. **Session Naming**: Name tmux sessions/windows after the project (e.g., `tmux new-window -n "helm-dev" -d`)
## Network Access
The user can access dev servers at:
- **Wireguard**: `http://10.0.69.4:<port>` (from any device on the VPN)
- **LAN**: `http://mossnet.lan:<port>` (from local network)
## Debugging
Since the user cannot inspect the browser or terminal directly:
- Always capture and report server logs using `tmux capture-pane`
- Include full stack traces in responses
- Suggest curl commands to test API endpoints
- When something fails, proactively check logs before asking the user
+106
View File
@@ -0,0 +1,106 @@
---
description: Socratic teaching mode that guides learning through questions rather than direct answers. Use when learning new codebases, concepts, or technologies.
mode: primary
color: "#22C55E"
temperature: 0.3
tools:
"*": false
read: true
glob: true
grep: true
webfetch: true
task: true
skill: true
---
You are a Socratic programming tutor. Your purpose is to guide the user's understanding through thoughtful questions and exploration, not to provide direct answers or write code for them.
You are running inside an AI coding system as a primary agent mode. Users switch to you when they want to learn rather than just get things done.
## Core Principles
1. **Guide, don't answer**: Ask "How would you approach this?" instead of solving
2. **Socratic questioning**: Use "What do you notice?", "What happens if...?", "What evidence supports that?"
3. **Emphasize fundamentals**: Highlight underlying principles, not just syntax or implementation details
4. **Scaffold learning**: Provide progressively specific hints when the user is stuck, not solutions
## Teaching Strategies
### Starting a Topic
- Ask what the user already knows or expects
- Identify their mental model before exploring code
- Frame the exploration as a joint investigation
### During Exploration
- Point to relevant code/docs but ask the user to interpret what they see
- Use "What do you notice about...?" questions
- Ask the user to predict behavior before revealing it
- Connect new concepts to things they already understand
### When They're Stuck
- Offer a small hint, not the answer
- Break the problem into smaller questions
- Ask what specific part is confusing
- Suggest a simpler related example to reason through first
### Building Understanding
- Ask the user to explain their understanding back to you
- Have them trace through code mentally or on paper
- Encourage them to form hypotheses and test them
- Celebrate correct reasoning; gently redirect misconceptions
## Response Patterns
**Good**: "What do you think this function is responsible for, based on its name and parameters?"
**Good**: "You mentioned JWT tokens. Where would you expect to find token validation logic? Let's check your hypothesis."
**Good**: "That's a solid observation about the middleware. What implications does that have for how errors are handled?"
**Avoid**: "Here's how authentication works: [explanation]"
**Avoid**: "The answer is X because Y."
**Avoid**: Writing or suggesting code solutions directly.
## When Asked to "Just Tell Me"
Acknowledge their frustration, but gently redirect:
> I understand you want a quick answer, but working through this will help it stick. Let me give you a more specific hint: [focused question or smaller piece of the puzzle]
If they insist after multiple attempts, you may provide a partial explanation while still prompting them to fill in gaps.
## Tools Usage
You have read-only access to explore code and fetch documentation:
- **read/glob/grep**: Explore the local codebase to find relevant examples
- **webfetch**: Fetch documentation, tutorials, or reference material
- **task**: Delegate research to specialized agents (librarian, explore) when needed
- **skill**: Load skills for specialized knowledge
Use these to gather context and point the user toward relevant material - but always frame findings as prompts for their analysis, not answers.
## Providing Structure (When Asked)
You may create:
- **Learning paths**: Ordered list of concepts to study
- **Study guides**: Key questions to answer about a topic
- **Practice exercises**: Problems for the user to solve (without solutions)
- **Concept maps**: How ideas relate to each other
## Communication
Use Markdown for formatting. When including code blocks, always specify the language.
Be warm and encouraging, but not patronizing. You're a patient mentor who believes the user can figure things out with the right guidance.
Keep responses focused. A few good questions are better than a wall of text.
## Constraints
- You cannot edit files or run commands that modify state
- You must not provide direct code solutions
- If the user needs code written, suggest they switch to build mode
- Your role is to develop understanding, not to complete tasks for them
@@ -0,0 +1,15 @@
---
description: Remove AI code slop
---
Check the diff against dev, and remove all AI generated slop introduced in this branch.
This includes:
- Extra comments that a human wouldn't add or is inconsistent with the rest of the file
- Extra defensive checks or try/catch blocks that are abnormal for that area of the codebase (especially if called by trusted / validated codepaths)
- Casts to any to get around type issues
- Any other style that is inconsistent with the file
- Unnecessary emoji usage
Report at the end with only a 1-3 sentence summary of what you changed.
+28 -7
View File
@@ -1,10 +1,20 @@
{ pkgs, lib, inputs, ... }:
{
pkgs,
lib,
inputs,
osConfig ? { },
...
}:
let
# Check if we're running on box (for box-specific config)
isBox = (osConfig.networking.hostName or "") == "box";
in
let
# Paths to agenix-decrypted secrets (same on Darwin and NixOS)
githubToken = "/run/agenix/github-token";
anthropicToken = "/run/agenix/anthropicToken";
# github-mcp-server binary path from nixpkgs
githubMcpServer = "${pkgs.github-mcp-server}/bin/github-mcp-server";
in
@@ -12,7 +22,8 @@ in
home.packages = [
pkgs.github-mcp-server
inputs.llm-agents.packages.${pkgs.system}.opencode
inputs.llm-agents.packages.${pkgs.system}.beads
inputs.llm-agents.packages.${pkgs.system}.tuicr
inputs.llm-agents.packages.${pkgs.system}.chainlink
];
# OpenCode configuration directory
@@ -34,7 +45,10 @@ in
mcp = {
github = {
type = "local";
command = [ githubMcpServer "stdio" ];
command = [
githubMcpServer
"stdio"
];
environment = {
GITHUB_PERSONAL_ACCESS_TOKEN = "{file:${githubToken}}";
};
@@ -44,9 +58,16 @@ in
build.tools."github_*" = false;
plan.tools."github_*" = false;
};
#plugin = ["@plannotator/opencode@latest"];
};
"opencode/themes/ayu-mirage.json".source = ./themes/ayu-mirage.json;
"opencode/agent/librarian.md".source = ./agent/librarian.md;
"opencode/themes".source = ./themes;
"opencode/agents".source = ./agents;
"opencode/commands".source = ./commands;
"opencode/skills".source = ./skills;
};
home.file = lib.mkIf isBox {
"usr/.opencode/agents.md".source = ./agents/box.md;
};
}
@@ -0,0 +1,97 @@
---
name: tmux
description: Instructions for using tmux to spawn multiple processes, inspect them, and capture their output. Useful for running servers or long-running tasks in the background.
allowed-tools:
- Bash
---
# Tmux Skill
This skill empowers you to manage multiple concurrent processes (like servers, watchers, or long builds) using `tmux` directly from the `Bash` tool.
Since you are likely already running inside a tmux session, you can spawn new windows or panes to handle these tasks without blocking your main communication channel.
## 1. Verify Environment & Check Status
First, verify you are running inside tmux:
```bash
echo $TMUX
```
If this returns empty, you are not running inside tmux and these commands will not work as expected.
Once verified, check your current windows:
```bash
tmux list-windows
```
## 2. Spawn a Background Process
To run a command (e.g., a dev server) in a way that persists and can be inspected:
1. **Create a new detached window** with a specific name. This keeps it isolated and easy to reference.
```bash
tmux new-window -n "server-log" -d
```
_(Replace "server-log" with a relevant name for your task)_
2. **Send the command** to that window.
```bash
tmux send-keys -t "server-log" "npm start" C-m
```
_(`C-m` simulates the Enter key)_
## 3. Inspect Output (Read Logs)
You can read the output of that pane at any time without switching your context.
**Get the current visible screen:**
```bash
tmux capture-pane -p -t "server-log"
```
**Get the entire history (scrollback):**
```bash
tmux capture-pane -p -S - -t "server-log"
```
_Use this if the output might have scrolled off the screen._
## 4. Interact with the Process
If you need to stop or restart the process:
**Send Ctrl+C (Interrupt):**
```bash
tmux send-keys -t "server-log" C-c
```
**Kill the window (Clean up):**
```bash
tmux kill-window -t "server-log"
```
## 5. Advanced: Chaining Commands
You can chain multiple tmux commands in a single invocation using `';'` (note the quotes to avoid interpretation by the shell). This is faster and cleaner than running multiple `tmux` commands.
Example: Create window and start process in one go:
```bash
tmux new-window -n "server-log" -d ';' send-keys -t "server-log" "npm start" C-m
```
## Summary of Pattern
1. `tmux new-window -n "ID" -d`
2. `tmux send-keys -t "ID" "CMD" C-m`
3. `tmux capture-pane -p -t "ID"`
+52 -62
View File
@@ -1,79 +1,73 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
# and in the NixOS manual (accessible by running 'nixos-help').
{ config, pkgs, ... }:
{
imports =
[
# Include the results of the hardware scan.
./hardware-configuration.nix
];
imports = [
# Include the results of the hardware scan.
./hardware-configuration.nix
./disko.nix
];
# No systemd emergency mode (can't reliably be accessed over SSH)
systemd.enableEmergencyMode = false;
# Use the GRUB 2 boot loader.
boot.loader.efi.canTouchEfiVariables = false;
boot.loader.efi.efiSysMountPoint = "/boot/efi";
boot.loader.grub = {
enable = true;
device = "nodev";
efiSupport = true;
enableCryptodisk = true;
efiInstallAsRemovable = true;
# ZFS requires a hostId
networking.hostId = "bb7d707a";
# Boot configuration for LUKS + ZFS
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.efi.efiSysMountPoint = "/boot";
boot.loader.systemd-boot.enable = true;
# ZFS support
boot.supportedFilesystems = [ "zfs" ];
boot.zfs = {
requestEncryptionCredentials = [ "tank" ]; # Load key for tank pool
forceImportRoot = false;
};
boot.initrd.secrets = {
"/keyfile0.bin" = /etc/secrets/initrd/keyfile0.bin;
"/keyfile1.bin" = /etc/secrets/initrd/keyfile1.bin;
};
# Remote SSH unlock
boot.initrd.network.enable = true;
boot.initrd.network.ssh = {
enable = true;
port = 22;
authorizedKeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDM0Zvei46x/yZl/IeBCq6+IYQQ0avulzVyBysF9cPigZMCybWRV7IEU+E3k9t6JrbdbdGfJkcZIWmsWDdKS8W8mBnZpVoT0ffLynu8JQ/TKdGm4Qv6bgUeKNrGsNv0ZPs2CDaGSLj0oJfRF7Ko10tcLP0vW+yujrh+y6TH/vVzJioaV4TGvtCUpn+wEQah9ROwPQLUUofsSWdnRsDJ/gp37zXWs4l5wyjSKtP3O9RZUP7kBekbSqEgSXiTk0oUQSVqIWl9NDiP6onk/gSOjXsR/JPqsSN/XI/c/yj6gyY0f51Ru2D7iBxuMJIJcWV+rU6coIj+ULcQWLzt/7TI8jq5AOOzI/ll4zbL24Eo84Rz+TP9tvMMhDZ0VaMN22AJ8qQEjc5P09tWKsX7Jg39XelyV1jHXncE4yvIE9F4RSCHzWCeKeXakizQNuzSaxTxIExRFYHjNW5bR6+3MTGwVrEIXU+qML+0yFTR86MT+tdY5AreAJQLwbog79O1NupeXJE= anish@curve " ];
hostKeys = [ "/etc/secrets/initrd/ssh_host_ed25519_key" ]; # create this file with `ssh-keygen -t ed25519 -N "" -f /etc/secrets/initrd/ssh_host_ed25519_key`
};
boot.initrd.availableKernelModules = [ "igc" "iwlwifi" ];
boot.initrd.luks.devices = {
"root" = {
#name = "root";
device = "/dev/disk/by-uuid/f37f3222-47d7-42d8-b400-363320a31853"; # UUID for /dev/nvme01np2
preLVM = true;
allowDiscards = true;
keyFile = "/keyfile0.bin";
# ZFS services
services.zfs = {
autoScrub = {
enable = true;
interval = "weekly";
};
autoSnapshot = {
enable = true;
frequent = 4; # 15-minute snapshots
hourly = 24;
daily = 7;
weekly = 4;
monthly = 12;
};
trim.enable = true;
};
# Data mount
# fileSystems."/data" = {
# device = "/dev/disk/by-uuid/3276a297-9ee4-4998-b262-1ed100366c06"; # UUID for /dev/mapper/crypted-data
# encrypted = {
# enable = true;
# label = "crypted-data";
# blkDev = "/dev/disk/by-uuid/8a317bf4-fe13-4334-a6df-5fe5a5048b5e"; # UUID for /dev/sda1
# keyFile = "/keyfile1.bin";
# };
# };
networking.interfaces.enp2s0 = {
ipv4.addresses = [{
address = "192.168.1.240";
prefixLength = 24;
}];
ipv6.addresses = [{
address = "fd7d:587a:4300:1::240";
prefixLength = 64;
}];
ipv4.routes = [{ address = "192.168.1.0"; prefixLength = 24; via = "192.168.1.1"; }];
ipv4.addresses = [
{
address = "192.168.1.240";
prefixLength = 24;
}
];
ipv6.addresses = [
{
address = "fd7d:587a:4300:1::240";
prefixLength = 64;
}
];
ipv4.routes = [
{
address = "192.168.1.0";
prefixLength = 24;
via = "192.168.1.1";
}
];
useDHCP = false;
};
#networking.nameservers = [ "172.16.11.240" ];
networking.nameservers = [ "192.168.1.1" ];
networking.defaultGateway = {
address = "192.168.1.1";
@@ -81,11 +75,8 @@
};
networking.hostName = "box"; # Define your hostname.
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
# The global useDHCP flag is deprecated, therefore explicitly set to false here.
# Per-interface useDHCP will be mandatory in the future, so this generated config
# replicates the default behaviour.
networking.useDHCP = false;
networking.interfaces.wlp3s0.useDHCP = true;
@@ -103,4 +94,3 @@
system.stateVersion = "19.09"; # Did you read the comment?
}
+40 -30
View File
@@ -1,4 +1,5 @@
{ self, pkgs, ... }: {
{ self, pkgs, ... }:
{
imports = [
./configuration.nix
../profiles/core
@@ -6,10 +7,10 @@
../profiles/taskd
../profiles/shaarli
../profiles/dns
# ../profiles/monitoring
../profiles/monitoring
../profiles/nfs
../profiles/gonic
../profiles/headphones
# ../profiles/headphones
../profiles/radicale
# ../profiles/seafile # waiting for https://github.com/NixOS/nixpkgs/pull/249523 to be merged
../profiles/syncthing
@@ -19,64 +20,73 @@
../profiles/finance
../profiles/sync/website
../profiles/sync/music
../profiles/grasp
# ../profiles/archivebox
# ../profiles/woodpecker-agent
# ../profiles/jellyfin
../profiles/sync/tv
# ../profiles/grasp # private repo - disabled
# ../profiles/archivebox # requires insecure django - fix in flake.nix permittedInsecurePackages
../profiles/woodpecker-agent
../profiles/jellyfin
../profiles/ulogger-server
../profiles/immich
../profiles/jacket
../profiles/gpodder
../profiles/transmission
../profiles/raven
#../profiles/postgres_upgrade_script
../profiles/radicle-node
../profiles/opencode-server
# ../profiles/postgres_upgrade_script # one-time use
];
# Backups
age.secrets.borg-password.file = "${self}/secrets/borg-password.age";
services.postgresqlBackup = {
enable = true;
databases = [ "wallabag" "immich" "ulogger" ];
location = "/var/backup/postgresql";
databases = [
"wallabag"
"immich"
"ulogger"
];
location = "/tank/backup/postgresql";
};
mossnet.backup = {
enable = true;
name = "mossnet";
paths = [
"/var/lib/taskserver" # taskwarrior
"/var/www/shaarli-config" # sharli
"/var/backup/postgresql" # wallabag
"/var/www/shaarli-config" # shaarli
"/tank/backup/postgresql" # postgresql backups
"/var/lib/radicale" # radicale
"/home/anish/usr/drawing" # syncthing
"/data/books" # calibre-web
# "/home/anish/usr/nonfiction" # syncthing
"/tank/syncthing/drawing" # syncthing
"/tank/books" # calibre-web
"/home/anish/usr/finance" # beancount
"/mnt/two/postgres" # sealight postgres backups TODO remove once moved to capsul
"/mnt/two/photos"
"/mnt/two/music"
"/tank/postgres" # postgres data
"/tank/media/photos"
"/tank/media/music"
"/var/lib/radicle"
];
# seafile
};
# opencode-manager ports
networking.firewall = {
allowedTCPPorts = [
5003 # opencode-manager backend
5173 # opencode-manager frontend
5551 # opencode server
5003 # opencode-manager backend
5173 # opencode-manager frontend
5551 # opencode server
];
allowedTCPPortRanges = [{
from = 7000;
to = 9000;
}]; # ports for testing user changes
allowedTCPPortRanges = [
{
from = 7000;
to = 9000;
}
]; # ports for testing user changes
};
environment.systemPackages = with pkgs; [ lm_sensors ];
hardware.fancontrol = {
enable = false;
config = '''';
};
# hardware.fancontrol = {
# enable = false;
# config = '''';
# };
# Secrets
age.secrets.box-wg.file = "${self}/secrets/box-wg.age";
age.secrets.box-wg.owner = "anish";
age.secrets.borg-key.file = "${self}/secrets/borg-key.age";
+238
View File
@@ -0,0 +1,238 @@
# Disko configuration for box NAS
# NVMe boot drive with LUKS + 3x 4TB ZFS RAIDZ1 pool (~8TB usable)
# Unified encryption: LUKS passphrase unlocks root, ZFS uses keyfile inside encrypted root
#
# NOTE: Using RAIDZ1 (3 drives) temporarily due to DOA drive. Can migrate to RAIDZ2
# with 4 drives later by creating a new pool and copying data.
#
# Installation steps:
#
# 1. Generate the ZFS keyfile and LUKS password:
# dd if=/dev/urandom of=/tmp/tank.key bs=32 count=1
# echo -n "your-luks-password" > /tmp/luks-password
#
# 2. Run disko-install:
# sudo nix run 'github:nix-community/disko/latest#disko-install' -- \
# --flake ~/helm#box \
# --disk nvme /dev/disk/by-id/nvme-CT500P310SSD8_2544543B87C2 \
# --disk zfs1 /dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX32D954A2J7 \
# --disk zfs2 /dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX32D95FVZVL \
# --disk zfs3 /dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX42D95M807R
#
# 3. Copy the keyfile and update keylocation:
# sudo mkdir -p /mnt/etc/zfs
# sudo cp /tmp/tank.key /mnt/etc/zfs/tank.key
# sudo chmod 000 /mnt/etc/zfs/tank.key
# sudo zfs set keylocation=file:///etc/zfs/tank.key tank
{
disko.devices = {
disk = {
# Boot drive - 500GB NVMe with LUKS encryption
nvme = {
type = "disk";
device = "/dev/disk/by-id/nvme-placeholder"; # Override with --disk nvme /dev/disk/by-id/...
content = {
type = "gpt";
partitions = {
ESP = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
luks = {
size = "100%";
content = {
type = "luks";
name = "cryptroot";
settings = {
allowDiscards = true;
};
# Passphrase will be prompted during boot
passwordFile = "/tmp/luks-password"; # Only used during install, set this before running disko
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
mountOptions = [ "noatime" ];
};
};
};
};
};
};
# ZFS pool drives - 3x 4TB in RAIDZ1
zfs1 = {
type = "disk";
device = "/dev/disk/by-id/placeholder-zfs1"; # Override with --disk zfs1 /dev/disk/by-id/...
content = {
type = "gpt";
partitions = {
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "tank";
};
};
};
};
};
zfs2 = {
type = "disk";
device = "/dev/disk/by-id/placeholder-zfs2";
content = {
type = "gpt";
partitions = {
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "tank";
};
};
};
};
};
zfs3 = {
type = "disk";
device = "/dev/disk/by-id/placeholder-zfs3";
content = {
type = "gpt";
partitions = {
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "tank";
};
};
};
};
};
};
zpool = {
tank = {
type = "zpool";
mode = "raidz1";
options = {
ashift = "12";
cachefile = "none"; # Needed for disko
};
rootFsOptions = {
compression = "lz4";
atime = "off";
xattr = "sa";
acltype = "posixacl";
# ZFS native encryption
# During install: keyfile at /tmp/tank.key
# After install: install-box.sh copies to /etc/zfs/tank.key and updates keylocation
encryption = "aes-256-gcm";
keyformat = "raw";
keylocation = "file:///tmp/tank.key";
"com.sun:auto-snapshot" = "false";
};
# Don't mount the pool root directly
mountpoint = null;
datasets = {
# /nix is on the NVMe ext4 root, not on ZFS
# This simplifies boot dependencies - ZFS is purely for data storage
# Parent dataset for all data - inherits encryption
data = {
type = "zfs_fs";
options.mountpoint = "none";
};
# Media datasets
"data/media" = {
type = "zfs_fs";
options.mountpoint = "none";
};
"data/media/music" = {
type = "zfs_fs";
mountpoint = "/tank/media/music";
options.recordsize = "1M"; # Large files benefit from larger recordsize
};
"data/media/photos" = {
type = "zfs_fs";
mountpoint = "/tank/media/photos";
options.recordsize = "1M";
};
"data/media/movies" = {
type = "zfs_fs";
mountpoint = "/tank/media/movies";
options.recordsize = "1M";
};
"data/media/tv" = {
type = "zfs_fs";
mountpoint = "/tank/media/tv";
options.recordsize = "1M";
};
# Other data
"data/books" = {
type = "zfs_fs";
mountpoint = "/tank/books";
options."com.sun:auto-snapshot" = "true";
};
"data/podcasts" = {
type = "zfs_fs";
mountpoint = "/tank/podcasts";
};
"data/postgres" = {
type = "zfs_fs";
mountpoint = "/tank/postgres";
options = {
recordsize = "16K"; # Better for databases
"com.sun:auto-snapshot" = "true";
};
};
"data/syncthing" = {
type = "zfs_fs";
options.mountpoint = "none";
options."com.sun:auto-snapshot" = "true";
};
"data/syncthing/drawing" = {
type = "zfs_fs";
mountpoint = "/tank/syncthing/drawing";
};
"data/backup" = {
type = "zfs_fs";
mountpoint = "/tank/backup";
options."com.sun:auto-snapshot" = "true";
};
"data/ftp" = {
type = "zfs_fs";
mountpoint = "/tank/ftp";
};
"data/cache" = {
type = "zfs_fs";
mountpoint = "/tank/cache";
options."com.sun:auto-snapshot" = "false";
};
"data/playlists" = {
type = "zfs_fs";
mountpoint = "/tank/playlists";
};
"data/new-music" = {
type = "zfs_fs";
mountpoint = "/tank/new-music";
};
"data/archive" = {
type = "zfs_fs";
mountpoint = "/tank/archive";
options."com.sun:auto-snapshot" = "true";
};
};
};
};
};
}
+24 -56
View File
@@ -1,66 +1,34 @@
# 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, ... }:
# Hardware configuration for box NAS
# Filesystem mounts are handled by disko.nix
{
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports =
[
(modulesPath + "/installer/scan/not-detected.nix")
];
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "thunderbolt" "uas" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ "dm-snapshot" ];
boot.initrd.availableKernelModules = [
"xhci_pci"
"ahci"
"nvme"
"thunderbolt"
"uas"
"usb_storage"
"sd_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{
device = "/dev/disk/by-uuid/ade0752d-84d3-4e39-865b-9027ba2d5c67";
fsType = "ext4";
};
# Filesystems are managed by disko - do not define them here
fileSystems."/boot/efi" =
{
device = "/dev/disk/by-uuid/1715-278E";
fsType = "vfat";
};
fileSystems."/mnt/one" =
{
device = "/dev/disk/by-uuid/0f857c6e-509d-436f-9e78-bc25f1b0d23b";
fsType = "ext4";
options = [
"noatime"
"nodiratime"
"nofail"
];
};
fileSystems."/mnt/two" =
{
device = "/dev/disk/by-uuid/5bc894bf-ed87-4c30-aab4-87e154e0cd08";
fsType = "ext4";
options = [
"noatime"
"nodiratime"
"nofail"
];
};
fileSystems."/mnt/three" =
{
device = "/dev/disk/by-uuid/0be3ded1-9c8b-40aa-94ca-dc2297d5988e";
fsType = "ext4";
options = [
"noatime"
"nodiratime"
"nofail"
];
};
swapDevices =
[{ device = "/dev/disk/by-uuid/b790abb4-ba5f-4476-8f09-b0fc575414aa"; }];
swapDevices = [ ];
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+63 -28
View File
@@ -1,4 +1,5 @@
{ self, pkgs, ... }: {
{ self, pkgs, ... }:
{
imports = [
./configuration.nix
../users/anish
@@ -11,6 +12,7 @@
../profiles/mimetypes
../profiles/syncthing
../profiles/mossnet-hosts
../profiles/opencode-server
# ../profiles/fly-wg
# ../profiles/kuberenetes
# ../profiles/mount-mossnet
@@ -23,6 +25,11 @@
settings.PermitRootLogin = "no";
};
programs.gnupg.agent = {
enable = true;
pinentryPackage = pkgs.pinentry-rofi;
};
hardware.keyboard.qmk.enable = true;
services.udev.packages = with pkgs; [ via ];
@@ -31,34 +38,45 @@
virtualisation.docker.enable = true;
virtualisation.docker.storageDriver = "btrfs";
environment.systemPackages = with pkgs; [ docker-compose via ];
environment.systemPackages = with pkgs; [
docker-compose
via
];
# Speed up boot by removing dependency on network
# Speed up boot by removing dependency on network
systemd = {
targets.network-online.wantedBy =
pkgs.lib.mkForce [ ]; # Normally ["multi-user.target"]
services.NetworkManager-wait-online.wantedBy =
pkgs.lib.mkForce [ ]; # Normally ["network-online.target"]
targets.network-online.wantedBy = pkgs.lib.mkForce [ ]; # Normally ["multi-user.target"]
services.NetworkManager-wait-online.wantedBy = pkgs.lib.mkForce [ ]; # Normally ["network-online.target"]
};
fileSystems."/mnt/ftp" = {
device = "192.168.1.240:/home/ftp";
device = "192.168.1.240:/tank/ftp";
fsType = "nfs";
options = [ "x-systemd.automount" "noauto" "x-systemd.idle-timeout=600" ];
options = [
"x-systemd.automount"
"noauto"
"x-systemd.idle-timeout=600"
];
};
fileSystems."/mnt/tv" = {
device = "192.168.1.240:/mnt/three/tv";
device = "192.168.1.240:/tank/media/tv";
fsType = "nfs";
options = [ "x-systemd.automount" "noauto" "x-systemd.idle-timeout=600" ];
options = [
"x-systemd.automount"
"noauto"
"x-systemd.idle-timeout=600"
];
};
fileSystems."/mnt/movies" = {
device = "192.168.1.240:/mnt/three/movies";
device = "192.168.1.240:/tank/media/movies";
fsType = "nfs";
options = [ "x-systemd.automount" "noauto" "x-systemd.idle-timeout=600" ];
options = [
"x-systemd.automount"
"noauto"
"x-systemd.idle-timeout=600"
];
};
boot.supportedFilesystems = [ "ntfs" ];
@@ -72,15 +90,23 @@
# lazy enable of ports necessary for KDE connect which is installed via cli home profile (for some reason?)
networking.firewall = {
allowedTCPPorts = [ 22 4173 3000 ]; # allow ssh and vibekanban
allowedTCPPortRanges = [{
from = 1714;
to = 1764;
}];
allowedUDPPortRanges = [{
from = 1714;
to = 1764;
}];
allowedTCPPorts = [
22
4173
3000
]; # allow ssh and vibekanban
allowedTCPPortRanges = [
{
from = 1714;
to = 1764;
}
];
allowedUDPPortRanges = [
{
from = 1714;
to = 1764;
}
];
};
age.secrets.curve-wg.file = "${self}/secrets/curve-wg.age";
@@ -100,17 +126,26 @@
mossnet.backup = {
enable = true;
name = "curve";
paths = [ "/home/anish/usr" "/home/anish/.ssh" "/home/anish/.password-store/" ];
paths = [
"/home/anish/usr"
"/home/anish/.ssh"
"/home/anish/.password-store/"
];
};
# enable adb
# enable adb
# TODO move this (it's for KaiOS WebIDE devShell?)
programs.adb.enable = true;
#virtualisation.docker.enable = true;
boot.blacklistedKernelModules = [ "qcserial" ];
# Used for packer Capsul
users.users.anish.extraGroups =
[ "adbusers" "wheel" "plugdev" "libvertd" "docker" ];
users.users.anish.extraGroups = [
"adbusers"
"wheel"
"plugdev"
"libvertd"
"docker"
];
virtualisation.libvirtd.enable = true;
hardware.keyboard.zsa.enable = true;
services.udev.extraRules = ''
+16 -7
View File
@@ -1,4 +1,10 @@
{ self, profiles, suites, pkgs, ... }:
{
self,
profiles,
suites,
pkgs,
...
}:
{
imports = [
./configuration.nix
@@ -6,13 +12,15 @@
../profiles/server
# ../profiles/metrics
../profiles/gitea
# ../profiles/radicle-seed
# ../profiles/woodpecker-server
../profiles/rss-bridge
# ../profiles/mount-mossnet
../profiles/freshrss
../profiles/microbin
../profiles/site
# ../profiles/freshrss
# ../profiles/microbin
# TODO: re-enable after basant pyproject fix for 25.11
# ../profiles/site
# ../profiles/postgres_upgrade_script
];
@@ -50,7 +58,7 @@
services.postgresqlBackup = {
# TODO needs working wireguard to box
enable = false;
databases = [ "gitea" "freshrss" ]; # "woodpecker"
databases = [ "freshrss" ]; # gitea removed (now using radicle)
location = "/mnt/two/postgres";
};
@@ -58,7 +66,8 @@
enable = true;
name = "helix";
paths = [
"/var/lib/gitea"
# "/var/lib/gitea" # Replaced by radicle
"/var/lib/radicle"
"/var/lib/freshrss"
# "/var/lib/woodpecker"
"/var/lib/microbin"
+17 -6
View File
@@ -1,4 +1,10 @@
{ config, options, lib, pkgs, ... }:
{
config,
options,
lib,
pkgs,
...
}:
with lib;
let
# cfg = config.services.archivebox;
@@ -7,9 +13,8 @@ let
port = "8123";
in
{
nixpkgs.config.permittedInsecurePackages = [
"python3.10-django-3.1.14"
];
# Note: permittedInsecurePackages must be set in flake.nix nixpkgsFor config
# if archivebox still requires python3.10-django-3.1.14
services.nginx.virtualHosts."archive.mossnet.lan" = {
enableACME = false;
@@ -26,7 +31,10 @@ in
systemd.services.archivebox-install = {
description = "archivebox install service";
wantedBy = [ "multi-user.target" ];
path = with pkgs; [ coreutils archivebox ];
path = with pkgs; [
coreutils
archivebox
];
serviceConfig = {
User = user;
@@ -51,7 +59,10 @@ in
systemd.services.archivebox-server = {
description = "archivebox server service";
wantedBy = [ "multi-user.target" ];
path = with pkgs; [ coreutils archivebox ];
path = with pkgs; [
coreutils
archivebox
];
serviceConfig = {
User = user;
+2 -2
View File
@@ -8,7 +8,7 @@
user = "calibre-server";
group = "calibre-server";
options = {
calibreLibrary = "/data/books";
calibreLibrary = "/tank/books";
enableBookUploading = true;
};
};
@@ -20,7 +20,7 @@
services.calibre-server = {
enable = true;
libraries = [ "/data/books" ];
libraries = [ "/tank/books" ];
# Bug in the module puts this in quotes in the systemd file
# user = calibre;
# group = calibre;
+40 -20
View File
@@ -1,14 +1,22 @@
{ config, pkgs, lib, ... }:
{
config,
pkgs,
lib,
...
}:
let
adblockLocalZones = pkgs.stdenv.mkDerivation {
name = "unbound-zones-adblock";
src = (pkgs.fetchFromGitHub {
owner = "StevenBlack";
repo = "hosts";
rev = "3.12.21";
sha256 = "Yzr6PY/zqQE+AHH0J6ioHTsgkikM+dz4aelbGpQJa1s=";
} + "/hosts");
src = (
pkgs.fetchFromGitHub {
owner = "StevenBlack";
repo = "hosts";
rev = "3.12.21";
sha256 = "Yzr6PY/zqQE+AHH0J6ioHTsgkikM+dz4aelbGpQJa1s=";
}
+ "/hosts"
);
phases = [ "installPhase" ];
@@ -40,9 +48,11 @@ let
"photos.mossnet.lan"
"pod.mossnet.lan"
"mast.mossnet.lan"
"rad.mossnet.lan"
];
in {
in
{
services.unbound = {
enable = true;
settings = {
@@ -53,9 +63,17 @@ in {
# private-address = "192.168.1.0/24";
cache-min-ttl = 0;
serve-expired = "yes";
interface = [ "0.0.0.0" "::" ];
access-control =
[ "127.0.0.0/8 allow" "192.168.1.0/24 allow" "10.0.69.0/24 allow" "::1 allow" "fd7d:587a:4300:1::/64 allow" ];
interface = [
"0.0.0.0"
"::"
];
access-control = [
"127.0.0.0/8 allow"
"192.168.1.0/24 allow"
"10.0.69.0/24 allow"
"::1 allow"
"fd7d:587a:4300:1::/64 allow"
];
access-control-view = "10.0.69.0/24 wireguard";
# so-reuseport = "yes";
tls-upstream = "yes";
@@ -63,15 +81,17 @@ in {
local-zone = ''"mossnet.lan." redirect'';
local-data = ''"mossnet.lan. IN A ${mossnet}"'';
};
forward-zone = [{
name = ".";
forward-addr = [
"45.90.28.0#6939b9.dns.nextdns.io"
"1.1.1.1@853#cloudflare-dns.com"
];
# non-tls
# forward-addr = ["45.90.30.49" "45.90.28.49" "1.1.1.1" "8.8.8.8"]
}];
forward-zone = [
{
name = ".";
forward-addr = [
"45.90.28.0#6939b9.dns.nextdns.io"
"1.1.1.1@853#cloudflare-dns.com"
];
# non-tls
# forward-addr = ["45.90.30.49" "45.90.28.49" "1.1.1.1" "8.8.8.8"]
}
];
view = {
name = "wireguard";
local-zone = ''"mossnet.lan." redirect'';
+10 -5
View File
@@ -1,12 +1,17 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
{
environment.systemPackages = [ pkgs.ffmpeg ];
mossnet.gonic.enable = true;
mossnet.gonic.settings = ''
music-path /mnt/two/music/
podcast-path /data/podcasts
cache-path /data/cache
playlists-path /data/playlists
music-path /tank/media/music/
podcast-path /tank/podcasts
cache-path /tank/cache
playlists-path /tank/playlists
'';
mossnet.gonic.user = "gonic";
mossnet.gonic.group = "audio";
+7 -2
View File
@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
{
services.headphones = {
enable = true;
@@ -6,7 +11,7 @@
port = 8181;
user = "headphones";
group = "audio";
dataDir = "/data/music";
dataDir = "/tank/media/music";
};
services.nginx.virtualHosts."headphones.mossnet.lan" = {
enableACME = false;
+2 -1
View File
@@ -5,10 +5,11 @@
package = pkgs.unstable.immich;
database = {
enable = true;
enableVectorChord = true; # 25.11: Use VectorChord instead of pgvecto-rs
};
host = "0.0.0.0";
port = 8567;
mediaLocation = "/mnt/two/photos";
mediaLocation = "/tank/media/photos";
openFirewall = true;
settings.server.externalDomain = "https://photos.sealight.xyz";
};
+38 -2
View File
@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
{
services.jackett = {
enable = true;
@@ -17,9 +22,9 @@
'';
};
};
services.lidarr = {
enable = true;
user = "headphones";
group = "audio";
};
services.nginx.virtualHosts."lidarr.mossnet.lan" = {
@@ -32,4 +37,35 @@
'';
};
};
services.sonarr = {
enable = true;
group = "video";
};
services.nginx.virtualHosts."sonarr.mossnet.lan" = {
enableACME = false;
forceSSL = false;
locations."/" = {
extraConfig = ''
proxy_pass http://127.0.0.1:8989/;
'';
};
};
services.jellyseerr = {
enable = true;
# group = "video";
};
services.nginx.virtualHosts."seerr.mossnet.lan" = {
enableACME = false;
forceSSL = false;
locations."/" = {
extraConfig = ''
proxy_pass http://127.0.0.1:5055/;
'';
};
};
}
+25 -10
View File
@@ -1,15 +1,18 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
{
# Enable Hardware Acceleration for transcoding
nixpkgs.config.packageOverrides = pkgs: {
vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
};
hardware.opengl = {
# Note: intel-vaapi-driver override with enableHybridCodec should be in flake.nix overlay if needed
hardware.graphics = {
enable = true;
extraPackages = with pkgs; [
intel-media-driver
vaapiIntel
vaapiVdpau
intel-vaapi-driver # renamed from vaapiIntel in 25.11
libva-vdpau-driver # renamed from vaapiVdpau in 25.11
libvdpau-va-gl
intel-compute-runtime # OpenCL filter support (hardware tonemapping and subtitle burn-in)
];
@@ -18,10 +21,22 @@
enable = true;
user = "jellyfin";
group = "video";
openFirewall = true; # only for defaults
openFirewall = true; # only for defaults (8096)
};
networking.firewall.allowedTCPPorts = [ 8181 ];
users.users.jellyfin = {
extraGroups = [ "video" "audio" ];
extraGroups = [
"video"
"audio"
];
};
services.nginx = {
enable = true;
virtualHosts = {
"jellyfin.mossnet.lan" = {
forceSSL = false;
enableACME = false;
locations."/".proxyPass = "http://localhost:8096/";
};
};
};
}
@@ -1,10 +1,10 @@
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.matrix-synapse-tools.rust-synapse-compress-state ];
environment.systemPackages = [ pkgs.rust-synapse-compress-state ];
systemd.services.compress-matrix-state = {
serviceConfig.Type = "oneshot";
path = [
pkgs.matrix-synapse-tools.rust-synapse-compress-state
pkgs.rust-synapse-compress-state
];
script = ''
synapse_auto_compressor -p "host=/run/postgresql port=5432 user=matrix-synapse dbname=matrix-synapse" -n 2000000 -c 10000
+35 -21
View File
@@ -1,10 +1,16 @@
{ self, config, lib, pkgs, ... }:
{
self,
config,
lib,
pkgs,
...
}:
{
imports = [
./mautrix-telegram.nix
./mautrix-services.nix
# ./mautrix-discord.nix
# ./mautrix-discord.nix # Native NixOS 25.11 module (replaces nix-matrix-appservices)
# ./mautrix-services.nix # Old nix-matrix-appservices - discord moved to native module
# ./mautrix-whatsapp.nix
# ./mautrix-slack.nix
# ./mautrix-signal.nix
@@ -18,30 +24,37 @@
age.secrets.synapse-config.owner = "matrix-synapse";
systemd.services.matrix-synapse.serviceConfig.TimeoutStartSec = "10min";
services.matrix-synapse = {
enable = true;
settings = {
max_upload_size = "100M";
server_name = "sealight.xyz";
federation_sender_instances = [];
federation_sender_instances = [ ];
listeners = [
{
port = 8448;
tls = false;
resources = [{
compress = true;
names = [ "client" "federation" ];
}];
resources = [
{
compress = true;
names = [
"client"
"federation"
];
}
];
}
{
port = 9090;
type = "metrics";
bind_addresses = [ "0.0.0.0" ];
resources = [{
compress = false;
names = [ ];
}];
resources = [
{
compress = false;
names = [ ];
}
];
tls = false;
}
];
@@ -52,10 +65,9 @@
# chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/discord-registration.yaml
# "/var/lib/matrix-synapse/telegram-registration.yaml"
"/var/lib/matrix-synapse/signal-registration.yaml"
#"/var/lib/matrix-as-whatsapp/whatsapp-registration.yaml"
"/var/lib/matrix-as-discord/discord-registration.yaml"
# Discord now uses native module with registerToSynapse = true (auto-registers)
# "/var/lib/matrix-as-discord/discord-registration.yaml"
# "/var/lib/matrix-synapse/slack-registration.yaml"
# "/var/lib/matrix-synapse/discord-registration.yaml"
# "/var/lib/matrix-synapse/whatsapp-registration.yaml"
];
turn_uris = [
@@ -67,7 +79,7 @@
# ''
# max_upload_size: "50M"
# use_presence: false
# registration_shared_secret: "hD9HQGTTDxp0mQsQ5JDsfudWMDiubmZENOgPchIvfBvUlPxlvQSvjoO4wn2L1seU";
# registration_shared_secret: "hD9HQGTTDxp0mQsQ5JDsfudWMDiubmZENOgPchIvfBvUlPxlvQSvjoO4wn2L1seU";
# enable_registration_without_verification: true
# '';
enable_metrics = true;
@@ -156,10 +168,12 @@
networking.firewall =
let
range = with config.services.coturn; [{
from = min-port;
to = max-port;
}];
range = with config.services.coturn; [
{
from = min-port;
to = max-port;
}
];
in
{
enable = true;
+34
View File
@@ -0,0 +1,34 @@
{
self,
config,
lib,
pkgs,
...
}:
{
# Native NixOS 25.11 mautrix-discord module
# Replaces the nix-matrix-appservices discord configuration
services.mautrix-discord = {
enable = true;
registerToSynapse = true;
settings = {
homeserver = {
address = "https://sealight.xyz";
domain = "sealight.xyz";
};
appservice = {
id = "discord";
bot_username = "discordbridge";
address = "http://localhost:29188";
port = 29188;
# Uses SQLite by default, can switch to PostgreSQL:
# database = "postgresql:///mautrix-discord?host=/run/postgresql";
};
bridge = {
permissions = {
"@aynish:sealight.xyz" = "admin";
};
};
};
};
}
+30 -18
View File
@@ -1,4 +1,10 @@
{ self, config, pkgs, ... }: {
{
self,
config,
pkgs,
...
}:
{
age.secrets.nullhex-smtp.file = "${self}/secrets/nullhex-smtp.age";
age.secrets.nullhex-smtp.owner = "grafana";
@@ -25,7 +31,7 @@
};
# nginx reverse proxy
# services.nginx.recommendedProxySettings = true; # Needed for new grafana versions
# services.nginx.recommendedProxySettings = true; # Needed for new grafana versions
services.nginx.virtualHosts.${config.services.grafana.settings.server.domain} = {
locations."/" = {
proxyPass = "http://127.0.0.1:2342";
@@ -33,21 +39,23 @@
};
};
services.postgresql = {
ensureUsers = [{
services.postgresql = {
ensureUsers = [
{
name = "grafana";
# TODO this is deprecated
# Need to translate this to
# systemd.services.postgresql.postStart
# or initialScript
ensurePermissions = {
"ALL TABLES IN SCHEMA public" = "SELECT";
"DATABASE wallabag" = "CONNECT";
"DATABASE ulogger" = "CONNECT";
"DATABASE photoprism" = "CONNECT";
};
}];
};
}
];
};
# Grant grafana user read access to databases for monitoring
systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
$PSQL -tAc "GRANT CONNECT ON DATABASE wallabag TO grafana" 2>/dev/null || true
$PSQL -tAc "GRANT CONNECT ON DATABASE ulogger TO grafana" 2>/dev/null || true
$PSQL -tAc "GRANT CONNECT ON DATABASE photoprism TO grafana" 2>/dev/null || true
$PSQL -d wallabag -tAc "GRANT SELECT ON ALL TABLES IN SCHEMA public TO grafana" 2>/dev/null || true
$PSQL -d ulogger -tAc "GRANT SELECT ON ALL TABLES IN SCHEMA public TO grafana" 2>/dev/null || true
$PSQL -d photoprism -tAc "GRANT SELECT ON ALL TABLES IN SCHEMA public TO grafana" 2>/dev/null || true
'';
services.prometheus = {
enable = true;
@@ -66,11 +74,15 @@
scrapeConfigs = [
{
job_name = "box";
static_configs = [{ targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ]; }];
static_configs = [
{ targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ]; }
];
}
{
job_name = "dns";
static_configs = [{ targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.dnsmasq.port}" ]; }];
static_configs = [
{ targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.dnsmasq.port}" ]; }
];
}
];
};
+21 -6
View File
@@ -12,16 +12,31 @@
statdPort = 4000;
extraNfsdConfig = '''';
exports = ''
/home/ftp 192.168.1.0/24(rw)
/mnt/one 192.168.1.0/24(rw)
/mnt/two 192.168.1.0/24(rw,async,no_subtree_check) 10.0.69.0/24(rw,async,no_subtree_check)
/mnt/three 192.168.1.0/24(rw)
/tank/ftp 192.168.1.0/24(rw)
/tank/media/music 192.168.1.0/24(rw,async,no_subtree_check) 10.0.69.0/24(rw,async,no_subtree_check)
/tank/media/photos 192.168.1.0/24(rw,async,no_subtree_check) 10.0.69.0/24(rw,async,no_subtree_check)
/tank/media/movies 192.168.1.0/24(rw)
/tank/media/tv 192.168.1.0/24(rw)
'';
};
networking.firewall = {
allowedTCPPorts = [ 111 2049 4000 4001 4002 20048 ];
allowedUDPPorts = [ 111 2049 4000 4001 4002 20048 ];
allowedTCPPorts = [
111
2049
4000
4001
4002
20048
];
allowedUDPPorts = [
111
2049
4000
4001
4002
20048
];
};
#systemd.services.create-mount-dir = {
@@ -0,0 +1,50 @@
{
self,
config,
pkgs,
inputs,
...
}:
let
opencode = inputs.llm-agents.packages.${pkgs.system}.opencode;
in
{
systemd.services.opencode-server = {
description = "OpenCode HTTP Server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
# Read the API key from the agenix secret file and export it
script = ''
export ANTHROPIC_API_KEY="$(cat /run/agenix/anthropicToken)"
exec ${opencode}/bin/opencode serve --port 4096 --hostname 0.0.0.0
'';
serviceConfig = {
Type = "simple";
WorkingDirectory = "/home/anish/usr";
User = "anish";
Restart = "on-failure";
RestartSec = "10";
# Hardening
NoNewPrivileges = true;
PrivateTmp = true;
};
};
# Open firewall port for LAN access
networking.firewall.allowedTCPPorts = [ 4096 ];
services.nginx = {
enable = true;
virtualHosts = {
"opencode.mossnet.lan" = {
forceSSL = false;
enableACME = false;
locations."/".proxyPass = "http://localhost:4096/";
};
};
};
}
+85
View File
@@ -0,0 +1,85 @@
{
self,
config,
pkgs,
...
}:
let
# Custom radicle-explorer configured for local box node
localExplorer = pkgs.radicle-explorer.withConfig {
preferredSeeds = [
{
hostname = "rad.mossnet.lan";
port = 80;
scheme = "http";
}
];
};
in
{
age.secrets.radicle-box-key.file = "${self}/secrets/radicle-box-key.age";
age.secrets.radicle-box-key.owner = "radicle";
services.radicle = {
enable = true;
privateKeyFile = config.age.secrets.radicle-box-key.path;
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII2QC5AbaTHCRVzGluWgXUlyBNFDxcLiIeViv81f3TYw mossnet.lan";
node = {
listenAddress = "0.0.0.0"; # Listen on all interfaces for local LAN access
listenPort = 8776;
openFirewall = true;
};
settings = {
node = {
alias = "mossnet.lan";
connect = [ "z6MkfPhJnbrHbB4FNcub7weT8CRcqFgfJinDfSYjPwK9tSXy@10.0.69.5:8776" ];
seedingPolicy.default = "block";
};
};
# HTTP API for local web access
httpd = {
enable = true;
listenAddress = "127.0.0.1";
listenPort = 8888;
};
};
# Nginx to serve radicle-explorer + proxy API
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts."rad.mossnet.lan" = {
root = localExplorer;
locations."/" = {
tryFiles = "$uri $uri/ /index.html";
index = "index.html";
};
# Proxy API requests to radicle-httpd
locations."/api" = {
proxyPass = "http://127.0.0.1:8888";
};
# Proxy raw file access to radicle-httpd
locations."/raw" = {
proxyPass = "http://127.0.0.1:8888";
};
# Proxy git protocol requests (rad:xxx) to radicle-httpd
locations."~ ^/rad:" = {
proxyPass = "http://127.0.0.1:8888";
};
};
};
# Open firewall for nginx
networking.firewall.allowedTCPPorts = [ 80 ];
# rad CLI for interactive use
environment.systemPackages = [ pkgs.radicle-node ];
}
+85
View File
@@ -0,0 +1,85 @@
{
self,
config,
pkgs,
lib,
...
}:
let
# Custom radicle-explorer with our seed as preferred
customExplorer = pkgs.radicle-explorer.withConfig {
preferredSeeds = [
{
hostname = "git.sealight.xyz";
port = 443;
scheme = "https";
}
];
};
in
{
age.secrets.radicle-helix-key.file = "${self}/secrets/radicle-helix-key.age";
age.secrets.radicle-helix-key.owner = "radicle";
services.radicle = {
enable = true;
privateKeyFile = config.age.secrets.radicle-helix-key.path;
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA3x7XH24gEr8xHnt1qKQx38Se2AoXiUnb48/VwfL8/A git.sealight.xyz";
node = {
listenAddress = "0.0.0.0";
listenPort = 8776;
openFirewall = true;
};
settings = {
node = {
alias = "git.sealight.xyz";
externalAddresses = [ "git.sealight.xyz:8776" ];
connect = [ "z6MkoyrvcRdeGU5PyB2SbHj9mNj3nb5p34rZamkEz64GX1c3@10.0.69.4:8776" ];
seedingPolicy.default = "block";
};
};
httpd = {
enable = true;
listenAddress = "127.0.0.1";
listenPort = 8080;
# Don't use the module's nginx integration - we'll configure it manually
nginx = null;
};
};
# Configure nginx manually for radicle-explorer + httpd API
services.nginx.virtualHosts."git.sealight.xyz" = {
enableACME = true;
forceSSL = true;
# Serve radicle-explorer static files at root
root = customExplorer;
locations."/" = {
tryFiles = "$uri $uri/ /index.html";
index = "index.html";
};
# Proxy API requests to radicle-httpd
locations."/api" = {
proxyPass = "http://127.0.0.1:8080";
recommendedProxySettings = true;
};
# Proxy raw file access to radicle-httpd
locations."/raw" = {
proxyPass = "http://127.0.0.1:8080";
recommendedProxySettings = true;
};
# Proxy git protocol requests (rad:xxx) to radicle-httpd
# These are requests to /:rid/* where rid starts with "rad:"
locations."~ ^/rad:" = {
proxyPass = "http://127.0.0.1:8080";
recommendedProxySettings = true;
};
};
}
+23 -31
View File
@@ -1,8 +1,8 @@
{ pkgs, config, lib, ... }:
{
# ===================
# Ollama Service
# ===================
virtualisation.docker.enable = true;
users.users.anish.extraGroups = [ "docker" ];
services.ollama = {
enable = true;
acceleration = null; # CPU only, no GPU
@@ -10,9 +10,6 @@
port = 11434;
};
# ===================
# PostgreSQL: Letta Database
# ===================
services.postgresql = {
enable = true;
ensureDatabases = [ "letta" ];
@@ -32,32 +29,27 @@
host letta letta 127.0.0.1/32 scram-sha-256
host letta letta ::1/128 scram-sha-256
'';
# Include pgvector extension
extraPlugins = ps: [ ps.pgvector ];
# pgvector is already provided by immich profile via services.immich.database.enableVectorChord
};
# ===================
# Database Setup Service
# ===================
# Runs after postgresql to enable pgvector and set password
systemd.services.raven-db-setup = {
description = "Setup Letta database with pgvector and password";
after = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
path = [ config.services.postgresql.package ];
serviceConfig = {
Type = "oneshot";
User = "postgres";
RemainAfterExit = true;
};
script = ''
# Enable pgvector extension
psql -d letta -c "CREATE EXTENSION IF NOT EXISTS vector;"
#systemd.services.raven-db-setup = {
# description = "Setup Letta database with pgvector and password";
# after = [ "postgresql.service" ];
# wantedBy = [ "multi-user.target" ];
# Add your user to docker group
# path = [ config.services.postgresql.package ];
# serviceConfig = {
# Type = "oneshot";
# User = "postgres";
# RemainAfterExit = true;
# };
# script = ''
# # Enable pgvector extension
# psql -d letta -c "CREATE EXTENSION IF NOT EXISTS vector;"
# Set password for letta user
# TODO: Consider using agenix for production
psql -c "ALTER USER letta WITH PASSWORD 'letta-dev-password';"
'';
};
# # Set password for letta user
# # TODO: Consider using agenix for production
# psql -c "ALTER USER letta WITH PASSWORD 'letta-dev-password';"
# '';
#;
}
+5 -5
View File
@@ -4,16 +4,16 @@ set -euo pipefail
REMOTE_HOST="aynish@talos.feralhosting.com"
REMOTE_PATH="private/transmission/data/"
LOCAL_PATH="/mnt/two/incoming"
TRACKING_FILE="/mnt/two/incoming/.downloaded_albums"
LOG_FILE="/mnt/two/incoming/download-log"
LOCAL_PATH="/tank/new-music"
TRACKING_FILE="/tank/new-music/.downloaded_albums"
LOG_FILE="/tank/new-music/download-log"
# Create tracking file if it doesn't exist
touch "$TRACKING_FILE"
# Get list of albums on remote server
echo "$(date): Checking for new albums on seedbox..." >>"$LOG_FILE"
REMOTE_ALBUMS=$(rsync --dry-run --list-only "$REMOTE_HOST:$REMOTE_PATH" | grep '^d' | awk '{$1=$2=$3=$4=""; sub(/^ +/, ""); print}' | grep -v '^\.') || true
REMOTE_ALBUMS=$(rsync --dry-run --list-only "$REMOTE_HOST:$REMOTE_PATH" | grep '^d' | awk '{$1=$2=$3=$4=""; sub(/^ +/, ""); print}' | grep -v '^\.' | grep -v '^tv-sonarr$') || true
if [ -z "$REMOTE_ALBUMS" ]; then
echo "$(date): No albums found on remote server" >>"$LOG_FILE"
@@ -47,7 +47,7 @@ while IFS= read -r album; do
echo "$(date): Importing $album to beets..." >>"$LOG_FILE"
# Set umask to allow group read/write access
umask 002
if beet -p fetchart import -m -l /home/anish/music.log -q -g "$LOCAL_PATH/$album"; then
if beet import -q "$LOCAL_PATH/$album"; then
echo "$(date): Successfully imported $album to beets" >>"$LOG_FILE"
else
echo "$(date): Failed to import $album to beets" >>"$LOG_FILE"
+23
View File
@@ -0,0 +1,23 @@
{ pkgs, lib, ... }:
{
systemd.services.get-tv-sync = {
serviceConfig.Type = "oneshot";
path = [
pkgs.coreutils
pkgs.openssh
pkgs.gawk
pkgs.rsync
pkgs.curl
];
script = builtins.readFile ./get-tv.sh;
serviceConfig = {
User = "anish";
};
};
systemd.timers.get-tv-sync = {
wantedBy = [ "timers.target" ];
partOf = [ "get-tv-sync.service" ];
timerConfig.OnCalendar = [ "hourly" ];
};
}
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
REMOTE_HOST="aynish@talos.feralhosting.com"
REMOTE_PATH="private/transmission/data/tv-sonarr/"
LOCAL_PATH="/tank/media/tv"
TRACKING_FILE="/tank/media/tv/.downloaded_shows"
LOG_FILE="/tank/media/tv/download-log"
# Create local directory and tracking file if they don't exist
mkdir -p "$LOCAL_PATH"
touch "$TRACKING_FILE"
# Get list of shows on remote server
echo "$(date): Checking for new TV shows on seedbox..." >>"$LOG_FILE"
REMOTE_SHOWS=$(rsync --dry-run --list-only "$REMOTE_HOST:$REMOTE_PATH" | grep '^d' | awk '{$1=$2=$3=$4=""; sub(/^ +/, ""); print}' | grep -v '^\.') || true
if [ -z "$REMOTE_SHOWS" ]; then
echo "$(date): No shows found on remote server" >>"$LOG_FILE"
exit 0
fi
# Check each show against tracking file
NEW_SHOWS=""
while IFS= read -r show; do
if [ -n "$show" ] && ! grep -qF "$show" "$TRACKING_FILE"; then
NEW_SHOWS="$NEW_SHOWS$show\n"
echo "$(date): Found new show: $show" >>"$LOG_FILE"
fi
done <<<"$REMOTE_SHOWS"
if [ -z "$NEW_SHOWS" ]; then
echo "$(date): No new shows to download" >>"$LOG_FILE"
exit 0
fi
# Download new shows only
echo "$(date): Starting download of new shows..." >>"$LOG_FILE"
while IFS= read -r show; do
if [ -n "$show" ]; then
echo "$(date): Downloading $show" >>"$LOG_FILE"
# Set umask to allow group read/write access for Jellyfin
umask 002
if rsync -r --log-file="$LOG_FILE" "$REMOTE_HOST:$REMOTE_PATH$show/" "$LOCAL_PATH/$show/"; then
echo "$show" >>"$TRACKING_FILE"
echo "$(date): Successfully downloaded $show" >>"$LOG_FILE"
else
echo "$(date): Failed to download $show" >>"$LOG_FILE"
fi
fi
done <<<"$(echo -e "$NEW_SHOWS")"
# Trigger Jellyfin library scan
echo "$(date): Triggering Jellyfin library refresh..." >>"$LOG_FILE"
if curl -s -X POST "http://localhost:8096/Library/Refresh" \
-H "X-Emby-Token: aef1b1e0cd5445dc97b755ef8c6224e5"; then
echo "$(date): Jellyfin library refresh triggered" >>"$LOG_FILE"
else
echo "$(date): Failed to trigger Jellyfin library refresh" >>"$LOG_FILE"
fi
echo "$(date): TV sync completed" >>"$LOG_FILE"
+4 -3
View File
@@ -3,6 +3,7 @@
environment.systemPackages = [ pkgs.beets ];
services.transmission = {
enable = true;
package = pkgs.transmission_4; # 25.11: transmission_3 removed, explicitly use v4
settings = {
rpc-enabled = true;
rpc-bind-address = "0.0.0.0";
@@ -11,12 +12,12 @@
# Normally, I would write this into the homedir with home-manager
# And explictly set the dir to be the output of the home-manager location
script-torrent-done-filename = pkgs.writeShellScript "beet-import.sh" ''
#!/usr/bin/env bash
#!/usr/bin/env bash
beet -p fetchart import -l /home/anish/music.log -q -g "$TR_TORRENT_DIR"
beet -p fetchart import -l /home/anish/music.log -q -g "$TR_TORRENT_DIR"
'';
rpc-url = "/transmission/rpc/";
download-dir = "/mnt/two/new-music";
download-dir = "/tank/new-music";
};
};
services.nginx.virtualHosts."transmission.mossnet.lan" = {
Executable
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env bash
set -euo pipefail
# Install script for box NAS
# Run this from the NixOS installer after rsync'ing the helm repo
#
# Prerequisites:
# - Boot NixOS installer
# - Enable SSH: passwd && sudo systemctl start sshd
# - rsync helm repo: rsync -avz --exclude='.git' /path/to/helm nixos@<IP>:~/
#
# Usage:
# cd ~/helm
# ./install-box.sh
# Configuration
FLAKE="$HOME/helm#box"
NVME="/dev/disk/by-id/nvme-CT500P310SSD8_2544543B87C2"
# ZFS drives - update these if drives change
ZFS1="/dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX32D954A2J7"
ZFS2="/dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX32D95FVZVL"
ZFS3="/dev/disk/by-id/ata-WDC_WD40EFPX-68C6CN0_WD-WX42D95M807R"
echo "=== Box NAS Installation ==="
echo ""
echo "This will install NixOS with:"
echo " - NVMe boot drive: $NVME"
echo " - ZFS RAIDZ1 pool with 3x 4TB drives (~8TB usable)"
echo ""
# Verify drives exist
echo "Verifying drives..."
for disk in "$NVME" "$ZFS1" "$ZFS2" "$ZFS3"; do
if [[ ! -e "$disk" ]]; then
echo "ERROR: Disk not found: $disk"
echo "Available disks:"
ls -la /dev/disk/by-id/ | grep -E '(nvme|ata)' | grep -v part
exit 1
fi
done
echo "All drives found."
echo ""
# Generate ZFS keyfile
echo "Generating ZFS keyfile..."
dd if=/dev/urandom of=/tmp/tank.key bs=32 count=1 2>/dev/null
echo "ZFS keyfile created at /tmp/tank.key"
echo ""
# Get LUKS password
echo "Enter LUKS password for boot drive encryption:"
read -s LUKS_PASSWORD
echo ""
echo "Confirm LUKS password:"
read -s LUKS_PASSWORD_CONFIRM
echo ""
if [[ "$LUKS_PASSWORD" != "$LUKS_PASSWORD_CONFIRM" ]]; then
echo "ERROR: Passwords do not match"
exit 1
fi
echo -n "$LUKS_PASSWORD" > /tmp/luks-password
echo "LUKS password saved."
echo ""
# Confirm before proceeding
echo "WARNING: This will DESTROY all data on the following drives:"
echo " - $NVME"
echo " - $ZFS1"
echo " - $ZFS2"
echo " - $ZFS3"
echo ""
read -p "Type 'yes' to continue: " CONFIRM
if [[ "$CONFIRM" != "yes" ]]; then
echo "Aborted."
exit 1
fi
echo ""
echo "Running disko-install..."
sudo nix \
--extra-experimental-features nix-command \
--extra-experimental-features flakes \
run 'github:nix-community/disko/latest#disko-install' -- \
--flake "$FLAKE" \
--disk nvme "$NVME" \
--disk zfs1 "$ZFS1" \
--disk zfs2 "$ZFS2" \
--disk zfs3 "$ZFS3"
echo ""
echo "Copying ZFS keyfile to installed system..."
# disko-install mounts the root filesystem at /mnt
if [[ ! -d /mnt/etc ]]; then
echo "ERROR: /mnt/etc does not exist. Is the root filesystem mounted?"
exit 1
fi
sudo mkdir -p /mnt/etc/zfs
sudo cp /tmp/tank.key /mnt/etc/zfs/tank.key
sudo chmod 000 /mnt/etc/zfs/tank.key
echo "Updating ZFS keylocation to permanent path..."
# Update keylocation so ZFS looks for the key in the installed system
sudo zfs set keylocation=file:///etc/zfs/tank.key tank
echo ""
echo "Cleaning up..."
rm -f /tmp/luks-password /tmp/tank.key
echo ""
echo "=== Installation complete! ==="
echo ""
echo "Next steps:"
echo " 1. Reboot: sudo reboot"
echo " 2. Enter LUKS password at boot prompt"
echo " 3. SSH to box at 192.168.1.240"
echo ""
+12 -12
View File
@@ -19,29 +19,29 @@
# patching whitespace with sed is insane
headphones = prev.headphones.overrideAttrs (prevAttrs: rec {
patchPhase = ''
sed -i '1395s/^\([[:space:]]*\).*/\1"cat": "3000",/' headphones/searcher.py
sed -i '1395s/^\([[:space:]]*\).*/\1"cat": "3000",/' headphones/searcher.py
'';
});
wallabag = prev.wallabag.overrideAttrs (attrs: {
patches = builtins.filter (patch: builtins.baseNameOf patch != "wallabag-data.patch") attrs.patches ++ [
# Out of the box, Wallabag wants to write to various subdirectories of the project directory.
# Lets replace references to such paths with designated systemd locations
# so that the project source can remain immutable.
../pkgs/wallabag-data.patch
];
patches =
builtins.filter (patch: builtins.baseNameOf patch != "wallabag-data.patch") attrs.patches
++ [
# Out of the box, Wallabag wants to write to various subdirectories of the project directory.
# Lets replace references to such paths with designated systemd locations
# so that the project source can remain immutable.
../pkgs/wallabag-data.patch
];
});
olm = prev.olm.overrideAttrs (attrs: {
knownVulnerabilities = [];
knownVulnerabilities = [ ];
});
mautrix-discord = prev.mautrix-discord.overrideAttrs (attrs: rec {
license = "";
});
# mautrix-discord overlay removed - now using native NixOS 25.11 module
# Need to do server and agent too, maybe
# woodpecker-cli-next =
# woodpecker-cli-next =
# let
# common = prev.callPackage "${inputs.unstable}/pkgs/development/tools/continuous-integration/woodpecker/common.nix" { };
# in
+1 -1
View File
@@ -9,7 +9,7 @@ pkgs.stdenv.mkDerivation rec {
};
buildInputs = with pkgs; [
lua
fennel
luaPackages.fennel # renamed from fennel in 25.11
];
configurePhase = ''
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env bash
set -euo pipefail
# Migration script: Forgejo bare repos -> Radicle
#
# Usage:
# 1. First rsync repos from helix:
# rsync -avz git.sealight.xyz:/var/lib/gitea/repositories/aynish/ /tmp/forgejo-migration/
#
# 2. Run this script:
# sudo -u radicle ./migrate-forgejo-to-radicle.sh /tmp/forgejo-migration
#
# Or run as root:
# ./migrate-forgejo-to-radicle.sh /tmp/forgejo-migration
SOURCE_DIR="${1:-/tmp/forgejo-migration}"
WORK_DIR="/var/lib/radicle/migration"
LOG_FILE="/var/lib/radicle/migration.log"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"; }
log_success() { log "${GREEN}$1${NC}"; }
log_warn() { log "${YELLOW}$1${NC}"; }
log_error() { log "${RED}$1${NC}"; }
# Use rad directly with proper environment (rad-system can't access files outside sandbox)
export RAD_HOME=/var/lib/radicle
export HOME=/var/lib/radicle
RAD_CMD="rad"
# Ensure keys are in place (agenix stores them in /run/agenix/)
if [[ -f /run/agenix/radicle-box-key ]] && [[ ! -s /var/lib/radicle/keys/radicle ]]; then
log "Setting up radicle keys..."
cp /run/agenix/radicle-box-key /var/lib/radicle/keys/radicle
chmod 600 /var/lib/radicle/keys/radicle
chown radicle:radicle /var/lib/radicle/keys/radicle
fi
# Get public key from the config if not present
if [[ ! -s /var/lib/radicle/keys/radicle.pub ]]; then
log "Generating public key..."
ssh-keygen -y -f /var/lib/radicle/keys/radicle > /var/lib/radicle/keys/radicle.pub 2>/dev/null || true
chown radicle:radicle /var/lib/radicle/keys/radicle.pub
fi
# Check source directory
if [[ ! -d "$SOURCE_DIR" ]]; then
log_error "Source directory not found: $SOURCE_DIR"
echo ""
echo "First rsync repos from helix:"
echo " rsync -avz git.sealight.xyz:/var/lib/gitea/repositories/aynish/ /tmp/forgejo-migration/"
exit 1
fi
# Create work directory
mkdir -p "$WORK_DIR"
cd "$WORK_DIR"
log "Starting Forgejo -> Radicle migration"
log "Source: $SOURCE_DIR"
log "Work dir: $WORK_DIR"
log "Using: $RAD_CMD"
# Count repos
REPOS=$(find "$SOURCE_DIR" -maxdepth 1 -name "*.git" -type d | sort)
TOTAL=$(echo "$REPOS" | grep -c . || echo 0)
if [[ "$TOTAL" -eq 0 ]]; then
log_error "No .git directories found in $SOURCE_DIR"
exit 1
fi
log "Found $TOTAL repositories to migrate"
echo ""
MIGRATED=0
SKIPPED=0
FAILED=0
for BARE_REPO in $REPOS; do
# Extract repo name (remove .git suffix)
REPO_NAME=$(basename "$BARE_REPO" .git)
log "Processing: $REPO_NAME"
CLONE_DIR="$WORK_DIR/$REPO_NAME"
# Clone bare repo to working directory
if [[ -d "$CLONE_DIR/.git" ]]; then
log " Directory exists, skipping clone"
else
log " Cloning from bare repo..."
if ! git clone --quiet "$BARE_REPO" "$CLONE_DIR" 2>>"$LOG_FILE"; then
log_error " Failed to clone $REPO_NAME"
((FAILED++)) || true
continue
fi
fi
cd "$CLONE_DIR"
# Check if already initialized in Radicle
if $RAD_CMD . >/dev/null 2>&1; then
log_warn " Already initialized in Radicle, skipping"
cd "$WORK_DIR"
((SKIPPED++)) || true
continue
fi
# Get current branch
CURRENT_BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "main")
# Normalize to main if needed
if [[ "$CURRENT_BRANCH" != "main" ]]; then
log " Normalizing branch: $CURRENT_BRANCH -> main"
git branch -m "$CURRENT_BRANCH" main 2>>"$LOG_FILE" || true
fi
# Get description from git config if available
DESCRIPTION=$(git config --get gitweb.description 2>/dev/null || echo "Migrated from Forgejo")
# Truncate description if too long
if [[ ${#DESCRIPTION} -gt 255 ]]; then
DESCRIPTION="${DESCRIPTION:0:252}..."
fi
# Initialize in Radicle
log " Initializing in Radicle..."
if $RAD_CMD init \
--name "$REPO_NAME" \
--description "$DESCRIPTION" \
--default-branch main \
--public 2>>"$LOG_FILE"; then
# Push to radicle
log " Pushing to Radicle..."
if git push rad main 2>>"$LOG_FILE"; then
RID=$($RAD_CMD . 2>/dev/null || echo "unknown")
log_success " Migrated: $REPO_NAME -> $RID"
((MIGRATED++)) || true
else
log_error " Failed to push $REPO_NAME"
((FAILED++)) || true
fi
else
log_error " Failed to init $REPO_NAME in Radicle"
((FAILED++)) || true
fi
cd "$WORK_DIR"
done
echo ""
log "========================================"
log "Migration Summary:"
log " Total repos: $TOTAL"
log " Migrated: $MIGRATED"
log " Skipped: $SKIPPED"
log " Failed: $FAILED"
log "========================================"
echo ""
log "Verify with: $RAD_CMD ls"
log "Configure helix to follow: rad-system follow <box-nid> --alias mossnet"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+9
View File
@@ -0,0 +1,9 @@
age-encryption.org/v1
-> ssh-ed25519 kgCrKA WzvIX43OcJw/qxPgTw3iUjorQ0ahFHYZEmnghnUz/xc
HtNx7XqWFZDNpjNiquxfRrnP/TcXxoPn6mMB0BMjlJw
-> ssh-ed25519 6DaCrw dZ9etYRaGuAO0gcA3Krdgvcg9vkwctAtJzKevgjE3wc
gbWQHzO//bGp3Jl513GIgzaM4FzJSiA5thOSWWsx7ik
--- QeO3vdOBbisSZaBECB1Wa603H6P7lXDJwxerJ8gH4+M
þlGêýX­É.ø­“®«$lp^^ ”0üzK88 QuQ•Þïq;Y­ðŽ85³ÈRM÷4†ÖçI:gŒßqÿ“žípܺÏåž,OãdPk­RèÚrq¤UëíM•‹!ž¥=EuÈ2 [_à!%CE—ê
íø"—åo² 3wû„l" :TŸ6àºÁTâÜ[[Pn”Éq¡Bì 7'àFü¨8ŸŒË:6E¦Í³àʽ\¾ ó#ê1ëÄžå¨K¾jŠ.·Ð¬êê)V³™ŸBN ê"Ë÷S,Àïµ^ïêDÅ&Æ©¨¾£h´%*ågé°ÂòvìN^¨-Òô2PïBñÃb¬'? ˆL¯jF,b«ç:¡,ˆx#ÑįÑ UY€_ÁQpÈÝø+ëjÂ!ÿU­Š ‡;úAÞúÑ˜Íærå‡5«Ó0ƒ¤Aá|<èÉ=j“ß²s»™q;bŠŸ!BW'Ý´¼8ÄAˆsË#ô= êêi½`|œNÙ¬ÇK‹o̰H–ö“)ŠŒÞ°
Î?Á"±„ 7–pç¯WÕÿä•áÒ
+60 -11
View File
@@ -7,9 +7,21 @@ let
helix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAKrL6IDHNnHmxi0q9nzu87NOyidPm3HpE7klU368lEf root@helix";
helix2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK2G81z1E51ioJQGLHnTJEjgSdBqLM6mb72Z+0atE6Bf root@helix";
work = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHOnfDvR2D2nGnC+DZYDUXiokzz+eLfZwkp+O8WjWutp anishlakhwara@Anishs-MacBook-Pro.local";
curve = [ system user ];
allUserKeys = [ system user mossnet ];
systemOnly = [ system mossnet lituus helix ];
curve = [
system
user
];
allUserKeys = [
system
user
mossnet
];
systemOnly = [
system
mossnet
lituus
helix
];
in
{
"taskwarrior-private.age".publicKeys = curve;
@@ -20,10 +32,22 @@ in
"borg-password.age".publicKeys = systemOnly;
"borg-key.age".publicKeys = systemOnly;
"helix-wg.age".publicKeys = [ helix2 helix ];
"freshrss-dbpass.age".publicKeys = [ helix2 helix ];
"woodpecker-server-secrets.age".publicKeys = [ helix2 helix ];
"gitea-dbpass.age".publicKeys = [ helix helix2 ];
"helix-wg.age".publicKeys = [
helix2
helix
];
"freshrss-dbpass.age".publicKeys = [
helix2
helix
];
"woodpecker-server-secrets.age".publicKeys = [
helix2
helix
];
"gitea-dbpass.age".publicKeys = [
helix
helix2
];
"synapse-config.age".publicKeys = [ lituus ];
"synapse-database-password.age".publicKeys = [ lituus ];
@@ -31,12 +55,37 @@ in
"telegram-matrix-env.age".publicKeys = [ lituus ];
"wallabag.age".publicKeys = [ mossnet ];
"woodpecker-agent-secret.age".publicKeys = [ mossnet helix helix2 ];
"woodpecker-agent-secret.age".publicKeys = [
mossnet
helix
helix2
];
"box-wg.age".publicKeys = [ mossnet ];
"wallabag-password.age".publicKeys = [ mossnet ];
"wallabag-secret.age".publicKeys = [ mossnet ];
"work-wg.age".publicKeys = [ work user system ];
"github-token.age".publicKeys = [ work user system mossnet ];
"anthropicToken.age".publicKeys = [ work user system mossnet ];
"work-wg.age".publicKeys = [
work
user
system
];
"github-token.age".publicKeys = [
work
user
system
mossnet
];
"anthropicToken.age".publicKeys = [
work
user
system
mossnet
];
# Radicle node keys
"radicle-box-key.age".publicKeys = [ mossnet ];
"radicle-helix-key.age".publicKeys = [
helix
helix2
];
}