feat hosts

This commit is contained in:
2026-07-27 21:18:00 +09:00
parent 9bb95535cf
commit 91bb7e80db
3 changed files with 161 additions and 74 deletions
+153 -68
View File
@@ -7,6 +7,10 @@ flake. `flake.nix` defines inputs and delegates flake outputs through
flake-parts. Keep configuration with the component that owns it, rather than in
the root flake or an unrelated host.
This file documents the current repository contract, not a hypothetical future
layout. When a structural, ownership, profile, host-role, or validation change
makes any statement here stale, update `AGENTS.md` in the same change.
| Path | Responsibility |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `modules/applications/` | One software component, including GUI applications, window managers, desktop environments, CLI tools, and editors |
@@ -31,23 +35,26 @@ Before adding configuration, decide whether it is owned by an application,
system foundation, service, hardware family, user, profile, or individual host.
Prefer the following placements:
| Configuration | Placement |
| ---------------------------------------------------- | ------------------------------------------------ |
| Nix settings shared by every system host | `modules/systems/nix/common.nix` |
| NixOS-only boot configuration | `modules/systems/boot/.../nixos.nix` |
| Ghostty-specific configuration | `modules/applications/ghostty/` |
| niri-specific configuration | `modules/applications/niri/` |
| Applications selected for the niri environment | `modules/profiles/interface/niri/meta.nix` |
| GNOME itself | `modules/applications/gnome/` |
| Docker daemon and Docker group membership | `modules/services/docker/nixos.nix` |
| Reusable ThinkPad-family configuration | `modules/hardwares/thinkpad/` |
| The laptop unit composition | `modules/profiles/platform/laptop/meta.nix` |
| The development-environment unit composition | `modules/profiles/workload/development/meta.nix` |
| A user's OS- and Home Manager-specific configuration | `modules/users/<name>/` |
| x1g13-specific monitor layout | `hosts/x1g13/home.nix` |
| x1g13-specific disk UUID | `hosts/x1g13/nixos.nix` |
| Package replacement or addition | `overlays/` |
| Formatter, checks, or Git hooks | `flake/` |
| Configuration | Placement |
| ---------------------------------------------------- | ------------------------------------------------------- |
| Nix settings shared by every system host | `modules/systems/nix/common.nix` |
| NixOS-only boot configuration | `modules/systems/boot/.../nixos.nix` |
| Ghostty-specific configuration | `modules/applications/ghostty/` |
| niri-specific configuration | `modules/applications/niri/` |
| Desktop applications shared by GNOME and niri | `modules/profiles/interface/linux-desktop/meta.nix` |
| Applications and services specific to niri | `modules/profiles/interface/niri/meta.nix` |
| GNOME itself | `modules/applications/gnome/` |
| A Linux package plus its macOS Homebrew cask | `modules/applications/<name>/home.nix` and `darwin.nix` |
| Docker daemon and Docker group membership | `modules/services/docker/nixos.nix` |
| The laptop unit composition | `modules/profiles/platform/laptop/meta.nix` |
| The Intel ThinkPad X1 composition | `modules/profiles/platform/thinkpad-x1/meta.nix` |
| The development-environment unit composition | `modules/profiles/workload/development/meta.nix` |
| Cross-platform fingerprint selection | `modules/profiles/security/fingerprint/meta.nix` |
| A user's OS- and Home Manager-specific configuration | `modules/users/<name>/` |
| Host-specific monitor layout | `hosts/<name>/home.nix` |
| Generated host disk UUIDs | `hosts/<name>/hardware-configuration.nix` |
| Package replacement or addition | `overlays/` |
| Formatter, checks, or Git hooks | `flake/` |
## Unit Discovery and Identity
@@ -283,12 +290,12 @@ use fully qualified unit IDs:
# modules/profiles/interface/niri/meta.nix
{
includes = [
"profiles.interface.linux-desktop"
"applications.niri"
"applications.ghostty"
"applications.noctalia"
"applications.vicinae"
"applications.nautilus"
"services.xdg-portal"
"services.ly"
"services.swayidle"
"services.swaylock"
];
}
```
@@ -301,41 +308,89 @@ in `meta.includes`.
Application metadata should include only dependencies technically required for
the application to work. A profile owns the user's choice to adopt several
otherwise independent applications together. For example, niri may include the
Wayland foundation and xdg-desktop-portal as technical dependencies, while
`profiles.interface.niri` selects Ghostty, Vicinae, Noctalia, and Nautilus.
Ghostty must not depend on niri, and niri-specific keybindings remain owned by
the niri unit.
otherwise independent applications together. For example, the niri application
includes the Wayland foundation as a technical dependency. The
`profiles.interface.linux-desktop` profile selects Ghostty, Nautilus, and
Vicinae because both GNOME and niri use them, while `profiles.interface.niri`
selects only the niri-specific shell and services. Ghostty must not depend on
niri, and niri-specific keybindings remain owned by the niri unit.
## Profiles
Profiles compose units by purpose or form factor; they do not replace clear
application, system, service, or hardware ownership. Suitable profile namespaces
include:
application, system, service, or hardware ownership. The current profile
structure is:
```text
modules/profiles/
├── README.md
├── base/
├── interface/
│ ├── niri/
│ ├── cli/
│ ├── linux-desktop/
│ ├── gnome/
│ ├── cli-minimal/
│ └── cli-interactive/
│ └── niri/
├── networking/
│ ├── tailscale-client/
│ └── tailscale-subnet-router/
├── platform/
│ ├── nixos/
│ ├── laptop/
│ ├── thinkpad/
│ ├── thinkpad-x1/
│ ├── desktop/
│ ├── vm/
│ └── wsl/
│ └── vm/
├── workload/
│ ├── development/
│ ├── personal/
│ ├── server/
│ └── remote/
│ └── remote-access/
└── security/
└── secure-boot/
├── fingerprint/
├── secrets/
├── secure-boot/
└── tpm-storage/
```
`modules/profiles/README.md` is the compatibility inventory for this structure.
Whenever a profile is added, removed, renamed, changes host-class support, or
changes meaning, update that README and every affected `hosts/default.nix`
selection in the same change. Remove stale profile directories and references;
do not retain compatibility aliases.
The profile layers have these responsibilities:
- `base` contains only invariants required by every supported host. It currently
includes only `systems.nix`; optional secrets, interface, hardware, and
workloads do not belong there.
- `interface` describes how the host is operated. `interface.cli` is shared by
NixOS and macOS and includes `tio`. `interface.linux-desktop` owns the common
GNOME/niri desktop selection, including Ghostty, Nautilus, and Vicinae. GNOME
and niri remain independently selectable and do not imply CLI or personal
workloads.
- `platform` describes NixOS foundations and physical or virtual form factors.
macOS does not need an empty symmetric platform profile.
- `workload` describes optional host uses. `workload.development` and
`workload.personal` are cross-platform profiles, not `*-linux` variants.
- `networking` describes network roles and topology rather than user workloads.
- `security` describes optional security policies. Select
`security.fingerprint` instead of listing `systems.fingerprint` directly in a
host. The underlying `systems.fingerprint` unit owns NixOS fingerprint
authentication and macOS Touch ID sudo configuration through its class
fragments.
Do not split a semantic profile into `*-linux` and cross-platform variants merely
because an application is installed differently on each OS. Keep the semantic
profile cross-platform when its purpose is shared, and implement OS differences
inside the owning application unit. For example, Chrome, Vesktop, draw.io,
Slack, and Zoom use Linux Home Manager configuration in `home.nix` and macOS
Homebrew casks in `darwin.nix`. Guard a Linux-only Home Manager package with the
host platform when the same unit also has a Darwin implementation.
An explicitly OS-specific profile is appropriate when the composition itself is
OS-specific, such as `interface.linux-desktop`, `platform.nixos`, or a NixOS
subnet-router. Do not create an OS suffix for a thin package difference that the
owning application unit can express.
The `desktop/` name above is a form-factor profile under `profiles/platform/`,
not a top-level module category.
@@ -352,6 +407,10 @@ conditions holds:
- Other units depend on it.
- It involves a daemon, permissions, or user groups.
`security.tpm-storage` intentionally does not own a disk identifier. A host that
selects it must define `boot.initrd.luks.devices.cryptroot.device` in its own
NixOS module.
## Registry Responsibilities
Implement unit discovery with Nix standard functionality such as
@@ -416,49 +475,46 @@ A host registry may use a specification like this:
```nix
# hosts/default.nix
{
x1g13 = {
x1g9 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./x1g13;
path = ./x1g9;
profiles = [
"base"
"platform.thinkpad"
"interface.niri"
"interface.cli"
"interface.gnome"
"workload.development"
"interface.niri"
"platform.thinkpad-x1"
"security.fingerprint"
"workload.personal"
"security.secure-boot"
];
applications = [
"codex-desktop"
];
units = [
"services.tailscale"
];
};
macbook = {
m2 = {
system = "aarch64-darwin";
stateVersion = "26.05";
user = "moons";
path = ./macbook;
path = ./m2;
profiles = [
"base"
"platform.laptop"
"interface.cli"
"security.fingerprint"
"workload.development"
"workload.personal"
];
applications = [
"ghostty"
];
};
}
```
The current role assignment is intentional: x1g9 is a full NixOS desktop with
niri, GNOME, ly, the shared Linux desktop applications, and the personal
workload. m2 is the daily-use macOS development and personal machine. Keep the
desktop sessions independently selectable, and keep m2's development and
personal profiles usable on Darwin.
Treat entries in `profiles` and `applications` as IDs relative to their
respective category roots. Add the category prefixes during host construction:
@@ -471,24 +527,29 @@ selectedUnits =
```
`units` is an escape hatch for fully qualified service, system, hardware, or
other unit IDs. Prefer profiles for the main composition; do not make hosts list
large numbers of low-level units directly.
other unit IDs. Do not use it when an existing profile expresses the concern or
when the concern is reusable enough to deserve a small profile. For example,
select `security.fingerprint`; do not write
`units = [ "systems.fingerprint" ];`. Prefer profiles for the main composition
and keep `units` empty unless a genuinely exceptional low-level selection is
required.
Host modules use normal Nix module semantics and are not Registry-guarded
configuration fragments. For example:
```text
hosts/x1g13/
├── nixos.nix
├── home.nix
├── hardware-configuration.nix
└── disko.nix
hosts/
├── x1g9/
│ ├── nixos.nix
│ └── hardware-configuration.nix
└── m2/
└── darwin.nix
```
`hosts/x1g13/nixos.nix` may explicitly load `hardware-configuration.nix` and
`disko.nix` with the normal top-level Nix module `imports`. Do not confuse these
host imports with the prohibition on top-level `imports` in unit configuration
fragments.
`hosts/x1g9/nixos.nix` explicitly loads `hardware-configuration.nix` with the
normal top-level Nix module `imports`. A future host-local `disko.nix` would be
loaded the same way. Do not confuse these host imports with the prohibition on
top-level `imports` in unit configuration fragments.
Derive the system class from the host's `system`:
@@ -527,6 +588,16 @@ When implementing or modifying modules:
- Do not override a path-derived unit ID from `meta.nix`.
- Keep technical application dependencies separate from the applications a
personal environment chooses to combine in a profile.
- Keep cross-platform profile names semantic. Put Linux package installation in
an application's `home.nix` and the corresponding macOS Homebrew cask in its
`darwin.nix`; do not create a thin `*-linux` profile for that difference.
- Keep shared GNOME/niri selections in `profiles.interface.linux-desktop` and
session-specific applications or services in the respective GNOME or niri
profile.
- Keep `modules/profiles/README.md`, the profile directories, and host profile
selections synchronized whenever any of them changes.
- Prefer an existing or newly justified profile over a host-level `units` entry
for reusable concerns such as fingerprint authentication.
- Do not rely on module-list ordering to override values. Use Nix module
priorities such as `lib.mkDefault`, `lib.mkForce`, `lib.mkBefore`, or
`lib.mkAfter` explicitly when required.
@@ -563,6 +634,20 @@ dependency closure through `meta.includes`, missing-unit errors, and class
dispatch. Verify that helper files are ignored until explicitly imported and
that directories without a directly contained reserved file remain namespaces.
For profile changes, additionally:
- Check for stale profile IDs after every add, removal, or rename.
- Evaluate every affected real host without switching it.
- Evaluate a cross-platform profile on both NixOS and nix-darwin, even when only
one current host selects it.
- Confirm `modules/profiles/README.md` accurately states compatibility and any
required host-owned values.
- When adding a Darwin application fragment, verify the resulting
`homebrew.casks` selection as well as module evaluation.
- Preserve the intended host roles: x1g9 provides niri, GNOME, ly, and the
personal application set, while m2 remains the daily-use development and
personal machine.
## Commit and Pull Request Guidelines
Recent history favors short, lowercase, imperative subjects such as `fix` and
+3 -2
View File
@@ -8,9 +8,11 @@
profiles = [
"base"
"interface.cli"
"interface.gnome"
"interface.niri"
"platform.thinkpad-x1"
"security.fingerprint"
"security.secrets"
"workload.personal"
];
};
@@ -24,7 +26,6 @@
"base"
"interface.cli"
"security.fingerprint"
"security.secrets"
"workload.development"
"workload.personal"
];
+5 -4
View File
@@ -44,10 +44,11 @@ when removing it from any supported host would make that host invalid.
| `security.tpm-storage` | NixOS with a host-defined LUKS device |
Select independent concerns independently in `hosts/default.nix`. For example,
a minimal NixOS laptop can combine `base`, `platform.thinkpad-x1`, and
`interface.cli`, while a daily-use macOS development machine can add
`workload.development` and `workload.personal`. Hardware support does not
implicitly select an interface or workload.
a NixOS desktop can combine `interface.gnome` and `interface.niri` to provide
both sessions while sharing `interface.linux-desktop`; niri supplies ly. A
daily-use macOS development machine can add `workload.development` and
`workload.personal`. Hardware support does not implicitly select an interface
or workload.
`security.tpm-storage` deliberately does not own a disk identifier. A host that
selects it must define `boot.initrd.luks.devices.cryptroot.device` in its