mirror of
https://github.com/moons-14/dotfiles.git
synced 2026-10-06 10:34:09 +09:00
Compare commits
98
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec3770502d | ||
|
|
fda29cd08d | ||
|
|
db0a440da4 | ||
|
|
76f5dce9c0 | ||
|
|
3b61457718 | ||
|
|
c9f1584797 | ||
|
|
d51948c307 | ||
|
|
9a38e9f614 | ||
|
|
2cb7e76ca1 | ||
|
|
749410e032 | ||
|
|
d43f19c20a | ||
|
|
32a3067cb0 | ||
|
|
6e60bd8886 | ||
|
|
bcf7ef56cf | ||
|
|
63e2008423 | ||
|
|
3b8147ff46 | ||
|
|
c84f257149 | ||
|
|
6347292c1d | ||
|
|
2a82433754 | ||
|
|
847ee17b29 | ||
|
|
95f74aabcd | ||
|
|
717572ae24 | ||
|
|
8086c9a7f3 | ||
|
|
eba23455d4 | ||
|
|
b3b1031364 | ||
|
|
366ff54403 | ||
|
|
456e9946f4 | ||
|
|
c104404e5b | ||
|
|
cb41932fec | ||
|
|
fa4b7ca404 | ||
|
|
847d33e83b | ||
|
|
b2c700e1e4 | ||
|
|
c1540d8764 | ||
|
|
5b8c3b1415 | ||
|
|
6743569789 | ||
|
|
70253fc451 | ||
|
|
5107b80173 | ||
|
|
2bdea522cb | ||
|
|
c113d0d46d | ||
|
|
fa50be8feb | ||
|
|
33ebef4a1e | ||
|
|
94048ef8d5 | ||
|
|
c7627fa1b0 | ||
|
|
d68da620ac | ||
|
|
5f0df47775 | ||
|
|
119342e564 | ||
|
|
1f066e8937 | ||
|
|
0a440e3da8 | ||
|
|
bdf93ac6bb | ||
|
|
9ae5da4d30 | ||
|
|
872436b170 | ||
|
|
c14325e29c | ||
|
|
45bc66e25f | ||
|
|
78ee2d41ec | ||
|
|
0b1ae13048 | ||
|
|
458b0a2cdb | ||
|
|
01179f3dc6 | ||
|
|
42949fc06c | ||
|
|
a7f514c0f9 | ||
|
|
9bed1c3e25 | ||
|
|
791b6baa83 | ||
|
|
349f49e496 | ||
|
|
3166c12448 | ||
|
|
4c459e4aa7 | ||
|
|
9b9141dd84 | ||
|
|
16e3fda275 | ||
|
|
ca36b07839 | ||
|
|
5ebcbb4abf | ||
|
|
f8fd8a3d99 | ||
|
|
16742d2fd7 | ||
|
|
15da7affaa | ||
|
|
548647fec7 | ||
|
|
bcbd08c225 | ||
|
|
a0ae83d24e | ||
|
|
33e09f8e93 | ||
|
|
eff32fddcd | ||
|
|
8ce3a6082a | ||
|
|
a8246261ad | ||
|
|
8b51b5c55f | ||
|
|
e24d85da56 | ||
|
|
01ead9a385 | ||
|
|
328f11d0ed | ||
|
|
d877ffc76c | ||
|
|
fe40adaeee | ||
|
|
991dde5305 | ||
|
|
96ce4d768c | ||
|
|
30b1480e50 | ||
|
|
71011d7bd1 | ||
|
|
9cced59e58 | ||
|
|
20a601402e | ||
|
|
1b4a5fa5a2 | ||
|
|
5fb55f2e6a | ||
|
|
2a3f7ee6ff | ||
|
|
247db71f2d | ||
|
|
a44a83a587 | ||
|
|
1f1d46ea2a | ||
|
|
29c4815b88 | ||
|
|
28a46d9990 |
@@ -30,3 +30,4 @@
|
||||
!/modules/
|
||||
|
||||
!/tests/
|
||||
!/skills/
|
||||
|
||||
@@ -24,6 +24,11 @@ makes any statement here stale, update `AGENTS.md` in the same change.
|
||||
| `overlays/` | Package replacements and additions |
|
||||
| `shells/` | Development shells |
|
||||
| `flake/` | Supporting flake outputs such as formatters, checks, and Git hooks |
|
||||
| `skills/` | Repository-specific Codex workflows that enforce this contract for recurring changes |
|
||||
|
||||
Before adding or materially extending an application or service, read and
|
||||
follow `skills/add-application-or-service/SKILL.md`. `AGENTS.md` remains the
|
||||
authoritative contract when the skill and repository ever disagree.
|
||||
|
||||
Use **unit** as the generic internal term for a Registry-managed component and
|
||||
**profile** for a unit that composes multiple units. Do not introduce a
|
||||
@@ -352,6 +357,7 @@ modules/profiles/
|
||||
│ ├── labwc/
|
||||
│ └── niri/
|
||||
├── networking/
|
||||
│ ├── homelab-cache-client/
|
||||
│ ├── tailscale-client/
|
||||
│ └── tailscale-subnet-router/
|
||||
├── platform/
|
||||
@@ -362,7 +368,11 @@ modules/profiles/
|
||||
│ ├── desktop/
|
||||
│ └── vm/
|
||||
├── workload/
|
||||
│ ├── camera/
|
||||
│ ├── development/
|
||||
│ ├── game/
|
||||
│ ├── machine-learning/
|
||||
│ ├── nix-builder/
|
||||
│ ├── personal/
|
||||
│ ├── server/
|
||||
│ └── remote-access/
|
||||
@@ -597,6 +607,7 @@ A host registry may use a specification like this:
|
||||
"security.secrets"
|
||||
"security.secure-boot"
|
||||
"security.tpm-storage"
|
||||
"workload.camera"
|
||||
"workload.development"
|
||||
"workload.personal"
|
||||
];
|
||||
@@ -619,6 +630,7 @@ A host registry may use a specification like this:
|
||||
"security.tpm-storage"
|
||||
"workload.development"
|
||||
"workload.game"
|
||||
"workload.machine-learning"
|
||||
"workload.personal"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# iOS Simulator 初期セットアップ
|
||||
|
||||
この手順は `m2` の macOS 環境で、stable Xcode と最新の stable iOS Simulator Runtime を使える状態にするためのもの。
|
||||
|
||||
## 前提
|
||||
|
||||
- `m2` が `workload.development` profile を有効にしていること
|
||||
- Mac App Store に Apple Account でサインイン済みであること
|
||||
- dotfiles を最新化していること
|
||||
|
||||
Xcode 本体は `applications.xcode` が Mac App Store 版を管理する。Simulator Runtime は Apple が管理する mutable state のため、Nix store には入れず専用 dev shell から導入する。
|
||||
|
||||
## 1. macOS 設定を反映する
|
||||
|
||||
リポジトリ直下で nix-darwin の設定を反映する。
|
||||
|
||||
```bash
|
||||
sudo darwin-rebuild switch --flake .#m2
|
||||
```
|
||||
|
||||
これにより `/Applications/Xcode.app` に stable Xcode がインストールされる。
|
||||
|
||||
Xcode のインストールで Mac App Store の認証エラーになる場合は、App Store を一度開いてサインイン状態を確認してから再実行する。
|
||||
|
||||
## 2. iOS Simulator Runtime を導入する
|
||||
|
||||
初回セットアップは次の1コマンドで行う。
|
||||
|
||||
```bash
|
||||
nix develop .#ios -c ios-simulator-install
|
||||
```
|
||||
|
||||
`ios-simulator-install` は次を順に実行する。
|
||||
|
||||
1. `/Applications/Xcode.app` が存在することを確認
|
||||
2. `xcode-select` の Developer Directory を stable Xcode に切り替え
|
||||
3. Xcode の first-launch components を導入
|
||||
4. 利用可能な新しい hardware support components を確認
|
||||
5. 選択中の Xcode に対応する最新の iOS Simulator Runtime をダウンロードしてインストール
|
||||
6. Xcode のバージョンとインストール済み Simulator Runtime を表示
|
||||
|
||||
途中で `sudo` の認証を求められる場合がある。
|
||||
|
||||
## 3. インストールを確認する
|
||||
|
||||
```bash
|
||||
xcodebuild -version
|
||||
xcode-select -p
|
||||
xcrun simctl list runtimes
|
||||
xcrun simctl list devices available
|
||||
```
|
||||
|
||||
`xcode-select -p` は次を指していること。
|
||||
|
||||
```text
|
||||
/Applications/Xcode.app/Contents/Developer
|
||||
```
|
||||
|
||||
`xcrun simctl list runtimes` に iOS runtime が表示されればセットアップ完了。
|
||||
|
||||
## 4. Simulator を起動する
|
||||
|
||||
```bash
|
||||
open -a Simulator
|
||||
```
|
||||
|
||||
Simulator の Device メニューから、インストール済み runtime で利用可能な iPhone を選択する。
|
||||
|
||||
## Runtime の更新
|
||||
|
||||
Xcode を stable の新しいバージョンへ更新した後は、同じコマンドを再実行する。
|
||||
|
||||
```bash
|
||||
nix develop .#ios -c ios-simulator-install
|
||||
```
|
||||
|
||||
Xcode の選択、first-launch components、hardware support、iOS Simulator Runtime の状態をまとめて更新できる。
|
||||
|
||||
## トラブルシューティング
|
||||
|
||||
### Xcode が見つからない
|
||||
|
||||
次のエラーが出る場合、先に nix-darwin の設定を反映する。
|
||||
|
||||
```text
|
||||
Xcode is not installed at /Applications/Xcode.app.
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo darwin-rebuild switch --flake .#m2
|
||||
```
|
||||
|
||||
### Simulator Runtime が見えない
|
||||
|
||||
まず runtime 一覧を確認する。
|
||||
|
||||
```bash
|
||||
xcrun simctl list runtimes
|
||||
```
|
||||
|
||||
iOS runtime がない場合は再度インストーラーを実行する。
|
||||
|
||||
```bash
|
||||
nix develop .#ios -c ios-simulator-install
|
||||
```
|
||||
|
||||
### Command Line Tools 側を参照している
|
||||
|
||||
```bash
|
||||
xcode-select -p
|
||||
```
|
||||
|
||||
が `/Library/Developer/CommandLineTools` を指している場合でも、`ios-simulator-install` が `/Applications/Xcode.app/Contents/Developer` へ切り替える。
|
||||
|
||||
手動で直す場合は次を実行する。
|
||||
|
||||
```bash
|
||||
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
|
||||
```
|
||||
Generated
+820
-295
File diff suppressed because it is too large
Load Diff
@@ -60,6 +60,11 @@
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
deploy-rs = {
|
||||
url = "github:serokell/deploy-rs";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
# Disk management
|
||||
disko = {
|
||||
url = "github:nix-community/disko";
|
||||
@@ -91,6 +96,13 @@
|
||||
url = "github:ilysenko/codex-desktop-linux";
|
||||
};
|
||||
|
||||
codex-session-usage.url = "github:moons-14/codex-session-usage";
|
||||
|
||||
skills = {
|
||||
url = "github:mattpocock/skills";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
# Index / Search
|
||||
nix-index-database = {
|
||||
url = "github:nix-community/nix-index-database";
|
||||
@@ -104,6 +116,9 @@
|
||||
url = "github:nix-community/browser-previews";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
nani-translate-linux.url = "git+https://github.com/zunoser/nani-translate-linux.git";
|
||||
|
||||
};
|
||||
|
||||
outputs =
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
imports = [
|
||||
./deploy.nix
|
||||
./formatter.nix
|
||||
./git-hooks.nix
|
||||
./registry.nix
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
inputs,
|
||||
self,
|
||||
...
|
||||
}:
|
||||
{
|
||||
flake.deploy = {
|
||||
nodes.nix-builder = {
|
||||
hostname = "nix-builder";
|
||||
sshUser = "moons";
|
||||
user = "root";
|
||||
|
||||
interactiveSudo = true;
|
||||
remoteBuild = true;
|
||||
autoRollback = true;
|
||||
magicRollback = true;
|
||||
|
||||
profiles.system.path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.nix-builder;
|
||||
};
|
||||
};
|
||||
|
||||
perSystem =
|
||||
{ system, ... }:
|
||||
{
|
||||
apps.deploy = inputs.deploy-rs.apps.${system}.default;
|
||||
checks = inputs.deploy-rs.lib.${system}.deployChecks self.deploy;
|
||||
};
|
||||
}
|
||||
+8
-31
@@ -1,47 +1,20 @@
|
||||
{
|
||||
nix-example = {
|
||||
nix-builder = {
|
||||
system = "x86_64-linux";
|
||||
stateVersion = "26.05";
|
||||
user = "moons";
|
||||
path = ./nix-example;
|
||||
path = ./nix-builder;
|
||||
|
||||
profiles = [
|
||||
"base"
|
||||
"interface.cli"
|
||||
"networking.tailscale-client"
|
||||
"platform.vm"
|
||||
"workload.development"
|
||||
"workload.nix-builder"
|
||||
"workload.remote-access"
|
||||
];
|
||||
};
|
||||
|
||||
ops = {
|
||||
system = "x86_64-linux";
|
||||
stateVersion = "26.05";
|
||||
user = "moons";
|
||||
path = ./ops;
|
||||
|
||||
profiles = [
|
||||
"base"
|
||||
"interface.cli"
|
||||
"platform.vm"
|
||||
"workload.remote-access"
|
||||
];
|
||||
};
|
||||
|
||||
internal-app-01 = {
|
||||
system = "x86_64-linux";
|
||||
stateVersion = "26.05";
|
||||
user = "moons";
|
||||
path = ./internal-app-01;
|
||||
|
||||
profiles = [
|
||||
"base"
|
||||
"interface.cli"
|
||||
"platform.vm"
|
||||
"workload.server"
|
||||
];
|
||||
};
|
||||
|
||||
installer = {
|
||||
system = "x86_64-linux";
|
||||
stateVersion = "26.05";
|
||||
@@ -91,6 +64,7 @@
|
||||
"workload.game"
|
||||
"workload.personal"
|
||||
];
|
||||
|
||||
};
|
||||
|
||||
galleria = {
|
||||
@@ -104,6 +78,7 @@
|
||||
"interface.cli"
|
||||
"interface.labwc"
|
||||
"interface.niri"
|
||||
"networking.tailscale-client"
|
||||
"platform.intel-nvidia-desktop"
|
||||
"security.secrets"
|
||||
"security.secure-boot"
|
||||
@@ -111,7 +86,9 @@
|
||||
"security.fingerprint"
|
||||
"workload.development"
|
||||
"workload.game"
|
||||
"workload.machine-learning"
|
||||
"workload.personal"
|
||||
"workload.camera"
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
...
|
||||
}:
|
||||
{
|
||||
# This desktop is permanently connected to AC power.
|
||||
systemd.user.services.swayidle.Service.Environment = [
|
||||
"SWAYIDLE_ASSUME_AC=1"
|
||||
];
|
||||
|
||||
services.kanshi = {
|
||||
enable = true;
|
||||
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
boot.initrd.luks.devices.cryptroot.device =
|
||||
"/dev/disk/by-partuuid/04295552-cbb8-4511-ac1e-1171ec20f8d1";
|
||||
|
||||
# Keep Windows data and recovery partitions out of UDisks-based file
|
||||
# managers. The shared EFI System Partition stays available as /boot.
|
||||
services.udev.extraRules = ''
|
||||
ENV{ID_PART_ENTRY_UUID}=="0480f887-d1f9-489d-b8fe-78549ced1938", ENV{UDISKS_IGNORE}="1"
|
||||
ENV{ID_PART_ENTRY_UUID}=="6c70041b-3f65-4eb1-8b08-18ed20001877", ENV{UDISKS_IGNORE}="1"
|
||||
'';
|
||||
|
||||
environment.systemPackages = with inputs.browser-previews.packages.${pkgs.system}; [
|
||||
google-chrome-beta
|
||||
];
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIKhxDkucmeCor6CKoXAua7DgDSzuXrZOtpdkyzQxz5+aAAAABHNzaDo= moons@moons14.com"
|
||||
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIN6hZJyng/5LgFKPjR6uZAd/00UkO0vN0uQOoIvfSELdAAAABHNzaDo= moons@moons14.com"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLwReAiwhXoO34S2+MrvqUhi8IWp4IzUq4OSp3niJdq"
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
# nix-builder bootstrap
|
||||
|
||||
The host configuration can be built before its cache signing secret exists.
|
||||
Harmonia's socket remains stopped until SOPS installs the signing key at
|
||||
`/run/secrets/harmonia/signing-key`.
|
||||
|
||||
## Proxmox storage layout
|
||||
|
||||
The host configuration expects three filesystems. Keep the build scratch space
|
||||
separate from the store so a large build cannot fill the root filesystem.
|
||||
|
||||
| Mount point | Suggested size | Contents |
|
||||
| -------------------- | -------------- | ------------------------------- |
|
||||
| `/` | 48 GiB | NixOS and mutable system state |
|
||||
| `/var/lib/nix-build` | 192 GiB | Disposable build scratch space |
|
||||
| `/nix/store` | 1 TiB | Fleet closures and binary cache |
|
||||
|
||||
The build-server policy starts emergency store GC below 64 GiB free and aims
|
||||
for 128 GiB free. Persistent roots under `/var/lib/nix-fleet/roots` protect the
|
||||
latest fleet builds from that GC. It also limits Nix to two concurrent
|
||||
derivations while allowing each derivation to use every vCPU assigned to the
|
||||
VM.
|
||||
|
||||
For the two dedicated ext4 data filesystems, remove the default root-reserved
|
||||
blocks once after formatting; keep the root filesystem's reserve intact:
|
||||
|
||||
```bash
|
||||
sudo tune2fs -m 0 /dev/disk/by-label/nix-build
|
||||
sudo tune2fs -m 0 /dev/disk/by-label/nix-store
|
||||
```
|
||||
|
||||
## Initial deployment
|
||||
|
||||
Once the VM is reachable as `moons@nix-builder`, deploy it from the repository:
|
||||
|
||||
```bash
|
||||
nix run .#deploy -- .#nix-builder
|
||||
```
|
||||
|
||||
deploy-rs uses the target's `ssh-ng` store, so the system closure is built on
|
||||
the builder rather than copied from the laptop. Automatic and magic rollback
|
||||
remain enabled.
|
||||
|
||||
## Add the host SOPS recipient
|
||||
|
||||
After the VM has a stable SSH host key, derive its age recipient:
|
||||
|
||||
```bash
|
||||
ssh-keyscan -t ed25519 nix-builder 2>/dev/null | ssh-to-age
|
||||
```
|
||||
|
||||
Add the recipient to `.sops.yaml` and add a creation rule for
|
||||
`secrets/hosts/nix-builder/*.yaml`. The admin YubiKey recipient should remain in
|
||||
the same key group for recovery.
|
||||
|
||||
## Generate the cache signing key
|
||||
|
||||
Run this on a trusted Nix machine, preferably with the temporary files on a
|
||||
tmpfs:
|
||||
|
||||
```bash
|
||||
nix-store --generate-binary-cache-key \
|
||||
cache.app.homelabs.run-1 \
|
||||
harmonia.private \
|
||||
harmonia.public
|
||||
```
|
||||
|
||||
Create `secrets/hosts/nix-builder/system.yaml` with SOPS and store the complete
|
||||
contents of `harmonia.private` at `harmonia.signing-key`:
|
||||
|
||||
```yaml
|
||||
harmonia:
|
||||
signing-key: cache.app.homelabs.run-1:REDACTED
|
||||
```
|
||||
|
||||
Copy the complete contents of `harmonia.public` to
|
||||
`modules/systems/nix/homelab-cache/public-key`. The private plaintext file must
|
||||
not be committed or retained.
|
||||
|
||||
After committing both encrypted/public files, select
|
||||
`networking.homelab-cache-client` on each client host.
|
||||
|
||||
Redeploy the builder and verify the cache after installing the secret:
|
||||
|
||||
```bash
|
||||
nix run .#deploy -- .#nix-builder
|
||||
curl --fail http://nix-builder:5000/nix-cache-info
|
||||
```
|
||||
|
||||
## Normal operation
|
||||
|
||||
Run `fleet-build` on the builder to build and root every NixOS host, or pass a
|
||||
list of host names to build only those hosts. Run `fleet-deploy` with the normal
|
||||
deploy-rs target syntax when additional fleet nodes have been added to
|
||||
`flake/deploy.nix`:
|
||||
|
||||
```bash
|
||||
fleet-build
|
||||
fleet-build x1g13 galleria
|
||||
fleet-deploy .#nix-builder
|
||||
```
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
fileSystems."/nix/store" = {
|
||||
device = "/dev/disk/by-label/nix-store";
|
||||
fsType = "ext4";
|
||||
|
||||
options = [
|
||||
"noatime"
|
||||
];
|
||||
|
||||
neededForBoot = true;
|
||||
};
|
||||
|
||||
fileSystems."/var/lib/nix-build" = {
|
||||
device = "/dev/disk/by-label/nix-build";
|
||||
fsType = "ext4";
|
||||
|
||||
options = [
|
||||
"noatime"
|
||||
];
|
||||
};
|
||||
|
||||
nix.settings.build-dir = "/var/lib/nix-build";
|
||||
|
||||
services.fstrim.enable = true;
|
||||
}
|
||||
+9
-5
@@ -1,8 +1,12 @@
|
||||
# Do not modify this file! It was generated by `nixos-generate-config` and may
|
||||
# be overwritten by future invocations.
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ lib, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
|
||||
imports = [
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [
|
||||
"ata_piix"
|
||||
@@ -17,12 +21,12 @@
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-uuid/1b12ab98-2537-4207-a3f4-bb8ba7b53b00";
|
||||
device = "/dev/disk/by-uuid/49fc2e1c-7909-41cc-ac78-55b4d9a01e62";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/8365-C778";
|
||||
device = "/dev/disk/by-uuid/40D4-ABBE";
|
||||
fsType = "vfat";
|
||||
options = [
|
||||
"fmask=0077"
|
||||
@@ -0,0 +1,19 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
hostSecrets = ../../secrets/hosts/nix-builder/system.yaml;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./filesystem.nix
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
sops.secrets = lib.mkIf (builtins.pathExists hostSecrets) {
|
||||
"harmonia/signing-key" = {
|
||||
sopsFile = hostSecrets;
|
||||
restartUnits = [ "harmonia.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.interfaces."tailscale0".allowedTCPPorts = [ 5000 ];
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
# Do not modify this file! It was generated by `nixos-generate-config` and may
|
||||
# be overwritten by future invocations.
|
||||
{ lib, modulesPath, ... }:
|
||||
{
|
||||
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
|
||||
|
||||
boot.initrd.availableKernelModules = [
|
||||
"ata_piix"
|
||||
"uhci_hcd"
|
||||
"virtio_pci"
|
||||
"virtio_scsi"
|
||||
"sd_mod"
|
||||
"sr_mod"
|
||||
];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-uuid/69fa2193-1e4f-438a-8898-5de8a3f36e5b";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/D09B-4277";
|
||||
fsType = "vfat";
|
||||
options = [
|
||||
"fmask=0077"
|
||||
"dmask=0077"
|
||||
];
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
networking = {
|
||||
useDHCP = false;
|
||||
|
||||
interfaces = {
|
||||
ens18 = {
|
||||
useDHCP = false;
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "10.50.128.20";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
ens19 = {
|
||||
useDHCP = false;
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "10.50.7.101";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
ens20 = {
|
||||
useDHCP = false;
|
||||
ipv4.routes = [
|
||||
{
|
||||
address = "10.50.64.0";
|
||||
prefixLength = 24;
|
||||
via = "10.50.82.1";
|
||||
}
|
||||
];
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "10.50.82.10";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
defaultGateway = {
|
||||
address = "10.50.128.1";
|
||||
interface = "ens18";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -1,9 +1,37 @@
|
||||
_: {
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
chrome = pkgs.google-chrome.overrideAttrs (old: {
|
||||
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ];
|
||||
|
||||
postFixup = (old.postFixup or "") + ''
|
||||
wrapProgram $out/bin/google-chrome-stable \
|
||||
--set LIBVA_DRIVER_NAME nvidia \
|
||||
--set NVD_BACKEND direct
|
||||
'';
|
||||
});
|
||||
|
||||
features = [
|
||||
"MiddleClickAutoscroll"
|
||||
"AcceleratedVideoDecoder"
|
||||
"AcceleratedVideoDecodeLinuxGL"
|
||||
"PlatformHEVCDecoderSupport"
|
||||
]
|
||||
++ lib.optional config.my.hardwares.nvidia.enable "VaapiOnNvidiaGPUs";
|
||||
in
|
||||
{
|
||||
programs.google-chrome = {
|
||||
enable = true;
|
||||
package = if config.my.hardwares.nvidia.enable then chrome else pkgs.google-chrome;
|
||||
|
||||
commandLineArgs = [
|
||||
"--enable-features=MiddleClickAutoscroll"
|
||||
"--enable-features=${lib.concatStringsSep "," features}"
|
||||
"--use-gl=angle"
|
||||
"--use-angle=gl"
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
_: {
|
||||
description = "Codex Desktop for Linux";
|
||||
|
||||
includes = [ "applications.codex" ];
|
||||
|
||||
imports.nixos = [
|
||||
inputs.codex-desktop-linux.nixosModules.default
|
||||
];
|
||||
}
|
||||
|
||||
@@ -4,15 +4,7 @@
|
||||
...
|
||||
}:
|
||||
{
|
||||
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"
|
||||
];
|
||||
};
|
||||
environment.systemPackages = [
|
||||
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.chatgpt
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
codexSessionUsage = inputs.codex-session-usage.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
||||
in
|
||||
{
|
||||
home.packages = [ codexSessionUsage ];
|
||||
|
||||
xdg.dataFile = {
|
||||
"vicinae/scripts/codex-session-usage/start" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!${lib.getExe pkgs.bash}
|
||||
# @vicinae.schemaVersion 1
|
||||
# @vicinae.title Start Codex Session Usage
|
||||
# @vicinae.description Start the local Codex session usage dashboard
|
||||
# @vicinae.mode compact
|
||||
# @vicinae.icon 📊
|
||||
# @vicinae.argument1 { "type": "text", "placeholder": "Port (optional)", "optional": true }
|
||||
|
||||
if [[ -z "$1" ]]; then
|
||||
exec ${lib.getExe codexSessionUsage} start
|
||||
fi
|
||||
|
||||
if [[ "$1" =~ ^[0-9]+$ ]] && (( 10#$1 >= 1 && 10#$1 <= 65535 )); then
|
||||
exec ${lib.getExe codexSessionUsage} start --port "$1"
|
||||
fi
|
||||
|
||||
printf '%s\n' 'Port must be an integer between 1 and 65535.' >&2
|
||||
exit 2
|
||||
'';
|
||||
};
|
||||
|
||||
"vicinae/scripts/codex-session-usage/stop" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!${lib.getExe pkgs.bash}
|
||||
# @vicinae.schemaVersion 1
|
||||
# @vicinae.title Stop Codex Session Usage
|
||||
# @vicinae.description Stop the local Codex session usage dashboard
|
||||
# @vicinae.mode compact
|
||||
# @vicinae.icon 📊
|
||||
|
||||
exec ${lib.getExe codexSessionUsage} stop
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
model = "gpt-5.6-sol"
|
||||
model_reasoning_effort = "medium"
|
||||
|
||||
approval_policy = "on-request"
|
||||
approvals_reviewer = "auto_review"
|
||||
sandbox_mode = "workspace-write"
|
||||
web_search = "cached"
|
||||
|
||||
[sandbox_workspace_write]
|
||||
network_access = false
|
||||
|
||||
[projects."/home/moons/dotfiles"]
|
||||
trust_level = "trusted"
|
||||
@@ -1,6 +1,36 @@
|
||||
{ inputs, pkgs, ... }:
|
||||
{
|
||||
home.packages = [
|
||||
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex
|
||||
];
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
configDirectory =
|
||||
if config.home.preferXdgDirectories then
|
||||
"${config.xdg.configHome}/codex"
|
||||
else
|
||||
"${config.home.homeDirectory}/.codex";
|
||||
configFile = "${configDirectory}/config.toml";
|
||||
in
|
||||
{
|
||||
programs.codex = {
|
||||
enable = true;
|
||||
package = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex;
|
||||
|
||||
skills = {
|
||||
grilling = inputs.skills + "/skills/productivity/grilling";
|
||||
};
|
||||
};
|
||||
|
||||
# Keep the repository copy as an initial value. Codex may mutate the live
|
||||
# file between activations; each Home Manager switch resets it from here.
|
||||
home.activation.resetCodexConfig = {
|
||||
after = [ "writeBoundary" ];
|
||||
before = [ ];
|
||||
data = ''
|
||||
${pkgs.coreutils}/bin/mkdir -p ${lib.escapeShellArg configDirectory}
|
||||
${pkgs.coreutils}/bin/install -m 0600 ${./config.toml} ${lib.escapeShellArg configFile}
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
_: {
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.stdenv.hostPlatform.system};
|
||||
in
|
||||
{
|
||||
programs.vesktop = {
|
||||
enable = true;
|
||||
package = unstable.vesktop;
|
||||
|
||||
settings = {
|
||||
discordBranch = "stable";
|
||||
@@ -16,6 +25,10 @@ _: {
|
||||
|
||||
openLinksWithElectron = false;
|
||||
|
||||
# Keep WebRTC on the public interface selected by the default route.
|
||||
# Secondary private interfaces can otherwise stall voice at DTLS.
|
||||
webRTCIPHandlingPolicy = "default_public_interface_only";
|
||||
|
||||
spellCheckLanguages = [
|
||||
"ja-JP"
|
||||
"en-US"
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
{ pkgs, ... }:
|
||||
{ inputs, pkgs, ... }:
|
||||
{
|
||||
|
||||
services.hazkey.enable = true;
|
||||
services.hazkey = {
|
||||
enable = true;
|
||||
server.package =
|
||||
inputs.nix-hazkey.packages.${pkgs.stdenv.hostPlatform.system}.hazkey-server.override
|
||||
{ enableVulkan = true; };
|
||||
};
|
||||
|
||||
i18n.inputMethod = {
|
||||
enable = true;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = [ pkgs.ffmpeg ];
|
||||
}
|
||||
@@ -6,6 +6,7 @@ _: {
|
||||
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";
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
{ inputs, system, ... }: {
|
||||
programs.ghostty = {
|
||||
systemd.enable = true;
|
||||
# Labwc's Close action correctly targets one xdg-toplevel, but Ghostty's
|
||||
# systemd service runs every window in one GTK single-instance process.
|
||||
# If that process exits while handling the request, every Ghostty window
|
||||
# disappears together. Keep each launcher invocation independent instead.
|
||||
systemd.enable = false;
|
||||
package = inputs.ghostty.packages.${system}.default;
|
||||
|
||||
settings.gtk-single-instance = false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = [ pkgs.python314Packages.huggingface-hub ];
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
screenshot = import ./screenshot.nix { inherit pkgs; };
|
||||
|
||||
systemctl = lib.getExe' pkgs.systemd "systemctl";
|
||||
|
||||
keybind = key: actionAttrs: {
|
||||
@@ -62,8 +60,6 @@ let
|
||||
};
|
||||
in
|
||||
{
|
||||
home.packages = [ screenshot ];
|
||||
|
||||
wayland.windowManager.labwc = {
|
||||
enable = true;
|
||||
# NixOS owns the package so Home Manager only generates the user config.
|
||||
@@ -106,8 +102,6 @@ in
|
||||
(action "W-q" "Close")
|
||||
(action "W-f" "ToggleMaximize")
|
||||
(action "W-c" "Iconify")
|
||||
(action "W-Tab" "NextWindow")
|
||||
(action "W-S-Tab" "PreviousWindow")
|
||||
(action "W-Up" "Lower")
|
||||
(action "W-Down" "Raise")
|
||||
(action "W-Left" "NextWindow")
|
||||
@@ -117,9 +111,9 @@ in
|
||||
(snapToEdge "W-C-Up" "up")
|
||||
(snapToEdge "W-C-Down" "down")
|
||||
(confirmAction "W-S-e" "Exit labwc?" "Exit")
|
||||
(execute "Print" "labwc-screenshot region")
|
||||
(execute "C-Print" "labwc-screenshot output")
|
||||
(execute "A-Print" "labwc-screenshot all")
|
||||
(execute "Print" "screenshot region")
|
||||
(execute "C-Print" "screenshot output")
|
||||
(execute "A-Print" "screenshot all")
|
||||
|
||||
# spawn applications (sync with niri modules/applications/niri/home.nix)
|
||||
(execute "W-t" "ghostty")
|
||||
@@ -127,9 +121,13 @@ in
|
||||
(execute "W-s" "noctalia msg panel-toggle launcher")
|
||||
(execute "W-e" "nautilus --new-window")
|
||||
(execute "W-l" "loginctl lock-session")
|
||||
(execute "W-v" "vicinae vicinae://launch/clipboard/history?toggle=true")
|
||||
(execute "W-v" "vicinae vicinae://launch/clipboard/history")
|
||||
(execute "W-j" "nani-translate-primary")
|
||||
(execute "W-S-j" "nani-translate-ocr")
|
||||
(execute "W-C-j" "${lib.getExe' pkgs.xdg-utils "xdg-open"} naniapp://translate")
|
||||
(execute "W-space" "ghostty +toggle-quick-terminal")
|
||||
(execute "W-p" "wdisplays")
|
||||
(execute "W-z" "wl-find-cursor -c 0xCCFF453A -s 160 -d 1200")
|
||||
|
||||
# Function keys (sync with niri modules/applications/niri/home.nix)
|
||||
(execute "XF86AudioRaiseVolume" "noctalia msg volume-up")
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
{
|
||||
description = "labwc Wayland stacking compositor";
|
||||
|
||||
includes = [ "systems.wayland" ];
|
||||
includes = [
|
||||
"systems.wayland"
|
||||
"applications.screenshot"
|
||||
"applications.wl-find-cursor"
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
{
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.stdenv.hostPlatform.system};
|
||||
in
|
||||
{
|
||||
programs.labwc = {
|
||||
enable = true;
|
||||
package = unstable.labwc;
|
||||
};
|
||||
|
||||
xdg.portal.config.labwc.default = [
|
||||
"wlr"
|
||||
"gtk"
|
||||
];
|
||||
|
||||
# xdg-desktop-portal-wlr implements screencasting for wlroots compositors.
|
||||
# Keep it with Labwc: Niri uses xdg-desktop-portal-gnome instead.
|
||||
xdg.portal.wlr = {
|
||||
enable = true;
|
||||
settings.screencast = {
|
||||
chooser_type = "dmenu";
|
||||
chooser_cmd = "${pkgs.fuzzel}/bin/fuzzel --dmenu";
|
||||
};
|
||||
};
|
||||
|
||||
# NixOS decides whether a graphical session manages graphical-session.target
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
{ pkgs }:
|
||||
|
||||
pkgs.writeShellApplication {
|
||||
name = "labwc-screenshot";
|
||||
|
||||
runtimeInputs = with pkgs; [
|
||||
coreutils
|
||||
grim
|
||||
slurp
|
||||
wl-clipboard
|
||||
xdg-user-dirs
|
||||
];
|
||||
|
||||
text = ''
|
||||
mode="''${1:-region}"
|
||||
|
||||
pictures_dir="$(xdg-user-dir PICTURES)"
|
||||
if [[ -z "$pictures_dir" ]]; then
|
||||
pictures_dir="$HOME/Pictures"
|
||||
fi
|
||||
|
||||
output_dir="$pictures_dir/Screenshots"
|
||||
output_file="$output_dir/Screenshot from $(date '+%Y-%m-%d %H-%M-%S').png"
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
|
||||
case "$mode" in
|
||||
region)
|
||||
geometry="$(slurp)" || exit 0
|
||||
grim -g "$geometry" "$output_file"
|
||||
;;
|
||||
|
||||
output)
|
||||
geometry="$(slurp -o)" || exit 0
|
||||
grim -g "$geometry" "$output_file"
|
||||
;;
|
||||
|
||||
all)
|
||||
grim "$output_file"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown screenshot mode: $mode" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
wl-copy --type image/png < "$output_file"
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
homebrew = {
|
||||
enable = true;
|
||||
casks = [ "nani" ];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
tessdataBest = pkgs.runCommand "tessdata-best-jpn-eng-chi-sim" { } ''
|
||||
mkdir -p "$out"
|
||||
ln -s ${
|
||||
pkgs.fetchurl {
|
||||
url = "https://github.com/tesseract-ocr/tessdata_best/raw/main/jpn.traineddata";
|
||||
hash = "sha256-Nr35rII/WRHmJMMNBVPokLirx8MaZbPvFNqUNljEC3k=";
|
||||
}
|
||||
} "$out/jpn.traineddata"
|
||||
ln -s ${
|
||||
pkgs.fetchurl {
|
||||
url = "https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata";
|
||||
hash = "sha256-goCu0Hgv4nJXpo6hD+fvMkyg+Nhb0v0UXRwrVgvLZro=";
|
||||
}
|
||||
} "$out/eng.traineddata"
|
||||
ln -s ${
|
||||
pkgs.fetchurl {
|
||||
url = "https://github.com/tesseract-ocr/tessdata_best/raw/main/chi_sim.traineddata";
|
||||
hash = "sha256-T+8tEwbI6HYW1NPkxsZ/r11EvjNCKQz48vD246p+c1s=";
|
||||
}
|
||||
} "$out/chi_sim.traineddata"
|
||||
'';
|
||||
|
||||
tesseract = pkgs.tesseract5.override {
|
||||
tessdata = tessdataBest;
|
||||
};
|
||||
|
||||
naniTranslatePrimary = pkgs.writeShellApplication {
|
||||
name = "nani-translate-primary";
|
||||
|
||||
runtimeInputs = with pkgs; [
|
||||
jq
|
||||
wl-clipboard
|
||||
xdg-utils
|
||||
];
|
||||
|
||||
text = ''
|
||||
selected_text="$(wl-paste --primary --no-newline)" || exit 0
|
||||
[ -n "$selected_text" ] || exit 0
|
||||
encoded_text="$(printf '%s' "$selected_text" | jq -sRr @uri)"
|
||||
exec xdg-open "naniapp://translate?source=$encoded_text"
|
||||
'';
|
||||
};
|
||||
|
||||
naniTranslateOcr = pkgs.writeShellApplication {
|
||||
name = "nani-translate-ocr";
|
||||
|
||||
runtimeInputs = with pkgs; [
|
||||
grim
|
||||
jq
|
||||
slurp
|
||||
tesseract
|
||||
xdg-utils
|
||||
];
|
||||
|
||||
text = ''
|
||||
geometry="$(slurp)" || exit 0
|
||||
captured_text="$(
|
||||
grim -g "$geometry" - \
|
||||
| tesseract stdin stdout -l jpn+eng+chi_sim --oem 1 --psm 6
|
||||
)"
|
||||
[ -n "$captured_text" ] || exit 0
|
||||
encoded_text="$(printf '%s' "$captured_text" | jq -sRr @uri)"
|
||||
exec xdg-open "naniapp://translate?source=$encoded_text"
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
programs.naniTranslateLinux.enable = true;
|
||||
|
||||
xdg.mimeApps.defaultApplications."x-scheme-handler/naniapp" = "nani.desktop";
|
||||
|
||||
home.packages = [
|
||||
naniTranslatePrimary
|
||||
naniTranslateOcr
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
description = "Nani Translate application";
|
||||
|
||||
imports.home = [
|
||||
inputs.nani-translate-linux.homeManagerModules.default
|
||||
];
|
||||
}
|
||||
@@ -25,6 +25,7 @@ in
|
||||
systemd.user.sessionVariables.NAUTILUS_4_EXTENSION_DIR = nautilusExtensionDir;
|
||||
|
||||
xdg.dataFile."nautilus-python/extensions/open-in-editor.py".text = ''
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from gi.repository import GObject, Nautilus
|
||||
@@ -75,6 +76,12 @@ in
|
||||
|
||||
return paths
|
||||
|
||||
@staticmethod
|
||||
def get_working_directory(paths):
|
||||
path = paths[0]
|
||||
|
||||
return path if os.path.isdir(path) else os.path.dirname(path)
|
||||
|
||||
@staticmethod
|
||||
def launch(_item, command):
|
||||
subprocess.Popen(
|
||||
@@ -101,6 +108,22 @@ in
|
||||
|
||||
items.append(item)
|
||||
|
||||
item = Nautilus.MenuItem(
|
||||
name=f"OpenInEditor::{context}::ghostty",
|
||||
label="Ghostty で開く",
|
||||
)
|
||||
|
||||
item.connect(
|
||||
"activate",
|
||||
self.launch,
|
||||
[
|
||||
"${lib.getExe pkgs.ghostty}",
|
||||
f"--working-directory={self.get_working_directory(paths)}",
|
||||
],
|
||||
)
|
||||
|
||||
items.append(item)
|
||||
|
||||
return items
|
||||
|
||||
def get_file_items(self, files):
|
||||
@@ -139,14 +162,6 @@ in
|
||||
"file://${config.home.homeDirectory}/Desktop Desktop"
|
||||
"file://${config.home.homeDirectory}/Pictures Pictures"
|
||||
"file://${config.home.homeDirectory}/Downloads Downloads"
|
||||
"file://${config.home.homeDirectory}/projects projects"
|
||||
"file://${config.home.homeDirectory}/Projects Projects"
|
||||
];
|
||||
|
||||
home.activation.createProjectsDirectory = {
|
||||
after = [ "writeBoundary" ];
|
||||
before = [ ];
|
||||
data = ''
|
||||
$DRY_RUN_CMD mkdir -p "$HOME/projects"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,4 +5,38 @@
|
||||
NH_FLAKE = "${config.home.homeDirectory}/dotfiles";
|
||||
NH_SHOW_ACTIVATION_LOGS = "1";
|
||||
};
|
||||
|
||||
programs.zsh.initContent = ''
|
||||
export SUDO_PROMPT=$'\a[sudo] authenticate for %u: '
|
||||
|
||||
nh() {
|
||||
local notify=false
|
||||
local argument
|
||||
|
||||
case "$1:$2" in
|
||||
os:switch | os:build) notify=true ;;
|
||||
esac
|
||||
|
||||
for argument in "$@"; do
|
||||
if [[ "$argument" == "--update" ]]; then
|
||||
notify=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
command nh "$@"
|
||||
local status=$?
|
||||
|
||||
if [[ "$notify" == true ]]; then
|
||||
printf '\a'
|
||||
if ((status == 0)); then
|
||||
print -P "%F{green}nh completed%f"
|
||||
else
|
||||
print -P "%F{red}nh failed (exit $status)%f"
|
||||
fi
|
||||
fi
|
||||
|
||||
return "$status"
|
||||
}
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# niri のデフォルトキーバインド。編集しないこと。
|
||||
{
|
||||
"Mod+Shift+Slash".action.show-hotkey-overlay = { };
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ in
|
||||
|
||||
binds = keybindings // {
|
||||
# niri window or focus move
|
||||
"Mod+MouseMiddle".action.toggle-window-floating = [ ];
|
||||
|
||||
"Mod+Shift+Left" = {
|
||||
action.focus-monitor-left = [ ];
|
||||
hotkey-overlay.title = "Focus Monitor Left";
|
||||
@@ -24,6 +26,18 @@ in
|
||||
hotkey-overlay.title = "Focus Monitor Down";
|
||||
};
|
||||
|
||||
# Use the modifier combinations in the opposite direction from Niri's defaults.
|
||||
"Mod+WheelScrollDown".action.focus-column-right = [ ];
|
||||
"Mod+WheelScrollUp".action.focus-column-left = [ ];
|
||||
"Mod+Shift+WheelScrollDown" = {
|
||||
cooldown-ms = 150;
|
||||
action.focus-workspace-down = [ ];
|
||||
};
|
||||
"Mod+Shift+WheelScrollUp" = {
|
||||
cooldown-ms = 150;
|
||||
action.focus-workspace-up = [ ];
|
||||
};
|
||||
|
||||
"Mod+Shift+Ctrl+Left" = {
|
||||
action.move-window-to-monitor-left = [ ];
|
||||
hotkey-overlay.title = "Move Window to Monitor Left";
|
||||
@@ -41,6 +55,19 @@ in
|
||||
hotkey-overlay.title = "Move Window to Monitor Down";
|
||||
};
|
||||
|
||||
"Print".action.spawn = [
|
||||
"screenshot"
|
||||
"region"
|
||||
];
|
||||
"Ctrl+Print".action.spawn = [
|
||||
"screenshot"
|
||||
"output"
|
||||
];
|
||||
"Alt+Print".action.spawn = [
|
||||
"screenshot"
|
||||
"all"
|
||||
];
|
||||
|
||||
# spawn applications (sync with labwc modules/applications/labwc/home.nix)
|
||||
"Mod+T" = {
|
||||
action.spawn = "ghostty";
|
||||
@@ -79,10 +106,28 @@ in
|
||||
"Mod+V" = {
|
||||
action.spawn = [
|
||||
"vicinae"
|
||||
"vicinae://launch/clipboard/history?toggle=true"
|
||||
"vicinae://launch/clipboard/history"
|
||||
];
|
||||
hotkey-overlay.title = "Clipboard History";
|
||||
};
|
||||
"Mod+J" = {
|
||||
repeat = false;
|
||||
action.spawn = [ "nani-translate-primary" ];
|
||||
hotkey-overlay.title = "Translate Primary Selection";
|
||||
};
|
||||
"Mod+Shift+J" = {
|
||||
repeat = false;
|
||||
action.spawn = [ "nani-translate-ocr" ];
|
||||
hotkey-overlay.title = "OCR and Translate with Nani";
|
||||
};
|
||||
"Mod+Ctrl+J" = {
|
||||
repeat = false;
|
||||
action.spawn = [
|
||||
(lib.getExe' pkgs.xdg-utils "xdg-open")
|
||||
"naniapp://translate"
|
||||
];
|
||||
hotkey-overlay.title = "Open Nani Translate";
|
||||
};
|
||||
"Mod+Space" = {
|
||||
action.spawn = [
|
||||
"ghostty"
|
||||
@@ -94,6 +139,18 @@ in
|
||||
action.spawn = "wdisplays";
|
||||
hotkey-overlay.title = "Display Settings: wdisplays";
|
||||
};
|
||||
"Mod+Z" = {
|
||||
action.spawn = [
|
||||
"wl-find-cursor"
|
||||
"-c"
|
||||
"0xCCFF453A"
|
||||
"-s"
|
||||
"160"
|
||||
"-d"
|
||||
"1200"
|
||||
];
|
||||
hotkey-overlay.title = "Find Cursor";
|
||||
};
|
||||
|
||||
# Function keys (sync with labwc modules/applications/labwc/home.nix)
|
||||
"XF86AudioRaiseVolume".action.spawn = [
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
{
|
||||
description = "niri Wayland compositor";
|
||||
|
||||
includes = [ "systems.wayland" ];
|
||||
includes = [
|
||||
"systems.wayland"
|
||||
"applications.screenshot"
|
||||
"applications.wl-find-cursor"
|
||||
];
|
||||
|
||||
imports = {
|
||||
nixos = [
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
description = "Fleet build and deploy command-line tools";
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
primaryUser,
|
||||
...
|
||||
}:
|
||||
let
|
||||
system = pkgs.stdenv.hostPlatform.system;
|
||||
deployRs = inputs.deploy-rs.packages.${system}.default;
|
||||
|
||||
fleetBuild = pkgs.writeShellApplication {
|
||||
name = "fleet-build";
|
||||
runtimeInputs = [
|
||||
pkgs.jq
|
||||
pkgs.nix
|
||||
];
|
||||
text = ''
|
||||
flake_ref="''${FLAKE:-/home/${primaryUser}/dotfiles}"
|
||||
|
||||
if (( $# == 0 )); then
|
||||
# Keep this pipeline inside command substitution so pipefail and
|
||||
# writeShellApplication's errexit propagate evaluation failures.
|
||||
host_lines="$(
|
||||
nix eval --json "$flake_ref#nixosConfigurations" \
|
||||
--apply 'configs: builtins.attrNames configs' |
|
||||
jq -r '.[] | select(. != "installer")'
|
||||
)"
|
||||
if [[ -z "$host_lines" ]]; then
|
||||
echo "No deployable NixOS hosts found in $flake_ref" >&2
|
||||
exit 1
|
||||
fi
|
||||
mapfile -t hosts <<< "$host_lines"
|
||||
else
|
||||
hosts=("$@")
|
||||
fi
|
||||
|
||||
for host in "''${hosts[@]}"; do
|
||||
nix build \
|
||||
--out-link "/var/lib/nix-fleet/roots/build/$host" \
|
||||
"$flake_ref#nixosConfigurations.$host.config.system.build.toplevel"
|
||||
done
|
||||
'';
|
||||
};
|
||||
|
||||
fleetDeploy = pkgs.writeShellApplication {
|
||||
name = "fleet-deploy";
|
||||
runtimeInputs = [ deployRs ];
|
||||
text = ''
|
||||
cd "''${FLAKE:-/home/${primaryUser}/dotfiles}" || exit 1
|
||||
|
||||
exec deploy \
|
||||
--keep-result \
|
||||
--result-path /var/lib/nix-fleet/roots/deploy \
|
||||
"$@"
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
environment.systemPackages = [
|
||||
fleetBuild
|
||||
fleetDeploy
|
||||
];
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, pkgs }:
|
||||
let
|
||||
version = "0.46.0";
|
||||
version = "0.56.0";
|
||||
architecture =
|
||||
if pkgs.stdenv.hostPlatform.isx86_64 then
|
||||
"x86_64"
|
||||
@@ -10,8 +10,8 @@ let
|
||||
throw "CodexBar CLI is only packaged for x86_64-linux and aarch64-linux";
|
||||
hash =
|
||||
{
|
||||
x86_64 = "sha256-yMrOpu1WIv2sGVgvY9qf2XCoX2AXMSqR2b8bQDRU6os=";
|
||||
aarch64 = "sha256-pCp3NOlxFN6zeH67W04WGSPbUae+ktzR5vEunWqu00g=";
|
||||
x86_64 = "sha256-hzCnAyiizm8ZDfE1ONEP6S2Pdnskclm+XdDBBhEYVqE=";
|
||||
aarch64 = "sha256-vfcgDEFpORPymcRYmlqvsjhV4pU7lNC8Vd9FDPI9UjM=";
|
||||
}
|
||||
.${architecture};
|
||||
in
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
@@ -41,6 +42,8 @@ in
|
||||
programs.noctalia = {
|
||||
enable = true;
|
||||
|
||||
package = inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
||||
|
||||
systemd.enable = true;
|
||||
|
||||
settings = {
|
||||
@@ -154,7 +157,7 @@ in
|
||||
network-connection = {
|
||||
type = "custom_button";
|
||||
glyph = "access-point";
|
||||
actions.left = "nm-connection-editor";
|
||||
actions.left = "exec nm-connection-editor";
|
||||
};
|
||||
tray = {
|
||||
type = "tray";
|
||||
@@ -171,10 +174,11 @@ in
|
||||
"org.gnome.Nautilus"
|
||||
"org.gnome.TextEditor"
|
||||
"com.mitchellh.ghostty"
|
||||
"thunderbird"
|
||||
"google-chrome"
|
||||
"code"
|
||||
"dev.zed.Zed"
|
||||
"codex-desktop.desktop"
|
||||
"chatgpt"
|
||||
"vesktop"
|
||||
];
|
||||
show_all_outputs = true;
|
||||
@@ -193,7 +197,7 @@ in
|
||||
};
|
||||
|
||||
wallpaper = {
|
||||
enabled = true;
|
||||
enabled = lib.mkDefault true;
|
||||
directory = "~/.wallpapers";
|
||||
fill_mode = "crop";
|
||||
automation = {
|
||||
|
||||
@@ -2,5 +2,19 @@
|
||||
{
|
||||
home.packages = [
|
||||
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.opencode
|
||||
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.oh-my-opencode
|
||||
];
|
||||
|
||||
home.file.".omo/omo.jsonc".text = builtins.toJSON {
|
||||
agents = {
|
||||
sisyphus.model = "openai/gpt-5.6-sol";
|
||||
hephaestus.model = "openai/gpt-5.6-terra";
|
||||
prometheus.model = "openai/gpt-5.6-terra";
|
||||
oracle.model = "openai/gpt-5.6-terra";
|
||||
momus.model = "openai/gpt-5.6-terra";
|
||||
librarian.model = "openai/gpt-5.6-luna";
|
||||
explore.model = "openai/gpt-5.6-luna";
|
||||
atlas.model = "openai/gpt-5.6-luna";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "screenshot";
|
||||
|
||||
runtimeInputs = with pkgs; [
|
||||
coreutils
|
||||
grim
|
||||
slurp
|
||||
wl-clipboard
|
||||
xdg-user-dirs
|
||||
];
|
||||
|
||||
text = ''
|
||||
mode="''${1:-region}"
|
||||
|
||||
pictures_dir="$(xdg-user-dir PICTURES)"
|
||||
if [[ -z "$pictures_dir" ]]; then
|
||||
pictures_dir="$HOME/Pictures"
|
||||
fi
|
||||
|
||||
output_dir="$pictures_dir/Screenshots"
|
||||
output_file="$output_dir/Screenshot from $(date '+%Y-%m-%d %H-%M-%S').png"
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
|
||||
case "$mode" in
|
||||
region)
|
||||
geometry="$(slurp)" || exit 0
|
||||
grim -g "$geometry" "$output_file"
|
||||
;;
|
||||
|
||||
output)
|
||||
geometry="$(slurp -o)" || exit 0
|
||||
grim -g "$geometry" "$output_file"
|
||||
;;
|
||||
|
||||
all)
|
||||
grim "$output_file"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown screenshot mode: $mode" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
wl-copy --type image/png < "$output_file"
|
||||
'';
|
||||
})
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
description = "Wayland screenshot command";
|
||||
}
|
||||
@@ -24,6 +24,9 @@ lib.mkMerge [
|
||||
};
|
||||
|
||||
extraConfig = ''
|
||||
Match exec "test -n \"$SSH_AUTH_SOCK\" && test -S \"$SSH_AUTH_SOCK\""
|
||||
IdentityAgent $SSH_AUTH_SOCK
|
||||
|
||||
Match exec "test -S %d/.1password/agent.sock"
|
||||
IdentityAgent %d/.1password/agent.sock
|
||||
'';
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
programs.thunderbird = {
|
||||
enable = true;
|
||||
package = pkgs.thunderbird;
|
||||
|
||||
languagePacks = [ "ja" ];
|
||||
|
||||
policies = {
|
||||
DisableTelemetry = true;
|
||||
DisableAppUpdate = true;
|
||||
InAppNotification_Disabled = true;
|
||||
};
|
||||
|
||||
settings = {
|
||||
"mailnews.start_page.enabled" = false;
|
||||
"mail.shell.checkDefaultClient" = false;
|
||||
};
|
||||
|
||||
profiles.default = {
|
||||
isDefault = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
_: {
|
||||
xdg.mimeApps = {
|
||||
enable = true;
|
||||
|
||||
defaultApplications = {
|
||||
"x-scheme-handler/mailto" = "thunderbird.desktop";
|
||||
"message/rfc822" = "thunderbird.desktop";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -10,6 +10,8 @@ in
|
||||
programs.vicinae = {
|
||||
enable = true;
|
||||
|
||||
enableChromeIntegration = false;
|
||||
|
||||
settings = {
|
||||
font.size = 11;
|
||||
close_on_focus_loss = true;
|
||||
|
||||
@@ -8,9 +8,6 @@ let
|
||||
in
|
||||
{
|
||||
programs.vicinae = {
|
||||
|
||||
package = pkgs.vicinae;
|
||||
|
||||
systemd = {
|
||||
enable = true;
|
||||
autoStart = true;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{ inputs, pkgs, ... }:
|
||||
let
|
||||
unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.stdenv.hostPlatform.system};
|
||||
in
|
||||
{
|
||||
home.packages = [ unstable.wl-find-cursor ];
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
description = "Wayland cursor locator";
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
homebrew = {
|
||||
enable = true;
|
||||
masApps = {
|
||||
Xcode = 497799835;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = [ pkgs.yt-dlp ];
|
||||
}
|
||||
@@ -4,8 +4,11 @@
|
||||
extensions = [
|
||||
"catppuccin"
|
||||
"nix"
|
||||
"dockerfile"
|
||||
];
|
||||
mutableUserSettings = false;
|
||||
mutableUserKeymaps = false;
|
||||
userKeymaps = import ./keymaps.nix;
|
||||
|
||||
userSettings = {
|
||||
agent = {
|
||||
@@ -36,6 +39,9 @@
|
||||
light = "Catppuccin Latte";
|
||||
dark = "Catppuccin Mocha";
|
||||
};
|
||||
edit_predictions = {
|
||||
provider = "copilot";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
context = "Editor && vim_mode == normal";
|
||||
bindings = {
|
||||
# This selected native-equivalent subset preserves Zed's Vim defaults for
|
||||
# K, gd, grr, gri, gra, gO, ]d, [d, zM, zR, [b, and ]b.
|
||||
"g r t" = "editor::GoToTypeDefinition";
|
||||
"space space" = "pane::AlternateFile";
|
||||
"space r n" = "editor::Rename";
|
||||
"space c a" = "editor::ToggleCodeActions";
|
||||
"space c f" = "editor::Format";
|
||||
"space d l" = "editor::Hover";
|
||||
"space e" = "project_panel::Toggle";
|
||||
"space t t" = "terminal_panel::Toggle";
|
||||
"space b c" = "pane::CloseActiveItem";
|
||||
"space f f" = "file_finder::Toggle";
|
||||
"space f g" = "pane::DeploySearch";
|
||||
"space f b" = "tab_switcher::ToggleAll";
|
||||
"space f s" = "outline::Toggle";
|
||||
"space f shift-s" = "project_symbols::Toggle";
|
||||
"space x x" = "diagnostics::Deploy";
|
||||
};
|
||||
}
|
||||
{
|
||||
# Keep normal-mode editor navigation out of terminals and other panels.
|
||||
context = "Editor && vim_mode == normal && !menu";
|
||||
bindings = {
|
||||
"ctrl-h" = "workspace::ActivatePaneLeft";
|
||||
"ctrl-j" = "workspace::ActivatePaneDown";
|
||||
"ctrl-k" = "workspace::ActivatePaneUp";
|
||||
"ctrl-l" = "workspace::ActivatePaneRight";
|
||||
"ctrl-left" = "workspace::ActivatePaneLeft";
|
||||
"ctrl-down" = "workspace::ActivatePaneDown";
|
||||
"ctrl-up" = "workspace::ActivatePaneUp";
|
||||
"ctrl-right" = "workspace::ActivatePaneRight";
|
||||
};
|
||||
}
|
||||
]
|
||||
@@ -5,10 +5,7 @@
|
||||
modesetting.enable = true;
|
||||
open = true;
|
||||
|
||||
powerManagement = {
|
||||
enable = true;
|
||||
kernelSuspendNotifier = true;
|
||||
};
|
||||
powerManagement.enable = true;
|
||||
|
||||
moduleParams.nvidia.NVreg_TemporaryFilePath = "/var/tmp";
|
||||
|
||||
|
||||
@@ -38,9 +38,13 @@ required on every supported host.
|
||||
| `platform.vm` | UEFI QEMU NixOS guest with NFS client support |
|
||||
| `workload.development` | NixOS, macOS with Home Manager |
|
||||
| `workload.game` | NixOS, macOS |
|
||||
| `workload.machine-learning` | NixOS with Home Manager |
|
||||
| `workload.nix-builder` | NixOS central build and binary-cache VM |
|
||||
| `workload.personal` | NixOS, macOS with Home Manager |
|
||||
| `workload.remote-access` | NixOS, macOS |
|
||||
| `workload.camera` | NixOS |
|
||||
| `workload.server` | NixOS, macOS with Home Manager |
|
||||
| `networking.homelab-cache-client` | NixOS, macOS with access to nix-builder |
|
||||
| `networking.tailscale-client` | NixOS, macOS |
|
||||
| `networking.tailscale-subnet-router` | NixOS |
|
||||
| `security.fingerprint` | NixOS, macOS |
|
||||
@@ -58,11 +62,26 @@ selects labwc. A daily-use macOS development machine can combine
|
||||
`interface.macos`, `workload.development`, and `workload.personal`. Hardware
|
||||
support does not implicitly select an interface or workload.
|
||||
|
||||
`workload.machine-learning` provides the Hugging Face Hub CLI for hosts used
|
||||
to download and publish machine learning models and datasets.
|
||||
|
||||
`workload.nix-builder` provides the central build policy, persistent fleet GC
|
||||
roots, deploy-rs tooling, SOPS integration, and Harmonia binary cache. Network
|
||||
reachability and remote shell access remain independent host selections.
|
||||
|
||||
`networking.homelab-cache-client` adds the internal Harmonia substituter and
|
||||
its trusted public key. It requires the public key generated during
|
||||
`hosts/nix-builder/README.md` bootstrap.
|
||||
|
||||
`workload.personal` provides Pear Desktop on both NixOS and macOS. Home Manager
|
||||
enables performance improvements, synced lyrics, tracker blocking, the album
|
||||
color theme, and custom output-device selection while preserving user-owned
|
||||
settings such as the selected device.
|
||||
|
||||
`workload.personal` provides ActivityWatch for local activity tracking. On
|
||||
NixOS, its server and Wayland-compatible watcher run as Home Manager user
|
||||
services. On macOS, the Homebrew cask starts at login.
|
||||
|
||||
On NixOS, `workload.game` provides Steam with Valve Proton and Proton-GE,
|
||||
Protontricks, Wayland-compatible Steam Input, GameMode, Gamescope, and MangoHud.
|
||||
Enabling Steam also activates the 32-bit graphics and PipeWire support required
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
alacritty
|
||||
grim
|
||||
slurp
|
||||
wf-recorder
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
{ pkgs, ... }: {
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = [
|
||||
pkgs.playerctl
|
||||
];
|
||||
|
||||
xdg.userDirs = {
|
||||
enable = true;
|
||||
createDirectories = true;
|
||||
@@ -13,5 +15,6 @@
|
||||
publicShare = "$HOME/Public";
|
||||
templates = "$HOME/Templates";
|
||||
videos = "$HOME/Videos";
|
||||
projects = "$HOME/Projects";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
"applications.gtk"
|
||||
"applications.loupe"
|
||||
"applications.nautilus"
|
||||
"applications.nani"
|
||||
"applications.papers"
|
||||
"applications.qalculate-gtk"
|
||||
"applications.resources"
|
||||
"applications.vlc"
|
||||
"hardwares.graphics"
|
||||
"services.gvfs"
|
||||
"services.evremap"
|
||||
"services.polkit-gnome"
|
||||
"systems.audio"
|
||||
"systems.fonts"
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
alacritty
|
||||
grim
|
||||
slurp
|
||||
wf-recorder
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
description = "Use the homelab Harmonia binary cache";
|
||||
|
||||
includes = [ "systems.nix.homelab-cache" ];
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
# every system sleep path; screen blanking while locked is handled by
|
||||
# services.swayidle in the graphical session.
|
||||
systemd.sleep.settings.Sleep = {
|
||||
AllowSuspend = true;
|
||||
AllowHibernation = false;
|
||||
AllowHybridSleep = false;
|
||||
AllowSuspendThenHibernate = false;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
sops.secrets."users/moons/hashedPassword" = {
|
||||
sopsFile = ../../../secrets/common/system.yaml;
|
||||
neededForUsers = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
description = "Camera capture and virtual camera tools";
|
||||
|
||||
includes = [ "systems.boot.v4l2loopback" ];
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
gphoto2
|
||||
ffmpeg
|
||||
v4l-utils
|
||||
];
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
bind
|
||||
bun
|
||||
nil
|
||||
python312
|
||||
python314
|
||||
uv
|
||||
];
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"applications.claude"
|
||||
"applications.codex"
|
||||
"applications.codex-desktop"
|
||||
"applications.codex-session-usage"
|
||||
"applications.docker"
|
||||
"applications.drawio"
|
||||
"applications.ghostty"
|
||||
@@ -13,6 +14,7 @@
|
||||
"applications.java"
|
||||
"applications.opencode"
|
||||
"applications.vscode"
|
||||
"applications.xcode"
|
||||
"applications.zed"
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
description = "Machine learning tools";
|
||||
|
||||
includes = [ "applications.huggingface-cli" ];
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
description = "Central Nix builder, deploy controller, and binary cache";
|
||||
|
||||
includes = [
|
||||
"applications.nix-fleet"
|
||||
"services.harmonia"
|
||||
"systems.nix.build-server"
|
||||
"systems.sops"
|
||||
];
|
||||
}
|
||||
@@ -3,13 +3,18 @@
|
||||
|
||||
includes = [
|
||||
"applications.1password"
|
||||
"applications.activitywatch"
|
||||
"applications.chrome"
|
||||
"applications.discord"
|
||||
"applications.ffmpeg"
|
||||
"applications.gnome-text-editor"
|
||||
"applications.kde"
|
||||
"applications.moonlight"
|
||||
"applications.slack"
|
||||
"applications.zoom"
|
||||
"applications.obs"
|
||||
"applications.nani"
|
||||
"applications.thunderbird"
|
||||
"applications.yt-dlp"
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
services.evremap = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
device_name = "VXE VXE Mouse 1K Dongle Mouse";
|
||||
|
||||
remap = [
|
||||
{
|
||||
input = [ "BTN_SIDE" ];
|
||||
output = [ "KEY_LEFTMETA" ];
|
||||
}
|
||||
{
|
||||
input = [ "BTN_EXTRA" ];
|
||||
output = [ "BTN_SIDE" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
description = "Harmonia binary cache backed by the local Nix store";
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
let
|
||||
signingKeyPath = "/run/secrets/harmonia/signing-key";
|
||||
in
|
||||
{
|
||||
services.harmonia.cache = {
|
||||
enable = true;
|
||||
signKeyPaths = [ signingKeyPath ];
|
||||
|
||||
settings = {
|
||||
bind = "0.0.0.0:5000";
|
||||
priority = 30;
|
||||
};
|
||||
};
|
||||
|
||||
# Keep activation usable while the host-specific SOPS secret is bootstrapped.
|
||||
# Once the secret exists, starting the socket also starts Harmonia on demand.
|
||||
systemd.sockets.harmonia.unitConfig.ConditionPathExists = signingKeyPath;
|
||||
systemd.services.harmonia.unitConfig.ConditionPathExists = signingKeyPath;
|
||||
}
|
||||
@@ -10,6 +10,8 @@ let
|
||||
brightnessState = "$XDG_RUNTIME_DIR/swayidle-brightness";
|
||||
|
||||
onBattery = pkgs.writeShellScript "swayidle-on-battery" ''
|
||||
[ "''${SWAYIDLE_ASSUME_AC:-0}" = 1 ] && exit 1
|
||||
|
||||
for supply in /sys/class/power_supply/*; do
|
||||
[ -f "$supply/type" ] || continue
|
||||
[ "$(< "$supply/type")" = "Battery" ] || continue
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 8;
|
||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||
boot.kernelPackages = pkgs.linuxPackages;
|
||||
programs.nix-ld.enable = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
boot = {
|
||||
extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
|
||||
kernelModules = [ "v4l2loopback" ];
|
||||
extraModprobeConfig = ''
|
||||
options v4l2loopback devices=1 video_nr=42 card_label="LUMIX S9" exclusive_caps=1
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -1,12 +1,98 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
networking.nameservers = lib.mkDefault [
|
||||
"1.1.1.1"
|
||||
"1.0.0.1"
|
||||
let
|
||||
dohPort = 5300;
|
||||
|
||||
dohLocalUpstream = "127.0.0.1#${toString dohPort}";
|
||||
|
||||
internalDns = [
|
||||
"10.50.80.53"
|
||||
"10.50.80.54"
|
||||
|
||||
# "fd00:50:80::53"
|
||||
# "fd00:50:80::54"
|
||||
];
|
||||
|
||||
services.resolved.enable = lib.mkDefault false;
|
||||
security.pki.certificateFiles = [ ./root_ca.crt ];
|
||||
internalZones = [
|
||||
"app.homelabs.run"
|
||||
];
|
||||
|
||||
internalDnsServers = lib.concatMap (zone: map (dns: "/${zone}/${dns}") internalDns) internalZones;
|
||||
in
|
||||
{
|
||||
services.resolved.enable = false;
|
||||
|
||||
networking.networkmanager.dns = "none";
|
||||
|
||||
services.dnscrypt-proxy = {
|
||||
enable = true;
|
||||
|
||||
upstreamDefaults = true;
|
||||
|
||||
settings = {
|
||||
listen_addresses = [
|
||||
"127.0.0.1:${toString dohPort}"
|
||||
];
|
||||
|
||||
server_names = [
|
||||
"cloudflare"
|
||||
"cloudflare-ipv6"
|
||||
];
|
||||
|
||||
ipv4_servers = true;
|
||||
ipv6_servers = true;
|
||||
|
||||
dnscrypt_servers = false;
|
||||
doh_servers = true;
|
||||
odoh_servers = false;
|
||||
|
||||
cache = false;
|
||||
|
||||
block_ipv6 = false;
|
||||
|
||||
ignore_system_dns = true;
|
||||
|
||||
bootstrap_resolvers = [
|
||||
"9.9.9.11:53"
|
||||
"149.112.112.11:53"
|
||||
"[2620:fe::11]:53"
|
||||
"[2620:fe::fe:11]:53"
|
||||
];
|
||||
|
||||
netprobe_address = "1.1.1.1:443";
|
||||
|
||||
timeout = 5000;
|
||||
keepalive = 30;
|
||||
};
|
||||
};
|
||||
|
||||
services.dnsmasq = {
|
||||
enable = true;
|
||||
|
||||
resolveLocalQueries = true;
|
||||
|
||||
settings = {
|
||||
no-resolv = true;
|
||||
|
||||
local-service = "host";
|
||||
|
||||
server = [ dohLocalUpstream ] ++ internalDnsServers;
|
||||
|
||||
all-servers = true;
|
||||
|
||||
cache-size = 10000;
|
||||
|
||||
dns-loop-detect = true;
|
||||
domain-needed = true;
|
||||
bogus-priv = true;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.dnsmasq = {
|
||||
wants = [ "dnscrypt-proxy.service" ];
|
||||
after = [ "dnscrypt-proxy.service" ];
|
||||
};
|
||||
|
||||
security.pki.certificateFiles = [
|
||||
./root_ca.crt
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
description = "Central Nix build server policy and persistent fleet roots";
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{ primaryUser, ... }:
|
||||
let
|
||||
GiB = 1024 * 1024 * 1024;
|
||||
in
|
||||
{
|
||||
nix = {
|
||||
nrBuildUsers = 64;
|
||||
|
||||
settings = {
|
||||
# Limit concurrent derivations so build scratch and memory usage remain
|
||||
# bounded. Each derivation may still use every vCPU exposed to the VM.
|
||||
max-jobs = 2;
|
||||
cores = 0;
|
||||
|
||||
# Keep enough room for large desktop, browser, and CUDA closures.
|
||||
min-free = 64 * GiB;
|
||||
max-free = 128 * GiB;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.nix-daemon.serviceConfig = {
|
||||
MemoryAccounting = true;
|
||||
MemoryMax = "90%";
|
||||
OOMScoreAdjust = 500;
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/nix-fleet 0750 ${primaryUser} users - -"
|
||||
"d /var/lib/nix-fleet/roots 0750 ${primaryUser} users - -"
|
||||
"d /var/lib/nix-fleet/roots/build 0750 ${primaryUser} users - -"
|
||||
"d /var/lib/nix-fleet/roots/deploy 0750 ${primaryUser} users - -"
|
||||
];
|
||||
}
|
||||
@@ -7,14 +7,18 @@
|
||||
"flakes"
|
||||
];
|
||||
|
||||
connect-timeout = 10;
|
||||
|
||||
extra-substituters = [
|
||||
"https://cache.nixos.org"
|
||||
"https://nix-community.cachix.org"
|
||||
"https://moons-dotfiles.cachix.org"
|
||||
"https://noctalia.cachix.org"
|
||||
"https://vicinae.cachix.org"
|
||||
"https://ghostty.cachix.org"
|
||||
"https://cache.numtide.com"
|
||||
"https://codex-desktop-linux.cachix.org"
|
||||
"https://cuda-maintainers.cachix.org"
|
||||
];
|
||||
|
||||
extra-trusted-public-keys = [
|
||||
@@ -23,8 +27,10 @@
|
||||
"moons-dotfiles.cachix.org-1:WHoroKiNScG2/dpxHHL1I0qVmvuQhJbEAP+DS2j9Rr0="
|
||||
"noctalia.cachix.org-1:pCOR47nnMEo5thcxNDtzWpOxNFQsBRglJzxWPp3dkU4="
|
||||
"vicinae.cachix.org-1:1kDrfienkGHPYbkpNj1mWTr7Fm1+zcenzgTizIcI3oc="
|
||||
"ghostty.cachix.org-1:QB389yTa6gTyneehvqG58y0WnHjQOqgnA+wBnpWWxns="
|
||||
"niks3.numtide.com-1:DTx8wZduET09hRmMtKdQDxNNthLQETkc/yaX7M4qK0g="
|
||||
"codex-desktop-linux.cachix.org-1:nX/xy6AdK9hQE24A8ALGjkCKj2ObFmcnemiL5Cid4nk="
|
||||
"cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E="
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
publicKeyFile = ./public-key;
|
||||
hasPublicKey = builtins.pathExists publicKeyFile;
|
||||
publicKey = if hasPublicKey then lib.removeSuffix "\n" (builtins.readFile publicKeyFile) else "";
|
||||
in
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = hasPublicKey;
|
||||
message = ''
|
||||
systems.nix.homelab-cache requires
|
||||
modules/systems/nix/homelab-cache/public-key
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
nix.settings = lib.mkIf hasPublicKey {
|
||||
extra-substituters = [ "http://nix-builder:5000" ];
|
||||
extra-trusted-public-keys = [ publicKey ];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
description = "Homelab Harmonia binary-cache client settings";
|
||||
}
|
||||
@@ -1,8 +1,3 @@
|
||||
{
|
||||
services.pcscd.enable = true;
|
||||
|
||||
sops.secrets."users/moons/hashedPassword" = {
|
||||
sopsFile = ../../../secrets/common/system.yaml;
|
||||
neededForUsers = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
imports = [
|
||||
./dotnix.nix
|
||||
./android.nix
|
||||
./ios.nix
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
_: {
|
||||
perSystem =
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
installIosSimulator = pkgs.writeShellApplication {
|
||||
name = "ios-simulator-install";
|
||||
text = ''
|
||||
if [[ "$(/usr/bin/uname -s)" != "Darwin" ]]; then
|
||||
echo "ios-simulator-install is only supported on macOS." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
xcode_app="/Applications/Xcode.app"
|
||||
developer_dir="$xcode_app/Contents/Developer"
|
||||
|
||||
if [[ ! -d "$developer_dir" ]]; then
|
||||
echo "Xcode is not installed at $xcode_app." >&2
|
||||
echo "Apply the m2 nix-darwin configuration first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
current_developer_dir="$(/usr/bin/xcode-select -p 2>/dev/null || true)"
|
||||
if [[ "$current_developer_dir" != "$developer_dir" ]]; then
|
||||
echo "Selecting stable Xcode..."
|
||||
/usr/bin/sudo /usr/bin/xcode-select --switch "$developer_dir"
|
||||
fi
|
||||
|
||||
echo "Installing Xcode first-launch components..."
|
||||
/usr/bin/sudo /usr/bin/xcodebuild -runFirstLaunch
|
||||
|
||||
echo "Checking for newer hardware support..."
|
||||
/usr/bin/xcodebuild -runFirstLaunch -checkForNewerComponents
|
||||
|
||||
echo "Downloading and installing the latest iOS Simulator runtime..."
|
||||
/usr/bin/xcodebuild -downloadPlatform iOS
|
||||
|
||||
echo
|
||||
/usr/bin/xcodebuild -version
|
||||
/usr/bin/xcrun simctl list runtimes
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
devShells.ios = pkgs.mkShell {
|
||||
packages = [ installIosSimulator ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
name: add-application-or-service
|
||||
description: Add, install, configure, or enable an application or long-running service in this NixOS, nix-darwin, and Home Manager flake while preserving its Registry architecture and quality bar. Use for new GUI or CLI applications, packages, daemons, background services, application-service pairs, cross-platform installations, profile adoption, or substantial extensions to an existing application or service unit.
|
||||
---
|
||||
|
||||
# Add Application or Service
|
||||
|
||||
Add the smallest complete Registry unit change that has a clear owner, an
|
||||
explicit dependency path, and evidence that every affected host class
|
||||
evaluates. Treat `AGENTS.md` as the authoritative repository contract; never
|
||||
replace it with generic Nix conventions.
|
||||
|
||||
## Follow the workflow
|
||||
|
||||
### 1. Establish the baseline
|
||||
|
||||
1. Read `AGENTS.md` completely before editing.
|
||||
2. Run `git status --short`. Preserve all pre-existing user changes and identify
|
||||
which later diffs belong to this task.
|
||||
3. Translate the request into observable outcomes: package or program, desired
|
||||
configuration, supported host classes, required daemon or permissions, and
|
||||
the profile or user intent that should select it.
|
||||
4. Inspect the nearest existing units, relevant profiles, `hosts/default.nix`,
|
||||
and Registry implementation. Prefer repository evidence over memory.
|
||||
5. Verify current package names, module options, external module exports, and
|
||||
Homebrew cask names from the locked inputs or authoritative upstream
|
||||
documentation. Do not guess an option path.
|
||||
6. Read [references/review-checklist.md](references/review-checklist.md) before
|
||||
choosing files or dependencies.
|
||||
|
||||
### 2. Choose ownership before code
|
||||
|
||||
Classify each concern independently:
|
||||
|
||||
- Put the user-facing program and its settings in
|
||||
`modules/applications/<name>/`.
|
||||
- Put a daemon, long-running process, firewall rule, permission, or user/group
|
||||
membership in `modules/services/<name>/`.
|
||||
- Split an application and independently meaningful daemon into two units.
|
||||
Let the application include the service only when the service is a technical
|
||||
requirement of that application.
|
||||
- Put adoption of otherwise independent units in the narrowest coherent
|
||||
`modules/profiles/` composition.
|
||||
- Use another documented owner when the request is actually a system,
|
||||
hardware, user, overlay, or host concern. Do not force it into an application
|
||||
or service directory merely because this skill was invoked.
|
||||
|
||||
Choose only the reserved fragments that contain real configuration. Use
|
||||
`common.nix`, `nixos.nix`, and `darwin.nix` for system-side configuration; use
|
||||
`home.nix` or `home/{common,nixos,darwin}.nix` for Home Manager. Use `meta.nix`
|
||||
only for description, fully qualified `includes`, and external module imports.
|
||||
|
||||
Before editing, formulate a short implementation contract containing:
|
||||
|
||||
- the unit ID and owner;
|
||||
- each file to create or change and why;
|
||||
- technical dependencies versus profile-level choices;
|
||||
- supported and affected host classes;
|
||||
- the evaluations or builds that will prove the change.
|
||||
|
||||
Rework the design if an ordinary addition appears to require Registry changes,
|
||||
new global `specialArgs`, `_module.args`, direct host selection, or an overlay.
|
||||
Use those mechanisms only with concrete evidence that the documented extension
|
||||
points cannot express the requirement.
|
||||
|
||||
### 3. Implement the minimum complete change
|
||||
|
||||
1. Return configuration directly from every reserved fragment. Do not add
|
||||
top-level `imports`, `options`, or `config`, and do not reproduce Registry
|
||||
`mkEnableOption`, `cfg`, or `mkIf` boilerplate.
|
||||
2. Put upstream NixOS, nix-darwin, or Home Manager modules in
|
||||
`meta.imports.<class>`. Import ordinary helper files explicitly from the
|
||||
fragment that uses them.
|
||||
3. Declare unit-to-unit technical dependencies only through fully qualified
|
||||
`meta.includes`. Never enable another unit by assigning its
|
||||
`my.<path>.enable` option inside a fragment.
|
||||
4. Add an independent application or service to an existing coherent profile,
|
||||
or create a justified profile when no existing one expresses the user
|
||||
intent. Do not use `hosts/default.nix` application or unit escape hatches for
|
||||
normal composition.
|
||||
5. Keep cross-platform purpose shared and installation differences in the
|
||||
owning unit. Do not create thin `*-linux` profiles.
|
||||
6. Use existing module arguments and standard options. Do not inject a
|
||||
dependency through global arguments, Registry internals, import ordering, or
|
||||
`lib.mkForce`. Use explicit module priorities only when a real ownership
|
||||
boundary requires them and make that reason visible in the code or handoff.
|
||||
7. Avoid speculative abstraction. Create a helper only when it separates
|
||||
meaningful configuration or prevents real duplication. Do not add empty
|
||||
fragments, compatibility aliases, unused options, redundant comments, or
|
||||
copied boilerplate.
|
||||
8. Update `modules/profiles/README.md`, `AGENTS.md`, profile selections, or
|
||||
other contract documentation whenever the change makes an existing
|
||||
statement stale. Do not edit them performatively when their meaning remains
|
||||
accurate.
|
||||
|
||||
### 4. Prove the change
|
||||
|
||||
Run the validation matrix in
|
||||
[references/review-checklist.md](references/review-checklist.md). At minimum:
|
||||
|
||||
1. Format the task-owned files with the repository formatter and run
|
||||
`git diff --check`.
|
||||
2. Inspect the complete task diff for accidental files, duplication, leaked
|
||||
secrets, forced values, direct enable assignments, and unrelated rewrites.
|
||||
3. Run `nix flake check`.
|
||||
4. Run `pre-commit run --all-files`.
|
||||
5. Evaluate every affected real host without switching it. For a
|
||||
cross-platform unit or profile, evaluate both NixOS and nix-darwin even if
|
||||
only one class changed. Build an affected configuration with `--no-link`
|
||||
when the current platform can build it.
|
||||
6. Verify selection as well as syntax: confirm that the expected package,
|
||||
program, service, group, cask, or external module appears in the resulting
|
||||
configuration.
|
||||
|
||||
If a command is unavailable, blocked by the environment, or fails for a
|
||||
pre-existing reason, diagnose it and report the exact gap. Never silently skip
|
||||
a required check or weaken the implementation to make a check pass.
|
||||
|
||||
### 5. Audit before completion
|
||||
|
||||
Reject the change until all of the following are true:
|
||||
|
||||
- Every line has one clear owner and is required by the requested behavior.
|
||||
- Every dependency is either technical and declared in `meta.includes`, or a
|
||||
user choice owned by a profile.
|
||||
- The unit is reachable from the intended profile or has an explicit reason to
|
||||
remain independently selectable.
|
||||
- No host, Registry, flake root, global argument, or overlay was changed as a
|
||||
shortcut.
|
||||
- Reserved fragments, metadata, and profile documentation satisfy the current
|
||||
repository contract.
|
||||
- Validation covers every affected host class and all failures are resolved or
|
||||
explicitly reported.
|
||||
|
||||
Conclude with the owner and selection rationale, affected hosts or profiles,
|
||||
validation commands and results, and any manual activation or runtime check
|
||||
that remains. Do not claim runtime behavior that was only evaluated.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Add Application or Service"
|
||||
short_description: "Add clean, validated Registry units"
|
||||
default_prompt: "Use $add-application-or-service to add an application or service cleanly and verify every affected host class."
|
||||
@@ -0,0 +1,139 @@
|
||||
# Application and Service Review Checklist
|
||||
|
||||
Use this reference during design and again during final review.
|
||||
|
||||
## Ownership and fragment matrix
|
||||
|
||||
| Concern | Owner | Typical fragment |
|
||||
| -------------------------------------------------------- | ----------------------------------- | ----------------------------------------- |
|
||||
| User-facing GUI, CLI, editor, or compositor | `modules/applications/<name>/` | `home*.nix`, `nixos.nix`, or `darwin.nix` |
|
||||
| User-scoped package and program settings | Application unit | `home.nix` or `home/<class>.nix` |
|
||||
| macOS Homebrew package or cask | Owning application or service | `darwin.nix` |
|
||||
| Daemon or long-running service | `modules/services/<name>/` | `nixos.nix` or `darwin.nix` |
|
||||
| Firewall, group, permission, or service account | Owning service | `nixos.nix` or `darwin.nix` |
|
||||
| Upstream module defining options | Owning unit metadata | `meta.nix` under `imports.<class>` |
|
||||
| Technical prerequisite unit | Owning unit metadata | Fully qualified `meta.includes` |
|
||||
| A set of independent tools chosen for one purpose | Narrowest coherent profile | Profile `meta.includes` |
|
||||
| Machine fact such as UUID, monitor ID, or static address | `hosts/<name>/` | Normal host module |
|
||||
| Missing or replaced package | `overlays/` only after proving need | Overlay definition |
|
||||
|
||||
Use `home/common.nix` when Home Manager configuration is truly shared between
|
||||
NixOS and Darwin. Use `home/nixos.nix` or `home/darwin.nix` for class-specific
|
||||
Home Manager behavior. Root `common.nix` is system-side and never Home Manager.
|
||||
Do not create an unused counterpart for symmetry.
|
||||
|
||||
## Dependency review
|
||||
|
||||
For every edge from unit A to unit B, answer these questions:
|
||||
|
||||
1. Does A fail to work without B? If yes, put the fully qualified ID of B in
|
||||
A's `meta.includes`.
|
||||
2. Are A and B merely useful together for a particular workflow? If yes, let a
|
||||
profile include both.
|
||||
3. Does the dependency exist only on one host? Keep the machine fact in the
|
||||
host, but keep reusable behavior in its unit or profile.
|
||||
4. Is a new `specialArgs`, `_module.args`, Registry field, or direct
|
||||
`my.*.enable` assignment being proposed? Reject it unless the repository's
|
||||
normal module and `meta.includes` mechanisms provably cannot model the
|
||||
requirement.
|
||||
5. Would adding the dependency make the depended-on application select a
|
||||
compositor, desktop, personal workload, or unrelated tool? Reverse or remove
|
||||
the edge; application metadata contains technical requirements, not taste.
|
||||
|
||||
Accept no circular dependency, shortened unit ID, duplicate include, stale
|
||||
unit ID, or ordering-dependent override.
|
||||
|
||||
## Minimality and code-quality review
|
||||
|
||||
Reject any of these patterns:
|
||||
|
||||
- Empty or placeholder reserved fragments.
|
||||
- Hand-written enable options or guards already generated by the Registry.
|
||||
- Top-level `imports`, `options`, or `config` in a configuration fragment.
|
||||
- External module imports hidden in a guarded configuration fragment.
|
||||
- Helper files assumed to be auto-imported.
|
||||
- A helper abstraction used once without reducing meaningful complexity.
|
||||
- Configuration duplicated across fragments when a shared fragment can express
|
||||
it cleanly.
|
||||
- Direct host application or unit selection where a profile expresses the
|
||||
concern.
|
||||
- A new flake input or overlay when the locked package set already provides the
|
||||
package and required module.
|
||||
- Global argument injection for a value owned by one unit.
|
||||
- `lib.mkForce` used to win an ordering fight instead of resolving ownership.
|
||||
- Secret material, generated state, machine IDs, or mutable user preferences
|
||||
committed as reusable configuration.
|
||||
- Comments that repeat the code, compatibility aliases, dead options, or
|
||||
opportunistic unrelated cleanup.
|
||||
|
||||
Prefer standard upstream module options over hand-written service definitions.
|
||||
Prefer existing repository arguments and helpers over new plumbing. Preserve
|
||||
user-owned mutable state unless the requested policy explicitly owns it.
|
||||
|
||||
## Validation matrix
|
||||
|
||||
Run checks from the repository root and keep the exact results for the handoff.
|
||||
Do not switch or activate a live system merely to validate a change.
|
||||
|
||||
### Always
|
||||
|
||||
1. Format task-owned files. If the worktree contains unrelated user changes,
|
||||
pass only task-owned paths to the configured formatter when supported.
|
||||
2. Run `git diff --check`.
|
||||
3. Review `git status --short`, `git diff --stat`, and the complete `git diff`.
|
||||
4. Run `nix flake check`.
|
||||
5. Run `pre-commit run --all-files`.
|
||||
|
||||
### NixOS or Home Manager on NixOS
|
||||
|
||||
- Evaluate each affected host's system toplevel derivation.
|
||||
- Build at least one affected NixOS configuration with `--no-link` when the
|
||||
current system supports it.
|
||||
- Inspect the resulting option that proves selection: for example
|
||||
`environment.systemPackages`, the user's `home.packages`,
|
||||
`systemd.services`, `users.users.<name>.extraGroups`, or the upstream
|
||||
`programs`/`services` option.
|
||||
|
||||
Typical build shape:
|
||||
|
||||
```sh
|
||||
nix build .#nixosConfigurations.<host>.config.system.build.toplevel --no-link
|
||||
```
|
||||
|
||||
### nix-darwin or Home Manager on Darwin
|
||||
|
||||
- Evaluate every affected Darwin host even when running on Linux.
|
||||
- Inspect `homebrew.casks` or `homebrew.brews` for Homebrew-backed additions.
|
||||
- Evaluate the relevant Home Manager program or package option.
|
||||
- Build a Darwin configuration only on a compatible Darwin builder; otherwise
|
||||
report that build as an explicit runtime-validation gap.
|
||||
|
||||
Typical evaluation shapes:
|
||||
|
||||
```sh
|
||||
nix eval --raw .#darwinConfigurations.<host>.system.drvPath
|
||||
nix eval --json .#darwinConfigurations.<host>.config.homebrew.casks
|
||||
```
|
||||
|
||||
Confirm the exact output attribute against the current flake before using a
|
||||
command; do not paste these shapes blindly.
|
||||
|
||||
### Profiles and cross-platform changes
|
||||
|
||||
- Determine transitive selection through `meta.includes`, not only direct
|
||||
mentions.
|
||||
- Evaluate every real host selecting the changed profile.
|
||||
- Evaluate both host classes for a cross-platform profile, even if only one
|
||||
current fragment changed.
|
||||
- Re-read `modules/profiles/README.md` and `hosts/default.nix` for stale meaning,
|
||||
compatibility, or role statements.
|
||||
- If no real host selects the new unit, construct a non-persistent evaluation
|
||||
that enables it or explain why the unit is intentionally dormant. Do not add
|
||||
a fake host or permanent direct selection as a test harness.
|
||||
|
||||
### Runtime-dependent behavior
|
||||
|
||||
Evaluation and builds cannot prove GUI appearance, credentials, network access,
|
||||
hardware behavior, or successful daemon interaction. State the precise manual
|
||||
post-activation check needed for those behaviors. Never describe evaluation as
|
||||
a runtime test.
|
||||
Reference in New Issue
Block a user