Compare commits

...

26 Commits

Author SHA1 Message Date
Alexander Heldt d0ef7f5b7e manatee: Add wl-clipboard 2026-07-26 07:36:05 +00:00
Alexander Heldt 5eacb60b50 manatee: Add claude 2026-07-26 07:35:53 +00:00
Alexander Heldt a33a22aa50 Update solo-referee flake input 2026-07-26 07:34:21 +00:00
Alexander Heldt 56c04b1f70 manatee: Guard podman containers against crash-looping
Add a start-limit (5 restarts / 5 min) to the romm, romm-db, romm-redis
and homeassistant podman services so a failing container enters a
`failed` state instead of retrying forever. A slow crash-loop (~5s per
attempt) stays under systemd's default 5-starts-per-10s limit, so a
longer window is needed to catch it.
2026-07-26 07:32:16 +00:00
Alexander Heldt cd81da9bfd Update puppy-tracker flake input 2026-07-24 15:19:12 +00:00
Alexander Heldt ed3e5844a0 Update puppy-tracker flake input 2026-07-24 12:31:14 +00:00
Alexander Heldt 08a3bae6c6 manatee: Add solo-referee module 2026-07-24 12:26:33 +00:00
Alexander Heldt cdb657bd36 pinwheel: Set hyprland config variant 2026-07-23 10:56:37 +02:00
Alexander Heldt 538fb0390a pinwheel: set ASKPASS
And cache the git signing key
2026-07-23 10:56:01 +02:00
Alexander Heldt 8f22f82066 pinwheel: Fix emacs startup
And don't force the async path, wait at least 0.1sec for terminal to
answer with capabilities. Using the async path broke the answer and
inserted 4 spaces in the beginning of the buffer
2026-07-23 10:55:00 +02:00
Alexander Heldt 82b7ce8ccc pinwheel/tadpole: Rename alex.pinwheel-tadpole-ed25519 2026-07-21 09:38:35 +02:00
Alexander Heldt 99b5cb3380 Update puppy-tracker flake input 2026-07-21 07:20:31 +00:00
Alexander Heldt 100a7c455f pinwheel: Remove bitwarden gui client 2026-07-21 08:58:55 +02:00
Alexander Heldt 23bc741d5e Update flake inputs 2026-07-21 08:58:53 +02:00
Alexander Heldt 64e71cce31 pinwheel: Add ai module
With work/personal claude configs
2026-07-21 08:58:52 +02:00
Alexander Heldt 0b3e8c162a pinwheel: Ensure hyprland monitor detection works on start 2026-07-21 08:58:50 +02:00
Alexander Heldt 421c6179d6 manatee: Add tmux module 2026-07-17 09:15:46 +00:00
Alexander Heldt 2c80e01a6e Update puppy-tracker flake input 2026-07-13 06:16:35 +00:00
Alexander Heldt 12eb945230 Update puppy-tracker flake input 2026-07-09 19:51:51 +00:00
Alexander Heldt 42079c2268 Update puppy-tracker flake input 2026-07-09 20:35:48 +02:00
Alexander Heldt 4742e0f593 manatee: Add puppy-tracker behind virtual host puppy.ppp.pm 2026-07-09 20:34:43 +02:00
Alexander Heldt 3446756cc1 manatee: Add invite code secret for puppy-tracker 2026-07-09 20:34:12 +02:00
Alexander Heldt aa7ef695f4 manatee: Add ability to specify public url for homepage card 2026-07-09 20:33:22 +02:00
Alexander Heldt ff02728d82 manatee: Add puppy.ppp.pm sub-domain
With cert and ip update
2026-07-09 16:59:13 +00:00
Alexander Heldt e2f62568b5 Update puppy-tracker flake input 2026-07-04 09:27:46 +00:00
Alexander Heldt 304d07fea3 Update puppy-tracker flake input 2026-07-04 09:21:06 +00:00
27 changed files with 419 additions and 98 deletions
Generated
+96 -63
View File
@@ -43,11 +43,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1780756231, "lastModified": 1782073106,
"narHash": "sha256-tXQxKdG5716uB9/LIkLQqQwHKf5mRSpHoZhz3lyI2Cg=", "narHash": "sha256-dnS5SaZlPqR1E0dPXaPc+lFkBwLUbAgbwsVMk7uA6dY=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "6ecde03f47172753fe5a2f334f9d3facfb7e6784", "rev": "6d6e2384f381def4ea4ea81543cba4bbdac72457",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -106,11 +106,11 @@
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1782043410, "lastModified": 1784109865,
"narHash": "sha256-OD+6NEnJFlFIsyjHD6io0TDrNAx7wk/LDixkQD16FsQ=", "narHash": "sha256-UCJ0O811UeGSe3GlLj8QxVa4ykHRfjl9rZvqFpiECME=",
"owner": "nix-community", "owner": "nix-community",
"repo": "emacs-overlay", "repo": "emacs-overlay",
"rev": "fee960f0f42d444773d55c495f53fd9214322893", "rev": "422352494e740d44d7551549916655b122a9fd01",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -205,25 +205,21 @@
"type": "github" "type": "github"
} }
}, },
"gitignore": { "flake-utils_4": {
"inputs": { "inputs": {
"nixpkgs": [ "systems": "systems_7"
"hyprland",
"pre-commit-hooks",
"nixpkgs"
]
}, },
"locked": { "locked": {
"lastModified": 1709087332, "lastModified": 1731533236,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "hercules-ci", "owner": "numtide",
"repo": "gitignore.nix", "repo": "flake-utils",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "hercules-ci", "owner": "numtide",
"repo": "gitignore.nix", "repo": "flake-utils",
"type": "github" "type": "github"
} }
}, },
@@ -255,11 +251,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1782051614, "lastModified": 1783963347,
"narHash": "sha256-xBRAhYLEXcjp8hM2tkkTTLb6PWU7VDxDoogl25g7Ezs=", "narHash": "sha256-r376E2XpakiXwModDHIxlvB6qLq4iFVEq730vxOO4JY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "d1ccd0721ec599866622665f3651e19e6e2d4c6a", "rev": "a45a7c451455a51ae740ec3bce4024b312809c29",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -313,11 +309,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1776426399, "lastModified": 1782566056,
"narHash": "sha256-RUESLKNikIeEq9ymGJ6nmcDXiSFQpUW1IhJ245nL3xM=", "narHash": "sha256-haEZcHzYrePnjFOYSWTbxm/Nrla0aPslJfmvdCvqtVc=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprgraphics", "repo": "hyprgraphics",
"rev": "68d064434787cf1ed4a2fe257c03c5f52f33cf84", "rev": "c6e7b9f673f4360bc813d3dc75028f75ee88d3f8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -345,11 +341,11 @@
"xdph": "xdph" "xdph": "xdph"
}, },
"locked": { "locked": {
"lastModified": 1782059327, "lastModified": 1784043142,
"narHash": "sha256-DkXzKpyckIEOAdPjNnceCSsb6i9pWPShcX+igU1D03s=", "narHash": "sha256-vd4VSlddmDAToJv/twyr0O8Siq4U/sOIXeo6DFZIolc=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "Hyprland", "repo": "Hyprland",
"rev": "8f91ba920f3d791e1e2eddb817d7da7ce8b1872a", "rev": "79bc0ca16e7cca40c247a9200634d150fa8193d1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -365,11 +361,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1780083791, "lastModified": 1782811467,
"narHash": "sha256-epTJKmTCNL1Hm6/YdEWAgiOMVBSzC9/v/rjyOieP3yA=", "narHash": "sha256-JP0D8r8o9+jnYk0/B5O722La+oZeC5iNQ3lonKFTmbQ=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "contrib", "repo": "contrib",
"rev": "bf1a7cdb086587e6bed6e8ecd285a81c01a11c54", "rev": "3dcbce715ae8b93107fa8632db15bf976862a573",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -411,11 +407,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1776426575, "lastModified": 1782563850,
"narHash": "sha256-KI6nIfVihn/DPaeB5Et46Xg3dkNHrrEtUd5LBBVomB0=", "narHash": "sha256-rs/EzgrgPHbCtJjFZN4aR1HYldH/0NtGAempWVpWQTs=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-guiutils", "repo": "hyprland-guiutils",
"rev": "a968d211048e3ed538e47b84cb3649299578f19d", "rev": "5ba080ee036c30cb2485f2647ff8a61f7aa08178",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -517,11 +513,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772462885, "lastModified": 1782554491,
"narHash": "sha256-5pHXrQK9zasMnIo6yME6EOXmWGFMSnCITcfKshhKJ9I=", "narHash": "sha256-+p3MlyN/nqRefcf2IckPlGRUn9+hielqpS9XClbLleM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprtoolkit", "repo": "hyprtoolkit",
"rev": "9af245a69fa6b286b88ddfc340afd288e00a6998", "rev": "bdba25ced39ea39ab004a8f31593ba0b0ff1ca35",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -542,11 +538,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1780251518, "lastModified": 1783002634,
"narHash": "sha256-fG9xbb1SOAAJ+2kJRakp3ch+BmA/3dEg/K3PoAZTKkw=", "narHash": "sha256-xGqHIUK0wIZoW7SiMalwvO6uGOO/VrlQwoRobpE7dDI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "40ede2e7bdec80ba5d4c443160d905e9f841ae5f", "rev": "41fb809557abd29a57151b6e1aaeabd05f9437e1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -737,11 +733,11 @@
"systems": "systems_5" "systems": "systems_5"
}, },
"locked": { "locked": {
"lastModified": 1781977476, "lastModified": 1783761716,
"narHash": "sha256-KQYpaKtE5d5ubjxJsz+PmzhKE+jutoJyaF8yjYRDlYI=", "narHash": "sha256-1I1HEeTEBHcBy/jIO2l5NiJJZSqrQSMjwKo9A9ONZr4=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-jetbrains-plugins", "repo": "nix-jetbrains-plugins",
"rev": "7e94828396922aa446f0c6799942350257064a6f", "rev": "dc3c00516880f4fd82671bea4b3500451b29958d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -755,11 +751,11 @@
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1781622756, "lastModified": 1784100666,
"narHash": "sha256-JrPh4M6S7aPsEE9tOENuZrxC6o2szSLlK+t4+nLke9s=", "narHash": "sha256-HF/mrw5NYQfKFZgkfV2h1UL5/E3ccfsE2XJ1AbbLLJ0=",
"owner": "nixos", "owner": "nixos",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "08018c72174a4df5657f8d94178ac69fb9c243e5", "rev": "fccfa9031a85b78a437f2f153c1f6449f3bc3185",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -787,11 +783,11 @@
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1781216227, "lastModified": 1784011430,
"narHash": "sha256-9mUW6gNwoN2SWc/l0fW4svPNOulXLl8ijqKyeSOGgJE=", "narHash": "sha256-lDebytrYdd47IBLwvNOD+6AGeoqZ78CIKlp70hzW280=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a0374025a863d007d98e3297f6aa46cc3141c2f0", "rev": "8eeec934ae0dbeca3d7868c059568a65c08b2fc3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -816,11 +812,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1781577229, "lastModified": 1784007870,
"narHash": "sha256-lrp67w8AulE9Ks53n27I45ADSzbOCn4H+CNW1Ck8B+8=", "narHash": "sha256-djcLt/JJphyNt4eDY9XTly+/WbCK5lqWq9lSgCmJkkQ=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "567a49d1913ce81ac6e9582e3553dd90a955875f", "rev": "18b9261cb3294b6d2a06d03f96872827b8fe2698",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -854,18 +850,17 @@
"pre-commit-hooks": { "pre-commit-hooks": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [ "nixpkgs": [
"hyprland", "hyprland",
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1778507602, "lastModified": 1783008725,
"narHash": "sha256-kTwur1wV+01SdqskVMSo6JMEpg71ps3HpbFY2GsflKs=", "narHash": "sha256-jGiy6+sxjNWXSjp25uoJuNfyH9zBK1PEDY0lVoL4ibQ=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "61ab0e80d9c7ab14c256b5b453d8b3fb0189ba0a", "rev": "bca82caa46d5ec0f5d422c61fb1e30bc51313cbe",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -882,11 +877,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1782397486, "lastModified": 1784906229,
"narHash": "sha256-biua4k3PXXnLTkOyNOCbciTcpkaUkc72j24jhaH8UBk=", "narHash": "sha256-9ZzpwieFwushXgbZZj1W4i8uhI0dmLZCcQSb6qVhn18=",
"ref": "main", "ref": "main",
"rev": "709a051afb8e4589e64dd6a8859abbd117ec876f", "rev": "374e630d8fd0fa063753ffaa3537ada4fb4bc11e",
"revCount": 3, "revCount": 55,
"type": "git", "type": "git",
"url": "ssh://gitea@git.ppp.pm:1122/alex/puppy-tracker.git" "url": "ssh://gitea@git.ppp.pm:1122/alex/puppy-tracker.git"
}, },
@@ -915,10 +910,33 @@
"nixpkgs": "nixpkgs_3", "nixpkgs": "nixpkgs_3",
"pppdotpm-site": "pppdotpm-site", "pppdotpm-site": "pppdotpm-site",
"puppy-tracker": "puppy-tracker", "puppy-tracker": "puppy-tracker",
"solo-referee": "solo-referee",
"whib-backend": "whib-backend", "whib-backend": "whib-backend",
"whib-frontend": "whib-frontend" "whib-frontend": "whib-frontend"
} }
}, },
"solo-referee": {
"inputs": {
"flake-utils": "flake-utils_4",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1785015267,
"narHash": "sha256-NHaaFMznPus9jABGXlSHo++bYcbQeBnxvYPt/CzBEHg=",
"ref": "main",
"rev": "42af5dc48d1e2466a6b09273c7c96dfe2ab13c0b",
"revCount": 10,
"type": "git",
"url": "ssh://gitea@git.ppp.pm:1122/alex/solo-referee.git"
},
"original": {
"ref": "main",
"type": "git",
"url": "ssh://gitea@git.ppp.pm:1122/alex/solo-referee.git"
}
},
"systems": { "systems": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,
@@ -1009,6 +1027,21 @@
"type": "github" "type": "github"
} }
}, },
"systems_7": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"whib-backend": { "whib-backend": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -1079,11 +1112,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1780133819, "lastModified": 1782644412,
"narHash": "sha256-0YPKIY3dlnR7SPq7Z8ekFVvzFsfeiAtEj+QUI3KHrlI=", "narHash": "sha256-/iSa/bL1QQFLv+uJ9gI0N87J8gOeZXvca7EjoPGKE6w=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "4a170c0ba96fd37374f93d8f91c9ed91814828ac", "rev": "c01c99fc278ec68c82e9865923088f043c7c1621",
"type": "github" "type": "github"
}, },
"original": { "original": {
+6
View File
@@ -92,6 +92,12 @@
# url = "path:/home/alex/code/puppy-tracker"; # url = "path:/home/alex/code/puppy-tracker";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
solo-referee = {
url = "git+ssh://gitea@git.ppp.pm:1122/alex/solo-referee.git?ref=main";
# url = "path:/home/alex/code/solo-referee";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = outputs =
+2
View File
@@ -15,6 +15,8 @@
home.packages = [ home.packages = [
pkgs.streamrip pkgs.streamrip
pkgs.claude-code
pkgs.wl-clipboard
]; ];
home.stateVersion = "24.11"; home.stateVersion = "24.11";
+13
View File
@@ -46,6 +46,19 @@
"--http-timeout=60" "--http-timeout=60"
]; ];
}; };
"puppy.ppp.pm" = {
dnsProvider = "hetzner";
environmentFile = config.age.secrets.hetzner-dns.path;
group = "nginx";
extraLegoFlags = [
"--dns.resolvers=1.1.1.1:53,8.8.8.8:53"
"--dns.propagation-wait=60s"
"--dns-timeout=60"
"--http-timeout=60"
];
};
}; };
}; };
+2
View File
@@ -12,6 +12,7 @@ in
ssh.enable = true; ssh.enable = true;
git.enable = true; git.enable = true;
tmux.enable = true;
nginx.enable = true; nginx.enable = true;
syncthing.enable = true; syncthing.enable = true;
@@ -25,6 +26,7 @@ in
homepage.enable = true; homepage.enable = true;
disk-smart.enable = true; disk-smart.enable = true;
puppy-tracker.enable = true; puppy-tracker.enable = true;
solo-referee.enable = true;
}; };
}; };
} }
@@ -117,6 +117,16 @@ in
hardware.bluetooth.enable = true; hardware.bluetooth.enable = true;
# Give up and enter a `failed` state (visible in `systemctl --failed`) if the
# container restarts more than 5 times in 5 minutes, instead of crash-looping
# forever. The window is deliberately long: a slow crash-loop (~5s per attempt)
# stays under systemd's default 5-starts-per-10s limit and would otherwise
# retry indefinitely.
systemd.services.podman-homeassistant = {
startLimitIntervalSec = 300;
startLimitBurst = 5;
};
virtualisation.oci-containers = { virtualisation.oci-containers = {
backend = "podman"; backend = "podman";
@@ -241,7 +251,7 @@ in
]; ];
script = '' script = ''
SUBDOMAINS="ha komga romm" SUBDOMAINS="ha komga romm puppy"
INTERFACE="enp3s0" INTERFACE="enp3s0"
CURRENT_IP=$(curl -s --fail --interface "$INTERFACE" ifconfig.me) CURRENT_IP=$(curl -s --fail --interface "$INTERFACE" ifconfig.me)
+12 -2
View File
@@ -9,8 +9,13 @@ let
nginxEnabled = config.mod.nginx.enable; nginxEnabled = config.mod.nginx.enable;
services = config.mod.homepage.services; services = config.mod.homepage.services;
serviceToCard = svc: '' serviceToCard =
<a class="card" href="http://manatee:${toString svc.port}"> svc:
let
href = if svc.url != null then svc.url else "http://manatee:${toString svc.port}";
in
''
<a class="card" href="${href}">
<div class="name">${svc.name}</div> <div class="name">${svc.name}</div>
<div class="desc">${svc.description}</div> <div class="desc">${svc.description}</div>
<div class="port">:${toString svc.port}</div> <div class="port">:${toString svc.port}</div>
@@ -83,6 +88,11 @@ in
name = lib.mkOption { type = lib.types.str; }; name = lib.mkOption { type = lib.types.str; };
port = lib.mkOption { type = lib.types.port; }; port = lib.mkOption { type = lib.types.port; };
description = lib.mkOption { type = lib.types.str; }; description = lib.mkOption { type = lib.types.str; };
url = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Link target for the card; defaults to http://manatee:<port>.";
};
}; };
} }
); );
@@ -6,6 +6,7 @@
}: }:
let let
enabled = config.mod.puppy-tracker.enable; enabled = config.mod.puppy-tracker.enable;
nginxEnabled = config.mod.nginx.enable;
port = 8089; port = 8089;
in in
{ {
@@ -25,6 +26,8 @@ in
name = "Puppy Tracker"; name = "Puppy Tracker";
port = port; port = port;
description = "Sleep, meals, pees, poos"; description = "Sleep, meals, pees, poos";
# Login needs HTTPS (Secure cookies), so link to the public vhost.
url = "https://puppy.ppp.pm";
} }
]; ];
@@ -32,6 +35,29 @@ in
enable = true; enable = true;
inherit port; inherit port;
openFirewall = true; openFirewall = true;
# Served publicly over HTTPS via the nginx vhost below.
secureCookies = true;
# Shared registration secret; the file holds `PUPPY_INVITE_CODE=...`.
inviteCodeFile = config.age.secrets."puppy-tracker-invite-code".path;
}; };
services.nginx = lib.mkIf nginxEnabled {
virtualHosts."puppy.ppp.pm" = {
forceSSL = true;
useACMEHost = "puppy.ppp.pm";
# Photo uploads are up to 15 MB; give nginx headroom over its 1 MB default.
extraConfig = ''
client_max_body_size 20m;
'';
locations."/" = {
proxyPass = "http://127.0.0.1:${toString port}";
};
};
};
age.secrets."puppy-tracker-invite-code".file =
../../../../secrets/manatee/puppy-tracker-invite-code.age;
}; };
} }
+14
View File
@@ -26,6 +26,16 @@ let
- 'Thumbs.db' - 'Thumbs.db'
- '.DS_Store' - '.DS_Store'
''; '';
# Give up and enter a `failed` state (visible in `systemctl --failed`) if a
# container restarts more than 5 times in 5 minutes, instead of crash-looping
# forever. The window is deliberately long: a slow crash-loop (~5s per attempt)
# stays under systemd's default 5-starts-per-10s limit and would otherwise
# retry indefinitely.
crashLoopGuard = {
startLimitIntervalSec = 300;
startLimitBurst = 5;
};
in in
{ {
options = { options = {
@@ -51,6 +61,10 @@ in
"d /var/lib/romm/assets 0755 root root -" "d /var/lib/romm/assets 0755 root root -"
]; ];
systemd.services.podman-romm = crashLoopGuard;
systemd.services.podman-romm-db = crashLoopGuard;
systemd.services.podman-romm-redis = crashLoopGuard;
systemd.services.romm-net = { systemd.services.romm-net = {
description = "Create Podman network for RomM"; description = "Create Podman network for RomM";
after = [ "podman.service" ]; after = [ "podman.service" ];
@@ -0,0 +1,46 @@
{
inputs,
lib,
config,
...
}:
let
enabled = config.mod.solo-referee.enable;
port = 8090;
in
{
options = {
mod.solo-referee = {
enable = lib.mkEnableOption "Enable solo-referee module";
};
};
imports = [
inputs.solo-referee.nixosModules.default
];
config = lib.mkIf enabled {
mod.homepage.services = [
{
name = "Solo Referee";
port = port;
description = "Solo-RPG tool with Claude as GM";
# url omitted → homepage links to http://manatee:${port}.
}
];
services.solo-referee = {
enable = true;
inherit port;
# Reachable on the LAN / Tailscale at manatee:${port}; no public vhost.
address = "0.0.0.0";
openFirewall = true;
# Anthropic API key kept out of the store; the file holds
# `ANTHROPIC_API_KEY=...`. Without it the offline stub GM runs.
apiKeyFile = config.age.secrets."solo-referee-api-key".path;
};
age.secrets."solo-referee-api-key".file =
../../../../secrets/manatee/solo-referee-api-key.age;
};
}
+71
View File
@@ -0,0 +1,71 @@
{
pkgs,
lib,
config,
...
}:
let
enabled = config.mod.tmux.enable;
in
{
options = {
mod.tmux = {
enable = lib.mkEnableOption "enable tmux module";
};
};
config = lib.mkIf enabled {
home-manager.users.alex = {
programs.tmux = {
enable = true;
baseIndex = 1;
keyMode = "vi";
# Allow vi mode to be enabled instantly
escapeTime = 0;
plugins = [ pkgs.tmuxPlugins.sensible ];
extraConfig = ''
set -g renumber-windows on
# https://old.reddit.com/r/tmux/comments/mesrci/tmux_2_doesnt_seem_to_use_256_colors/
set -g default-terminal "xterm-256color"
set -ga terminal-overrides ",*256col*:Tc"
set -ga terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[ q'
set-environment -g COLORTERM "truecolor"
set-option -g allow-rename off
# Remove date/time etc. on the right side
set -g status-right ""
bind r source-file ~/.config/tmux/tmux.conf \; display "Config reloaded"
# Remove accidental `suspend-client` triggers
unbind C-z
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
# Move panes shortcuts
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Resize panes
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# Move windows
bind -r Left swap-window -t -1 \; select-window -t -1
bind -r Right swap-window -t +1 \; select-window -t +1
'';
};
};
};
}
-2
View File
@@ -16,7 +16,6 @@
home.packages = [ home.packages = [
inputs.whib-backend.packages.${pkgs.stdenv.hostPlatform.system}.whib-import inputs.whib-backend.packages.${pkgs.stdenv.hostPlatform.system}.whib-import
# pkgs.beekeeper-studio # pkgs.beekeeper-studio
pkgs.bitwarden-desktop
pkgs.gimp pkgs.gimp
pkgs.zip pkgs.zip
pkgs.unzip pkgs.unzip
@@ -27,7 +26,6 @@
pkgs.onlyoffice-desktopeditors pkgs.onlyoffice-desktopeditors
pkgs.wdisplays pkgs.wdisplays
pkgs.vlc pkgs.vlc
pkgs.claude-code
pkgs.opencode pkgs.opencode
]; ];
+29
View File
@@ -0,0 +1,29 @@
{
pkgs,
lib,
config,
...
}:
let
enabled = config.mod.ai.enable;
in
{
options = {
mod.ai = {
enable = lib.mkEnableOption "enable ai module";
};
};
config = lib.mkIf enabled {
home-manager.users.alex = {
home.packages = [
pkgs.claude-code
];
programs.zsh.shellAliases = {
wclaude = "CLAUDE_CONFIG_DIR=$HOME/.claude-personal claude";
pclaude = "CLAUDE_CONFIG_DIR=$HOME/.claude-work claude";
};
};
};
}
+2
View File
@@ -42,6 +42,8 @@ in
}; };
vm.enable = true; vm.enable = true;
scripts.enable = true; scripts.enable = true;
ai.enable = true;
}; };
}; };
} }
+1 -1
View File
@@ -58,7 +58,7 @@
#+END_SRC #+END_SRC
*** This makes emacsclient startup faster in TUI-mode *** This makes emacsclient startup faster in TUI-mode
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(setq-default xterm-query-timeout nil) (setq-default xterm-query-timeout 0.1)
#+END_SRC #+END_SRC
*** Disable startup messages *** Disable startup messages
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
+37
View File
@@ -6,6 +6,38 @@
}: }:
let let
enabled = config.mod.git.enable; enabled = config.mod.git.enable;
# Wrapper around `ssh-keygen` used as git's SSH signing program. Before a
# signing operation it ensures the passphrase-protected signing key is loaded
# into the agent — `ssh-keygen -Y sign` reads the key from disk and re-prompts
# every commit otherwise, since `AddKeysToAgent` only ever caches auth keys.
# Loading it once (through the GUI askpass) lets later commits reuse the
# cached key from the agent. Verification and every other op pass straight
# through to the real ssh-keygen untouched.
sshSignWrapper = pkgs.writeShellApplication {
name = "git-ssh-sign";
runtimeInputs = [
pkgs.openssh
pkgs.gawk
pkgs.gnugrep
];
text = ''
key="${config.age.secrets."alex.pinwheel-github.com-signing".path}"
case " $* " in
*" -Y sign "*)
fp=""
fp="$(ssh-keygen -lf "$key.pub" 2>/dev/null | awk '{print $2}')" || true
if [ -n "$fp" ] && ! ssh-add -l 2>/dev/null | grep -qF "$fp"; then
# </dev/null detaches stdin so ssh-add uses SSH_ASKPASS (the GUI).
ssh-add "$key" </dev/null || true
fi
;;
esac
exec ssh-keygen "$@"
'';
};
in in
{ {
options = { options = {
@@ -33,6 +65,11 @@ in
# Tells Git to use SSH instead of the default GPG # Tells Git to use SSH instead of the default GPG
gpg.format = "ssh"; gpg.format = "ssh";
# Sign via a wrapper that loads the signing key into the agent on
# first use, so subsequent signed commits reuse the cached key
# instead of re-prompting for the passphrase every time.
gpg.ssh.program = "${sshSignWrapper}/bin/git-ssh-sign";
}; };
}; };
+15 -4
View File
@@ -55,12 +55,22 @@ let
esac esac
} }
# Bind workspaces on startup # Start the event listener first so monitoradded events emitted during
bind_workspaces # session startup are not lost in the gap before we begin reading them.
${pkgs.socat}/bin/socat -U - UNIX-CONNECT:"$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" | while read -r line; do ${pkgs.socat}/bin/socat -U - UNIX-CONNECT:"$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" | while read -r line; do
handle_event "$line" handle_event "$line"
done done &
LISTENER_PID=$!
# Give socat a moment to actually connect before the initial bind.
sleep 0.2
bind_workspaces
# Re-bind once more after the DRM subsystem has had time to enumerate
# external connectors, in case they were not yet present at session start.
(sleep 3; bind_workspaces) &
wait $LISTENER_PID
''; '';
in in
{ {
@@ -87,6 +97,7 @@ in
wayland.windowManager.hyprland = { wayland.windowManager.hyprland = {
enable = true; enable = true;
systemd.enable = false; systemd.enable = false;
configType = "hyprlang";
extraConfig = '' extraConfig = ''
exec-once = uwsm app -- waybar exec-once = uwsm app -- waybar
+14 -13
View File
@@ -13,6 +13,20 @@
components = [ "secrets" ]; components = [ "secrets" ];
}; };
home.sessionVariables = {
# gnome-keyring's PAM hooks export SSH_AUTH_SOCK pointing at a dead gcr
# socket (gcr-ssh-agent is disabled above), which shadows openssh's own
# agent and silently breaks passphrase caching. Force it back to the
# openssh agent started by `programs.ssh.startAgent`.
SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/ssh-agent";
# Route passphrase prompts through seahorse's GUI askpass instead of the
# terminal. `prefer` uses the GUI even when a tty is attached (ssh only
# falls back to askpass with no controlling terminal otherwise).
SSH_ASKPASS = "${pkgs.seahorse}/libexec/seahorse/ssh-askpass";
SSH_ASKPASS_REQUIRE = "prefer";
};
programs.ssh = { programs.ssh = {
enable = true; enable = true;
enableDefaultConfig = false; enableDefaultConfig = false;
@@ -135,19 +149,6 @@
owner = "alex"; owner = "alex";
group = "users"; group = "users";
}; };
"alex.pinwheel-tadpole-ed25519" = {
file = ../../../../secrets/pinwheel/alex.pinwheel-tadpole-ed25519.age;
path = "/home/alex/.ssh/alex.pinwheel-tadpole-ed25519";
owner = "alex";
group = "users";
};
"alex.pinwheel-tadpole-ed25519.pub" = {
file = ../../../../secrets/pinwheel/alex.pinwheel-tadpole-ed25519.pub.age;
path = "/home/alex/.ssh/alex.pinwheel-tadpole-ed25519.pub";
owner = "alex";
group = "users";
};
}; };
services.openssh = { services.openssh = {
+8
View File
@@ -56,6 +56,14 @@ in
initContent = lib.strings.concatStringsSep "\n" [ initContent = lib.strings.concatStringsSep "\n" [
"export KEYTIMEOUT=1" "export KEYTIMEOUT=1"
# Point every interactive shell at openssh's ssh-agent. home-manager's
# session vars set this too, but hm-session-vars runs once and is then
# inherited — so a tmux server that outlives this change (or started
# with the stale gcr socket) hands new panes a dead SSH_AUTH_SOCK.
# Re-exporting the fixed path per-shell keeps every pane on the same
# agent, so each key is only ever prompted for once per session.
''export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent"''
"bindkey -v '^?' backward-delete-char" "bindkey -v '^?' backward-delete-char"
"bindkey '^a' beginning-of-line" "bindkey '^a' beginning-of-line"
"bindkey '^e' end-of-line" "bindkey '^e' end-of-line"
-5
View File
@@ -98,11 +98,6 @@ in
path = "${authorizedKeysPath}/alex.pinwheel-tadpole.pub"; path = "${authorizedKeysPath}/alex.pinwheel-tadpole.pub";
}; };
"alex.pinwheel-tadpole-ed25519.pub" = {
file = ../../../../secrets/pinwheel/alex.pinwheel-tadpole-ed25519.pub.age;
path = "${authorizedKeysPath}/alex.pinwheel-tadpole-ed25519.pub";
};
"alex.tadpole-git.ppp.pm" = { "alex.tadpole-git.ppp.pm" = {
file = ../../../../secrets/tadpole/alex.tadpole-git.ppp.pm.age; file = ../../../../secrets/tadpole/alex.tadpole-git.ppp.pm.age;
path = "/home/alex/.ssh/alex.tadpole-git.ppp.pm"; path = "/home/alex/.ssh/alex.tadpole-git.ppp.pm";
@@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 wkRvNA 1U7rIOHezvIpeb7QBkwz+NOgagrPDltkFtWY2N/hdE4
9rLqhxhc4c7cGB9hDPy9r0y5QbDp0CcYFwIWczB0mlU
-> ssh-ed25519 +oNaHQ w9QggF6DOTSMUC5n+7OKpFOM8iDSQakgx/10pIhM9ws
GOk7OQpLh5OjyZTiJQxd7hhN93EcSMnMxueNh6AwCOk
--- mzQrbeaXCVPu0MqNC0iAMLCiZbopyfYanwhsgDjFbZE
¡&ÈEÆÝ¼žÊÆ öfh(tJn´Ð†ç$^åkì[ Cå
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -15,8 +15,6 @@ in {
"pinwheel/alex.pinwheel-backwards.pub.age".publicKeys = [ pinwheel backwards alex ]; "pinwheel/alex.pinwheel-backwards.pub.age".publicKeys = [ pinwheel backwards alex ];
"pinwheel/alex.pinwheel-tadpole.age".publicKeys = [ pinwheel alex ]; "pinwheel/alex.pinwheel-tadpole.age".publicKeys = [ pinwheel alex ];
"pinwheel/alex.pinwheel-tadpole.pub.age".publicKeys = [ pinwheel tadpole alex ]; "pinwheel/alex.pinwheel-tadpole.pub.age".publicKeys = [ pinwheel tadpole alex ];
"pinwheel/alex.pinwheel-tadpole-ed25519.age".publicKeys = [ pinwheel alex ];
"pinwheel/alex.pinwheel-tadpole-ed25519.pub.age".publicKeys = [ pinwheel tadpole alex ];
"pinwheel/alex.pinwheel-github.com.age".publicKeys = [ pinwheel alex ]; "pinwheel/alex.pinwheel-github.com.age".publicKeys = [ pinwheel alex ];
"pinwheel/alex.pinwheel-github.com.pub.age".publicKeys = [ pinwheel alex ]; "pinwheel/alex.pinwheel-github.com.pub.age".publicKeys = [ pinwheel alex ];
"pinwheel/alex.pinwheel-github.com-signing.age".publicKeys = [ pinwheel alex ]; "pinwheel/alex.pinwheel-github.com-signing.age".publicKeys = [ pinwheel alex ];
@@ -44,6 +42,8 @@ in {
"manatee/romm-auth-secret-key.age".publicKeys = [ manatee alex ]; "manatee/romm-auth-secret-key.age".publicKeys = [ manatee alex ];
"manatee/romm-db-password.age".publicKeys = [ manatee alex ]; "manatee/romm-db-password.age".publicKeys = [ manatee alex ];
"manatee/romm-metadata-api-keys.age".publicKeys = [ manatee alex ]; "manatee/romm-metadata-api-keys.age".publicKeys = [ manatee alex ];
"manatee/puppy-tracker-invite-code.age".publicKeys = [ manatee alex ];
"manatee/solo-referee-api-key.age".publicKeys = [ manatee alex ];
"backwards/root.backwards.age".publicKeys = [ backwards alex ]; "backwards/root.backwards.age".publicKeys = [ backwards alex ];
"backwards/root.backwards.pub.age".publicKeys = [ backwards alex ]; "backwards/root.backwards.pub.age".publicKeys = [ backwards alex ];