Skip to content

feat: cluster test framework #545

Open
DaRacci wants to merge 12 commits into
masterfrom
push-xvsqsqnwmrup
Open

feat: cluster test framework #545
DaRacci wants to merge 12 commits into
masterfrom
push-xvsqsqnwmrup

Conversation

@DaRacci

@DaRacci DaRacci commented Mar 9, 2026

Copy link
Copy Markdown
Owner

Based off #544

@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added VM integration test scenarios, including automatic per-host unit checks and multi-node scenarios.
    • Introduced nixosTestConfigurations to assemble host and scenario-based VM tests.
  • Bug Fixes
    • Improved null-safety for API key checks and per-host attribute lookups.
    • Corrected AdGuard Home hostlist filter fileId stringification.
  • Tests
    • Expanded CI coverage with Woodpecker PR+KVM workflow and a clearer VM test runner with per-host reporting.
  • Documentation
    • Added a full guide for authoring and running VM integration tests.

Walkthrough

Adds VM test generation and execution wiring, a shared VM test profile, per-host unit tests, documentation, CI and local runners, plus importExternals gating across core modules and null-safe API-key auth checks.

Changes

VM Integration Test Framework

Layer / File(s) Summary
Test configuration generation
flake/default.nix, flake/nixos/flake-module.nix
Adds checks = "ci" mapping and builds nixosTestConfigurations from server hosts plus discovered scenarios.
Test builder and node helpers
tests/builder.nix, tests/mkNode.nix, tests/lib.nix
Adds the VM test builder, host node constructor, and multi-node helper used to assemble host and scenario scripts.
VM profile and execution helpers
tests/profiles/dummy.yaml, tests/profiles/vm-test.nix, run-test.sh
Adds the VM test profile, dummy secret profile, and a local runner for selected VM scenarios.
CI pipeline
.woodpecker/test-vm.yaml
Adds the pull-request VM test pipeline that archives flake inputs and builds each host test.
Docs and scenario tests
docs/src/SUMMARY.md, docs/src/development/vm_integration_tests.md, tests/scenarios/*
Adds VM test docs and new backup, firewall, PostgreSQL, proxy, and Redis scenario tests.

Per-host server.tests.units Definitions

Layer / File(s) Summary
Host unit test scripts
hosts/server/nixai/*, hosts/server/nixarr/*, hosts/server/nixcloud/*, hosts/server/nixdev/*, hosts/server/nixio/*, hosts/server/nixmon/default.nix, hosts/server/nixserv/default.nix
Adds unit-test entries across host modules for service load-state checks, connectivity checks, kernel forwarding, and one hostlist stringification fix.

importExternals Gating and API Key Null-Safety

Layer / File(s) Summary
External config gating
modules/nixos/core/nix.nix, modules/nixos/core/boot/secureboot.nix, modules/nixos/core/host/persistence.nix, modules/nixos/core/sops.nix, modules/nixos/core/stylix.nix, modules/nixos/services/ai-agent.nix, modules/nixos/server/storage/seaweedfs.nix
Adds importExternals handling and conditionally includes several core configuration blocks.
API key null-safety
modules/nixos/server/proxy/extensions/api-key-auth.nix
Makes virtual-host API-key detection and collection null-safe.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant flakeModule as flake/nixos/flake-module.nix
  participant testsBuilder as tests/builder.nix
  participant woodpecker as .woodpecker/test-vm.yaml
  participant nixBuild as nix build
  flakeModule->>testsBuilder: build nixosTestConfigurations
  woodpecker->>nixBuild: run per-host VM builds
  nixBuild-->>woodpecker: pass or FAILED per host
Loading

Poem

A rabbit hops through flake and test,
And prods each service to attest. 🐇
VMs hum, the logs unfurl,
Scenarios whirl through every pearl,
With externals gated, neat and true,
The burrow shines in greener hue.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description only references another PR and doesn't describe the changes in this changeset. Replace it with a brief summary of the feature, such as adding a cluster test framework based on PR #544.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: introducing a cluster test framework.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch push-xvsqsqnwmrup
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch push-xvsqsqnwmrup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mergify

mergify Bot commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🔴 Enforce conventional commit

Waiting for

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?:
This rule is failing.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?:

🔴 Do not merge outdated PRs

Waiting for

  • #commits-behind <= 10
This rule is failing.

Make sure PRs are almost up to date before merging

  • #commits-behind <= 10

@mergify

mergify Bot commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

🧪 CI Insights

Here's what we observed from your CI run for 072e115.

🟢 All jobs passed!

But CI Insights is watching 👀

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
flake/ci/flake-module.nix (1)

12-29: ⚠️ Potential issue | 🟠 Major

checks.cluster never consults the new server.tests.enable flag.

clusterHosts is derived only from getHostsByType self, and tests/default.nix:17-19 turns every entry in that list into a VM node. As written, flipping server.tests.enable in modules/nixos/server/tests.nix cannot change which hosts participate in the cluster test, so the new opt-in flag is ineffective for membership.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@flake/ci/flake-module.nix` around lines 12 - 29, The cluster test currently
uses clusterHosts = (getHostsByType self).server or [] which ignores the new
server.tests.enable flag; update the clusterHosts computation so it filters the
hosts list to only include hosts whose server.tests.enable is true (i.e.,
evaluate each host's module/config and keep it only when server.tests.enable is
truthy) before passing clusterHosts into checks.cluster (references:
clusterHosts, getHostsByType, checks.cluster, server.tests.enable,
tests/default.nix).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/src/modules/nixos/desktop.md`:
- Around line 7-8: The docs currently imply RGB and VFIO are enabled by default;
update the desktop.md wording to state these are opt-in features and are only
enabled when their config flag is set (they are gated with mkIf cfg.enable in
the rgb.nix and vfio.nix modules), and clarify how
modules/nixos/desktop/default.nix composes those modules rather than enabling
them globally; change the two spots called out to mention "opt-in via
cfg.enable" and mirror the suggested wording.

In `@modules/nixos/desktop/virtual-machine.nix`:
- Around line 92-96: The mounts option currently uses mkOption with type =
types.attrsOf types.anything which removes validation; update the description
for the mounts option (the mkOption named "mounts") to document the expected
attribute structure and provide a concrete example showing host-path keys
mapping to attrs including target and readonly (e.g. host path -> { target =
"/guest/path"; readonly = false; }) so users know the required fields and shape;
keep the existing type but make the description clear and copyable for users.

In `@modules/nixos/server/tests.nix`:
- Around line 10-11: The module is incorrectly inheriting type helpers from lib
(which has no .type); update the inherits to pull from lib.types so the NixOS
module type helpers are resolved: change the first inherit to reference
lib.types when bringing in type, mkOption and mkEnableOption, and change the
second inherit to reference lib.types for submodule, attrsOf, either, listOf,
str, bool, functionTo (or alternatively only import type once and then inherit
(type) ...), ensuring mkOption, mkEnableOption, submodule, attrsOf, either,
listOf, str, bool, and functionTo come from lib.types.
- Around line 17-38: The options declaration for server.tests.units currently
assigns a raw attrsOf (submodule ...) value instead of an option; wrap the whole
attrsOf (submodule ({ name, ... }: { ... })) expression in mkOption so
server.tests.units is an actual Nix option. Specifically, replace the bare units
= attrsOf (...) with units = mkOption (attrsOf (submodule ({ name, ... }: {
options = { ... } }))) (or equivalent mkOption form), keeping the same inner
options (name, testScript) to match other modules (metrics.nix, mcpo.nix,
virtual-machine.nix, dashboard.nix) that use mkOption for units.

In `@tests/lib.nix`:
- Around line 6-9: The helper runOnAllNodes is passing the literal string
"node.name" to the callback so callers receive a string instead of the node
object; change the interpolation so the callback is invoked with the node object
(not node.name) inside the for-loop/subtest, i.e. pass node into ${f(...)} so
callers can call methods like wait_for_unit on the actual node object; update
any related docs/tests to expect the node object argument and keep using
subtest(node.name) as the subtest label.

In `@tests/mkNode.nix`:
- Around line 7-11: The test node import currently uses only
modules/flake/apply/system.nix causing tests to build minimal VMs; update the
imports to build test nodes with the full production module stack by either
reusing the existing builder lib/builders/mkSystem.nix or by expanding the
imports to include the NixOS modules, device-type modules, host directory and
shared config modules (preserve existing attributes like allocations, hostName
and deviceType). Locate the imports block that references
modules/flake/apply/system.nix and replace it with a call to
lib/builders/mkSystem.nix (or mirror its module list) so test VMs are built the
same way as production.

---

Outside diff comments:
In `@flake/ci/flake-module.nix`:
- Around line 12-29: The cluster test currently uses clusterHosts =
(getHostsByType self).server or [] which ignores the new server.tests.enable
flag; update the clusterHosts computation so it filters the hosts list to only
include hosts whose server.tests.enable is true (i.e., evaluate each host's
module/config and keep it only when server.tests.enable is truthy) before
passing clusterHosts into checks.cluster (references: clusterHosts,
getHostsByType, checks.cluster, server.tests.enable, tests/default.nix).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4df9fa6f-3aca-4579-86f4-9a365402645c

📥 Commits

Reviewing files that changed from the base of the PR and between baec492 and 072e115.

📒 Files selected for processing (60)
  • docs/src/modules/nixos/desktop.md
  • docs/src/modules/nixos/services.md
  • flake/ci/flake-module.nix
  • flake/default.nix
  • home/shared/applications/media.nix
  • home/shared/desktop/gnome/default.nix
  • lib/builders/mkSystem.nix
  • modules/home-manager/services/mcpo.nix
  • modules/nixos/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/desktop/rgb.nix
  • modules/nixos/desktop/vfio.nix
  • modules/nixos/desktop/virtual-machine.nix
  • modules/nixos/encrypted-root.nix
  • modules/nixos/laptop/default.nix
  • modules/nixos/proxies.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/kanidm.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core.nix
  • modules/nixos/shared/core/auto-upgrade.nix
  • modules/nixos/shared/core/boot/default.nix
  • modules/nixos/shared/core/boot/quietboot.nix
  • modules/nixos/shared/core/boot/secureboot.nix
  • modules/nixos/shared/core/boot/systemd-boot.nix
  • modules/nixos/shared/core/default.nix
  • modules/nixos/shared/core/hardware/backlight.nix
  • modules/nixos/shared/core/hardware/biometrics.nix
  • modules/nixos/shared/core/hardware/bluetooth.nix
  • modules/nixos/shared/core/hardware/cooling.nix
  • modules/nixos/shared/core/hardware/default.nix
  • modules/nixos/shared/core/hardware/display.nix
  • modules/nixos/shared/core/hardware/graphics.nix
  • modules/nixos/shared/core/hardware/openrgb.nix
  • modules/nixos/shared/core/hardware/storage/default.nix
  • modules/nixos/shared/core/hardware/storage/ephemeral.nix
  • modules/nixos/shared/core/hardware/storage/maintenance.nix
  • modules/nixos/shared/core/hardware/storage/partitions/btrfs.nix
  • modules/nixos/shared/core/hardware/storage/partitions/esp.nix
  • modules/nixos/shared/core/hardware/storage/partitions/luks.nix
  • modules/nixos/shared/core/hardware/storage/partitions/tmpfs.nix
  • modules/nixos/shared/core/host/default.nix
  • modules/nixos/shared/core/host/device.nix
  • modules/nixos/shared/core/host/persistence.nix
  • modules/nixos/shared/default.nix
  • modules/nixos/shared/features/display-manager.nix
  • modules/nixos/shared/features/hm-helper/1password.nix
  • modules/nixos/shared/features/hm-helper/default.nix
  • modules/nixos/shared/features/hm-helper/kde-connect.nix
  • modules/nixos/shared/features/hm-helper/mpv.nix
  • modules/nixos/shared/features/hm-helper/nautilus.nix
  • modules/nixos/shared/features/remote.nix
  • modules/nixos/shared/services/default.nix
  • modules/nixos/shared/services/huntress.nix
  • modules/nixos/shared/services/mcpo.nix
  • modules/nixos/shared/services/metrics.nix
  • modules/nixos/shared/services/tailscale.nix
  • tests/default.nix
  • tests/lib.nix
  • tests/mkNode.nix
💤 Files with no reviewable changes (4)
  • modules/nixos/default.nix
  • modules/nixos/encrypted-root.nix
  • modules/nixos/proxies.nix
  • modules/nixos/shared/core.nix
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Build nixosConfigurations.nixmi.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixarr.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixdev.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixcloud.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixio.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build homeConfigurations.racci.activationPackage on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixmon.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixserv.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixai.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🧰 Additional context used
📓 Path-based instructions (15)
**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/building/SKILL.md)

Use nix fmt to format Nix code and check syntax

**/*.nix: Run nix fmt <paths...> after making any changes to ensure consistent formatting
Use 2 spaces for indentation in Nix files
Use kebab-case for Nix file and directory names
Use camelCase for Nix attributes (e.g., myOption, enableFeature)
Use camelCase for Nix option paths (e.g., services.myService.enable)
Prefer minimal comments; code should be self-explanatory, using comments to explain why, not what
Prefer relative imports over absolute imports (e.g., ./modules/foo.nix)
Group imports at the top of the Nix file and use list format for multiple imports
When generating JSON, YAML, or other structured formats, define as Nix attribute sets and convert using builtins functions (e.g., builtins.toJSON), rather than using inline string literals
Follow the standard module structure pattern with config, lib, pkgs destructuring, let bindings for module configuration, and options/config sections
Use let bindings with inherit for importing functions from libraries (e.g., inherit (lib) mkIf mkEnableOption)

Run nix fmt to format code before submitting changes

**/*.nix: Use builtins.trace to add trace statements for seeing values during Nix evaluation, with builtins.toJSON for complex attribute sets
Check for circular dependencies in imports or option definitions as the root cause of infinite recursion errors in Nix
Verify attribute names, imports, and option paths to resolve 'attribute missing' errors in Nix configurations

Run nix fmt on changed Nix files after modifying modules

**/*.nix: Declare secrets in Nix using sops.secrets with the secret path as the key
Specify custom permissions for secrets using owner, group, and mode attributes in sops.secrets declarations
Use sops.templates to combine multiple secrets into configuration files with placeholders
Add restartUnits to secret declarations to automatically restart services when secrets change
Use empty `k...

Files:

  • modules/nixos/shared/default.nix
  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • tests/lib.nix
  • modules/nixos/server/proxy/kanidm.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/desktop/virtual-machine.nix
  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
  • modules/nixos/server/default.nix
  • flake/ci/flake-module.nix
  • modules/nixos/laptop/default.nix
  • flake/default.nix
  • tests/mkNode.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core/default.nix
  • tests/default.nix
modules/nixos/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Create NixOS modules at modules/nixos/<category>/<name>.nix with standard pattern including options definition, lib imports (mkEnableOption, mkOption, mkIf, types), config variable binding, and conditional config application using mkIf

Files:

  • modules/nixos/shared/default.nix
  • modules/nixos/server/proxy/kanidm.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/desktop/virtual-machine.nix
  • modules/nixos/server/default.nix
  • modules/nixos/laptop/default.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core/default.nix
modules/nixos/*/default.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Register NixOS modules in parent default.nix using imports list pattern: _: { imports = [ ./module-a.nix ./module-b.nix ]; }

Files:

  • modules/nixos/shared/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/server/default.nix
  • modules/nixos/laptop/default.nix
modules/nixos/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Reusable NixOS module fragments should be placed in modules/nixos/ directory

Files:

  • modules/nixos/shared/default.nix
  • modules/nixos/server/proxy/kanidm.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/desktop/virtual-machine.nix
  • modules/nixos/server/default.nix
  • modules/nixos/laptop/default.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core/default.nix
modules/home-manager/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

modules/home-manager/**/*.nix: Create Home-Manager modules at modules/home-manager/<category>/<name>.nix with osConfig parameter support and conditional config application using mkIf
Use purpose.<category> namespace for use-case modules in Home-Manager modules
Use custom.<name> namespace for custom extensions in Home-Manager modules
Use user.<name> namespace for user-specific options in Home-Manager modules

Files:

  • modules/home-manager/services/mcpo.nix
modules/home-manager/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Reusable Home-Manager module fragments should be placed in modules/home-manager/ directory

Files:

  • modules/home-manager/services/mcpo.nix
lib/builders/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Custom system and home builders should be implemented in lib/builders/ directory with mkSystem.nix and mkHome.nix as entry points

Files:

  • lib/builders/mkSystem.nix
modules/nixos/server/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Use server.<name> namespace for server cluster options in NixOS modules

Files:

  • modules/nixos/server/proxy/kanidm.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/tests.nix
home/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/contributing/SKILL.md)

Test at least one affected home configuration before submitting changes

Files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
home/shared/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Shared Home-Manager configurations across all users should be placed in home/shared/ directory

Files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
home/shared/desktop/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Shared desktop environment configurations should be in home/shared/desktop/

Files:

  • home/shared/desktop/gnome/default.nix
home/shared/applications/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Shared application-specific Home-Manager configurations should be in home/shared/applications/

Files:

  • home/shared/applications/media.nix
flake/ci/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

CI-specific flake definitions and scripts should be located in the flake/ci/ directory

Files:

  • flake/ci/flake-module.nix
docs/src/**/*.md

📄 CodeRabbit inference engine (.opencode/skills/docs/SKILL.md)

docs/src/**/*.md: Create or update Markdown files in docs/src following the documentation workflow: analyze changes, identify impact on documentation files, draft content with underscore filenames, update docs/src/SUMMARY.md, and verify Nix code examples are valid
Keep documentation explanations concise and focus on why something is configured a certain way rather than just what the code does

Files:

  • docs/src/modules/nixos/services.md
  • docs/src/modules/nixos/desktop.md
docs/**

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Project documentation should be maintained in the docs/ directory

Files:

  • docs/src/modules/nixos/services.md
  • docs/src/modules/nixos/desktop.md
🧠 Learnings (85)
📓 Common learnings
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/users/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:41.504Z
Learning: Applies to home/*/features/**/*.nix : User's feature modules should be organized in a `features/` directory within the user directory (`home/<username>/features/`)
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to modules/nixos/** : Reusable NixOS module fragments should be placed in `modules/nixos/` directory
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Follow the standard module structure pattern with `config`, `lib`, `pkgs` destructuring, `let` bindings for module configuration, and `options`/`config` sections
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to hosts/shared/optional/** : Optional NixOS features (gaming, containers, etc.) should be organized in `hosts/shared/optional/`
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/**/*.nix : Create NixOS modules at `modules/nixos/<category>/<name>.nix` with standard pattern including options definition, lib imports (mkEnableOption, mkOption, mkIf, types), config variable binding, and conditional config application using mkIf
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to home/shared/features/** : Shared feature modules (CLI tools, features, etc.) should be in `home/shared/features/`
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/default.nix : Export module categories from top-level `modules/nixos/default.nix` as attribute set with structure: `{ boot = import ./boot; hardware = import ./hardware; services = import ./services; }`
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to modules/nixos/default.nix : NixOS modules should be exported through `modules/nixos/default.nix`
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to flake/nixos/** : NixOS flake modules should be organized in the `flake/nixos/` directory
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/server/**/*.nix : Use `server.<name>` namespace for server cluster options in NixOS modules
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/*/default.nix : Register NixOS modules in parent `default.nix` using imports list pattern: `_: { imports = [ ./module-a.nix ./module-b.nix ]; }`

Applied to files:

  • modules/nixos/shared/default.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/server/default.nix
  • modules/nixos/laptop/default.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to modules/nixos/default.nix : NixOS modules should be exported through `modules/nixos/default.nix`

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/server/default.nix
  • docs/src/modules/nixos/services.md
  • modules/nixos/laptop/default.nix
  • tests/mkNode.nix
  • modules/nixos/shared/core/default.nix
  • docs/src/modules/nixos/desktop.md
  • tests/default.nix
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/default.nix : Export module categories from top-level `modules/nixos/default.nix` as attribute set with structure: `{ boot = import ./boot; hardware = import ./hardware; services = import ./services; }`

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/server/default.nix
  • docs/src/modules/nixos/services.md
  • modules/nixos/laptop/default.nix
  • tests/mkNode.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core/default.nix
  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/home-manager/*/default.nix : Register Home-Manager modules in parent `default.nix` using imports list pattern

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/server/default.nix
  • docs/src/modules/nixos/services.md
  • modules/nixos/laptop/default.nix
  • modules/nixos/shared/core/default.nix
  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:24:22.881Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Prefer relative imports over absolute imports (e.g., `./modules/foo.nix`)

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/server/default.nix
  • modules/nixos/laptop/default.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to modules/home-manager/default.nix : Home-Manager modules should be exported through `modules/home-manager/default.nix`

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • docs/src/modules/nixos/services.md
  • modules/nixos/laptop/default.nix
  • tests/mkNode.nix
  • modules/nixos/shared/core/default.nix
  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Prefer relative imports (e.g., `./modules/foo.nix`) over absolute paths

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/laptop/default.nix
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Applies to hosts/{server,desktop,laptop}/*/default.nix : Host `default.nix` files must import `${modulesPath}/virtualisation/proxmox-lxc.nix` for LXC containers or `./hardware.nix` for physical machines

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/laptop/default.nix
  • tests/mkNode.nix
  • docs/src/modules/nixos/desktop.md
  • tests/default.nix
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/services/**/*.nix : Use `services.<name>` namespace for system services in NixOS modules

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/home-manager/services/mcpo.nix
  • docs/src/modules/nixos/services.md
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to **/*.nix : Check for infinite recursion by examining recent changes for circular imports between modules or option definitions that reference themselves

Applied to files:

  • modules/nixos/shared/default.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/server/default.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Avoid hardcoded paths that should be configurable options

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/desktop/virtual-machine.nix
  • home/shared/applications/media.nix
  • modules/nixos/server/default.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Group imports at the top of the file and use list format for multiple imports

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/laptop/default.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Ensure all used functions are properly inherited to avoid circular imports and hidden dependencies

Applied to files:

  • modules/nixos/shared/default.nix
  • tests/lib.nix
  • modules/nixos/desktop/default.nix
  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
  • modules/nixos/server/default.nix
  • modules/nixos/laptop/default.nix
  • tests/mkNode.nix
📚 Learning: 2026-03-01T12:26:01.611Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/packages/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:01.611Z
Learning: Applies to overlays/default.nix : Expose custom packages via overlays/default.nix by importing the pkgs directory with inputs, lib, and pkgs parameters

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/desktop/default.nix
📚 Learning: 2026-03-01T12:24:22.881Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Group imports at the top of the Nix file and use list format for multiple imports

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/laptop/default.nix
📚 Learning: 2026-03-01T12:24:22.881Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Follow the standard module structure pattern with `config`, `lib`, `pkgs` destructuring, `let` bindings for module configuration, and `options`/`config` sections

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/server/default.nix
  • docs/src/modules/nixos/services.md
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:24:22.881Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Use camelCase for Nix option paths (e.g., `services.myService.enable`)

Applied to files:

  • modules/nixos/shared/default.nix
  • docs/src/modules/nixos/services.md
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Ensure all required options are defined before use in configuration blocks

Applied to files:

  • modules/nixos/shared/default.nix
  • modules/nixos/server/default.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:26:41.504Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/users/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:41.504Z
Learning: Applies to home/*/hm-config.nix : Import shared user configurations from `home/shared/` directories in user configs: use `../shared/global/` for configs applied to all users, `../shared/applications/` for application configs, `../shared/desktop/` for desktop environment configs, and `../shared/features/cli/` for CLI tool configurations

Applied to files:

  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/laptop/default.nix
📚 Learning: 2026-03-01T12:24:22.881Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Use `let` bindings with `inherit` for importing functions from libraries (e.g., `inherit (lib) mkIf mkEnableOption`)

Applied to files:

  • modules/home-manager/services/mcpo.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:26:01.611Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/packages/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:01.611Z
Learning: Applies to pkgs/*/default.nix : For multi-output packages, use a let binding to define multiple outputs and register them with inherit syntax in pkgs/default.nix

Applied to files:

  • modules/home-manager/services/mcpo.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Always use `inherit` to bring functions and values into scope instead of manual assignment

Applied to files:

  • modules/home-manager/services/mcpo.nix
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Applies to hosts/{desktop,laptop}/*/hardware.nix : Physical hardware configurations should import appropriate modules from `inputs.nixos-hardware` (e.g., CPU, SSD, GPU modules) in `hardware.nix`

Applied to files:

  • modules/home-manager/services/mcpo.nix
  • lib/builders/mkSystem.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/desktop/virtual-machine.nix
  • flake/ci/flake-module.nix
  • modules/nixos/laptop/default.nix
  • tests/mkNode.nix
  • modules/nixos/shared/core/default.nix
  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Follow the standard NixOS module structure pattern with config, lib, pkgs parameters and proper `let`/`in` blocks

Applied to files:

  • modules/home-manager/services/mcpo.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/host/**/*.nix : Use `host.<name>` namespace for host-specific options in NixOS modules

Applied to files:

  • modules/home-manager/services/mcpo.nix
  • modules/nixos/desktop/virtual-machine.nix
  • docs/src/modules/nixos/services.md
  • tests/mkNode.nix
  • modules/nixos/server/tests.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to lib/builders/** : Custom system and home builders should be implemented in `lib/builders/` directory with `mkSystem.nix` and `mkHome.nix` as entry points

Applied to files:

  • lib/builders/mkSystem.nix
📚 Learning: 2026-03-01T12:27:25.837Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/test.md:0-0
Timestamp: 2026-03-01T12:27:25.837Z
Learning: For changes affecting only hosts, build at least one affected host configuration using 'nix build .#nixosConfigurations.<hostname>.config.system.build.toplevel'

Applied to files:

  • lib/builders/mkSystem.nix
  • flake/ci/flake-module.nix
📚 Learning: 2026-03-01T12:26:41.504Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/users/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:41.504Z
Learning: Applies to home/*/hm-config.nix : Create `hm-config.nix` in `home/<username>/` as the main Home-Manager entry point containing shared configuration across all hosts for that user

Applied to files:

  • lib/builders/mkSystem.nix
  • docs/src/modules/nixos/services.md
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/home-manager/**/*.nix : Use `user.<name>` namespace for user-specific options in Home-Manager modules

Applied to files:

  • lib/builders/mkSystem.nix
  • docs/src/modules/nixos/services.md
📚 Learning: 2026-03-01T12:26:41.504Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/users/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:41.504Z
Learning: Applies to home/*/features/**/*.nix : User's feature modules should be organized in a `features/` directory within the user directory (`home/<username>/features/`)

Applied to files:

  • lib/builders/mkSystem.nix
  • modules/nixos/laptop/default.nix
📚 Learning: 2026-03-01T12:26:41.504Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/users/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:41.504Z
Learning: Applies to home/*/[!.]*@(hm-config|os-config|secrets).nix : Create host-specific configuration files named `<hostname>.nix` in the user directory (`home/<username>/<hostname>.nix`), containing Home-Manager configuration with user-specific git settings, imports of shared features, and host-specific customizations

Applied to files:

  • lib/builders/mkSystem.nix
  • flake/default.nix
📚 Learning: 2026-03-01T12:26:25.327Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/secrets/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:25.327Z
Learning: Applies to **/*.nix : Declare secrets in Nix using `sops.secrets` with the secret path as the key

Applied to files:

  • lib/builders/mkSystem.nix
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Applies to hosts/{desktop,laptop}/*/hardware.nix : Hardware configurations must define filesystem mount points with device labels and filesystem types (e.g., `fileSystems./`)

Applied to files:

  • modules/nixos/desktop/virtual-machine.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Verify option type definitions match their usage and configuration values

Applied to files:

  • modules/nixos/desktop/virtual-machine.nix
  • flake/default.nix
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to **/*.nix : Verify type mismatches by checking option type definitions and the value being provided in NixOS options

Applied to files:

  • modules/nixos/desktop/virtual-machine.nix
📚 Learning: 2026-03-01T12:24:38.213Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/debugging/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:38.213Z
Learning: Applies to **/*.nix : Verify attribute names, imports, and option paths to resolve 'attribute missing' errors in Nix configurations

Applied to files:

  • modules/nixos/desktop/virtual-machine.nix
  • modules/nixos/server/default.nix
  • flake/default.nix
  • tests/mkNode.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to hosts/{desktop,laptop,server}/** : Per-machine NixOS configurations should be organized in `hosts/<type>/<hostname>/` where type is desktop, laptop, or server

Applied to files:

  • modules/nixos/desktop/virtual-machine.nix
  • flake/ci/flake-module.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to hosts/{desktop,laptop,server}/*/default.nix : Host system configurations should follow the pattern `hosts/<type>/<hostname>/default.nix`

Applied to files:

  • modules/nixos/desktop/virtual-machine.nix
  • flake/ci/flake-module.nix
  • tests/mkNode.nix
  • docs/src/modules/nixos/desktop.md
  • tests/default.nix
📚 Learning: 2026-03-01T12:24:22.881Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Use camelCase for Nix attributes (e.g., `myOption`, `enableFeature`)

Applied to files:

  • modules/nixos/desktop/virtual-machine.nix
📚 Learning: 2026-03-01T12:24:29.910Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/contributing/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:29.910Z
Learning: Applies to **/*.nix : Run `nix fmt` to format code before submitting changes

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
📚 Learning: 2026-03-01T12:27:25.837Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/test.md:0-0
Timestamp: 2026-03-01T12:27:25.837Z
Learning: Applies to **/*.nix : Always ensure formatting is correct by running 'nix fmt' on changed files

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to **/*.nix : Run `nix fmt <changed-files>` to fix Nix formatting failures in CI checks

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to **/*.nix : Run `nix fmt` on changed Nix files after modifying modules

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Code MUST pass `nix fmt` formatting validation

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
  • modules/nixos/server/default.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Remove unused let bindings

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
📚 Learning: 2026-03-01T12:24:22.881Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/code-style/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:22.881Z
Learning: Applies to **/*.nix : Run `nix fmt <paths...>` after making any changes to ensure consistent formatting

Applied to files:

  • home/shared/desktop/gnome/default.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Use intermediate bindings instead of deeply nested attribute access for improved readability

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
  • modules/nixos/server/default.nix
📚 Learning: 2026-03-01T12:24:29.910Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/contributing/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:29.910Z
Learning: Applies to home/**/*.nix : Test at least one affected home configuration before submitting changes

Applied to files:

  • home/shared/desktop/gnome/default.nix
  • home/shared/applications/media.nix
  • modules/nixos/server/default.nix
  • flake/ci/flake-module.nix
  • flake/default.nix
  • tests/mkNode.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/server/**/*.nix : Use `server.<name>` namespace for server cluster options in NixOS modules

Applied to files:

  • modules/nixos/server/default.nix
  • docs/src/modules/nixos/services.md
  • tests/mkNode.nix
  • modules/nixos/server/tests.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:26:31.937Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/testing/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:31.937Z
Learning: Run `nix build .#nixosConfigurations.<hostname>.config.system.build.toplevel` to test a host configuration

Applied to files:

  • modules/nixos/server/default.nix
  • flake/ci/flake-module.nix
  • tests/mkNode.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Applies to hosts/{server,desktop,laptop}/*/default.nix : Each host requires a `default.nix` file as the main configuration entry point

Applied to files:

  • modules/nixos/server/default.nix
  • tests/mkNode.nix
  • docs/src/modules/nixos/desktop.md
  • tests/default.nix
📚 Learning: 2026-03-01T12:27:29.965Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-01T12:27:29.965Z
Learning: Applies to **/*.nix : All affected configurations MUST be tested before completing any task, using the test agent and testing skill to identify affected configurations

Applied to files:

  • modules/nixos/server/default.nix
  • flake/ci/flake-module.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:24:29.910Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/contributing/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:29.910Z
Learning: Applies to hosts/**/*.nix : Test at least one affected host configuration before submitting changes

Applied to files:

  • modules/nixos/server/default.nix
  • flake/ci/flake-module.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to flake.nix : Top-level flake definitions and inputs/outputs configuration should be placed in `flake.nix`

Applied to files:

  • flake/ci/flake-module.nix
  • flake/default.nix
📚 Learning: 2026-03-01T12:27:25.837Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/test.md:0-0
Timestamp: 2026-03-01T12:27:25.837Z
Learning: For flake.nix or flake.lock changes, run a full flake check in addition to building representative configs

Applied to files:

  • flake/ci/flake-module.nix
  • flake/default.nix
📚 Learning: 2026-03-01T12:24:29.910Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/contributing/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:29.910Z
Learning: Applies to {flake.nix,flake.lock} : Run `nix flake check` (with devenv-root override) before submitting changes

Applied to files:

  • flake/ci/flake-module.nix
  • flake/default.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to flake/nixos/** : NixOS flake modules should be organized in the `flake/nixos/` directory

Applied to files:

  • flake/ci/flake-module.nix
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Applies to flake/nixos/flake-module.nix : For CUDA or ROCm hardware acceleration support, register the host in `flake/nixos/flake-module.nix` under the appropriate `accelerationHosts` category

Applied to files:

  • flake/ci/flake-module.nix
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to flake.nix : Use `./flake/ci/detect-affected-outputs.nu nixosConfigurations --json` and `./flake/ci/detect-affected-outputs.nu homeConfigurations --json` to identify which outputs are affected by dirty files in CI

Applied to files:

  • flake/ci/flake-module.nix
  • flake/default.nix
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Host auto-discovery scans `hosts/` for subdirectories, filters out `shared/` and `secrets.yaml`, and automatically registers each as a nixosConfiguration

Applied to files:

  • flake/ci/flake-module.nix
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to **/*.nix : Use `nix eval .#nixosConfigurations.<host>.config.system.build.toplevel --apply 'x: "ok"'` to check if Nix expressions evaluate correctly

Applied to files:

  • flake/ci/flake-module.nix
  • flake/default.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:24:15.388Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/building/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:15.388Z
Learning: Build a host's NixOS system using `nix build .#nixosConfigurations.<host>.config.system.build.toplevel`

Applied to files:

  • flake/ci/flake-module.nix
  • tests/mkNode.nix
📚 Learning: 2026-03-01T12:27:16.409Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/security.md:0-0
Timestamp: 2026-03-01T12:27:16.409Z
Learning: Applies to **/*.nix : Apply systemd hardening options (DynamicUser, ProtectSystem, ProtectHome, PrivateTmp, NoNewPrivileges, CapabilityBoundingSet, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, MemoryDenyWriteExecute, LockPersonality) to service definitions

Applied to files:

  • docs/src/modules/nixos/services.md
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to hosts/shared/optional/** : Optional NixOS features (gaming, containers, etc.) should be organized in `hosts/shared/optional/`

Applied to files:

  • docs/src/modules/nixos/services.md
  • modules/nixos/laptop/default.nix
  • modules/nixos/shared/core/default.nix
  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/home-manager/**/*.nix : Create Home-Manager modules at `modules/home-manager/<category>/<name>.nix` with osConfig parameter support and conditional config application using mkIf

Applied to files:

  • docs/src/modules/nixos/services.md
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/home-manager/**/*.nix : Use `custom.<name>` namespace for custom extensions in Home-Manager modules

Applied to files:

  • docs/src/modules/nixos/services.md
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/**/*.nix : Create NixOS modules at `modules/nixos/<category>/<name>.nix` with standard pattern including options definition, lib imports (mkEnableOption, mkOption, mkIf, types), config variable binding, and conditional config application using mkIf

Applied to files:

  • docs/src/modules/nixos/services.md
  • tests/mkNode.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core/default.nix
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to flake.{nix,lock} : Verify `flake.lock` conflicts by checking if inputs were updated and ensuring compatibility between updated inputs

Applied to files:

  • flake/default.nix
📚 Learning: 2026-03-01T12:24:38.213Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/debugging/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:38.213Z
Learning: Use `nix flake check --no-build` to verify flake syntax validity without building

Applied to files:

  • flake/default.nix
📚 Learning: 2026-03-01T12:26:31.937Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/testing/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:31.937Z
Learning: Run `nix flake check --override-input devenv-root "file+file://$PWD/.devenv/root"` to perform a full flake check

Applied to files:

  • flake/default.nix
📚 Learning: 2026-03-01T12:24:15.388Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/building/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:15.388Z
Learning: Use `nix flake check` to evaluate all configurations and run linters

Applied to files:

  • flake/default.nix
📚 Learning: 2026-03-01T12:27:25.837Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/test.md:0-0
Timestamp: 2026-03-01T12:27:25.837Z
Learning: Use 'nix eval .#homeConfigurations --apply "builtins.attrNames"' to list available home configurations

Applied to files:

  • flake/default.nix
📚 Learning: 2026-03-01T12:27:25.837Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/test.md:0-0
Timestamp: 2026-03-01T12:27:25.837Z
Learning: Use 'nix eval .#nixosConfigurations --apply "builtins.attrNames"' to list available host configurations

Applied to files:

  • flake/default.nix
  • tests/mkNode.nix
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to **/*.nix : Use `nix eval .#nixosConfigurations.<host>.config.services --apply 'builtins.attrNames'` to diagnose 'attribute not found' errors by listing available attributes

Applied to files:

  • flake/default.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Always use `mkIf` guards on config sections that are conditionally applied

Applied to files:

  • flake/default.nix
📚 Learning: 2026-03-01T12:26:51.425Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/ci-failure.md:0-0
Timestamp: 2026-03-01T12:26:51.425Z
Learning: Applies to **/*.nix : When a new module isn't being found, verify the imports list in the parent module, check that the file path is correct (use kebab-case), and ensure the module is syntactically valid

Applied to files:

  • tests/mkNode.nix
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Applies to hosts/server/*/default.nix : Server hosts must set `host.device.isHeadless = true` in their configuration

Applied to files:

  • tests/mkNode.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to modules/nixos/** : Reusable NixOS module fragments should be placed in `modules/nixos/` directory

Applied to files:

  • modules/nixos/server/tests.nix
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to pkgs/default.nix : Custom packages should export their definitions through `pkgs/default.nix`

Applied to files:

  • modules/nixos/shared/core/default.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:27:02.914Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/agent/nix-review.md:0-0
Timestamp: 2026-03-01T12:27:02.914Z
Learning: Applies to **/*.nix : Use `mkDefault`, `mkForce`, and `mkOverride` correctly to control option priority

Applied to files:

  • modules/nixos/shared/core/default.nix
  • tests/default.nix
📚 Learning: 2026-03-01T12:25:06.603Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/modules/SKILL.md:0-0
Timestamp: 2026-03-01T12:25:06.603Z
Learning: Applies to modules/nixos/hardware/**/*.nix : Use `hardware.<name>` namespace for hardware configuration in NixOS modules

Applied to files:

  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:24:57.319Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/hosts/SKILL.md:0-0
Timestamp: 2026-03-01T12:24:57.319Z
Learning: Applies to hosts/{desktop,laptop}/*/hardware.nix : Physical host machines (desktops/laptops) must include a `hardware.nix` file with hardware-specific configuration

Applied to files:

  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:26:14.740Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/project-structure/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:14.740Z
Learning: Applies to home/shared/desktop/** : Shared desktop environment configurations should be in `home/shared/desktop/`

Applied to files:

  • docs/src/modules/nixos/desktop.md
📚 Learning: 2026-03-01T12:26:01.610Z
Learnt from: CR
Repo: DaRacci/nix-config PR: 0
File: .opencode/skills/packages/SKILL.md:0-0
Timestamp: 2026-03-01T12:26:01.610Z
Learning: Applies to pkgs/*/default.nix : Each package should have its own directory under pkgs/ with a default.nix file containing the package definition

Applied to files:

  • tests/default.nix

Comment thread docs/src/modules/nixos/desktop.md Outdated
Comment thread modules/nixos/desktop/virtual-machine.nix
Comment thread modules/nixos/server/tests.nix Outdated
Comment thread modules/nixos/server/tests.nix Outdated
Comment thread tests/lib.nix
Comment thread tests/mkNode.nix
Comment on lines +7 to +11
imports = [
(import "${self}/modules/flake/apply/system.nix" {
inherit allocations hostName;
deviceType = "server";
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
echo '== tests/mkNode.nix =='
sed -n '1,80p' tests/mkNode.nix
echo
echo '== lib/builders/mkSystem.nix =='
sed -n '30,70p' lib/builders/mkSystem.nix

Repository: DaRacci/nix-config

Length of output: 1518


Build each test node from the real host module stack.

The test node only imports modules/flake/apply/system.nix, whilst the production builder (lib/builders/mkSystem.nix) includes all nixos modules, device-type modules, the host directory, and shared configuration modules. The cluster test will pass with near-empty VMs, failing to validate actual server configurations.

Either include the full module stack or reuse lib/builders/mkSystem.nix to ensure test parity with production builds.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/mkNode.nix` around lines 7 - 11, The test node import currently uses
only modules/flake/apply/system.nix causing tests to build minimal VMs; update
the imports to build test nodes with the full production module stack by either
reusing the existing builder lib/builders/mkSystem.nix or by expanding the
imports to include the NixOS modules, device-type modules, host directory and
shared config modules (preserve existing attributes like allocations, hostName
and deviceType). Locate the imports block that references
modules/flake/apply/system.nix and replace it with a call to
lib/builders/mkSystem.nix (or mirror its module list) so test VMs are built the
same way as production.

@DaRacci DaRacci force-pushed the push-xvsqsqnwmrup branch from 072e115 to 2a6a397 Compare March 28, 2026 08:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
modules/nixos/desktop/virtual-machine.nix (1)

74-74: ⚠️ Potential issue | 🔴 Critical

mkDoc is not a standard lib function — this will cause evaluation failure.

The mkDoc function used here does not exist in nixpkgs.lib. This will throw an "attribute 'mkDoc' missing" error during evaluation. Use a plain string instead.

🐛 Proposed fix
-            description = mkDoc "The percentage of maxMemory to reserve for the host.";
+            description = "The percentage of maxMemory to reserve for the host.";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/desktop/virtual-machine.nix` at line 74, The description
attribute for the virtual machine option uses a non-existent mkDoc function
which will break evaluation; replace the use of mkDoc in the description
assignment (the line containing description = mkDoc "The percentage of maxMemory
to reserve for the host."; ) with a plain string literal (e.g. description =
"The percentage of maxMemory to reserve for the host.";), ensuring no mkDoc
references remain in the virtual-machine.nix option definition.
modules/nixos/shared/core/printing.nix (1)

16-21: ⚠️ Potential issue | 🟠 Major

Wrap the enable assignment with lib.mkDefault for consistency with other custom.core toggles.

The custom.core.audio, custom.core.bluetooth, and custom.core.network options in default.nix define their defaults at the option level (lines 34–53). However, custom.core.printing.enable lacks a default in its option definition and instead assigns its value in the config section (line 18) without mkDefault. This creates an inconsistency: if a host-level configuration sets custom.core.printing.enable without using mkDefault, both the module and host assignment would be at priority 100, causing a merge conflict. Wrap the assignment in lib.mkDefault to allow host-level overrides to take precedence and align with NixOS module conventions.

Suggested fix
  config = mkMerge [
    {
-      custom.core.printing.enable = config.host.device.role != "server" && !config.host.device.isVirtual;
+      custom.core.printing.enable = lib.mkDefault (
+        config.host.device.role != "server" && !config.host.device.isVirtual
+      );
    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/shared/core/printing.nix` around lines 16 - 21, The
config-level assignment for custom.core.printing.enable should be wrapped with
lib.mkDefault to match other custom.core toggles; update the config = mkMerge
block where custom.core.printing.enable is set (currently using
config.host.device.role != "server" && !config.host.device.isVirtual) to instead
call lib.mkDefault(...) so host-level overrides win and avoid merge-priority
conflicts with option-level defaults (see related symbols:
custom.core.printing.enable, lib.mkDefault, config = mkMerge, cfg.enable).
♻️ Duplicate comments (2)
modules/nixos/server/tests.nix (2)

10-11: ⚠️ Potential issue | 🔴 Critical

Import type helpers from lib.types, not lib.type.

Line 10 and Line 11 currently pull types from lib.type, which will fail evaluation in standard NixOS modules.

Proposed fix
 let
-  inherit (lib) type mkOption mkEnableOption;
-  inherit (type) submodule attrsOf either listOf str bool functionTo;
+  inherit (lib) mkEnableOption mkOption;
+  inherit (lib.types) attrsOf bool either functionTo listOf str submodule;
 in {
#!/bin/bash
# Verify current type-helper imports and whether any custom lib.type alias exists.
rg -n -C2 --type=nix '\binherit\s+\(lib\)\s+type\b|\blib\.type\b|\blib\.types\b'

Based on learnings: Verify attribute names, imports, and option paths to resolve attribute-missing errors in Nix configurations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/server/tests.nix` around lines 10 - 11, The module is importing
type helpers from lib.type which is incorrect; change the imports to use
lib.types so the type helpers (mkOption, mkEnableOption, submodule, attrsOf,
either, listOf, str, bool, functionTo) are pulled from lib.types instead of
lib.type and update both inherit statements accordingly to reference lib.types.

17-38: ⚠️ Potential issue | 🔴 Critical

Wrap server.tests.units in mkOption.

Line 17 assigns a raw type under options; this needs to be an option declaration to evaluate correctly in the module system.

Proposed fix
-      units = attrsOf (submodule ({ name, ... }: {
-        options = {
-          name = mkOption {
-            type = str;
-            default = name;
-            description = ''
-              The name to give to this unit test.
-              This is used to enter into a subtest within the testScript of the cluster test.
-            '';
-          };
-
-          testScript = mkOption {
-            type = either str (functionTo str);
-            description = ''
-              Python code to be ran within the subtest for this unit.
-
-              If this is a function with one argument of this nodes config.
-              If this is a function with two arguments, the second argument is the entire cluster configuration.
-            '';
-          };
-        };
-      }));
+      units = mkOption {
+        type = attrsOf (submodule ({ name, ... }: {
+          options = {
+            name = mkOption {
+              type = str;
+              default = name;
+              description = ''
+                The name to give to this unit test.
+                This is used to enter into a subtest within the testScript of the cluster test.
+              '';
+            };
+
+            testScript = mkOption {
+              type = either str (functionTo str);
+              description = ''
+                Python code to be ran within the subtest for this unit.
+
+                If this is a function with one argument of this nodes config.
+                If this is a function with two arguments, the second argument is the entire cluster configuration.
+              '';
+            };
+          };
+        }));
+        default = { };
+      };
#!/bin/bash
# Verify how attrsOf/submodule options are declared in this repo and in this file.
rg -n -C3 --type=nix 'attrsOf\s*\(submodule|units\s*=\s*mkOption|units\s*=\s*attrsOf'

As per coding guidelines, follow the standard NixOS module structure pattern with proper options declarations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/server/tests.nix` around lines 17 - 38, The block assigning
server.tests.units uses attrsOf(submodule(...)) directly under options instead
of declaring it as an option; wrap the entire units value in a mkOption so it
becomes a proper NixOS option declaration. Specifically, change the declaration
of server.tests.units (the attrsOf(submodule({...}) value that defines options
name and testScript) to be returned from mkOption with appropriate type (e.g.,
attrsOf _ or an attributeset of submodules) and include its existing nested
options (name, testScript) as the option's documentation/type; ensure references
to attrsOf, submodule, and the nested options name and testScript remain intact
while replacing the raw value with mkOption(...) so the module system evaluates
it correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@flake/ci/flake-module.nix`:
- Line 28: The partition allocations accessor is incorrect: change the inherited
path from config.partitions.nixos.module.allocations to
config.partitions.nixos.allocations; locate the inherit statement that
references (config.partitions.nixos.module) allocations and update it to inherit
from (config.partitions.nixos) allocations so it matches how the flake module is
merged and aligns with other accessors like config.partitions.docs.extraInputs.

In `@modules/home-manager/services/mcpo.nix`:
- Line 11: The import in modules/home-manager/services/mcpo.nix currently uses
the `${self}`-style absolute path in the expression `(import
"${self}/modules/nixos/shared/services/mcpo.nix" {` — replace that with a
file-relative import (e.g., `./modules/nixos/shared/services/mcpo.nix`) to
follow repo conventions; update the import expression in the same file by
changing the path string to the relative path so the module is loaded relative
to modules/home-manager/services/mcpo.nix rather than via `${self}`.

In `@modules/nixos/server/tests.nix`:
- Around line 13-42: The server.tests options are declared but never used;
update the test harness (tests/default.nix) to read the evaluated host config's
server.tests.* and build a composite testScript passed to runNixOSTest: iterate
over server.tests.units, call each unit's testScript (handling both string and
function signatures—1-arg node config or 2-arg node+cluster config) to produce
the per-host subtests, and respect server.tests.enable to skip wiring when
disabled; ensure the evaluated host config is threaded into the harness so
testScript functions receive the proper node/cluster args before invoking
runNixOSTest.

In `@modules/nixos/shared/core/default.nix`:
- Around line 58-62: Update the custom.defaultGroups list to use the correct
NetworkManager group name and avoid adding non-existent PipeWire group: replace
any occurrence of "network" in custom.defaultGroups with "networkmanager", and
only append "pipewire" to custom.defaultGroups when services.pipewire.systemWide
is true (guard the addition with that condition); apply the same change for the
other occurrence of custom.defaultGroups later in the file (the second block
around lines referenced in the review).

In `@tests/default.nix`:
- Line 24: Fix the typo in the comment string "Wait for all nodes to each
multi-user.target" by changing "each" to "reach" so it reads "Wait for all nodes
to reach multi-user.target"; update the comment where that exact phrase appears
to correct the wording.
- Line 12: The import binding testLib in tests/default.nix is unused; remove the
unused import statement (the line defining testLib = import ./lib.nix;) so the
file no longer creates an unused symbol and to avoid lint warnings.

---

Outside diff comments:
In `@modules/nixos/desktop/virtual-machine.nix`:
- Line 74: The description attribute for the virtual machine option uses a
non-existent mkDoc function which will break evaluation; replace the use of
mkDoc in the description assignment (the line containing description = mkDoc
"The percentage of maxMemory to reserve for the host."; ) with a plain string
literal (e.g. description = "The percentage of maxMemory to reserve for the
host.";), ensuring no mkDoc references remain in the virtual-machine.nix option
definition.

In `@modules/nixos/shared/core/printing.nix`:
- Around line 16-21: The config-level assignment for custom.core.printing.enable
should be wrapped with lib.mkDefault to match other custom.core toggles; update
the config = mkMerge block where custom.core.printing.enable is set (currently
using config.host.device.role != "server" && !config.host.device.isVirtual) to
instead call lib.mkDefault(...) so host-level overrides win and avoid
merge-priority conflicts with option-level defaults (see related symbols:
custom.core.printing.enable, lib.mkDefault, config = mkMerge, cfg.enable).

---

Duplicate comments:
In `@modules/nixos/server/tests.nix`:
- Around line 10-11: The module is importing type helpers from lib.type which is
incorrect; change the imports to use lib.types so the type helpers (mkOption,
mkEnableOption, submodule, attrsOf, either, listOf, str, bool, functionTo) are
pulled from lib.types instead of lib.type and update both inherit statements
accordingly to reference lib.types.
- Around line 17-38: The block assigning server.tests.units uses
attrsOf(submodule(...)) directly under options instead of declaring it as an
option; wrap the entire units value in a mkOption so it becomes a proper NixOS
option declaration. Specifically, change the declaration of server.tests.units
(the attrsOf(submodule({...}) value that defines options name and testScript) to
be returned from mkOption with appropriate type (e.g., attrsOf _ or an
attributeset of submodules) and include its existing nested options (name,
testScript) as the option's documentation/type; ensure references to attrsOf,
submodule, and the nested options name and testScript remain intact while
replacing the raw value with mkOption(...) so the module system evaluates it
correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 56811165-b6e5-477d-a481-a22044ea4ca2

📥 Commits

Reviewing files that changed from the base of the PR and between 072e115 and 2a6a397.

📒 Files selected for processing (58)
  • docs/src/modules/nixos/desktop.md
  • docs/src/modules/nixos/services.md
  • flake/ci/flake-module.nix
  • flake/default.nix
  • lib/builders/mkSystem.nix
  • modules/home-manager/services/mcpo.nix
  • modules/nixos/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/desktop/rgb.nix
  • modules/nixos/desktop/vfio.nix
  • modules/nixos/desktop/virtual-machine.nix
  • modules/nixos/encrypted-root.nix
  • modules/nixos/laptop/default.nix
  • modules/nixos/proxies.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core.nix
  • modules/nixos/shared/core/auto-upgrade.nix
  • modules/nixos/shared/core/boot/default.nix
  • modules/nixos/shared/core/boot/quietboot.nix
  • modules/nixos/shared/core/boot/secureboot.nix
  • modules/nixos/shared/core/boot/systemd-boot.nix
  • modules/nixos/shared/core/default.nix
  • modules/nixos/shared/core/hardware/backlight.nix
  • modules/nixos/shared/core/hardware/biometrics.nix
  • modules/nixos/shared/core/hardware/bluetooth.nix
  • modules/nixos/shared/core/hardware/cooling.nix
  • modules/nixos/shared/core/hardware/default.nix
  • modules/nixos/shared/core/hardware/display.nix
  • modules/nixos/shared/core/hardware/graphics.nix
  • modules/nixos/shared/core/hardware/openrgb.nix
  • modules/nixos/shared/core/hardware/storage/default.nix
  • modules/nixos/shared/core/hardware/storage/ephemeral.nix
  • modules/nixos/shared/core/hardware/storage/maintenance.nix
  • modules/nixos/shared/core/hardware/storage/partitions/btrfs.nix
  • modules/nixos/shared/core/hardware/storage/partitions/esp.nix
  • modules/nixos/shared/core/hardware/storage/partitions/luks.nix
  • modules/nixos/shared/core/hardware/storage/partitions/tmpfs.nix
  • modules/nixos/shared/core/host/default.nix
  • modules/nixos/shared/core/host/device.nix
  • modules/nixos/shared/core/host/persistence.nix
  • modules/nixos/shared/core/printing.nix
  • modules/nixos/shared/default.nix
  • modules/nixos/shared/features/display-manager.nix
  • modules/nixos/shared/features/hm-helper/1password.nix
  • modules/nixos/shared/features/hm-helper/default.nix
  • modules/nixos/shared/features/hm-helper/kde-connect.nix
  • modules/nixos/shared/features/hm-helper/mpv.nix
  • modules/nixos/shared/features/hm-helper/nautilus.nix
  • modules/nixos/shared/features/remote.nix
  • modules/nixos/shared/services/default.nix
  • modules/nixos/shared/services/huntress.nix
  • modules/nixos/shared/services/mcpo.nix
  • modules/nixos/shared/services/metrics.nix
  • modules/nixos/shared/services/tailscale.nix
  • tests/default.nix
  • tests/lib.nix
  • tests/mkNode.nix
💤 Files with no reviewable changes (4)
  • modules/nixos/proxies.nix
  • modules/nixos/default.nix
  • modules/nixos/encrypted-root.nix
  • modules/nixos/shared/core.nix

Comment thread flake/ci/flake-module.nix Outdated
Comment thread modules/home-manager/services/mcpo.nix Outdated
Comment thread modules/nixos/server/tests.nix
Comment thread modules/nixos/shared/core/default.nix Outdated
Comment thread tests/default.nix Outdated
Comment thread tests/default.nix Outdated
@DaRacci DaRacci force-pushed the push-xvsqsqnwmrup branch from 2a6a397 to 692fe91 Compare April 30, 2026 12:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/nixos/desktop/virtual-machine.nix (1)

74-74: ⚠️ Potential issue | 🔴 Critical

Replace mkDoc with plain string—mkDoc is undefined.

The code uses mkDoc on line 74, but this function is not defined in your custom lib or standard Nix lib. This will cause module evaluation to fail with an "undefined variable" error.

Use a plain string instead:

Suggested fix
-            description = mkDoc "The percentage of maxMemory to reserve for the host.";
+            description = "The percentage of maxMemory to reserve for the host.";

If you need markdown formatting in descriptions, use lib.mdDoc instead, but for plain text a simple string is sufficient.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/desktop/virtual-machine.nix` at line 74, Replace the undefined
mkDoc call used for the description attribute with a plain string (or lib.mdDoc
if markdown is needed); specifically change the description = mkDoc "The
percentage of maxMemory to reserve for the host."; to use a simple string value
for the description property (or lib.mdDoc("...") if you want markdown),
ensuring you update the description assignment in the virtual-machine module
where description is set so evaluation no longer fails due to mkDoc being
undefined.
♻️ Duplicate comments (6)
tests/lib.nix (1)

6-10: ⚠️ Potential issue | 🟠 Major

Pass the node object into the callback, not node.name.

The helper currently feeds a string expression to f, so generated snippets can’t safely call node methods.

Suggested fix
   runOnAllNodes = f: ''
     for node in cluster.nodes:
       with subtest(node.name):
-        ${f "node.name"}
+        ${f "node"}
   '';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/lib.nix` around lines 6 - 10, The helper runOnAllNodes currently
invokes the callback f with the string "node.name", preventing consumers from
accessing node methods; change the invocation from ${f "node.name"} to ${f
"node"} so the actual node object is passed (keep the surrounding for node in
cluster.nodes and the with subtest(node.name) as-is), and update any callers of
runOnAllNodes to expect a node object instead of a name string.
tests/default.nix (1)

21-29: ⚠️ Potential issue | 🟠 Major

Wire server.tests units into testScript generation.

This script is static and never reads server.tests.enable / server.tests.units.*.testScript, so the newly declared framework remains inert in CI.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/default.nix` around lines 21 - 29, The testScript in default.nix is
static and omits any server.tests configuration; update the generation of
testScript (the value bound to testScript and the start_all()/cluster.nodes
logic) to conditionally include server.tests when server.tests.enable is true by
iterating server.tests.units and injecting each unit's testScript (e.g.,
server.tests.units.*.testScript) or calling its test routine into the combined
testScript; ensure the produced script still calls start_all(), waits for
multi-user.target on cluster.nodes, and then executes or sources each enabled
unit's testScript so CI picks up server.tests units.
modules/nixos/server/tests.nix (2)

17-38: ⚠️ Potential issue | 🔴 Critical

Declare server.tests.units with mkOption.

Inside options, this is currently a raw type expression, not an option declaration. That prevents the option tree from evaluating correctly.

Suggested fix
-      units = attrsOf (submodule ({ name, ... }: {
-        options = {
-          name = mkOption {
-            type = str;
-            default = name;
-            description = ''
-              The name to give to this unit test.
-              This is used to enter into a subtest within the testScript of the cluster test.
-            '';
-          };
-
-          testScript = mkOption {
-            type = either str (functionTo str);
-            description = ''
-              Python code to be ran within the subtest for this unit.
-
-              If this is a function with one argument of this nodes config.
-              If this is a function with two arguments, the second argument is the entire cluster configuration.
-            '';
-          };
-        };
-      }));
+      units = mkOption {
+        type = attrsOf (submodule ({ name, ... }: {
+          options = {
+            name = mkOption {
+              type = str;
+              default = name;
+              description = ''
+                The name to give to this unit test.
+                This is used to enter into a subtest within the testScript of the cluster test.
+              '';
+            };
+
+            testScript = mkOption {
+              type = either str (functionTo str);
+              description = ''
+                Python code to be ran within the subtest for this unit.
+
+                If this is a function with one argument of this nodes config.
+                If this is a function with two arguments, the second argument is the entire cluster configuration.
+              '';
+            };
+          };
+        }));
+        default = { };
+      };

As per coding guidelines: Create NixOS modules with standard options definitions using mkOption/mkEnableOption.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/server/tests.nix` around lines 17 - 38, The top-level option
server.tests.units is currently defined as a raw attrsOf(submodule(...))
expression instead of an mkOption declaration; wrap that expression in mkOption
(e.g., set server.tests.units = mkOption { type = attrsOf (submodule ({ name,
... }: { options = { name = mkOption { ... }; testScript = mkOption { ... }; };
})); description = "..."; }); so the option tree evaluates correctly and follows
the NixOS module pattern; keep the inner submodule options (name, testScript) as
mkOption entries and add an appropriate description/defaults for
server.tests.units.

10-11: ⚠️ Potential issue | 🔴 Critical

Import type helpers from lib.types, not lib.type.

This currently resolves from a non-standard path and will break evaluation when type constructors are used.

Suggested fix
 let
-  inherit (lib) type mkOption mkEnableOption;
-  inherit (type) submodule attrsOf either listOf str bool functionTo;
+  inherit (lib) mkOption mkEnableOption;
+  inherit (lib.types) submodule attrsOf either listOf str bool functionTo;
 in {

Based on learnings: Verify attribute names, imports, and option paths to resolve 'attribute missing' errors in Nix configurations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/server/tests.nix` around lines 10 - 11, The import uses
lib.type which is incorrect; change the inherits so the type constructors come
from lib.types (e.g. reference mkOption and mkEnableOption from lib.types) and
ensure the second inherit uses the correct symbol source for submodule, attrsOf,
either, listOf, str, bool, and functionTo; update the inherit lines to import
mkOption/mkEnableOption and the listed type helpers from lib.types so Nix
evaluation uses the standard type constructors.
tests/mkNode.nix (1)

7-12: ⚠️ Potential issue | 🟠 Major

Build test nodes from the full host module stack.

Right now the node definition only applies the flake-apply layer, so cluster checks can pass without exercising the actual server host modules.

Based on learnings: All affected configurations MUST be tested, and this requires node definitions that mirror real host configuration paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/mkNode.nix` around lines 7 - 12, The test node currently imports only
the flake-apply layer ("${self}/modules/flake/apply/system.nix") so cluster
checks bypass real host modules; change the import to load the full host module
stack used in production (the real host module path that composes allocations
and hostName) instead of the flake-apply shortcut, keeping the same inherited
attributes (inherit allocations hostName) and deviceType = "server" so tests
exercise the actual server host modules.
modules/nixos/shared/core/default.nix (1)

58-62: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use service-aligned group names and gate pipewire membership.

Line 130 uses "network", which does not match the usual NetworkManager access group, and Line 60 adds "pipewire" unconditionally. This can produce ineffective or invalid group assignments.

Suggested fix
     (mkIf cfg.audio.enable {
-      custom.defaultGroups = [
-        "audio"
-        "pipewire"
-        "rtkit"
-      ];
+      custom.defaultGroups =
+        [
+          "audio"
+          "rtkit"
+        ]
+        ++ lib.optional config.services.pipewire.systemWide "pipewire";
@@
     (mkIf cfg.network.enable {
-      custom.defaultGroups = [ "network" ];
+      custom.defaultGroups = [ "networkmanager" ];
       networking.networkmanager.enable = true;
     })
#!/bin/bash
# Read-only verification of relevant group usage and toggles.
rg -n -C2 'custom\.defaultGroups\s*=\s*\[\s*"network"' --type nix
rg -n -C2 '"pipewire"' --type nix
rg -n -C2 'services\.pipewire\.systemWide\s*=\s*true' --type nix
rg -n -C2 'users\.groups\.(network|networkmanager|pipewire)\b' --type nix

As per coding guidelines, "Verify attribute names, imports, and option paths to resolve 'attribute missing' errors in Nix configurations".

Also applies to: 129-131

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@modules/nixos/shared/core/default.nix` around lines 58 - 62, Update
custom.defaultGroups to use service-aligned group names and make pipewire
membership conditional: replace the hardcoded "network" with the
Distribution/Service group used by NetworkManager (e.g., "networkmanager") and
remove the unconditional "pipewire" entry in custom.defaultGroups; instead, add
"pipewire" to defaultGroups only when services.pipewire.systemWide is true. Also
verify that users.groups contains the corresponding group attributes
(networkmanager and pipewire) so group names match existing definitions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.vscode/settings.json:
- Line 2: Remove the workspace-level setting that disables Git by deleting the
"git.enabled": false entry from .vscode/settings.json (or revert that file to
not include the key) and instead apply this preference in your personal VS Code
user settings if needed; look for the "git.enabled" key in the settings file and
remove or relocate it so the repository does not force-disable Source Control
for all users.

In `@modules/nixos/shared/core/hardware/backlight.nix`:
- Around line 44-46: Change the udev rule so i2c devices are assigned to a
dedicated group and restrictive mode: update services.udev.extraRules replacing
GROUP="users" with GROUP="i2c", MODE="0660" for the KERNEL=="i2c-[0-9]*" rule,
and ensure the group exists (e.g., add a users.groups.i2c declaration elsewhere
in the Nix config). This scopes access to the i2c group and enforces least
privilege for the KERNEL=="i2c-[0-9]*" devices.

---

Outside diff comments:
In `@modules/nixos/desktop/virtual-machine.nix`:
- Line 74: Replace the undefined mkDoc call used for the description attribute
with a plain string (or lib.mdDoc if markdown is needed); specifically change
the description = mkDoc "The percentage of maxMemory to reserve for the host.";
to use a simple string value for the description property (or lib.mdDoc("...")
if you want markdown), ensuring you update the description assignment in the
virtual-machine module where description is set so evaluation no longer fails
due to mkDoc being undefined.

---

Duplicate comments:
In `@modules/nixos/server/tests.nix`:
- Around line 17-38: The top-level option server.tests.units is currently
defined as a raw attrsOf(submodule(...)) expression instead of an mkOption
declaration; wrap that expression in mkOption (e.g., set server.tests.units =
mkOption { type = attrsOf (submodule ({ name, ... }: { options = { name =
mkOption { ... }; testScript = mkOption { ... }; }; })); description = "...";
}); so the option tree evaluates correctly and follows the NixOS module pattern;
keep the inner submodule options (name, testScript) as mkOption entries and add
an appropriate description/defaults for server.tests.units.
- Around line 10-11: The import uses lib.type which is incorrect; change the
inherits so the type constructors come from lib.types (e.g. reference mkOption
and mkEnableOption from lib.types) and ensure the second inherit uses the
correct symbol source for submodule, attrsOf, either, listOf, str, bool, and
functionTo; update the inherit lines to import mkOption/mkEnableOption and the
listed type helpers from lib.types so Nix evaluation uses the standard type
constructors.

In `@modules/nixos/shared/core/default.nix`:
- Around line 58-62: Update custom.defaultGroups to use service-aligned group
names and make pipewire membership conditional: replace the hardcoded "network"
with the Distribution/Service group used by NetworkManager (e.g.,
"networkmanager") and remove the unconditional "pipewire" entry in
custom.defaultGroups; instead, add "pipewire" to defaultGroups only when
services.pipewire.systemWide is true. Also verify that users.groups contains the
corresponding group attributes (networkmanager and pipewire) so group names
match existing definitions.

In `@tests/default.nix`:
- Around line 21-29: The testScript in default.nix is static and omits any
server.tests configuration; update the generation of testScript (the value bound
to testScript and the start_all()/cluster.nodes logic) to conditionally include
server.tests when server.tests.enable is true by iterating server.tests.units
and injecting each unit's testScript (e.g., server.tests.units.*.testScript) or
calling its test routine into the combined testScript; ensure the produced
script still calls start_all(), waits for multi-user.target on cluster.nodes,
and then executes or sources each enabled unit's testScript so CI picks up
server.tests units.

In `@tests/lib.nix`:
- Around line 6-10: The helper runOnAllNodes currently invokes the callback f
with the string "node.name", preventing consumers from accessing node methods;
change the invocation from ${f "node.name"} to ${f "node"} so the actual node
object is passed (keep the surrounding for node in cluster.nodes and the with
subtest(node.name) as-is), and update any callers of runOnAllNodes to expect a
node object instead of a name string.

In `@tests/mkNode.nix`:
- Around line 7-12: The test node currently imports only the flake-apply layer
("${self}/modules/flake/apply/system.nix") so cluster checks bypass real host
modules; change the import to load the full host module stack used in production
(the real host module path that composes allocations and hostName) instead of
the flake-apply shortcut, keeping the same inherited attributes (inherit
allocations hostName) and deviceType = "server" so tests exercise the actual
server host modules.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5f064077-dd35-408a-abda-03433eadc7e6

📥 Commits

Reviewing files that changed from the base of the PR and between 2a6a397 and 692fe91.

⛔ Files ignored due to path filters (11)
  • openspec/changes/testing-framework-predeploy/.openspec.yaml is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/README.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/design.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/proposal.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/server-vm-test-harness/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/service-aware-vm-tests/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/vm-test-documentation/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/vm-test-profile-overrides/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/vm-test-secret-generation/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/woodpecker-vm-test-gating/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/tasks.md is excluded by !openspec/**
📒 Files selected for processing (57)
  • .vscode/settings.json
  • flake/ci/flake-module.nix
  • flake/default.nix
  • lib/builders/mkSystem.nix
  • modules/home-manager/services/mcpo.nix
  • modules/nixos/default.nix
  • modules/nixos/desktop/default.nix
  • modules/nixos/desktop/rgb.nix
  • modules/nixos/desktop/vfio.nix
  • modules/nixos/desktop/virtual-machine.nix
  • modules/nixos/encrypted-root.nix
  • modules/nixos/laptop/default.nix
  • modules/nixos/proxies.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/shared/core.nix
  • modules/nixos/shared/core/auto-upgrade.nix
  • modules/nixos/shared/core/boot/default.nix
  • modules/nixos/shared/core/boot/quietboot.nix
  • modules/nixos/shared/core/boot/secureboot.nix
  • modules/nixos/shared/core/boot/systemd-boot.nix
  • modules/nixos/shared/core/default.nix
  • modules/nixos/shared/core/hardware/backlight.nix
  • modules/nixos/shared/core/hardware/biometrics.nix
  • modules/nixos/shared/core/hardware/bluetooth.nix
  • modules/nixos/shared/core/hardware/cooling.nix
  • modules/nixos/shared/core/hardware/default.nix
  • modules/nixos/shared/core/hardware/display.nix
  • modules/nixos/shared/core/hardware/graphics.nix
  • modules/nixos/shared/core/hardware/openrgb.nix
  • modules/nixos/shared/core/hardware/storage/default.nix
  • modules/nixos/shared/core/hardware/storage/ephemeral.nix
  • modules/nixos/shared/core/hardware/storage/maintenance.nix
  • modules/nixos/shared/core/hardware/storage/partitions/btrfs.nix
  • modules/nixos/shared/core/hardware/storage/partitions/esp.nix
  • modules/nixos/shared/core/hardware/storage/partitions/luks.nix
  • modules/nixos/shared/core/hardware/storage/partitions/tmpfs.nix
  • modules/nixos/shared/core/host/default.nix
  • modules/nixos/shared/core/host/device.nix
  • modules/nixos/shared/core/host/persistence.nix
  • modules/nixos/shared/core/printing.nix
  • modules/nixos/shared/default.nix
  • modules/nixos/shared/features/display-manager.nix
  • modules/nixos/shared/features/hm-helper/1password.nix
  • modules/nixos/shared/features/hm-helper/default.nix
  • modules/nixos/shared/features/hm-helper/kde-connect.nix
  • modules/nixos/shared/features/hm-helper/mpv.nix
  • modules/nixos/shared/features/hm-helper/nautilus.nix
  • modules/nixos/shared/features/remote.nix
  • modules/nixos/shared/services/default.nix
  • modules/nixos/shared/services/huntress.nix
  • modules/nixos/shared/services/mcpo.nix
  • modules/nixos/shared/services/metrics.nix
  • modules/nixos/shared/services/tailscale.nix
  • tests/default.nix
  • tests/lib.nix
  • tests/mkNode.nix
💤 Files with no reviewable changes (4)
  • modules/nixos/proxies.nix
  • modules/nixos/encrypted-root.nix
  • modules/nixos/default.nix
  • modules/nixos/shared/core.nix

Comment thread .vscode/settings.json Outdated
Comment thread modules/nixos/shared/core/hardware/backlight.nix Outdated
@mergify mergify Bot added the conflict label Jun 6, 2026
DaRacci added 12 commits July 1, 2026 16:32
- Move mapAttrsToList from builtins to lib (Lix 2.94 compat)
- Builder accepts testUnits param, iterates in testScript
- Flake-module passes config.server.tests.units to builder
- Inject scenario name from directory name
Scenario files define nodes + testScript but not name.
Inject name = scenarioName so builder can set derivation name.
~48 unit tests, 7 multi-node scenarios, 2 infra + 1 security suites
across 3 phases. Based on full fleet audit: 7 hosts, 40+ services.
Audit found 15 missed services, 3 false positives, 11 brittle points.
Phase 1 (25 unit + 2 scenarios): per-host service tests + postgres/redis cross-host
Phase 2 (22 unit + 6 scenarios + security): secondary services, monitoring, proxy, firewall

Key:
- Scenarios self-contain services, test real behavior (psql, redis-cli, prometheus scrape, cross-host HTTP)
- Host-level unit tests verify service definitions exist (catches config breakage)
- Caddy TLS skipped (root CA install fails in QEMU sandbox)
- vm-test.nix overrides: postgres JIT off + trust auth, caddy deps stripped
- mkNode.nix stubs server options to avoid cross-config recursion

All 15 nixosTestConfigurations pass (7 hosts + 8 scenarios).
@DaRacci DaRacci force-pushed the push-xvsqsqnwmrup branch from 692fe91 to d600b72 Compare July 1, 2026 06:40
@gitguardian

gitguardian Bot commented Jul 1, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 4 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
34424190 Triggered Generic Password d600b72 tests/profiles/vm-test.nix View secret
34424190 Triggered Generic Password 7135633 tests/profiles/vm-test.nix View secret
34424190 Triggered Generic Password 7135633 tests/profiles/vm-test.nix View secret
34424190 Triggered Generic Password 011e1f6 tests/profiles/vm-test.nix View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 25

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@_run_tests.sh`:
- Line 7: The HOSTS array in _run_tests.sh is hardcoded and can drift from the
actual set of test hosts. Replace the static HOSTS definition with dynamic host
discovery, matching the approach used in .woodpecker/test-vm.yaml by evaluating
nixosTestConfigurations via nix eval so new hosts like nixarr, nixcloud, and
nixserv are picked up automatically. Keep the rest of the script logic unchanged
and ensure the dynamic source feeds the same HOSTS variable used by the test
loop.

In @.woodpecker/test-vm.yaml:
- Around line 25-32: The VM test loop in the Run VM tests step is swallowing
failures because `nix build` is followed by `|| echo "FAILED: $host"`, so the
script still exits successfully. Update the command block so failures from `nix
build ".#nixosTestConfigurations.$host"` are propagated and cause the step to
fail, using the `Run VM tests` job script and the `host` loop as the place to
fix it. Keep the per-host logging if needed, but ensure a non-zero exit from any
VM test build makes the pipeline fail.

In `@docs/src/development/vm_integration_tests.md`:
- Around line 187-190: The example command in vm_integration_tests.md uses
`--override-input` with `.`, which is not a valid flake input for setting
`testFilter` and should be removed or replaced. Update the section around the
`nix build` example to either keep only the local-edit command or show a command
that overrides a real named input, so the `postgres-connect` filter is
demonstrated correctly. Refer to the existing `nix build
.#nixosTestConfigurations.<host>` example and adjust that snippet accordingly.

In `@flake/nixos/flake-module.nix`:
- Around line 97-120: The scenario discovery block in the flake module should
only include directory entries from builtins.readDir so stray files like
README.md do not get imported as scenarios and break evaluation. Update the
scenario enumeration in the builder setup to filter by entry type before
constructing the listToAttrs mapping, using the existing scenariosDir/import
logic as the locator. Also guard the final // merge against silent name
collisions with server host names by detecting duplicate keys and failing
explicitly or separating the namespaces so auto-discovered scenarios cannot
overwrite host tests unnoticed.

In `@hosts/server/nixai/ai-agent.nix`:
- Around line 10-23: The unit test setup repeats the same LoadState check
boilerplate, so factor it into a shared helper instead of duplicating the
command in each `testScript`. Add a reusable function in `tests/lib.nix` such as
`mkLoadStateTest` that takes the node and unit name, builds the `systemctl show
... | grep -i loadstate` command, and returns the test script, then update
`server.tests.units` and the other matching call sites to use that helper
consistently.
- Around line 10-23: The unit tests for ai-agent-api and ai-agent-dashboard
currently use a grep on “loadstate” that will always pass and does not verify
the service actually loaded. Update the testScript commands in the
server.tests.units definitions to assert the expected loaded state explicitly,
using a case-insensitive match on the full LoadState value from systemctl show
(for example, the unique ai-agent-api.service and ai-agent-dashboard.service
checks should validate “LoadState=loaded” rather than just the key name). Apply
the same fix pattern consistently anywhere the same systemctl show | grep -i
loadstate check is repeated.

In `@hosts/server/nixarr/arr/downloader.nix`:
- Around line 88-100: The unit checks in server.tests.units for transmission and
sabnzbd are no-ops because `systemctl show ... | grep -i loadstate` always
succeeds. Update the testScript blocks to assert the actual `LoadState` value
returned by `systemctl show` for each service, using the existing transmission,
transmission-flood, and sabnzbd unit checks as the place to validate the
expected loaded state instead of just matching the property name.

In `@hosts/server/nixcloud/identity.nix`:
- Around line 216-220: The kanidm unit test is only checking that systemctl
outputs the LoadState field, so it cannot fail even when the service is missing
or inactive. Update the tests.units.kanidm testScript to assert the actual
expected LoadState value for kanidm.service rather than grepping for the key
name, using the existing nixcloud.succeed call so the test will fail when the
unit is masked, absent, or not loaded.

In `@hosts/server/nixcloud/immich.nix`:
- Around line 54-64: The unit tests for immich and immich-redis are using a
no-op `grep -i loadstate` check in their `testScript`, so the assertions never
verify the actual systemd state. Update both `tests.units.immich` and
`tests.units.immich-redis` in `immich.nix` to check the `LoadState` value
explicitly via `systemctl show` and compare it against the expected loaded
state, using the existing `immich-server.service` and `redis-immich.service`
identifiers.

In `@hosts/server/nixcloud/music.nix`:
- Around line 23-34: The unit tests for navidrome and music-assistant in
server.tests.units are currently using a no-op grep on the LoadState key, so
they never verify the actual service state. Update the testScript commands to
inspect the value returned by systemctl show for each service and assert the
expected loaded state using the existing navidrome.service and
music-assistant.service checks. Keep the fix localized to the server.tests.units
entries so both test cases validate real unit state instead of just matching the
key name.

In `@hosts/server/nixcloud/nextcloud.nix`:
- Around line 62-90: The unit tests in tests.units currently only check that
systemctl prints the LoadState field, which does not verify the service is
actually active or loaded. Update each testScript for nextcloud, elasticsearch,
clamav, imaginary, and notify-push to assert a meaningful LoadState value via
the existing nixcloud.succeed calls, using the corresponding service names
(phpfpm-nextcloud.service, elasticsearch.service, clamav-daemon.service,
imaginary.service, notify_push.service) so missing or failed units will fail the
tests.

In `@hosts/server/nixcloud/search.nix`:
- Around line 634-638: The searxng unit test is still using a no-op `grep -i
loadstate` check in `tests.units.searxng.testScript`, which does not
meaningfully assert service state. Update the `nixcloud.succeed(...)` command to
verify an actual expected property of `searxng.service` using `systemctl show`
and a concrete match, so the test fails when the service is not in the intended
state.

In `@hosts/server/nixdev/automation.nix`:
- Around line 100-107: The `tests.units.n8n` `testScript` is asserting only that
`systemctl show` prints the `LoadState` field, which is always true and can’t
detect a bad service state. Update the assertion in the `nixdev.succeed(...)`
call to check the actual value of `LoadState` for `n8n.service` instead of
grepping for the property name, so the test fails unless the unit is truly
loaded.

In `@hosts/server/nixdev/ci.nix`:
- Around line 25-30: The github-runner-nixos-runner-0.service test is only
checking that a LoadState line exists, so it can pass even when the unit is
broken. Update server.tests.units.github-runners in ci.nix to assert the actual
expected LoadState value using the testScript command instead of a generic grep,
so the check fails when the service does not load correctly.

In `@hosts/server/nixdev/coder.nix`:
- Around line 36-43: The coder unit test is only grepping for LoadState, so it
never verifies the service state. Update the testScript in the coder test to
assert the expected value from systemctl show for coder.service using a specific
LoadState check, following the same pattern used by the other unit test
assertions in this cohort.

In `@hosts/server/nixdev/default.nix`:
- Around line 26-33: The Docker unit test is asserting the presence of the
property name rather than validating its value, so it cannot detect a
failed-to-load docker.service. Update the testScript in
server.tests.units.docker to inspect the LoadState output from systemctl show
docker.service and assert that it equals the expected loaded state instead of
grepping for the key name. Use the existing docker testScript block to locate
the check and make the assertion value-based, not name-based.

In `@hosts/server/nixdev/registry.nix`:
- Around line 97-104: The current `docker-registry` unit test in `tests.units`
uses `systemctl show ... | grep -i loadstate`, which only matches the property
name and can pass even when the service load fails. Update the `testScript` to
assert the actual `LoadState` value from `docker-registry.service` via the
existing `nixdev.succeed` check, using `systemctl show` with a value comparison
so the test fails unless the service is properly loaded.

In `@hosts/server/nixdev/woodpecker.nix`:
- Around line 59-72: The `tests.units` checks for `woodpecker-server` and
`woodpecker-agent` are currently tautological because `systemctl show ... | grep
-i loadstate` matches the field name instead of verifying the service state.
Update both `testScript` blocks to assert the actual `LoadState` value reported
by `systemctl show` in a non-trivial way, so the `woodpecker-server` and
`woodpecker-agent` unit tests fail when the service is not loaded. Use the
existing `tests.units` entries and their `systemctl show` commands to locate the
assertions.

In `@hosts/server/nixio/adguard.nix`:
- Around line 223-228: The adguard unit test is using a tautological LoadState
check because `grep -i loadstate` matches the property name instead of the
service’s state. Update `server.tests.units.adguard` in the `testScript` to
assert the actual `systemctl show` value for `adguardhome.service` using the
correct property/value pattern, so the test verifies the service is loaded
rather than just finding the field name.

In `@hosts/server/nixio/default.nix`:
- Around line 96-103: The kernel-forwarding unit test is currently proving only
that sysctl can be written at runtime, not that the declared boot-time
configuration is applied. Update the testScript in
server.tests.units.kernel-forwarding to stop using the sysctl -w calls and only
verify the existing values with sysctl -n checks, so it validates the
boot.kernel.sysctl settings instead of re-setting them itself.

In `@hosts/server/nixmon/default.nix`:
- Around line 65-69: The node exporter test is checking the wrong systemd unit
name. Update the testScript in the node-exporter case to reference the unit used
by services.prometheus.exporters.node, specifically
prometheus-node-exporter.service, instead of node_exporter.service. Keep the
check in the same test block so it still verifies the exporter service state
correctly.
- Around line 34-76: The unit test scripts under server.tests.units all use the
no-op systemctl show ... | grep -i loadstate pattern, so they never assert the
service state value. Update each testScript for prometheus, loki, grafana,
alertmanager, uptime-kuma, node-exporter, and alloy to check the actual
LoadState value from systemctl show (using the same nixmon.succeed calls), and
make the assertion fail when the service is missing or not loaded.

In `@hosts/server/nixserv/default.nix`:
- Around line 50-54: The atticd-config test currently only calls systemctl show
atticd.service via nixserv.succeed, which can pass without proving anything and
duplicates the atticd coverage. Update atticd-config in default.nix to either
remove it or replace it with a real assertion that checks a specific unit/config
value from the atticd.service setup, using the existing testScript entry as the
location to make the test meaningful.
- Around line 44-48: The atticd testScript is using the same no-op grep pattern,
so update the check to assert a real expected service property in the
atticd.service validation. In the atticd test case inside the testScript block,
replace the current systemctl show | grep -i loadstate command with a meaningful
assertion on a specific value or state so the test fails when the service is not
configured correctly.

In `@modules/nixos/server/proxy/extensions/api-key-auth.nix`:
- Around line 85-111: The `config` callback in `getExtensionsForVhost` is
dereferencing `vh.requireApiKey.enable` without a null check, which can fail for
vhosts that don’t define `requireApiKey` when extensions are applied broadly.
Update this guard to match the other call sites by first checking that
`vh.requireApiKey` is present before reading `enable`, and keep the existing
API-key config generation logic under that combined condition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 01879bb7-d995-48cf-b2d0-7822e9feed1d

📥 Commits

Reviewing files that changed from the base of the PR and between 692fe91 and d600b72.

📒 Files selected for processing (41)
  • .woodpecker/test-vm.yaml
  • _run_tests.sh
  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
  • flake/default.nix
  • flake/nixos/flake-module.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixserv/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: generate-matrix
⚠️ CI failures not shown inline (3)

GitHub Check: GitGuardian Security Checks: 4 secrets uncovered!

Conclusion: failure

View job details

#### 4 secrets were uncovered from the scan of 12 commits in your pull request. ❌
Please have a look to GitGuardian findings and remediate in order to secure your code.
### 🔎 Detected hardcoded secrets in your pull request
-   Pull request `#545`: `push-xvsqsqnwmrup` 👉 `master`
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
| -------------- | ------------------ | ------ | ------ | -------- | ---- |
| [34424190](https://dashboard.gitguardian.com/workspace/233667/incidents/34424190?occurrence=276310304) | Triggered | Generic Password | d600b72464642ac451674ba06cdd8931785af98e | tests/profiles/vm-test.nix | [View secret](https://github.com/DaRacci/nix-config/commit/d600b72464642ac451674ba06cdd8931785af98e#diff-404f8053b181e2e0a352c9a9a3da131cfadebac38692ebf53612420193caae7fR220) |
| [34424190](https://dashboard.gitguardian.com/workspace/233667/incidents/34424190?occurrence=276310306) | Triggered | Generic Password | 7135633da5c1d502f9403af61941b032af9f4e2e | tests/profiles/vm-test.nix | [View secret](https://github.com/DaRacci/nix-config/commit/7135633da5c1d502f9403af61941b032af9f4e2e#diff-404f8053b181e2e0a352c9a9a3da131cfadebac38692ebf53612420193caae7fR174) |
| [34424190](https://dashboard.gitguardian.com/workspace/233667/incidents/34424190?occurrence=276310308) | Triggered | Generic Password | 7135633da5c1d502f9403af61941b032af9f4e2e | tests/profiles/vm-test.nix | [View secret](https://github.com/DaRacci/nix-config/commit/7135633da5c1d502f9403af61941b032af9f4e2e#diff-404f8053b181e2e0a352c9a9a3da131cfadebac38692ebf53612420193caae7fR149) |
| [34424190](https://dashboard.gitguardian.com/workspace/233667/incidents/34424190?occurrence=276310311) | Triggered | Generic Password | 011e1f60ae7c76cbf8fd9511ba300fcf2d54c3fa | tests/profiles/vm-test.nix | [View secret](https://github.com/DaRacci/nix-config/commit/011e1f60ae7c76cbf8fd9511ba300fcf2d54c3fa#diff-404f8053b181e2e0a352c9a9a3da131cfadebac38692ebf53612420193caae7fR149) |
### 🛠 Guidelines to re...

Commit Status: ci/woodpecker/pr/check: ci/woodpecker/pr/check

Conclusion: failure

Pipeline failed

Commit Status: ci/woodpecker/pr/check-upstream-todos: ci/woodpecker/pr/check-upstream-todos

Conclusion: failure

Pipeline failed
🧰 Additional context used
📓 Path-based instructions (13)
docs/**/*

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Project documentation should be placed in the docs/ directory

Files:

  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
docs/src/**/*.md

📄 CodeRabbit inference engine (.opencode/skills/docs/SKILL.md)

docs/src/**/*.md: Use underscore filenames (e.g., my_new_feature.md) instead of hyphens for documentation files
Keep documentation prose focused on behavior, architecture, usage examples, and operational notes; let generated fragments provide exhaustive option reference

Files:

  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Verify documentation accurately reflects new behavior in docs/ directory before proceeding to commit

Files:

  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/code-style-nix)

**/*.nix: Follow Nix code style conventions and best practices
Use consistent indentation and formatting in Nix configuration files
Follow established patterns for module organization in home-manager configurations

**/*.nix: Format code and check syntax using nix fmt
Evaluate Nix expressions without building using nix eval with the target configuration path
Format specific Nix files or directories using nix fmt followed by the file or directory path
Use --show-trace flag with nix build or nix eval commands to diagnose evaluation errors
For infinite recursion errors in Nix builds, check for circular imports or conflicting option definitions

**/*.nix: Use builtins.trace to add trace statements and inspect values during Nix evaluation (format: builtins.trace "message: ${toString var}" var)
Use builtins.toJSON to convert complex Nix attribute sets to JSON for easier inspection during evaluation
Check for circular imports between modules and option definitions that depend on themselves to resolve infinite recursion errors
Verify attribute names are correct and imports are complete when debugging 'attribute not found' errors in Nix
Check option type definitions and ensure provided values match the expected type to resolve type mismatch errors
Read assertion messages and provide required configuration values when assertion failures occur in NixOS modules

**/*.nix: Store sensitive data in secrets.yaml encrypted with sops instead of hardcoding passwords, API keys, or tokens in plain text
Declare sops secrets with proper owner, group, and mode attributes; use restrictive modes like 0400 for secrets files
Set restartUnits or reloadUnits for sops secrets declarations so services that depend on secrets are restarted when secrets change
Use config.sops.placeholder in sops templates instead of directly interpolating secret paths in multi-secret templates
Do not pass secrets as environment variables in plain Nix; use environmentFile or...

Files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • modules/nixos/core/sops.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • modules/nixos/core/boot/secureboot.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/core/stylix.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • flake/nixos/flake-module.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
  • hosts/server/nixdev/default.nix
  • flake/default.nix
  • hosts/server/nixcloud/identity.nix
hosts/server/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Server machine-specific NixOS configs should be placed in hosts/server/<machine>/

Files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixcloud/identity.nix
hosts/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Enable NixOS modules in host configuration files, e.g. set services.<name>.enable = true;.

Files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixcloud/identity.nix
hosts/*/*/default.nix

📄 CodeRabbit inference engine (.opencode/skills/hosts/SKILL.md)

Each host must have a default.nix file in hosts/<type>/<hostname>/ as the main config entry point

Per-machine NixOS configurations should be placed in hosts/<type>/<hostname>/default.nix

Files:

  • hosts/server/nixio/default.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixdev/default.nix
hosts/server/*/default.nix

📄 CodeRabbit inference engine (.opencode/skills/hosts/SKILL.md)

Server hosts in default.nix should set host.device.isHeadless = true to indicate they are headless systems

Files:

  • hosts/server/nixio/default.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixdev/default.nix
modules/nixos/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Reusable NixOS module fragments should be placed in modules/nixos/

Create new NixOS modules under modules/nixos/<category>/<name>.nix.

Files:

  • modules/nixos/core/sops.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
modules/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

modules/**/*.nix: Use the standard Nix module pattern: accept { config, lib, pkgs, ... }, define cfg from config, and structure the file with options plus a config = mkIf cfg.enable { ... } section.
Use the documented module namespaces appropriately: services.<name>, hardware.<name>, boot.<name>, host.<name>, server.<name>, core.<name>, purpose.<category>, and user.<name>.
When extending a submodule declared in another module, declare the same options.<path> with the same outer wrapper (for example, attrsOf (submodule ...)) so the inner options merge additively.
Do not use dynamic imports inside a submodule that read from config; this causes infinite recursion. Use static imports only when they do not depend on config.
When behavior should be conditional inside an imported submodule, wrap the submodule's config in mkIf; do not try to conditionally gate the option declaration itself.
When extending submodule or submoduleWith, keep the outer type wrapper identical across declarations so the inner options attrsets can merge.

Files:

  • modules/nixos/core/sops.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
modules/nixos/**/default.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Register NixOS modules in the parent default.nix via an imports = [ ... ]; list.

Files:

  • modules/nixos/server/default.nix
flake/nixos/flake-module.nix

📄 CodeRabbit inference engine (.opencode/skills/hosts/SKILL.md)

For hosts requiring CUDA or ROCm acceleration support, add the host name to the corresponding array in flake/nixos/flake-module.nix under accelerationHosts

Files:

  • flake/nixos/flake-module.nix
flake/nixos/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

NixOS flake module definitions should be organized in flake/nixos/

Files:

  • flake/nixos/flake-module.nix
🧠 Learnings (10)
📚 Learning: 2026-04-13T14:02:32.760Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: hosts/server/nixdev/default.nix:18-18
Timestamp: 2026-04-13T14:02:32.760Z
Learning: When configuring NixOS Docker via `virtualisation.docker.daemon.settings`, it is valid to set `storage-driver = "overlayfs"` (do not flag it as an invalid Docker storage-driver). Use `overlayfs` specifically for Docker Engine 29+ and/or when the containerd snapshotter integration is enabled (`virtualisation.docker.features.containerd-snapshotter = true`). Treat this as the containerd snapshotter name for OverlayFS, distinct from the legacy `overlay2` classic Docker storage driver.

Applied to files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • modules/nixos/core/sops.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • modules/nixos/core/boot/secureboot.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/core/stylix.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • flake/nixos/flake-module.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
  • hosts/server/nixdev/default.nix
  • flake/default.nix
  • hosts/server/nixcloud/identity.nix
📚 Learning: 2026-05-01T10:02:55.261Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/sops.nix:49-53
Timestamp: 2026-05-01T10:02:55.261Z
Learning: In this nix-config repo, when declaring `sops.secrets` in Nix files, avoid explicitly setting `owner = "root"` and/or `group = "root"` if the intended ownership is root. `sops-nix` defaults `sops.secrets` to `root:root`, so adding these fields explicitly is redundant boilerplate.

Applied to files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • modules/nixos/core/sops.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • modules/nixos/core/boot/secureboot.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/core/stylix.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • flake/nixos/flake-module.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
  • hosts/server/nixdev/default.nix
  • flake/default.nix
  • hosts/server/nixcloud/identity.nix
📚 Learning: 2026-05-01T14:14:49.691Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:119-119
Timestamp: 2026-05-01T14:14:49.691Z
Learning: When configuring the NixOS `wivrn` module option `services.wivrn.config.json.application`, pass the raw package/derivation (e.g., `pkgs.wayvr`) rather than converting it to a string executable path (e.g., `lib.getExe pkgs.wayvr`). The upstream module expects a list of derivations/packages (it internally `toList`s the value, asserts the first element is a derivation, and then resolves the executable internally). Code review should not recommend changing `pkgs.wayvr` to `lib.getExe pkgs.wayvr` for this option.

Applied to files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • modules/nixos/core/sops.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • modules/nixos/core/boot/secureboot.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/core/stylix.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • flake/nixos/flake-module.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
  • hosts/server/nixdev/default.nix
  • flake/default.nix
  • hosts/server/nixcloud/identity.nix
📚 Learning: 2026-05-20T13:12:46.610Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: docs/site.nix:127-127
Timestamp: 2026-05-20T13:12:46.610Z
Learning: In DaRacci/nix-config, treating `passthru.discovery = false` as a known repo-wide convention to exclude a derivation from automated flake discovery/package CI. Do not require or flag an inline explanatory comment specifically for the absence of a comment when `passthru.discovery = false` is set.

Applied to files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • modules/nixos/core/sops.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • modules/nixos/core/boot/secureboot.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/core/stylix.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • flake/nixos/flake-module.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
  • hosts/server/nixdev/default.nix
  • flake/default.nix
  • hosts/server/nixcloud/identity.nix
📚 Learning: 2026-06-28T05:00:06.970Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 599
File: hosts/server/nixai/mnemosyne.nix:6-11
Timestamp: 2026-06-28T05:00:06.970Z
Learning: In this repo’s Nix host configuration, for `sops.secrets.<name>` declarations managed by `sops-nix`, avoid explicitly setting `mode = "0400"` when you are not overriding `sops-nix`’s default secret permissions. `sops-nix` already defaults decrypted secret files to root ownership with mode `0400`, so an explicit `mode = "0400"` is typically redundant. Only set `mode` when you truly need non-default permissions (or you have config that changes the module defaults).

Applied to files:

  • hosts/server/nixai/web.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixserv/default.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixcloud/identity.nix
📚 Learning: 2026-05-01T09:11:22.009Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:65-65
Timestamp: 2026-05-01T09:11:22.009Z
Learning: In Nix code, do not flag shell-variable literals like "$XDG_RUNTIME_DIR" used inside Steam’s `extraEnv` (e.g., `pkgs.steam.override { extraEnv = { ... }; }`, including `modules/nixos/core/gaming.nix`). The Steam wrapper script expands these shell variables at runtime, so they should be treated as intended unexpanded literals rather than an interpolation/quoting mistake.

Applied to files:

  • modules/nixos/core/sops.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
📚 Learning: 2026-05-01T14:35:32.037Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/remote.nix:153-179
Timestamp: 2026-05-01T14:35:32.037Z
Learning: In this repo’s NixOS module code (e.g., shell scripts produced via `writeShellApplication` inside `modules/nixos/**`), do not treat missing `XDG_STATE_HOME` fallbacks (like `${XDG_STATE_HOME:-$HOME/.local/state}`) as an error in the embedded shell script. On NixOS user sessions, `XDG_STATE_HOME` is reliably set via PAM/systemd, so flagging its absence as potentially unset is overly defensive for these generated scripts.

Applied to files:

  • modules/nixos/core/sops.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
📚 Learning: 2026-06-20T14:33:25.328Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 590
File: modules/nixos/server/monitoring/collector/tempo.nix:71-72
Timestamp: 2026-06-20T14:33:25.328Z
Learning: When reviewing DaRacci/nix-config NixOS modules that use sops-nix, do not flag `sops.secrets` entries as missing `owner`, `group`, `mode`, or `restartUnits` if the secret declarations are only placeholder sources for `sops.templates`:
- The secret value is referenced exclusively via `config.sops.placeholder.<NAME>` inside a `sops.templates` definition (i.e., no other code reads the decrypted secret from the raw secret path).
- The rendered `sops.templates` output is what is used by systemd via a `systemd.services.*.serviceConfig.EnvironmentFile` (the template is the effective boundary).
In this pattern, the template’s own `restartUnits` are the relevant access-control/restart boundary; the raw `sops.secrets` files are only decrypted in-memory by sops-nix (run as root) to render the template. Therefore, empty-attrset `sops.secrets.<NAME> = { };` declarations should not be treated as missing permissions/restart hooks when they are only feeding a `sops.templates` placeholder.

Applied to files:

  • modules/nixos/core/sops.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
📚 Learning: 2026-05-01T09:57:09.578Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/services/ai-agent.nix:15-15
Timestamp: 2026-05-01T09:57:09.578Z
Learning: In this repo’s Nix modules, `inputs.services-zeroclaw` is a flake input that resolves to an attrset containing a `_file` attribute, and Nix coerces that attrset to a file path via `_file`. When importing/using it as a path in `imports` (e.g., `modules/nixos/services/ai-agent.nix`), use the string interpolation form "${inputs.services-zeroclaw}". Do not change it to `inputs.services-zeroclaw` (raw attrset form) in `imports`, because it will not work correctly.

Applied to files:

  • modules/nixos/core/sops.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/host/persistence.nix
📚 Learning: 2026-03-18T23:46:49.905Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: .woodpecker/lix.yaml:15-15
Timestamp: 2026-03-18T23:46:49.905Z
Learning: In nix-config repository (.woodpecker/*.yaml), image references intentionally omit explicit tags or digests (e.g., registry.racci.dev/lix-woodpecker without :tag). Do not flag or suggest adding explicit tags or digests to these image references; treat such omissions as intentional and maintain consistency across the CI config.

Applied to files:

  • .woodpecker/test-vm.yaml
🪛 LanguageTool
docs/src/development/vm_integration_tests.md

[uncategorized] ~207-~207: Loose punctuation mark.
Context: ...run. ### Requirements - /dev/kvm: QEMU tests require KVM acceleration. Wi...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.22.1)
docs/src/SUMMARY.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

docs/src/development/vm_integration_tests.md

[warning] 13-13: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 233-233: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🔇 Additional comments (34)
modules/nixos/server/default.nix (2)

193-196: LGTM!

Also applies to: 143-154, 230-243


74-80: 🎯 Functional Correctness

No change needed getAllAttrsFunc already routes through filterEmpty, so null results are removed before callers see the list.

			> Likely an incorrect or invalid review comment.
flake/default.nix (1)

49-52: LGTM!

flake/nixos/flake-module.nix (3)

28-28: LGTM!

Also applies to: 63-70, 82-96


74-78: 📐 Maintainability & Code Quality

No issue hereallocations on line 44 is the partition’s option definition, and config.partitions.nixos.module.allocations reads the evaluated partition output, so this isn’t a self-reference.

			> Likely an incorrect or invalid review comment.

78-78: 🎯 Functional Correctness

x86_64-linux matches the current host setup. No server host overrides system or nixpkgs.hostPlatform, so this test builder pin isn’t introducing a mismatch.

			> Likely an incorrect or invalid review comment.
_run_tests.sh (1)

1-41: LGTM!

docs/src/SUMMARY.md (1)

19-19: LGTM!

docs/src/development/vm_integration_tests.md (3)

13-20: 📐 Maintainability & Code Quality | ⚡ Quick win

Add a language identifier to the fenced code block.

Static analysis (MD040) flags this fence as missing a language tag.

📝 Proposed fix
-```
+```text
 flake.nix
 ├── nixosConfigurations/   # Production host configs (nixio, nixai, ...)
 └── nixosTestConfigurations/   # VM test derivations
     ├── nixio              # Auto-discovered per-host test
     ├── nixai              # Auto-discovered per-host test
     └── proxy-routing       # Explicit scenario test
</details>

<!-- cr-comment:v1:92d2f65611389465ea059517 -->

_Source: Linters/SAST tools_

---

`231-236`: _📐 Maintainability & Code Quality_ | _⚡ Quick win_

**Surround fenced code block with blank lines.**

Static analysis (MD031) flags this fence for missing surrounding blank lines inside the numbered list item.

<!-- cr-comment:v1:13f789d347de719049e8de86 -->

_Source: Linters/SAST tools_

---

`1-372`: LGTM!

<!-- cr-comment:v1:59d5e4a43eee9ad790f9aaad -->

</blockquote></details>
<details>
<summary>.woodpecker/test-vm.yaml (1)</summary><blockquote>

`1-24`: LGTM!

<!-- cr-comment:v1:e5ff72a4d621faedb525cb87 -->

</blockquote></details>
<details>
<summary>hosts/server/nixai/voice.nix (1)</summary><blockquote>

`19-32`: _🎯 Functional Correctness_ | _⚡ Quick win_

**Same `grep -i loadstate` correctness issue as ai-agent.nix.**

`grep -i loadstate` matches `LoadState=not-found` equally well, so this never actually validates the units loaded successfully. Same fix applies: match `loadstate=loaded` explicitly.

<!-- cr-comment:v1:7e21eed4f7ce5c29e01d7561 -->

</blockquote></details>
<details>
<summary>hosts/server/nixai/web.nix (1)</summary><blockquote>

`43-48`: _🎯 Functional Correctness_ | _⚡ Quick win_

**Same `grep -i loadstate` correctness issue as ai-agent.nix.**

This assertion will pass even if `open-webui.service` fails to load; the grep matches the key name regardless of value.

<!-- cr-comment:v1:df564e34b1c67d92463fc11a -->

</blockquote></details>
<details>
<summary>hosts/server/nixarr/arr/default.nix (1)</summary><blockquote>

`29-34`: _🎯 Functional Correctness_ | _⚡ Quick win_

**Same `grep -i loadstate` correctness issue as ai-agent.nix.**

Same problem — `grep -i loadstate` doesn't verify the unit actually loaded (`loaded` vs `not-found`/`masked`).

<!-- cr-comment:v1:f37060fdd0a4bdaee84246d9 -->

</blockquote></details>
<details>
<summary>hosts/server/nixio/dashboard.nix (1)</summary><blockquote>

`61-66`: _🎯 Functional Correctness_ | _⚡ Quick win_

**Same `grep -i loadstate` correctness issue as ai-agent.nix.**

<!-- cr-comment:v1:79af61b41aa3813fc2207071 -->

</blockquote></details>
<details>
<summary>hosts/server/nixio/database.nix (3)</summary><blockquote>

`82-101`: _🎯 Functional Correctness_ | _⚡ Quick win_

**Same `grep -i loadstate` correctness issue as ai-agent.nix.**

Applies to `pgadmin`, `postgres-exporter`, `redis-exporter`, and `postgresql-backup` here.

<!-- cr-comment:v1:1cd1828dc8ade447fbedff7e -->

---

`70-80`: LGTM!

<!-- cr-comment:v1:8822adf55a081b15db2b73a6 -->

---

`41-48`: _🎯 Functional Correctness_

**These attrs are safe to drop here.** The merged secret set only feeds `sops.secrets`, and the in-tree test secret generator keys off `attrNames`, not these value fields. 

				> Likely an incorrect or invalid review comment.

<!-- cr-comment:v1:68c1c4c6cf08c07e78372f67 -->

</blockquote></details>
<details>
<summary>hosts/server/nixio/default.nix (1)</summary><blockquote>

`90-94`: LGTM!

<!-- cr-comment:v1:d9982d7f98ac35594607c7b6 -->

</blockquote></details>
<details>
<summary>hosts/server/nixarr/default.nix (1)</summary><blockquote>

`80-134`: _🎯 Functional Correctness_

**Same no-op `loadstate` grep pattern as flagged in `hosts/server/nixarr/arr/downloader.nix`.**

All nine unit tests here (jellyfin, seerr, samba, wireguard, sonarr, radarr, lidarr, prowlarr, bazarr) share the same flaw: `grep -i loadstate` matches unconditionally regardless of the actual `LoadState` value, so the check never fails.

<!-- cr-comment:v1:e8e267c815b56a191607fafb -->

</blockquote></details>
<details>
<summary>hosts/server/nixcloud/home-assistant/connectivity.nix (1)</summary><blockquote>

`134-157`: _🎯 Functional Correctness_

**Same no-op `loadstate` grep pattern as flagged in `hosts/server/nixarr/arr/downloader.nix`.**

All four unit tests (mosquitto, esphome, zigbee2mqtt, matter-server) share the same flaw.

<!-- cr-comment:v1:6c32e8f6943477eade2f5a7c -->

</blockquote></details>
<details>
<summary>hosts/server/nixcloud/home-assistant/default.nix (1)</summary><blockquote>

`94-106`: _🎯 Functional Correctness_

**Same no-op `loadstate` grep pattern as flagged in `hosts/server/nixarr/arr/downloader.nix`.**

Both unit tests (home-assistant, avahi) share the same flaw.

<!-- cr-comment:v1:f7fa9afa94f110eeef45afc0 -->

</blockquote></details>
<details>
<summary>hosts/server/nixcloud/homebox.nix (1)</summary><blockquote>

`31-35`: _🎯 Functional Correctness_

**Same no-op `loadstate` grep pattern as flagged in `hosts/server/nixarr/arr/downloader.nix`.**

<!-- cr-comment:v1:26c2e015ac2bfa71f20b79cc -->

</blockquote></details>
<details>
<summary>hosts/server/nixio/proxy.nix (1)</summary><blockquote>

`132-148`: _🎯 Functional Correctness_

**Same no-op `loadstate` grep pattern as flagged in `hosts/server/nixarr/arr/downloader.nix`.**

All three unit tests (caddy, upgrade-status, hacompanion) share the same flaw.

<!-- cr-comment:v1:68bbfb15517edf56ce2e6683 -->

</blockquote></details>
<details>
<summary>hosts/server/nixio/storage.nix (1)</summary><blockquote>

`55-79`: _🎯 Functional Correctness_

**Same no-op `loadstate` grep pattern as flagged in `hosts/server/nixarr/arr/downloader.nix`.**

All four unit tests (minio, seaweedfs-master, seaweedfs-volume, seaweedfs-filer) share the same flaw.

<!-- cr-comment:v1:4eb13e26664e04c6962a78d4 -->

</blockquote></details>
<details>
<summary>hosts/server/nixdev/coder.nix (1)</summary><blockquote>

`62-62`: LGTM!

<!-- cr-comment:v1:24ba040def30653820a850fd -->

</blockquote></details>
<details>
<summary>hosts/server/nixio/adguard.nix (1)</summary><blockquote>

`183-183`: LGTM!

<!-- cr-comment:v1:9382916b689dc9fbc9bce7f5 -->

</blockquote></details>
<details>
<summary>modules/nixos/core/nix.nix (1)</summary><blockquote>

`7-19`: LGTM!



Also applies to: 38-41, 73-76, 86-86

<!-- cr-comment:v1:91d49b7d56f0824f7d67afa0 -->

</blockquote></details>
<details>
<summary>modules/nixos/core/boot/secureboot.nix (1)</summary><blockquote>

`19-19`: LGTM!



Also applies to: 25-41

<!-- cr-comment:v1:e76fb6e431ce3940b5aaac4a -->

</blockquote></details>
<details>
<summary>modules/nixos/core/host/persistence.nix (1)</summary><blockquote>

`215-215`: LGTM!



Also applies to: 217-273

<!-- cr-comment:v1:212612c588fe512ca16feb11 -->

</blockquote></details>
<details>
<summary>modules/nixos/core/sops.nix (1)</summary><blockquote>

`28-28`: LGTM!



Also applies to: 43-62

<!-- cr-comment:v1:ef05b7a1b451ded242cc7799 -->

</blockquote></details>
<details>
<summary>modules/nixos/core/stylix.nix (1)</summary><blockquote>

`27-27`: LGTM!



Also applies to: 29-39

<!-- cr-comment:v1:4d4fb64d4924bb8923085950 -->

</blockquote></details>
<details>
<summary>modules/nixos/server/proxy/extensions/api-key-auth.nix (1)</summary><blockquote>

`35-47`: LGTM!

<!-- cr-comment:v1:d93203fd9b2c8551d4cddefc -->

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@DaRacci

DaRacci commented Jul 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 32

♻️ Duplicate comments (1)
tests/lib.nix (1)

6-10: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

runOnAllNodes still passes the string "node.name", not the node object — same bug flagged previously.

A prior review on this file identified this exact issue and was marked "Addressed in commits 78c9dd9 to 2a6a397", but the code shown still interpolates the literal string "node.name" into the callback. Any caller doing f = node: "${node}.wait_for_unit(...)" would produce invalid Python like node.name.wait_for_unit(...). If this was meant to be fixed, the fix doesn't appear to be present in this version of the file.

🔧 Suggested fix
   /*
-    Run a python function on all nodes in the cluster.
-    The function takes one argument, a function with one argument which is the node's name.
+    Run a Python snippet on all nodes in the cluster.
+    The callback receives the Python node variable.
   */
   runOnAllNodes = f: ''
     for node in cluster.nodes:
       with subtest(node.name):
-        ${f "node.name"}
+        ${f "node"}
   '';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/lib.nix` around lines 6 - 10, `runOnAllNodes` is still passing the
literal string "node.name" into the callback instead of the actual node object.
Update the `runOnAllNodes` helper in `tests/lib.nix` so the interpolated
argument uses the loop variable itself inside the generated Python snippet, not
a quoted string, and verify callers like `f = node:
"${node}.wait_for_unit(...)"` receive a real node reference.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@_run_tests.sh`:
- Line 7: The HOSTS array in _run_tests.sh is hardcoded and can drift from the
actual NixOS test targets. Update the script to discover hosts dynamically using
the same approach as .woodpecker/test-vm.yaml and the docs, via nix eval on
.#nixosTestConfigurations with builtins.attrNames. Make sure the main
host-selection logic in _run_tests.sh consumes that generated list so newly
added hosts like nixarr, nixcloud, and nixserv are picked up automatically.

In @.woodpecker/test-vm.yaml:
- Around line 28-32: The VM test loop in the test step runs each host serially,
so it will become a CI bottleneck as the host list grows. Update the logic
around the host iteration in the test script to use a parallelized or
dynamically generated execution strategy instead of a single shell loop in one
agent, while keeping the current `nix eval .#nixosTestConfigurations` host
discovery and `nix build` per-host behavior intact.
- Around line 28-32: The “Run VM tests” loop is swallowing failures because the
`nix build` error is followed by a successful `echo`, so the shell step always
exits 0. Update the VM test commands in `.woodpecker/test-vm.yaml` to let `nix
build` failures propagate from the loop instead of masking them, and ensure the
step exits non-zero when any host build fails. Use the existing `nix build
".#nixosTestConfigurations.$host"` loop and the `echo "::group::VM test: $host"`
/ `echo "::endgroup::"` structure as the location to fix this behavior.
- Around line 1-5: The PR-only KVM job currently builds every server and
scenario host via nixosTestConfigurations, which does not scale as the repo
grows. Update the test-vm pipeline to run only affected hosts by filtering
against the PR’s changed files (for example, comparing changes under
hosts/server/** and scenario directories) before expanding the build set. Keep
the logic anchored around the test-vm job and the nixosTestConfigurations
consumer so the affected-host selection happens before VM builds are scheduled.

In `@docs/src/development/vm_integration_tests.md`:
- Around line 231-236: The Markdown list item in the documentation section is
missing a blank line before the fenced bash block, triggering MD031. Update the
content around the existing `nixosTestConfigurations` guidance so the fenced
code block is separated by a blank line from the preceding list item text,
keeping the same wording and placement of the `nix build
.#nixosTestConfigurations.<name>` example.
- Around line 13-20: The fenced block in the VM integration tests docs is
missing a language identifier, which triggers markdownlint. Update the code
fence in the relevant documentation snippet to include an explicit language tag
using the existing fenced block around the flake.nix tree so the markdown linter
recognizes it.

In `@flake/nixos/flake-module.nix`:
- Around line 80-96: The `nixosTestConfigurations` generation in the
`serverHosts` pipeline ignores `server.tests.enable`, so every host gets a test
entry even when it opted out. Update the `builtins.map`/`builtins.listToAttrs`
flow in this flake module to consult
`self.nixosConfigurations.${hostName}.config.server.tests.enable` before calling
`builder`, and skip or filter out hosts where that flag is false. Use the
existing `serverHosts`, `hostName`, and `builder` symbols to keep the check
localized to the test-entry construction.
- Around line 102-117: `builtins.readDir` in the scenario discovery logic is
including non-directory entries, so only directories should be treated as
scenarios. Update the `scenarioName` source in the `builtins.listToAttrs` block
inside the scenario loader to filter `builtins.readDir scenariosDir` by entries
whose type is directory before calling `import
"${scenariosDir}/${scenarioName}/test.nix"`. Keep the fix localized to this
scenario enumeration code so only real scenario folders are mapped.
- Around line 106-111: The scenario-mode builder call is missing the required
inputs argument, causing evaluation to fail in every discovered scenario. Update
the scenario branch in the flake-module logic where builder is invoked so it
passes inputs through alongside self, pkgs, and lib. Use the builder call in the
scenarioName mapping to locate the change and ensure tests/builder.nix receives
inputs consistently.

In `@hosts/server/nixai/ai-agent.nix`:
- Around line 10-23: The unit tests for ai-agent-api and ai-agent-dashboard only
grep for the LoadState field, so they can pass even when the service is missing.
Update each testScript to assert the exact loaded state from systemctl show by
matching LoadState=loaded instead of just searching for the key, using the
ai-agent-api and ai-agent-dashboard unit checks as the targets to fix.

In `@hosts/server/nixai/voice.nix`:
- Around line 19-32: The unit tests for wyoming-piper and wyoming-whisper are
only checking that systemctl show prints the LoadState field name, not that the
service is actually loaded. Update the testScript checks in tests.units for
wyoming-piper and wyoming-whisper to assert the LoadState value is loaded (using
the existing service names wyoming-piper.service and
wyoming-faster-whisper.service) so the tests fail unless the units are truly
loaded.

In `@hosts/server/nixarr/arr/downloader.nix`:
- Around line 88-100: The unit checks in server.tests.units are currently
ineffective because grepping for LoadState never proves the service exists.
Update the transmission and sabnzbd testScript assertions to validate the actual
LoadState value returned by systemctl show for the relevant unit names, using
the existing nixarr.succeed calls so the tests fail when a unit is missing or
not loaded.

In `@hosts/server/nixarr/default.nix`:
- Around line 80-134: The unit tests in tests.units are using a grep on
systemctl show output that matches the LoadState property name instead of
verifying the service state. Update each testScript to assert the actual value
of LoadState for the relevant service units in nixarr, and consider
de-duplicating the repeated
jellyfin/seerr/samba/wg/sonarr/radarr/lidarr/prowlarr/bazarr blocks with a small
helper or genAttrs in default.nix so the same fixed check is applied
consistently.

In `@hosts/server/nixcloud/home-assistant/connectivity.nix`:
- Around line 134-158: The unit tests for mosquitto, esphome, zigbee2mqtt, and
matter-server are using an ineffective `systemctl show ... | grep -i loadstate`
check that only matches the property name, not the actual service state. Update
each `testScript` in `server.tests.units` to assert on the `LoadState` value
instead, using `systemctl show <unit> --property=LoadState --value` and checking
that it matches `loaded`; keep the existing unit names and `testScript` blocks
so the change is localized and easy to verify.

In `@hosts/server/nixcloud/home-assistant/default.nix`:
- Around line 94-106: The unit tests in server.tests.units for home-assistant
and avahi are using an ineffective systemctl show | grep -i loadstate check that
can never fail on a missing or unloaded unit. Update the testScript assertions
to verify the actual LoadState value from systemctl show (using the existing
nixcloud.succeed checks) so each test fails when the service is not loaded; use
the home-assistant and avahi test blocks as the places to fix.

In `@hosts/server/nixcloud/homebox.nix`:
- Around line 31-36: The current homebox unit test uses an ineffective systemctl
status check that can pass even when the service fails to load. Update the
testScript in homebox to assert the service actually loads successfully by
checking a stronger signal from systemctl show or an equivalent loaded/active
state condition, using the homebox.service target in the existing test block.

In `@hosts/server/nixcloud/identity.nix`:
- Around line 215-220: The current unit test in tests.units.kanidm is
ineffective because systemctl show always emits LoadState, so grepping for
loadstate will pass even when kanidm.service is missing or broken. Update the
testScript to assert the actual expected state of the kanidm.service unit using
a more specific check on systemctl show output, and apply the same fix anywhere
the same grep pattern is reused across the host test files.

In `@hosts/server/nixdev/automation.nix`:
- Around line 100-107: The unit test in the n8n testScript uses a weak assertion
because `systemctl show` always emits the `LoadState=` key, so the current grep
can succeed even when the service is not loaded. Update the assertion to check
the actual `LoadState` value returned by `systemctl show` instead of matching
the key name, and apply the same fix anywhere this pattern is repeated in the
automation tests.

In `@hosts/server/nixdev/ci.nix`:
- Around line 25-30: The github-runners test in
server.tests.units.github-runners uses a weak loadstate check that only matches
the property name, so it never verifies the actual unit state. Update the
testScript to assert the real output of systemctl show for the
github-runner-nixos-runner-0.service unit, using the load state value itself
rather than a grep on the key, so the test fails when the service is not
properly loaded.

In `@hosts/server/nixdev/coder.nix`:
- Around line 36-43: The current tests.units.coder.testScript still relies on a
weak loadstate check, so replace it with a stronger assertion that verifies
coder.service is actually running and healthy via systemctl show or status
fields such as ActiveState/SubState. Update the coder unit test in tests.units
to use the service’s real runtime state instead of only grep’ing for loadstate.

In `@hosts/server/nixdev/default.nix`:
- Around line 26-33: The docker unit test in server.tests.units still uses a
weak loadstate-only check, so tighten the assertion in the docker testScript to
verify the service is actually active/running rather than just loaded. Update
the systemctl grep command in this docker block to assert on the operational
state, using the existing docker.service test as the reference point so it
matches the stronger check used elsewhere.

In `@hosts/server/nixdev/registry.nix`:
- Around line 97-104: The docker-registry unit test in tests.units uses a weak
loadstate check, so update the testScript for docker-registry to assert the
service is actually running instead of only loaded. Use a stronger
systemctl-based check such as querying the service state/active status in a way
that fails unless docker-registry.service is started successfully.

In `@hosts/server/nixdev/woodpecker.nix`:
- Around line 59-72: The unit tests for woodpecker-server and woodpecker-agent
only check LoadState, which is too weak and can pass even when the services are
not actually healthy. Update the testScript assertions in the tests.units block
to validate the services are really started and operational, using the same
stronger checks as the automation.nix fix, and reference the woodpecker-server
and woodpecker-agent service names so the tests verify actual service state
rather than just being loaded.

In `@hosts/server/nixio/adguard.nix`:
- Around line 223-228: The adguard unit test in server.tests.units.adguard uses
a weak systemctl show loadstate check, which is too shallow for validating the
service. Update the testScript to assert a stronger condition on
adguardhome.service, such as verifying the service is active/running or
otherwise confirming the expected runtime state, using the existing
nixio.succeed test block.

In `@hosts/server/nixio/default.nix`:
- Around line 90-94: The baseline-io test in server.tests.units.baseline-io
currently only checks that journalctl runs, not that the boot was healthy.
Update the testScript to assert on the actual log content by querying journalctl
for recent entries and failing if any -p err (or worse) messages are present, so
the test verifies a clean boot instead of just command availability.
- Around line 96-102: The kernel-forwarding unit test is tautological because it
sets the forwarding sysctls before asserting them. Update
server.tests.units.kernel-forwarding in the nixio/default.nix testScript to only
verify the configured state via sysctl reads, and remove the sysctl -w calls so
the test checks the host’s existing NixOS configuration rather than forcing
net.ipv4.ip_forward and net.ipv6.conf.all.forwarding to 1 first.

In `@hosts/server/nixio/proxy.nix`:
- Around line 132-149: The unit tests for caddy, upgrade-status, and hacompanion
are only checking for loadstate with a case-insensitive grep, which is too weak
and matches the same ineffective pattern as the other host tests. Update each
testScript in server.tests.units to assert the service is actually
active/running using the appropriate systemctl property or a more specific
status check, and keep the assertions aligned with the existing caddy,
upgrade-status, and hacompanion service names so the test verifies real service
health.

In `@hosts/server/nixio/storage.nix`:
- Around line 55-79: The unit tests for minio and the seaweedfs services are
using the same ineffective systemctl check, so the assertion is not validating
the service state meaningfully. Update the testScript entries in
server.tests.units for minio, seaweedfs-master, seaweedfs-volume, and
seaweedfs-filer to use a stronger service status assertion in place of the
current systemctl show ... | grep -i loadstate pattern, matching the approach
used to fix the same issue elsewhere. Keep the existing test names and
structure, but change the command inside each testScript so it actually verifies
the intended service is loaded/active.

In `@hosts/server/nixserv/default.nix`:
- Around line 50-54: The atticd-config test currently only runs systemctl show
atticd.service, which always exits successfully and does not verify anything
meaningful. Update the testScript in atticd-config to assert on specific output
from atticd.service, using the existing nixserv.succeed helper plus a
grep/assertion for expected service properties so the test fails when the unit
is masked, missing, or misconfigured.

In `@modules/nixos/server/tests.nix`:
- Around line 37-45: The testScript option currently advertises functionTo str
support, but the builder still treats unit.testScript as a plain string, so
function values will fail during evaluation. Either remove the functionTo str
branch from the testScript option in tests.nix, or update the builder logic in
tests/builder.nix to detect function-form scripts and invoke them before
interpolating. Use the existing testScript option and builder interpolation path
as the main places to fix.

In `@run-test.sh`:
- Around line 2-4: The test script currently writes build output to a
predictable shared path, which can be clobbered by concurrent runs and is
unsafe. Update run-test.sh to create a unique temporary log file with mktemp,
use that path in the nix build redirect, and keep the file reference in a
variable so the rest of the script can read it consistently.

In `@tests/builder.nix`:
- Around line 34-40: The multi-line Nix strings used by baselineAssertions and
unit.testScript are being interpolated directly inside with subtest() blocks,
which can break Python indentation after the first line. Move these helpers so
each one is a self-contained Python block with its own indentation, then invoke
them flush-left from the host and scenario branches instead of wrapping the
interpolated text inside with subtest():. Apply the same pattern anywhere
unit.testScript is embedded so all assertions stay inside the intended scope.

---

Duplicate comments:
In `@tests/lib.nix`:
- Around line 6-10: `runOnAllNodes` is still passing the literal string
"node.name" into the callback instead of the actual node object. Update the
`runOnAllNodes` helper in `tests/lib.nix` so the interpolated argument uses the
loop variable itself inside the generated Python snippet, not a quoted string,
and verify callers like `f = node: "${node}.wait_for_unit(...)"` receive a real
node reference.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2bac686a-9cb4-46ce-b466-e3889ab9bdff

📥 Commits

Reviewing files that changed from the base of the PR and between d364cbd and d600b72.

⛔ Files ignored due to path filters (21)
  • openspec/changes/archive/2026-06-23-server-cluster-monitoring/proposal.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/.openspec.yaml is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/design.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/proposal.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/specs/database.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/specs/network.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/specs/proxy.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/specs/security.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/specs/storage.md is excluded by !openspec/**
  • openspec/changes/comprehensive-server-tests/tasks.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/.openspec.yaml is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/README.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/design.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/proposal.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/server-vm-test-harness/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/service-aware-vm-tests/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/vm-test-documentation/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/vm-test-profile-overrides/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/vm-test-secret-generation/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/specs/woodpecker-vm-test-gating/spec.md is excluded by !openspec/**
  • openspec/changes/testing-framework-predeploy/tasks.md is excluded by !openspec/**
📒 Files selected for processing (55)
  • .woodpecker/test-vm.yaml
  • _run_tests.sh
  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
  • flake/default.nix
  • flake/nixos/flake-module.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixserv/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/services/ai-agent.nix
  • run-test.sh
  • tests/builder.nix
  • tests/lib.nix
  • tests/mkNode.nix
  • tests/profiles/dummy.yaml
  • tests/profiles/vm-test.nix
  • tests/scenarios/database-backup-chain/test.nix
  • tests/scenarios/firewall-port-audit/test.nix
  • tests/scenarios/io-guardian/test.nix
  • tests/scenarios/proxy-routing/test.nix
  • tests/scenarios/redis-remote-connect/test.nix
📜 Review details
⚠️ CI failures not shown inline (4)

GitHub Actions: Build and test flake outputs / 1_generate-matrix.txt: feat: cluster test framework

Conclusion: failure

View job details

##[group]Run workflow/nix-shell-action@v4.0.0
 with:
   flakes: nixpkgs#jq,nixpkgs#nushell
   script: SCRIPT_ARGS="--json"
if [[ -n "692fe91125d3630dfe4e3a6c6872a45728687c2f" ]]; then
  SCRIPT_ARGS+=" --range 692fe91125d3630dfe4e3a6c6872a45728687c2f..e34b5188ef8201a065d95ea58e8d59c1003cecbd"
else
  SCRIPT_ARGS+=" $(find . -type f | sed 's|^\./||' | grep -v '^\.git/' | tr '\n' ' ')"
fi
CHANGED_HOSTS=$(./flake/ci/detect-affected-outputs.nu nixosConfigurations $SCRIPT_ARGS | jq 'to_entries | map("nixosConfigurations." + .key + ".config.system.build.toplevel")' )
CHANGED_USERS=$(./flake/ci/detect-affected-outputs.nu homeConfigurations $SCRIPT_ARGS | jq 'to_entries | map("homeConfigurations." + .key + ".activationPackage")' )
EXTRA_SPACE='["nixmi"]'
NO_BUILD='["nixmi"]'
{
  echo 'matrix<<EOF'
  jq -n --argjson hosts "$CHANGED_HOSTS" --argjson users "$CHANGED_USERS" \
    --argjson rule_extra_space "$EXTRA_SPACE" \
    --argjson rule_no_build "$NO_BUILD" '
    ($hosts + $users) | map({
      attr: .,
      system: "x86_64-linux",
      extraSpace: IN($rule_extra_space[]; (. | split(".")[1])),
      noBuild: IN($rule_no_build[]; (. | split(".")[1]))
    })' 2>/dev/null || echo "[]"
  echo EOF
} >> "$GITHUB_OUTPUT"
   interpreter: bash
   packages: bash
   flakes-from-devshell: false
 ##[endgroup]
 fetching path input 'path:/nix/store/3a2vdn5i7vd2wl654xs8nb52jf1v6cbh-source'
 fetching path input 'path:/nix/store/3a2vdn5i7vd2wl654xs8nb52jf1v6cbh-source'
 these 2 paths will be fetched (13.06 MiB download, 58.01 MiB unpacked):
   /nix/store/ncw52xsl5hgplh8csybbp9fli64iw1aq-jq-1.8.1-man
   /nix/store/h6y0fybw66qx4d784nh515m4s8160ian-nushell-0.113.0
 copying path '/nix/store/ncw52xsl5hgplh8csybbp9fli64iw1aq-jq-1.8.1-man' from 'https://cache.nixos.org'...
 copying path '/nix/store/h6y0fybw66qx4d784nh515m4s8160ian-nushell-0.113.0' from 'https://cache.nixos.org'...
 fetching path input 'path:/nix/store/3a2vdn5i7vd2wl654xs8nb52jf1v6cbh-source'
 fetching git input 'git+file:///run...

Commit Status: ci/woodpecker/pr/check: ci/woodpecker/pr/check

Conclusion: failure

Pipeline failed

Commit Status: ci/woodpecker/pr/check-upstream-todos: ci/woodpecker/pr/check-upstream-todos

Conclusion: failure

Pipeline failed

Commit Status: ci/woodpecker/pr/flake-checker: ci/woodpecker/pr/flake-checker

Conclusion: failure

Pipeline failed
🧰 Additional context used
📓 Path-based instructions (13)
docs/**/*

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Project documentation should be placed in the docs/ directory

Files:

  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
docs/src/**/*.md

📄 CodeRabbit inference engine (.opencode/skills/docs/SKILL.md)

docs/src/**/*.md: Use underscore filenames (e.g., my_new_feature.md) instead of hyphens for documentation files
Keep documentation prose focused on behavior, architecture, usage examples, and operational notes; let generated fragments provide exhaustive option reference

Files:

  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Verify documentation accurately reflects new behavior in docs/ directory before proceeding to commit

Files:

  • docs/src/SUMMARY.md
  • docs/src/development/vm_integration_tests.md
**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/code-style-nix)

**/*.nix: Follow Nix code style conventions and best practices
Use consistent indentation and formatting in Nix configuration files
Follow established patterns for module organization in home-manager configurations

**/*.nix: Format code and check syntax using nix fmt
Evaluate Nix expressions without building using nix eval with the target configuration path
Format specific Nix files or directories using nix fmt followed by the file or directory path
Use --show-trace flag with nix build or nix eval commands to diagnose evaluation errors
For infinite recursion errors in Nix builds, check for circular imports or conflicting option definitions

**/*.nix: Use builtins.trace to add trace statements and inspect values during Nix evaluation (format: builtins.trace "message: ${toString var}" var)
Use builtins.toJSON to convert complex Nix attribute sets to JSON for easier inspection during evaluation
Check for circular imports between modules and option definitions that depend on themselves to resolve infinite recursion errors
Verify attribute names are correct and imports are complete when debugging 'attribute not found' errors in Nix
Check option type definitions and ensure provided values match the expected type to resolve type mismatch errors
Read assertion messages and provide required configuration values when assertion failures occur in NixOS modules

**/*.nix: Store sensitive data in secrets.yaml encrypted with sops instead of hardcoding passwords, API keys, or tokens in plain text
Declare sops secrets with proper owner, group, and mode attributes; use restrictive modes like 0400 for secrets files
Set restartUnits or reloadUnits for sops secrets declarations so services that depend on secrets are restarted when secrets change
Use config.sops.placeholder in sops templates instead of directly interpolating secret paths in multi-secret templates
Do not pass secrets as environment variables in plain Nix; use environmentFile or...

Files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • tests/scenarios/proxy-routing/test.nix
  • tests/lib.nix
  • tests/scenarios/firewall-port-audit/test.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • tests/scenarios/database-backup-chain/test.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • modules/nixos/core/boot/secureboot.nix
  • flake/nixos/flake-module.nix
  • tests/builder.nix
  • hosts/server/nixio/database.nix
  • tests/scenarios/redis-remote-connect/test.nix
  • modules/nixos/core/stylix.nix
  • flake/default.nix
  • hosts/server/nixai/ai-agent.nix
  • tests/mkNode.nix
  • hosts/server/nixserv/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • tests/profiles/vm-test.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
  • tests/scenarios/io-guardian/test.nix
hosts/server/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Server machine-specific NixOS configs should be placed in hosts/server/<machine>/

Files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixserv/default.nix
hosts/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Enable NixOS modules in host configuration files, e.g. set services.<name>.enable = true;.

Files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixserv/default.nix
hosts/*/*/default.nix

📄 CodeRabbit inference engine (.opencode/skills/hosts/SKILL.md)

Each host must have a default.nix file in hosts/<type>/<hostname>/ as the main config entry point

Per-machine NixOS configurations should be placed in hosts/<type>/<hostname>/default.nix

Files:

  • hosts/server/nixio/default.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixserv/default.nix
hosts/server/*/default.nix

📄 CodeRabbit inference engine (.opencode/skills/hosts/SKILL.md)

Server hosts in default.nix should set host.device.isHeadless = true to indicate they are headless systems

Files:

  • hosts/server/nixio/default.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixserv/default.nix
modules/nixos/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Reusable NixOS module fragments should be placed in modules/nixos/

Create new NixOS modules under modules/nixos/<category>/<name>.nix.

Files:

  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
modules/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

modules/**/*.nix: Use the standard Nix module pattern: accept { config, lib, pkgs, ... }, define cfg from config, and structure the file with options plus a config = mkIf cfg.enable { ... } section.
Use the documented module namespaces appropriately: services.<name>, hardware.<name>, boot.<name>, host.<name>, server.<name>, core.<name>, purpose.<category>, and user.<name>.
When extending a submodule declared in another module, declare the same options.<path> with the same outer wrapper (for example, attrsOf (submodule ...)) so the inner options merge additively.
Do not use dynamic imports inside a submodule that read from config; this causes infinite recursion. Use static imports only when they do not depend on config.
When behavior should be conditional inside an imported submodule, wrap the submodule's config in mkIf; do not try to conditionally gate the option declaration itself.
When extending submodule or submoduleWith, keep the outer type wrapper identical across declarations so the inner options attrsets can merge.

Files:

  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
modules/nixos/**/default.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Register NixOS modules in the parent default.nix via an imports = [ ... ]; list.

Files:

  • modules/nixos/server/default.nix
flake/nixos/flake-module.nix

📄 CodeRabbit inference engine (.opencode/skills/hosts/SKILL.md)

For hosts requiring CUDA or ROCm acceleration support, add the host name to the corresponding array in flake/nixos/flake-module.nix under accelerationHosts

Files:

  • flake/nixos/flake-module.nix
flake/nixos/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

NixOS flake module definitions should be organized in flake/nixos/

Files:

  • flake/nixos/flake-module.nix
🧠 Learnings (12)
📚 Learning: 2026-04-13T14:02:32.760Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: hosts/server/nixdev/default.nix:18-18
Timestamp: 2026-04-13T14:02:32.760Z
Learning: When configuring NixOS Docker via `virtualisation.docker.daemon.settings`, it is valid to set `storage-driver = "overlayfs"` (do not flag it as an invalid Docker storage-driver). Use `overlayfs` specifically for Docker Engine 29+ and/or when the containerd snapshotter integration is enabled (`virtualisation.docker.features.containerd-snapshotter = true`). Treat this as the containerd snapshotter name for OverlayFS, distinct from the legacy `overlay2` classic Docker storage driver.

Applied to files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • tests/scenarios/proxy-routing/test.nix
  • tests/lib.nix
  • tests/scenarios/firewall-port-audit/test.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • tests/scenarios/database-backup-chain/test.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • modules/nixos/core/boot/secureboot.nix
  • flake/nixos/flake-module.nix
  • tests/builder.nix
  • hosts/server/nixio/database.nix
  • tests/scenarios/redis-remote-connect/test.nix
  • modules/nixos/core/stylix.nix
  • flake/default.nix
  • hosts/server/nixai/ai-agent.nix
  • tests/mkNode.nix
  • hosts/server/nixserv/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • tests/profiles/vm-test.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
  • tests/scenarios/io-guardian/test.nix
📚 Learning: 2026-05-01T10:02:55.261Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/sops.nix:49-53
Timestamp: 2026-05-01T10:02:55.261Z
Learning: In this nix-config repo, when declaring `sops.secrets` in Nix files, avoid explicitly setting `owner = "root"` and/or `group = "root"` if the intended ownership is root. `sops-nix` defaults `sops.secrets` to `root:root`, so adding these fields explicitly is redundant boilerplate.

Applied to files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • tests/scenarios/proxy-routing/test.nix
  • tests/lib.nix
  • tests/scenarios/firewall-port-audit/test.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • tests/scenarios/database-backup-chain/test.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • modules/nixos/core/boot/secureboot.nix
  • flake/nixos/flake-module.nix
  • tests/builder.nix
  • hosts/server/nixio/database.nix
  • tests/scenarios/redis-remote-connect/test.nix
  • modules/nixos/core/stylix.nix
  • flake/default.nix
  • hosts/server/nixai/ai-agent.nix
  • tests/mkNode.nix
  • hosts/server/nixserv/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • tests/profiles/vm-test.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
  • tests/scenarios/io-guardian/test.nix
📚 Learning: 2026-05-01T14:14:49.691Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:119-119
Timestamp: 2026-05-01T14:14:49.691Z
Learning: When configuring the NixOS `wivrn` module option `services.wivrn.config.json.application`, pass the raw package/derivation (e.g., `pkgs.wayvr`) rather than converting it to a string executable path (e.g., `lib.getExe pkgs.wayvr`). The upstream module expects a list of derivations/packages (it internally `toList`s the value, asserts the first element is a derivation, and then resolves the executable internally). Code review should not recommend changing `pkgs.wayvr` to `lib.getExe pkgs.wayvr` for this option.

Applied to files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • tests/scenarios/proxy-routing/test.nix
  • tests/lib.nix
  • tests/scenarios/firewall-port-audit/test.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • tests/scenarios/database-backup-chain/test.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • modules/nixos/core/boot/secureboot.nix
  • flake/nixos/flake-module.nix
  • tests/builder.nix
  • hosts/server/nixio/database.nix
  • tests/scenarios/redis-remote-connect/test.nix
  • modules/nixos/core/stylix.nix
  • flake/default.nix
  • hosts/server/nixai/ai-agent.nix
  • tests/mkNode.nix
  • hosts/server/nixserv/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • tests/profiles/vm-test.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
  • tests/scenarios/io-guardian/test.nix
📚 Learning: 2026-05-20T13:12:46.610Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: docs/site.nix:127-127
Timestamp: 2026-05-20T13:12:46.610Z
Learning: In DaRacci/nix-config, treating `passthru.discovery = false` as a known repo-wide convention to exclude a derivation from automated flake discovery/package CI. Do not require or flag an inline explanatory comment specifically for the absence of a comment when `passthru.discovery = false` is set.

Applied to files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • tests/scenarios/proxy-routing/test.nix
  • tests/lib.nix
  • tests/scenarios/firewall-port-audit/test.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • tests/scenarios/database-backup-chain/test.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • modules/nixos/core/boot/secureboot.nix
  • flake/nixos/flake-module.nix
  • tests/builder.nix
  • hosts/server/nixio/database.nix
  • tests/scenarios/redis-remote-connect/test.nix
  • modules/nixos/core/stylix.nix
  • flake/default.nix
  • hosts/server/nixai/ai-agent.nix
  • tests/mkNode.nix
  • hosts/server/nixserv/default.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • tests/profiles/vm-test.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
  • tests/scenarios/io-guardian/test.nix
📚 Learning: 2026-06-28T05:00:06.970Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 599
File: hosts/server/nixai/mnemosyne.nix:6-11
Timestamp: 2026-06-28T05:00:06.970Z
Learning: In this repo’s Nix host configuration, for `sops.secrets.<name>` declarations managed by `sops-nix`, avoid explicitly setting `mode = "0400"` when you are not overriding `sops-nix`’s default secret permissions. `sops-nix` already defaults decrypted secret files to root ownership with mode `0400`, so an explicit `mode = "0400"` is typically redundant. Only set `mode` when you truly need non-default permissions (or you have config that changes the module defaults).

Applied to files:

  • hosts/server/nixdev/woodpecker.nix
  • hosts/server/nixio/default.nix
  • hosts/server/nixdev/coder.nix
  • hosts/server/nixarr/default.nix
  • hosts/server/nixcloud/immich.nix
  • hosts/server/nixcloud/search.nix
  • hosts/server/nixcloud/home-assistant/default.nix
  • hosts/server/nixdev/ci.nix
  • hosts/server/nixio/proxy.nix
  • hosts/server/nixcloud/identity.nix
  • hosts/server/nixio/adguard.nix
  • hosts/server/nixmon/default.nix
  • hosts/server/nixcloud/homebox.nix
  • hosts/server/nixarr/arr/downloader.nix
  • hosts/server/nixdev/automation.nix
  • hosts/server/nixio/dashboard.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/web.nix
  • hosts/server/nixcloud/music.nix
  • hosts/server/nixarr/arr/default.nix
  • hosts/server/nixdev/default.nix
  • hosts/server/nixio/storage.nix
  • hosts/server/nixcloud/nextcloud.nix
  • hosts/server/nixai/voice.nix
  • hosts/server/nixdev/registry.nix
  • hosts/server/nixio/database.nix
  • hosts/server/nixai/ai-agent.nix
  • hosts/server/nixserv/default.nix
📚 Learning: 2026-05-01T09:11:22.009Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:65-65
Timestamp: 2026-05-01T09:11:22.009Z
Learning: In Nix code, do not flag shell-variable literals like "$XDG_RUNTIME_DIR" used inside Steam’s `extraEnv` (e.g., `pkgs.steam.override { extraEnv = { ... }; }`, including `modules/nixos/core/gaming.nix`). The Steam wrapper script expands these shell variables at runtime, so they should be treated as intended unexpanded literals rather than an interpolation/quoting mistake.

Applied to files:

  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
📚 Learning: 2026-05-01T14:35:32.037Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/remote.nix:153-179
Timestamp: 2026-05-01T14:35:32.037Z
Learning: In this repo’s NixOS module code (e.g., shell scripts produced via `writeShellApplication` inside `modules/nixos/**`), do not treat missing `XDG_STATE_HOME` fallbacks (like `${XDG_STATE_HOME:-$HOME/.local/state}`) as an error in the embedded shell script. On NixOS user sessions, `XDG_STATE_HOME` is reliably set via PAM/systemd, so flagging its absence as potentially unset is overly defensive for these generated scripts.

Applied to files:

  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
📚 Learning: 2026-06-20T14:33:25.328Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 590
File: modules/nixos/server/monitoring/collector/tempo.nix:71-72
Timestamp: 2026-06-20T14:33:25.328Z
Learning: When reviewing DaRacci/nix-config NixOS modules that use sops-nix, do not flag `sops.secrets` entries as missing `owner`, `group`, `mode`, or `restartUnits` if the secret declarations are only placeholder sources for `sops.templates`:
- The secret value is referenced exclusively via `config.sops.placeholder.<NAME>` inside a `sops.templates` definition (i.e., no other code reads the decrypted secret from the raw secret path).
- The rendered `sops.templates` output is what is used by systemd via a `systemd.services.*.serviceConfig.EnvironmentFile` (the template is the effective boundary).
In this pattern, the template’s own `restartUnits` are the relevant access-control/restart boundary; the raw `sops.secrets` files are only decrypted in-memory by sops-nix (run as root) to render the template. Therefore, empty-attrset `sops.secrets.<NAME> = { };` declarations should not be treated as missing permissions/restart hooks when they are only feeding a `sops.templates` placeholder.

Applied to files:

  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
📚 Learning: 2026-05-01T09:57:09.578Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/services/ai-agent.nix:15-15
Timestamp: 2026-05-01T09:57:09.578Z
Learning: In this repo’s Nix modules, `inputs.services-zeroclaw` is a flake input that resolves to an attrset containing a `_file` attribute, and Nix coerces that attrset to a file path via `_file`. When importing/using it as a path in `imports` (e.g., `modules/nixos/services/ai-agent.nix`), use the string interpolation form "${inputs.services-zeroclaw}". Do not change it to `inputs.services-zeroclaw` (raw attrset form) in `imports`, because it will not work correctly.

Applied to files:

  • modules/nixos/server/storage/seaweedfs.nix
  • modules/nixos/server/default.nix
  • modules/nixos/core/boot/secureboot.nix
  • modules/nixos/core/stylix.nix
  • modules/nixos/server/proxy/extensions/api-key-auth.nix
  • modules/nixos/core/sops.nix
  • modules/nixos/core/host/persistence.nix
  • modules/nixos/server/tests.nix
  • modules/nixos/core/nix.nix
  • modules/nixos/services/ai-agent.nix
📚 Learning: 2026-05-02T15:02:17.285Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 542
File: modules/nixos/server/storage/seaweedfs.nix:362-366
Timestamp: 2026-05-02T15:02:17.285Z
Learning: When reviewing SeaweedFS configuration in Nix files, treat SeaweedFS CLI address flags like `-master`, `-admin`, etc. as valid when they use SeaweedFS’s documented address syntax `<host>:<httpPort>.<grpcPort>`. For example, `-admin=admin.seaweedfs.racci.dev:443.10443` means HTTP port `443` and gRPC port `10443`. Do not mark these as malformed addresses. Only flag the value if it does not match the `<host>:<number>.<number>` shape (e.g., missing the dot separator or non-numeric ports).

Applied to files:

  • modules/nixos/server/storage/seaweedfs.nix
📚 Learning: 2026-05-02T15:02:17.285Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 542
File: modules/nixos/server/storage/seaweedfs.nix:362-366
Timestamp: 2026-05-02T15:02:17.285Z
Learning: In SeaweedFS Nix/CLI configuration, address arguments for flags like `-master` and `-admin` use SeaweedFS’s documented format `<host>:<httpPort>.<grpcPort>`. This is valid and should not be treated as a malformed address. For example, `-admin=admin.seaweedfs.racci.dev:443.10443` sets HTTP port `443` and gRPC port `10443` in a single argument—so reviews should not flag the `:<httpPort>.<grpcPort>` segment as invalid syntax.

Applied to files:

  • modules/nixos/server/storage/seaweedfs.nix
📚 Learning: 2026-03-18T23:46:49.905Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: .woodpecker/lix.yaml:15-15
Timestamp: 2026-03-18T23:46:49.905Z
Learning: In nix-config repository (.woodpecker/*.yaml), image references intentionally omit explicit tags or digests (e.g., registry.racci.dev/lix-woodpecker without :tag). Do not flag or suggest adding explicit tags or digests to these image references; treat such omissions as intentional and maintain consistency across the CI config.

Applied to files:

  • .woodpecker/test-vm.yaml
🪛 ast-grep (0.44.0)
run-test.sh

[warning] 2-2: Writing to or reading from a hardcoded, predictable path under /tmp is vulnerable to symlink and TOCTOU attacks: a local attacker can pre-create the file (or a symlink pointing elsewhere) and hijack or corrupt the contents. Generate a unique, unpredictable temporary file with mktemp instead, e.g. tmpfile="$(mktemp)" (or mktemp -d for directories) and reference "$tmpfile".
Context: /tmp/test-result.log
Note: [CWE-377] Insecure Temporary File.

(predictable-tmp-file-bash)


[warning] 4-4: Writing to or reading from a hardcoded, predictable path under /tmp is vulnerable to symlink and TOCTOU attacks: a local attacker can pre-create the file (or a symlink pointing elsewhere) and hijack or corrupt the contents. Generate a unique, unpredictable temporary file with mktemp instead, e.g. tmpfile="$(mktemp)" (or mktemp -d for directories) and reference "$tmpfile".
Context: /tmp/test-result.log
Note: [CWE-377] Insecure Temporary File.

(predictable-tmp-file-bash)

🪛 LanguageTool
docs/src/development/vm_integration_tests.md

[uncategorized] ~207-~207: Loose punctuation mark.
Context: ...run. ### Requirements - /dev/kvm: QEMU tests require KVM acceleration. Wi...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.22.1)
docs/src/development/vm_integration_tests.md

[warning] 13-13: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 233-233: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

Comment thread _run_tests.sh
Comment thread .woodpecker/test-vm.yaml
Comment on lines +1 to +5
# PR-only, KVM.
# Build nixosTestConfigurations.* for all server hosts.
# TODO: affected-host build (PR-changed only).
#
# Independent of check.yaml.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🔵 Trivial

TODO acknowledges full-host builds; currently every PR builds all server + scenario hosts.

Per the flake/nixos/flake-module.nix snippet, nixosTestConfigurations enumerates every server host plus every scenario directory, so this pipeline will grow linearly (VM builds are expensive) as hosts/scenarios are added. Want help sketching an affected-host filter (e.g., diffing hosts/server/** against the PR's changed files) to close the TODO?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.woodpecker/test-vm.yaml around lines 1 - 5, The PR-only KVM job currently
builds every server and scenario host via nixosTestConfigurations, which does
not scale as the repo grows. Update the test-vm pipeline to run only affected
hosts by filtering against the PR’s changed files (for example, comparing
changes under hosts/server/** and scenario directories) before expanding the
build set. Keep the logic anchored around the test-vm job and the
nixosTestConfigurations consumer so the affected-host selection happens before
VM builds are scheduled.

Comment thread .woodpecker/test-vm.yaml
Comment on lines +28 to +32
for host in $(nix eval .#nixosTestConfigurations --apply 'builtins.attrNames' --json | jq -r '.[]'); do
echo "::group::VM test: $host"
nix build ".#nixosTestConfigurations.$host" --no-link -L || echo "FAILED: $host"
echo "::endgroup::"
done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🔵 Trivial

Sequential per-host loop won't scale as hosts/scenarios grow.

All builds run serially in a single shell loop on one agent, so total CI time grows linearly with the host count. Native Woodpecker matrix builds require statically-known values at parse time, which doesn't fit the dynamically discovered host list here (nix eval .#nixosTestConfigurations), so this isn't a drop-in fix — but worth considering a generated/dynamic pipeline step or splitting into parallel agent runs if VM build times become a bottleneck.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.woodpecker/test-vm.yaml around lines 28 - 32, The VM test loop in the test
step runs each host serially, so it will become a CI bottleneck as the host list
grows. Update the logic around the host iteration in the test script to use a
parallelized or dynamically generated execution strategy instead of a single
shell loop in one agent, while keeping the current `nix eval
.#nixosTestConfigurations` host discovery and `nix build` per-host behavior
intact.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Per-host build failures are swallowed — the step always reports success.

Woodpecker runs step commands as a single /bin/sh -e script, and a step's overall exit status is what determines pipeline pass/fail. Here, nix build ... || echo "FAILED: $host" suppresses the non-zero exit from -e, and the loop's last command (echo "::endgroup::") always returns 0. Consequently, this "Run VM tests" step will report success even if every host build fails, defeating the purpose of gating PRs on VM test results.

🐛 Proposed fix to propagate failures
   - name: Run VM tests
     image: registry.racci.dev/lix-woodpecker:latest
     commands: |
+      status=0
       for host in $(nix eval .#nixosTestConfigurations --apply 'builtins.attrNames' --json | jq -r '.[]'); do
         echo "::group::VM test: $host"
-        nix build ".#nixosTestConfigurations.$host" --no-link -L || echo "FAILED: $host"
+        if ! nix build ".#nixosTestConfigurations.$host" --no-link -L; then
+          echo "FAILED: $host"
+          status=1
+        fi
         echo "::endgroup::"
       done
+      exit $status
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for host in $(nix eval .#nixosTestConfigurations --apply 'builtins.attrNames' --json | jq -r '.[]'); do
echo "::group::VM test: $host"
nix build ".#nixosTestConfigurations.$host" --no-link -L || echo "FAILED: $host"
echo "::endgroup::"
done
status=0
for host in $(nix eval .#nixosTestConfigurations --apply 'builtins.attrNames' --json | jq -r '.[]'); do
echo "::group::VM test: $host"
if ! nix build ".#nixosTestConfigurations.$host" --no-link -L; then
echo "FAILED: $host"
status=1
fi
echo "::endgroup::"
done
exit $status
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.woodpecker/test-vm.yaml around lines 28 - 32, The “Run VM tests” loop is
swallowing failures because the `nix build` error is followed by a successful
`echo`, so the shell step always exits 0. Update the VM test commands in
`.woodpecker/test-vm.yaml` to let `nix build` failures propagate from the loop
instead of masking them, and ensure the step exits non-zero when any host build
fails. Use the existing `nix build ".#nixosTestConfigurations.$host"` loop and
the `echo "::group::VM test: $host"` / `echo "::endgroup::"` structure as the
location to fix this behavior.

Comment thread docs/src/development/vm_integration_tests.md
Comment thread docs/src/development/vm_integration_tests.md
Comment thread hosts/server/nixio/storage.nix
Comment thread hosts/server/nixserv/default.nix
Comment thread modules/nixos/server/tests.nix
Comment thread run-test.sh
Comment thread tests/builder.nix
Comment on lines +34 to +40
baselineAssertions = nodeName: ''
${nodeName}.wait_for_unit("multi-user.target")
${nodeName}.wait_for_unit("sshd.service")
${nodeName}.succeed("journalctl --no-pager -n 1")
out = ${nodeName}.succeed("systemctl list-units --state=failed --no-legend --no-pager")
assert out.strip() == "", f"Failed units found on ${nodeName}: {out}"
'';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Nested multi-line string interpolation will desync Python indentation inside with subtest(): blocks.

baselineAssertions (and unit.testScript at line 78) are multi-line Nix strings interpolated directly under a with subtest(...): line (e.g. lines 72‑73, 76‑78, 107‑109). Nix indented-string dedenting is computed from the literal source text before substitution — only the first line of the interpolated value inherits the surrounding indentation; every subsequent line keeps whatever (shallower) indentation was baked into the interpolated string itself. The generated Python will end up with the first assertion indented under with, but the remaining wait_for_unit/succeed/assert lines flush left — this is either an IndentationError or, worse, statements silently running outside the with subtest() scope.

This affects both the host branch (lines 69‑80) and the scenario branch (lines 102‑114), plus any multi-line unit.testScript.

🐛 Suggested fix — make each helper a self-contained block
-  baselineAssertions = nodeName: ''
-    ${nodeName}.wait_for_unit("multi-user.target")
-    ${nodeName}.wait_for_unit("sshd.service")
-    ${nodeName}.succeed("journalctl --no-pager -n 1")
-    out = ${nodeName}.succeed("systemctl list-units --state=failed --no-legend --no-pager")
-    assert out.strip() == "", f"Failed units found on ${nodeName}: {out}"
-  '';
+  baselineAssertions = nodeName: ''
+    with subtest("${nodeName} baseline"):
+        ${nodeName}.wait_for_unit("multi-user.target")
+        ${nodeName}.wait_for_unit("sshd.service")
+        ${nodeName}.succeed("journalctl --no-pager -n 1")
+        out = ${nodeName}.succeed("systemctl list-units --state=failed --no-legend --no-pager")
+        assert out.strip() == "", f"Failed units found on ${nodeName}: {out}"
+  '';

Then call it flush-left without an outer with subtest(): wrapper:

-      with subtest("${hostName} baseline"):
-        ${baselineAssertions hostName}
+      ${baselineAssertions hostName}

Apply the same pattern to the scenario branch and to how unit.testScript is wrapped.

Also applies to: 69-114

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/builder.nix` around lines 34 - 40, The multi-line Nix strings used by
baselineAssertions and unit.testScript are being interpolated directly inside
with subtest() blocks, which can break Python indentation after the first line.
Move these helpers so each one is a self-contained Python block with its own
indentation, then invoke them flush-left from the host and scenario branches
instead of wrapping the interpolated text inside with subtest():. Apply the same
pattern anywhere unit.testScript is embedded so all assertions stay inside the
intended scope.

Comment thread docs/src/development/vm_integration_tests.md
Comment thread docs/src/development/vm_integration_tests.md
inherit (config.partitions.nixos.module) allocations;

# Build per-system pkgs — need a pkgs instance for the builder
pkgs = lib.builders.mkPkgs { system = "x86_64-linux"; };

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldnt hard code the architecture.

Comment thread flake/nixos/flake-module.nix
Comment thread flake/default.nix
Comment on lines +34 to +77
server.tests.units = {
prometheus = {
testScript = ''
nixmon.succeed("systemctl show prometheus.service | grep -i loadstate")
'';
};

loki = {
testScript = ''
nixmon.succeed("systemctl show loki.service | grep -i loadstate")
'';
};

grafana = {
testScript = ''
nixmon.succeed("systemctl show grafana.service | grep -i loadstate")
'';
};

alertmanager = {
testScript = ''
nixmon.succeed("systemctl show alertmanager.service | grep -i loadstate")
'';
};

uptime-kuma = {
testScript = ''
nixmon.succeed("systemctl show uptime-kuma.service | grep -i loadstate")
'';
};

node-exporter = {
testScript = ''
nixmon.succeed("systemctl show node_exporter.service | grep -i loadstate")
'';
};

alloy = {
testScript = ''
nixmon.succeed("systemctl show alloy.service | grep -i loadstate")
'';
};
};

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless test, needs replacing with real tests.

Comment on lines +54 to +79

server.tests.units = {
minio = {
testScript = ''
nixio.succeed("systemctl show minio.service | grep -i loadstate")
'';
};

seaweedfs-master = {
testScript = ''
nixio.succeed("systemctl show seaweedfs-master.service | grep -i loadstate")
'';
};

seaweedfs-volume = {
testScript = ''
nixio.succeed("systemctl show seaweedfs-volume.service | grep -i loadstate")
'';
};

seaweedfs-filer = {
testScript = ''
nixio.succeed("systemctl show seaweedfs-filer.service | grep -i loadstate")
'';
};
};

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless test, needs replacing with real tests.

))
(builtins.mapAttrs (
_: value:
(removeAttrs value [ "sopsFileHash" ])

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this a required change ?

{
options = {
server.tests = {
enable = mkEnableOption "Enable testing of this machine in the cluster tests";

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
enable = mkEnableOption "Enable testing of this machine in the cluster tests";
enable = mkEnableOption "testing of this machine in the cluster tests";

Would read "Weather to enable Enable testing..." otherwise.

Comment on lines +28 to +35
name = mkOption {
type = str;
default = name;
description = ''
The name to give to this unit test.
This is used to enter into a subtest within the testScript of the cluster test.
'';
};

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a internal readOnly field.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant