split home-manager into their own submodules

This commit is contained in:
Danilo Reyes
2026-03-16 15:49:43 -06:00
parent 14eed4f7f6
commit 28c8db6cb7
43 changed files with 1011 additions and 626 deletions

View File

@@ -0,0 +1,2 @@
prefix_rule(pattern=["deadnix", "-e"], decision="allow")
prefix_rule(pattern=["nix", "eval"], decision="allow")

View File

@@ -26,6 +26,7 @@
backupFileExtension = "hbckup"; backupFileExtension = "hbckup";
useUserPackages = true; useUserPackages = true;
useGlobalPkgs = true; useGlobalPkgs = true;
sharedModules = [ ../modules/home-manager.nix ];
extraSpecialArgs = { extraSpecialArgs = {
inherit inputs outputs; inherit inputs outputs;
}; };
@@ -98,6 +99,7 @@
"flakes" "flakes"
"pipe-operators" "pipe-operators"
]; ];
download-buffer-size = 134217728;
substituters = [ substituters = [
"${config.my.servers.atticd.url}/nixos" "${config.my.servers.atticd.url}/nixos"
"${config.my.servers.atticd.url}/webref" "${config.my.servers.atticd.url}/webref"

View File

@@ -21,6 +21,7 @@ let
}; };
in in
{ {
imports = [ ./jawz-home.nix ];
home.stateVersion = "23.05"; home.stateVersion = "23.05";
programs = { programs = {
direnv = { direnv = {

32
config/jawz-home.nix Normal file
View File

@@ -0,0 +1,32 @@
{
lib,
inputs,
osConfig,
...
}:
let
inherit (osConfig.networking) hostName;
nixosHosts = inputs.self.lib.getNixosHosts osConfig.my.ips hostName lib;
nixosHostsMatch = lib.concatStringsSep " " nixosHosts;
in
{
home.file.".librewolf/.stignore".source = ../dotfiles/stignore;
programs.ssh = lib.mkIf osConfig.my.secureHost {
enable = true;
enableDefaultConfig = false;
matchBlocks = {
vps = {
hostname = osConfig.my.ips.vps;
user = "jawz";
port = 3456;
identityFile = osConfig.sops.secrets."private_keys/${hostName}".path;
};
"${nixosHostsMatch}" = {
user = "jawz";
identityFile = osConfig.sops.secrets."private_keys/${hostName}".path;
};
"${osConfig.my.servers.gitea.host} github.com gitlab.com bitbucket.org".identityFile =
osConfig.sops.secrets."git_private_keys/${hostName}".path;
};
};
}

View File

@@ -6,8 +6,6 @@
}: }:
let let
inherit (config.networking) hostName; inherit (config.networking) hostName;
nixosHosts = inputs.self.lib.getNixosHosts config.my.ips hostName lib;
nixosHostsMatch = lib.concatStringsSep " " nixosHosts;
in in
{ {
sops.secrets = lib.mkIf config.my.secureHost ( sops.secrets = lib.mkIf config.my.secureHost (
@@ -26,27 +24,6 @@ in
"git_private_keys/${hostName}" = keyConfig "${baseDir}_git"; "git_private_keys/${hostName}" = keyConfig "${baseDir}_git";
} }
); );
home-manager.users.jawz = {
home.file.".librewolf/.stignore".source = ../dotfiles/stignore;
programs.ssh = lib.mkIf config.my.secureHost {
enable = true;
enableDefaultConfig = false;
matchBlocks = {
vps = {
hostname = config.my.ips.vps;
user = "jawz";
port = 3456;
identityFile = config.sops.secrets."private_keys/${hostName}".path;
};
"${nixosHostsMatch}" = {
user = "jawz";
identityFile = config.sops.secrets."private_keys/${hostName}".path;
};
"${config.my.servers.gitea.host} github.com gitlab.com bitbucket.org".identityFile =
config.sops.secrets."git_private_keys/${hostName}".path;
};
};
};
users.users.jawz = { users.users.jawz = {
uid = 1000; uid = 1000;
linger = true; linger = true;

View File

@@ -7,7 +7,7 @@
## Repository Overview ## Repository Overview
- Architecture: Flake-based repo using `flake-parts` with inputs for pkgs (stable/unstable), stylix, home-manager, sops-nix, and service overlays. Common modules are composed through `parts/core.nix` and `parts/hosts.nix`. - Architecture: Flake-based repo using `flake-parts` with inputs for pkgs (stable/unstable), stylix, home-manager, sops-nix, and service overlays. Common modules are composed through `parts/core.nix` and `parts/hosts.nix`.
- Module auto-import: `modules/modules.nix` auto-imports `.nix` files under `modules/apps`, `modules/dev`, `modules/scripts`, `modules/servers`, `modules/services`, `modules/shell`, `modules/websites`, and `modules/network`, excluding `librewolf.nix`. Factories live in `modules/factories/` (`mkserver`, `mkscript`), and shared options are in `modules/nix` and `modules/users`. - Module auto-import: `modules/modules.nix` auto-imports legacy flat modules under `modules/apps`, `modules/dev`, `modules/scripts`, `modules/servers`, `modules/services`, `modules/shell`, `modules/websites`, and `modules/network`, excluding `librewolf.nix`, and also discovers nested `nixos.nix` files under those trees. `config/base.nix` registers `modules/home-manager.nix` as a Home Manager shared module, which discovers nested `home.nix` files under `modules/` for every Home Manager user. Factories live in `modules/factories/` (`mkserver`, `mkscript`), and shared options are in `modules/nix` and `modules/users`.
- Hosts and toggles: Host definitions live in `hosts/<name>/configuration.nix` with host-specific toggles in `hosts/<name>/toggles.nix`. The `my` namespace carries toggles for apps/dev/scripts/services/shell, feature flags like `enableProxy` and `enableContainers`, and per-host `interfaces` and `ips` maps. - Hosts and toggles: Host definitions live in `hosts/<name>/configuration.nix` with host-specific toggles in `hosts/<name>/toggles.nix`. The `my` namespace carries toggles for apps/dev/scripts/services/shell, feature flags like `enableProxy` and `enableContainers`, and per-host `interfaces` and `ips` maps.
- Port assignment: Service ports should live with the service module when the port is intrinsic to a server definition under `modules/servers/`. Miscellaneous or host-specific ports that do not belong to a server module should be centralized in `my.ports` in `modules/modules.nix` and referenced via `config.my.ports.*` (use `toString config.my.ports.*` where a string is required). - Port assignment: Service ports should live with the service module when the port is intrinsic to a server definition under `modules/servers/`. Miscellaneous or host-specific ports that do not belong to a server module should be centralized in `my.ports` in `modules/modules.nix` and referenced via `config.my.ports.*` (use `toString config.my.ports.*` where a string is required).
- Main server and proxies: `my.mainServer` selects the host that should serve traffic by default (default `vps`). Reverse proxies use helpers in `parts/core.nix` (`proxy`, `proxyReverse`, `proxyReverseFix`, `proxyReversePrivate`) and pick IPs from `my.ips` plus the hostName/ip set by `mkserver` options. Nginx defaults to `proxyReverse` for any server with `enableProxy = true` unless `useDefaultProxy = false` or the server is listed in the Fix/Private proxy lists. - Main server and proxies: `my.mainServer` selects the host that should serve traffic by default (default `vps`). Reverse proxies use helpers in `parts/core.nix` (`proxy`, `proxyReverse`, `proxyReverseFix`, `proxyReversePrivate`) and pick IPs from `my.ips` plus the hostName/ip set by `mkserver` options. Nginx defaults to `proxyReverse` for any server with `enableProxy = true` unless `useDefaultProxy = false` or the server is listed in the Fix/Private proxy lists.
@@ -30,10 +30,10 @@ config.services = {
``` ```
## Terminology and Naming Standards ## Terminology and Naming Standards
- Module: A Nix module under `modules/<category>/<name>.nix` auto-imported into the system. - Module: Prefer a feature directory under `modules/<category>/<name>/` with `nixos.nix` for system concerns and `home.nix` for Home Manager concerns. Legacy flat modules at `modules/<category>/<name>.nix` remain valid during migration.
- Factory: Shared option constructors in `modules/factories/` (use `mkserver` for server modules, `mkscript` for script units). - Factory: Shared option constructors in `modules/factories/` (use `mkserver` for server modules, `mkscript` for script units).
- Options: Settings under the `my` namespace (e.g., `my.services.<service>`, `my.scripts.<script>`). - Options: Settings under the `my` namespace (e.g., `my.services.<service>`, `my.scripts.<script>`).
- Toggles: Enablement maps in `hosts/<name>/toggles.nix` controlling categories (apps/dev/shell/scripts/services/servers/units) and features (`enableProxy`, `enableContainers`). - Toggles: Enablement maps in `hosts/<name>/toggles.nix` controlling categories (apps/dev/shell/scripts/services/servers/units) and features (`enableProxy`, `enableContainers`). Future standalone Home Manager or Darwin homes should mirror that shape in home-specific toggle files instead of embedding Home Manager settings in NixOS modules.
- Servers: Reverse-proxied services under `modules/servers/`, normally created with `mkserver` options (including `useDefaultProxy` to opt out of default proxyReverse). - Servers: Reverse-proxied services under `modules/servers/`, normally created with `mkserver` options (including `useDefaultProxy` to opt out of default proxyReverse).
- Websites: Static nginx vhosts under `modules/websites/` (portfolio/blog, mb-report), gated by `my.websites.*.enableProxy`. - Websites: Static nginx vhosts under `modules/websites/` (portfolio/blog, mb-report), gated by `my.websites.*.enableProxy`.
- Scripts: Units defined via `mkscript` with `enable`, `install`, `service`, `users`, `timer`, and `package` fields. - Scripts: Units defined via `mkscript` with `enable`, `install`, `service`, `users`, `timer`, and `package` fields.
@@ -48,6 +48,8 @@ config.services = {
## Module Categories and Active Hosts ## Module Categories and Active Hosts
- Module categories: apps, dev, scripts, servers, services, shell, websites, network, users, nix. Factories sit in `modules/factories/` and are imported explicitly; patch artifacts live at the repo root in `patches/`. - Module categories: apps, dev, scripts, servers, services, shell, websites, network, users, nix. Factories sit in `modules/factories/` and are imported explicitly; patch artifacts live at the repo root in `patches/`.
- Split-module preference: For categories that need both system and Home Manager behavior, co-locate both surfaces in `modules/<category>/<name>/nixos.nix` and `modules/<category>/<name>/home.nix`. Keep helpers local to that directory only when they are feature-specific; otherwise promote them into shared helpers/factories.
- User config split: Personal configs may also split across `config/<name>.nix` for NixOS-side account/secrets state and `config/<name>-home.nix` for Home Manager-only state imported from the user home module.
- Active hosts: `workstation`, `server`, `miniserver`, `galaxy`, `emacs`, `vps`. Host roles and secure status are defined in `hosts/<name>/configuration.nix` and toggles in `hosts/<name>/toggles.nix`. - Active hosts: `workstation`, `server`, `miniserver`, `galaxy`, `emacs`, `vps`. Host roles and secure status are defined in `hosts/<name>/configuration.nix` and toggles in `hosts/<name>/toggles.nix`.
## Precedence and Conflict Resolution ## Precedence and Conflict Resolution
@@ -55,7 +57,7 @@ config.services = {
- Conflict handling steps: identify the divergent rule, cite the source files, decide the authoritative rule per this constitution, update both the source file and the relevant doc, and record the decision and timestamp. - Conflict handling steps: identify the divergent rule, cite the source files, decide the authoritative rule per this constitution, update both the source file and the relevant doc, and record the decision and timestamp.
## Maintenance Triggers and Update Process ## Maintenance Triggers and Update Process
- Triggers: New factory/helper, new module category, new host, new toggle set, new proxy rule, new secret category/file, change to `my.mainServer` or `my.ips`, stylix scheme changes, or new auto-import filters. - Triggers: New factory/helper, new module category, new host, new toggle set, new proxy rule, new secret category/file, change to `my.mainServer` or `my.ips`, stylix scheme changes, or new auto-import filters/import trees.
- Update flow: (1) Amend the relevant module or toggle files; (2) Update `docs/constitution.md` for rules/terminology changes; (3) Update playbooks under `docs/playbooks/` affected by the change; (4) Update `docs/reference/index.md` for navigation paths; (5) Note the decision in `specs/001-ai-docs/research.md` and refresh `quickstart.md` if discoverability shifts. - Update flow: (1) Amend the relevant module or toggle files; (2) Update `docs/constitution.md` for rules/terminology changes; (3) Update playbooks under `docs/playbooks/` affected by the change; (4) Update `docs/reference/index.md` for navigation paths; (5) Note the decision in `specs/001-ai-docs/research.md` and refresh `quickstart.md` if discoverability shifts.
- Validation: Confirm discoverability within two clicks (constitution → reference map/playbook), secrets map completeness, and alignment with success criteria SC-001SC-004. - Validation: Confirm discoverability within two clicks (constitution → reference map/playbook), secrets map completeness, and alignment with success criteria SC-001SC-004.
@@ -64,6 +66,7 @@ config.services = {
- Reference map: `docs/reference/index.md` (paths, hosts, secrets, proxies, stylix) - Reference map: `docs/reference/index.md` (paths, hosts, secrets, proxies, stylix)
- MCP server reference: `docs/reference/mcp-server.md` (tools, invocation, sync checks) - MCP server reference: `docs/reference/mcp-server.md` (tools, invocation, sync checks)
- Playbook: `docs/playbooks/add-module.md` — add a module in the right category and confirm auto-import. - Playbook: `docs/playbooks/add-module.md` — add a module in the right category and confirm auto-import.
- Playbook: `docs/playbooks/split-home-manager.md` — migrate a mixed module into paired `nixos.nix` and `home.nix` files.
- Playbook: `docs/playbooks/add-server.md` — add a reverse-proxied server via `mkserver` and proxy rules. - Playbook: `docs/playbooks/add-server.md` — add a reverse-proxied server via `mkserver` and proxy rules.
- Playbook: `docs/playbooks/add-script.md` — add a script unit via `mkscript` with install/service/timer options. - Playbook: `docs/playbooks/add-script.md` — add a script unit via `mkscript` with install/service/timer options.
- Playbook: `docs/playbooks/add-host-toggle.md` — add or update host toggle maps under `hosts/<name>/toggles.nix`. - Playbook: `docs/playbooks/add-host-toggle.md` — add or update host toggle maps under `hosts/<name>/toggles.nix`.

View File

@@ -5,14 +5,14 @@
- Prerequisites: Identify target host(s) and toggle category; confirm `my.secureHost` if secrets are involved. - Prerequisites: Identify target host(s) and toggle category; confirm `my.secureHost` if secrets are involved.
- Inputs: Module name, category (apps/dev/scripts/servers/services/shell/network), required options, secret needs, proxy requirements if server-facing. - Inputs: Module name, category (apps/dev/scripts/servers/services/shell/network), required options, secret needs, proxy requirements if server-facing.
- Steps: - Steps:
1. Choose the category path from `docs/reference/index.md` and create `modules/<category>/<name>.nix` (auto-import picks it up; avoid names filtered out such as `librewolf.nix`). 1. Choose the category path from `docs/reference/index.md`. Prefer `modules/<category>/<name>/nixos.nix` plus `modules/<category>/<name>/home.nix` when the feature spans both system and Home Manager; use a legacy flat `modules/<category>/<name>.nix` only for NixOS-only modules or temporary migration work.
2. Define options under `my.<category>` or reuse factories (`mkserver` for servers, `mkscript` for scripts) instead of hand-rolled patterns. 2. Define options under `my.<category>` or reuse factories (`mkserver` for servers, `mkscript` for scripts) instead of hand-rolled patterns.
3. If the module needs secrets, guard references with `lib.mkIf config.my.secureHost` and map them to the correct secrets file (see secrets map). 3. If the module needs secrets, guard references with `lib.mkIf config.my.secureHost` and map them to the correct secrets file (see secrets map).
4. For networked services, align host selection with `my.mainServer` and `my.ips`; enable reverse proxy via `enableProxy` when applicable. 4. For networked services, align host selection with `my.mainServer` and `my.ips`; enable reverse proxy via `enableProxy` when applicable.
5. Wire toggles for target hosts in `hosts/<host>/toggles.nix`, ensuring users/groups and containers/proxy flags are set. 5. Wire toggles for target hosts in `hosts/<host>/toggles.nix`, ensuring users/groups and containers/proxy flags are set.
- Validation: - Validation:
- Module loads without extra imports (auto-import applies). - Module loads without extra imports (`nixos.nix` and `home.nix` are auto-discovered; legacy flat modules remain supported).
- Toggle wiring matches intended hosts; secureHost gating present for secrets. - Toggle wiring matches intended hosts; secureHost gating present for secrets.
- Proxy and port choices align with `my.mainServer`, `my.ips`, and firewall rules. - Proxy and port choices align with `my.mainServer`, `my.ips`, and firewall rules.
- Outputs: New module file and updated host toggles if required. - Outputs: New module file and updated host toggles if required.
- References: `docs/constitution.md` (Module Categories, Secrets Map, Main server and proxies), `docs/reference/index.md` (Module Directories, Proxy rules, Secrets Map) - References: `docs/constitution.md` (Module Categories, Secrets Map, Main server and proxies), `docs/reference/index.md` (Module Directories, Auto-Import Rules, Proxy rules, Secrets Map)

View File

@@ -0,0 +1,19 @@
# Playbook: Split a Mixed Module into NixOS and Home Manager
- Name: Split a feature module into `nixos.nix` and `home.nix`
- Purpose: Keep category-first organization while separating system concerns from Home Manager concerns for standalone homes and future Darwin usage.
- Prerequisites: Identify the feature path, current toggle shape under `my.*`, and whether the module has shared helpers that should stay adjacent or move into a factory.
- Inputs: Existing mixed module path, target category/name, host toggle impact, Home Manager consumers, secrets/proxy requirements.
- Steps:
1. Create `modules/<category>/<name>/nixos.nix` for NixOS-only concerns such as `users.users`, `environment.systemPackages`, `services.*`, `programs.*`, firewall rules, and SOPS-backed system resources.
2. Create `modules/<category>/<name>/home.nix` for Home Manager concerns such as `programs.*`, `xdg.*`, `home.file.*`, `services.*` within Home Manager, and per-user shell aliases/config files.
3. Keep the toggle namespace aligned across both files so the same feature name remains recognizable. During migration, duplicate the option schema if needed rather than keeping Home Manager logic embedded in the NixOS module.
4. If the feature has truly shared logic, extract it into a local helper file within the feature directory or promote it into `modules/factories/` when reused across features.
5. Remove the legacy flat module only after the paired files evaluate cleanly and all references are updated.
- Validation:
- `modules/modules.nix` discovers the features `nixos.nix`.
- `config/base.nix` registers `modules/home-manager.nix` in `home-manager.sharedModules`, and that loader discovers the features `home.nix`.
- System-only settings no longer reference `home-manager.users.*`.
- Home Manager settings no longer depend on `osConfig` unless that coupling is intentional and documented.
- Outputs: Split module directory, retained toggle shape, and updated docs if the feature introduces new structure patterns.
- References: `docs/constitution.md` (Repository Overview, Terminology and Naming Standards, Maintenance Triggers), `docs/reference/index.md` (Module Directories, Auto-Import Rules)

View File

@@ -1,24 +1,33 @@
# Reference Map # Reference Map
## Module Directories ## Module Directories
- apps → `modules/apps/` (desktop/workstation apps, auto-imported) - apps → `modules/apps/` (desktop/workstation apps; supports legacy flat modules and preferred split feature directories)
- dev → `modules/dev/` (language toolchains and dev shells, auto-imported) - dev → `modules/dev/` (language toolchains and dev shells; supports legacy flat modules and preferred split feature directories)
- scripts → `modules/scripts/` (script units built via `mkscript`, auto-imported) - scripts → `modules/scripts/` (script units built via `mkscript`; supports legacy flat modules and preferred split feature directories)
- servers → `modules/servers/` (reverse-proxied services built via `mkserver`) - servers → `modules/servers/` (reverse-proxied services built via `mkserver`; supports legacy flat modules and preferred split feature directories)
- services → `modules/services/` (supporting services like syncthing, wireguard) - services → `modules/services/` (supporting services like syncthing, wireguard; supports legacy flat modules and preferred split feature directories)
- shell → `modules/shell/` (shell customizations and CLI tooling) - shell → `modules/shell/` (shell customizations and CLI tooling; supports legacy flat modules and preferred split feature directories)
- websites → `modules/websites/` (static nginx vhosts for portfolio/blog and reports) - websites → `modules/websites/` (static nginx vhosts for portfolio/blog and reports; supports legacy flat modules and preferred split feature directories)
- network → `modules/network/` (networking rules, firewall helpers) - network → `modules/network/` (networking rules, firewall helpers; supports legacy flat modules and preferred split feature directories)
- users → `modules/users/` (user-related options) - users → `modules/users/` (user-related options)
- nix → `modules/nix/` (Nix configuration and helpers) - nix → `modules/nix/` (Nix configuration and helpers)
- factories → `modules/factories/` (`mkserver.nix`, `mkscript.nix` shared helpers) - factories → `modules/factories/` (`mkserver.nix`, `mkscript.nix` shared helpers)
- home-manager loader → `modules/home-manager.nix` (discovers nested `home.nix` files under `modules/`)
## Root Directories ## Root Directories
- patches → `patches/` (patch artifacts referenced by modules) - patches → `patches/` (patch artifacts referenced by modules)
## User Config Split
- System-side user config: `config/<name>.nix` for NixOS user accounts, host secrets, groups, and other OS-owned state.
- Home-side user config: `config/<name>-home.nix` for Home Manager-only files, shell/program configuration, and per-user match blocks.
- Current example: `config/jawz.nix` and `config/jawz-home.nix`.
## Auto-Import Rules ## Auto-Import Rules
- Source: `modules/modules.nix` uses `inputs.self.lib.autoImport` to load `.nix` files from module directories. - Source: `modules/modules.nix` uses `inputs.self.lib.autoImport` for legacy flat `.nix` files and `inputs.self.lib.autoImportLeaf` for nested `nixos.nix` files.
- Filter: Excludes `librewolf.nix`; all other `.nix` files in target dirs are loaded automatically. - Home Manager source: `config/base.nix` registers `modules/home-manager.nix` in `home-manager.sharedModules`, and that module uses `inputs.self.lib.autoImportLeaf` to discover nested `home.nix` files anywhere under `modules/`.
- Implication: Place new modules in the correct category directory with a `.nix` filename; no manual import wiring required unless adding a new factory. Patch artifacts under `patches/` are not auto-imported. - Filter: Legacy flat auto-import excludes `librewolf.nix`; nested split modules are discovered by exact leaf name (`nixos.nix` or `home.nix`).
- Preferred layout: `modules/<category>/<name>/nixos.nix` and `modules/<category>/<name>/home.nix`.
- Migration rule: Legacy flat `modules/<category>/<name>.nix` modules remain supported while features are moved into split directories.
- Implication: Place new dual-surface modules in a feature directory so NixOS and Home Manager stay adjacent; no manual import wiring is required unless adding a new factory.
## Hosts and Roles ## Hosts and Roles
- Configs: `hosts/<name>/configuration.nix` with toggles in `hosts/<name>/toggles.nix`. - Configs: `hosts/<name>/configuration.nix` with toggles in `hosts/<name>/toggles.nix`.
@@ -58,6 +67,7 @@
## Playbooks and Templates ## Playbooks and Templates
- Playbook template: `docs/playbooks/template.md` - Playbook template: `docs/playbooks/template.md`
- Playbook: `docs/playbooks/add-module.md` — add a module in the right category and confirm auto-import. - Playbook: `docs/playbooks/add-module.md` — add a module in the right category and confirm auto-import.
- Playbook: `docs/playbooks/split-home-manager.md` — migrate a mixed module into paired `nixos.nix` and `home.nix` files.
- Playbook: `docs/playbooks/add-server.md` — add a reverse-proxied server via `mkserver` and proxy rules. - Playbook: `docs/playbooks/add-server.md` — add a reverse-proxied server via `mkserver` and proxy rules.
- Playbook: `docs/playbooks/add-script.md` — add a script unit via `mkscript` with install/service/timer options. - Playbook: `docs/playbooks/add-script.md` — add a script unit via `mkscript` with install/service/timer options.
- Playbook: `docs/playbooks/add-host-toggle.md` — add or update host toggle maps under `hosts/<name>/toggles.nix`. - Playbook: `docs/playbooks/add-host-toggle.md` — add or update host toggle maps under `hosts/<name>/toggles.nix`.
@@ -69,7 +79,7 @@
- MCP server reference: `docs/reference/mcp-server.md` (tool catalog, `nixos-mcp` wrapper, invocation, sync-docs) - MCP server reference: `docs/reference/mcp-server.md` (tool catalog, `nixos-mcp` wrapper, invocation, sync-docs)
## Quick Audit Checklist ## Quick Audit Checklist
- Module coverage: All categories (apps, dev, scripts, servers, services, shell, websites, network, users, nix) have corresponding entries and auto-import rules; `patches/` is documented as a root directory. - Module coverage: All categories (apps, dev, scripts, servers, services, shell, websites, network, users, nix) have corresponding entries and auto-import rules for both legacy flat modules and split `nixos.nix`/`home.nix` modules; `patches/` is documented as a root directory.
- Host coverage: Active hosts listed with roles and secureHost status; `mainServer` noted. - Host coverage: Active hosts listed with roles and secureHost status; `mainServer` noted.
- Proxy rules: `enableProxy` usage, proxy helper selection, and `my.ips` mappings documented. - Proxy rules: `enableProxy` usage, proxy helper selection, and `my.ips` mappings documented.
- Secrets map: Every secrets file and secureHost gating captured; new secret types aligned to file purposes. - Secrets map: Every secrets file and secureHost gating captured; new secret types aligned to file purposes.

View File

@@ -1,66 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
krisp-settings = {
libraries = builtins.attrValues {
inherit (pkgs.python3Packages)
capstone
pyelftools
;
};
flakeIgnore = [
"E501" # line too long (82 > 79 characters)
"F403" # 'from module import *' used; unable to detect undefined names
"F405" # name may be undefined, or defined from star imports: module
];
};
krisp-patch = builtins.readFile (
pkgs.fetchurl {
url = "https://pastebin.com/raw/8tQDsMVd";
sha256 = "sha256-IdXv0MfRG1/1pAAwHLS2+1NESFEz2uXrbSdvU9OvdJ8=";
}
);
krisp-patcher = pkgs.writers.writePython3Bin "krisp-patcher" krisp-settings krisp-patch;
in
{
options.my.apps.internet = {
enable = lib.mkEnableOption "internet browsers and communication apps";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.apps;
description = "Users to install internet packages for";
};
};
config = lib.mkIf config.my.apps.internet.enable {
home-manager.users = inputs.self.lib.mkHomeManagerUsers lib config.my.apps.internet.users (_user: {
programs.librewolf = import ./librewolf.nix;
});
programs.geary.enable = true;
users.users =
let
packages = builtins.attrValues {
# inherit (inputs.zen-browser.packages.x86_64-linux) twilight;
inherit krisp-patcher;
inherit (pkgs)
# thunderbird # email client
warp # transfer files with based ppl
nextcloud-client # self-hosted google-drive alternative
fragments # beautiful torrent client
tor-browser # dark web, so dark!
telegram-desktop # furry chat
nicotine-plus # remember Ares?
discord # :3
vdhcoapp # video download helper assistant
nextcloud-talk-desktop # nextcloud talk client
fractal # matrix client
;
};
in
inputs.self.lib.mkUserPackages lib config.my.apps.internet.users packages;
};
}

View File

@@ -0,0 +1,68 @@
{
config,
inputs,
lib,
osConfig ? null,
pkgs,
...
}:
let
hm = inputs.self.lib.hmModule {
inherit
config
inputs
osConfig
;
optionPath = [
"apps"
"internet"
];
};
cfg = config.my.apps.internet;
krisp-settings = {
libraries = builtins.attrValues {
inherit (pkgs.python3Packages)
capstone
pyelftools
;
};
flakeIgnore = [
"E501"
"F403"
"F405"
];
};
krisp-patch = builtins.readFile (
pkgs.fetchurl {
url = "https://pastebin.com/raw/8tQDsMVd";
sha256 = "sha256-IdXv0MfRG1/1pAAwHLS2+1NESFEz2uXrbSdvU9OvdJ8=";
}
);
krisp-patcher = pkgs.writers.writePython3Bin "krisp-patcher" krisp-settings krisp-patch;
in
{
options.my.apps.internet.enable = lib.mkEnableOption "internet browsers and communication apps";
config = lib.mkMerge [
{
my.apps.internet.enable = lib.mkDefault hm.enabledByDefault;
}
(lib.mkIf cfg.enable {
programs.librewolf = import ../librewolf.nix;
home.packages = builtins.attrValues {
inherit krisp-patcher;
inherit (pkgs)
warp
nextcloud-client
fragments
tor-browser
telegram-desktop
nicotine-plus
discord
vdhcoapp
nextcloud-talk-desktop
fractal
;
};
})
];
}

View File

@@ -0,0 +1,19 @@
{
config,
inputs,
lib,
...
}:
{
options.my.apps.internet = {
enable = lib.mkEnableOption "internet browsers and communication apps";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.apps;
description = "Users to install internet packages for";
};
};
config = lib.mkIf config.my.apps.internet.enable {
programs.geary.enable = true;
};
}

View File

@@ -1,88 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
{
options.my.emacs = {
enable = lib.mkEnableOption "Doom Emacs configuration";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install Emacs packages for";
};
};
config = lib.mkIf config.my.emacs.enable {
home-manager.users = inputs.self.lib.mkHomeManagerUsers lib config.my.emacs.users (_user: {
xdg.dataFile = {
"doom/templates/events.org".source = ../../dotfiles/doom/templates/events.org;
"doom/templates/default.org".source = ../../dotfiles/doom/templates/default.org;
"doom/templates/programming.org".source = ../../dotfiles/doom/templates/programming.org;
};
services.lorri.enable = true;
programs.${config.my.shell.type}.shellAliases =
inputs.self.lib.mergeAliases inputs.self.lib.commonAliases
{
edit = "emacsclient -t";
e = "edit";
};
});
users.users =
let
packages = builtins.attrValues {
inherit (pkgs.xorg) xwininfo;
inherit (pkgs)
#emacs everywhere
xdotool
xclip
wl-clipboard-rs
fd # modern find, faster searches
fzf # fuzzy finder! super cool and useful
ripgrep # modern grep
tree-sitter # code parsing based on symbols and shit, I do not get it
graphviz # graphs
tetex # export pdf
languagetool # proofreader for English
# lsps
yaml-language-server
markdownlint-cli
;
inherit (pkgs.nodePackages)
vscode-json-languageserver
prettier # multi-language linter
;
};
in
inputs.self.lib.mkUserPackages lib config.my.emacs.users packages;
services.emacs = {
enable = true;
defaultEditor = true;
package = pkgs.emacsWithDoom {
doomDir = ../../dotfiles/doom;
doomLocalDir = "/home/${inputs.self.lib.getFirstUser config.my.emacs.users}/.local/share/nix-doom";
tangleArgs = "--all config.org";
extraPackages =
epkgs:
let
inherit
(config.home-manager.users.${inputs.self.lib.getFirstUser config.my.emacs.users}.programs.emacs)
extraPackages
extraConfig
;
extra = extraPackages epkgs;
themes = lib.optional config.my.stylix.enable [
(epkgs.trivialBuild {
pname = "stylix-theme";
src = pkgs.writeText "stylix-theme.el" extraConfig;
version = "0.1.0";
packageRequires = extra;
})
];
in
extra ++ themes;
};
};
};
}

View File

@@ -0,0 +1,44 @@
{
lib,
pkgs,
stylixEnabled,
emacsExtraConfig,
emacsExtraPackages,
}:
{
packages = builtins.attrValues {
inherit (pkgs.xorg) xwininfo;
inherit (pkgs)
xdotool
xclip
wl-clipboard-rs
fd
fzf
ripgrep
tree-sitter
graphviz
tetex
languagetool
yaml-language-server
markdownlint-cli
;
inherit (pkgs.nodePackages)
vscode-json-languageserver
prettier
;
};
extraPackages =
epkgs:
let
extra = emacsExtraPackages epkgs;
themes = lib.optional stylixEnabled [
(epkgs.trivialBuild {
pname = "stylix-theme";
src = pkgs.writeText "stylix-theme.el" emacsExtraConfig;
version = "0.1.0";
packageRequires = extra;
})
];
in
extra ++ themes;
}

View File

@@ -0,0 +1,61 @@
{
config,
inputs,
lib,
osConfig ? null,
pkgs,
...
}:
let
shellType = inputs.self.lib.hmShellType config osConfig;
hm = inputs.self.lib.hmModule {
inherit
config
inputs
osConfig
;
optionPath = [ "emacs" ];
};
cfg = config.my.emacs;
emacs = import ./common.nix {
inherit lib pkgs;
stylixEnabled = if osConfig == null then false else osConfig.my.stylix.enable;
emacsExtraConfig = config.programs.emacs.extraConfig;
emacsExtraPackages = config.programs.emacs.extraPackages;
};
in
{
imports = [ inputs.doom-emacs.homeModule ];
options.my.emacs.enable = lib.mkEnableOption "Doom Emacs configuration";
config = lib.mkMerge [
{
my.emacs.enable = lib.mkDefault hm.enabledByDefault;
}
(lib.mkIf cfg.enable {
home.packages = emacs.packages;
xdg.dataFile = {
"doom/templates/events.org".source = ../../../dotfiles/doom/templates/events.org;
"doom/templates/default.org".source = ../../../dotfiles/doom/templates/default.org;
"doom/templates/programming.org".source = ../../../dotfiles/doom/templates/programming.org;
};
services = {
lorri.enable = true;
emacs = {
enable = true;
defaultEditor = true;
};
};
programs.${shellType}.shellAliases = inputs.self.lib.mergeAliases inputs.self.lib.commonAliases {
edit = "emacsclient -t";
e = "edit";
};
programs.doom-emacs = {
enable = true;
doomDir = ../../../dotfiles/doom;
doomLocalDir = "${config.xdg.dataHome}/nix-doom";
tangleArgs = "--all config.org";
inherit (emacs) extraPackages;
};
})
];
}

View File

@@ -0,0 +1,16 @@
{
config,
inputs,
lib,
...
}:
{
options.my.emacs = {
enable = lib.mkEnableOption "Doom Emacs configuration";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install Emacs packages for";
};
};
}

View File

@@ -1,60 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
packages = builtins.attrValues {
inherit (pkgs) nodejs; # Node.js runtime
inherit (pkgs.nodePackages) pnpm; # Fast package manager alternative to npm
};
in
{
options = {
my.dev.javascript = {
enable = lib.mkEnableOption "Install JavaScript tooling globally";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install JavaScript packages for";
};
};
devShells.javascript = lib.mkOption {
type = lib.types.package;
default = pkgs.mkShell {
inherit packages;
name = "javascript-dev-shell";
shellHook = ''
echo "📦 JavaScript dev environment"
'';
};
description = "JavaScript/Node development shell with npm/pnpm support";
};
};
config = lib.mkMerge [
(lib.mkIf config.my.dev.javascript.enable {
users.users = inputs.self.lib.mkUserAttrs lib config.my.dev.javascript.users { inherit packages; };
})
{
home-manager.users = inputs.self.lib.mkHomeManagerUsers lib config.my.dev.javascript.users (_user: {
xdg.configFile = {
"npm/npmrc".source = ../../dotfiles/npmrc;
"configstore/update-notifier-npm-check.json".text = builtins.toJSON {
optOut = false;
lastUpdateCheck = 1646662583446;
};
};
});
environment.variables = {
NPM_CONFIG_USERCONFIG = "\${XDG_CONFIG_HOME}/npm/npmrc";
PNPM_HOME = "\${XDG_DATA_HOME}/pnpm";
PATH = [
"\${XDG_DATA_HOME}/npm/bin"
"\${XDG_DATA_HOME}/pnpm"
];
};
}
];
}

View File

@@ -0,0 +1,25 @@
{ pkgs }:
let
packages = builtins.attrValues {
inherit (pkgs) nodejs;
inherit (pkgs.nodePackages) pnpm;
};
in
{
inherit packages;
devShell = pkgs.mkShell {
inherit packages;
name = "javascript-dev-shell";
shellHook = ''
echo "📦 JavaScript dev environment"
'';
};
sessionVariables = {
NPM_CONFIG_USERCONFIG = "\${XDG_CONFIG_HOME}/npm/npmrc";
PNPM_HOME = "\${XDG_DATA_HOME}/pnpm";
};
sessionPath = [
"\${XDG_DATA_HOME}/npm/bin"
"\${XDG_DATA_HOME}/pnpm"
];
}

View File

@@ -0,0 +1,43 @@
{
config,
inputs,
lib,
osConfig ? null,
pkgs,
...
}:
let
hm = inputs.self.lib.hmModule {
inherit
config
inputs
osConfig
;
optionPath = [
"dev"
"javascript"
];
};
cfg = config.my.dev.javascript;
javascript = import ./common.nix { inherit pkgs; };
in
{
options.my.dev.javascript.enable = lib.mkEnableOption "Install JavaScript tooling globally";
config = lib.mkMerge [
{
my.dev.javascript.enable = lib.mkDefault hm.enabledByDefault;
}
(lib.mkIf cfg.enable {
home.packages = javascript.packages;
xdg.configFile = {
"npm/npmrc".source = ../../../dotfiles/npmrc;
"configstore/update-notifier-npm-check.json".text = builtins.toJSON {
optOut = false;
lastUpdateCheck = 1646662583446;
};
};
home.sessionVariables = javascript.sessionVariables;
home.sessionPath = javascript.sessionPath;
})
];
}

View File

@@ -0,0 +1,27 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
javascript = import ./common.nix { inherit pkgs; };
in
{
options = {
my.dev.javascript = {
enable = lib.mkEnableOption "Install JavaScript tooling globally";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install JavaScript packages for";
};
};
devShells.javascript = lib.mkOption {
type = lib.types.package;
default = javascript.devShell;
description = "JavaScript/Node development shell with npm/pnpm support";
};
};
}

View File

@@ -1,60 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
shellType = config.my.shell.type;
packages = builtins.attrValues {
inherit (pkgs)
nixfmt-rfc-style # formatting
cachix # binary cache management
nixd # language server for Nix
deadnix # detext unused/uneeded dependencies
statix # linter for Nix expressions
mcp-nixos # mcp server
;
};
in
{
options = {
my.dev.nix = {
enable = lib.mkEnableOption "Install Nix tooling globally";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install Nix packages for";
};
};
devShells.nix = lib.mkOption {
type = lib.types.package;
default = pkgs.mkShell {
inherit packages;
name = "nix-dev-shell";
shellHook = ''
echo " Nix dev environment"
'';
};
description = "Nix/NixOS development shell with formatter, linter, LSP, and Cachix";
};
};
config = lib.mkIf config.my.dev.nix.enable {
users.users = inputs.self.lib.mkUserAttrs lib config.my.dev.nix.users { inherit packages; };
home-manager.users = inputs.self.lib.mkHomeManagerUsers lib config.my.dev.nix.users (_user: {
programs.${shellType}.shellAliases = inputs.self.lib.mergeAliases inputs.self.lib.commonAliases {
nixformat = ''
deadnix -e && \
nix run nixpkgs#nixfmt-tree && \
statix fix
'';
nix-push-cache = ''
nix build $NH_FLAKE#nixosConfigurations.${config.networking.hostName}.config.system.build.toplevel \
--print-out-paths --fallback --max-jobs 100 --cores 0 |
nix run nixpkgs#attic-client -- push lan:nixos --stdin
'';
};
});
};
}

View File

@@ -0,0 +1,45 @@
{
pkgs,
hostName ? null,
}:
let
packages = builtins.attrValues {
inherit (pkgs)
nixfmt-rfc-style
cachix
nixd
deadnix
statix
mcp-nixos
;
};
in
{
inherit packages;
devShell = pkgs.mkShell {
inherit packages;
name = "nix-dev-shell";
shellHook = ''
echo " Nix dev environment"
'';
};
shellAliases = {
nixformat = ''
deadnix -e && \
nix run nixpkgs#nixfmt-tree && \
statix fix
'';
}
// (
if hostName == null then
{ }
else
{
nix-push-cache = ''
nix build $NH_FLAKE#nixosConfigurations.${hostName}.config.system.build.toplevel \
--print-out-paths --fallback --max-jobs 100 --cores 0 |
nix run nixpkgs#attic-client -- push lan:nixos --stdin
'';
}
);
}

40
modules/dev/nix/home.nix Normal file
View File

@@ -0,0 +1,40 @@
{
config,
inputs,
lib,
osConfig ? null,
pkgs,
...
}:
let
shellType = inputs.self.lib.hmShellType config osConfig;
hm = inputs.self.lib.hmModule {
inherit
config
inputs
osConfig
;
optionPath = [
"dev"
"nix"
];
};
cfg = config.my.dev.nix;
nix = import ./common.nix {
inherit pkgs;
hostName = if osConfig == null then null else osConfig.networking.hostName;
};
in
{
options.my.dev.nix.enable = lib.mkEnableOption "Install Nix tooling globally";
config = lib.mkMerge [
{
my.dev.nix.enable = lib.mkDefault hm.enabledByDefault;
}
(lib.mkIf cfg.enable {
home.packages = nix.packages;
programs.${shellType}.shellAliases =
inputs.self.lib.mergeAliases inputs.self.lib.commonAliases nix.shellAliases;
})
];
}

30
modules/dev/nix/nixos.nix Normal file
View File

@@ -0,0 +1,30 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
nix = import ./common.nix {
inherit pkgs;
inherit (config.networking) hostName;
};
in
{
options = {
my.dev.nix = {
enable = lib.mkEnableOption "Install Nix tooling globally";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install Nix packages for";
};
};
devShells.nix = lib.mkOption {
type = lib.types.package;
default = nix.devShell;
description = "Nix/NixOS development shell with formatter, linter, LSP, and Cachix";
};
};
}

View File

@@ -1,66 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
python = pkgs.python3.withPackages (
ps:
builtins.attrValues {
inherit (ps)
black # Python code formatter
editorconfig # follow rules of contributin
flake8 # wraper for pyflakes, pycodestyle and mccabe
isort # sort Python imports
pyflakes # checks source code for errors
pylint # bug and style checker for python
pytest # tests
speedtest-cli # check internet speed from the comand line
;
}
);
packages = builtins.attrValues {
inherit python;
inherit (pkgs)
pipenv # python development workflow for humans
pyright # LSP
;
};
in
{
options = {
my.dev.python = {
enable = lib.mkEnableOption "Install Python tools globally";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install Python packages for";
};
};
devShells.python = lib.mkOption {
type = lib.types.package;
default = pkgs.mkShell {
inherit packages;
name = "python-dev-shell";
shellHook = ''
echo "🐍 Python dev environment"
which python
'';
description = "Python development shell";
};
};
};
config = lib.mkMerge [
(lib.mkIf config.my.dev.python.enable {
users.users = inputs.self.lib.mkUserAttrs lib config.my.dev.python.users { inherit packages; };
})
{
home-manager.users = inputs.self.lib.mkHomeManagerUsers lib config.my.dev.python.users (_user: {
xdg.configFile."python/pythonrc".source = ../../dotfiles/pythonrc;
});
environment.variables.PYTHONSTARTUP = "\${XDG_CONFIG_HOME}/python/pythonrc";
}
];
}

View File

@@ -0,0 +1,31 @@
{ pkgs }:
let
packages = builtins.attrValues {
inherit (pkgs)
pipenv
pyright
;
inherit (pkgs.python3Packages)
black
editorconfig
flake8
isort
pyflakes
pylint
pytest
speedtest-cli
;
};
in
{
inherit packages;
devShell = pkgs.mkShell {
inherit packages;
name = "python-dev-shell";
shellHook = ''
echo "🐍 Python dev environment"
which python
'';
description = "Python development shell";
};
}

View File

@@ -0,0 +1,36 @@
{
config,
inputs,
lib,
osConfig ? null,
pkgs,
...
}:
let
python = import ./common.nix { inherit pkgs; };
hm = inputs.self.lib.hmModule {
inherit
config
inputs
osConfig
;
optionPath = [
"dev"
"python"
];
};
cfg = config.my.dev.python;
in
{
options.my.dev.python.enable = lib.mkEnableOption "Install Python tools globally";
config = lib.mkMerge [
{
my.dev.python.enable = lib.mkDefault hm.enabledByDefault;
}
(lib.mkIf cfg.enable {
home.packages = python.packages;
xdg.configFile."python/pythonrc".source = ../../../dotfiles/pythonrc;
home.sessionVariables.PYTHONSTARTUP = "\${XDG_CONFIG_HOME}/python/pythonrc";
})
];
}

View File

@@ -0,0 +1,26 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
python = import ./common.nix { inherit pkgs; };
in
{
options = {
my.dev.python = {
enable = lib.mkEnableOption "Install Python tools globally";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.dev;
description = "Users to install Python packages for";
};
};
devShells.python = lib.mkOption {
type = lib.types.package;
default = python.devShell;
};
};
}

4
modules/home-manager.nix Normal file
View File

@@ -0,0 +1,4 @@
{ inputs, ... }:
{
imports = inputs.self.lib.autoImportLeaf ./. "home.nix";
}

View File

@@ -10,13 +10,21 @@ in
{ {
imports = imports =
inputs.self.lib.autoImport ./apps filterNames inputs.self.lib.autoImport ./apps filterNames
++ inputs.self.lib.autoImportLeaf ./apps "nixos.nix"
++ inputs.self.lib.autoImport ./dev filterNames ++ inputs.self.lib.autoImport ./dev filterNames
++ inputs.self.lib.autoImportLeaf ./dev "nixos.nix"
++ inputs.self.lib.autoImport ./scripts filterNames ++ inputs.self.lib.autoImport ./scripts filterNames
++ inputs.self.lib.autoImportLeaf ./scripts "nixos.nix"
++ inputs.self.lib.autoImport ./servers filterNames ++ inputs.self.lib.autoImport ./servers filterNames
++ inputs.self.lib.autoImportLeaf ./servers "nixos.nix"
++ inputs.self.lib.autoImport ./services filterNames ++ inputs.self.lib.autoImport ./services filterNames
++ inputs.self.lib.autoImportLeaf ./services "nixos.nix"
++ inputs.self.lib.autoImport ./shell filterNames ++ inputs.self.lib.autoImport ./shell filterNames
++ inputs.self.lib.autoImportLeaf ./shell "nixos.nix"
++ inputs.self.lib.autoImport ./websites filterNames ++ inputs.self.lib.autoImport ./websites filterNames
++ inputs.self.lib.autoImportLeaf ./websites "nixos.nix"
++ inputs.self.lib.autoImport ./network filterNames ++ inputs.self.lib.autoImport ./network filterNames
++ inputs.self.lib.autoImportLeaf ./network "nixos.nix"
++ [ ++ [
./factories/mkscript.nix ./factories/mkscript.nix
./nix/build.nix ./nix/build.nix

View File

@@ -1,112 +0,0 @@
{
inputs,
pkgs,
lib,
config,
...
}:
{
options.my.units = {
download.enable = lib.mkEnableOption "media download automation scripts";
downloadManga.enable = lib.mkEnableOption "manga download automation";
};
config =
let
inherit (inputs.jawz-scripts.packages.x86_64-linux) download;
gallerySecretsPath = lib.attrByPath [ "sops" "secrets" "gallery-dl/secrets" "path" ] null config;
wrappedDownload =
if gallerySecretsPath != null then
pkgs.symlinkJoin {
name = "download-with-secrets";
paths = [ download ];
buildInputs = [ pkgs.makeWrapper ];
postBuild = ''
wrapProgram $out/bin/download --run 'if [ -r "${gallerySecretsPath}" ]; then set -a; source "${gallerySecretsPath}"; set +a; fi'
'';
}
else
download;
in
{
home-manager.users.jawz.programs.${config.my.shell.type}.shellAliases =
inputs.self.lib.mergeAliases inputs.self.lib.commonAliases
{
dl = "${wrappedDownload}/bin/download -u jawz -i";
};
systemd.user = {
services =
let
mkDownloadService = desc: execStartCmd: {
restartIfChanged = true;
description = "Downloads ${desc}";
wantedBy = [ "default.target" ];
path = [ pkgs.bash ];
serviceConfig = {
TimeoutStartSec = 2000;
TimeoutStopSec = 2000;
Restart = "on-failure";
RestartSec = 30;
ExecStart = "${wrappedDownload}/bin/download ${execStartCmd}";
}
// lib.optionalAttrs (gallerySecretsPath != null) {
EnvironmentFile = gallerySecretsPath;
};
};
in
{
tuhmayto = lib.mkIf config.my.units.download.enable (
mkDownloadService "tuhmayto stuff" ''
-u jawz -i https://x.com/tuhmayto/media \
https://www.furaffinity.net/user/tuhmayto/ \
https://bsky.app/profile/tumayto.bsky.social''
);
"download@" = lib.mkIf (config.my.units.download.enable || config.my.units.downloadManga.enable) (
mkDownloadService "post from multiple sources" "%I"
);
"instagram@" = lib.mkIf config.my.units.download.enable (
mkDownloadService "post types from instagram" "instagram -u jawz -t %I"
);
};
timers =
let
downloadTimer = time: delay: {
enable = true;
description = "Downloads post types from different sites";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = time;
RandomizedDelaySec = delay;
Persistent = true;
};
};
in
{
# "instagram@stories" = lib.mkIf config.my.units.download.enable (
# downloadTimer "*-*-* 12:34:00" 120 // { }
# );
"download@main" = lib.mkIf config.my.units.download.enable (
downloadTimer "*-*-* 06,18:02:00" 30 // { }
);
"download@push" = lib.mkIf config.my.units.download.enable (downloadTimer "*:0/5" 30 // { });
"download@manga" = lib.mkIf config.my.units.downloadManga.enable (
downloadTimer "*-*-* 03:08:00" 30 // { }
);
tuhmayto = lib.mkIf config.my.units.download.enable {
enable = true;
description = "Downloads tuhmayto stuff";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "*:0/10";
};
};
};
};
my.scripts.download = {
enable = lib.mkDefault false;
install = true;
service = false;
name = "download";
package = wrappedDownload;
};
};
}

View File

@@ -0,0 +1,25 @@
{
config,
inputs,
lib,
pkgs,
}:
let
inherit (inputs.jawz-scripts.packages.x86_64-linux) download;
gallerySecretsPath = lib.attrByPath [ "sops" "secrets" "gallery-dl/secrets" "path" ] null config;
in
{
inherit gallerySecretsPath;
wrappedDownload =
if gallerySecretsPath != null then
pkgs.symlinkJoin {
name = "download-with-secrets";
paths = [ download ];
buildInputs = [ pkgs.makeWrapper ];
postBuild = ''
wrapProgram $out/bin/download --run 'if [ -r "${gallerySecretsPath}" ]; then set -a; source "${gallerySecretsPath}"; set +a; fi'
'';
}
else
download;
}

View File

@@ -0,0 +1,25 @@
{
config,
inputs,
lib,
osConfig ? null,
pkgs,
...
}:
let
shellType = inputs.self.lib.hmShellType config osConfig;
enabled =
inputs.self.lib.hmOnlyUser config osConfig "jawz"
&& (osConfig.my.units.download.enable || osConfig.my.units.downloadManga.enable);
download = import ./common.nix {
config = if osConfig == null then { } else osConfig;
inherit inputs lib pkgs;
};
in
{
config = lib.mkIf enabled {
programs.${shellType}.shellAliases = inputs.self.lib.mergeAliases inputs.self.lib.commonAliases {
dl = "${download.wrappedDownload}/bin/download -u jawz -i";
};
};
}

View File

@@ -0,0 +1,95 @@
{
inputs,
pkgs,
lib,
config,
...
}:
let
download = import ./common.nix {
inherit
config
inputs
lib
pkgs
;
};
in
{
options.my.units = {
download.enable = lib.mkEnableOption "media download automation scripts";
downloadManga.enable = lib.mkEnableOption "manga download automation";
};
config = {
systemd.user = {
services =
let
mkDownloadService = desc: execStartCmd: {
restartIfChanged = true;
description = "Downloads ${desc}";
wantedBy = [ "default.target" ];
path = [ pkgs.bash ];
serviceConfig = {
TimeoutStartSec = 2000;
TimeoutStopSec = 2000;
Restart = "on-failure";
RestartSec = 30;
ExecStart = "${download.wrappedDownload}/bin/download ${execStartCmd}";
}
// lib.optionalAttrs (download.gallerySecretsPath != null) {
EnvironmentFile = download.gallerySecretsPath;
};
};
in
{
tuhmayto = lib.mkIf config.my.units.download.enable (
mkDownloadService "tuhmayto stuff" ''
-u jawz -i https://x.com/tuhmayto/media \
https://www.furaffinity.net/user/tuhmayto/ \
https://bsky.app/profile/tumayto.bsky.social''
);
"download@" = lib.mkIf (config.my.units.download.enable || config.my.units.downloadManga.enable) (
mkDownloadService "post from multiple sources" "%I"
);
"instagram@" = lib.mkIf config.my.units.download.enable (
mkDownloadService "post types from instagram" "instagram -u jawz -t %I"
);
};
timers =
let
downloadTimer = time: delay: {
enable = true;
description = "Downloads post types from different sites";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = time;
RandomizedDelaySec = delay;
Persistent = true;
};
};
in
{
"download@main" = lib.mkIf config.my.units.download.enable (
downloadTimer "*-*-* 06,18:02:00" 30 // { }
);
"download@push" = lib.mkIf config.my.units.download.enable (downloadTimer "*:0/5" 30 // { });
"download@manga" = lib.mkIf config.my.units.downloadManga.enable (
downloadTimer "*-*-* 03:08:00" 30 // { }
);
tuhmayto = lib.mkIf config.my.units.download.enable {
enable = true;
description = "Downloads tuhmayto stuff";
wantedBy = [ "timers.target" ];
timerConfig.OnCalendar = "*:0/10";
};
};
};
my.scripts.download = {
enable = lib.mkDefault false;
install = true;
service = false;
name = "download";
package = download.wrappedDownload;
};
};
}

View File

@@ -1,11 +1,17 @@
{ {
config, config,
inputs,
lib, lib,
pkgs, pkgs,
... ...
}: }:
{ {
config.my.scripts.update-org-agenda-cache = { config.my.scripts.update-org-agenda-cache =
let
user = inputs.self.lib.getFirstUser config.my.emacs.users;
emacsPackage = config.home-manager.users.${user}.programs.doom-emacs.finalEmacsPackage;
in
{
enable = lib.mkDefault false; enable = lib.mkDefault false;
install = config.my.emacs.enable; install = config.my.emacs.enable;
service = config.my.emacs.enable; service = config.my.emacs.enable;
@@ -15,7 +21,7 @@
package = pkgs.writeScriptBin "update-org-agenda-cache" '' package = pkgs.writeScriptBin "update-org-agenda-cache" ''
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#! nix-shell -i bash -p bash #! nix-shell -i bash -p bash
${config.services.emacs.package}/bin/emacsclient --eval '(my/update-org-agenda-cache)' ${emacsPackage}/bin/emacsclient --eval '(my/update-org-agenda-cache)'
''; '';
}; };
} }

View File

@@ -1,67 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
{
options.my.shell.multimedia = {
enable = lib.mkEnableOption "multimedia CLI tools and codecs";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.shell;
description = "Users to install multimedia shell tools for";
};
};
config = lib.mkIf (config.my.shell.multimedia.enable && config.my.secureHost) {
sops.secrets."gallery-dl/secrets" =
let
user = inputs.self.lib.getFirstUser config.my.shell.multimedia.users;
in
{
sopsFile = ../../secrets/gallery.yaml;
owner = user;
mode = "0400";
};
home-manager.users =
inputs.self.lib.mkHomeManagerUsers lib config.my.shell.multimedia.users
(user: {
programs = {
yt-dlp = {
enable = true;
settings = {
embed-thumbnail = true;
embed-subs = true;
sub-langs = "all";
cookies-from-browser = "firefox+gnomekeyring:/home/${user}/.librewolf/${user}";
};
};
gallery-dl = {
enable = true;
settings = inputs.self.lib.importDotfile ../../dotfiles/gallery-dl.nix;
};
${config.my.shell.type} = {
initExtra = lib.mkAfter ''
if [ -r "${config.sops.secrets."gallery-dl/secrets".path}" ]; then
set -a # automatically export all variables
source "${config.sops.secrets."gallery-dl/secrets".path}"
set +a # stop automatically exporting
fi
'';
};
};
});
users.users =
let
packages = builtins.attrValues {
inherit (pkgs)
ffmpeg # not ffmpreg, the coolest video conversion tool!
imagemagick # photoshop what??
ffpb # make ffmpeg encoding... a bit fun
;
};
in
inputs.self.lib.mkUserPackages lib config.my.shell.multimedia.users packages;
};
}

View File

@@ -0,0 +1,10 @@
{ pkgs }:
{
packages = builtins.attrValues {
inherit (pkgs)
ffmpeg
imagemagick
ffpb
;
};
}

View File

@@ -0,0 +1,62 @@
{
config,
inputs,
lib,
osConfig ? null,
pkgs,
...
}:
let
shellType = inputs.self.lib.hmShellType config osConfig;
hm = inputs.self.lib.hmModule {
inherit
config
inputs
osConfig
;
optionPath = [
"shell"
"multimedia"
];
};
cfg = config.my.shell.multimedia;
multimedia = import ./common.nix { inherit pkgs; };
in
{
options.my.shell.multimedia.enable = lib.mkEnableOption "multimedia CLI tools and codecs";
config = lib.mkMerge [
{
my.shell.multimedia.enable = lib.mkDefault hm.enabledByDefault;
}
(lib.mkIf cfg.enable {
home.packages = multimedia.packages;
programs = {
yt-dlp = {
enable = true;
settings = {
embed-thumbnail = true;
embed-subs = true;
sub-langs = "all";
cookies-from-browser = "firefox+gnomekeyring:${config.home.homeDirectory}/.librewolf/${config.home.username}";
};
};
gallery-dl = {
enable = true;
settings = inputs.self.lib.importDotfile ../../../dotfiles/gallery-dl.nix;
};
${shellType}.initExtra = lib.mkAfter (
if osConfig == null then
""
else
''
if [ -r "${osConfig.sops.secrets."gallery-dl/secrets".path}" ]; then
set -a
source "${osConfig.sops.secrets."gallery-dl/secrets".path}"
set +a
fi
''
);
};
})
];
}

View File

@@ -0,0 +1,27 @@
{
config,
inputs,
lib,
...
}:
{
options.my.shell.multimedia = {
enable = lib.mkEnableOption "multimedia CLI tools and codecs";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.shell;
description = "Users to install multimedia shell tools for";
};
};
config = lib.mkIf (config.my.shell.multimedia.enable && config.my.secureHost) {
sops.secrets."gallery-dl/secrets" =
let
user = inputs.self.lib.getFirstUser config.my.shell.multimedia.users;
in
{
sopsFile = ../../../secrets/gallery.yaml;
owner = user;
mode = "0400";
};
};
}

View File

@@ -3,22 +3,46 @@
lib, lib,
pkgs, pkgs,
inputs, inputs,
osConfig ? null,
... ...
}: }:
let let
shellType = config.my.shell.type; shellType = inputs.self.lib.hmShellType config osConfig;
hm = inputs.self.lib.hmModule {
inherit
config
inputs
osConfig
;
optionPath = [
"shell"
"tools"
];
};
cfg = config.my.shell.tools;
in in
{ {
options.my.shell.tools = { options.my.shell.tools.enable = lib.mkEnableOption "shell tools and utilities";
enable = lib.mkEnableOption "shell tools and utilities"; config = lib.mkMerge [
users = lib.mkOption { {
type = inputs.self.lib.usersOptionType lib; my.shell.tools.enable = lib.mkDefault hm.enabledByDefault;
default = config.my.toggleUsers.shell; }
description = "Users to install shell tools for"; (lib.mkIf cfg.enable {
home.packages = builtins.attrValues {
inherit (pkgs)
ripgrep
dust
fd
fzf
gdu
tealdeer
trash-cli
jq
yq
smartmontools
rmlint
;
}; };
};
config = lib.mkIf config.my.shell.tools.enable {
home-manager.users = inputs.self.lib.mkHomeManagerUsers lib config.my.shell.tools.users (user: {
programs = { programs = {
hstr.enable = true; hstr.enable = true;
htop = { htop = {
@@ -40,12 +64,12 @@ in
config.pager = "less -FR"; config.pager = "less -FR";
extraPackages = builtins.attrValues { extraPackages = builtins.attrValues {
inherit (pkgs.bat-extras) inherit (pkgs.bat-extras)
batman # man pages batman
batpipe # piping batpipe
batgrep # ripgrep batgrep
batdiff # this is getting crazy! batdiff
batwatch # probably my next best friend batwatch
prettybat # trans your sourcecode! prettybat
; ;
}; };
}; };
@@ -60,7 +84,7 @@ in
PASSWORD_STORE_NOPAGER = "false"; PASSWORD_STORE_NOPAGER = "false";
PASSWORD_STORE_NOTIFICATIONS = "false"; PASSWORD_STORE_NOTIFICATIONS = "false";
PASSWORD_STORE_PARSING = "true"; PASSWORD_STORE_PARSING = "true";
PASSWORD_STORE_PATH = "/home/${user}/.local/share/pass"; PASSWORD_STORE_PATH = "${config.home.homeDirectory}/.local/share/pass";
PASSWORD_STORE_SAFECONTENT = "true"; PASSWORD_STORE_SAFECONTENT = "true";
}; };
}; };
@@ -93,39 +117,11 @@ in
fi fi
''; '';
}; };
}); home.sessionVariables = {
programs = {
starship.enable = true;
tmux.enable = true;
fzf.fuzzyCompletion = true;
neovim = {
enable = true;
vimAlias = true;
};
};
users.users =
let
packages = builtins.attrValues {
inherit (pkgs)
ripgrep # modern grep
dust # rusty du similar to gdu
fd # modern find, faster searches
fzf # fuzzy finder! super cool and useful
gdu # disk-space utility checker, somewhat useful
tealdeer # man for retards
trash-cli # oop! did not meant to delete that
jq # json parser
yq # yaml parser
smartmontools # check hard drie health
rmlint # amazing dupe finder that integrates well with BTRFS
;
};
in
inputs.self.lib.mkUserPackages lib config.my.shell.tools.users packages;
environment.variables = {
HISTFILE = "\${XDG_STATE_HOME}/bash/history"; HISTFILE = "\${XDG_STATE_HOME}/bash/history";
LESSHISTFILE = "-"; LESSHISTFILE = "-";
RIPGREP_CONFIG_PATH = "\${XDG_CONFIG_HOME}/ripgrep/ripgreprc"; RIPGREP_CONFIG_PATH = "\${XDG_CONFIG_HOME}/ripgrep/ripgreprc";
}; };
}; })
];
} }

View File

@@ -0,0 +1,27 @@
{
config,
lib,
inputs,
...
}:
{
options.my.shell.tools = {
enable = lib.mkEnableOption "shell tools and utilities";
users = lib.mkOption {
type = inputs.self.lib.usersOptionType lib;
default = config.my.toggleUsers.shell;
description = "Users to install shell tools for";
};
};
config = lib.mkIf config.my.shell.tools.enable {
programs = {
starship.enable = true;
tmux.enable = true;
fzf.fuzzyCompletion = true;
neovim = {
enable = true;
vimAlias = true;
};
};
};
}

View File

@@ -55,6 +55,32 @@ in
|> builtins.attrNames |> builtins.attrNames
|> builtins.filter (file: builtins.match ".*\\.nix" file != null && filterFn file) |> builtins.filter (file: builtins.match ".*\\.nix" file != null && filterFn file)
|> map (file: dir + "/${file}"); |> map (file: dir + "/${file}");
autoImportLeaf =
dir: leafName:
let
visit =
current:
let
entries = builtins.readDir current;
in
entries
|> builtins.attrNames
|> map (
name:
let
entryType = entries.${name};
path = current + "/${name}";
in
if entryType == "directory" then
visit path
else if entryType == "regular" && name == leafName then
[ path ]
else
[ ]
)
|> builtins.concatLists;
in
visit dir;
proxy = locations: { proxy = locations: {
inherit locations; inherit locations;
forceSSL = true; forceSSL = true;
@@ -252,6 +278,37 @@ in
}) (inputs.self.lib.normalizeUsers users) }) (inputs.self.lib.normalizeUsers users)
); );
getFirstUser = users: if builtins.isString users then users else (builtins.head users); getFirstUser = users: if builtins.isString users then users else (builtins.head users);
hmModule =
{
config,
inputs,
osConfig ? null,
optionPath,
}:
let
getPath =
path: attrs:
builtins.foldl' (acc: key: if acc == null then null else acc.${key} or null) attrs path;
osCfg = if osConfig == null then null else getPath optionPath osConfig.my;
enabledByDefault =
if osCfg == null then
false
else
(osCfg.enable or false)
&& builtins.elem config.home.username (inputs.self.lib.normalizeUsers (osCfg.users or [ ]));
in
{
inherit osCfg enabledByDefault;
};
hmShellType =
config: osConfig:
if osConfig == null then
if config.programs.bash.enable then "bash" else "zsh"
else
osConfig.my.shell.type;
hmOnlyUser =
config: osConfig: user:
osConfig != null && config.home.username == user;
usersOptionType = usersOptionType =
lib: lib:
lib.mkOptionType { lib.mkOptionType {

View File

@@ -34,3 +34,8 @@
- **Decision**: Treat `patches/` as a root-level directory (not a module category) and update active hosts to include `vps`. - **Decision**: Treat `patches/` as a root-level directory (not a module category) and update active hosts to include `vps`.
- **Rationale**: Repo structure places patches at the root and hosts include `vps`; documentation must reflect actual paths and host inventory. - **Rationale**: Repo structure places patches at the root and hosts include `vps`; documentation must reflect actual paths and host inventory.
- **Alternatives considered**: (a) Move `patches/` under `modules/` (rejected: would change repo layout); (b) Keep `vps` undocumented (rejected: causes host list drift). - **Alternatives considered**: (a) Move `patches/` under `modules/` (rejected: would change repo layout); (b) Keep `vps` undocumented (rejected: causes host list drift).
## Decision 8 (2026-03-16): Preferred split layout for Home Manager and NixOS modules
- **Decision**: Support a gradual migration from mixed flat modules to feature directories with paired `nixos.nix` and `home.nix` files, discovered automatically by NixOS and Home Manager import loaders.
- **Rationale**: Keeps the current category-first browsing model while removing the need to embed Home Manager config inside NixOS modules, which is a cleaner fit for future standalone Home Manager and Darwin hosts.
- **Alternatives considered**: (a) Keep mixed modules and branch on platform forever (rejected: keeps NixOS/Home Manager tightly coupled); (b) Split into separate top-level `modules/nixos` and `modules/home` trees (rejected: loses adjacency between the two surfaces of a single feature).