From c969f66c6092508dc4fb04e3f81b7a6951cf1ec8 Mon Sep 17 00:00:00 2001 From: ahuston-0 Date: Fri, 10 Apr 2026 01:12:11 -0400 Subject: [PATCH 1/2] add configuration for copilot/continue integration --- .continue/agents/ollama.yaml | 32 ++ .github/copilot-instructions.md | 698 ++++++++++++++++++++++++++++++++ .vscode/extensions.json | 5 + checks.nix | 2 +- 4 files changed, 736 insertions(+), 1 deletion(-) create mode 100644 .continue/agents/ollama.yaml create mode 100644 .github/copilot-instructions.md create mode 100644 .vscode/extensions.json diff --git a/.continue/agents/ollama.yaml b/.continue/agents/ollama.yaml new file mode 100644 index 0000000..ba1f414 --- /dev/null +++ b/.continue/agents/ollama.yaml @@ -0,0 +1,32 @@ +# This is an example configuration file +# To learn more, see the full config.yaml reference: https://docs.continue.dev/reference +name: ollama +version: 1.0.0 +schema: v1 +# Define which models can be used +# https://docs.continue.dev/customization/models +models: + - name: StarCoder2 Local + provider: ollama + model: starcoder2:7b + modelTimeout: "5s" + roles: + - autocomplete + autocompleteOptions: + useCache: true + useImports: true + useRecentlyEdited: true + - name: Nomic Embed Local + provider: ollama + model: nomic-embed-text:latest + roles: + - embed + - name: Autodetect + provider: ollama + model: AUTODETECT + defaultCompletionOptions: + contextLength: 64000 +# MCP Servers that Continue can access +# https://docs.continue.dev/customization/mcp-tools +mcpServers: + - uses: anthropic/memory-mcp diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..9faca8d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,698 @@ +# Nix Dotfiles Repository Guide + +This repository contains NixOS configurations for personal infrastructure. The setup is organized around a flake-based structure with per-system configurations and user-specific settings. + +## Project Structure + +- `flake.nix` - Main flake definition with inputs and outputs +- `systems/` - Per-system configurations (e.g., `artemision`, `palatine-hill`) +- `users/` - Per-user configurations using home-manager +- `modules/` - Reusable Nix modules for common services +- `lib/` - Custom Nix library functions +- `hydra/` - Hydra CI/CD configuration +- `secrets/` - SOPS encrypted secrets + +## Key Concepts + +### System Configuration + +Each system has its own directory under `systems/` containing: + +- `configuration.nix` - Main system configuration +- Component modules (audio.nix, desktop.nix, etc.) +- Hardware-specific configurations + +### User Configuration + +User configurations are in `users//`: + +- `home.nix` - Home-manager configuration using `home.packages` and imports +- `secrets.yaml` - SOPS-encrypted secrets using age encryption +- `non-server.nix` - Desktop-specific configurations + +### Nix Patterns + +1. **Module-based approach**: Uses Nix modules for organizing configuration +1. **Home-manager integration**: User environment managed via home-manager +1. **SOPS secrets**: Secrets managed with SOPS and age encryption +1. **Flake-based**: Uses flakes for reproducible builds and development environments +1. **Multi-system support**: Supports multiple machines with different configurations +1. **Dynamic configuration generation**: Modules in the `modules/` directory are automatically imported into all systems (can be overridden per system). New systems are automatically discovered by `genSystems()` + +### Modern Nix Features + +This repository uses modern Nix features including: + +- **Flakes**: Enabled via `flake` experimental feature +- **Nix Command**: Enabled via `nix-command` experimental feature +- **Blake3 Hashes**: Enabled via `blake3-hashes` experimental feature +- **Git Hashing**: Enabled via `git-hashing` experimental feature +- **Verified Fetches**: Enabled via `verified-fetches` experimental feature + +### Key Commands + +- `nh os switch` - Apply system configuration (using nix-community/nh) +- `nh home switch` - Apply user configuration (using nix-community/nh) +- `nh os build` - Build a specific system (using nix-community/nh) +- `nix build .#` - Build a specific system +- `nix run .#` - Run a specific system +- `nix flake update` - Update flake inputs + +### Development Workflow + +1. Make changes to system or user configuration +1. Test with `nh os switch` or `nh home switch` +1. For CI/CD, Hydra automatically builds and tests changes +1. Secrets are managed with SOPS and age keys + +### Important Files + +- `flake.nix` - Main entry point for the flake +- `systems/artemision/configuration.nix` - Example system configuration +- `users/alice/home.nix` - Example user configuration +- `modules/base.nix` - Base module with common settings +- `hydra/jobsets.nix` - Hydra CI configuration + +### External Dependencies + +- NixOS unstable channel +- Nixpkgs unstable channel +- SOPS for secrets management +- age for encryption +- home-manager for user environments +- nh (nix-community/nh) for simplified Nix operations + +### Nix MCP Server + +- Use the nix MCP server for looking up package names and options +- Specify `unstable` channel if the channel is specifiable (e.g., for `pkgs.`) + +## Dynamic Configuration System (lib/systems.nix) + +This repository automatically generates NixOS system configurations based on the folder structure. Understanding how `constructSystem` and `genSystems` work is essential when adding new systems or global modules. + +### How Configuration Generation Works + +The process happens in three stages: + +**Stage 1: Discovery** (`flake.nix` → `genSystems`) + +- `flake.nix` calls `genSystems inputs outputs src (src + "/systems")` +- `genSystems` scans the `systems/` directory and lists all subdirectories +- Each subdirectory name becomes a system hostname (e.g., `artemision`, `palatine-hill`) + +**Stage 2: Parameter Loading** (`genSystems` reads `default.nix`) + +- For each discovered system, `genSystems` imports `systems//default.nix` +- This file exports parameters for `constructSystem` like: +- `users = [ "alice" ]` — which users to create +- `home = true` — enable home-manager +- `sops = true` — enable secret decryption +- `server = true/false` — machine role +- `modules = [ ... ]` — additional system-specific modules + +**Stage 3: Assembly** (`constructSystem` assembles the full config) + +- Loads essential system files: `hardware.nix`, `configuration.nix` +- Auto-imports all `.nix` files from `modules/` directory via `lib.adev.fileList` +- Conditionally loads home-manager, SOPS, and user configs based on parameters +- Merges everything into a complete NixOS system configuration + +### Key Functions in lib/systems.nix + +| Function | Purpose | Called By | +|----------|---------|-----------| +| `genSystems` | Scans `systems/` directory and creates configs for each subdirectory | `flake.nix` | +| `constructSystem` | Assembles a single NixOS system with all modules and configs | `genSystems` | +| `genHome` | Imports home-manager configs for specified users | `constructSystem` | +| `genSops` | Imports SOPS-encrypted secrets for users | `constructSystem` | +| `genUsers` | Imports user account configs from `users//` | `constructSystem` | +| `genHostName` | Creates hostname attribute set | `constructSystem` | +| `genWrapper` | Conditionally applies generator functions | `constructSystem` | + +### Special Arguments Passed to All Configs + +These are available in `configuration.nix`, `hardware.nix`, and all modules: + +```nix +{ config, pkgs, lib, inputs, outputs, server, system, ... }: +``` + +- `config` — NixOS configuration options +- `pkgs` — Nix packages (nixpkgs) +- `lib` — Nix library functions (extended with `lib.adev`) +- `inputs` — Flake inputs (nixpkgs, home-manager, sops-nix, etc.) +- `outputs` — Flake outputs (for Hydra and other tools) +- `server` — Boolean: true for servers, false for desktops +- `system` — System architecture string (e.g., `"x86_64-linux"`) + +## Adding a New NixOS System + +### Step 1: Create the Directory Structure + +```bash +mkdir -p systems/ +cd systems/ +``` + +### Step 2: Create `default.nix` (System Parameters) + +This file is automatically discovered and loaded by `genSystems`. It exports the parameters passed to `constructSystem`. + +**Minimal example:** + +```nix +{ inputs }: +{ + # Required: List of users to create (must have entries in users/ directory) + users = [ "alice" ]; + + # Optional: Enable home-manager (default: true) + home = true; + + # Optional: Enable SOPS secrets (default: true) + sops = true; + + # Optional: Is this a server? Used to conditionally enable server features + server = false; + + # Optional: System architecture (default: "x86_64-linux") + system = "x86_64-linux"; + + # Optional: System-specific modules (in addition to global modules/) + modules = [ + # ./custom-service.nix + ]; +} +``` + +**See `systems/palatine-hill/default.nix` for a complex example with all options.** + +### Step 3: Create `hardware.nix` (Hardware Configuration) + +Generate this via: + +```bash +sudo nixos-generate-config --show-hardware-config > systems//hardware.nix +``` + +This file typically includes: + +- Boot configuration and bootloader +- Filesystem mounts and ZFS/LVM settings +- Hardware support (CPU, GPU, network drivers) +- Device-specific kernel modules + +### Step 4: Create `configuration.nix` (System Configuration) + +This is the main NixOS configuration file. Structure: + +```nix +{ config, pkgs, lib, inputs, server, system, ... }: +{ + # System hostname (usually matches directory name) + networking.hostName = "new-hostname"; + + # Desktop/desktop specific config + services.xserver.enable = !server; + + # System packages + environment.systemPackages = with pkgs; [ + # ... + ]; + + # Services to enable + services.openssh.enable = server; + + # System-specific settings override global defaults + boot.kernelParams = [ "nomodeset" ]; +} +``` + +### Step 5: Add Optional Secrets + +If the system has sensitive data: + +```bash +# Create and encrypt secrets file +sops systems//secrets.yaml + +# This will be automatically loaded by genSops if sops = true +``` + +### Step 6: Add Optional System-Specific Modules + +For system-specific functionality that shouldn't be global, create separate `.nix` files in the system directory: + +```text +systems// +├── configuration.nix # Main config +├── default.nix +├── hardware.nix +├── secrets.yaml # (optional) +├── custom-service.nix # (optional) System-specific modules +├── networking.nix # (optional) +└── graphics.nix # (optional) +``` + +Reference these in `default.nix`: + +```nix +{ inputs }: +{ + users = [ "alice" ]; + modules = [ + ./custom-service.nix + ./networking.nix + ./graphics.nix + ]; +} +``` + +### Step 7: Deploy the New System + +The system is now automatically registered! Deploy with: + +```bash +# Build the new system +nix build .# + +# Or if you want to switch immediately +nh os switch +``` + +## Adding a Global Module to modules/ + +Global modules are automatically imported into all systems. No registration needed. + +### Create a Module File + +Add a new `.nix` file to the `modules/` directory. Example: `modules/my-service.nix` + +### Module Structure + +```nix +{ config, pkgs, lib, inputs, server, ... }: +{ + # Define configuration options for this module + options.myService = { + enable = lib.mkEnableOption "my service"; + port = lib.mkOption { + type = lib.types.int; + default = 3000; + description = "Port for the service"; + }; + }; + + # Actual configuration (conditional on enable option) + config = lib.mkIf config.myService.enable { + environment.systemPackages = [ pkgs.my-service ]; + + systemd.services.my-service = { + description = "My Service"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.my-service}/bin/my-service"; + Restart = "always"; + }; + }; + }; +} +``` + +### Using mkIf, mkDefault, and mkForce + +- **`mkIf`** — Conditionally apply config based on a boolean + + ```nix + config = lib.mkIf config.myService.enable { ... }; + ``` + +- **`mkDefault`** — Provide a default value that can be overridden + + ```nix + boot.kernelParams = lib.mkDefault [ "quiet" ]; + ``` + +- **`mkForce`** — Force a value, preventing other modules from overriding + + ```nix + services.openssh.enable = lib.mkForce true; + ``` + +- **`mkEnableOption`** — Define an `enable` option with standard description + + ```nix + options.myService.enable = lib.mkEnableOption "my service"; + ``` + +### Disable a Global Module for a Specific System + +To disable a module for one system, override it in that system's `configuration.nix`: + +```nix +{ config, lib, ... }: +{ + # Disable the module entirely + myService.enable = false; + + # Or override specific options + services.openssh.port = 2222; +} +``` + +### Module Loading Order in constructSystem + +Modules are applied in this order (later modules override earlier ones): + +1. `inputs.nixos-modules.nixosModule` (SuperSandro2000's convenience functions) +1. `inputs.nix-index-database.nixosModules.nix-index` +1. Hostname attribute from `genHostName` +1. `hardware.nix` (hardware-specific config) +1. `configuration.nix` (main system config) +1. **System-specific modules** from `modules` parameter in `default.nix` (e.g., custom-service.nix) +1. **All `.nix` files from global `modules/` directory** (features enabled across all systems) +1. SOPS module (if `sops = true`) +1. Home-manager module (if `home = true`) +1. User configurations (if `users = [...]` and `home = true`) + +Important: Global modules (step 7) are applied after system-specific configs, so they can't override those values unless using `mkForce`. System-specific modules take precedence over global ones. + +## Common Tasks + +### Enable a Feature Across All Systems + +1. Create `modules/my-feature.nix` with `options.myFeature.enable` +1. Set the feature enabled in `configuration.nix` of systems that need it: + + ```nix + myFeature.enable = true; + ``` + +1. Or enable globally and disable selectively: + + ```nix + # In modules/my-feature.nix + config = lib.mkIf config.myFeature.enable { + # ...enabled by default + }; + + # In a system's configuration.nix + myFeature.enable = false; # Disable just for this system + ``` + +### Add a New User to the System + +1. Create user config: `users//default.nix` and `users//home.nix` +1. Update system's `default.nix`: + + ```nix + users = [ "alice" "newuser" ]; + ``` + +1. Create secrets: `sops users//secrets.yaml` +1. Redeploy: `nh os switch` + +### Override a Module's Default Behavior + +In any system's `configuration.nix`: + +```nix +{ + # Disable a service that's enabled by default in a module + services.openssh.enable = false; + + # Override module options + boot.kernelParams = [ "nomodeset" ]; + + # Add to existing lists + environment.systemPackages = [ pkgs.custom-tool ]; +} +``` + +### Check Which Modules Are Loaded + +```bash +# List all module paths being loaded +nix eval .#nixosConfigurations..options --json | jq keys | head -20 + +# Evaluate a specific config value +nix eval .#nixosConfigurations..config.services.openssh.enable +``` + +### Validate Configuration Before Deploying + +```bash +# Check syntax and evaluate +nix flake check + +# Build without switching +nix build .# + +# Preview what would change +nix build .# && nix-diff /run/current-system ./result +``` + +## Secrets Management + +SOPS (Secrets Operations) manages sensitive data like passwords and API keys. This repository uses age encryption with SOPS to encrypt secrets per system and per user. + +### Directory Structure + +Secrets are stored alongside their respective configs: + +```text +systems//secrets.yaml # System-wide secrets +users//secrets.yaml # User-specific secrets +``` + +### Creating and Editing Secrets + +**Create or edit a secrets file:** + +```bash +# For a system +sops systems//secrets.yaml + +# For a user +sops users//secrets.yaml +``` + +SOPS will open your `$EDITOR` with decrypted content. When you save and exit, it automatically re-encrypts the file. + +**Example secrets structure for a system:** + +```yaml +# systems/palatine-hill/secrets.yaml +acme: + email: user@example.com + api_token: "secret-token-here" +postgresql: + password: "db-password" +``` + +**Example secrets for a user:** + +```yaml +# users/alice/secrets.yaml +# The user password is required +user-password: "hashed-password-here" +``` + +### Accessing Secrets in Configuration + +Secrets are made available via `config.sops.secrets` in modules and configurations: + +```nix +# In a module or configuration.nix +{ config, lib, ... }: +{ + # Reference a secret + services.postgresql.initialScript = '' + CREATE USER app WITH PASSWORD '${config.sops.secrets."postgresql/password".path}'; + ''; + + # Or use the secret directly if it supports content + systemd.services.my-app.serviceConfig = { + EnvironmentFiles = [ config.sops.secrets."api-token".path ]; + }; +} +``` + +### Merging Secrets Files + +When multiple systems or users modify secrets, use the sops-mergetool to resolve conflicts: + +```bash +# Set up mergetool +git config merge.sopsmergetool.command "sops-mergetool-wrapper $BASE $CURRENT $OTHER $MERGED" + +# Then during a merge conflict +git merge branch-name + +# Git will use sops-mergetool to intelligently merge encrypted files +``` + +The repository includes helper scripts: `utils/sops-mergetool.sh` and `utils/sops-mergetool-new.sh` + +### Adding a New Machine's Age Key + +When adding a new system (`systems//`), you need to register its age encryption key: + +1. Generate the key on the target machine (if using existing deployment) or during initial setup +1. Add the public key to `.sops.yaml`: + + ```yaml + keys: + - &artemision + - &palatine-hill + - &new-hostname + + creation_rules: + - path_regex: 'systems/new-hostname/.*' + key_groups: + - age: *new-hostname + ``` + +1. Re-encrypt existing secrets with the new key: + + ```bash + sops updatekeys systems/new-hostname/secrets.yaml + ``` + +## Real-World Examples + +### Example 1: Adding a Feature to All Desktop Machines + +Using `artemision` (desktop) as an example: + +**Create `modules/gpu-optimization.nix`:** + +```nix +{ config, lib, server, ... }: +{ + options.gpu.enable = lib.mkEnableOption "GPU optimization"; + + config = lib.mkIf (config.gpu.enable && !server) { + # Desktop-only GPU settings + hardware.nvidia.open = true; + services.xserver.videoDrivers = [ "nvidia" ]; + }; +} +``` + +**Enable in `systems/artemision/configuration.nix`:** + +```nix +{ + gpu.enable = true; +} +``` + +**Deploy:** + +```bash +nix build .#artemision +nh os switch +``` + +### Example 2: Adding a Server Service to One System + +Using `palatine-hill` (server) as an example: + +**Create `systems/palatine-hill/postgresql-backup.nix`:** + +```nix +{ config, pkgs, lib, ... }: +{ + systemd.timers.postgres-backup = { + description = "PostgreSQL daily backup"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "03:00"; + Persistent = true; + }; + }; + + systemd.services.postgres-backup = { + description = "Backup PostgreSQL database"; + script = '' + ${pkgs.postgresql}/bin/pg_dumpall | gzip > /backups/postgres-$(date +%Y%m%d).sql.gz + ''; + }; +} +``` + +**Reference in `systems/palatine-hill/default.nix`:** + +```nix +{ inputs }: +{ + users = [ "alice" ]; + server = true; + modules = [ + ./postgresql-backup.nix + ]; +} +``` + +**Deploy:** + +```bash +nix build .#palatine-hill +``` + +### Example 3: Disabling a Global Module for a Specific System + +To disable `modules/steam.nix` on a server (`palatine-hill`) while it stays enabled on desktops: + +**In `systems/palatine-hill/configuration.nix`:** + +```nix +{ + steam.enable = false; # Override the module option +} +``` + +The module in `modules/steam.nix` should use: + +```nix +config = lib.mkIf config.steam.enable { + # steam configuration only if enabled +}; +``` + +## Debugging & Validation + +### Check Module Evaluation + +```bash +# See which modules are loaded for a system +nix eval .#nixosConfigurations.artemision.config.environment.systemPackages --no-allocator + +# Validate module option exists +nix eval .#nixosConfigurations.artemision.options.myService.enable +``` + +### Debug SOPS Secrets + +```bash +# View encrypted secrets (you must have the age key) +sops systems/palatine-hill/secrets.yaml + +# Check if SOPS integration is working +nix eval .#nixosConfigurations.palatine-hill.config.sops.secrets --json +``` + +### Test Configuration Without Deploying + +```bash +# Evaluate the entire configuration +nix eval .#nixosConfigurations.artemision --no-allocator + +# Build (but don't activate) +nix build .#artemision + +# Check for errors in the derivation +nix path-info ./result +``` diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..741afdd --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "davidanson.vscode-markdownlint" + ] +} \ No newline at end of file diff --git a/checks.nix b/checks.nix index 6d55445..a4e6b87 100644 --- a/checks.nix +++ b/checks.nix @@ -56,7 +56,7 @@ forEachSystem ( #!/usr/bin/env ruby all - rule 'MD013', :tables => false + rule 'MD013', :tables => false, :line_length => 220 '').outPath; }; From 11061e769248b2eaf0736a91b6343caa628f3bbc Mon Sep 17 00:00:00 2001 From: ahuston-0 Date: Sun, 12 Apr 2026 10:48:47 -0400 Subject: [PATCH 2/2] add video and render groups --- users/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/users/default.nix b/users/default.nix index 7de3767..d81436a 100644 --- a/users/default.nix +++ b/users/default.nix @@ -28,6 +28,8 @@ "plugdev" "uaccess" "ydotool" + "video" + "render" ] ++ groups; }