Author SHA1 Message Date
moons-14 913a86e9c2 fix(labwc): close only the active Ghostty tab with Mod+Q 2026-08-06 19:12:54 +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
moons-14 a8e9a4dce5 update flake.nix 2026-07-27 20:34:27 +09:00
moons-14 72ff60fb16 x1g9 2026-07-27 19:58:07 +09:00
moons-14 f65318b765 mac 2026-07-27 19:43:42 +09:00
moons-14 0257b2e2fd mac 2026-07-27 19:43:31 +09:00
moons-14 8fec0494ec feat 2026-07-27 19:31:25 +09:00
moons-14 89eeb23d1c add docs 2026-07-27 18:41:42 +09:00
moons-14 bf94d1183f add profiles 2026-07-27 18:31:50 +09:00
moons-14 6bd05887db add systems 2026-07-27 18:02:48 +09:00
moons-14 3e32c9874b add apps 2026-07-27 16:49:48 +09:00
moons-14 684acef46c add apps 2026-07-27 16:10:17 +09:00
moons-14 9061825c63 add apps 2026-07-27 16:10:03 +09:00
moons-14 e703e1b31c add vim, vscode, zed, zellij, zsh 2026-07-27 15:24:37 +09:00
moons-14 79cc69045f add gtk, niri, noctalia, ssh, swaylock 2026-07-27 15:10:46 +09:00
moons-14 5c2ff3cbcf add nix-index, ly 2026-07-27 14:32:59 +09:00
moons-14 c5d4de5a9d add fcitx5, ghostty, git 2026-07-27 14:06:13 +09:00
moons-14 c58bdd30c3 x1g9 2026-07-27 12:34:20 +09:00
moons-14 9771a85e3f x1g9 2026-07-27 11:26:27 +09:00
moons-14 5b1bde7d90 nix registory 2026-07-27 10:58:24 +09:00
moons-14 1d82ab92b6 feat 2026-07-27 10:05:55 +09:00
moons-14 19bc309b8b add document 2026-07-27 06:18:24 +09:00
moons-14 e477c6bee8 init files 2026-07-27 06:13:53 +09:00
moons-14 0171582307 delete 2026-07-27 05:51:17 +09:00
moons-14 dd40b978dd fix 2026-07-27 01:52:41 +09:00
moons-14 4487c38f0b update action
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-24 11:44:14 +09:00
moons-14 873223cb78 update
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-24 06:19:02 +09:00
moons-14 3022acb412 jq
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-24 06:04:21 +09:00
moons-14 18d30bd490 update 2026-07-24 05:59:01 +09:00
moons-14 f2d9eafefa dns
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-23 20:13:02 +09:00
moons-14 85a4458376 nix update
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-21 18:37:22 +09:00
moons-14 b60a840a3d update 2026-07-21 18:34:15 +09:00
moons-14 e1c9beb362 remove nix pkg oci 2026-07-21 18:34:14 +09:00
moons-14 45957d0b40 waylock fingerprint 2026-07-21 18:34:05 +09:00
moons-14 455512ec8a zed 2026-07-21 18:34:04 +09:00
moons-14 754af0a68a Merge pull request #39 from moons-14/renovate/actions-checkout-7.x
chore(deps): update actions/checkout action to v7.0.1
2026-07-21 18:28:54 +09:00
moons-14 475b1432d0 Merge pull request #40 from moons-14/renovate/renovatebot-github-action-46.x
chore(deps): update renovatebot/github-action action to v46.1.20
2026-07-21 18:28:41 +09:00
Renovate Bot e51480e692 chore(deps): update renovatebot/github-action action to v46.1.20 2026-07-20 19:41:45 +00:00
Renovate Bot e09d2d525f chore(deps): update actions/checkout action to v7.0.1 2026-07-20 19:41:42 +00:00
moons-14 6ec1f5762a imutable zed settings
NixOS CI / Validate flake (push) Has been cancelled
Publish Nix cache / Build and publish uncached paths (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-20 07:10:25 +09:00
moons-14 ac6d333af8 zed 2026-07-20 06:50:11 +09:00
moons-14 ad8d66cde1 zoom
Publish Nix cache / Build and publish uncached paths (push) Has been cancelled
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-20 06:28:35 +09:00
moons-14 b2283ba328 nix cache
NixOS CI / Validate flake (push) Has been cancelled
Publish Nix cache / Build and publish uncached paths (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-18 20:09:04 +09:00
moons-14 1e38d17dba grok
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-18 19:52:38 +09:00
moons-14 e67dd6a791 grok 2026-07-18 19:07:47 +09:00
moons-14 0c6b2f41b9 vicinae
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-18 19:05:30 +09:00
moons-14 1091e790db Merge pull request #35 from moons-14/renovate/lock-file-maintenance-nix-flake-inputs
chore(deps): lock file maintenance
2026-07-18 19:04:08 +09:00
Renovate Bot 6c053486a7 chore(deps): lock file maintenance 2026-07-16 19:07:23 +00:00
moons-14 60b64c89b9 Merge pull request #33 from moons-14/renovate/lock-file-maintenance-nix-flake-inputs
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
chore(deps): lock file maintenance
2026-07-17 01:12:56 +09:00
Renovate Bot f264649782 chore(deps): lock file maintenance 2026-07-16 16:12:29 +00:00
moons-14 5370e864e1 Update renovate.json 2026-07-17 01:10:00 +09:00
moons-14 9302d1e50f Merge pull request #31 from moons-14/renovate/cachix-install-nix-action-31.x
chore(deps): update cachix/install-nix-action action to v31.11.0
2026-07-17 01:05:48 +09:00
moons-14 8616aacd7f Merge pull request #32 from moons-14/renovate/actions-checkout-7.x
chore(deps): update actions/checkout action to v7
2026-07-17 01:05:29 +09:00
Renovate Bot 21947ba06a chore(deps): update actions/checkout action to v7 2026-07-16 16:03:57 +00:00
Renovate Bot d75528c712 chore(deps): update cachix/install-nix-action action to v31.11.0 2026-07-16 16:03:54 +00:00
moons-14 afcbe77e98 Add lockFileMaintenance configuration
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
Enable lock file maintenance with scheduling.
2026-07-17 00:52:53 +09:00
moons-14 4ff5ae8883 feat
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
2026-07-15 14:38:59 +09:00
moons-14 166b6f2492 gitea update
Update Nix binary cache / Build every host and publish new cache objects (push) Has been cancelled
2026-07-15 00:37:41 +09:00
moons-14 703e24fcdf gitea update
Update Nix binary cache / Build every host and publish new cache objects (push) Failing after 24s
Bootstrap Nix binary cache / Build every host and bootstrap the cache (push) Waiting to run
2026-07-14 22:34:07 +09:00
moons-14 04622b921f gitea update
Update Nix binary cache / Build every host and publish new cache objects (push) Failing after 25s
Bootstrap Nix binary cache / Build every host and bootstrap the cache (push) Waiting to run
2026-07-14 21:19:31 +09:00
moons-14 0d2aaa8569 Merge pull request #28 from moons-14/codex/nixos-ci
Update Nix binary cache / Build every host and publish new cache objects (push) Has been cancelled
Codex/nixos ci
2026-07-14 20:48:02 +09:00
moons-14 0a685ce028 gitea update
Update Nix binary cache / Build every host and publish new cache objects (push) Failing after 28s
Bootstrap Nix binary cache / Build every host and bootstrap the cache (push) Waiting to run
2026-07-14 20:30:37 +09:00
moons-14 4606041d4f update 2026-07-14 20:21:21 +09:00
moons-14 7f47448980 ci: strengthen NixOS checks 2026-07-14 19:49:56 +09:00
522 changed files with 11099 additions and 6863 deletions
-612
View File
@@ -1,612 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# Gitea Releases are used as an append-only object store. The cache-latest
# release contains the HTTP binary-cache index, while generation releases
# contain immutable NAR payloads.
mode=${CACHE_MODE:-}
server_url=${CACHE_SERVER_URL:-}
repository=${CACHE_REPOSITORY:-}
commit=${CACHE_COMMIT:-}
ref_name=${CACHE_REF_NAME:-unknown}
index_tag=${CACHE_INDEX_TAG:-cache-latest}
generation_prefix=${CACHE_GENERATION_PREFIX:-nix-cache-generation-}
upload_jobs=${CACHE_UPLOAD_JOBS:-4}
key_file=${NIX_CACHE_KEY_FILE:-}
for command in curl jq nix awk sed find sort; do
if ! command -v "$command" >/dev/null 2>&1; then
echo "Required command is unavailable: $command" >&2
exit 1
fi
done
if [[ $mode != bootstrap && $mode != update ]]; then
echo "CACHE_MODE must be either 'bootstrap' or 'update'." >&2
exit 1
fi
if [[ -z $server_url || -z $repository || -z $commit ]]; then
echo "CACHE_SERVER_URL, CACHE_REPOSITORY, and CACHE_COMMIT are required." >&2
exit 1
fi
if [[ -z ${GITEA_TOKEN:-} ]]; then
echo "GITEA_TOKEN is required." >&2
exit 1
fi
if [[ ! -s $key_file ]]; then
echo "NIX_CACHE_KEY_FILE must point to a non-empty signing key." >&2
exit 1
fi
if [[ ! $upload_jobs =~ ^[1-9][0-9]*$ ]]; then
echo "CACHE_UPLOAD_JOBS must be a positive integer." >&2
exit 1
fi
server_url=${server_url%/}
api_base="${server_url}/api/v1/repos/${repository}"
download_base="${server_url}/${repository}/releases/download"
cache_uri="${download_base}/${index_tag}"
manifest_url="${cache_uri}/cache-manifest.json"
public_key_url="${cache_uri}/cache-public-key"
public_key=$(nix key convert-secret-to-public <"$key_file")
key_name=${public_key%%:*}
work_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/nix-release-cache.XXXXXX")
cache_dir="${work_dir}/cache"
rewritten_dir="${work_dir}/narinfo"
manifest_file="${work_dir}/manifest.json"
all_releases_file="${work_dir}/all-releases.json"
generation_release_file="${work_dir}/generation-release.json"
object_updates_file="${work_dir}/object-updates.jsonl"
narinfo_updates_file="${work_dir}/narinfo-updates.jsonl"
nar_upload_queue="${work_dir}/nar-upload-queue"
narinfo_upload_queue="${work_dir}/narinfo-upload-queue"
mkdir -p "$cache_dir" "$rewritten_dir"
: >"$object_updates_file"
: >"$narinfo_updates_file"
: >"$nar_upload_queue"
: >"$narinfo_upload_queue"
trap 'rm -rf "$work_dir"' EXIT
api_request() {
local method=$1
local path=$2
shift 2
curl --fail-with-body --silent --show-error \
--retry 5 --retry-delay 2 --retry-all-errors \
--request "$method" \
--header "Authorization: token ${GITEA_TOKEN}" \
--header "Accept: application/json" \
"$@" \
"${api_base}${path}"
}
api_get_optional() {
local path=$1
local output=$2
local status
status=$(curl --silent --show-error \
--retry 5 --retry-delay 2 --retry-all-errors \
--output "$output" --write-out '%{http_code}' \
--header "Authorization: token ${GITEA_TOKEN}" \
--header "Accept: application/json" \
"${api_base}${path}")
case "$status" in
200)
return 0
;;
404)
rm -f "$output"
return 1
;;
*)
echo "Gitea API request failed with HTTP ${status}: ${path}" >&2
cat "$output" >&2
return 2
;;
esac
}
create_release() {
local tag=$1
local name=$2
local body=$3
local prerelease=$4
jq -n \
--arg tag "$tag" \
--arg name "$name" \
--arg body "$body" \
--arg target "$commit" \
--argjson prerelease "$prerelease" \
'{
tag_name: $tag,
target_commitish: $target,
name: $name,
body: $body,
draft: false,
prerelease: $prerelease
}' | api_request POST /releases \
--header 'Content-Type: application/json' \
--data-binary @-
}
delete_asset() {
local release_id=$1
local asset_id=$2
api_request DELETE "/releases/${release_id}/assets/${asset_id}" >/dev/null
}
upload_asset() {
local release_id=$1
local file=$2
local name=$3
curl --fail-with-body --silent --show-error \
--retry 5 --retry-delay 2 --retry-all-errors \
--request POST \
--header "Authorization: token ${GITEA_TOKEN}" \
--form "attachment=@${file};type=application/octet-stream" \
--output /dev/null \
"${api_base}/releases/${release_id}/assets?name=${name}"
}
upload_asset_response() {
local release_id=$1
local file=$2
local name=$3
curl --fail-with-body --silent --show-error \
--retry 5 --retry-delay 2 --retry-all-errors \
--request POST \
--header "Authorization: token ${GITEA_TOKEN}" \
--form "attachment=@${file};type=application/octet-stream" \
"${api_base}/releases/${release_id}/assets?name=${name}"
}
rename_asset() {
local release_id=$1
local asset_id=$2
local name=$3
jq -n --arg name "$name" '{name: $name}' | api_request PATCH \
"/releases/${release_id}/assets/${asset_id}" \
--header 'Content-Type: application/json' \
--data-binary @- >/dev/null
}
upload_queue() {
local release_id=$1
local queue_file=$2
local file
local name
local pid
local failed=0
local -a pids=()
if [[ ! -s $queue_file ]]; then
return
fi
while IFS=$'\t' read -r file name; do
upload_asset "$release_id" "$file" "$name" &
pids+=("$!")
if ((${#pids[@]} == upload_jobs)); then
for pid in "${pids[@]}"; do
if ! wait "$pid"; then
failed=1
fi
done
pids=()
if ((failed)); then
return 1
fi
fi
done <"$queue_file"
for pid in "${pids[@]}"; do
if ! wait "$pid"; then
failed=1
fi
done
if ((failed)); then
return 1
fi
}
list_all_releases() {
local page=1
local page_file="${work_dir}/releases-page.json"
local releases_jsonl="${work_dir}/releases.jsonl"
local count
: >"$releases_jsonl"
while :; do
api_request GET "/releases?draft=false&pre-release=true&limit=50&page=${page}" >"$page_file"
count=$(jq 'length' "$page_file")
if ((count == 0)); then
break
fi
jq -c '.[]' "$page_file" >>"$releases_jsonl"
((page += 1))
done
jq -s '.' "$releases_jsonl" >"$all_releases_file"
}
initialize_manifest() {
jq -n \
--arg uri "$cache_uri" \
--arg manifest "$manifest_url" \
--arg public_key "$public_key" \
--arg public_key_url "$public_key_url" \
'{
schemaVersion: 1,
cache: {
uri: $uri,
nixCacheInfo: ($uri + "/nix-cache-info"),
manifest: $manifest,
publicKey: $public_key,
publicKeyUrl: $public_key_url
},
generatedAt: null,
generations: [],
objects: {},
narinfos: {}
}' >"$manifest_file"
}
index_release_file="${work_dir}/index-release.json"
if api_get_optional "/releases/tags/${index_tag}" "$index_release_file"; then
if [[ $mode == bootstrap ]]; then
if jq -e '.assets[]? | select(.name == "cache-manifest.json")' \
"$index_release_file" >/dev/null; then
echo "Release '${index_tag}' is already bootstrapped." >&2
exit 1
fi
echo "Resuming an interrupted cache bootstrap."
initialize_manifest
else
manifest_asset_url=$(jq -r '
[
.assets[]?
| select(.name == "cache-manifest.json")
]
| last
| .browser_download_url // empty
' "$index_release_file")
if [[ -z $manifest_asset_url ]]; then
manifest_asset_url=$(jq -r '
[
.assets[]?
| select(.name | test("^cache-manifest-[0-9a-f]+\\.json$"))
]
| sort_by(.created_at)
| last
| .browser_download_url // empty
' "$index_release_file")
if [[ -z $manifest_asset_url ]]; then
echo "The cache index has no recoverable manifest." >&2
exit 1
fi
echo "Recovering the cache index from a temporary manifest."
fi
curl --fail-with-body --silent --show-error \
--retry 5 --retry-delay 2 --retry-all-errors \
--header "Authorization: token ${GITEA_TOKEN}" \
--output "$manifest_file" \
"$manifest_asset_url"
if ! jq -e --arg public_key "$public_key" \
'.schemaVersion == 1 and .cache.publicKey == $public_key' \
"$manifest_file" >/dev/null; then
echo "The cache manifest is invalid or was signed by a different key." >&2
exit 1
fi
fi
else
optional_status=$?
if ((optional_status != 1)); then
exit "$optional_status"
fi
if [[ $mode == update ]]; then
echo "Release '${index_tag}' is missing. Run the bootstrap workflow first." >&2
exit 1
fi
create_release \
"$index_tag" \
"Nix binary cache index" \
"Stable HTTP index for the release-backed Nix binary cache." \
false >"$index_release_file"
initialize_manifest
fi
index_release_id=$(jq -r '.id' "$index_release_file")
if [[ -z $index_release_id || $index_release_id == null ]]; then
echo "Could not determine the cache index release ID." >&2
exit 1
fi
echo "Evaluating NixOS hosts..."
hosts_file="${work_dir}/hosts"
nix eval --json '.#nixosConfigurations' \
--apply 'configs: builtins.attrNames configs' | jq -r '.[]' >"$hosts_file"
mapfile -t hosts <"$hosts_file"
if ((${#hosts[@]} == 0)); then
echo "No NixOS configurations were discovered." >&2
exit 1
fi
targets=()
for host in "${hosts[@]}"; do
targets+=(".#nixosConfigurations.${host}.config.system.build.toplevel")
done
echo "Building hosts: ${hosts[*]}"
roots_file="${work_dir}/roots"
nix build --no-link --print-out-paths --print-build-logs "${targets[@]}" | sort -u >"$roots_file"
mapfile -t roots <"$roots_file"
if ((${#roots[@]} == 0)); then
echo "The Nix build returned no store paths." >&2
exit 1
fi
echo "Exporting the complete host closures to a signed local binary cache..."
nix copy \
--to "file://${cache_dir}?compression=zstd&compression-level=6&secret-key=${key_file}" \
"${roots[@]}"
first_narinfo=$(find "$cache_dir" -maxdepth 1 -type f -name '*.narinfo' -print -quit)
if [[ -z $first_narinfo ]] || ! grep -Fq "Sig: ${key_name}:" "$first_narinfo"; then
echo "Generated narinfo files do not contain the expected cache signature." >&2
exit 1
fi
list_all_releases
# Recover immutable NAR objects left by an interrupted older run. A NAR asset's
# content-addressed filename is globally unique, so it can be reused safely.
discovered_objects_file="${work_dir}/discovered-objects.json"
jq --arg prefix "$generation_prefix" '
reduce (
.[]
| select(.tag_name | startswith($prefix)) as $release
| $release.assets[]?
| select(.name | test("\\.nar\\.(zst|xz|bz2|gz)$"))
| {
key: .name,
value: {
url: .browser_download_url,
generation: $release.tag_name,
size: .size
}
}
) as $object ({}; .[$object.key] //= $object.value)
' "$all_releases_file" >"$discovered_objects_file"
jq --slurpfile discovered "$discovered_objects_file" \
'.objects = ($discovered[0] + .objects)' \
"$manifest_file" >"${manifest_file}.new"
mv "${manifest_file}.new" "$manifest_file"
generation_tag="${generation_prefix}${commit}"
if api_get_optional "/releases/tags/${generation_tag}" "$generation_release_file"; then
echo "Resuming generation release '${generation_tag}'."
else
optional_status=$?
if ((optional_status != 1)); then
exit "$optional_status"
fi
create_release \
"$generation_tag" \
"Nix cache ${commit:0:12}" \
"Branch: ${ref_name}\nCommit: ${commit}\nMode: ${mode}" \
true >"$generation_release_file"
fi
generation_release_id=$(jq -r '.id' "$generation_release_file")
declare -A known_narinfos=()
declare -A object_urls=()
declare -A object_sizes=()
declare -A queued_objects=()
declare -A index_asset_ids=()
while IFS= read -r hash; do
known_narinfos["$hash"]=1
done < <(jq -r '.narinfos | keys[]' "$manifest_file")
while IFS=$'\t' read -r name url; do
object_urls["$name"]=$url
done < <(
jq -r '.objects | to_entries[] | [.key, .value.url] | @tsv' \
"$manifest_file"
)
while IFS=$'\t' read -r name id; do
index_asset_ids["$name"]=$id
done < <(jq -r '.assets[]? | [.name, (.id | tostring)] | @tsv' "$index_release_file")
new_nar_count=0
new_narinfo_count=0
while IFS= read -r -d '' narinfo_file; do
narinfo_name=$(basename "$narinfo_file")
store_hash=${narinfo_name%.narinfo}
if [[ -n ${known_narinfos[$store_hash]:-} ]]; then
continue
fi
nar_relative=$(sed -n 's/^URL: //p' "$narinfo_file")
store_path=$(sed -n 's/^StorePath: //p' "$narinfo_file")
if [[ $nar_relative != nar/* || -z $store_path ]]; then
echo "Malformed narinfo file: ${narinfo_file}" >&2
exit 1
fi
nar_name=${nar_relative#nar/}
nar_file="${cache_dir}/${nar_relative}"
if [[ ! -f $nar_file ]]; then
echo "NAR payload is missing: ${nar_file}" >&2
exit 1
fi
if [[ -z ${object_urls[$nar_name]:-} ]]; then
object_urls["$nar_name"]="${download_base}/${generation_tag}/${nar_name}"
object_sizes["$nar_name"]=$(stat -c '%s' "$nar_file")
if [[ -z ${queued_objects[$nar_name]:-} ]]; then
printf '%s\t%s\n' "$nar_file" "$nar_name" >>"$nar_upload_queue"
queued_objects["$nar_name"]=1
((new_nar_count += 1))
fi
jq -cn \
--arg key "$nar_name" \
--arg url "${object_urls[$nar_name]}" \
--arg generation "$generation_tag" \
--argjson size "${object_sizes[$nar_name]}" \
'{key: $key, value: {url: $url, generation: $generation, size: $size}}' \
>>"$object_updates_file"
fi
rewritten_file="${rewritten_dir}/${narinfo_name}"
awk -v url="${object_urls[$nar_name]}" '
BEGIN { replaced = 0 }
/^URL: / {
print "URL: " url
replaced = 1
next
}
{ print }
END { if (!replaced) exit 1 }
' "$narinfo_file" >"$rewritten_file"
if [[ -n ${index_asset_ids[$narinfo_name]:-} ]]; then
delete_asset "$index_release_id" "${index_asset_ids[$narinfo_name]}"
fi
printf '%s\t%s\n' "$rewritten_file" "$narinfo_name" >>"$narinfo_upload_queue"
jq -cn \
--arg key "$store_hash" \
--arg url "${cache_uri}/${narinfo_name}" \
--arg store_path "$store_path" \
--arg nar "$nar_name" \
'{key: $key, value: {url: $url, storePath: $store_path, nar: $nar}}' \
>>"$narinfo_updates_file"
((new_narinfo_count += 1))
done < <(find "$cache_dir" -maxdepth 1 -type f -name '*.narinfo' -print0 | sort -z)
echo "Uploading ${new_nar_count} new NAR objects to '${generation_tag}'..."
upload_queue "$generation_release_id" "$nar_upload_queue"
echo "Uploading ${new_narinfo_count} new narinfo files to '${index_tag}'..."
upload_queue "$index_release_id" "$narinfo_upload_queue"
now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
generations_file="${work_dir}/generations.json"
jq --arg prefix "$generation_prefix" '
[
.[]
| select(.tag_name | startswith($prefix))
| {
tag: .tag_name,
commit: .target_commitish,
createdAt: .created_at
}
]
' "$all_releases_file" >"$generations_file"
jq -s \
--slurpfile object_updates "$object_updates_file" \
--slurpfile narinfo_updates "$narinfo_updates_file" \
--slurpfile generations "$generations_file" \
--arg generation_tag "$generation_tag" \
--arg commit "$commit" \
--arg now "$now" \
'
.[0]
| reduce $object_updates[] as $update (.; .objects[$update.key] = $update.value)
| reduce $narinfo_updates[] as $update (.; .narinfos[$update.key] = $update.value)
| .generatedAt = $now
| .objects as $objects
| .generations = (
reduce (
$generations[0] + [{tag: $generation_tag, commit: $commit, createdAt: $now}]
)[] as $generation (
{};
.[$generation.tag] = $generation
)
| [.[]]
| sort_by(.createdAt)
| map(
. as $generation
| . + {
objects: [
$objects
| to_entries[]
| select(.value.generation == $generation.tag)
| .key
]
}
)
)
' "$manifest_file" >"${manifest_file}.new"
mv "${manifest_file}.new" "$manifest_file"
if [[ $mode == bootstrap ]]; then
for root_asset_name in nix-cache-info cache-public-key; do
root_asset_id=${index_asset_ids[$root_asset_name]:-}
if [[ -n $root_asset_id ]]; then
delete_asset "$index_release_id" "$root_asset_id"
fi
done
upload_asset "$index_release_id" "${cache_dir}/nix-cache-info" nix-cache-info
printf '%s\n' "$public_key" >"${work_dir}/cache-public-key"
upload_asset "$index_release_id" "${work_dir}/cache-public-key" cache-public-key
fi
manifest_asset_name=cache-manifest.json
old_manifest_asset_id=${index_asset_ids[$manifest_asset_name]:-}
temporary_manifest_name="cache-manifest-${commit}.json"
while IFS= read -r stale_temporary_asset_id; do
delete_asset "$index_release_id" "$stale_temporary_asset_id"
done < <(
jq -r '
.assets[]?
| select(.name | test("^cache-manifest-[0-9a-f]+\\.json$"))
| .id
' "$index_release_file"
)
temporary_manifest_asset=$(
upload_asset_response "$index_release_id" "$manifest_file" "$temporary_manifest_name"
)
temporary_manifest_asset_id=$(jq -r '.id' <<<"$temporary_manifest_asset")
if [[ -z $temporary_manifest_asset_id || $temporary_manifest_asset_id == null ]]; then
echo "Could not determine the temporary manifest asset ID." >&2
exit 1
fi
if [[ -n $old_manifest_asset_id ]]; then
delete_asset "$index_release_id" "$old_manifest_asset_id"
fi
rename_asset "$index_release_id" "$temporary_manifest_asset_id" "$manifest_asset_name"
echo "Published Nix cache generation: ${generation_tag}"
echo "Cache URI: ${cache_uri}"
echo "Public key: ${public_key}"
-46
View File
@@ -1,46 +0,0 @@
name: Bootstrap Nix binary cache
on:
workflow_dispatch:
permissions:
contents: write
concurrency:
group: nix-release-cache-publisher
cancel-in-progress: false
jobs:
bootstrap:
name: Build every host and bootstrap the cache
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
- name: Build and publish the initial cache
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
NIX_CACHE_PRIVATE_KEY: ${{ secrets.NIX_CACHE_PRIVATE_KEY }}
CACHE_MODE: bootstrap
CACHE_REPOSITORY: moons-14/dotfiles
CACHE_SERVER_URL: https://git.yutakobayashi.com
CACHE_COMMIT: ${{ github.sha }}
CACHE_REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
if [[ -z "${NIX_CACHE_PRIVATE_KEY:-}" ]]; then
echo "Repository secret NIX_CACHE_PRIVATE_KEY is required." >&2
exit 1
fi
key_file="${RUNNER_TEMP:-/tmp}/nix-cache-private-key"
umask 077
printf '%s\n' "$NIX_CACHE_PRIVATE_KEY" > "$key_file"
unset NIX_CACHE_PRIVATE_KEY
export NIX_CACHE_KEY_FILE="$key_file"
trap 'rm -f "$key_file"' EXIT
./.gitea/scripts/publish-nix-cache.sh
-49
View File
@@ -1,49 +0,0 @@
name: Update Nix binary cache
on:
push:
branches:
- "**"
workflow_dispatch:
permissions:
contents: write
concurrency:
group: nix-release-cache-publisher
cancel-in-progress: false
jobs:
update:
name: Build every host and publish new cache objects
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
- name: Build and publish new cache objects
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
NIX_CACHE_PRIVATE_KEY: ${{ secrets.NIX_CACHE_PRIVATE_KEY }}
CACHE_MODE: update
CACHE_REPOSITORY: moons-14/dotfiles
CACHE_SERVER_URL: https://git.yutakobayashi.com
CACHE_COMMIT: ${{ github.sha }}
CACHE_REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
if [[ -z "${NIX_CACHE_PRIVATE_KEY:-}" ]]; then
echo "Repository secret NIX_CACHE_PRIVATE_KEY is required." >&2
exit 1
fi
key_file="${RUNNER_TEMP:-/tmp}/nix-cache-private-key"
umask 077
printf '%s\n' "$NIX_CACHE_PRIVATE_KEY" > "$key_file"
unset NIX_CACHE_PRIVATE_KEY
export NIX_CACHE_KEY_FILE="$key_file"
trap 'rm -f "$key_file"' EXIT
./.gitea/scripts/publish-nix-cache.sh
+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
-70
View File
@@ -1,70 +0,0 @@
name: NixOS build
on:
pull_request:
branches:
- main
paths:
- ".github/workflows/nixos-build.yml"
- "flake.lock"
- "flake.nix"
- "flake/**"
- "hosts/**"
- "modules/**"
- "overlays/**"
- "profiles/**"
- "shells/**"
- ".sops.yaml"
- "secrets/**"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
discover-hosts:
name: Discover NixOS hosts
runs-on: ubuntu-latest
outputs:
hosts: ${{ steps.hosts.outputs.hosts }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
access-tokens = github.com=${{ github.token }}
- name: Evaluate NixOS hosts
id: hosts
run: |
set -euo pipefail
hosts_json=$(nix eval --json '.#nixosConfigurations' --apply 'configs: builtins.attrNames configs')
echo "hosts=${hosts_json}" >> "$GITHUB_OUTPUT"
echo "Discovered hosts: ${hosts_json}"
build-host:
name: Build ${{ matrix.host }}
needs: discover-hosts
if: ${{ needs.discover-hosts.outputs.hosts != '[]' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
host: ${{ fromJSON(needs.discover-hosts.outputs.hosts) }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
access-tokens = github.com=${{ github.token }}
- name: Build NixOS system
run: |
set -euo pipefail
nix build ".#nixosConfigurations.${{ matrix.host }}.config.system.build.toplevel" \
--print-build-logs
-69
View File
@@ -1,69 +0,0 @@
name: NixOS eval
on:
pull_request:
branches:
- main
paths:
- ".github/workflows/nixos-eval.yml"
- "flake.lock"
- "flake.nix"
- "flake/**"
- "hosts/**"
- "modules/**"
- "overlays/**"
- "profiles/**"
- "shells/**"
- ".sops.yaml"
- "secrets/**"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
discover-hosts:
name: Discover NixOS hosts
runs-on: ubuntu-latest
outputs:
hosts: ${{ steps.hosts.outputs.hosts }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
access-tokens = github.com=${{ github.token }}
- name: Evaluate NixOS hosts
id: hosts
run: |
set -euo pipefail
hosts_json=$(nix eval --json '.#nixosConfigurations' --apply 'configs: builtins.attrNames configs')
echo "hosts=${hosts_json}" >> "$GITHUB_OUTPUT"
echo "Discovered hosts: ${hosts_json}"
eval-host:
name: Eval ${{ matrix.host }}
needs: discover-hosts
if: ${{ needs.discover-hosts.outputs.hosts != '[]' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
host: ${{ fromJSON(needs.discover-hosts.outputs.hosts) }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
access-tokens = github.com=${{ github.token }}
- name: Evaluate NixOS system derivation
run: |
set -euo pipefail
nix eval ".#nixosConfigurations.${{ matrix.host }}.config.system.build.toplevel.drvPath"
+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
-29
View File
@@ -1,29 +0,0 @@
name: Renovate
on:
schedule:
# Every day at 03:00 JST (18:00 UTC on the previous day).
- cron: "0 18 * * *"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: renovate
cancel-in-progress: false
jobs:
renovate:
name: Update Nix flake inputs
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout repository
uses: actions/[email protected]
# Use a PAT or GitHub App token so Renovate PRs trigger the other workflows.
- name: Run Renovate
uses: renovatebot/[email protected]
with:
renovate-version: 43.262.1
token: ${{ secrets.RENOVATE_TOKEN }}
env:
LOG_LEVEL: info
RENOVATE_PLATFORM: github
RENOVATE_REPOSITORIES: ${{ github.repository }}
+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.
+15 -10
View File
@@ -4,6 +4,7 @@
!README.md !README.md
!LICENSE !LICENSE
!AGENTS.md !AGENTS.md
!/docs/
!.github/ !.github/
!.gitea/ !.gitea/
@@ -14,15 +15,19 @@
!/flake.nix !/flake.nix
!/flake.lock !/flake.lock
!/renovate.json
!shells/
!hosts/
!overlays/
!profiles/
!modules/
!docs/
!images/
!secrets/
!/shells/
!/flake/ !/flake/
!/overlays/
!/images/
!/secrets/
!/windows/
!/hosts/
!/libs/
!/modules/
!/tests/
!/skills/
+2
View File
@@ -3,6 +3,7 @@ keys:
- &host_x1g13 age12g85cuvg4kjfr79lqf5fx2k0d82tchrgv88xgkt7ukk2cfcsw98s2rjyat - &host_x1g13 age12g85cuvg4kjfr79lqf5fx2k0d82tchrgv88xgkt7ukk2cfcsw98s2rjyat
- &host_ops age18rtm2dq2r62zvnhwdq0gkm24hu85r7zyleyk3jqv22zpdtw064eq7ay7dl - &host_ops age18rtm2dq2r62zvnhwdq0gkm24hu85r7zyleyk3jqv22zpdtw064eq7ay7dl
- &host_internal-app-01 age1mcp5gma7y0k59equhzqfsnn0ed335ljjtn0k08ua77htlxf0x54qsravch - &host_internal-app-01 age1mcp5gma7y0k59equhzqfsnn0ed335ljjtn0k08ua77htlxf0x54qsravch
- &host_galleria age1wh7r9wnvyrgt5efjvg2324khsf4w6e9atpmz2udr4uw7frhnvvwquzcu72
creation_rules: creation_rules:
- path_regex: ^secrets/common/[^/]+\.ya?ml$ - path_regex: ^secrets/common/[^/]+\.ya?ml$
key_groups: key_groups:
@@ -11,6 +12,7 @@ creation_rules:
- *host_x1g13 - *host_x1g13
- *host_ops - *host_ops
- *host_internal-app-01 - *host_internal-app-01
- *host_galleria
- path_regex: ^secrets/hosts/x1g13/[^/]+\.ya?ml$ - path_regex: ^secrets/hosts/x1g13/[^/]+\.ya?ml$
key_groups: key_groups:
- age: - age:
+769 -350
View File
File diff suppressed because it is too large Load Diff
+2 -190
View File
@@ -1,191 +1,3 @@
# dotfiles # moons14 dotfiles
My NixOS + Home Manager configurations built with flake-parts. My NixOS + Home Manager configurations build with flake.
## Overview
- **OS**: NixOS 26.05 (stable) + nixpkgs-unstable
- **Window Manager**: Niri (Wayland)
- **Shell**: Zsh
- **Terminal**: Ghostty
- **Editor**: Neovim (nixvim), VSCode
- **Launcher**: Vicinae
- **Theme**: Stylix (Dracula)
- **Secrets**: sops-nix + age + YubiKey
## Hosts
| Host | Description | Profiles |
| ------------- | --------------- | -------------------------------------------- |
| `x1g13` | ThinkPad laptop | gui, thinkpad, dev, personal, secure-storage |
| `nix-example` | VM | cli-interactive, vm, dev, remote |
| `installer` | NixOS installer | (standalone) |
## Directory Structure
```
.
├── flake.nix # Flake inputs and outputs
├── flake/
│ ├── formatter.nix # treefmt configuration (nixfmt, deadnix, statix, etc.)
│ └── git-hooks.nix # pre-commit hooks
├── hosts/
│ ├── default.nix # mkSystem helper and host definitions
│ ├── x1g13/ # ThinkPad host config
│ ├── nix-example/ # VM host config
│ └── installer/ # Installer ISO config
├── modules/
│ ├── applications/ # Application configs (NixOS + Home Manager)
│ │ ├── niri/ # Wayland compositor
│ │ ├── ghostty/ # Terminal emulator
│ │ ├── vim/ # Neovim (nixvim)
│ │ ├── vscode/ # VSCode
│ │ ├── zsh/ # Shell
│ │ ├── zellij/ # Terminal multiplexer
│ │ ├── git/ # Git config
│ │ ├── docker.nix # Container runtime
│ │ ├── tailscale.nix # VPN
│ │ ├── claude/ # Claude Code
│ │ ├── opencode.nix # OpenCode
│ │ └── ... # chrome, discord, zoom, slack, etc.
│ ├── system/ # NixOS system configs
│ │ ├── audio.nix # PipeWire
│ │ ├── boot/ # Bootloader (systemd-boot, lanzaboote)
│ │ ├── disko.nix # Disk partitioning
│ │ ├── fonts.nix # Fonts
│ │ ├── network/ # Networking
│ │ ├── sops.nix # Secrets management
│ │ ├── user/ # User accounts
│ │ └── ...
│ ├── features/ # Feature bundles (abstraction layer)
│ │ ├── application/ # browser, communication
│ │ ├── boot/ # UEFI
│ │ ├── cli/ # base, interactive, shell
│ │ ├── connect/ # WiFi, Bluetooth
│ │ ├── dev/ # agent, nix, python, bun, java, arduino
│ │ ├── gui/ # desktop, terminal, audio, editor, capture
│ │ ├── identity/ # SSH key, fingerprint
│ │ ├── network/ # Tailscale
│ │ ├── services/ # container, KDE
│ │ └── storage/ # disko
│ ├── drivers/ # Hardware drivers (Intel)
│ └── integrations/ # Home Manager integration
├── profiles/
│ ├── interfaces/ # cli-minimal, cli-interactive, gui
│ ├── platforms/ # desktop, laptop, thinkpad, vm
│ └── workloads/ # dev, personal, srv, remote, secure-storage
├── overlays/ # nixpkgs overlays
├── shells/ # devShells (pre-commit hooks, sops, age)
├── secrets/ # Encrypted secrets (sops)
└── docs/ # Documentation
```
## Architecture
```
profile (enable features)
→ features (bundle applications/system + add packages)
→ applications (system.nix + home.nix)
→ system (NixOS config)
```
### Module Patterns
**Simple Module** — Single file for NixOS-only or Home Manager-only configs:
```nix
{ lib, config, ... }:
let cfg = config.my.system.audio;
in {
options.my.system.audio.enable = lib.mkEnableOption "Audio";
config = lib.mkIf cfg.enable { ... };
}
```
**Complex Module** — Directory with `default.nix`, `system.nix`, `home.nix`:
```
modules/applications/<app>/
├── default.nix # Master enable + imports
├── system.nix # NixOS config
└── home.nix # Home Manager config (sharedModules)
```
**Feature Module** — Bundles multiple applications/system modules:
```nix
{ lib, config, ... }:
let cfg = config.my.features.gui.desktop;
in {
options.my.features.gui.desktop.enable = lib.mkEnableOption "Desktop";
config = lib.mkIf cfg.enable {
my.applications = { niri.enable = true; gtk.enable = true; ... };
};
}
```
**Profile** — Thin layer that only enables features:
```nix
{
my.features = {
gui.desktop.enable = true;
dev.agent.enable = true;
};
}
```
## Packages
### CLI
- **Shell**: Zsh with zoxide, direnv
- **Terminal multiplexer**: Zellij
- **Editor**: Neovim (nixvim)
- **Tools**: ripgrep, curl, wget, htop, btop, fastfetch, unzip, unrar
### GUI
- **Compositor**: Niri
- **Terminal**: Ghostty, Alacritty
- **Editor**: VSCode
- **Browser**: Chrome
- **Launcher**: Vicinae
- **File manager**: Nautilus
- **Communication**: Discord, Zoom, Slack
### Development
- **AI agents**: Claude Code, Codex, OpenCode, Grok
- **Languages**: Python, Bun (JavaScript/TypeScript), Java, Arduino
- **Container**: Docker
- **Nix**: nh, nixfmt, deadnix, statix
### System
- **VPN**: Tailscale
- **Secrets**: sops-nix, age
- **Boot**: systemd-boot, lanzaboote (Secure Boot)
- **Disk**: disko
- **Theme**: Stylix
## Commands
```sh
nix flake update # Update flake inputs
nix fmt # Format code
nix develop .#dotnix # Enter dev shell
sudo nixos-rebuild switch --flake .#<host> # Apply config
sudo nixos-rebuild build --flake .#<host> # Build without applying
```
## Inspired
- [Zaney/zaneyos](https://gitlab.com/Zaney/zaneyos)
- [fa0311/.zshrc](https://gist.github.com/fa0311/d37d53ff39c73c54c883379e8e3732df)
- [AsianLovesLinux/Niri](https://github.com/AsianLovesLinux/Niri)
- [natsukium/dotfiles](https://github.com/natsukium/dotfiles)
- [dracula](https://github.com/dracula)
- [akazdayo/nix-configs](https://github.com/akazdayo/nix-configs)
- [yutakobayashidev/dotnix](https://github.com/yutakobayashidev/dotnix)
- [kawaemon/dotfiles](https://github.com/kawaemon/dotfiles)
-76
View File
@@ -1,76 +0,0 @@
# Gitea Release-backed Nix binary cache
The workflows in `.gitea/workflows/` publish the closures of every
`nixosConfigurations` host to Gitea Releases.
- `nix-cache-bootstrap.yml` is a one-shot manual workflow that creates the
initial cache.
- `nix-cache-update.yml` runs on every branch push. It creates one immutable
generation release per commit and uploads only NAR content hashes that have
not appeared in an older generation.
- The `cache-latest` release is the stable cache index. It contains
`nix-cache-info`, `cache-public-key`, `cache-manifest.json`, and every
`<store-hash>.narinfo` file.
- Each narinfo has an absolute `URL:` that points at the generation release
containing its immutable NAR. Rewriting `URL:` does not alter the signed
store-path fingerprint.
The operational manifest enumerates all narinfo and NAR URLs. Nix itself does
not read that manifest: it requests `nix-cache-info` and
`<store-hash>.narinfo` directly from the cache URI.
## One-time setup
Generate a signing key on a trusted machine:
```sh
umask 077
nix key generate-secret --key-name dotfiles-gitea-cache-1 > cache-private-key
nix key convert-secret-to-public < cache-private-key
```
Add the complete contents of `cache-private-key` as the repository Actions
secret `NIX_CACHE_PRIVATE_KEY`. Do not commit this file. Ensure the repository
Actions token is allowed to write Releases, then run **Bootstrap Nix binary
cache** once from the Actions UI.
The bootstrap log and the following stable asset expose the public key:
```text
https://git.yutakobayashi.com/moons-14/dotfiles/releases/download/cache-latest/cache-public-key
```
The repository and its Release assets must be publicly readable for ordinary
Nix clients to use this as an unauthenticated substituter. The runner needs
enough disk for the Nix store plus one compressed copy of all host closures.
It also needs `bash`, `curl`, `jq`, and standard GNU userland tools.
## NixOS client configuration
After bootstrap, copy the exact value from `cache-public-key` into
`extra-trusted-public-keys`:
```nix
{
nix.settings = {
extra-substituters = [
"https://git.yutakobayashi.com/moons-14/dotfiles/releases/download/cache-latest"
];
extra-trusted-public-keys = [
"dotfiles-gitea-cache-1:REPLACE_WITH_THE_GENERATED_PUBLIC_KEY"
];
};
}
```
The substituter value is the directory-like cache URI, not the manifest file
URL. A quick validation after bootstrap is:
```sh
cache=https://git.yutakobayashi.com/moons-14/dotfiles/releases/download/cache-latest
curl --fail "$cache/nix-cache-info"
curl --fail "$cache/cache-manifest.json" | jq '.cache, (.objects | length), (.narinfos | length)'
```
Because every branch receives the signing secret, only trusted users should be
allowed to push branches or modify Actions workflows in this repository.
Generated
+537 -268
View File
File diff suppressed because it is too large Load Diff
+25 -14
View File
@@ -11,6 +11,11 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nix-darwin = {
url = "github:nix-darwin/nix-darwin/nix-darwin-26.05";
inputs.nixpkgs.follows = "nixpkgs";
};
# Hardware / Platform # Hardware / Platform
nixos-hardware.url = "github:NixOS/nixos-hardware/master"; nixos-hardware.url = "github:NixOS/nixos-hardware/master";
nixos-wsl.url = "github:nix-community/NixOS-WSL"; nixos-wsl.url = "github:nix-community/NixOS-WSL";
@@ -18,6 +23,11 @@
# Desktop # Desktop
niri-flake.url = "github:sodiboo/niri-flake"; niri-flake.url = "github:sodiboo/niri-flake";
nix-hazkey = {
url = "github:aster-void/nix-hazkey";
inputs.nixpkgs.follows = "nixpkgs";
};
stylix = { stylix = {
url = "github:nix-community/stylix"; url = "github:nix-community/stylix";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -25,7 +35,13 @@
# Terminal # Terminal
ghostty = { ghostty = {
url = "github:moons-14/ghostty"; url = "github:ghostty-org/ghostty";
};
# Speech to text
handy = {
url = "github:cjpais/Handy";
inputs.nixpkgs.follows = "nixpkgs";
}; };
# Shell / Launcher # Shell / Launcher
@@ -36,10 +52,7 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
noctalia = { noctalia.url = "github:noctalia-dev/noctalia/cachix";
url = "github:noctalia-dev/noctalia";
inputs.nixpkgs.follows = "nixpkgs";
};
# Editor # Editor
nixvim = { nixvim = {
@@ -78,12 +91,10 @@
# LLM agents # LLM agents
llm-agents = { llm-agents = {
url = "github:numtide/llm-agents.nix"; url = "github:numtide/llm-agents.nix";
inputs.nixpkgs.follows = "nixpkgs-unstable";
}; };
codex-desktop-linux = { codex-desktop-linux = {
url = "github:ilysenko/codex-desktop-linux"; url = "github:ilysenko/codex-desktop-linux";
inputs.nixpkgs.follows = "nixpkgs-unstable";
}; };
# Index / Search # Index / Search
@@ -93,13 +104,15 @@
}; };
# Systems # Systems
systems.url = "github:nix-systems/default-linux"; systems.url = "github:nix-systems/default";
# Japanese Input Method browser-previews = {
nix-hazkey = { url = "github:nix-community/browser-previews";
url = "github:aster-void/nix-hazkey";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nani-translate-linux.url = "git+https://github.com/zunoser/nani-translate-linux.git";
}; };
outputs = outputs =
@@ -113,10 +126,8 @@
imports = [ imports = [
./overlays ./overlays
./hosts
./shells ./shells
./flake/formatter.nix ./flake
./flake/git-hooks.nix
]; ];
}; };
} }
+7
View File
@@ -0,0 +1,7 @@
{
imports = [
./formatter.nix
./git-hooks.nix
./registry.nix
];
}
+54
View File
@@ -0,0 +1,54 @@
{
inputs,
lib,
...
}:
let
dotfilesLib = import ../libs {
inherit inputs lib;
root = ../.;
};
hostSpecsPath = ../hosts/default.nix;
hostSpecs =
if builtins.pathExists hostSpecsPath then
let
value = import hostSpecsPath;
in
if builtins.isFunction value then
value (
builtins.intersectAttrs (builtins.functionArgs value) {
inherit inputs lib;
}
)
else
value
else
{ };
configurations = dotfilesLib.hosts.mkConfigurations hostSpecs;
in
{
flake = {
inherit (configurations) darwinConfigurations nixosConfigurations;
lib = dotfilesLib;
};
perSystem =
{ pkgs, system, ... }:
let
nixosChecks =
lib.mapAttrs' (name: nixos: lib.nameValuePair "nixos-${name}" nixos.config.system.build.toplevel)
(
lib.filterAttrs (
_: nixos: nixos.pkgs.stdenv.hostPlatform.system == system
) configurations.nixosConfigurations
);
in
{
checks = {
registry = import ../tests/registry.nix {
inherit inputs lib pkgs;
};
}
// nixosChecks;
};
}
+129 -98
View File
@@ -1,105 +1,136 @@
{ {
inputs, nix-example = {
config, system = "x86_64-linux";
lib, stateVersion = "26.05";
... user = "moons";
}: path = ./nix-example;
let
inherit (inputs.nixpkgs.lib) nixosSystem;
username = "moons"; profiles = [
"base"
"interface.cli"
"platform.vm"
"workload.development"
"workload.remote-access"
];
};
mkSystem = ops = {
{ system = "x86_64-linux";
host, stateVersion = "26.05";
system, user = "moons";
profiles ? [ ], path = ./ops;
extraModules ? [ ],
}:
let
unstable = import inputs.nixpkgs-unstable {
inherit system;
config = {
allowUnfree = true;
};
};
in
assert lib.assertMsg (lib.elem system config.systems)
"mkSystem: system '${system}' not in valid systems: ${lib.generators.toPretty { } config.systems}";
nixosSystem {
inherit system;
modules = [
{
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = builtins.attrValues inputs.self.overlays;
}
../modules
./${host}/default.nix
]
++ map (p: ../profiles/${p}.nix) profiles
++ extraModules;
specialArgs = {
inherit
inputs
username
unstable
host
;
};
};
in
{
flake.nixosConfigurations = {
nix-example = mkSystem {
host = "nix-example";
system = "x86_64-linux";
profiles = [
"interfaces/cli-interactive"
"platforms/vm"
"workloads/dev"
"workloads/remote"
];
};
ops = mkSystem {
host = "ops";
system = "x86_64-linux";
profiles = [
"interfaces/cli-interactive"
"platforms/vm"
"workloads/remote"
];
};
internal-app-01 = mkSystem { profiles = [
host = "internal-app-01"; "base"
system = "x86_64-linux"; "interface.cli"
profiles = [ "platform.vm"
"interfaces/cli-interactive" "workload.remote-access"
"platforms/vm" ];
"workloads/srv" };
];
};
x1g13 = mkSystem {
host = "x1g13";
system = "x86_64-linux";
profiles = [
"interfaces/gui"
"platforms/thinkpad"
"workloads/dev"
"workloads/personal"
"workloads/secure-storage"
"workloads/tailscale/client"
];
};
installer = nixosSystem { internal-app-01 = {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ stateVersion = "26.05";
./installer/default.nix user = "moons";
]; path = ./internal-app-01;
specialArgs = {
inherit inputs; 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"
# "security.secrets"
"workload.personal"
];
};
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"
"interface.wallpaperengine"
"platform.intel-nvidia-desktop"
"security.secrets"
"security.secure-boot"
"security.tpm-storage"
"security.fingerprint"
"workload.development"
"workload.game"
"workload.personal"
];
};
m2 = {
system = "aarch64-darwin";
stateVersion = "26.05";
user = "moons";
path = ./m2;
profiles = [
"base"
"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;
}
+46
View File
@@ -0,0 +1,46 @@
{
lib,
config,
...
}:
{
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;
};
}
+14
View File
@@ -0,0 +1,14 @@
{ inputs, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
./disko.nix
];
boot.initrd.luks.devices.cryptroot.device =
"/dev/disk/by-partuuid/04295552-cbb8-4511-ac1e-1171ec20f8d1";
environment.systemPackages = with inputs.browser-previews.packages.${pkgs.system}; [
google-chrome-beta
];
}
@@ -5,9 +5,9 @@
... ...
}: }:
{ {
imports = [ imports = [ "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" ];
"${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix"
]; boot.zfs.forceImportRoot = false;
networking = { networking = {
hostName = "nixos-installer"; hostName = "nixos-installer";
@@ -34,23 +34,28 @@
]; ];
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
git # Clone dotfiles repository git
disko # Disk partitioning disko
sops # Secrets management sops
age # Age encryption age
ssh-to-age # Convert SSH keys to age ssh-to-age
age-plugin-yubikey # YubiKey support age-plugin-yubikey
yubikey-manager # YubiKey management yubikey-manager
pcsc-tools # Smart card tools pcsc-tools
mkpasswd # Password hash generation mkpasswd
rsync # File synchronization rsync
vim # Text editor vim
wget # Download files wget
curl # HTTP client curl
jq # JSON processor jq
parted # Partition tools parted
cryptsetup # LUKS encryption cryptsetup
btrfs-progs # Btrfs filesystem tools btrfs-progs
efibootmgr
pciutils
sbctl
tpm2-tools
util-linux
]; ];
services.pcscd.enable = true; services.pcscd.enable = true;
@@ -186,6 +191,4 @@
}; };
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
system.stateVersion = "26.05";
} }
@@ -1,12 +1,8 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’ # Do not modify this file! It was generated by `nixos-generate-config` and may
# and may be overwritten by future invocations. Please make changes # be overwritten by future invocations.
# to /etc/nixos/configuration.nix instead.
{ lib, modulesPath, ... }: { lib, modulesPath, ... }:
{ {
imports = [ imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ boot.initrd.availableKernelModules = [
"ata_piix" "ata_piix"
+3
View File
@@ -0,0 +1,3 @@
{
imports = [ ./hardware-configuration.nix ];
}
+10
View File
@@ -0,0 +1,10 @@
{ hostName, ... }:
{
# networking.hostName and networking.localHostName are derived from the
# registry name; computerName controls the user-visible macOS name.
networking.computerName = hostName;
# Keep this value stable after the first activation. It is independent of
# the Home Manager stateVersion in hosts/default.nix.
system.stateVersion = 7;
}
-6
View File
@@ -1,6 +0,0 @@
{ ... }:
{
imports = [
./hardware-configuration.nix
];
}
+4 -11
View File
@@ -1,15 +1,8 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’ # Do not modify this file! It was generated by `nixos-generate-config` and may
# and may be overwritten by future invocations. Please make changes # be overwritten by future invocations.
# to /etc/nixos/configuration.nix instead. { lib, modulesPath, ... }:
{ {
lib, imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ boot.initrd.availableKernelModules = [
"ata_piix" "ata_piix"
+3
View File
@@ -0,0 +1,3 @@
{
imports = [ ./hardware-configuration.nix ];
}
+4 -12
View File
@@ -1,16 +1,8 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’ # Do not modify this file! It was generated by `nixos-generate-config` and may
# and may be overwritten by future invocations. Please make changes # be overwritten by future invocations.
# to /etc/nixos/configuration.nix instead. { lib, modulesPath, ... }:
{ {
lib, imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ boot.initrd.availableKernelModules = [
"ata_piix" "ata_piix"
@@ -1,8 +1,5 @@
{ ... }:
{ {
imports = [ imports = [ ./hardware-configuration.nix ];
./hardware-configuration.nix
];
networking = { networking = {
useDHCP = false; useDHCP = false;
@@ -44,13 +41,11 @@
} }
]; ];
}; };
}; };
defaultGateway = { defaultGateway = {
address = "10.50.128.1"; address = "10.50.128.1";
interface = "ens18"; interface = "ens18";
}; };
}; };
} }
+3 -13
View File
@@ -1,7 +1,6 @@
_: _:
let let
espPart = "/dev/disk/by-partuuid/a53e3b19-67de-40de-9ded-3eac3117689a"; espPart = "/dev/disk/by-partuuid/a53e3b19-67de-40de-9ded-3eac3117689a";
nixosPart = "/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e"; nixosPart = "/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e";
btrfsMountOptions = [ btrfsMountOptions = [
@@ -24,9 +23,7 @@ in
type = "filesystem"; type = "filesystem";
format = "vfat"; format = "vfat";
mountpoint = "/boot"; mountpoint = "/boot";
mountOptions = [ mountOptions = [ "umask=0077" ];
"umask=0077"
];
}; };
}; };
@@ -38,12 +35,8 @@ in
content = { content = {
type = "luks"; type = "luks";
name = "cryptroot"; name = "cryptroot";
askPassword = true; askPassword = true;
settings.allowDiscards = true;
settings = {
allowDiscards = true;
};
extraFormatArgs = [ extraFormatArgs = [
"--type" "--type"
@@ -85,10 +78,7 @@ in
"@swap" = { "@swap" = {
mountpoint = "/.swapvol"; mountpoint = "/.swapvol";
mountOptions = [ mountOptions = [ "noatime" ];
"noatime"
];
swap.swapfile.size = "32G"; swap.swapfile.size = "32G";
}; };
}; };
+2 -3
View File
@@ -1,6 +1,5 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’ # Do not modify this file! It was generated by `nixos-generate-config`
# and may be overwritten by future invocations. Please make changes # and may be overwritten by future invocations. Make changes in nixos.nix.
# to /etc/nixos/configuration.nix instead.
{ {
config, config,
lib, lib,
+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;
}
];
};
}
];
};
}
@@ -1,4 +1,3 @@
{ ... }:
{ {
imports = [ imports = [
./hardware-configuration.nix ./hardware-configuration.nix
+52
View File
@@ -0,0 +1,52 @@
# 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"
"thunderbolt"
"nvme"
"usb_storage"
"sd_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/16b29578-6836-414b-a5e1-863bc21c5fc3";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/209A-C8C9";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp0s20f3.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
@@ -1,4 +1,3 @@
{ ... }:
{ {
imports = [ imports = [
./hardware-configuration.nix ./hardware-configuration.nix
+17
View File
@@ -0,0 +1,17 @@
{
inputs,
lib ? inputs.nixpkgs.lib,
root,
}:
let
registry = import ./registry.nix {
inherit inputs lib;
modulesRoot = root + "/modules";
};
hosts = import ./hosts.nix {
inherit inputs lib registry;
};
in
{
inherit hosts registry;
}
+191
View File
@@ -0,0 +1,191 @@
{
inputs,
lib,
registry,
}:
let
ensure =
condition: message: value:
if condition then value else throw "host registry: ${message}";
isLinux = system: lib.hasSuffix "-linux" system;
isDarwin = system: lib.hasSuffix "-darwin" system;
hostFile =
spec: name:
let
path = spec.path + "/${name}";
in
if builtins.pathExists path then path else null;
selectedUnits =
spec:
[ "users.${spec.user}" ]
++ map (name: "profiles.${name}") (spec.profiles or [ ])
++ map (name: "applications.${name}") (spec.applications or [ ])
++ (spec.units or [ ]);
validateSpec =
name: spec:
ensure (builtins.isAttrs spec) "${name}: host specification must be an attribute set" (
ensure (spec ? system && builtins.isString spec.system) "${name}: system is required" (
ensure (isLinux spec.system || isDarwin spec.system)
"${name}: unsupported system '${spec.system}'; expected a Linux NixOS or Darwin system"
(
ensure (spec ? user && builtins.isString spec.user && spec.user != "") "${name}: user is required" (
ensure (spec ? path && builtins.pathExists spec.path)
"${name}: path must name an existing host directory"
(
ensure
(
spec ? stateVersion
&& builtins.isString spec.stateVersion
&& builtins.match "[0-9][0-9]\\.[0-9][0-9]" spec.stateVersion != null
)
"${name}: stateVersion is required and must have the form YY.MM"
(
ensure
(lib.all
(field: builtins.isList (spec.${field} or [ ]) && lib.all builtins.isString (spec.${field} or [ ]))
[
"profiles"
"applications"
"units"
]
)
"${name}: profiles, applications, and units must be lists of strings"
(ensure (builtins.isBool (spec.homeManager or true)) "${name}: homeManager must be a boolean" spec)
)
)
)
)
)
);
mkSpecialArgs = name: spec: {
inherit inputs registry;
inherit (spec) system;
hostName = name;
primaryUser = spec.user;
};
mkHomeManagerModule =
name: spec: selected:
let
homePath = hostFile spec "home.nix";
homeModules = [
(registry.mkModule {
class = "home";
systemClass = "nixos";
})
(registry.mkSelectionModule selected)
{ home.stateVersion = spec.stateVersion; }
]
++ lib.optional (homePath != null) homePath;
in
{
imports = [ inputs.home-manager.nixosModules.home-manager ];
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = mkSpecialArgs name spec;
users.${spec.user}.imports = homeModules;
};
};
mkDarwinHomeManagerModule =
name: spec: selected:
let
homePath = hostFile spec "home.nix";
homeModules = [
(registry.mkModule {
class = "home";
systemClass = "darwin";
})
(registry.mkSelectionModule selected)
{ home.stateVersion = spec.stateVersion; }
]
++ lib.optional (homePath != null) homePath;
in
{
imports = [ inputs.home-manager.darwinModules.home-manager ];
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = mkSpecialArgs name spec;
users.${spec.user}.imports = homeModules;
};
};
mkNixos =
name: rawSpec:
let
spec = validateSpec name rawSpec;
selected = registry.validateUnitIds (selectedUnits spec);
nixosPath = hostFile spec "nixos.nix";
modules = [
(registry.mkModule { class = "nixos"; })
(registry.mkSelectionModule selected)
{
networking.hostName = lib.mkDefault name;
system.stateVersion = spec.stateVersion;
}
]
++ lib.optional (spec.homeManager or true) (mkHomeManagerModule name spec selected)
++ lib.optional (nixosPath != null) nixosPath;
in
inputs.nixpkgs.lib.nixosSystem {
inherit (spec) system;
specialArgs = mkSpecialArgs name spec;
inherit modules;
};
mkDarwin =
name: rawSpec:
let
spec = validateSpec name rawSpec;
selected = registry.validateUnitIds (selectedUnits spec);
darwinPath = hostFile spec "darwin.nix";
modules = [
(registry.mkModule { class = "darwin"; })
(registry.mkSelectionModule selected)
{
networking.hostName = lib.mkDefault name;
system.primaryUser = lib.mkDefault spec.user;
}
]
++ lib.optional (spec.homeManager or true) (mkDarwinHomeManagerModule name spec selected)
++ lib.optional (darwinPath != null) darwinPath;
in
ensure (inputs ? nix-darwin) "${name}: the nix-darwin input is required" (
inputs.nix-darwin.lib.darwinSystem {
inherit (spec) system;
specialArgs = mkSpecialArgs name spec;
inherit modules;
}
);
mkConfigurations =
hostSpecs:
let
validated = lib.mapAttrs validateSpec hostSpecs;
in
{
nixosConfigurations = lib.mapAttrs mkNixos (
lib.filterAttrs (_: spec: isLinux spec.system) validated
);
darwinConfigurations = lib.mapAttrs mkDarwin (
lib.filterAttrs (_: spec: isDarwin spec.system) validated
);
};
in
{
inherit
mkConfigurations
mkDarwin
mkNixos
selectedUnits
;
}
+386
View File
@@ -0,0 +1,386 @@
{
inputs,
lib,
modulesRoot,
}:
let
rootFragmentFiles = {
common = "common.nix";
nixos = "nixos.nix";
darwin = "darwin.nix";
home = "home.nix";
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 =
condition: message: value:
if condition then value else throw "unit registry: ${message}";
callWithAvailableArgs =
value: availableArgs:
if builtins.isFunction value then
value (builtins.intersectAttrs (builtins.functionArgs value) availableArgs)
else
value;
pathFor =
relativePath:
if relativePath == [ ] then
modulesRoot
else
modulesRoot + "/${lib.concatStringsSep "/" relativePath}";
entryIsFile = entries: name: builtins.hasAttr name entries && isFile entries.${name};
normalizeMeta =
unit:
let
metaPath = unit.fragments.meta;
importedValue =
if metaPath == null then
{ }
else
callWithAvailableArgs (import metaPath) {
inherit inputs lib unit;
};
imported =
ensure (builtins.isAttrs importedValue) "${unit.id}: meta.nix must return an attribute set"
importedValue;
allowedKeys = [
"description"
"includes"
"imports"
];
unknownKeys = lib.filter (name: !(builtins.elem name allowedKeys)) (builtins.attrNames imported);
description = imported.description or null;
includes = imported.includes or [ ];
imports = imported.imports or { };
allowedImportKeys = [
"nixos"
"darwin"
"home"
];
unknownImportKeys =
if builtins.isAttrs imports then
lib.filter (name: !(builtins.elem name allowedImportKeys)) (builtins.attrNames imports)
else
[ ];
normalized = {
inherit description includes;
imports = {
nixos = imports.nixos or [ ];
darwin = imports.darwin or [ ];
home = imports.home or [ ];
};
};
in
ensure (unknownKeys == [ ])
"${unit.id}: meta.nix has unsupported keys: ${lib.concatStringsSep ", " unknownKeys}"
(
ensure (description == null || builtins.isString description)
"${unit.id}: meta.description must be a string"
(
ensure (builtins.isList includes && lib.all builtins.isString includes)
"${unit.id}: meta.includes must be a list of fully qualified unit IDs"
(
ensure (lib.unique includes == includes) "${unit.id}: meta.includes contains duplicate unit IDs" (
ensure (builtins.isAttrs imports) "${unit.id}: meta.imports must be an attribute set" (
ensure (unknownImportKeys == [ ])
"${unit.id}: meta.imports has unsupported classes: ${lib.concatStringsSep ", " unknownImportKeys}"
(
ensure (lib.all builtins.isList [
normalized.imports.nixos
normalized.imports.darwin
normalized.imports.home
]) "${unit.id}: every meta.imports.<class> value must be a list" normalized
)
)
)
)
)
);
makeUnit =
relativePath: entries: homeEntries:
let
directory = pathFor relativePath;
id = lib.concatStringsSep "." relativePath;
rootFragments = lib.mapAttrs (
_class: fileName: if entryIsFile entries fileName then directory + "/${fileName}" else null
) rootFragmentFiles;
homeFragments = lib.mapAttrs (
_class: fileName: if entryIsFile homeEntries fileName then directory + "/home/${fileName}" else null
) homeFragmentFiles;
fragments = rootFragments // homeFragments;
baseUnit = {
inherit
id
directory
fragments
relativePath
;
optionPath = [ "my" ] ++ relativePath ++ [ "enable" ];
kind = builtins.head relativePath;
name = lib.last relativePath;
}
//
lib.optionalAttrs (builtins.length relativePath > 2 && builtins.head relativePath == "profiles")
{
group = builtins.elemAt relativePath 1;
};
in
ensure (relativePath != [ ]) "the modules root cannot itself be a unit" (
ensure (lib.all (component: component != "" && !(lib.hasInfix "." component)) relativePath)
"${id}: path components must be non-empty and must not contain dots"
(baseUnit // { meta = normalizeMeta baseUnit; })
);
walk =
relativePath:
let
directory = pathFor relativePath;
entries = builtins.readDir directory;
homeEntries =
if relativePath != [ ] && (entries.home or null) == "directory" then
builtins.readDir (directory + "/home")
else
{ };
hasRootFragment = lib.any (fileName: entryIsFile entries fileName) (
builtins.attrValues rootFragmentFiles
);
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;
discoveredUnits =
ensure (builtins.pathExists modulesRoot) "modules root does not exist: ${toString modulesRoot}"
(walk [ ]);
unitsById = builtins.listToAttrs (map (unit: lib.nameValuePair unit.id unit) discoveredUnits);
dependencyValidation = lib.foldl' (
valid: unit:
lib.foldl' (
inner: includedId:
if builtins.hasAttr includedId unitsById then
inner
else
throw "unit registry: ${unit.id} includes missing unit '${includedId}'"
) valid unit.meta.includes
) true discoveredUnits;
units = builtins.seq dependencyValidation unitsById;
unitIds = builtins.attrNames units;
getUnit =
id: if builtins.hasAttr id units then units.${id} else throw "unit registry: unknown unit '${id}'";
validateUnitIds =
ids:
ensure (
builtins.isList ids && lib.all builtins.isString ids
) "selected units must be a list of strings" (map (id: builtins.seq (getUnit id) id) ids);
optionDefinitions = lib.foldl' lib.recursiveUpdate { } (
map (
unit:
lib.setAttrByPath unit.optionPath (
lib.mkOption {
type = lib.types.bool;
default = false;
description =
if unit.meta.description == null then
"Whether to enable the ${unit.id} unit."
else
"Whether to enable ${unit.meta.description}.";
}
)
) discoveredUnits
);
enabled = config: unit: lib.getAttrFromPath unit.optionPath config;
enableUnit = id: lib.setAttrByPath (getUnit id).optionPath true;
includeConfig =
config: unit: lib.mkIf (enabled config unit) (lib.mkMerge (map enableUnit unit.meta.includes));
fragmentClasses = {
nixos = [
"common"
"nixos"
];
darwin = [
"common"
"darwin"
];
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,
unit,
}:
let
fragment = import fragmentPath;
directArgs = specialArgs // {
inherit
config
lib
options
specialArgs
unit
;
};
fragmentArgSpec = builtins.functionArgs fragment;
fragmentArgs = builtins.listToAttrs (
lib.concatMap (
name:
if builtins.hasAttr name directArgs then
[ (lib.nameValuePair name directArgs.${name}) ]
else if fragmentArgSpec.${name} then
[ ]
else
[ (lib.nameValuePair name config._module.args.${name}) ]
) (builtins.attrNames fragmentArgSpec)
);
resultValue = if builtins.isFunction fragment then fragment fragmentArgs else fragment;
result =
ensure (builtins.isAttrs resultValue) "${unit.id}: ${fragmentName} must return an attribute set"
resultValue;
forbiddenKeys = lib.filter (name: builtins.hasAttr name result) [
"imports"
"options"
"config"
];
in
ensure (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,
systemClass ? null,
}:
let
selectedFragmentClasses = fragmentClassesFor { inherit class systemClass; };
in
builtins.seq selectedFragmentClasses (
builtins.seq dependencyValidation (
{
config,
lib,
options,
specialArgs,
...
}:
let
fragmentConfigs = lib.concatMap (
unit:
lib.filter (value: value != null) (
map (
fragmentClass:
let
fragmentName = fragmentFileNames.${fragmentClass};
fragmentPath = unit.fragments.${fragmentClass};
in
if fragmentPath == null then
null
else
lib.mkIf (enabled config unit) (applyFragment {
inherit
config
fragmentName
fragmentPath
options
specialArgs
unit
;
})
) selectedFragmentClasses
)
) discoveredUnits;
in
{
imports = externalImports class;
options = optionDefinitions;
config = lib.mkMerge ((map (includeConfig config) discoveredUnits) ++ fragmentConfigs);
}
)
);
mkSelectionModule =
selectedIds:
let
checkedIds = validateUnitIds (lib.unique selectedIds);
in
{
config = lib.mkMerge (map enableUnit checkedIds);
};
in
{
inherit
getUnit
mkModule
mkSelectionModule
unitIds
units
validateUnitIds
;
}
-26
View File
@@ -1,26 +0,0 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications."1password";
in
{
options.my.applications."1password" = {
enable = lib.mkEnableOption "1Password password manager";
};
config = lib.mkIf cfg.enable {
programs._1password.enable = true;
programs._1password-gui = {
enable = true;
polkitPolicyOwners = [ "moons" ];
};
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,4 @@
_: {
programs._1password-gui.enable = true;
programs._1password.enable = true;
}
+9
View File
@@ -0,0 +1,9 @@
{ primaryUser, lib, ... }:
{
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";
}
-29
View File
@@ -1,29 +0,0 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.arduino;
arduinoIdeX11 = pkgs.arduino-ide.overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ];
postFixup = (old.postFixup or "") + ''
wrapProgram $out/bin/arduino-ide \
--add-flags "--ozone-platform=x11"
'';
});
in
{
options.my.applications.arduino = {
enable = lib.mkEnableOption "Arduino development tools";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = with pkgs; [
arduino-cli # Arduino command-line interface
arduinoIdeX11 # Arduino IDE with X11 support
];
};
}
+4
View File
@@ -0,0 +1,4 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.arduino-cli ];
}
+14
View File
@@ -0,0 +1,14 @@
{ pkgs, ... }:
let
arduinoIdeX11 = pkgs.arduino-ide.overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ];
postFixup = (old.postFixup or "") + ''
wrapProgram $out/bin/arduino-ide \
--add-flags "--ozone-platform=x11"
'';
});
in
{
environment.systemPackages = [ arduinoIdeX11 ];
}
+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 ];
}
-23
View File
@@ -1,23 +0,0 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.btop;
in
{
imports = [
./home.nix
./system.nix
];
options.my.applications.btop = {
enable = lib.mkEnableOption "btop system monitor";
};
config = lib.mkIf cfg.enable {
my.applications.btop.system.enable = lib.mkDefault true;
my.applications.btop.homeManager.enable = lib.mkDefault true;
};
}
+3 -3
View File
@@ -1,5 +1,5 @@
#Bashtop theme with nord palette (https://www.nordtheme.com) # Bashtop theme with Nord palette (https://www.nordtheme.com)
#by Justin Zobel <[email protected]> # by Justin Zobel <[email protected]>
# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: "#RRGGBB", "#BW" or "0-255 0-255 0-255" # Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: "#RRGGBB", "#BW" or "0-255 0-255 0-255"
# example for white: "#ffffff", "#ff" or "255 255 255". # example for white: "#ffffff", "#ff" or "255 255 255".
@@ -18,7 +18,7 @@ theme[main_fg]="#BD93F9"
# Title color for boxes # Title color for boxes
theme[title]="#f8f8f2" theme[title]="#f8f8f2"
# Higlight color for keyboard shortcuts # Highlight color for keyboard shortcuts
theme[hi_fg]="#ff79c6" theme[hi_fg]="#ff79c6"
# Background color of selected item in processes box # Background color of selected item in processes box
+5 -22
View File
@@ -1,25 +1,8 @@
{ {
lib, programs.btop = {
config, enable = true;
...
}:
let
cfg = config.my.applications.btop.homeManager;
in
{
options.my.applications.btop.homeManager = {
enable = lib.mkEnableOption "btop home-manager configuration";
};
config.home-manager.sharedModules = [ settings.color_theme = "dracula";
{ themes.dracula = builtins.readFile ./dracula.theme;
config = lib.mkIf cfg.enable { };
programs.btop = {
enable = true;
settings.color_theme = "dracula";
themes.dracula = builtins.readFile ./dracula.theme;
};
};
}
];
} }
-20
View File
@@ -1,20 +0,0 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.btop.system;
in
{
options.my.applications.btop.system = {
enable = lib.mkEnableOption "btop system configuration";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = with pkgs; [
btop # Resource monitor that shows usage and stats
];
};
}
@@ -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"
]
);
};
}
-44
View File
@@ -1,44 +0,0 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.chrome;
in
{
options.my.applications.chrome = {
enable = lib.mkEnableOption "Google Chrome browser";
};
config = lib.mkIf cfg.enable {
home-manager.sharedModules = [
{
home.packages = with pkgs; [
google-chrome # Popular web browser from Google
];
xdg.desktopEntries."google-chrome" = {
name = "Google Chrome";
genericName = "Web Browser";
exec = "${pkgs.google-chrome}/bin/google-chrome-stable --enable-features=TouchpadOverscrollHistoryNavigation %U";
terminal = false;
icon = "google-chrome";
categories = [
"Network"
"WebBrowser"
];
startupNotify = true;
type = "Application";
};
xdg.mimeApps.defaultApplications = {
"text/html" = "google-chrome.desktop";
"x-scheme-handler/http" = "google-chrome.desktop";
"x-scheme-handler/https" = "google-chrome.desktop";
};
}
];
};
}
+6
View File
@@ -0,0 +1,6 @@
{
homebrew = {
enable = true;
casks = [ "google-chrome" ];
};
}
@@ -0,0 +1,19 @@
_: {
programs.google-chrome = {
enable = true;
commandLineArgs = [
"--enable-features=MiddleClickAutoscroll"
];
};
xdg.mimeApps = {
enable = true;
defaultApplications = {
"text/html" = "google-chrome.desktop";
"x-scheme-handler/http" = "google-chrome.desktop";
"x-scheme-handler/https" = "google-chrome.desktop";
};
};
}
-23
View File
@@ -1,23 +0,0 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.claude;
in
{
imports = [
./home.nix
./system.nix
];
options.my.applications.claude = {
enable = lib.mkEnableOption "Claude Code AI assistant";
};
config = lib.mkIf cfg.enable {
my.applications.claude.system.enable = lib.mkDefault true;
my.applications.claude.homeManager.enable = lib.mkDefault true;
};
}
+12 -21
View File
@@ -1,27 +1,18 @@
{ {
lib, inputs,
config, pkgs,
... ...
}: }:
let
cfg = config.my.applications.claude.homeManager;
in
{ {
options.my.applications.claude.homeManager = { home.packages = [
enable = lib.mkEnableOption "Claude Code home-manager configuration"; inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.claude-code
};
config.home-manager.sharedModules = [
{
config = lib.mkIf cfg.enable {
home.file.".claude/settings.json".text = builtins.toJSON {
statusLine = {
type = "command";
command = "bun x ccusage statusline --no-offline";
padding = 0;
};
};
};
}
]; ];
home.file.".claude/settings.json".text = builtins.toJSON {
statusLine = {
type = "command";
command = "bun x ccusage statusline --no-offline";
padding = 0;
};
};
} }
-20
View File
@@ -1,20 +0,0 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.claude.system;
in
{
options.my.applications.claude.system = {
enable = lib.mkEnableOption "Claude Code system configuration";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [
pkgs.llm-agents.claude-code # AI coding assistant
];
};
}
-65
View File
@@ -1,65 +0,0 @@
{
inputs,
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.codexDesktop;
codexCliPackage = pkgs.llm-agents.codex;
codexDesktopPackage =
inputs.codex-desktop-linux.packages.${pkgs.stdenv.hostPlatform.system}.codex-desktop-computer-use-ui;
codexDesktopLauncher = pkgs.makeDesktopItem {
name = "codex";
desktopName = "Codex";
genericName = "ChatGPT Desktop";
comment = "Run Codex Desktop on Linux";
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" ];
keywords = [
"codex"
"chatgpt"
"openai"
"ai"
"assistant"
];
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";
};
};
extraConfig = {
X-GNOME-WMClass = "codex-desktop";
};
};
in
{
imports = [
inputs.codex-desktop-linux.nixosModules.default
];
options.my.applications.codexDesktop = {
enable = lib.mkEnableOption "ChatGPT Desktop for Linux";
};
config = lib.mkIf cfg.enable {
my.applications.codex.enable = true;
programs.codexDesktopLinux = {
enable = true;
package = codexDesktopPackage;
cliPackage = codexCliPackage;
computerUseUi.enable = true;
};
environment.systemPackages = [
codexDesktopLauncher # Vicinae-searchable Codex Desktop launcher alias
];
};
}
@@ -0,0 +1,8 @@
{
# The former Codex app cask is deprecated in favor of ChatGPT, whose desktop
# application includes the current Codex experience on macOS.
homebrew = {
enable = true;
casks = [ "chatgpt" ];
};
}
@@ -0,0 +1,10 @@
{ inputs, ... }:
{
description = "Codex Desktop for Linux";
includes = [ "applications.codex" ];
imports.nixos = [
inputs.codex-desktop-linux.nixosModules.default
];
}
@@ -0,0 +1,18 @@
{
inputs,
pkgs,
...
}:
{
programs.codexDesktopLinux = {
enable = true;
cliPackage = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex;
remoteControl.enable = true;
remoteMobileControl.enable = true;
computerUseUi.enable = false;
linuxFeatures = [
"appshots"
"open-target-discovery"
];
};
}
-20
View File
@@ -1,20 +0,0 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.codex;
in
{
options.my.applications.codex = {
enable = lib.mkEnableOption "Codex AI coding assistant";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [
pkgs.llm-agents.codex # OpenAI Codex CLI
];
};
}
+6
View File
@@ -0,0 +1,6 @@
{ inputs, pkgs, ... }:
{
home.packages = [
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex
];
}
-46
View File
@@ -1,46 +0,0 @@
{
imports = [
./1password.nix
./arduino.nix
./btop
./chrome.nix
./claude
./codex-desktop.nix
./codex.nix
./direnv.nix
./discord.nix
./docker.nix
./fcitx5
./ghostty
./git
./gnupg
./grok.nix
./gnome.nix
./greetd.nix
./ly
./gtk
./java
./kde.nix
./nautilus.nix
./nh.nix
./niri
./nix-index
./noctalia
./opencode.nix
./openssh.nix
./slack.nix
./ssh
./swayidle.nix
./swaylock
./tailscale.nix
./vicinae.nix
./vim
./vscode
./wayland.nix
./yazi.nix
./zellij
./zoom.nix
./zoxide.nix
./zsh
];
}
-16
View File
@@ -1,16 +0,0 @@
{ lib, config, ... }:
let
cfg = config.my.applications.direnv;
in
{
options.my.applications.direnv = {
enable = lib.mkEnableOption "direnv environment variable manager";
};
config = lib.mkIf cfg.enable {
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
};
}
+10
View File
@@ -0,0 +1,10 @@
{
programs.direnv = {
enable = true;
nix-direnv.enable = true;
config.global = {
warn_timeout = "10s";
};
};
}
-23
View File
@@ -1,23 +0,0 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.discord;
in
{
options.my.applications.discord = {
enable = lib.mkEnableOption "Discord (Vesktop)";
};
config = lib.mkIf cfg.enable {
home-manager.sharedModules = [
{
programs.vesktop = {
enable = true;
};
}
];
};
}
+95
View File
@@ -0,0 +1,95 @@
_: {
programs.vesktop = {
enable = true;
settings = {
discordBranch = "stable";
hardwareAcceleration = true;
hardwareVideoAcceleration = true;
tray = true;
minimizeToTray = true;
# Discord Rich Presence
arRPC = true;
openLinksWithElectron = false;
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;
};
};
};
};
}
-34
View File
@@ -1,34 +0,0 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.docker;
in
{
options.my.applications.docker = {
enable = lib.mkEnableOption "Docker container runtime";
};
config = lib.mkIf cfg.enable {
virtualisation.docker = {
enable = true;
autoPrune = {
enable = true;
dates = "weekly";
};
daemon.settings = {
ipv6 = true;
"fixed-cidr-v6" = "fd00:30::/64";
ip6tables = true;
};
};
environment.systemPackages = with pkgs; [
docker # Container runtime
oxker # Docker TUI Tool
];
};
}
+6
View File
@@ -0,0 +1,6 @@
{
homebrew = {
enable = true;
casks = [ "orbstack" ];
};
}
@@ -0,0 +1,6 @@
{ pkgs, ... }:
{
home.packages = [
pkgs.docker-client
];
}
@@ -0,0 +1,6 @@
{ pkgs, ... }:
{
home.packages = [
pkgs.oxker
];
}
+5
View File
@@ -0,0 +1,5 @@
{
description = "Docker command-line client and NixOS daemon";
includes = [ "services.docker" ];
}
+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
-23
View File
@@ -1,23 +0,0 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.fcitx5;
in
{
imports = [
./home.nix
./system.nix
];
options.my.applications.fcitx5 = {
enable = lib.mkEnableOption "fcitx5 input method";
};
config = lib.mkIf cfg.enable {
my.applications.fcitx5.system.enable = lib.mkDefault true;
my.applications.fcitx5.homeManager.enable = lib.mkDefault true;
};
}
-24
View File
@@ -1,24 +0,0 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.fcitx5.homeManager;
in
{
options.my.applications.fcitx5.homeManager = {
enable = lib.mkEnableOption "fcitx5 home-manager configuration";
};
config.home-manager.sharedModules = [
{
config = lib.mkIf cfg.enable {
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 ];
}
-68
View File
@@ -1,68 +0,0 @@
{
pkgs,
lib,
config,
inputs,
...
}:
let
system = pkgs.stdenv.hostPlatform.system;
cfg = config.my.applications.fcitx5.system;
in
{
options.my.applications.fcitx5.system = {
enable = lib.mkEnableOption "fcitx5 system configuration";
};
imports = [
inputs.nix-hazkey.nixosModules.hazkey
];
config = lib.mkIf cfg.enable {
services.hazkey = {
enable = true;
server.package = inputs.nix-hazkey.packages.${system}.hazkey-server.override {
enableVulkan = true;
};
installHazkeySettings = false;
installFcitx5Addon = false;
};
environment.systemPackages = [ inputs.nix-hazkey.packages.${system}.hazkey-settings ];
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5 = {
waylandFrontend = true;
addons = with pkgs; [
inputs.nix-hazkey.packages.${system}.fcitx5-hazkey
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 = "";
};
};
};
};
};
}
+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;
};
}
-40
View File
@@ -1,40 +0,0 @@
theme = dracula
background-blur-radius = 20
background-opacity = 0.9
font-family = BlexMono Nerd Font Mono
mouse-hide-while-typing = true
window-decoration = true
# keybind
# Copy/Paste
keybind = performable:ctrl+shift+c=copy_to_clipboard
keybind = ctrl+shift+v=paste_from_clipboard
# create new tab
keybind = ctrl+shift+t=new_tab
# move tabs
keybind = ctrl+alt+left_bracket=previous_tab
keybind = ctrl+alt+right_bracket=next_tab
# close tab
keybind = ctrl+alt+q=close_window
# font size
keybind = ctrl+shift+semicolon=increase_font_size:1
keybind = ctrl+shift+minus=increase_font_size:1
# quick terminal
keybind = global:super+space=toggle_quick_terminal
quick-terminal-position = top
quick-terminal-size = 100%
gtk-quick-terminal-layer = overlay
quick-terminal-keyboard-interactivity = exclusive
quick-terminal-autohide = false
quit-after-last-window-closed = false
shell-integration-features = ssh-terminfo,ssh-env
+6
View File
@@ -0,0 +1,6 @@
{
homebrew = {
enable = true;
casks = [ "ghostty" ];
};
}
-23
View File
@@ -1,23 +0,0 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.ghostty;
in
{
imports = [
./home.nix
./system.nix
];
options.my.applications.ghostty = {
enable = lib.mkEnableOption "ghostty terminal emulator";
};
config = lib.mkIf cfg.enable {
my.applications.ghostty.system.enable = lib.mkDefault true;
my.applications.ghostty.homeManager.enable = lib.mkDefault true;
};
}
-83
View File
@@ -1,83 +0,0 @@
{
pkgs,
lib,
config,
inputs,
...
}:
let
cfg = config.my.applications.ghostty.homeManager;
system = pkgs.stdenv.hostPlatform.system;
ghosttyPkg = inputs.ghostty.packages.${system}.ghostty-releasefast;
in
{
options.my.applications.ghostty.homeManager = {
enable = lib.mkEnableOption "ghostty home-manager configuration";
};
config.home-manager.sharedModules = [
(
{ lib, ... }:
{
config = lib.mkIf cfg.enable {
programs.ghostty = {
enable = true;
package = ghosttyPkg;
systemd.enable = true;
settings = {
theme = "dracula";
background-blur-radius = 20;
background-opacity = 0.9;
font-family = "BlexMono Nerd Font Mono";
mouse-hide-while-typing = true;
window-decoration = "auto";
keybind = [
# Copy/Paste
"performable:ctrl+shift+c=copy_to_clipboard"
"ctrl+shift+v=paste_from_clipboard"
# Create new tab
"ctrl+shift+t=new_tab"
# Move tabs
"ctrl+alt+left_bracket=previous_tab"
"ctrl+alt+right_bracket=next_tab"
# Close window
"ctrl+alt+q=close_window"
# Font size
"ctrl+shift+semicolon=increase_font_size:1"
"ctrl+shift+minus=decrease_font_size:1"
];
# Quick terminal
quick-terminal-position = "top";
quick-terminal-size = "98%,100%";
quick-terminal-autohide = false;
quick-terminal-keyboard-interactivity = "on-demand";
gtk-quick-terminal-layer = "top";
quit-after-last-window-closed = false;
shell-integration-features = "no-ssh-env,no-ssh-terminfo";
};
};
xdg.configFile."ghostty/themes/dracula".source = ./dracula.theme;
};
}
)
];
}
@@ -0,0 +1,39 @@
_: {
programs.ghostty = {
enable = true;
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";
keybind = [
"performable:ctrl+shift+c=copy_to_clipboard"
"ctrl+shift+v=paste_from_clipboard"
"ctrl+shift+t=new_tab"
"ctrl+alt+left_bracket=previous_tab"
"ctrl+alt+right_bracket=next_tab"
"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;
quick-terminal-keyboard-interactivity = "on-demand";
gtk-quick-terminal-layer = "top";
quit-after-last-window-closed = false;
shell-integration-features = "no-ssh-env,no-ssh-terminfo";
};
};
xdg.configFile."ghostty/themes/dracula".source = ./dracula.theme;
}
@@ -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;
}
@@ -42,4 +42,3 @@ cursor-color = #f8f8f2
cursor-text = #282a36 cursor-text = #282a36
selection-foreground = #f8f8f2 selection-foreground = #f8f8f2
selection-background = #44475a selection-background = #44475a
@@ -0,0 +1,6 @@
{ inputs, system, ... }: {
programs.ghostty = {
systemd.enable = true;
package = inputs.ghostty.packages.${system}.default;
};
}
-26
View File
@@ -1,26 +0,0 @@
{
pkgs,
lib,
config,
inputs,
...
}:
let
cfg = config.my.applications.ghostty.system;
system = pkgs.stdenv.hostPlatform.system;
ghosttyPkg = inputs.ghostty.packages.${system}.ghostty-releasefast;
in
{
options.my.applications.ghostty.system = {
enable = lib.mkEnableOption "ghostty system configuration";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [
ghosttyPkg # A fast and minimal terminal emulator for Wayland
ghosttyPkg.terminfo # Terminfo database for ghostty
];
};
}

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