Author SHA1 Message Date
moons-14 ec3770502d Add central Nix builder and binary cache 2026-08-31 08:07:48 +09:00
moons-14 fda29cd08d update 2026-08-30 06:48:50 +09:00
moons-14 db0a440da4 update Python to 3.14 2026-08-30 05:52:30 +09:00
moons-14 76f5dce9c0 update CodexBar to 0.56.0 2026-08-30 05:52:23 +09:00
moons-14 3b61457718 remove obsolete Codex skill alias 2026-08-30 05:52:16 +09:00
moons-14 c9f1584797 replace Codex Desktop with ChatGPT 2026-08-30 05:52:06 +09:00
moons-14 d51948c307 hugging face 2026-08-29 16:29:42 +09:00
moons-14 9a38e9f614 gpu settings 2026-08-29 16:14:32 +09:00
moons-14 2cb7e76ca1 nix s9 camera 2026-08-27 12:09:55 +09:00
moons-14 749410e032 fix 2026-08-26 21:35:17 +09:00
moons-14 d43f19c20a nix builder 2026-08-26 17:28:09 +09:00
moons-14 32a3067cb0 hardware configuration 2026-08-26 15:53:44 +09:00
moons-14 6e60bd8886 add nix-builder 2026-08-26 13:21:37 +09:00
moons-14 bcf7ef56cf update 2026-08-25 09:24:58 +09:00
moons-14 63e2008423 chrome video play 2026-08-24 02:14:30 +09:00
moons-14 3b8147ff46 codex setting 2026-08-23 14:06:05 +09:00
moons-14 c84f257149 ffmpeg and yt-dlp 2026-08-23 14:04:36 +09:00
moons-14 6347292c1d projects 2026-08-21 05:44:16 +09:00
moons-14 2a82433754 fix(vesktop): restrict WebRTC to public default interface (#67) 2026-08-21 05:31:13 +09:00
moons-14 847ee17b29 linuxPackages 2026-08-21 05:08:30 +09:00
moons-14 95f74aabcd feat 2026-08-21 05:08:30 +09:00
moons-14 717572ae24 feat 2026-08-21 05:08:30 +09:00
moons-14 8086c9a7f3 fix(vesktop): avoid DTLS stalls with multiple interfaces (#66)
* fix(vesktop): add WebRTC IP handling support

* fix(vesktop): constrain WebRTC interface selection
2026-08-21 04:31:24 +09:00
moons-14 eba23455d4 noctalia 2026-08-21 02:32:23 +09:00
moons-14 b3b1031364 fix 2026-08-20 06:18:23 +09:00
moons-14 366ff54403 allow suspend 2026-08-18 10:19:12 +09:00
moons-14 456e9946f4 flake update 2026-08-18 06:56:34 +09:00
moons-14 c104404e5b remove handy 2026-08-18 06:56:28 +09:00
moons-14 cb41932fec add installer keys 2026-08-18 06:29:01 +09:00
moons-14 fa4b7ca404 codex mutable config 2026-08-18 06:25:46 +09:00
moons-14 847d33e83b simplify codex home configuration 2026-08-18 06:12:20 +09:00
moons-14 b2c700e1e4 remove niri window overview bindings 2026-08-18 06:10:56 +09:00
moons-14 c1540d8764 remove noctalia patches 2026-08-18 06:10:43 +09:00
moons-14 5b8c3b1415 remove labwc patch 2026-08-18 06:10:29 +09:00
moons-14 6743569789 remove window-overview 2026-08-18 06:09:11 +09:00
moons-14 70253fc451 evremap 2026-08-18 05:16:18 +09:00
moons-14 5107b80173 feat(ssh): use available SSH agent socket 2026-08-18 05:00:21 +09:00
moons-14 2bdea522cb feat(niri): toggle floating windows with middle click 2026-08-18 05:00:13 +09:00
moons-14 c113d0d46d feat(x1g9): remap VXE mouse buttons 2026-08-18 05:00:05 +09:00
moons-14 fa50be8feb vicinae chrome integuration 2026-08-18 04:41:31 +09:00
moons-14 33ebef4a1e niri keybind 2026-08-18 04:21:16 +09:00
moons-14 94048ef8d5 wallpaper 2026-08-18 04:20:59 +09:00
moons-14 c7627fa1b0 darwin: add stable Xcode and iOS simulator shell (#65)
* darwin: add xcode ios simulator shell

* docs: add iOS simulator setup
2026-08-14 20:35:13 +09:00
moons-14 d68da620ac oh my openagent 2026-08-10 03:25:01 +09:00
moons-14 5f0df47775 codex 2026-08-09 19:54:35 +09:00
moons-14 119342e564 codex 2026-08-09 19:12:02 +09:00
moons-14 1f066e8937 codex 2026-08-09 18:51:09 +09:00
moons-14 0a440e3da8 update codex session usage 2026-08-09 18:13:03 +09:00
moons-14 bdf93ac6bb codex agents prompt 2026-08-09 15:58:40 +09:00
moons-14 9ae5da4d30 zed docker file extension 2026-08-09 15:40:11 +09:00
moons-14 872436b170 skill 2026-08-08 13:14:29 +09:00
moons-14 c14325e29c Update flake.lock 2026-08-08 06:46:59 +09:00
moons-14 45bc66e25f codex prompt 2026-08-08 06:45:22 +09:00
moons-14 78ee2d41ec codex usage vicinae 2026-08-08 05:51:40 +09:00
moons-14 0b1ae13048 window-overview 2026-08-08 04:15:35 +09:00
moons-14 458b0a2cdb galleria tailscale 2026-08-08 00:16:33 +09:00
moons-14 01179f3dc6 desktop: disable system sleep 2026-08-07 22:00:03 +09:00
moons-14 42949fc06c zed: enable Copilot edit predictions 2026-08-07 21:59:57 +09:00
moons-14 a7f514c0f9 opencode: install package through Home Manager 2026-08-07 21:59:47 +09:00
moons-14 9bed1c3e25 zed: add vim keymaps 2026-08-07 21:58:25 +09:00
moons-14 791b6baa83 mod + v toggle 2026-08-07 20:33:44 +09:00
moons-14 349f49e496 fix 2026-08-07 20:33:33 +09:00
moons-14 3166c12448 codex 2026-08-07 18:34:49 +09:00
moons-14 4c459e4aa7 codex back vesion 2026-08-07 18:34:17 +09:00
moons-14 9b9141dd84 lock codex version 2026-08-07 17:30:50 +09:00
moons-14 16e3fda275 ghostty single instance 2026-08-07 14:44:48 +09:00
moons-14 ca36b07839 Display OFF 2026-08-07 06:28:27 +09:00
moons-14 5ebcbb4abf labwc 2026-08-06 17:22:00 +09:00
moons-14 f8fd8a3d99 wallpaper engine 2026-08-06 17:13:02 +09:00
moons-14 16742d2fd7 window overlay 2026-08-05 06:21:26 +09:00
moons-14 15da7affaa window-overview 2026-08-05 05:53:23 +09:00
moons-14 548647fec7 window switch 2026-08-05 05:27:40 +09:00
moons-14 bcbd08c225 wallpaper vicinae 2026-08-05 05:04:22 +09:00
moons-14 a0ae83d24e feat 2026-08-05 04:37:32 +09:00
moons-14 33e09f8e93 normcap-translate 2026-08-05 03:56:16 +09:00
moons-14 eff32fddcd background-opacity 2026-08-05 03:56:16 +09:00
moons-14 8ce3a6082a dns 2026-08-05 03:56:16 +09:00
moons-14 a8246261ad noctalia: add taskbar overview command hook (#61) 2026-08-05 03:54:14 +09:00
moons-14 8b51b5c55f noctalia taskbar 2026-08-05 02:55:46 +09:00
moons-14 e24d85da56 echo cancel 2026-08-05 02:10:48 +09:00
moons-14 01ead9a385 labwc suspend 2026-08-05 02:10:36 +09:00
moons-14 328f11d0ed screencast 2026-08-05 01:40:35 +09:00
moons-14 d877ffc76c nh 2026-08-05 01:40:18 +09:00
moons-14 fe40adaeee activity watch 2026-08-05 00:59:32 +09:00
moons-14 991dde5305 noctalia patch 2026-08-05 00:40:02 +09:00
moons-14 96ce4d768c nani wayland 2026-08-05 00:16:12 +09:00
moons-14 30b1480e50 hazkey 2026-08-04 23:06:25 +09:00
moons-14 71011d7bd1 thunderbird 2026-08-04 23:06:11 +09:00
moons-14 9cced59e58 thunderbird 2026-08-04 23:06:01 +09:00
moons-14 20a601402e rate 2026-08-04 17:03:03 +09:00
moons-14 1b4a5fa5a2 wallpaper engine 2026-08-04 16:58:40 +09:00
moons-14 5fb55f2e6a open ghostty 2026-08-04 16:49:56 +09:00
moons-14 2a3f7ee6ff nani 2026-08-04 16:16:32 +09:00
moons-14 247db71f2d nani 2026-08-04 16:04:44 +09:00
moons-14 a44a83a587 handy 2026-08-04 15:43:12 +09:00
moons-14 1f1d46ea2a find-cursor 2026-08-04 15:26:43 +09:00
moons-14 29c4815b88 screenshot 2026-08-04 14:59:21 +09:00
moons-14 28a46d9990 skill 2026-08-04 14:42:31 +09:00
moons-14 403971eef6 vesktop
CI: NixOS / Check all NixOS configurations (push) Canceled after 0s
2026-08-04 01:22:34 +09:00
moons-14 c62468396d chrome 2026-08-03 23:35:42 +09:00
moons-14 9145b36412 wallpaper 2026-08-03 23:16:21 +09:00
moons-14 f574b1d1e7 obs 2026-08-03 23:16:14 +09:00
moons-14 cf088a6998 labwc 2026-08-03 22:56:44 +09:00
moons-14 e4eb1802d7 screen shot 2026-08-03 22:29:39 +09:00
moons-14 a7c6a1507c ghostty 2026-08-03 22:27:58 +09:00
moons-14 49141e3478 kanshi 2026-08-03 21:45:35 +09:00
moons-14 cc91ad88b0 noctalia doc 2026-08-03 21:44:02 +09:00
moons-14 bb1f81a598 codex bar 2026-08-03 21:42:33 +09:00
moons-14 c0fdd9b4ef vscode 2026-08-03 21:35:44 +09:00
moons-14 aafcc1555d vicinae 2026-08-03 21:31:30 +09:00
moons-14 245f22e094 hash 2026-08-03 20:07:54 +09:00
moons-14 15ca59e43c suspend 2026-08-03 19:59:45 +09:00
moons-14 3627587bc7 niri 2026-08-03 18:17:42 +09:00
moons-14 d90aed6903 vicinae 2026-08-03 17:45:24 +09:00
moons-14 3e57b6c4c1 Keyring 2026-08-03 15:52:28 +09:00
moons-14 bdca6fb2fb lock screen 2026-08-03 15:28:52 +09:00
moons-14 98397cf152 polkit-gnome 2026-08-03 15:11:58 +09:00
moons-14 3162bc0eba neovim 2026-08-03 15:10:03 +09:00
moons-14 c3bb2f4d43 mac dock 2026-08-03 15:08:41 +09:00
moons-14 5edbc6cbb4 zsh 2026-08-03 14:50:42 +09:00
moons-14 bf28275b40 zoom 2026-08-03 14:46:57 +09:00
moons-14 92b4bc7b8d yazi 2026-08-03 14:33:31 +09:00
moons-14 9bbef37010 vscode 2026-08-03 14:33:25 +09:00
moons-14 e708ceee26 nh 2026-08-03 14:32:59 +09:00
moons-14 7604dfb0e3 vlc 2026-08-03 14:04:42 +09:00
moons-14 02f97f73df vicinae 2026-08-03 14:02:41 +09:00
moons-14 cde17e6a68 tealdeer 2026-08-03 13:40:02 +09:00
moons-14 64fe5020d0 ssh 2026-08-03 13:34:02 +09:00
moons-14 843dd0cbf4 slack 2026-08-03 13:32:27 +09:00
moons-14 0060fdae15 gnome app 2026-08-03 13:27:35 +09:00
moons-14 6402cdcf3a nautilus right click 2026-08-03 13:27:23 +09:00
moons-14 118d91f1d5 nautilus 2026-08-03 13:05:38 +09:00
moons-14 b261f4aec7 remote desktop 2026-08-03 13:05:34 +09:00
moons-14 b146081ba8 minecraft 2026-08-03 13:05:24 +09:00
moons-14 6f19ea8f23 prismlauncher 2026-08-03 12:47:45 +09:00
moons-14 aaa4542f25 mangohud 2026-08-03 12:33:25 +09:00
moons-14 d3ce44ff63 loupe 2026-08-03 12:32:10 +09:00
moons-14 fb3254daa1 playerctl 2026-08-03 12:28:50 +09:00
moons-14 e69203ce4c keybind 2026-08-03 12:24:38 +09:00
moons-14 e84fa82710 niri 2026-08-03 11:44:27 +09:00
moons-14 d5e4c90710 fcitx5 on labwc 2026-08-03 11:44:15 +09:00
moons-14 d67d53644e fcitx5 2026-08-03 09:59:01 +09:00
moons-14 f1dd96945a vscode 2026-08-03 09:50:43 +09:00
moons-14 aceb3d4808 labwc 2026-08-02 23:53:38 +09:00
moons-14 ac874a849e grok 2026-08-02 22:06:39 +09:00
moons-14 519f7dd54d gnone apps 2026-08-02 22:04:46 +09:00
moons-14 233ba91309 ghostty 2026-08-02 21:57:19 +09:00
moons-14 e6c80ad5d6 gamemode 2026-08-02 21:48:44 +09:00
moons-14 847d7ee6dd nix-index 2026-08-02 21:48:38 +09:00
moons-14 5e12c1d953 fxitx5 2026-08-02 21:35:35 +09:00
moons-14 dfc4dc79d6 easyeffects 2026-08-02 20:39:24 +09:00
moons-14 5deab38d3c drawio 2026-08-02 20:35:08 +09:00
moons-14 3c674e34c1 docker 2026-08-02 20:33:19 +09:00
moons-14 506602d7e1 vesktop 2026-08-02 20:25:18 +09:00
moons-14 6b4253e1d4 direnv 2026-08-02 20:17:14 +09:00
moons-14 a3660b5733 chatgpt 2026-08-02 20:14:08 +09:00
moons-14 894b18bd10 chrome 2026-08-02 19:57:32 +09:00
moons-14 08effb9e29 celluloid 2026-08-02 19:52:47 +09:00
moons-14 605e63acdb home file 2026-08-02 19:40:54 +09:00
moons-14 12c9d5241b galleria fingerprint 2026-08-02 19:11:42 +09:00
moons-14 ac44bdf22f baobab 2026-08-02 19:07:23 +09:00
moons-14 421ede5d57 atuin 2026-08-02 19:03:25 +09:00
moons-14 7204e3e8f6 1password 2026-08-02 19:00:34 +09:00
moons-14 f696ed6b93 remove pear-desktop 2026-08-02 18:56:37 +09:00
moons-14 d1891382ea 1password 2026-08-02 18:54:40 +09:00
moons-14 4a7516939c galleria disk uuid 2026-08-02 18:28:13 +09:00
moons-14 176cd60d68 feat 2026-08-02 17:54:30 +09:00
moons-14 7c66c15da5 Replace Parsec with Sunshine and Moonlight 2026-07-31 23:56:43 +09:00
moons-14 dddb7e07ab galleria chrome beta 2026-07-31 23:40:25 +09:00
moons-14 9ede34fcfd fix 2026-07-31 23:07:22 +09:00
moons-14 855b8c55cf luncher 2026-07-31 22:49:18 +09:00
moons-14 a51e9584b0 apps 2026-07-31 22:06:53 +09:00
moons-14 3dae1d26ef noctalia 2026-07-31 22:02:52 +09:00
moons-14 06cd9516b3 side folder 2026-07-31 21:24:40 +09:00
moons-14 f3098f2674 feat 2026-07-31 15:29:21 +09:00
moons-14 2f9c8f3d33 text editor 2026-07-31 14:39:43 +09:00
moons-14 82d00fb574 systemd 2026-07-31 14:39:33 +09:00
moons-14 ad6dff2f6a ly 2026-07-31 14:19:55 +09:00
moons-14 54b84c0544 noctalia workspace 2026-07-31 13:58:24 +09:00
moons-14 c3dbcda528 display 2026-07-31 13:58:09 +09:00
moons-14 480a1c3194 display 2026-07-31 13:40:16 +09:00
moons-14 37d4a4a7c5 kmscon 2026-07-31 13:40:08 +09:00
moons-14 e68e2f536f remove app list 2026-07-31 13:26:27 +09:00
moons-14 36f01a084f galleria host 2026-07-31 12:24:17 +09:00
moons-14 e9ab8c2caa sops add host 2026-07-31 12:23:05 +09:00
moons-14 7ef25c5e63 galleria hardware 2026-07-31 12:02:52 +09:00
moons-14 d6026a5bfc update 2026-07-30 18:02:00 +09:00
moons-14 b477446f5c galleria 2026-07-30 16:46:44 +09:00
moons-14 ee9ce66d55 mozc 2026-07-30 16:45:45 +09:00
moons-14 ecabb8b630 nwg-drawer 2026-07-30 16:16:41 +09:00
moons-14 831ae7bbc2 labwc 2026-07-30 15:56:46 +09:00
moons-14 8dc9452d95 labwc 2026-07-30 15:24:55 +09:00
moons-14 c566f426ec zoom 2026-07-30 02:05:35 +09:00
moons-14 e56af06b04 display 2026-07-30 02:05:29 +09:00
moons-14 acb5ed3449 zoom 2026-07-30 01:33:43 +09:00
moons-14 9f40aadab3 vscode 2026-07-30 01:32:32 +09:00
moons-14 55e1e0b5b4 minecraft mac 2026-07-30 01:06:13 +09:00
moons-14 aef1338d79 minecraft 2026-07-29 14:30:22 +09:00
moons-14 5bbf1d42e9 ci 2026-07-29 10:19:59 +09:00
moons-14 f02eeac2a3 parsec 2026-07-29 10:14:22 +09:00
moons-14 e23e0058bd privact 2026-07-29 09:52:32 +09:00
moons-14 e474c38aff parsec 2026-07-29 09:33:54 +09:00
moons-14 04e4bdaeff windows codex update error 2026-07-29 04:57:38 +09:00
moons-14 c02d6936fa windows 2026-07-29 04:54:08 +09:00
moons-14 3f35a54e0a windows 2026-07-29 04:01:25 +09:00
moons-14 601c94a5d8 niri 2026-07-28 01:33:30 +09:00
moons-14 7e8bd33c89 mac 2026-07-28 01:01:21 +09:00
moons-14 6f4f048f4c mac keyboard 2026-07-28 00:45:32 +09:00
moons-14 c2a5e174b9 mac dock 2026-07-28 00:30:46 +09:00
moons-14 b1954ba5be add hosts 2026-07-28 00:19:14 +09:00
moons-14 09a4fd83a7 noctalia 2026-07-28 00:07:48 +09:00
moons-14 1f4ec6b8cd x1g13 2026-07-27 23:45:54 +09:00
moons-14 5132a1af1b vicinae 2026-07-27 23:16:30 +09:00
moons-14 2a02beda38 mac 2026-07-27 22:27:49 +09:00
moons-14 ee0bd37915 mac 2026-07-27 22:04:11 +09:00
moons-14 a8113633db oxker test 2026-07-27 21:29:20 +09:00
moons-14 91bb7e80db feat hosts 2026-07-27 21:18:00 +09:00
moons-14 9bb95535cf fingerprint 2026-07-27 20:57:15 +09:00
moons-14 fcd0d75537 feat 2026-07-27 20:55:05 +09:00
308 changed files with 8911 additions and 1778 deletions
+27
View File
@@ -0,0 +1,27 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/workflows/nix-build.yaml
name: Check NixOS configurations
description: Build every NixOS configuration and the Registry tests
runs:
using: composite
steps:
- name: Build every NixOS configuration
shell: bash
run: |
set -euo pipefail
mapfile -t hosts < <(
nix eval --raw .#nixosConfigurations \
--apply 'configs: builtins.concatStringsSep "\n" (builtins.attrNames configs)'
)
installables=(.#checks.x86_64-linux.registry)
for host in "${hosts[@]}"; do
installables+=(".#nixosConfigurations.${host}.config.system.build.toplevel")
done
nix build \
--keep-going \
--no-link \
--print-build-logs \
--show-trace \
"${installables[@]}"
+22
View File
@@ -0,0 +1,22 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/actions/setup-nix/action.yaml
name: Setup Nix
description: Install Nix and cache the Nix store
runs:
using: composite
steps:
- name: Allow unprivileged user namespaces
if: runner.os == 'Linux'
shell: bash
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 2>/dev/null || true
- name: Install Nix
uses: nixbuild/nix-quick-install-action@9f63be77f412a248c9d9a65a4c82cf066cdf8f0c # v35
with:
nix_conf: |
accept-flake-config = true
max-jobs = auto
- name: Cache Nix store
uses: nix-community/cache-nix-action@7df957e333c1e5da7721f60227dbba6d06080569 # v7.0.2
with:
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('flake.lock') }}
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}-
gc-max-store-size-linux: 4G
+51
View File
@@ -0,0 +1,51 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/workflows/nix-build.yaml
name: "CI: NixOS"
on:
push:
branches:
- main
paths:
- flake.nix
- flake.lock
- "flake/**"
- "hosts/**"
- "libs/**"
- "modules/**"
- "overlays/**"
- "shells/**"
- "tests/**"
- ".github/actions/check-nixos/**"
- ".github/actions/setup-nix/**"
- ".github/workflows/nixos.yaml"
pull_request:
paths:
- flake.nix
- flake.lock
- "flake/**"
- "hosts/**"
- "libs/**"
- "modules/**"
- "overlays/**"
- "shells/**"
- "tests/**"
- ".github/actions/check-nixos/**"
- ".github/actions/setup-nix/**"
- ".github/workflows/nixos.yaml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
check:
name: Check all NixOS configurations
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Nix
uses: ./.github/actions/setup-nix
- name: Check NixOS configurations
uses: ./.github/actions/check-nixos
+48
View File
@@ -0,0 +1,48 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/workflows/update-flake.yaml
name: "Bot: Update flake inputs"
on:
schedule:
- cron: "0 6 * * *"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
jobs:
update:
name: Update and validate flake inputs
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Nix
uses: ./.github/actions/setup-nix
- name: Update flake inputs
id: update
run: |
nix flake update
if git diff --quiet -- flake.lock; then
echo 'changed=false' >> "$GITHUB_OUTPUT"
else
echo 'changed=true' >> "$GITHUB_OUTPUT"
fi
- name: Check updated NixOS configurations
if: steps.update.outputs.changed == 'true'
uses: ./.github/actions/check-nixos
- name: Create update pull request
if: steps.update.outputs.changed == 'true'
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
add-paths: flake.lock
branch: automation/update-flake-lock
delete-branch: true
commit-message: "flake: update inputs"
title: "flake: update inputs"
body: |
Automated update of `flake.lock`.
The updated inputs passed the Registry tests and a build of every NixOS configuration.
+3 -2
View File
@@ -23,10 +23,11 @@
!/images/
!/secrets/
!/windows/
!/hosts/
!/libs/
!/modules/
!/tests/
!/skills/
+2
View File
@@ -3,6 +3,7 @@ keys:
- &host_x1g13 age12g85cuvg4kjfr79lqf5fx2k0d82tchrgv88xgkt7ukk2cfcsw98s2rjyat
- &host_ops age18rtm2dq2r62zvnhwdq0gkm24hu85r7zyleyk3jqv22zpdtw064eq7ay7dl
- &host_internal-app-01 age1mcp5gma7y0k59equhzqfsnn0ed335ljjtn0k08ua77htlxf0x54qsravch
- &host_galleria age1wh7r9wnvyrgt5efjvg2324khsf4w6e9atpmz2udr4uw7frhnvvwquzcu72
creation_rules:
- path_regex: ^secrets/common/[^/]+\.ya?ml$
key_groups:
@@ -11,6 +12,7 @@ creation_rules:
- *host_x1g13
- *host_ops
- *host_internal-app-01
- *host_galleria
- path_regex: ^secrets/hosts/x1g13/[^/]+\.ya?ml$
key_groups:
- age:
+383 -108
View File
@@ -7,6 +7,10 @@ flake. `flake.nix` defines inputs and delegates flake outputs through
flake-parts. Keep configuration with the component that owns it, rather than in
the root flake or an unrelated host.
This file documents the current repository contract, not a hypothetical future
layout. When a structural, ownership, profile, host-role, or validation change
makes any statement here stale, update `AGENTS.md` in the same change.
| Path | Responsibility |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `modules/applications/` | One software component, including GUI applications, window managers, desktop environments, CLI tools, and editors |
@@ -15,59 +19,81 @@ the root flake or an unrelated host.
| `modules/hardwares/` | Reusable drivers, hardware families, and VM or WSL guest configuration |
| `modules/users/` | User identity and the user's NixOS-, nix-darwin-, and Home Manager-specific definitions |
| `modules/profiles/` | Purpose- or form-factor-oriented compositions of multiple units |
| `hosts/` | Machine-specific facts and the profiles or applications selected for each machine |
| `hosts/` | Machine-specific facts and the profiles selected for each machine; direct unit selections are exceptional |
| `libs/` | Registry, unit discovery, and host construction logic |
| `overlays/` | Package replacements and additions |
| `shells/` | Development shells |
| `flake/` | Supporting flake outputs such as formatters, checks, and Git hooks |
| `skills/` | Repository-specific Codex workflows that enforce this contract for recurring changes |
Before adding or materially extending an application or service, read and
follow `skills/add-application-or-service/SKILL.md`. `AGENTS.md` remains the
authoritative contract when the skill and repository ever disagree.
Use **unit** as the generic internal term for a Registry-managed component and
**profile** for a unit that composes multiple units. Do not introduce a
`features/` layer. Window managers and desktop environments such as niri and
GNOME belong in `modules/applications/`; do not create a separate `desktop/`
labwc belong in `modules/applications/`; do not create a separate `desktop/`
module category.
Before adding configuration, decide whether it is owned by an application,
system foundation, service, hardware family, user, profile, or individual host.
Prefer the following placements:
| Configuration | Placement |
| ---------------------------------------------------- | ------------------------------------------------ |
| Nix settings shared by every system host | `modules/systems/nix/common.nix` |
| NixOS-only boot configuration | `modules/systems/boot/.../nixos.nix` |
| Ghostty-specific configuration | `modules/applications/ghostty/` |
| niri-specific configuration | `modules/applications/niri/` |
| Applications selected for the niri environment | `modules/profiles/interface/niri/meta.nix` |
| GNOME itself | `modules/applications/gnome/` |
| Docker daemon and Docker group membership | `modules/services/docker/nixos.nix` |
| Reusable ThinkPad-family configuration | `modules/hardwares/thinkpad/` |
| The laptop unit composition | `modules/profiles/platform/laptop/meta.nix` |
| The development-environment unit composition | `modules/profiles/workload/development/meta.nix` |
| A user's OS- and Home Manager-specific configuration | `modules/users/<name>/` |
| x1g13-specific monitor layout | `hosts/x1g13/home.nix` |
| x1g13-specific disk UUID | `hosts/x1g13/nixos.nix` |
| Package replacement or addition | `overlays/` |
| Formatter, checks, or Git hooks | `flake/` |
| Configuration | Placement |
| ---------------------------------------------------- | --------------------------------------------------------- |
| Nix settings shared by every system host | `modules/systems/nix/common.nix` |
| NixOS-only boot configuration | `modules/systems/boot/.../nixos.nix` |
| Disko NixOS module and CLI | `modules/systems/disko/` |
| macOS-wide input, document, and dialog defaults | `modules/systems/macos-defaults/darwin.nix` |
| macOS Dock defaults | `modules/systems/dock/darwin.nix` |
| macOS trackpad defaults | `modules/systems/trackpad/darwin.nix` |
| Finder-specific preferences | `modules/applications/finder/darwin.nix` |
| Ghostty-specific configuration | `modules/applications/ghostty/` |
| niri-specific configuration | `modules/applications/niri/` |
| Desktop applications shared by labwc and niri | `modules/profiles/interface/linux-desktop/meta.nix` |
| Applications and services specific to niri | `modules/profiles/interface/niri/meta.nix` |
| labwc and its session configuration | `modules/applications/labwc/` |
| A Linux package plus its macOS Homebrew cask | `modules/applications/<name>/home.nix` and `darwin.nix` |
| Docker daemon and Docker group membership | `modules/services/docker/nixos.nix` |
| The laptop unit composition | `modules/profiles/platform/laptop/meta.nix` |
| The Intel ThinkPad X1 composition | `modules/profiles/platform/thinkpad-x1/meta.nix` |
| The Intel/NVIDIA desktop composition | `modules/profiles/platform/intel-nvidia-desktop/meta.nix` |
| NVIDIA GPU driver configuration | `modules/hardwares/nvidia/` |
| The development-environment unit composition | `modules/profiles/workload/development/meta.nix` |
| Cross-platform fingerprint selection | `modules/profiles/security/fingerprint/meta.nix` |
| A user's OS- and Home Manager-specific configuration | `modules/users/<name>/` |
| Host-specific monitor layout | `hosts/<name>/home.nix` |
| Generated host disk UUIDs | `hosts/<name>/hardware-configuration.nix` |
| Package replacement or addition | `overlays/` |
| Formatter, checks, or Git hooks | `flake/` |
## Unit Discovery and Identity
A directory below `modules/` is a unit if, and only if, it directly contains at
least one reserved file. Directories used only for classification, such as
`modules/applications/` or `modules/profiles/interface/`, are namespaces rather
than units when they have no reserved file of their own.
A directory below `modules/` is a unit if, and only if, it contains at least one
reserved root file or reserved Home Manager fragment. Directories used only for
classification, such as `modules/applications/` or
`modules/profiles/interface/`, are namespaces rather than units when they have
no reserved fragment of their own.
The Registry recognizes exactly these five reserved filenames:
The Registry recognizes exactly these eight reserved paths relative to a unit:
| File | Target and responsibility |
| ------------ | -------------------------------------------------------------------------------- |
| `common.nix` | System-side configuration fragment shared by NixOS and nix-darwin |
| `nixos.nix` | NixOS-only configuration fragment |
| `darwin.nix` | nix-darwin-only configuration fragment |
| `home.nix` | Home Manager configuration fragment |
| `meta.nix` | Registry descriptor for dependencies, external modules, and descriptive metadata |
| File | Target and responsibility |
| ----------------- | -------------------------------------------------------------------------------- |
| `common.nix` | System-side configuration fragment shared by NixOS and nix-darwin |
| `nixos.nix` | NixOS-only system configuration fragment |
| `darwin.nix` | nix-darwin-only system configuration fragment |
| `home.nix` | Home Manager fragment shared by NixOS and nix-darwin |
| `home/common.nix` | Home Manager fragment shared by NixOS and nix-darwin |
| `home/nixos.nix` | Home Manager fragment loaded only on NixOS |
| `home/darwin.nix` | Home Manager fragment loaded only on nix-darwin |
| `meta.nix` | Registry descriptor for dependencies, external modules, and descriptive metadata |
`common.nix` is never applied to Home Manager. OS-independent Home Manager
configuration still belongs in `home.nix`.
Root `common.nix` is never applied to Home Manager. `home.nix` and
`home/common.nix` have identical dispatch semantics; use either or both when a
useful file split exists. The `home/` directory is a reserved fragment directory
of its parent unit when it contains `common.nix`, `nixos.nix`, or `darwin.nix`;
it is not discovered as a child unit in that case.
The Registry derives a unit ID from the path relative to `modules/`, joining
path components with dots. Category names remain plural. It also derives the
@@ -123,10 +149,13 @@ of the following are valid units:
# Home Manager only
modules/applications/ghostty/
├── home.nix
├── home/
│ ├── nixos.nix
│ └── darwin.nix
└── settings.nix
# NixOS only
modules/applications/gnome/
modules/services/docker/
└── nixos.nix
# nix-darwin only
@@ -150,16 +179,16 @@ modules/systems/nix/
└── common.nix
```
If a unit has no `home.nix`, do not generate or apply a Home Manager module for
it. The same rule applies independently to `common.nix`, `nixos.nix`, and
`darwin.nix`.
Each fragment is optional and registered independently. A unit may therefore
contain only `home/nixos.nix` or `home/darwin.nix`; it does not need a
placeholder `home.nix` or `home/common.nix`.
### Configuration fragments
`common.nix`, `nixos.nix`, `darwin.nix`, and `home.nix` are configuration
fragments to which the Registry adds the enable condition. They return the
configuration for their class directly and must not define top-level `imports`,
`options`, or `config` attributes:
Every reserved path except `meta.nix` is a configuration fragment to which the
Registry adds the enable condition. These fragments return the configuration
for their class directly and must not define top-level `imports`, `options`, or
`config` attributes:
```nix
# modules/services/docker/nixos.nix
@@ -194,9 +223,9 @@ fragment.
### Helper files and directories
Every filename other than the five reserved names is an ordinary helper,
regardless of its extension. The Registry neither discovers nor automatically
imports helper files such as `settings.nix`, `keybindings.nix`, `packages.nix`,
Every path other than the eight reserved paths is an ordinary helper, regardless
of its extension. The Registry neither discovers nor automatically imports
helper files such as `settings.nix`, `keybindings.nix`, `packages.nix`,
`colors.nix`, `rules.nix`, or `helpers.nix`. Import a helper explicitly from the
reserved fragment that uses it:
@@ -239,9 +268,10 @@ modules/applications/niri/
```
Here `parts/` is not a unit because it directly contains no reserved file. A
helper directory that directly contains `home.nix` or another reserved file is
itself discovered as a unit, so never use reserved filenames inside a directory
that is intended to contain helpers only.
helper directory that directly contains a root reserved file is itself
discovered as a unit, so never use reserved filenames inside a directory that
is intended to contain helpers only. The reserved `home/` fragment directory is
the sole exception to ordinary recursive child-unit discovery.
### Registry metadata
@@ -283,12 +313,11 @@ use fully qualified unit IDs:
# modules/profiles/interface/niri/meta.nix
{
includes = [
"profiles.interface.linux-desktop"
"applications.niri"
"applications.ghostty"
"applications.noctalia"
"applications.vicinae"
"applications.nautilus"
"services.xdg-portal"
"services.ly"
"services.swayidle"
];
}
```
@@ -301,41 +330,104 @@ in `meta.includes`.
Application metadata should include only dependencies technically required for
the application to work. A profile owns the user's choice to adopt several
otherwise independent applications together. For example, niri may include the
Wayland foundation and xdg-desktop-portal as technical dependencies, while
`profiles.interface.niri` selects Ghostty, Vicinae, Noctalia, and Nautilus.
Ghostty must not depend on niri, and niri-specific keybindings remain owned by
the niri unit.
otherwise independent applications together. For example, the niri application
includes the Wayland foundation as a technical dependency. The
`profiles.interface.linux-desktop` profile selects Ghostty and Nautilus because
both labwc and niri use them, while the cross-platform `profiles.interface.gui`
profile selects Vicinae for graphical hosts. The labwc and niri profiles select
their compositor, Noctalia, and the session services they require. Ghostty and
Vicinae must not depend on either compositor, and compositor-specific
keybindings remain owned by the corresponding application unit.
## Profiles
Profiles compose units by purpose or form factor; they do not replace clear
application, system, service, or hardware ownership. Suitable profile namespaces
include:
application, system, service, or hardware ownership. The current profile
structure is:
```text
modules/profiles/
├── README.md
├── base/
├── interface/
│ ├── niri/
│ ├── gnome/
│ ├── cli-minimal/
│ └── cli-interactive/
│ ├── cli/
│ ├── gui/
│ ├── macos/
│ ├── linux-desktop/
│ ├── labwc/
│ └── niri/
├── networking/
│ ├── homelab-cache-client/
│ ├── tailscale-client/
│ └── tailscale-subnet-router/
├── platform/
│ ├── nixos/
│ ├── intel-nvidia-desktop/
│ ├── laptop/
│ ├── thinkpad/
│ ├── thinkpad-x1/
│ ├── desktop/
│ ├── vm/
│ └── wsl/
│ └── vm/
├── workload/
│ ├── camera/
│ ├── development/
│ ├── game/
│ ├── machine-learning/
│ ├── nix-builder/
│ ├── personal/
│ ├── server/
│ └── remote/
│ └── remote-access/
└── security/
└── secure-boot/
├── fingerprint/
├── secrets/
├── secure-boot/
└── tpm-storage/
```
`modules/profiles/README.md` is the compatibility inventory for this structure.
Whenever a profile is added, removed, renamed, changes host-class support, or
changes meaning, update that README and every affected `hosts/default.nix`
selection in the same change. Remove stale profile directories and references;
do not retain compatibility aliases.
The profile layers have these responsibilities:
- `base` contains only invariants required by every supported host. It includes
`systems.nix` and the universal Atuin, tealdeer, trippy, and xh CLI tools;
optional secrets, interface, hardware, and workloads do not belong there.
- `interface` describes how the host is operated. `interface.cli` is shared by
NixOS and macOS and includes `tio`. `interface.gui` owns cross-platform
graphical interface applications such as Vicinae. `interface.macos` owns the
macOS Finder, Dock, trackpad, and shared default preferences and includes
`interface.gui`.
`interface.linux-desktop` owns the common labwc/niri desktop selection,
including Ghostty and Nautilus, and also includes `interface.gui`. Labwc and
niri remain independently selectable and do not imply CLI or personal
workloads.
- `platform` describes NixOS foundations and physical or virtual form factors.
macOS does not need an empty symmetric platform profile.
- `workload` describes optional host uses. `workload.development` and
`workload.personal` are cross-platform profiles, not `*-linux` variants.
- `networking` describes network roles and topology rather than user workloads.
- `security` describes optional security policies. Select
`security.fingerprint` instead of listing `systems.fingerprint` directly in a
host. The underlying `systems.fingerprint` unit owns NixOS fingerprint
authentication and macOS Touch ID sudo configuration through its class
fragments.
Do not split a semantic profile into `*-linux` and cross-platform variants merely
because an application is installed differently on each OS. Keep the semantic
profile cross-platform when its purpose is shared, and implement OS differences
inside the owning application unit. For example, Chrome, Vesktop, draw.io,
Slack, and Zoom use Linux Home Manager configuration in `home.nix` and macOS
Homebrew casks in `darwin.nix`. Guard a Linux-only Home Manager package with the
host platform when the same unit also has a Darwin implementation.
An explicitly OS-specific profile is appropriate when the composition itself is
OS-specific, such as `interface.macos`, `interface.linux-desktop`,
`platform.nixos`, or a NixOS
subnet-router. Do not create an OS suffix for a thin package difference that the
owning application unit can express.
The `desktop/` name above is a form-factor profile under `profiles/platform/`,
not a top-level module category.
@@ -352,6 +444,10 @@ conditions holds:
- Other units depend on it.
- It involves a daemon, permissions, or user groups.
`security.tpm-storage` intentionally does not own a disk identifier. A host that
selects it must define `boot.initrd.luks.devices.cryptroot.device` in its own
NixOS module.
## Registry Responsibilities
Implement unit discovery with Nix standard functionality such as
@@ -360,8 +456,10 @@ mechanism, and do not design the repository around `import-tree`. Registry logic
has these responsibilities:
1. Recursively visit directories below `modules/`.
2. Check only the five reserved filenames directly within each directory.
3. Register a directory as a unit when at least one reserved file exists there.
2. Check the five reserved root filenames and the three reserved filenames
directly inside the unit's `home/` fragment directory.
3. Register a directory as a unit when at least one reserved fragment exists
there, including a unit that has only a reserved `home/` fragment.
4. Derive the unit ID from the path relative to `modules/`.
5. Record only class fragments that exist.
6. Evaluate `meta.nix` as a descriptor only when it exists.
@@ -370,7 +468,8 @@ has these responsibilities:
9. Enable included units from `meta.includes`.
10. Raise a clear evaluation error for a reference to a missing unit ID.
11. Apply only the fragments appropriate to the current host class.
12. Pass `home.nix` to Home Manager only for hosts that enable Home Manager.
12. Pass `home.nix`, `home/common.nix`, and the matching OS-specific Home
Manager fragment only for hosts that enable Home Manager.
A unit record may conceptually look like this; the implementation need not use
this exact representation:
@@ -385,6 +484,9 @@ this exact representation:
nixos = null;
darwin = null;
home = ./applications/ghostty/home.nix;
homeCommon = null;
homeNixos = ./applications/ghostty/home/nixos.nix;
homeDarwin = ./applications/ghostty/home/darwin.nix;
};
meta = { };
@@ -409,58 +511,164 @@ host-owned data includes:
- Kernel parameters required by one machine only.
- `system.stateVersion`.
- Host-specific secret references.
- The profiles, applications, and other units enabled on that host.
- The profiles enabled on that host and, only in exceptional cases, direct
application or other unit selections that cannot be expressed by a coherent
reusable profile.
A host registry may use a specification like this:
```nix
# hosts/default.nix
{
nix-example = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./nix-example;
profiles = [
"base"
"interface.cli"
"platform.vm"
"workload.development"
"workload.remote-access"
];
};
ops = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./ops;
profiles = [
"base"
"interface.cli"
"platform.vm"
"workload.remote-access"
];
};
internal-app-01 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./internal-app-01;
profiles = [
"base"
"interface.cli"
"platform.vm"
"workload.server"
];
};
installer = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./installer;
homeManager = false;
profiles = [ "base" ];
};
x1g9 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./x1g9;
profiles = [
"base"
"interface.cli"
"interface.labwc"
"interface.niri"
"platform.thinkpad-x1"
"security.fingerprint"
"workload.personal"
];
};
x1g13 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./x1g13;
profiles = [
"base"
"platform.thinkpad"
"interface.cli"
"interface.labwc"
"interface.niri"
"interface.gnome"
"networking.tailscale-client"
"platform.thinkpad-x1"
"security.fingerprint"
"security.secrets"
"security.secure-boot"
"security.tpm-storage"
"workload.camera"
"workload.development"
"workload.personal"
"security.secure-boot"
];
applications = [
"codex-desktop"
];
units = [
"services.tailscale"
];
};
macbook = {
system = "aarch64-darwin";
galleria = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./macbook;
path = ./galleria;
profiles = [
"base"
"platform.laptop"
"interface.cli"
"interface.labwc"
"interface.niri"
"platform.intel-nvidia-desktop"
"security.secrets"
"security.secure-boot"
"security.tpm-storage"
"workload.development"
"workload.game"
"workload.machine-learning"
"workload.personal"
];
};
applications = [
"ghostty"
m2 = {
system = "aarch64-darwin";
stateVersion = "26.05";
user = "moons";
path = ./m2;
profiles = [
"base"
"interface.cli"
"interface.macos"
"security.fingerprint"
"workload.development"
"workload.personal"
];
};
}
```
Treat entries in `profiles` and `applications` as IDs relative to their
respective category roots. Add the category prefixes during host construction:
The current role assignment is intentional: nix-example is the development VM;
ops is the remote-access VM with host-specific static networking;
internal-app-01 is the container server VM; and installer builds the minimal
installation ISO without Home Manager. x1g9 is a full NixOS desktop with niri,
labwc, ly, the shared Linux desktop applications, and the personal workload.
x1g13 is the secure NixOS development and personal ThinkPad, with the same
desktop sessions plus Tailscale client, SOPS, Secure Boot, and TPM-backed disk
unlock. galleria is the Intel/NVIDIA physical desktop shared with Windows; it
uses dedicated NixOS partitions, LUKS, Secure Boot, and TPM-backed disk unlock.
m2 is the daily-use macOS development and personal machine with the macOS
interface defaults. Keep the desktop sessions independently selectable, and
keep the development and personal profiles usable across NixOS and Darwin.
Treat entries in `profiles` and the exceptional `applications` field as IDs
relative to their respective category roots. Add the category prefixes during
host construction:
```nix
selectedUnits =
@@ -470,36 +678,72 @@ selectedUnits =
++ spec.units or [ ];
```
`units` is an escape hatch for fully qualified service, system, hardware, or
other unit IDs. Prefer profiles for the main composition; do not make hosts list
large numbers of low-level units directly.
`applications` and `units` are escape hatches, not normal host composition.
Do not add either field when an existing profile expresses the concern, when an
existing profile can coherently include the unit, or when the concern is
reusable enough to deserve a small profile. For example, add a development tool
to `workload.development` and select `security.fingerprint`; do not write
`applications = [ "ghostty" ];` or `units = [ "systems.fingerprint" ];` in a
host. A direct selection is permitted only for a genuinely exceptional,
machine-specific unit that would make every reasonable profile misleading; add
an adjacent comment explaining that exception. Prefer profiles for host
composition and omit both escape-hatch fields by default.
Host modules use normal Nix module semantics and are not Registry-guarded
configuration fragments. For example:
```text
hosts/x1g13/
├── nixos.nix
├── home.nix
├── hardware-configuration.nix
└── disko.nix
hosts/
├── installer/
│ └── nixos.nix
├── internal-app-01/
│ ├── nixos.nix
│ └── hardware-configuration.nix
├── nix-example/
│ ├── nixos.nix
│ └── hardware-configuration.nix
├── ops/
│ ├── nixos.nix
│ └── hardware-configuration.nix
├── galleria/
│ ├── disk-identifiers.nix
│ ├── disko.nix
│ ├── hardware-configuration.nix
│ └── nixos.nix
├── x1g9/
│ ├── nixos.nix
│ └── hardware-configuration.nix
├── x1g13/
│ ├── nixos.nix
│ ├── home.nix
│ ├── disko.nix
│ └── hardware-configuration.nix
└── m2/
└── darwin.nix
```
`hosts/x1g13/nixos.nix` may explicitly load `hardware-configuration.nix` and
`disko.nix` with the normal top-level Nix module `imports`. Do not confuse these
host imports with the prohibition on top-level `imports` in unit configuration
fragments.
`hosts/x1g9/nixos.nix` explicitly loads `hardware-configuration.nix` with the
normal top-level Nix module `imports`. `hosts/x1g13/nixos.nix` loads its
generated hardware configuration and host-local `disko.nix` the same way. Do
not confuse these host imports with the prohibition on top-level `imports` in
unit configuration fragments. `hosts/galleria/disko.nix` manages only the two
dedicated NixOS partitions by PARTUUID and deliberately excludes the Windows
disk, Windows partitions, and the Windows EFI System Partition.
Derive the system class from the host's `system`:
- A Linux NixOS host receives `common.nix` and `nixos.nix`.
- A nix-darwin host receives `common.nix` and `darwin.nix`.
- A host with integrated Home Manager additionally receives `home.nix`.
- A NixOS host with integrated Home Manager additionally receives `home.nix`,
`home/common.nix`, and `home/nixos.nix`.
- A nix-darwin host with integrated Home Manager additionally receives
`home.nix`, `home/common.nix`, and `home/darwin.nix`.
Home Manager is additive, not a system class mutually exclusive with NixOS or
nix-darwin. The supported combinations are NixOS plus Home Manager and
nix-darwin plus Home Manager. If standalone Home Manager is supported later, add
an explicit host kind because `system` alone cannot distinguish it from NixOS.
nix-darwin. Normal machine configurations combine NixOS or nix-darwin with Home
Manager; the installer ISO explicitly sets `homeManager = false`. If standalone
Home Manager is supported later, add an explicit host kind because `system`
alone cannot distinguish it from NixOS.
Do not duplicate reusable settings in hosts, but do not force genuinely
machine-specific values into a common unit merely to remove a host-local line.
@@ -522,11 +766,23 @@ When implementing or modifying modules:
unit's enable option from a class fragment.
- Do not assume any non-reserved file is discovered or loaded automatically.
- Do not require an `_` prefix for helper or private files.
- Do not create unused `common.nix`, `nixos.nix`, `darwin.nix`, `home.nix`, or
`meta.nix` files.
- Do not create unused reserved fragments, including placeholder files under the
reserved `home/` fragment directory.
- Do not override a path-derived unit ID from `meta.nix`.
- Keep technical application dependencies separate from the applications a
personal environment chooses to combine in a profile.
- Keep cross-platform profile names semantic. Put Linux package installation in
an application's `home.nix` and the corresponding macOS Homebrew cask in its
`darwin.nix`; do not create a thin `*-linux` profile for that difference.
- Keep shared labwc/niri selections in `profiles.interface.linux-desktop` and
session-specific applications or services in the respective labwc or niri
profile.
- Keep `modules/profiles/README.md`, the profile directories, and host profile
selections synchronized whenever any of them changes.
- Do not select applications or units directly in `hosts/default.nix` unless
they meet the documented exceptional, machine-specific escape-hatch rule.
Prefer adding the unit to an existing coherent profile or creating a small,
justified reusable profile.
- Do not rely on module-list ordering to override values. Use Nix module
priorities such as `lib.mkDefault`, `lib.mkForce`, `lib.mkBefore`, or
`lib.mkAfter` explicitly when required.
@@ -563,6 +819,25 @@ dependency closure through `meta.includes`, missing-unit errors, and class
dispatch. Verify that helper files are ignored until explicitly imported and
that directories without a directly contained reserved file remain namespaces.
For profile changes, additionally:
- Check for stale profile IDs after every add, removal, or rename.
- Evaluate every affected real host without switching it.
- Evaluate a cross-platform profile on both NixOS and nix-darwin, even when only
one current host selects it.
- Confirm `modules/profiles/README.md` accurately states compatibility and any
required host-owned values.
- When adding a Darwin application fragment, verify the resulting
`homebrew.casks` selection as well as module evaluation.
- Preserve the intended host roles: nix-example remains the development VM;
ops remains the statically networked remote-access VM; internal-app-01 remains
the container server VM; installer remains the Home Manager-free installation
ISO; x1g9 provides niri, labwc, ly, and the personal application set; x1g13
additionally provides the development, Tailscale client, secrets, Secure Boot,
and TPM storage roles; galleria remains the Intel/NVIDIA dual-boot desktop
with LUKS, Secure Boot, and TPM storage; m2 remains the daily-use development
and personal machine.
## Commit and Pull Request Guidelines
Recent history favors short, lowercase, imperative subjects such as `fix` and
+119
View File
@@ -0,0 +1,119 @@
# iOS Simulator 初期セットアップ
この手順は `m2` の macOS 環境で、stable Xcode と最新の stable iOS Simulator Runtime を使える状態にするためのもの。
## 前提
- `m2` が `workload.development` profile を有効にしていること
- Mac App Store に Apple Account でサインイン済みであること
- dotfiles を最新化していること
Xcode 本体は `applications.xcode` が Mac App Store 版を管理する。Simulator Runtime は Apple が管理する mutable state のため、Nix store には入れず専用 dev shell から導入する。
## 1. macOS 設定を反映する
リポジトリ直下で nix-darwin の設定を反映する。
```bash
sudo darwin-rebuild switch --flake .#m2
```
これにより `/Applications/Xcode.app` に stable Xcode がインストールされる。
Xcode のインストールで Mac App Store の認証エラーになる場合は、App Store を一度開いてサインイン状態を確認してから再実行する。
## 2. iOS Simulator Runtime を導入する
初回セットアップは次の1コマンドで行う。
```bash
nix develop .#ios -c ios-simulator-install
```
`ios-simulator-install` は次を順に実行する。
1. `/Applications/Xcode.app` が存在することを確認
2. `xcode-select` の Developer Directory を stable Xcode に切り替え
3. Xcode の first-launch components を導入
4. 利用可能な新しい hardware support components を確認
5. 選択中の Xcode に対応する最新の iOS Simulator Runtime をダウンロードしてインストール
6. Xcode のバージョンとインストール済み Simulator Runtime を表示
途中で `sudo` の認証を求められる場合がある。
## 3. インストールを確認する
```bash
xcodebuild -version
xcode-select -p
xcrun simctl list runtimes
xcrun simctl list devices available
```
`xcode-select -p` は次を指していること。
```text
/Applications/Xcode.app/Contents/Developer
```
`xcrun simctl list runtimes` に iOS runtime が表示されればセットアップ完了。
## 4. Simulator を起動する
```bash
open -a Simulator
```
Simulator の Device メニューから、インストール済み runtime で利用可能な iPhone を選択する。
## Runtime の更新
Xcode を stable の新しいバージョンへ更新した後は、同じコマンドを再実行する。
```bash
nix develop .#ios -c ios-simulator-install
```
Xcode の選択、first-launch components、hardware support、iOS Simulator Runtime の状態をまとめて更新できる。
## トラブルシューティング
### Xcode が見つからない
次のエラーが出る場合、先に nix-darwin の設定を反映する。
```text
Xcode is not installed at /Applications/Xcode.app.
```
```bash
sudo darwin-rebuild switch --flake .#m2
```
### Simulator Runtime が見えない
まず runtime 一覧を確認する。
```bash
xcrun simctl list runtimes
```
iOS runtime がない場合は再度インストーラーを実行する。
```bash
nix develop .#ios -c ios-simulator-install
```
### Command Line Tools 側を参照している
```bash
xcode-select -p
```
が `/Library/Developer/CommandLineTools` を指している場合でも、`ios-simulator-install` が `/Applications/Xcode.app/Contents/Developer` へ切り替える。
手動で直す場合は次を実行する。
```bash
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
```
Generated
+905 -265
View File
File diff suppressed because it is too large Load Diff
+26 -1
View File
@@ -23,6 +23,11 @@
# Desktop
niri-flake.url = "github:sodiboo/niri-flake";
nix-hazkey = {
url = "github:aster-void/nix-hazkey";
inputs.nixpkgs.follows = "nixpkgs";
};
stylix = {
url = "github:nix-community/stylix";
inputs.nixpkgs.follows = "nixpkgs";
@@ -30,7 +35,7 @@
# Terminal
ghostty = {
url = "github:moons-14/ghostty";
url = "github:ghostty-org/ghostty";
};
# Shell / Launcher
@@ -55,6 +60,11 @@
inputs.nixpkgs.follows = "nixpkgs";
};
deploy-rs = {
url = "github:serokell/deploy-rs";
inputs.nixpkgs.follows = "nixpkgs";
};
# Disk management
disko = {
url = "github:nix-community/disko";
@@ -86,6 +96,13 @@
url = "github:ilysenko/codex-desktop-linux";
};
codex-session-usage.url = "github:moons-14/codex-session-usage";
skills = {
url = "github:mattpocock/skills";
flake = false;
};
# Index / Search
nix-index-database = {
url = "github:nix-community/nix-index-database";
@@ -94,6 +111,14 @@
# Systems
systems.url = "github:nix-systems/default";
browser-previews = {
url = "github:nix-community/browser-previews";
inputs.nixpkgs.follows = "nixpkgs";
};
nani-translate-linux.url = "git+https://github.com/zunoser/nani-translate-linux.git";
};
outputs =
+1
View File
@@ -1,5 +1,6 @@
{
imports = [
./deploy.nix
./formatter.nix
./git-hooks.nix
./registry.nix
+28
View File
@@ -0,0 +1,28 @@
{
inputs,
self,
...
}:
{
flake.deploy = {
nodes.nix-builder = {
hostname = "nix-builder";
sshUser = "moons";
user = "root";
interactiveSudo = true;
remoteBuild = true;
autoRollback = true;
magicRollback = true;
profiles.system.path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.nix-builder;
};
};
perSystem =
{ system, ... }:
{
apps.deploy = inputs.deploy-rs.apps.${system}.default;
checks = inputs.deploy-rs.lib.${system}.deployChecks self.deploy;
};
}
+88 -4
View File
@@ -1,4 +1,30 @@
{
nix-builder = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./nix-builder;
profiles = [
"base"
"interface.cli"
"networking.tailscale-client"
"platform.vm"
"workload.nix-builder"
"workload.remote-access"
];
};
installer = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./installer;
homeManager = false;
profiles = [ "base" ];
};
x1g9 = {
system = "x86_64-linux";
stateVersion = "26.05";
@@ -7,10 +33,62 @@
profiles = [
"base"
"interface.gui"
"platform.thinkpad"
"interface.cli"
"interface.labwc"
"interface.niri"
"platform.thinkpad-x1"
"security.fingerprint"
# "security.secrets"
"workload.personal"
"workload.tailscale.client"
];
};
x1g13 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./x1g13;
profiles = [
"base"
"interface.cli"
"interface.labwc"
"interface.niri"
"networking.tailscale-client"
"platform.thinkpad-x1"
"security.fingerprint"
"security.secrets"
"security.secure-boot"
"security.tpm-storage"
"workload.development"
"workload.game"
"workload.personal"
];
};
galleria = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./galleria;
profiles = [
"base"
"interface.cli"
"interface.labwc"
"interface.niri"
"networking.tailscale-client"
"platform.intel-nvidia-desktop"
"security.secrets"
"security.secure-boot"
"security.tpm-storage"
"security.fingerprint"
"workload.development"
"workload.game"
"workload.machine-learning"
"workload.personal"
"workload.camera"
];
};
@@ -22,7 +100,13 @@
profiles = [
"base"
"interface.cli-minimal"
"interface.cli"
"interface.macos"
"security.fingerprint"
# "security.secrets"
"workload.development"
"workload.game"
"workload.personal"
];
};
}
+91
View File
@@ -0,0 +1,91 @@
_:
let
espPart = "/dev/disk/by-partuuid/008b04ef-9c06-4049-bffb-3906f5c3a9c1";
nixosPart = "/dev/disk/by-partuuid/04295552-cbb8-4511-ac1e-1171ec20f8d1";
btrfsMountOptions = [
"compress=zstd"
"noatime"
"ssd"
"space_cache=v2"
];
in
{
disko.enableConfig = true;
# These are deliberately partition paths, not the whole Windows disk. Disko
# must never own or destroy the disk's GPT or any Windows partition.
disko.devices.disk = {
esp = {
type = "disk";
device = espPart;
destroy = false;
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
nixos = {
type = "disk";
device = nixosPart;
destroy = false;
content = {
type = "luks";
name = "cryptroot";
askPassword = true;
settings.allowDiscards = true;
extraFormatArgs = [
"--type"
"luks2"
"--pbkdf"
"argon2id"
"--label"
"NixOS-LUKS"
];
content = {
type = "btrfs";
extraArgs = [
"-f"
"-L"
"NixOS"
];
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = btrfsMountOptions;
};
"@home" = {
mountpoint = "/home";
mountOptions = btrfsMountOptions;
};
"@nix" = {
mountpoint = "/nix";
mountOptions = btrfsMountOptions;
};
"@log" = {
mountpoint = "/var/log";
mountOptions = btrfsMountOptions;
};
"@swap" = {
mountpoint = "/.swapvol";
mountOptions = [ "noatime" ];
swap.swapfile.size = "32G";
};
};
};
};
};
};
}
+30
View File
@@ -0,0 +1,30 @@
# 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,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [
"xhci_pci"
"ahci"
"nvme"
"usbhid"
"usb_storage"
"sd_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
+51
View File
@@ -0,0 +1,51 @@
{
lib,
config,
...
}:
{
# This desktop is permanently connected to AC power.
systemd.user.services.swayidle.Service.Environment = [
"SWAYIDLE_ASSUME_AC=1"
];
services.kanshi = {
enable = true;
settings = [
{
profile = {
name = "galleria";
outputs = [
{
criteria = "HDMI-A-1";
status = "enable";
position = "0,0";
scale = 1.5;
}
{
criteria = "DP-1";
status = "enable";
position = "2560,0";
}
{
criteria = "DP-2";
status = "enable";
position = "5120,0";
scale = 1.5;
}
];
};
}
];
};
home.file.".wallpapers" = {
source = lib.mkForce (
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/Pictures/wallpapers"
);
recursive = lib.mkForce false;
};
}
+21
View File
@@ -0,0 +1,21 @@
{ inputs, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
./disko.nix
];
boot.initrd.luks.devices.cryptroot.device =
"/dev/disk/by-partuuid/04295552-cbb8-4511-ac1e-1171ec20f8d1";
# Keep Windows data and recovery partitions out of UDisks-based file
# managers. The shared EFI System Partition stays available as /boot.
services.udev.extraRules = ''
ENV{ID_PART_ENTRY_UUID}=="0480f887-d1f9-489d-b8fe-78549ced1938", ENV{UDISKS_IGNORE}="1"
ENV{ID_PART_ENTRY_UUID}=="6c70041b-3f65-4eb1-8b08-18ed20001877", ENV{UDISKS_IGNORE}="1"
'';
environment.systemPackages = with inputs.browser-previews.packages.${pkgs.system}; [
google-chrome-beta
];
}
+195
View File
@@ -0,0 +1,195 @@
{
pkgs,
lib,
modulesPath,
...
}:
{
imports = [ "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" ];
boot.zfs.forceImportRoot = false;
networking = {
hostName = "nixos-installer";
networkmanager = {
enable = true;
wifi.powersave = false;
};
};
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "prohibit-password";
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
PubkeyAuthentication = "yes";
};
};
users.users.root.openssh.authorizedKeys.keys = [
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIKhxDkucmeCor6CKoXAua7DgDSzuXrZOtpdkyzQxz5+aAAAABHNzaDo= moons@moons14.com"
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIN6hZJyng/5LgFKPjR6uZAd/00UkO0vN0uQOoIvfSELdAAAABHNzaDo= moons@moons14.com"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLwReAiwhXoO34S2+MrvqUhi8IWp4IzUq4OSp3niJdq"
];
environment.systemPackages = with pkgs; [
git
disko
sops
age
ssh-to-age
age-plugin-yubikey
yubikey-manager
pcsc-tools
mkpasswd
rsync
vim
wget
curl
jq
parted
cryptsetup
btrfs-progs
efibootmgr
pciutils
sbctl
tpm2-tools
util-linux
];
services.pcscd.enable = true;
environment.etc."installer-help.txt".text = ''
╔══════════════════════════════════════════════════════════════╗
║ NixOS Installer ISO ║
╠══════════════════════════════════════════════════════════════╣
║ ║
║ SSH Access: ║
║ ssh root@<ip-address> ║
║ ║
║ Network Setup: ║
║ Wired: Auto-configured via DHCP ║
║ WiFi: nmcli device wifi connect <SSID> --ask ║
║ ║
║ Installation Workflow: ║
║ ║
║ 1. Clone dotfiles: ║
║ git clone git@github.com:moons-14/dotfiles.git ~/dotfiles║
║ ║
║ 2. Generate SSH host key for new host: ║
║ ssh-keygen -t ed25519 -f /tmp/ssh_host_ed25519_key -N "" ║
║ ║
║ 3. Get age public key from SSH host key: ║
║ ssh-to-age -i /tmp/ssh_host_ed25519_key.pub ║
║ ║
║ 4. Add age key to .sops.yaml: ║
║ cd ~/dotfiles ║
║ # Edit .sops.yaml and add the age key ║
║ # Add new host entry to creation_rules ║
║ ║
║ 5. Re-encrypt secrets: ║
║ sops updatekeys secrets/common/system.yaml ║
║ sops updatekeys secrets/hosts/<host>/*.yaml ║
║ ║
║ 6. Create disko.nix for new host: ║
║ # Check disk devices ║
║ lsblk -f ║
║ ║
║ # Create hosts/<host>/disko.nix ║
║ # Example: LUKS + btrfs ║
║ # See hosts/x1g13/disko.nix for reference ║
║ ║
║ 7. Partition disk with disko: ║
║ nix run github:nix-community/disko -- \ ║
║ --mode disko hosts/<host>/disko.nix ║
║ ║
║ 8. Copy host key to installed system: ║
║ mkdir -p /mnt/etc/ssh ║
║ cp /tmp/ssh_host_ed25519_key* /mnt/etc/ssh/ ║
║ chmod 600 /mnt/etc/ssh/ssh_host_ed25519_key ║
║ ║
║ 9. Install NixOS: ║
║ nixos-install --flake ~/dotfiles#<host> ║
║ ║
║ Disko Configuration Examples: ║
║ ║
║ Simple (no encryption): ║
║ disko.devices.disk.main = { ║
║ type = "disk"; ║
║ device = "/dev/sda"; ║
║ content = { ║
║ type = "gpt"; ║
║ partitions = { ║
║ ESP = { size = "512M"; type = "EF00"; ║
║ content = { type = "filesystem"; ║
║ format = "vfat"; mountpoint = "/boot"; }; }; ║
║ root = { size = "100%"; ║
║ content = { type = "filesystem"; ║
║ format = "ext4"; mountpoint = "/"; }; }; ║
║ }; ║
║ }; ║
║ }; ║
║ ║
║ LUKS + btrfs (see hosts/x1g13/disko.nix): ║
║ - Use partuuid for device path ║
║ - Set askPassword = true for LUKS ║
║ - Configure btrfs subvolumes ║
║ ║
╚══════════════════════════════════════════════════════════════╝
'';
systemd.services.installer-banner = {
description = "Display installer help on console";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.coreutils}/bin/cat /etc/installer-help.txt";
StandardOutput = "tty";
TTYPath = "/dev/tty1";
};
};
systemd.services.display-ip = {
description = "Display IP address on console";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = pkgs.writeShellScript "display-ip" ''
sleep 2
echo ""
echo "=== Network Interfaces ==="
${pkgs.iproute2}/bin/ip -4 addr show | ${pkgs.gnugrep}/bin/grep inet
echo ""
echo "=== SSH Access ==="
for ip in $(${pkgs.iproute2}/bin/ip -4 addr show | ${pkgs.gnugrep}/bin/grep -oP 'inet \K[\d.]+' | ${pkgs.gnugrep}/bin/grep -v '127.0.0.1'); do
echo " ssh root@$ip"
done
echo ""
'';
StandardOutput = "tty";
TTYPath = "/dev/tty1";
};
};
nix = {
settings = {
experimental-features = [
"nix-command"
"flakes"
];
trusted-users = [ "root" ];
};
extraOptions = ''
experimental-features = nix-command flakes
'';
};
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}
+101
View File
@@ -0,0 +1,101 @@
# nix-builder bootstrap
The host configuration can be built before its cache signing secret exists.
Harmonia's socket remains stopped until SOPS installs the signing key at
`/run/secrets/harmonia/signing-key`.
## Proxmox storage layout
The host configuration expects three filesystems. Keep the build scratch space
separate from the store so a large build cannot fill the root filesystem.
| Mount point | Suggested size | Contents |
| -------------------- | -------------- | ------------------------------- |
| `/` | 48 GiB | NixOS and mutable system state |
| `/var/lib/nix-build` | 192 GiB | Disposable build scratch space |
| `/nix/store` | 1 TiB | Fleet closures and binary cache |
The build-server policy starts emergency store GC below 64 GiB free and aims
for 128 GiB free. Persistent roots under `/var/lib/nix-fleet/roots` protect the
latest fleet builds from that GC. It also limits Nix to two concurrent
derivations while allowing each derivation to use every vCPU assigned to the
VM.
For the two dedicated ext4 data filesystems, remove the default root-reserved
blocks once after formatting; keep the root filesystem's reserve intact:
```bash
sudo tune2fs -m 0 /dev/disk/by-label/nix-build
sudo tune2fs -m 0 /dev/disk/by-label/nix-store
```
## Initial deployment
Once the VM is reachable as `moons@nix-builder`, deploy it from the repository:
```bash
nix run .#deploy -- .#nix-builder
```
deploy-rs uses the target's `ssh-ng` store, so the system closure is built on
the builder rather than copied from the laptop. Automatic and magic rollback
remain enabled.
## Add the host SOPS recipient
After the VM has a stable SSH host key, derive its age recipient:
```bash
ssh-keyscan -t ed25519 nix-builder 2>/dev/null | ssh-to-age
```
Add the recipient to `.sops.yaml` and add a creation rule for
`secrets/hosts/nix-builder/*.yaml`. The admin YubiKey recipient should remain in
the same key group for recovery.
## Generate the cache signing key
Run this on a trusted Nix machine, preferably with the temporary files on a
tmpfs:
```bash
nix-store --generate-binary-cache-key \
cache.app.homelabs.run-1 \
harmonia.private \
harmonia.public
```
Create `secrets/hosts/nix-builder/system.yaml` with SOPS and store the complete
contents of `harmonia.private` at `harmonia.signing-key`:
```yaml
harmonia:
signing-key: cache.app.homelabs.run-1:REDACTED
```
Copy the complete contents of `harmonia.public` to
`modules/systems/nix/homelab-cache/public-key`. The private plaintext file must
not be committed or retained.
After committing both encrypted/public files, select
`networking.homelab-cache-client` on each client host.
Redeploy the builder and verify the cache after installing the secret:
```bash
nix run .#deploy -- .#nix-builder
curl --fail http://nix-builder:5000/nix-cache-info
```
## Normal operation
Run `fleet-build` on the builder to build and root every NixOS host, or pass a
list of host names to build only those hosts. Run `fleet-deploy` with the normal
deploy-rs target syntax when additional fleet nodes have been added to
`flake/deploy.nix`:
```bash
fleet-build
fleet-build x1g13 galleria
fleet-deploy .#nix-builder
```
+25
View File
@@ -0,0 +1,25 @@
{
fileSystems."/nix/store" = {
device = "/dev/disk/by-label/nix-store";
fsType = "ext4";
options = [
"noatime"
];
neededForBoot = true;
};
fileSystems."/var/lib/nix-build" = {
device = "/dev/disk/by-label/nix-build";
fsType = "ext4";
options = [
"noatime"
];
};
nix.settings.build-dir = "/var/lib/nix-build";
services.fstrim.enable = true;
}
@@ -0,0 +1,40 @@
# 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.
{ lib, modulesPath, ... }:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/49fc2e1c-7909-41cc-ac78-55b4d9a01e62";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/40D4-ABBE";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}
+19
View File
@@ -0,0 +1,19 @@
{ lib, ... }:
let
hostSecrets = ../../secrets/hosts/nix-builder/system.yaml;
in
{
imports = [
./filesystem.nix
./hardware-configuration.nix
];
sops.secrets = lib.mkIf (builtins.pathExists hostSecrets) {
"harmonia/signing-key" = {
sopsFile = hostSecrets;
restartUnits = [ "harmonia.service" ];
};
};
networking.firewall.interfaces."tailscale0".allowedTCPPorts = [ 5000 ];
}
@@ -0,0 +1,36 @@
# Do not modify this file! It was generated by `nixos-generate-config` and may
# be overwritten by future invocations.
{ lib, modulesPath, ... }:
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/8f0eaec6-5dc9-4821-aa8d-fb6809b5a5bf";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/201C-961B";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}
+3
View File
@@ -0,0 +1,3 @@
{
imports = [ ./hardware-configuration.nix ];
}
+89
View File
@@ -0,0 +1,89 @@
_:
let
espPart = "/dev/disk/by-partuuid/a53e3b19-67de-40de-9ded-3eac3117689a";
nixosPart = "/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e";
btrfsMountOptions = [
"compress=zstd"
"noatime"
"ssd"
"space_cache=v2"
];
in
{
disko.enableConfig = true;
disko.devices.disk = {
esp = {
type = "disk";
device = espPart;
destroy = false;
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
nixos = {
type = "disk";
device = nixosPart;
destroy = false;
content = {
type = "luks";
name = "cryptroot";
askPassword = true;
settings.allowDiscards = true;
extraFormatArgs = [
"--type"
"luks2"
"--pbkdf"
"argon2id"
"--label"
"NixOS-LUKS"
];
content = {
type = "btrfs";
extraArgs = [
"-f"
"-L"
"NixOS"
];
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = btrfsMountOptions;
};
"@home" = {
mountpoint = "/home";
mountOptions = btrfsMountOptions;
};
"@nix" = {
mountpoint = "/nix";
mountOptions = btrfsMountOptions;
};
"@log" = {
mountpoint = "/var/log";
mountOptions = btrfsMountOptions;
};
"@swap" = {
mountpoint = "/.swapvol";
mountOptions = [ "noatime" ];
swap.swapfile.size = "32G";
};
};
};
};
};
};
}
+32
View File
@@ -0,0 +1,32 @@
# Do not modify this file! It was generated by `nixos-generate-config`
# and may be overwritten by future invocations. Make changes in nixos.nix.
{
config,
lib,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [
"xhci_pci"
"thunderbolt"
"nvme"
"usb_storage"
"sd_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
swapDevices = [ ];
networking.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
+22
View File
@@ -0,0 +1,22 @@
{
services.kanshi = {
enable = true;
settings = [
{
profile = {
name = "x1g13";
outputs = [
{
criteria = "eDP-1";
status = "enable";
position = "0,0";
scale = 1.5;
}
];
};
}
];
};
}
+9
View File
@@ -0,0 +1,9 @@
{
imports = [
./hardware-configuration.nix
./disko.nix
];
boot.initrd.luks.devices.cryptroot.device =
"/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e";
}
+8 -2
View File
@@ -74,7 +74,10 @@ let
let
homePath = hostFile spec "home.nix";
homeModules = [
(registry.mkModule { class = "home"; })
(registry.mkModule {
class = "home";
systemClass = "nixos";
})
(registry.mkSelectionModule selected)
{ home.stateVersion = spec.stateVersion; }
]
@@ -96,7 +99,10 @@ let
let
homePath = hostFile spec "home.nix";
homeModules = [
(registry.mkModule { class = "home"; })
(registry.mkModule {
class = "home";
systemClass = "darwin";
})
(registry.mkSelectionModule selected)
{ home.stateVersion = spec.stateVersion; }
]
+77 -15
View File
@@ -4,7 +4,7 @@
modulesRoot,
}:
let
reservedFiles = {
rootFragmentFiles = {
common = "common.nix";
nixos = "nixos.nix";
darwin = "darwin.nix";
@@ -12,6 +12,14 @@ let
meta = "meta.nix";
};
homeFragmentFiles = {
homeCommon = "common.nix";
homeNixos = "nixos.nix";
homeDarwin = "darwin.nix";
};
fragmentFileNames = rootFragmentFiles // lib.mapAttrs (_: name: "home/${name}") homeFragmentFiles;
isFile = kind: kind == "regular" || kind == "symlink";
ensure =
@@ -103,13 +111,17 @@ let
);
makeUnit =
relativePath: entries:
relativePath: entries: homeEntries:
let
directory = pathFor relativePath;
id = lib.concatStringsSep "." relativePath;
fragments = lib.mapAttrs (
rootFragments = lib.mapAttrs (
_class: fileName: if entryIsFile entries fileName then directory + "/${fileName}" else null
) reservedFiles;
) rootFragmentFiles;
homeFragments = lib.mapAttrs (
_class: fileName: if entryIsFile homeEntries fileName then directory + "/home/${fileName}" else null
) homeFragmentFiles;
fragments = rootFragments // homeFragments;
baseUnit = {
inherit
id
@@ -138,11 +150,22 @@ let
let
directory = pathFor relativePath;
entries = builtins.readDir directory;
hasReservedFile = lib.any (fileName: entryIsFile entries fileName) (
builtins.attrValues reservedFiles
homeEntries =
if relativePath != [ ] && (entries.home or null) == "directory" then
builtins.readDir (directory + "/home")
else
{ };
hasRootFragment = lib.any (fileName: entryIsFile entries fileName) (
builtins.attrValues rootFragmentFiles
);
childDirectories = lib.filter (name: entries.${name} == "directory") (builtins.attrNames entries);
current = lib.optional hasReservedFile (makeUnit relativePath entries);
hasHomeFragment = lib.any (fileName: entryIsFile homeEntries fileName) (
builtins.attrValues homeFragmentFiles
);
hasFragment = hasRootFragment || hasHomeFragment;
childDirectories = lib.filter (
name: entries.${name} == "directory" && !(name == "home" && hasHomeFragment)
) (builtins.attrNames entries);
current = lib.optional hasFragment (makeUnit relativePath entries homeEntries);
children = lib.concatMap (name: walk (relativePath ++ [ name ])) childDirectories;
in
current ++ children;
@@ -208,12 +231,44 @@ let
"common"
"darwin"
];
home = [ "home" ];
home = {
nixos = [
"home"
"homeCommon"
"homeNixos"
];
darwin = [
"home"
"homeCommon"
"homeDarwin"
];
};
};
fragmentClassesFor =
{
class,
systemClass,
}:
ensure (builtins.hasAttr class fragmentClasses) "unsupported module class '${class}'" (
if class == "home" then
ensure
(builtins.elem systemClass [
"nixos"
"darwin"
])
"the home module class requires systemClass to be 'nixos' or 'darwin'"
fragmentClasses.home.${systemClass}
else
ensure (
systemClass == null
) "systemClass is only supported for the home module class" fragmentClasses.${class}
);
applyFragment =
{
config,
fragmentName,
fragmentPath,
options,
specialArgs,
@@ -244,8 +299,7 @@ let
);
resultValue = if builtins.isFunction fragment then fragment fragmentArgs else fragment;
result =
ensure (builtins.isAttrs resultValue)
"${unit.id}: ${builtins.baseNameOf fragmentPath} must return an attribute set"
ensure (builtins.isAttrs resultValue) "${unit.id}: ${fragmentName} must return an attribute set"
resultValue;
forbiddenKeys = lib.filter (name: builtins.hasAttr name result) [
"imports"
@@ -254,14 +308,20 @@ let
];
in
ensure (forbiddenKeys == [ ])
"${unit.id}: ${builtins.baseNameOf fragmentPath} is a configuration fragment and cannot define top-level ${lib.concatStringsSep ", " forbiddenKeys}"
"${unit.id}: ${fragmentName} is a configuration fragment and cannot define top-level ${lib.concatStringsSep ", " forbiddenKeys}"
result;
externalImports = class: lib.concatMap (unit: unit.meta.imports.${class}) discoveredUnits;
mkModule =
{ class }:
ensure (builtins.hasAttr class fragmentClasses) "unsupported module class '${class}'" (
{
class,
systemClass ? null,
}:
let
selectedFragmentClasses = fragmentClassesFor { inherit class systemClass; };
in
builtins.seq selectedFragmentClasses (
builtins.seq dependencyValidation (
{
config,
@@ -277,6 +337,7 @@ let
map (
fragmentClass:
let
fragmentName = fragmentFileNames.${fragmentClass};
fragmentPath = unit.fragments.${fragmentClass};
in
if fragmentPath == null then
@@ -285,13 +346,14 @@ let
lib.mkIf (enabled config unit) (applyFragment {
inherit
config
fragmentName
fragmentPath
options
specialArgs
unit
;
})
) fragmentClasses.${class}
) selectedFragmentClasses
)
) discoveredUnits;
in
@@ -0,0 +1,4 @@
_: {
programs._1password-gui.enable = true;
programs._1password.enable = true;
}
@@ -1,8 +0,0 @@
{
# The macOS app must live in /Applications for its background integrations,
# including the SSH agent, to work correctly.
homebrew = {
enable = true;
casks = [ "1password" ];
};
}
-7
View File
@@ -1,7 +0,0 @@
{ pkgs, ... }:
{
home.packages = [
pkgs._1password-cli
]
++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [ pkgs._1password-gui ];
}
+2 -5
View File
@@ -1,11 +1,8 @@
{ primaryUser, lib, ... }:
{
programs._1password.enable = true;
programs._1password-gui = {
enable = true;
polkitPolicyOwners = [ primaryUser ];
};
programs._1password-gui.polkitPolicyOwners = [ primaryUser ];
# 1Password SSH Agentと競合するagentを無効化
programs.ssh.startAgent = lib.mkForce false;
programs.gnupg.agent.enableSSHSupport = lib.mkForce false;
services.gnome.gcr-ssh-agent.enable = lib.mkForce false;
@@ -0,0 +1,8 @@
{
homebrew.casks = [ "activitywatch" ];
launchd.agents.activitywatch = {
command = "/usr/bin/open -gja ActivityWatch";
serviceConfig.RunAtLoad = true;
};
}
@@ -0,0 +1,11 @@
{ pkgs, ... }:
{
services.activitywatch = {
enable = true;
watchers.aw-awatcher = {
package = pkgs.awatcher;
executable = "awatcher";
};
};
}
@@ -0,0 +1,3 @@
{
description = "ActivityWatch automated time tracker";
}
+9
View File
@@ -0,0 +1,9 @@
{
programs.atuin = {
enable = true;
enableZshIntegration = true;
enableBashIntegration = true;
enableFishIntegration = true;
};
}
+4
View File
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.baobab ];
}
@@ -0,0 +1,31 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.celluloid ];
xdg.mimeApps = {
enable = true;
defaultApplicationPackages = [ pkgs.celluloid ];
defaultApplications = builtins.listToAttrs (
map
(mime: {
name = mime;
value = [ "io.github.celluloid_player.Celluloid.desktop" ];
})
[
"video/3gpp"
"video/3gpp2"
"video/mp2t"
"video/mp4"
"video/mpeg"
"video/ogg"
"video/quicktime"
"video/webm"
"video/x-flv"
"video/x-m4v"
"video/x-matroska"
"video/x-msvideo"
"video/x-ms-wmv"
]
);
};
}
+6
View File
@@ -0,0 +1,6 @@
{
homebrew = {
enable = true;
casks = [ "google-chrome" ];
};
}
-4
View File
@@ -1,4 +0,0 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.google-chrome ];
}
@@ -0,0 +1,47 @@
{
config,
lib,
pkgs,
...
}:
let
chrome = pkgs.google-chrome.overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ];
postFixup = (old.postFixup or "") + ''
wrapProgram $out/bin/google-chrome-stable \
--set LIBVA_DRIVER_NAME nvidia \
--set NVD_BACKEND direct
'';
});
features = [
"MiddleClickAutoscroll"
"AcceleratedVideoDecoder"
"AcceleratedVideoDecodeLinuxGL"
"PlatformHEVCDecoderSupport"
]
++ lib.optional config.my.hardwares.nvidia.enable "VaapiOnNvidiaGPUs";
in
{
programs.google-chrome = {
enable = true;
package = if config.my.hardwares.nvidia.enable then chrome else pkgs.google-chrome;
commandLineArgs = [
"--enable-features=${lib.concatStringsSep "," features}"
"--use-gl=angle"
"--use-angle=gl"
];
};
xdg.mimeApps = {
enable = true;
defaultApplications = {
"text/html" = "google-chrome.desktop";
"x-scheme-handler/http" = "google-chrome.desktop";
"x-scheme-handler/https" = "google-chrome.desktop";
};
};
}
-25
View File
@@ -1,25 +0,0 @@
{ pkgs, ... }:
let
chromeLauncher = pkgs.makeDesktopItem {
name = "google-chrome";
desktopName = "Google Chrome";
genericName = "Web Browser";
exec = "${pkgs.google-chrome}/bin/google-chrome-stable --enable-features=TouchpadOverscrollHistoryNavigation %U";
icon = "google-chrome";
terminal = false;
categories = [
"Network"
"WebBrowser"
];
startupNotify = true;
};
in
{
environment.systemPackages = [ chromeLauncher ];
xdg.mime.defaultApplications = {
"text/html" = "google-chrome.desktop";
"x-scheme-handler/http" = "google-chrome.desktop";
"x-scheme-handler/https" = "google-chrome.desktop";
};
}
+1 -6
View File
@@ -1,10 +1,5 @@
{ inputs, ... }:
{
_: {
description = "Codex Desktop for Linux";
includes = [ "applications.codex" ];
imports.nixos = [
inputs.codex-desktop-linux.nixosModules.default
];
}
+3 -30
View File
@@ -1,37 +1,10 @@
{
inputs,
lib,
pkgs,
...
}:
let
codexCliPackage = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex;
codexDesktopPackage =
inputs.codex-desktop-linux.packages.${pkgs.stdenv.hostPlatform.system}.codex-desktop-computer-use-ui;
launcher = pkgs.makeDesktopItem {
name = "codex";
desktopName = "Codex";
genericName = "ChatGPT Desktop";
comment = "Run Codex Desktop";
exec = "env CODEX_CLI_PATH=${lib.getExe' codexCliPackage "codex"} BAMF_DESKTOP_FILE_HINT=codex.desktop CHROME_DESKTOP=codex.desktop ${lib.getExe' codexDesktopPackage "codex-desktop"} %u";
icon = "codex-desktop";
terminal = false;
categories = [ "Development" ];
startupNotify = true;
startupWMClass = "codex-desktop";
actions.new-window = {
name = "New Window";
exec = "env CODEX_CLI_PATH=${lib.getExe' codexCliPackage "codex"} BAMF_DESKTOP_FILE_HINT=codex.desktop CHROME_DESKTOP=codex.desktop CODEX_MULTI_LAUNCH=1 ${lib.getExe' codexDesktopPackage "codex-desktop"} --new-instance";
};
};
in
{
programs.codexDesktopLinux = {
enable = true;
package = codexDesktopPackage;
cliPackage = codexCliPackage;
computerUseUi.enable = true;
};
environment.systemPackages = [ launcher ];
environment.systemPackages = [
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.chatgpt
];
}
@@ -0,0 +1,52 @@
{
lib,
pkgs,
inputs,
...
}:
let
codexSessionUsage = inputs.codex-session-usage.packages.${pkgs.stdenv.hostPlatform.system}.default;
in
{
home.packages = [ codexSessionUsage ];
xdg.dataFile = {
"vicinae/scripts/codex-session-usage/start" = {
executable = true;
text = ''
#!${lib.getExe pkgs.bash}
# @vicinae.schemaVersion 1
# @vicinae.title Start Codex Session Usage
# @vicinae.description Start the local Codex session usage dashboard
# @vicinae.mode compact
# @vicinae.icon 📊
# @vicinae.argument1 { "type": "text", "placeholder": "Port (optional)", "optional": true }
if [[ -z "$1" ]]; then
exec ${lib.getExe codexSessionUsage} start
fi
if [[ "$1" =~ ^[0-9]+$ ]] && (( 10#$1 >= 1 && 10#$1 <= 65535 )); then
exec ${lib.getExe codexSessionUsage} start --port "$1"
fi
printf '%s\n' 'Port must be an integer between 1 and 65535.' >&2
exit 2
'';
};
"vicinae/scripts/codex-session-usage/stop" = {
executable = true;
text = ''
#!${lib.getExe pkgs.bash}
# @vicinae.schemaVersion 1
# @vicinae.title Stop Codex Session Usage
# @vicinae.description Stop the local Codex session usage dashboard
# @vicinae.mode compact
# @vicinae.icon 📊
exec ${lib.getExe codexSessionUsage} stop
'';
};
};
}
+13
View File
@@ -0,0 +1,13 @@
model = "gpt-5.6-sol"
model_reasoning_effort = "medium"
approval_policy = "on-request"
approvals_reviewer = "auto_review"
sandbox_mode = "workspace-write"
web_search = "cached"
[sandbox_workspace_write]
network_access = false
[projects."/home/moons/dotfiles"]
trust_level = "trusted"
+34 -4
View File
@@ -1,6 +1,36 @@
{ inputs, pkgs, ... }:
{
home.packages = [
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex
];
config,
inputs,
lib,
pkgs,
...
}:
let
configDirectory =
if config.home.preferXdgDirectories then
"${config.xdg.configHome}/codex"
else
"${config.home.homeDirectory}/.codex";
configFile = "${configDirectory}/config.toml";
in
{
programs.codex = {
enable = true;
package = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex;
skills = {
grilling = inputs.skills + "/skills/productivity/grilling";
};
};
# Keep the repository copy as an initial value. Codex may mutate the live
# file between activations; each Home Manager switch resets it from here.
home.activation.resetCodexConfig = {
after = [ "writeBoundary" ];
before = [ ];
data = ''
${pkgs.coreutils}/bin/mkdir -p ${lib.escapeShellArg configDirectory}
${pkgs.coreutils}/bin/install -m 0600 ${./config.toml} ${lib.escapeShellArg configFile}
'';
};
}
+4
View File
@@ -2,5 +2,9 @@
programs.direnv = {
enable = true;
nix-direnv.enable = true;
config.global = {
warn_timeout = "10s";
};
};
}
+106 -1
View File
@@ -1,3 +1,108 @@
{
programs.vesktop.enable = true;
inputs,
pkgs,
...
}:
let
unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.stdenv.hostPlatform.system};
in
{
programs.vesktop = {
enable = true;
package = unstable.vesktop;
settings = {
discordBranch = "stable";
hardwareAcceleration = true;
hardwareVideoAcceleration = true;
tray = true;
minimizeToTray = true;
# Discord Rich Presence
arRPC = true;
openLinksWithElectron = false;
# Keep WebRTC on the public interface selected by the default route.
# Secondary private interfaces can otherwise stall voice at DTLS.
webRTCIPHandlingPolicy = "default_public_interface_only";
spellCheckLanguages = [
"ja-JP"
"en-US"
];
};
vencord = {
useSystem = false;
settings = {
autoUpdate = true;
autoUpdateNotification = false;
useQuickCss = false;
cloud.settingsSync = false;
notifications = {
position = "bottom-right";
useNative = "not-focused";
timeout = 5000;
logLimit = 50;
};
plugins = {
# プライバシー・安全性
NoTrack.enabled = true;
ClearURLs.enabled = true;
# 設定・セッション
BetterSettings.enabled = true;
BetterSessions.enabled = true;
# 画像・添付ファイル
FixImagesQuality.enabled = true;
ImageZoom.enabled = true;
ViewIcons.enabled = true;
CopyFileContents.enabled = true;
# メッセージ操作
QuickReply.enabled = true;
SendTimestamps.enabled = true;
FullSearchContext.enabled = true;
MessageLinkEmbeds.enabled = true;
Unindent.enabled = true;
ValidReply.enabled = true;
# 通知・誤操作対策
ReadAllNotificationsButton.enabled = true;
NoReplyMention.enabled = true;
NotificationVolume.enabled = true;
# UI・パフォーマンス
NoTypingAnimation.enabled = true;
FavoriteEmojiFirst.enabled = true;
KeepCurrentChannel.enabled = true;
# サーバー・権限確認
PermissionsViewer.enabled = true;
MemberCount.enabled = true;
# ボイス・アクティビティ
CallTimer.enabled = true;
GameActivityToggle.enabled = true;
# Vesktop向け
WebKeybinds.enabled = true;
WebScreenShareFixes.enabled = true;
# Message history
MessageLogger.enabled = true;
ShowHiddenChannels.enabled = true;
};
};
};
};
}
@@ -2,6 +2,5 @@
{
home.packages = [
pkgs.docker-client
pkgs.oxker
];
}
@@ -0,0 +1,6 @@
{ pkgs, ... }:
{
home.packages = [
pkgs.oxker
];
}
+4
View File
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.drawio ];
}
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.easyeffects ];
}
-69
View File
@@ -1,69 +0,0 @@
[Hotkey]
# トリガーキーを押すたびに切り替える
EnumerateWithTriggerKeys=False
# 一時的に第1入力メソッドに切り替える
AltTriggerKeys=
# 切り替え時は第1入力メソッドをスキップする
EnumerateSkipFirst=False
# Time limit in milliseconds for triggering modifier key shortcuts
ModifierOnlyKeyTimeout=250
[Hotkey/TriggerKeys]
1=Zenkaku_Hankaku
[Hotkey/ActivateKeys]
0=Henkan
[Hotkey/DeactivateKeys]
0=Muhenkan
[Hotkey/PrevPage]
0=Up
[Hotkey/NextPage]
0=Down
[Hotkey/PrevCandidate]
0=Shift+Tab
[Hotkey/NextCandidate]
0=Tab
[Hotkey/TogglePreedit]
0=Control+Alt+P
[Behavior]
# デフォルトで有効にする
ActiveByDefault=False
# フォーカス時に状態をリセット
resetStateWhenFocusIn=No
# 入力状態を共有する
ShareInputState=No
# アプリケーションにプリエディットを表示する
PreeditEnabledByDefault=True
# 入力メソッドを切り替える際に入力メソッドの情報を表示する
ShowInputMethodInformation=True
# フォーカスを変更する際に入力メソッドの情報を表示する
showInputMethodInformationWhenFocusIn=False
# 入力メソッドの情報をコンパクトに表示する
CompactInputMethodInformation=True
# 第1入力メソッドの情報を表示する
ShowFirstInputMethodInformation=True
# デフォルトのページサイズ
DefaultPageSize=5
# XKB オプションより優先する
OverrideXkbOption=False
# カスタム XKB オプション
CustomXkbOption=
# Force Enabled Addons
EnabledAddons=
# Force Disabled Addons
DisabledAddons=
# Preload input method to be used by default
PreloadInputMethod=True
# パスワード欄に入力メソッドを許可する
AllowInputMethodForPassword=False
# パスワード入力時にプリエディットテキストを表示する
ShowPreeditForPassword=False
# ユーザーデータを保存する間隔(分)
AutoSavePeriod=30
-6
View File
@@ -1,6 +0,0 @@
{
home.file.".config/fcitx5/config" = {
recursive = true;
source = ./config;
};
}
@@ -0,0 +1,82 @@
{ inputs, pkgs, ... }:
{
services.hazkey = {
enable = true;
server.package =
inputs.nix-hazkey.packages.${pkgs.stdenv.hostPlatform.system}.hazkey-server.override
{ enableVulkan = true; };
};
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5 = {
waylandFrontend = true;
addons = with pkgs; [
fcitx5-gtk
kdePackages.fcitx5-qt
qt6Packages.fcitx5-configtool
];
settings = {
inputMethod = {
GroupOrder."0" = "Default";
"Groups/0" = {
Name = "Default";
"Default Layout" = "jp";
DefaultIM = "hazkey";
};
"Groups/0/Items/0" = {
Name = "keyboard-jp";
};
"Groups/0/Items/1" = {
Name = "hazkey";
};
};
globalOptions = {
Hotkey = {
EnumerateWithTriggerKeys = false;
EnumerateSkipFirst = false;
ModifierOnlyKeyTimeout = 250;
};
"Hotkey/TriggerKeys"."1" = "Zenkaku_Hankaku";
"Hotkey/ActivateKeys"."0" = "Henkan";
"Hotkey/DeactivateKeys"."0" = "Muhenkan";
"Hotkey/PrevPage"."0" = "Up";
"Hotkey/NextPage"."0" = "Down";
"Hotkey/PrevCandidate"."0" = "Shift+Tab";
"Hotkey/NextCandidate"."0" = "Tab";
"Hotkey/TogglePreedit"."0" = "Control+Alt+P";
Behavior = {
ActiveByDefault = false;
resetStateWhenFocusIn = "No";
ShareInputState = "No";
PreeditEnabledByDefault = true;
ShowInputMethodInformation = true;
showInputMethodInformationWhenFocusIn = false;
CompactInputMethodInformation = true;
ShowFirstInputMethodInformation = true;
DefaultPageSize = 5;
OverrideXkbOption = false;
CustomXkbOption = "";
EnabledAddons = "";
DisabledAddons = "";
PreloadInputMethod = true;
AllowInputMethodForPassword = false;
ShowPreeditForPassword = false;
AutoSavePeriod = 30;
};
};
};
};
};
}
+6
View File
@@ -0,0 +1,6 @@
{ inputs, ... }:
{
description = "Fcitx 5 input method framework with Hazkey Japanese input";
imports.home = [ inputs.nix-hazkey.homeModules.hazkey ];
}
-34
View File
@@ -1,34 +0,0 @@
{ pkgs, ... }:
{
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5 = {
waylandFrontend = true;
addons = with pkgs; [
fcitx5-mozc-ut
fcitx5-gtk
kdePackages.fcitx5-qt
qt6Packages.fcitx5-configtool
];
settings.inputMethod = {
GroupOrder."0" = "Default";
"Groups/0" = {
Name = "Default";
"Default Layout" = "jp";
DefaultIM = "mozc";
};
"Groups/0/Items/0" = {
Name = "keyboard-jp";
Layout = "";
};
"Groups/0/Items/1" = {
Name = "mozc";
Layout = "";
};
};
};
};
}
+4
View File
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.ffmpeg ];
}
+15
View File
@@ -0,0 +1,15 @@
{
system.defaults.finder = {
AppleShowAllExtensions = true;
AppleShowAllFiles = false;
ShowPathbar = true;
ShowStatusBar = true;
_FXShowPosixPathInTitle = true;
_FXSortFoldersFirst = true;
FXDefaultSearchScope = "SCcf";
FXPreferredViewStyle = "Nlsv";
NewWindowTarget = "Home";
FXEnableExtensionChangeWarning = true;
FXRemoveOldTrashItems = true;
};
}
+17
View File
@@ -0,0 +1,17 @@
{
programs.gamemode = {
enable = true;
enableRenice = true;
settings = {
general = {
softrealtime = "auto";
renice = 10;
};
custom = {
start = "notify-send -a 'Gamemode' 'Optimizations activated'";
end = "notify-send -a 'Gamemode' 'Optimizations deactivated'";
};
};
};
}
+6
View File
@@ -0,0 +1,6 @@
{
programs.gamescope = {
enable = true;
capSysNice = true;
};
}
@@ -1,25 +1,12 @@
{
inputs,
pkgs,
...
}:
let
package =
if pkgs.stdenv.hostPlatform.isLinux then
inputs.ghostty.packages.${pkgs.stdenv.hostPlatform.system}.ghostty-releasefast
else
null;
in
{
_: {
programs.ghostty = {
enable = true;
inherit package;
systemd.enable = pkgs.stdenv.hostPlatform.isLinux;
settings = {
theme = "dracula";
background-blur-radius = 20;
background-opacity = 0.9;
background-opacity-cells = true;
font-family = "BlexMono Nerd Font Mono";
mouse-hide-while-typing = true;
window-decoration = "auto";
@@ -30,11 +17,14 @@ in
"ctrl+shift+t=new_tab"
"ctrl+alt+left_bracket=previous_tab"
"ctrl+alt+right_bracket=next_tab"
"ctrl+alt+q=close_window"
"alt+q=close_window"
"global:alt+space=toggle_quick_terminal"
"global:alt+t=new_window"
"ctrl+shift+semicolon=increase_font_size:1"
"ctrl+shift+minus=decrease_font_size:1"
];
quick-terminal-screen = "mouse";
quick-terminal-position = "top";
quick-terminal-size = "98%,100%";
quick-terminal-autohide = false;
@@ -0,0 +1,17 @@
_: {
# Global Ghostty keybindings are handled by the running app. Start it hidden
# at login so Option+T and Option+Space work before opening a terminal.
launchd.agents.ghostty-global-keybindings = {
enable = true;
config = {
ProgramArguments = [
"/usr/bin/open"
"-gja"
"Ghostty"
];
RunAtLoad = true;
};
};
programs.ghostty.package = null;
}
@@ -0,0 +1,12 @@
{ inputs, system, ... }: {
programs.ghostty = {
# Labwc's Close action correctly targets one xdg-toplevel, but Ghostty's
# systemd service runs every window in one GTK single-instance process.
# If that process exits while handling the request, every Ghostty window
# disappears together. Keep each launcher invocation independent instead.
systemd.enable = false;
package = inputs.ghostty.packages.${system}.default;
settings.gtk-single-instance = false;
};
}
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.gnome-disk-utility ];
}
@@ -0,0 +1,24 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.gnome-text-editor ];
dconf.settings."org/gnome/TextEditor" = {
style-variant = "follow";
wrap-text = true;
spellcheck = true;
restore-session = true;
show-line-numbers = false;
show-right-margin = false;
show-map = false;
highlight-current-line = false;
auto-indent = false;
discover-settings = false;
enable-snippets = false;
keybindings = "default";
};
xdg.mimeApps = {
enable = true;
defaultApplicationPackages = [ pkgs.gnome-text-editor ];
};
}
-56
View File
@@ -1,56 +0,0 @@
{ pkgs, lib, ... }:
lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
dconf.settings = {
"org/gnome/desktop/sound" = {
event-sounds = false;
input-feedback-sounds = false;
};
"org/gnome/desktop/wm/keybindings" = {
close = [ "<Super>q" ];
show-desktop = [ ];
};
"org/gnome/settings-daemon/plugins/media-keys" = {
home = [ ];
screensaver = [ "<Super>l" ];
custom-keybindings = [
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom2/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom3/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom4/"
];
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0" = {
name = "Open Terminal";
command = "ghostty";
binding = "<Super>t";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1" = {
name = "Run Application";
command = "vicinae toggle";
binding = "<Super>d";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom2" = {
name = "Open File Manager";
command = "nautilus --new-window";
binding = "<Super>e";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom3" = {
name = "Clipboard History";
command = "vicinae vicinae://extensions/vicinae/clipboard/history";
binding = "<Super>v";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom4" = {
name = "Log Out";
command = "gnome-session-quit --logout --no-prompt";
binding = "<Super><Shift>e";
};
"org/gnome/shell".favorite-apps = [
"google-chrome.desktop"
"code.desktop"
"com.mitchellh.ghostty.desktop"
"slack.desktop"
"vesktop.desktop"
];
};
}
-10
View File
@@ -1,10 +0,0 @@
{ pkgs, lib, ... }:
{
services.desktopManager.gnome.enable = true;
services.displayManager.gdm.enable = lib.mkForce false;
environment.systemPackages = [
pkgs.gnome-tweaks
pkgs.gnome-extension-manager
];
}
+3 -6
View File
@@ -1,9 +1,6 @@
{ inputs, pkgs, ... }:
let
grok = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.grok.overrideAttrs (_: {
versionCheckProgram = "${placeholder "out"}/libexec/grok/grok-launcher";
});
in
{
home.packages = [ grok ];
home.packages = [
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.grok
];
}
+4
View File
@@ -15,4 +15,8 @@
name = "Papirus-Dark";
};
};
dconf.settings."org/gnome/desktop/wm/preferences" = {
button-layout = ":minimize,maximize,close";
};
}
+1
View File
@@ -2,4 +2,5 @@
programs.dconf.enable = true;
programs.seahorse.enable = true;
services.gnome.gnome-keyring.enable = true;
security.pam.services.ly.enableGnomeKeyring = true;
}
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.python314Packages.huggingface-hub ];
}
+225
View File
@@ -0,0 +1,225 @@
{ lib, pkgs, ... }:
let
systemctl = lib.getExe' pkgs.systemd "systemctl";
keybind = key: actionAttrs: {
"@key" = key;
action = actionAttrs;
};
action =
key: name:
keybind key {
"@name" = name;
};
execute =
key: command:
keybind key {
"@name" = "Execute";
"@command" = command;
};
snapToEdge =
key: direction:
keybind key {
"@name" = "SnapToEdge";
"@direction" = direction;
"@combine" = "yes";
};
confirmAction = key: message: name: {
"@key" = key;
action = {
"@name" = "If";
prompt."@message" = message;
"then".action."@name" = name;
};
};
menuExecute = label: command: {
inherit label;
action = {
name = "Execute";
inherit command;
};
};
showMenu = button: menu: {
"@button" = button;
"@action" = "Press";
action = {
"@name" = "ShowMenu";
"@menu" = menu;
};
};
menuAction = label: name: {
inherit label;
action.name = name;
};
in
{
wayland.windowManager.labwc = {
enable = true;
# NixOS owns the package so Home Manager only generates the user config.
package = null;
systemd = {
enable = true;
variables = [
"DISPLAY"
"WAYLAND_DISPLAY"
"XDG_CURRENT_DESKTOP"
"XDG_SESSION_TYPE"
];
};
menu = [
{
menuId = "root-menu";
items = [
(menuExecute "ターミナル" "ghostty")
(menuExecute "Vicinae" "vicinae toggle")
(menuExecute "ファイル" "nautilus --new-window")
{ separator = true; }
(menuAction "Reconfigure" "Reconfigure")
(menuAction "Exit" "Exit")
];
}
];
rc = {
keyboard = {
default = true;
numlock = "on";
keybind = [
# labwc window management
(action "W-q" "Close")
(action "W-f" "ToggleMaximize")
(action "W-c" "Iconify")
(action "W-Up" "Lower")
(action "W-Down" "Raise")
(action "W-Left" "NextWindow")
(action "W-Right" "PreviousWindow")
(snapToEdge "W-C-Left" "left")
(snapToEdge "W-C-Right" "right")
(snapToEdge "W-C-Up" "up")
(snapToEdge "W-C-Down" "down")
(confirmAction "W-S-e" "Exit labwc?" "Exit")
(execute "Print" "screenshot region")
(execute "C-Print" "screenshot output")
(execute "A-Print" "screenshot all")
# spawn applications (sync with niri modules/applications/niri/home.nix)
(execute "W-t" "ghostty")
(execute "W-d" "vicinae toggle")
(execute "W-s" "noctalia msg panel-toggle launcher")
(execute "W-e" "nautilus --new-window")
(execute "W-l" "loginctl lock-session")
(execute "W-v" "vicinae vicinae://launch/clipboard/history")
(execute "W-j" "nani-translate-primary")
(execute "W-S-j" "nani-translate-ocr")
(execute "W-C-j" "${lib.getExe' pkgs.xdg-utils "xdg-open"} naniapp://translate")
(execute "W-space" "ghostty +toggle-quick-terminal")
(execute "W-p" "wdisplays")
(execute "W-z" "wl-find-cursor -c 0xCCFF453A -s 160 -d 1200")
# Function keys (sync with niri modules/applications/niri/home.nix)
(execute "XF86AudioRaiseVolume" "noctalia msg volume-up")
(execute "XF86AudioLowerVolume" "noctalia msg volume-down")
(execute "XF86AudioMute" "noctalia msg volume-mute")
(execute "XF86AudioMicMute" "noctalia msg mic-mute")
(execute "XF86MonBrightnessUp" "noctalia msg brightness-up")
(execute "XF86MonBrightnessDown" "noctalia msg brightness-down")
(execute "XF86Favorites" "noctalia msg caffeine-toggle")
(execute "XF86AudioPlay" "playerctl play-pause")
(execute "XF86AudioPause" "playerctl play-pause")
(execute "XF86AudioStop" "playerctl stop")
(execute "XF86AudioPrev" "playerctl previous")
(execute "XF86AudioNext" "playerctl next")
(execute "XF86Display" "wdisplays")
];
};
core = {
decoration = "client";
gap = 10;
autoEnableOutputs = "yes";
reuseOutputMode = "yes";
};
theme = {
name = "Dracula";
cornerRadius = 8;
dropShadows = "yes";
dropShadowsOnTiled = "yes";
};
windowSwitcher = {
"@preview" = "yes";
"@outlines" = "yes";
osd = {
"@style" = "thumbnail";
};
};
focus = {
followMouse = "yes";
followMouseRequiresMovement = "yes";
raiseOnFocus = "no";
};
desktops = {
"@number" = 1;
"@popupTime" = 500;
"@prefix" = "Workspace";
};
mouse = {
default = true;
context = {
"@name" = "Desktop";
mousebind = [
(showMenu "Right" "root-menu")
(showMenu "Middle" "client-list-combined-menu")
];
};
};
libinput.device = [
{
"@category" = "touchpad";
naturalScroll = "yes";
tap = "yes";
tapAndDrag = "yes";
dragLock = "yes";
clickMethod = "clickfinger";
scrollMethod = "twoFinger";
scrollFactor = "4.0";
disableWhileTyping = "yes";
}
{
"@category" = "non-touch";
pointerSpeed = "-0.1";
accelProfile = "flat";
}
];
};
environment = [
"XKB_DEFAULT_LAYOUT=jp"
"XKB_DEFAULT_OPTIONS=ctrl:nocaps"
];
};
xdg.configFile."labwc/shutdown".text = lib.mkAfter ''
${systemctl} --user stop graphical-session.target
'';
}
+9
View File
@@ -0,0 +1,9 @@
{
description = "labwc Wayland stacking compositor";
includes = [
"systems.wayland"
"applications.screenshot"
"applications.wl-find-cursor"
];
}
+57
View File
@@ -0,0 +1,57 @@
{
inputs,
lib,
pkgs,
...
}:
let
unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.stdenv.hostPlatform.system};
in
{
programs.labwc = {
enable = true;
package = unstable.labwc;
};
xdg.portal.config.labwc.default = [
"wlr"
"gtk"
];
# xdg-desktop-portal-wlr implements screencasting for wlroots compositors.
# Keep it with Labwc: Niri uses xdg-desktop-portal-gnome instead.
xdg.portal.wlr = {
enable = true;
settings.screencast = {
chooser_type = "dmenu";
chooser_cmd = "${pkgs.fuzzel}/bin/fuzzel --dmenu";
};
};
# NixOS decides whether a graphical session manages graphical-session.target
# itself by checking XDG_CURRENT_DESKTOP against a hard-coded list. Labwc is
# currently absent from that list, so NixOS starts
# nixos-fake-graphical-session.target before Labwc is ready.
#
# This configuration uses Home Manager's Labwc systemd integration, which
# imports the Wayland environment and starts labwc-session.target correctly.
# Mark the Labwc session as systemd-aware before the display-manager wrapper
# performs its hard-coded check. Otherwise services such as Fcitx5 can start
# before WAYLAND_DISPLAY is available.
#
# Despite the services.xserver namespace, this session wrapper is also used
# for Wayland sessions by display managers such as Ly.
services.xserver.displayManager.sessionCommands = lib.mkAfter ''
case ":''${XDG_CURRENT_DESKTOP:-}:" in
*:labwc:*)
case ":$XDG_CURRENT_DESKTOP:" in
*:X-NIXOS-SYSTEMD-AWARE:*)
;;
*)
export XDG_CURRENT_DESKTOP="$XDG_CURRENT_DESKTOP:X-NIXOS-SYSTEMD-AWARE"
;;
esac
;;
esac
'';
}
+22
View File
@@ -0,0 +1,22 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.loupe ];
xdg.mimeApps = {
enable = true;
defaultApplicationPackages = [ pkgs.loupe ];
defaultApplications = {
"image/avif" = [ "org.gnome.Loupe.desktop" ];
"image/bmp" = [ "org.gnome.Loupe.desktop" ];
"image/gif" = [ "org.gnome.Loupe.desktop" ];
"image/heic" = [ "org.gnome.Loupe.desktop" ];
"image/heif" = [ "org.gnome.Loupe.desktop" ];
"image/jpeg" = [ "org.gnome.Loupe.desktop" ];
"image/jxl" = [ "org.gnome.Loupe.desktop" ];
"image/png" = [ "org.gnome.Loupe.desktop" ];
"image/svg+xml" = [ "org.gnome.Loupe.desktop" ];
"image/webp" = [ "org.gnome.Loupe.desktop" ];
};
};
}
@@ -0,0 +1,3 @@
_: {
programs.mangohud.enable = true;
}
@@ -0,0 +1,6 @@
{
homebrew = {
enable = true;
casks = [ "prismlauncher" ];
};
}
@@ -0,0 +1,44 @@
{ pkgs, ... }: {
home.packages = [ pkgs.packwiz ];
programs.prismlauncher = {
enable = true;
package = null;
settings = {
UseSystemLocale = true;
# Minecraftのバージョンに応じてJavaを切り替える。
AutomaticJavaSwitch = true;
IgnoreJavaCompatibility = false;
# 軽量~中規模構成のグローバル既定値。
MinMemAlloc = 512;
MaxMemAlloc = 4096;
LowMemWarning = true;
# 通常はコンソールを隠し、異常時だけ表示する。
ShowConsole = false;
ShowConsoleOnError = true;
LogPrePostOutput = true;
ConsoleMaxLines = 100000;
ConsoleOverflowStop = true;
# Mod管理。
ModMetadataDisabled = false;
ModDependenciesDisabled = false;
SkipModpackUpdatePrompt = false;
ShowModIncompat = true;
DownloadGameFilesDuringInstanceCreation = true;
# プレイ時間。
RecordGameTime = true;
ShowGameTime = true;
ShowGlobalGameTime = true;
MetaRefreshOnLaunch = true;
};
};
}
@@ -0,0 +1,5 @@
_: {
programs.prismlauncher.settings = {
AutomaticJavaDownload = true;
};
}
@@ -0,0 +1,8 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.prismlauncher ];
programs.prismlauncher.settings = {
EnableFeralGamemode = true;
};
}
@@ -0,0 +1,6 @@
{
homebrew = {
enable = true;
casks = [ "moonlight" ];
};
}
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.moonlight-qt ];
}
+6
View File
@@ -0,0 +1,6 @@
{
homebrew = {
enable = true;
casks = [ "nani" ];
};
}
+78
View File
@@ -0,0 +1,78 @@
{ pkgs, ... }:
let
tessdataBest = pkgs.runCommand "tessdata-best-jpn-eng-chi-sim" { } ''
mkdir -p "$out"
ln -s ${
pkgs.fetchurl {
url = "https://github.com/tesseract-ocr/tessdata_best/raw/main/jpn.traineddata";
hash = "sha256-Nr35rII/WRHmJMMNBVPokLirx8MaZbPvFNqUNljEC3k=";
}
} "$out/jpn.traineddata"
ln -s ${
pkgs.fetchurl {
url = "https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata";
hash = "sha256-goCu0Hgv4nJXpo6hD+fvMkyg+Nhb0v0UXRwrVgvLZro=";
}
} "$out/eng.traineddata"
ln -s ${
pkgs.fetchurl {
url = "https://github.com/tesseract-ocr/tessdata_best/raw/main/chi_sim.traineddata";
hash = "sha256-T+8tEwbI6HYW1NPkxsZ/r11EvjNCKQz48vD246p+c1s=";
}
} "$out/chi_sim.traineddata"
'';
tesseract = pkgs.tesseract5.override {
tessdata = tessdataBest;
};
naniTranslatePrimary = pkgs.writeShellApplication {
name = "nani-translate-primary";
runtimeInputs = with pkgs; [
jq
wl-clipboard
xdg-utils
];
text = ''
selected_text="$(wl-paste --primary --no-newline)" || exit 0
[ -n "$selected_text" ] || exit 0
encoded_text="$(printf '%s' "$selected_text" | jq -sRr @uri)"
exec xdg-open "naniapp://translate?source=$encoded_text"
'';
};
naniTranslateOcr = pkgs.writeShellApplication {
name = "nani-translate-ocr";
runtimeInputs = with pkgs; [
grim
jq
slurp
tesseract
xdg-utils
];
text = ''
geometry="$(slurp)" || exit 0
captured_text="$(
grim -g "$geometry" - \
| tesseract stdin stdout -l jpn+eng+chi_sim --oem 1 --psm 6
)"
[ -n "$captured_text" ] || exit 0
encoded_text="$(printf '%s' "$captured_text" | jq -sRr @uri)"
exec xdg-open "naniapp://translate?source=$encoded_text"
'';
};
in
{
programs.naniTranslateLinux.enable = true;
xdg.mimeApps.defaultApplications."x-scheme-handler/naniapp" = "nani.desktop";
home.packages = [
naniTranslatePrimary
naniTranslateOcr
];
}
+8
View File
@@ -0,0 +1,8 @@
{ inputs, ... }:
{
description = "Nani Translate application";
imports.home = [
inputs.nani-translate-linux.homeManagerModules.default
];
}
-8
View File
@@ -1,8 +0,0 @@
{ pkgs, lib, ... }:
lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
home.packages = [
pkgs.nautilus
pkgs.gvfs
pkgs.sushi
];
}
@@ -0,0 +1,167 @@
{
config,
lib,
pkgs,
...
}:
let
nautilusExtensionDir = "${pkgs.nautilus-python}/lib/nautilus/extensions-4";
in
{
home.packages = [
pkgs.nautilus
pkgs.nautilus-python
pkgs.sushi
];
# Nautilus に nautilus-python のC拡張を認識させる。
# home.sessionVariables:
# 通常のログインセッションやシェルから起動したNautilus向け
#
# systemd.user.sessionVariables:
# D-Bus/systemdユーザーサービス経由で起動したNautilus向け
home.sessionVariables.NAUTILUS_4_EXTENSION_DIR = nautilusExtensionDir;
systemd.user.sessionVariables.NAUTILUS_4_EXTENSION_DIR = nautilusExtensionDir;
xdg.dataFile."nautilus-python/extensions/open-in-editor.py".text = ''
import os
import subprocess
from gi.repository import GObject, Nautilus
class OpenInEditorExtension(
GObject.GObject,
Nautilus.MenuProvider,
):
EDITORS = (
(
"vscode",
"VS Code で開く",
["${lib.getExe pkgs.vscode}"],
),
(
"zed",
"Zed で開く",
["${lib.getExe pkgs.zed-editor}"],
),
(
"neovim",
"Neovim で開く",
[
"${lib.getExe pkgs.ghostty}",
"-e",
"${lib.getExe pkgs.neovim}",
],
),
)
@staticmethod
def get_local_paths(files):
paths = []
for file in files:
location = file.get_location()
if location is None:
return []
path = location.get_path()
if path is None:
return []
paths.append(path)
return paths
@staticmethod
def get_working_directory(paths):
path = paths[0]
return path if os.path.isdir(path) else os.path.dirname(path)
@staticmethod
def launch(_item, command):
subprocess.Popen(
command,
start_new_session=True,
close_fds=True,
)
def create_items(self, context, paths):
items = []
for editor_id, label, command in self.EDITORS:
item = Nautilus.MenuItem(
# 選択項目用と背景用で異なるIDにする
name=f"OpenInEditor::{context}::{editor_id}",
label=label,
)
item.connect(
"activate",
self.launch,
[*command, *paths],
)
items.append(item)
item = Nautilus.MenuItem(
name=f"OpenInEditor::{context}::ghostty",
label="Ghostty で開く",
)
item.connect(
"activate",
self.launch,
[
"${lib.getExe pkgs.ghostty}",
f"--working-directory={self.get_working_directory(paths)}",
],
)
items.append(item)
return items
def get_file_items(self, files):
paths = self.get_local_paths(files)
if not paths:
return []
# 選択中のファイル・ディレクトリを渡す
return self.create_items("selection", paths)
def get_background_items(self, current_folder):
paths = self.get_local_paths([current_folder])
if not paths:
return []
# 何も選択せず背景を右クリックした場合だけ現在位置を渡す
return self.create_items("background", paths)
'';
dconf.settings = {
"org/gnome/nautilus/preferences" = {
always-use-location-entry = true;
default-folder-viewer = "list-view";
};
"org/gnome/nautilus/list-view".use-tree-view = true;
# Nautilus 50 migrates this setting from GTK 3 to GTK 4.
"org/gtk/settings/file-chooser".show-hidden = true;
"org/gtk/gtk4/settings/file-chooser".show-hidden = true;
};
gtk.gtk3.bookmarks = [
"file://${config.home.homeDirectory}/Desktop Desktop"
"file://${config.home.homeDirectory}/Pictures Pictures"
"file://${config.home.homeDirectory}/Downloads Downloads"
"file://${config.home.homeDirectory}/Projects Projects"
];
}
+38 -1
View File
@@ -1,5 +1,42 @@
{ config, pkgs, ... }:
{
home.packages = [ pkgs.nh ];
home.sessionVariables.NH_FLAKE = "${config.home.homeDirectory}/dotfiles";
home.sessionVariables = {
NH_FLAKE = "${config.home.homeDirectory}/dotfiles";
NH_SHOW_ACTIVATION_LOGS = "1";
};
programs.zsh.initContent = ''
export SUDO_PROMPT=$'\a[sudo] authenticate for %u: '
nh() {
local notify=false
local argument
case "$1:$2" in
os:switch | os:build) notify=true ;;
esac
for argument in "$@"; do
if [[ "$argument" == "--update" ]]; then
notify=true
break
fi
done
command nh "$@"
local status=$?
if [[ "$notify" == true ]]; then
printf '\a'
if ((status == 0)); then
print -P "%F{green}nh completed%f"
else
print -P "%F{red}nh failed (exit $status)%f"
fi
fi
return "$status"
}
'';
}
@@ -1,44 +1,91 @@
# niri のデフォルトキーバインド。編集しないこと。
{
"Mod+Shift+Slash".action.show-hotkey-overlay = { };
"Mod+T" = {
hotkey-overlay.title = "Open a Terminal: alacritty";
action.spawn = "alacritty";
};
"Mod+D" = {
hotkey-overlay.title = "Run an Application: fuzzel";
action.spawn = "fuzzel";
};
"Super+Alt+L" = {
hotkey-overlay.title = "Lock the Screen: swaylock";
action.spawn = "swaylock";
};
"Super+Alt+S" = {
allow-when-locked = true;
hotkey-overlay.hidden = true;
action.spawn-sh = "pkill orca || exec orca";
};
"XF86AudioRaiseVolume" = {
allow-when-locked = true;
action.spawn = [
"wpctl"
"set-volume"
"@DEFAULT_AUDIO_SINK@"
"0.1+"
];
action.spawn-sh = "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+ -l 1.0";
};
"XF86AudioLowerVolume" = {
allow-when-locked = true;
action.spawn = [
"wpctl"
"set-volume"
"@DEFAULT_AUDIO_SINK@"
"0.1-"
];
action.spawn-sh = "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-";
};
"XF86AudioMute" = {
allow-when-locked = true;
action.spawn = [
"wpctl"
"set-mute"
"@DEFAULT_AUDIO_SINK@"
"toggle"
];
action.spawn-sh = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
};
"XF86AudioMicMute" = {
allow-when-locked = true;
action.spawn-sh = "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle";
};
"XF86AudioPlay" = {
allow-when-locked = true;
action.spawn-sh = "playerctl play-pause";
};
"XF86AudioPause" = {
allow-when-locked = true;
action.spawn-sh = "playerctl play-pause";
};
"XF86AudioStop" = {
allow-when-locked = true;
action.spawn-sh = "playerctl stop";
};
"XF86AudioPrev" = {
allow-when-locked = true;
action.spawn-sh = "playerctl previous";
};
"XF86AudioNext" = {
allow-when-locked = true;
action.spawn-sh = "playerctl next";
};
"XF86MonBrightnessUp" = {
allow-when-locked = true;
action.spawn = [
"wpctl"
"set-mute"
"@DEFAULT_AUDIO_SOURCE@"
"toggle"
"brightnessctl"
"--class=backlight"
"set"
"+10%"
];
};
"XF86MonBrightnessDown" = {
allow-when-locked = true;
action.spawn = [
"brightnessctl"
"--class=backlight"
"set"
"10%-"
];
};
"Mod+Q".action.close-window = { };
"Mod+O" = {
repeat = false;
action.toggle-overview = { };
};
"Mod+Q" = {
repeat = false;
action.close-window = { };
};
"Mod+Left".action.focus-column-left = { };
"Mod+Down".action.focus-window-down = { };
@@ -130,6 +177,7 @@
"Mod+7".action.focus-workspace = 7;
"Mod+8".action.focus-workspace = 8;
"Mod+9".action.focus-workspace = 9;
"Mod+Ctrl+1".action.move-column-to-workspace = 1;
"Mod+Ctrl+2".action.move-column-to-workspace = 2;
"Mod+Ctrl+3".action.move-column-to-workspace = 3;
@@ -140,21 +188,46 @@
"Mod+Ctrl+8".action.move-column-to-workspace = 8;
"Mod+Ctrl+9".action.move-column-to-workspace = 9;
"Mod+BracketLeft".action.consume-or-expel-window-left = { };
"Mod+BracketRight".action.consume-or-expel-window-right = { };
"Mod+Comma".action.consume-window-into-column = { };
"Mod+Period".action.expel-window-from-column = { };
"Mod+R".action.switch-preset-column-width = { };
"Mod+Shift+R".action.reset-window-height = { };
"Mod+Shift+R".action.switch-preset-column-width-back = { };
"Mod+Ctrl+Shift+R".action.switch-preset-window-height = { };
"Mod+Ctrl+R".action.reset-window-height = { };
"Mod+F".action.maximize-column = { };
"Mod+Shift+F".action.fullscreen-window = { };
"Mod+M".action.maximize-window-to-edges = { };
"Mod+Ctrl+F".action.expand-column-to-available-width = { };
"Mod+C".action.center-column = { };
"Mod+Ctrl+C".action.center-visible-columns = { };
"Mod+Minus".action.set-column-width = "-10%";
"Mod+Equal".action.set-column-width = "+10%";
"Mod+Shift+Minus".action.set-window-height = "-10%";
"Mod+Shift+Equal".action.set-window-height = "+10%";
"Mod+V".action.toggle-window-floating = { };
"Mod+Shift+V".action.switch-focus-between-floating-and-tiling = { };
"Mod+W".action.toggle-column-tabbed-display = { };
"Print".action.screenshot = { };
"Ctrl+Print".action.screenshot-screen = { };
"Alt+Print".action.screenshot-window = { };
"Mod+Escape" = {
allow-inhibiting = false;
action.toggle-keyboard-shortcuts-inhibit = { };
};
"Mod+Shift+E".action.quit = { };
"Ctrl+Alt+Delete".action.quit = { };
"Mod+Shift+P".action.power-off-monitors = { };
}
@@ -4,98 +4,10 @@ let
in
{
programs.niri.settings = {
input = {
touchpad = {
natural-scroll = true;
scroll-factor = 4.0;
scroll-method = "two-finger";
click-method = "clickfinger";
drag = true;
drag-lock = true;
};
keyboard.xkb = {
layout = "jp";
options = "ctrl:nocaps";
};
mouse = {
accel-profile = "flat";
accel-speed = -0.1;
};
warp-mouse-to-focus.enable = true;
focus-follows-mouse = {
enable = true;
max-scroll-amount = "0%";
};
};
spawn-at-startup = [
{ command = [ "noctalia" ]; }
{
command = [
"${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"
];
}
];
cursor.size = 16;
layout = {
focus-ring = {
active.color = "#bd93f9";
inactive.color = "#6272a4";
};
border = {
active.color = "#ffc87f";
inactive.color = "#505050";
urgent.color = "#9b0000";
};
shadow.color = "#0007";
background-color = "transparent";
};
binds = keybindings // {
"Mod+T" = {
action.spawn = "ghostty";
hotkey-overlay.title = "Open a Terminal: ghostty";
};
"Mod+D" = {
action.spawn = [
"vicinae"
"toggle"
];
hotkey-overlay.title = "Run an Application: vicinae";
};
"Mod+E" = {
action.spawn = [
"nautilus"
"--new-window"
];
hotkey-overlay.title = "Open File Manager: nautilus";
};
"Mod+L" = {
action.spawn = [
(lib.getExe' pkgs.systemd "loginctl")
"lock-session"
];
hotkey-overlay.title = "Lock the Screen";
};
"Mod+V" = {
action.spawn = [
"vicinae"
"vicinae://launch/clipboard/history?toggle=true"
];
hotkey-overlay.title = "Clipboard History";
};
"Mod+Space" = {
action.spawn = [
"ghostty"
"+toggle-quick-terminal"
];
hotkey-overlay.title = "Toggle Quick Terminal: ghostty";
};
# niri window or focus move
"Mod+MouseMiddle".action.toggle-window-floating = [ ];
"Mod+Shift+Left" = {
action.focus-monitor-left = [ ];
@@ -114,6 +26,18 @@ in
hotkey-overlay.title = "Focus Monitor Down";
};
# Use the modifier combinations in the opposite direction from Niri's defaults.
"Mod+WheelScrollDown".action.focus-column-right = [ ];
"Mod+WheelScrollUp".action.focus-column-left = [ ];
"Mod+Shift+WheelScrollDown" = {
cooldown-ms = 150;
action.focus-workspace-down = [ ];
};
"Mod+Shift+WheelScrollUp" = {
cooldown-ms = 150;
action.focus-workspace-up = [ ];
};
"Mod+Shift+Ctrl+Left" = {
action.move-window-to-monitor-left = [ ];
hotkey-overlay.title = "Move Window to Monitor Left";
@@ -131,6 +55,104 @@ in
hotkey-overlay.title = "Move Window to Monitor Down";
};
"Print".action.spawn = [
"screenshot"
"region"
];
"Ctrl+Print".action.spawn = [
"screenshot"
"output"
];
"Alt+Print".action.spawn = [
"screenshot"
"all"
];
# spawn applications (sync with labwc modules/applications/labwc/home.nix)
"Mod+T" = {
action.spawn = "ghostty";
hotkey-overlay.title = "Open a Terminal: ghostty";
};
"Mod+D" = {
action.spawn = [
"vicinae"
"toggle"
];
hotkey-overlay.title = "Run an Application: vicinae";
};
"Mod+S" = {
action.spawn = [
"noctalia"
"msg"
"panel-toggle"
"launcher"
];
hotkey-overlay.title = "Run an Application: Noctalia Launcher";
};
"Mod+E" = {
action.spawn = [
"nautilus"
"--new-window"
];
hotkey-overlay.title = "Open File Manager: nautilus";
};
"Mod+L" = {
action.spawn = [
(lib.getExe' pkgs.systemd "loginctl")
"lock-session"
];
hotkey-overlay.title = "Lock the Screen";
};
"Mod+V" = {
action.spawn = [
"vicinae"
"vicinae://launch/clipboard/history"
];
hotkey-overlay.title = "Clipboard History";
};
"Mod+J" = {
repeat = false;
action.spawn = [ "nani-translate-primary" ];
hotkey-overlay.title = "Translate Primary Selection";
};
"Mod+Shift+J" = {
repeat = false;
action.spawn = [ "nani-translate-ocr" ];
hotkey-overlay.title = "OCR and Translate with Nani";
};
"Mod+Ctrl+J" = {
repeat = false;
action.spawn = [
(lib.getExe' pkgs.xdg-utils "xdg-open")
"naniapp://translate"
];
hotkey-overlay.title = "Open Nani Translate";
};
"Mod+Space" = {
action.spawn = [
"ghostty"
"+toggle-quick-terminal"
];
hotkey-overlay.title = "Toggle Quick Terminal: ghostty";
};
"Mod+P" = {
action.spawn = "wdisplays";
hotkey-overlay.title = "Display Settings: wdisplays";
};
"Mod+Z" = {
action.spawn = [
"wl-find-cursor"
"-c"
"0xCCFF453A"
"-s"
"160"
"-d"
"1200"
];
hotkey-overlay.title = "Find Cursor";
};
# Function keys (sync with labwc modules/applications/labwc/home.nix)
"XF86AudioRaiseVolume".action.spawn = [
"noctalia"
"msg"
@@ -166,15 +188,84 @@ in
"msg"
"caffeine-toggle"
];
"XF86AudioPlay".action.spawn = [
"playerctl"
"play-pause"
];
"XF86AudioPause".action.spawn = [
"playerctl"
"play-pause"
];
"XF86AudioStop".action.spawn = [
"playerctl"
"stop"
];
"XF86AudioPrev".action.spawn = [
"playerctl"
"previous"
];
"XF86AudioNext".action.spawn = [
"playerctl"
"next"
];
"XF86Display".action.spawn = [
"wdisplays"
];
};
input = {
touchpad = {
natural-scroll = true;
scroll-factor = 4.0;
scroll-method = "two-finger";
click-method = "clickfinger";
drag = true;
drag-lock = true;
dwt = true;
};
keyboard = {
numlock = true;
xkb = {
layout = "jp";
options = "ctrl:nocaps";
};
};
mouse = {
accel-profile = "flat";
accel-speed = -0.1;
};
trackpoint = {
accel-profile = "flat";
accel-speed = -0.1;
};
warp-mouse-to-focus.enable = true;
focus-follows-mouse = {
enable = true;
max-scroll-amount = "0%";
};
};
cursor.size = 16;
layout = {
focus-ring = {
active.color = "#bd93f9";
inactive.color = "#6272a4";
};
background-color = "transparent";
};
window-rules = [
{
geometry-corner-radius = {
top-left = 20.0;
top-right = 20.0;
bottom-left = 20.0;
bottom-right = 20.0;
top-left = 8.0;
top-right = 8.0;
bottom-left = 8.0;
bottom-right = 8.0;
};
clip-to-geometry = true;
}
@@ -184,6 +275,46 @@ in
default-column-width.fixed = 1080;
default-window-height.fixed = 920;
}
{
# Zoom presents these two fixed-size primary windows. Explicitly keep
# them tiled, overriding Niri's automatic fixed-size-window floating.
matches = [
{
app-id = "^(?i:zoom)$";
title = "^(?i:zoom workplace)$";
}
{
app-id = "^(?i:zoom)$";
title = "^ミーティング$";
}
];
open-floating = false;
}
{
# Zoom's screen-share controls are a toolbar, so open them where the
# client expects them rather than in the middle of the workspace.
matches = [
{
app-id = "^(?i:zoom)$";
title = "^as_toolbar$";
}
];
open-floating = true;
default-floating-position = {
x = 0;
y = 8;
relative-to = "top";
};
}
{
# Keep all other Zoom auxiliary windows freely positionable.
matches = [ { app-id = "^(?i:zoom)$"; } ];
excludes = [
{ title = "^(?i:zoom workplace)$"; }
{ title = "^ミーティング$"; }
];
open-floating = true;
}
];
layer-rules = [
+8 -3
View File
@@ -2,10 +2,15 @@
{
description = "niri Wayland compositor";
includes = [ "systems.wayland" ];
includes = [
"systems.wayland"
"applications.screenshot"
"applications.wl-find-cursor"
];
imports = {
nixos = [ inputs.niri-flake.nixosModules.niri ];
home = [ ./niri-home-module.nix ];
nixos = [
inputs.niri-flake.nixosModules.niri
];
};
}
@@ -1,9 +0,0 @@
{
inputs,
lib,
system,
...
}:
{
imports = lib.optional (lib.hasSuffix "-darwin" system) inputs.niri-flake.homeModules.niri;
}
+13 -6
View File
@@ -1,9 +1,16 @@
{ pkgs, ... }:
{
programs.niri.enable = true;
config,
pkgs,
inputs,
...
}:
{
programs.niri = {
enable = true;
package = inputs.niri-flake.packages.${pkgs.stdenv.hostPlatform.system}.niri-unstable;
};
environment.systemPackages = with pkgs; [
wdisplays # Wayland display configuration GUI
wlr-randr # Wayland output management CLI
];
# niri-flake supplies the compositor package but does not register its
# user units with NixOS. Without this, Ly cannot start niri-session.
systemd.packages = [ config.programs.niri.package ];
}
+3
View File
@@ -0,0 +1,3 @@
{
description = "Fleet build and deploy command-line tools";
}
+63
View File
@@ -0,0 +1,63 @@
{
inputs,
pkgs,
primaryUser,
...
}:
let
system = pkgs.stdenv.hostPlatform.system;
deployRs = inputs.deploy-rs.packages.${system}.default;
fleetBuild = pkgs.writeShellApplication {
name = "fleet-build";
runtimeInputs = [
pkgs.jq
pkgs.nix
];
text = ''
flake_ref="''${FLAKE:-/home/${primaryUser}/dotfiles}"
if (( $# == 0 )); then
# Keep this pipeline inside command substitution so pipefail and
# writeShellApplication's errexit propagate evaluation failures.
host_lines="$(
nix eval --json "$flake_ref#nixosConfigurations" \
--apply 'configs: builtins.attrNames configs' |
jq -r '.[] | select(. != "installer")'
)"
if [[ -z "$host_lines" ]]; then
echo "No deployable NixOS hosts found in $flake_ref" >&2
exit 1
fi
mapfile -t hosts <<< "$host_lines"
else
hosts=("$@")
fi
for host in "''${hosts[@]}"; do
nix build \
--out-link "/var/lib/nix-fleet/roots/build/$host" \
"$flake_ref#nixosConfigurations.$host.config.system.build.toplevel"
done
'';
};
fleetDeploy = pkgs.writeShellApplication {
name = "fleet-deploy";
runtimeInputs = [ deployRs ];
text = ''
cd "''${FLAKE:-/home/${primaryUser}/dotfiles}" || exit 1
exec deploy \
--keep-result \
--result-path /var/lib/nix-fleet/roots/deploy \
"$@"
'';
};
in
{
environment.systemPackages = [
fleetBuild
fleetDeploy
];
}

Some files were not shown because too many files have changed in this diff Show More