Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

NixOS logo

This flake manages all Nix-based configurations — NixOS, nix-darwin, and Home Manager — from a single repository.

What’s inside

DirectoryPurpose
systems/NixOS and nix-darwin host configurations (one directory per host)
homes/Home Manager user environments
modules/Reusable NixOS, darwin, home-manager, and devix (dev-env) modules
packages/Custom packages and overrides
shells/Dev shells (nix develop .#go, .#website, .#nix)
overlays/Nixpkgs overlays
lib/Helper functions
secrets/sops-encrypted secrets
docs/This documentation (mdBook)

See Architecture for the full map, the tag system, and how to add a host or user.

Key technologies

Architecture

This page is the map of the repository: what lives where, how a host gets built, and where to start when adding something new.

Directory layout

PathPurpose
flake.nixInputs and output wiring. Host/user discovery is delegated to systems/ and homes/.
systems/<arch>/<host>/One directory per host, auto-discovered. The directory name is the hostname.
systems/iso/Installer ISO definition and the list of hosts that get an iso-* image.
modules/nixos/NixOS modules (desktop, services, system, security, users, …).
modules/darwin/nix-darwin modules (homebrew, services, system, users).
modules/home-manager/Home Manager modules — the largest tree, see background vs foreground.
modules/devix/Development-environment mechanism: a registry of languages, addons, LSPs, and formatters consumed by editors (helix, zed, opencode). Exposed as homeModules.devix and devenvModules.*. See devix.
homes/<user>/Per-user Home Manager entry points, auto-discovered for standalone homeConfigurations. SSH public keys live in homes/<user>/keys/.
lib/Small helper library layered onto nixpkgs.lib (directory listing, tag predicate, eachSystem).
overlays/Nixpkgs overlays: custom packages, modifications, pkgs.unstable, …
packages/Custom packages: top-level/ (auto-discovered), custom/ (namespaced under pkgs.custom), plus python/kodi/home-assistant scopes and the docs book.
shells/Dev shells (nix develop .#go, .#website, .#nix).
secrets/sops-encrypted secrets. Recipients (age keys per user and host) are declared in secrets/.sops.yaml.
scripts/Repo tooling (package bump script, CI checks) — driven via the justfile.
docs/This mdBook. Published via GitHub Pages, buildable with nix build .#docs.
justfileTask runner: just --list shows all daily commands.

How a host is built

flake.nix
  └─ systems/default.nix          scans systems/<arch>/ for host directories
       ├─ arch contains "darwin"? ─ nix-darwin's darwinSystem
       │    └─ modules/darwin + home-manager + stylix + sops + homes/nixos.nix
       └─ otherwise ─────────────── lib.nixosSystem
            └─ modules/nixos + home-manager + facter + homes/nixos.nix
                 └─ homes/nixos.nix instantiates home-manager for
                    homes.users (default: the primary user), each importing
                    homes/<user>/ + modules/home-manager
  • networking.hostName is forced to the directory name.
  • A facter.json in the host directory is picked up automatically (hardware detection via nixos-facter).
  • A nixpkgs.nix in the host directory supplies per-host nixpkgs config, merged over the shared one. This is the only way to set it: pkgs is instantiated in systems/default.nix outside the module system, so a host cannot use nixpkgs.config in its configuration.nix (the nixpkgs module rejects it). See systems/x86_64-linux/kyuubi/nixpkgs.nix, which permits an insecure Broadcom wifi driver for that host alone.
  • users.primaryUser must be set in every host config; the user account itself comes from modules/nixos/users/ (or modules/darwin/users/).
  • Standalone homeConfigurations.<user> (for non-NixOS machines) are generated from the homes/<user>/ directories, independent of any host.

The tag system

Hosts describe themselves with a list of tags instead of toggling dozens of options:

# systems/x86_64-linux/madara/configuration.nix
system.tags = [ "desktop" "workstation" "development" "management" ];
  • The known tags are enumerated in modules/shared/tags.nix — the option type rejects anything else at eval time, so a typo or a tag without consumers cannot slip in silently. Current tags: desktop, laptop, workstation, development, management, nas, gaming, server (each with a one-line meaning in that file).
  • Modules query tags through config.lib.tags.hasTag "<tag>" (the predicate lives in lib/has-tag.nix; the option is declared under modules/{nixos,darwin}/system/tags/).
  • Tag modules under modules/{nixos,darwin}/system/tags/ translate tags into concrete settings (e.g. desktop enables the desktop environment stack, management installs colmena, gaming enables Steam). Server roles key on the server tag — tailscale exit-node/connector/SSH advertising and the no-sound-stack default — never on the absence of an interactive tag: a workstation or laptop without desktop is still somebody’s machine.
  • Colmena reuses the same tags for deployment targeting: colmena apply --on @desktop (wired via colmena.deployment.tags).
  • Home Manager cannot read config.lib.tags without infinite recursion, so modules/home-manager/imports.nix imports the predicate directly against osConfig and maps tags onto its own hosts.{desktop,laptop,workstation,development}.enable options. Inside home-manager modules, gate on config.hosts.*.enable.

Background vs foreground

modules/home-manager/ is split by session type, not by program category:

  • background/ — everything that works on a headless machine or over SSH: shell, git, editors, CLI tools, AI tooling, user services. Imported unconditionally.
  • foreground/ — everything that needs a display: desktop environments, bars, GUI programs, fonts-for-GUI. Gated behind foreground.enable, which defaults from the desktop tag (darwin), the gui.enable option (NixOS), or true (standalone home-manager).
  • theming/ — stylix wiring, wallpaper, color scheme; enabled with the desktop tag.
  • development/policy: which languages/tools from modules/devix (the mechanism) are turned on for development-tagged hosts.

devix

Development-environment mechanism: describe a language once — its language servers, formatters and indentation — and every editor that consumes the description configures itself from it. Stylix’s idea, applied to dev tooling.

It is documented in its own section, starting at devix: concepts, usage, adding a language, adding an editor, and a generated support matrix and option reference.

The one thing worth repeating here is the split this repository depends on: modules/devix is pure mechanism and enables nothing, while modules/home-manager/development/ is the policy that decides which languages are on for which hosts.

Adding a host

  1. Create systems/<arch>/<hostname>/default.nix (plus configuration.nix, hardware-configuration.nix or facter.json, and optionally disk.nix for disko). The directory is discovered automatically.
  2. Set users.primaryUser and system.tags in the config.
  3. Add the host’s age key to secrets/.sops.yaml and re-encrypt: just secrets-rekey (key comes from the host’s SSH key, see sops).
  4. For colmena deploys, set colmena.deployment.targetHost.
  5. If the host should get an installer image, add it to the list in systems/iso/default.nix — then just iso <hostname>.

Adding a user

  1. Create homes/<user>/default.nix (auto-discovered as homeConfigurations.<user>); put SSH public keys in homes/<user>/keys/.
  2. Create modules/nixos/users/<user>.nix (auto-imported; see mirza.nix for the pattern).
  3. Set users.primaryUser = "<user>" on the hosts that belong to them, and add their age key to secrets/.sops.yaml.

Custom options cheat sheet

Options defined by this flake (as opposed to upstream NixOS/HM options):

OptionDefined inMeaning
system.tagsmodules/{nixos,darwin}/system/tags/Host capability tags (see above)
users.primaryUsermodules/{nixos,darwin}/users/The one human this machine belongs to
users.users.<u>.isAdminmodules/nixos/users/wheel + virtualisation groups
homes.users / homes.enablehomes/nixos.nixWhich users get home-manager
gui.enablemodules/nixos/programs/“This host has GUI applications” (feeds foreground.enable)
desktop-environment.enablemodules/nixos/desktop/Desktop environment stack
hosts.{desktop,laptop,workstation,development}.enablemodules/home-manager/imports.nixHM-side mirror of the tags
devix.*modules/devix/Development environments — see the devix section
foreground.enablemodules/home-manager/foreground/GUI-facing home config
theming.{enable,scheme,image}modules/home-manager/theming/, modules/nixos/system/theming.nixStylix scheme/wallpaper
rssh.enable, yubikey.enable, cachix.enable, latex.enablemodules/nixos/**Feature toggles for individual services

NAS behaviour follows the nas tag, and the TPM2 stack is driven by the upstream security.tpm2.enable (this flake just layers PKCS11/tooling on top).

New custom options should be namespaced (or documented here) so they stay distinguishable from upstream options.

Getting Started

Clone

git clone https://github.com/arunoruto/flake ~/.config/flake

The flake sets NH_FLAKE (used by nh) to ~/.config/flake automatically. If you clone elsewhere, override it:

export NH_FLAKE=/path/to/flake

Most day-to-day commands are wrapped in the justfile — run just --list from the repo root to see them.

NixOS

First-time install:

sudo nixos-rebuild switch --flake ~/.config/flake#<device-name> --accept-flake-config

After initial setup, use nh for convenience (see Daily Usage):

nh os switch ~/.config/flake#<device-name>

Darwin (macOS)

sudo nix run nix-darwin/nix-darwin-<version>#darwin-rebuild -- switch

Replace <version> with the nix-darwin release (e.g., 25.11).

Home Manager

On NixOS

home-manager switch --flake ~/.config/flake#<username> --accept-flake-config

Standalone (non-NixOS)

nix --experimental-features 'nix-command flakes' --accept-flake-config run nixpkgs#home-manager -- switch --flake ~/.config/flake#<username>

Shells like zsh require quoting: --flake './#<username>'

Directory layout

Your host config lives in systems/<arch>/<host>/. Home Manager profiles are in homes/<username>/. Add new ones following the existing patterns.

Building ISOs for NixOS Hosts

This flake supports building bootable ISOs that embed the flake source, so nixos-install --flake works against /etc/nixos/flake without network access to the flake repo.

ISOs are generated from a single generic module (systems/iso/installer.nix) parameterized by hostname.

Quick start

# Build ISO + .sha256 checksum sidecar (Ventoy-ready)
nix build .#iso-<hostname>

# Copy to USB (ISO + sidecar file)
cp -r result/iso/* /mnt/ventoy/

# Or write directly with dd
sudo dd if=result/iso/*.iso of=/dev/sdX bs=4M status=progress conv=fsync

## Adding a new ISO target

Append the hostname to the `isoHosts` list in `flake.nix`:

```nix
isoHosts = [ "shinji" "kenpachi" "zangetsu" ];

The generic installer.nix module:

  • Sets isoImage.edition = hostname (distinguishable filenames like nixos-shinji-25.11-x86_64-linux.iso)
  • Embeds the flake source at /nixos-flake → copied to /etc/nixos/flake at boot
  • Includes disko in the live Nix store
  • Prints MOTD instructions referencing the hostname
  • Provides an autoinstall systemd oneshot (triggers when autoinstall is in /proc/cmdline)

Install workflow

Manual (default)

  1. Boot from USB
  2. Login (root, no password)
  3. Follow the on-screen instructions:
sudo disko --mode disko --flake /etc/nixos/flake#<hostname>
sudo nixos-install --flake /etc/nixos/flake#<hostname> --root /mnt
sudo reboot

Autoinstall

Add autoinstall to the kernel command line at boot:

  1. In the GRUB menu, highlight the entry and press e
  2. Append autoinstall to the linux line
  3. Press Ctrl+x or F10 to boot

The system will automatically partition the disk (via disko), install NixOS, and reboot.

Example: shinji ISO

# Build ISO only
nix build .#nixosConfigurations.iso-shinji.config.system.build.isoImage

# Build ISO + checksums (recommended)
nix build .#nixosConfigurations.iso-shinji.config.system.build.isoChecksums

# Write to USB
sudo dd if=result/iso/*.iso of=/dev/sdX bs=4M status=progress conv=fsync

For Ventoy, copy result/iso/* directly — the .sha256 file will be auto-detected.

Prerequisites for a host to be ISO-installable

The target host must:

  • Use disko for disk partitioning (disk.nix importing inputs.disko.nixosModules.disko)
  • Have fileSystems in hardware-configuration.nix commented out — disko generates them declaratively
  • Include the block device kernel module in boot.initrd.availableKernelModules (e.g. "nvme", "ahci", "sd_mod")

How it works

systems/iso/installer.nix receives hostname via specialArgs and uses it to:

  • Set the ISO edition/volume label
  • Populate MOTD instructions and autoinstall commands dynamically
  • The flake source (self) is embedded as a raw copy on the ISO at /nixos-flake
  • At boot, postBootCommands copies it to /etc/nixos/flake where nixos-install --flake can find it

Verification

Build the ISO with an accompanying .sha256 checksum file for verification:

nix build .#nixosConfigurations.iso-<hostname>.config.system.build.isoChecksums

Output:

result/
├── iso/
│   ├── nixos-<hostname>-...iso
│   └── nixos-<hostname>-...iso.sha256
└── SHA256SUMS

The .sha256 file uses sha256sum format (hash filename). Copy result/iso/* to your USB stick.

Ventoy

Ventoy auto-detects .sha256 files placed next to the ISO. Select the ISO in the Ventoy boot menu, press m, choose SHA256 — it calculates and compares against the file, confirming the copy was not corrupted.

Manual verification

cd result/
sha256sum -c SHA256SUMS

Size considerations

  • The ISO includes the flake source closure, the live Nix store (squashfs), and disko
  • Typical size: ~1.4 GB depending on extra storeContents
  • Use isoImage.squashfsCompression = "zstd -Xcompression-level 19" (default) for best compression
  • Add isoImage.compressImage = true for an extra .zst layer (slower build, smaller file)

Generic minimal ISO

The flake also has a barebones ISO at systems/iso/default.nix that imports the standard installation-cd-minimal with helix added. Not registered as a nixosConfiguration — build it directly if needed.

Secrets Management (sops-nix)

All secrets in this flake are encrypted with sops using age as the backing encryption layer. sops-nix handles decryption at boot and materializes secrets into /run/secrets/ (NixOS) or ~/.config/sops/ (Home Manager).

How it works

secrets/secrets.yaml ──encrypted to──► 15 age public keys (.sops.yaml)
       │
       ▼ sops-nix (at boot)
  /run/secrets/<name>          (NixOS hosts)
  ~/.config/sops/<name>        (Home Manager / macOS)

Each host derives its age identity from its SSH host ed25519 key. The age public key is listed in .sops.yaml. At boot, sops-nix converts the host’s SSH private key to an age identity and decrypts the secrets.

NixOS hosts

Key generation at first boot

SSH host keys are generated by services.openssh.hostKeys (configured in modules/nixos/services/ssh.nix). The ed25519 key at /etc/ssh/ssh_host_ed25519_key is the one used by sops-nix.

sops-nix auto-converts this key to an age identity via generateKey = true and stores it at /var/lib/sops-nix/keys.txt. No manual key provisioning needed on the host — it “just works” after first boot.

Configuration (per host, implicit)

# modules/nixos/security/secrets.nix
sops = {
  defaultSopsFile = "${secretspath}/secrets.yaml";
  age = {
    sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
    keyFile = "/var/lib/sops-nix/keys.txt";
    generateKey = true;
  };
};

Using a secret in a host config

sops.secrets."tokens/beszel-marvin" = {
  mode = "0444";
};

Then reference it:

environment.KEY_FILE = config.sops.secrets."tokens/beszel-marvin".path;

Adding a new NixOS host to secrets

  1. Generate the age public key from the host’s SSH key:
ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub
# Output: age1...

If ssh-to-age isn’t available:

nix shell nixpkgs#ssh-to-age --command ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub
  1. Add the age public key to secrets/.sops.yaml under the host’s entry:
creation_rules:
  - path_regex: secrets.yaml$
    key_groups:
      - age:
        - age1...  # shinji
        - age1...  # kenpachi
        - age1...  # new-host  ← add here
  1. Re-encrypt the secrets file so the new host can decrypt it:
sops updatekeys secrets/secrets.yaml
  1. Commit the updated .sops.yaml and secrets.yaml. The new host can now decrypt secrets on its next boot.

Home Manager / macOS

User age key

Home Manager users decrypt secrets using their own age identity at ~/.config/sops/age/keys.txt (not an SSH host key). This file must be placed manually:

mkdir -p ~/.config/sops/age
# Copy your age identity (private key) here:
echo "AGE-SECRET-KEY-..." > ~/.config/sops/age/keys.txt
chmod 600 ~/.config/sops/age/keys.txt

Bootstrap: user SSH key from secrets

The user’s SSH private key (~/.ssh/id_ed25519) is itself stored in secrets.yaml and decrypted at Home Manager activation. This works because the user’s age key (e.g. mirza) is separately listed in .sops.yaml and can decrypt the SSH key secret.

# modules/home-manager/background/secrets.nix
sops.secrets."ssh_keys/${config.user}" = {
  path = "${config.home.homeDirectory}/.ssh/id_ed25519";
};

The user’s age key (for sops CLI use) is separate from the SSH key (for git/SSH access).

Editing secrets

# Decrypt, edit in $EDITOR, re-encrypt
sops secrets/secrets.yaml

To add a new secret entry:

# secrets/secrets.yaml
my-new-token: "sk-abc123..."

Then reference it in your Nix config:

sops.secrets."my-new-token".path = "/run/secrets/my-token";

Key hierarchy

KeySourceUsed by
Host age keys (shinji, kenpachi, …)/etc/ssh/ssh_host_ed25519_key → agesops-nix decryption on that host
User age keys (mirza, mar)Manually generated with age-keygensops CLI for editing secrets
User SSH keysDecrypted from secrets.yaml by Home ManagerGit push, SSH access, etc.
SSH host keysGenerated at first boot by services.openssh.hostKeysSSH server identity + age identity source

Common commands

# Edit secrets
sops secrets/secrets.yaml

# Re-encrypt after adding/removing recipients
sops updatekeys secrets/secrets.yaml

# Check which keys can decrypt
sops --decrypt secrets/secrets.yaml > /dev/null && echo "OK"

# List recipients
grep age secrets/.sops.yaml

# Convert SSH key to age
ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub

# Generate a new age key (for users)
age-keygen -o ~/.config/sops/age/keys.txt

Determinate Nix

Determinate Nix is Determinate Systems’ downstream distribution of Nix (flakes enabled by default, lazy-trees, its own determinate-nixd daemon). This flake used to run it on every host; it has since been removed in favour of the stock Nix that ships with nixpkgs.

This page documents how it was wired in so it can be re-enabled if ever needed — and the one gotcha (source rebuilds) that made it painful.

Why it was removed

The determinate module pins a specific determinate-nix-<version> build. That build is published as a binary on the FlakeHub cache, but this flake never listed https://cache.flakehub.com as a substituter — only its public key was present (see the gotcha below). So every version bump rebuilt Determinate Nix (and its boost etc. dependencies) from source during nh os switch, which was slow enough to not be worth it. Stock Nix already covers everything this config needs (flakes, nix-command, pipe-operators are enabled in modules/nixos/system/nix-utils.nix and modules/darwin/system/nix.nix, independent of Determinate).

How to re-enable it

Three edits, then rebuild:

  1. Add the flake input (flake.nix):

    determinate.url = "https://flakehub.com/f/DeterminateSystems/determinate/*";
    
  2. Import the module for the relevant platform (systems/default.nix) — it lives in the nixosModules / darwinModules list:

    # in nixosModules
    determinate.nixosModules.default
    # in darwinModules
    determinate.darwinModules.default
    
  3. Add the FlakeHub cache substituter (flake.nixnixConfig). This is the important one — without it, Determinate Nix builds from source:

    extra-substituters = [
      # …
      "https://cache.flakehub.com"
    ];
    extra-trusted-public-keys = [
      # …
      "cache.flakehub.com-3:hJuILl5sVK4iKm86JzgdXW12Y2Hwd5G07qKtHTOcDCM="
    ];
    

Then just switch (NixOS) / just switch on the darwin host.

The gotcha: install.determinate.systems is the installer host, not a binary cache. The Determinate Nix binaries live on cache.flakehub.com. If you re-add the module but forget the substituter, you’ll compile Nix from source on every lockfile bump — the exact reason it was removed.

Platform notes

NixOS

The determinate.nixosModules.default module sets nix.package to the Determinate build and hands daemon management to determinate-nixd. Nothing else in the config depends on it — nix-command/flakes/pipe-operators come from modules/nixos/system/nix-utils.nix, so removing Determinate does not disable flakes.

darwin (tensa)

On darwin the module sets nix.enable = false, telling nix-darwin not to manage Nix (Determinate manages it out-of-band via determinate-nixd). It also consumes a determinateNix.customSettings option to push the shared settings into Determinate’s config.

If you run darwin on stock Nix instead, nix.enable must be true so nix-darwin manages the daemon — otherwise nothing configures Nix on that host. modules/darwin/system/nix.nix is where both live.

Storage

Filesystems at a glance

FSUse in this flakeBest for
ext4the default root filesystem for most hostsSimplicity, zero maintenance
btrfsroot on shinji, yhwach, kyuubiCompression, snapshots
zfsdata pools only (sado, kuchiki)Large storage, checksums
vfatEvery host with /boot (EFI)EFI system partition

Host → filesystem mapping

HostRootDataManaged by
shinjibtrfs (@root + @nix)disko
yhwachbtrfs (subvol=@)hardware-config
kyuubibtrfs (subvol=@)hardware-config
sadoext4zfs (/mnt/flash)hardware-config
kuchikiext4zfs (/mnt/storage)hardware-config
kenpachiext4 (LVM)disko
aizenext4 (LVM)disko
all othersext4hardware-config

Choosing a filesystem for a new host

  • ext4 — the default. Simple, proven, zero configuration. Used on most hosts.
  • btrfs — when you want transparent zstd compression (saves ~25% on /nix/store) or snapshot support. Use the @root + @nix subvolume layout to keep snapshots lightweight. See btrfs.md for details.
  • zfs — only for dedicated data pools that benefit from checksums, dedup, or RAID-Z. Do not use for root: the out-of-tree kernel module frequently breaks on kernel updates.

Disko

Disko provides declarative disk partitioning. Instead of manually running fdisk, mkfs, and recording UUIDs in hardware-configuration.nix, you define everything in a disk.nix:

  • Partition layout (BIOS boot, ESP, root)
  • Filesystem type (ext4, btrfs, zfs)
  • Subvolume layout for btrfs
  • LVM volumes if needed

Disko is imported per-host via inputs.disko.nixosModules.disko in the host’s disk.nix. A few hosts use it (shinji, kenpachi, aizen); the rest use a manually-generated hardware-configuration.nix with explicit fileSystems entries.

When disko manages the filesystems, the fileSystems entries in hardware-configuration.nix should be commented out — disko generates them declaratively at build time.

Example: shinji

# systems/x86_64-linux/shinji/default.nix
{ inputs, ... }: {
  imports = [
    ./configuration.nix
    ./disk.nix              # disko: btrfs on NVMe with @root + @nix subvolumes
    ./hardware-configuration.nix  # fileSystems commented out, disko handles them
  ];
}

See btrfs.md for a complete disko + btrfs walkthrough.

Btrfs on NixOS

Why btrfs

FeatureBenefit on NixOS
zstd compression20-30% space saved on /nix/store transparently
SubvolumesSeparate / and /nix — snapshot root without bloating snapshots with store data
SnapshotsRoll back a bad nixos-rebuild in seconds
Native kernelNo out-of-tree module — works on every kernel update (unlike ZFS)

Compared to ext4: same simplicity, more features. Compared to ZFS: fewer features but zero maintenance overhead.

Layout used in this flake

Two subvolumes on a single btrfs partition:

/dev/<disk> (btrfs)
├── @root  → /        compress=zstd
└── @nix   → /nix     compress=zstd,noatime
  • @root: the OS, your home, /etc — everything except the Nix store.
  • @nix: the Nix store only. Mounted with noatime to reduce metadata writes during package operations.
  • Why separate? Snapshots of / don’t capture /nix/store, keeping them small. Restoring / from a snapshot doesn’t touch the store.

Disko configuration

The flake uses disko for declarative partitioning. Here’s a minimal btrfs layout:

{ inputs, lib, ... }:
{
  imports = [ inputs.disko.nixosModules.disko ];

  disko.devices = {
    disk.main = {
      device = lib.mkDefault "/dev/nvme0n1";
      type = "disk";
      content = {
        type = "gpt";
        partitions = {
          boot = {
            size = "1M";
            type = "EF02";
          };
          esp = {
            size = "512M";
            type = "EF00";
            content = {
              type = "filesystem";
              format = "vfat";
              mountpoint = "/boot";
            };
          };
          root = {
            size = "100%";
            content = {
              type = "btrfs";
              extraArgs = [ "-f" ];
              subvolumes = {
                "@root" = {
                  mountpoint = "/";
                  mountOptions = [ "compress=zstd" ];
                };
                "@nix" = {
                  mountpoint = "/nix";
                  mountOptions = [
                    "compress=zstd"
                    "noatime"
                  ];
                };
              };
            };
          };
        };
      };
    };
  };
}

See systems/x86_64-linux/shinji/disk.nix for a real example.

Maintenance

Check filesystem usage

btrfs filesystem usage /
btrfs filesystem df /

Scrub (data integrity check)

Run occasionally to detect bit rot or disk errors:

sudo btrfs scrub start /
sudo btrfs scrub status /

Balance

Only needed when adding/removing drives or after heavy usage patterns. Not routine:

sudo btrfs balance start -dusage=50 /

Compression stats

See how much space compression saves:

sudo compsize /nix/store

Snapshots

Manual snapshot before a risky rebuild

sudo btrfs subvolume snapshot -r / /snapshots/root-$(date -I)

Roll back to a snapshot

# Boot from a live USB, mount the btrfs volume
sudo mount -o subvol=/ /dev/<disk> /mnt
sudo mv /mnt/@root /mnt/@root-broken
sudo btrfs subvolume snapshot /mnt/snapshots/root-2026-01-01 /mnt/@root
reboot

Delete old snapshots

sudo btrfs subvolume delete /snapshots/root-2025-12-01

Recovery

Mount subvolumes from a live USB

sudo mount /dev/<device> /mnt
# The default subvolume mounts automatically
# Access subvolumes:
ls /mnt/@root
ls /mnt/@nix

Mount a specific subvolume for chroot repair

sudo mount -o subvol=@root,compress=zstd /dev/<device> /mnt
sudo mount -o subvol=@nix,compress=zstd /dev/<device> /mnt/nix
sudo mount /dev/<esp> /mnt/boot
sudo nixos-enter

Filesystem creation (manual, without disko)

If you need to set up btrfs manually instead of using disko:

mkfs.btrfs -f /dev/<partition>
mount /dev/<partition> /mnt
btrfs subvolume create /mnt/@root
btrfs subvolume create /mnt/@nix
umount /mnt
mount -o subvol=@root,compress=zstd /dev/<partition> /mnt
mkdir -p /mnt/nix
mount -o subvol=@nix,compress=zstd,noatime /dev/<partition> /mnt/nix

ZFS on NixOS

Why ZFS for data pools

FeatureBenefit
ChecksumsDetects and repairs bit rot on every read
SnapshotsInstant, zero-overhead point-in-time copies
Dataset propertiesCompression, recordsize, etc. per dataset — no chattr hacks
RAID-ZRedundancy without a hardware RAID controller
Send/ReceiveEfficient backup and replication

Why NOT for root

  • Out-of-tree kernel module — ZFS frequently breaks when the kernel updates. On NixOS with boot.kernelPackages = linuxPackages_latest, this is a recurring headache.
  • Boot complexity — requires ZFSBootMenu or a separate /boot + manual pool import in initrd.
  • This flake’s convention — ext4 or btrfs for root, ZFS exclusively for data pools (/mnt/flash, /mnt/storage).

Pool structure in this flake

sado — flash pool

flash
├── flash/appdata       → /mnt/flash/appdata    (immich, paperless, komga configs)
├── flash/photos        → /mnt/flash/photos
├── flash/documents     → /mnt/flash/documents
└── flash/books         → /mnt/flash/books

Source: systems/x86_64-linux/sado/hardware-configuration.nix

kuchiki — storage pool

storage
├── storage/appdata     → /mnt/storage/appdata   (media service configs)
├── storage/downloads   → /mnt/storage/downloads
└── storage/media       → /mnt/storage/media

Source: systems/x86_64-linux/kuchiki/hardware-configuration.nix

Both hosts use hosts.zfs.enable = true (shared module at modules/nixos/system/zfs.nix) and systemd.services.zfs-mount.enable = false (mount via NixOS fileSystems declarations instead).

Creating a pool

Single disk — no redundancy

zpool create tank /dev/sda

Mirror — survives 1 disk failure

zpool create tank mirror /dev/sda /dev/sdb

Good for: root filesystem (if you must), appdata where uptime matters.

RAID-Z — 1 disk parity, minimum 3 disks

zpool create tank raidz /dev/sda /dev/sdb /dev/sdc

Good for: media storage where capacity > performance.

RAID-Z2 — 2 disk parity, minimum 4 disks

zpool create tank raidz2 /dev/sda /dev/sdb /dev/sdc /dev/sdd

Good for: large arrays where rebuild time is a concern.

Ashift — always set for modern drives

4K sector drives (all SSDs and most HDDs since ~2011) need ashift=12:

zpool create -o ashift=12 tank mirror /dev/sda /dev/sdb

Without it: write amplification and performance degradation on 4K-native drives.

Adding to NixOS config

After creating pools/datasets imperatively, declare them in hardware-configuration.nix so NixOS mounts them at boot:

fileSystems."/mnt/tank" = {
  device = "tank";
  fsType = "zfs";
};

fileSystems."/mnt/tank/media" = {
  device = "tank/media";
  fsType = "zfs";
};

Datasets

Creating

zfs create tank/appdata
zfs create tank/media

# Custom mountpoint
zfs create -o mountpoint=/custom/path tank/custom
PropertyValueWhy
compressionlz4 or zstdFree space savings, negligible CPU cost. lz4 for speed, zstd for higher compression.
recordsize1M (media) / 128K (general) / 16K (databases)Match workload I/O patterns.
atimeoffEliminates metadata writes on every read access.
xattrsaStore extended attributes in dnodes instead of hidden files — big speedup.
acltypeposixPOSIX ACLs; enables nfs4 if you need that.
aclinheritpassthroughInherit ACLs from parent if using ACLs.
dedupoffKeep it off — RAM consumption is enormous.

Media dataset — large sequential files

zfs set compression=zstd recordsize=1M atime=off tank/media

Appdata dataset — small random I/O (databases, configs)

zfs set compression=lz4 recordsize=128K atime=off xattr=sa tank/appdata

Downloads dataset — mixed, discard-friendly

zfs set compression=zstd recordsize=1M atime=off tank/downloads

Snapshots

Manual

zfs snapshot tank/media@backup-$(date -I)
zfs list -t snapshot

Automatic (zfs-auto-snapshot)

services.zfs.autoSnapshot = {
  enable = true;
  frequent = 4;   # keep 4 quarter-hourly snapshots
  hourly = 24;
  daily = 7;
  weekly = 4;
  monthly = 6;
};

Rollback

zfs rollback tank/media@backup-2026-01-01

# For older snapshots (destroys intermediate snapshots):
zfs rollback -r tank/media@backup-2025-12-01

Access files from a snapshot without rollback

Snapshots are mounted read-only under /.zfs/snapshot/<name>/:

ls /mnt/tank/media/.zfs/snapshot/backup-2026-01-01/
cp /mnt/tank/media/.zfs/snapshot/backup-2026-01-01/deleted-file.txt .

Maintenance

Scrubbing — data integrity check

zpool scrub tank
zpool status tank    # watch progress

This flake enables auto-scrub in modules/nixos/system/zfs.nix:

services.zfs.autoScrub = {
  enable = true;
  interval = "*-*-1,15 02:30";   # 1st and 15th of every month at 2:30 AM
};

Pool and dataset status

zpool status              # health, errors, scrub progress
zpool list                # space per pool
zfs list                  # space per dataset
zfs list -t snapshot      # list all snapshots
zfs get all tank/appdata  # all properties of a dataset

Replacing a failed disk

# After physically swapping the disk:
zpool replace tank /dev/sdb /dev/sdc
zpool status tank         # wait for resilver

Destroying a pool

zpool destroy tank
# If pool claims to be busy:
zpool destroy -f tank

Adding ZFS to a new host

  1. Enable the shared ZFS module:
hosts.zfs.enable = true;
  1. Set a host ID (required — pick a random hex string):
networking.hostId = "a1b2c3d4";
  1. Disable automatic zfs-mount service (NixOS handles mounting via fileSystems):
systemd.services.zfs-mount.enable = false;
  1. Declare datasets in hardware-configuration.nix:
fileSystems."/mnt/tank" = {
  device = "tank";
  fsType = "zfs";
};
fileSystems."/mnt/tank/appdata" = {
  device = "tank/appdata";
  fsType = "zfs";
};

See systems/x86_64-linux/sado/ and systems/x86_64-linux/kuchiki/ for working examples.

devix

Stylix, but for development environments.

Stylix lets you declare a colour scheme once and have every program that understands theming configure itself from it. devix does the same thing for development tooling: you describe a language once — its language servers, its formatters, how it should be indented — and every editor that understands the description configures itself from it.

The problem it solves is duplication. Setting up Rust in Helix means writing a languages.toml stanza. Setting up the same Rust in Zed means writing a different stanza in settings.json. Doing it for an AI harness like OpenCode means a third format. Three files, three syntaxes, one fact — which is exactly the kind of thing Nix is supposed to abolish.

devix = {
  enable = true;
  languages.rust.enable = true;
};

programs.helix.enable = true;
programs.zed-editor.enable = true;

That is the whole configuration. Both editors get rust-analyzer wired up with rustfmt on save and the right indentation, because both of them consume the same description.

Why editors are not the only consumers

Language servers used to be an editor concern. They are not anymore — coding agents such as OpenCode and Claude Code benefit from exactly the same information, because “which LSP understands this file, and what formats it” is a fact about the project, not about the program looking at it.

devix calls anything that consumes the description a consumer. An editor is a consumer. An AI harness is a consumer. Adding a new one does not require touching a single language definition.

Where to go next

Status

devix currently lives inside this flake as modules/devix, and is exported as homeModules.devix and devenvModules.*. It has no dependency on the rest of the configuration: the language definitions use plain nixpkgs, so the module works against a stock home-manager setup. If it outgrows this repository it can move out as-is.

Concepts

devix is built from four pieces. Three of them are things you write; the fourth is the machinery that connects them.

languages/<lang>.nix   pure data: lsps, formatters, indentation, consumerMeta
addons/<addon>.nix     server groups that attach to languages (grammar, ai)
        │
        ▼
devix.lsps / devix.formatters             shared registries
devix.languages.<lang> / .addons.<addon>  what is on
        │
        ▼
consumers/registry.nix   applies exposure + capability, resolves per consumer
        │
        ├─ consumers/helix/    → programs.helix.languages
        ├─ consumers/zed/      → programs.zed-editor.userSettings
        └─ consumers/opencode/ → programs.opencode.settings

Languages

A language is one file in modules/devix/languages/, and it is pure data — no conditionals, no references to your configuration:

{ lib, pkgs }:
{
  lsps.tinymist = {
    enable = true;
    package = pkgs.tinymist;
  };

  formatters.typstyle = {
    enable = true;
    package = pkgs.typstyle;
  };

  language = {
    lspServers = [ "tinymist" ];
    formatters = [ "typstyle" ];
    tabWidth = 2;
    insertSpaces = true;
  };

  consumerMeta.zed = {
    name = "Typst";
    extensions = [ "typst" ];
    languageServers = [ "tinymist" "..." ];
  };

  consumerMeta.opencode.extensions = [ ".typ" ];
}

Adding a file to that directory is all it takes — the directory is scanned, and each file becomes a devix.languages.<name> option. There is no list to update.

Registries

Notice that the language above refers to its server as the string "tinymist", not as the definition directly. Server and formatter definitions go into two shared registries, devix.lsps and devix.formatters, and languages reference them by name.

That indirection is what makes overrides work in one place:

devix.lsps.pyright.config.python.analysis.typeCheckingMode = "basic";

Every consumer that uses pyright now uses that setting. If each language embedded its servers directly, you would be overriding the same thing once per editor — the duplication devix exists to remove.

A server’s command is derived from its package, so swapping a build is one line and every consumer follows:

devix.lsps.nixd.package = pkgs.unstable.nixd;

Addons

Some servers are not tied to a language. Spell and grammar checking applies to prose formats; AI completion applies to everything. Making them languages would be a lie — and would leak a phantom “grammar” entry into your editor’s language list.

An addon is a group of servers plus the languages it attaches to:

{
  description = "spelling, grammar and style checking";
  lsps = { ltex = { ... }; codebook = { ... }; harper = { ... }; };
  lspServers = [ "ltex" "codebook" ];      # attached
  languages = [ "markdown" "latex" "typst" ];  # "*" for everything
}

Enabling it appends those servers to the languages named, wherever they are enabled. Nothing appears in an editor as a language of its own.

Consumers

A consumer is anything that reads the description and configures itself: an editor, an AI harness. Each is one directory under modules/devix/consumers/, containing what it is (default.nix), a pure transform into its config format (transform.nix), and one adapter per target (home.nix, optionally devenv.nix).

Consumers attach themselves the way Stylix targets do — enabling the program is enough:

devix.consumers.<name>.enable   # defaults to
  devix.autoEnable && programs.<editor>.enable

The two rules

Exactly two things decide what a given consumer sees, and both are applied in one place (consumers/registry.nix) rather than by each adapter.

Exposure — every language, addon, server and formatter carries a consumers.<name>.enable toggle, defaulting to true. This is how you say “markdown’s grammar servers everywhere, except in Zed”.

Capability — what a consumer can handle at all. Each consumer declares one of two models:

capabilityMeaningExample
"all"Configures languages generically; handles anything devix definesHelix
"meta"Only covers languages carrying consumerMeta.<name>Zed, OpenCode

Zed addresses languages by its own display name and curates its own server list, so it cannot configure a language that has not told it how. OpenCode attaches servers by file extension, so it needs to know the extensions. Helix needs neither, so it takes everything.

A "meta" consumer also declares metaOptions, which types its slice of consumerMeta. A typo or a wrong type in a language’s metadata is a build error rather than something silently ignored.

The support matrix shows the result of these rules across every language currently defined.

Mechanism and policy

devix itself enables nothing. It defines what a language is and how each consumer should be configured — the mechanism. Deciding that Rust should be on for development machines is policy, and in this flake it lives in modules/home-manager/development/. Keeping the two apart is what lets devix be lifted out of this repository unchanged.

Usage

Getting started

devix is a Home Manager module. Import it, turn it on, and enable the languages you want:

{
  imports = [ inputs.flake.homeModules.devix ];

  devix = {
    enable = true;
    defaultEditor = "helix";
    languages = {
      nix.enable = true;
      python.enable = true;
      rust.enable = true;
    };
  };

  programs.helix.enable = true;
}

Enabling the editor is all that is needed for devix to configure it — devix.consumers.helix.enable defaults to devix.autoEnable && programs.helix.enable. Set devix.autoEnable = false if you would rather opt each consumer in by hand.

defaultEditor sets EDITOR and VISUAL. Only consumers that are actual editors are candidates; an AI harness like OpenCode is not offered.

The language servers and formatters a language references are installed for you — there is no separate home.packages entry to maintain.

Adding an addon

devix.addons.grammar.enable = true;

This attaches ltex and codebook to markdown, LaTeX and Typst wherever those are enabled. To change what it attaches or where:

devix.addons.grammar = {
  enable = true;
  lspServers = [ "codebook" ];          # drop ltex, it is heavy
  languages = [ "markdown" "typst" ];   # leave LaTeX alone
};

Overriding a server

Servers live in a shared registry, so an override applies to every consumer at once. Change its settings:

devix.lsps.pyright.config.python.analysis.typeCheckingMode = "basic";

Change which build is used — command follows package, so this is enough:

devix.lsps.nixd.package = pkgs.unstable.nixd;

Turn one off everywhere without touching the language:

devix.lsps.markdown-oxide.enable = false;

Turning things off per editor

Every language, addon, server and formatter has a per-consumer toggle. They all default to enabled, so you only write the exceptions.

# Zed has good built-in Markdown support; keep devix out of it
devix.languages.markdown.consumers.zed.enable = false;

# Grammar servers are useful in the editor, noise in the AI harness
devix.addons.grammar.consumers.opencode.enable = false;

# One server, one editor
devix.lsps.ltex.consumers.zed.enable = false;

Note the difference between this and devix.lsps.<name>.enable = false: the latter switches the server off everywhere, the former only hides it from one consumer.

Changing a language’s servers

lspServers and formatters are lists of registry keys, so you can reorder, extend or replace them:

devix.languages.python = {
  enable = true;
  lspServers = [ "pyright" "ruff" ];   # add a second server
  formatters = [ "ruff-format" ];      # drop the import-sorting pass
};

Referencing a name that no registry entry defines is caught with a clear message rather than an obscure evaluation failure:

devix.languages / devix.addons reference unknown LSPs: ruff

Migrating from development.*

Options used to live under development.*, and autoEnable used to be called autoConfigureEditors. The old names still work and warn:

The option `development.languages.rust' has been renamed to `devix.languages.rust'.

The aliases live in modules/devix/core/renames.nix and can be deleted once nothing refers to the old paths.

Adding a language

Create one file in modules/devix/languages/. The directory is scanned, so there is no list to update and no module to write — the file becomes a devix.languages.<name> option automatically, named after the file.

The shape

# modules/devix/languages/zig.nix
{ lib, pkgs }:

{
  description = "Zig development environment";

  lsps.zls = {
    enable = true;
    package = pkgs.zls;
  };

  formatters.zig-fmt = {
    enable = true;
    package = pkgs.zig;
    command = lib.getExe' pkgs.zig "zig";
    args = [ "fmt" "--stdin" ];
  };

  language = {
    lspServers = [ "zls" ];
    formatters = [ "zig-fmt" ];
    tabWidth = 4;
    insertSpaces = true;
    roots = [ "build.zig" ];
  };

  consumerMeta.zed = {
    name = "Zig";
    extensions = [ "zig" ];
    languageServers = [ "zls" "..." ];
  };

  consumerMeta.opencode.extensions = [ ".zig" ];
}

That is the entire change. devix.languages.zig now exists, defaulted from this file, and every consumer picks it up.

Field by field

description — optional; shown in the generated option reference.

lsps / formatters — definitions that go into the shared registries. command is derived from package, so you normally omit it. Set it explicitly only when the binary is not the package’s main program, as with the lib.getExe' call above.

language.lspServers / language.formatters — which registry entries this language uses, by name. A language may define more than it uses; the extras stay available for users to opt into. Multiple formatters are piped in order.

language.roots — files that mark a project root, for consumers that support the notion.

consumerMeta.<consumer> — how a "meta" consumer should handle this language. Omit it and that consumer simply skips the language. The shape is typed by each consumer’s metaOptions, so mistakes fail the build:

  • zedname is Zed’s display name and becomes the settings key. languageServers is a curated, ordered list; the literal "..." means “then Zed’s own defaults”. Omitting a devix server here is how you let Zed use its built-in support instead.
  • opencodeextensions are the file extensions, with leading dots.

Helix needs no metadata: it declares capability = "all" and configures languages generically.

Rules

Use plain pkgs. Language files must not reference this flake’s overlays — no pkgs.unstable, no pkgs.custom. devix is exported as a standalone module and has to evaluate against stock nixpkgs. “Use the unstable build” is a policy decision and belongs in modules/home-manager/development/:

devix.lsps.zls.package = pkgs.unstable.zls;

Do not enable anything. A language file describes; it never decides. Turning zig on for development machines is policy.

Keep it data. No config, no lib.mkIf, no reading the user’s settings. The file receives lib and pkgs, and returns an attribute set.

Checking your work

# does everything still evaluate?
nix eval .#homeConfigurations.<user>.activationPackage.drvPath

# what did the consumers make of it?
nix eval .#homeConfigurations.<user>.config.programs.helix.languages --json | jq

# rebuild the generated reference and matrix
nix build .#docs-devix-reference && cat result/support-matrix.md

Your language should appear in the support matrix with a mark under each consumer that covers it.

Adding an editor

A consumer is one directory under modules/devix/consumers/. The directory is discovered automatically, and everything derived from it — the consumer list, the per-item exposure toggles, the defaultEditor candidates, the EDITOR/VISUAL map, the adapter lists both targets assemble from — follows without you editing anything else.

consumers/<name>/
  default.nix    what this consumer is (the registry entry)
  transform.nix  pure: resolved languages -> that tool's config format
  home.nix       Home Manager adapter
  devenv.nix     devenv adapter (optional)

1. The registry entry

# consumers/kakoune/default.nix
{
  description = "Kakoune text editor";

  # "all"  — configures languages generically, needs no per-language metadata
  # "meta" — only covers languages carrying consumerMeta.kakoune
  capability = "meta";

  # Types the `consumerMeta.kakoune` block in each language file. Required for
  # "meta" consumers; null for "all".
  metaOptions = lib: {
    filetypes = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ ];
      description = "Kakoune filetype names for this language.";
    };
  };

  # When should this consumer switch itself on?
  activeWhen = config: config.programs.kakoune.enable or false;

  # Command for EDITOR/VISUAL, or null if this is not an interactive editor.
  editorCommand = "kak";

  home = ./home.nix;
  devenv = null;
}

Declaring capability = "meta" without metaOptions is rejected at evaluation time, so the two cannot drift apart.

2. The transform

Keep this pure — it takes resolved languages and returns the tool’s config. Being a plain function of lib makes it easy to reason about and to reuse across targets.

# consumers/kakoune/transform.nix
{ lib }:
let
  toKakoune = name: language: { ... };
in
{
  toKakouneConfig = languages: lib.mapAttrs toKakoune languages;
}

Languages arrive already filtered and resolved: only those enabled, exposed to you, and supported by your capability model, with their server and formatter lists already narrowed and the registry entries attached as lsps and formatterConfigs. Do not re-implement that filtering — it lives in consumers/registry.nix precisely so every consumer agrees.

3. The adapter

# consumers/kakoune/home.nix
{ config, lib, ... }:

let
  consumers = import ../registry.nix { inherit lib; };
  kakouneLib = import ./transform.nix { inherit lib; };

  cfg = config.devix;
  languages = consumers.languagesFor "kakoune" cfg.languages;
  resolved = consumers.resolveForConsumer "kakoune" cfg languages;
in
{
  config = lib.mkIf (cfg.enable && cfg.consumers.kakoune.enable && languages != { }) {
    programs.kakoune.settings = kakouneLib.toKakouneConfig resolved;
  };
}

The adapter does not need to enable itself — targets/home/auto-enable.nix derives that from your activeWhen for every consumer at once.

4. Teach the languages about it

For a "meta" consumer, add a consumerMeta.kakoune block to each language it should cover. Languages without one are skipped, which is a perfectly good resting state — support can grow language by language, and the support matrix shows the coverage at a glance.

Checking your work

nix eval --impure --expr '
  let lib = (import <nixpkgs> {}).lib;
  in (import ./modules/devix/consumers/registry.nix { inherit lib; }).names'

nix eval .#homeConfigurations.<user>.config.programs.kakoune.settings --json | jq

Your consumer should appear in names, gain a column in the support matrix, and show up as a toggle on every language, addon, server and formatter.

Support matrix

Generated from the language and addon definitions in modules/devix, so it cannot drift from the code.

Languages

A consumer whose capability is "all" configures every language generically. One with capability = "meta" only covers languages that carry metadata for it — the marks below show the Zed language name and the OpenCode file extensions that metadata provides.

LanguageLanguage serversFormattershelixopencodezed
bashshfmt.sh .bash✅ Shell Script
fishfish-lspfish-indent.fish✅ Fish
fortranfortlsfprettify.f90 .f95 .f03 .f .for
gogopls, golangci-lint-langservergofmt.go✅ Go
jsonvscode-json-languageserverprettier-json.json .jsonc✅ JSON
juliajulia-ls.jl
latextexlab.tex .sty .cls✅ LaTeX
markdownmarksman, markdown-oxide, iweprettier-markdown.md .markdown✅ Markdown
matlabmatlab-ls.m
nixnixd, nilnixfmt.nix✅ Nix
nunufmt.nu✅ Nu
pythonpyrightruff-check, ruff-format.py .pyi✅ Python
rustrust-analyzerrustfmt.rs✅ Rust
tomltaplotaplo-fmt.toml✅ TOML
typsttinymisttypstyle.typ✅ Typst
xmllemminx.xml✅ XML
yamlyaml-lspyamlfmt.yaml .yml✅ YAML

Consumer capabilities: helix all, opencode meta, zed meta.

Addons

AddonAttached by defaultAvailable, not attachedAttaches to
aicopilot, lsp-aievery enabled language
grammarltex, codebookharpermarkdown, latex, typst

A server in the Available, not attached column is defined in the registry but stays inactive until you add it to that addon’s lspServers.

Core options

The top-level switches: whether devix is active, how consumers attach themselves, and which editor becomes EDITOR.

devix.enable

Whether to let devix configure development tooling. When off, the language and addon definitions are still available as options but no editor is configured and no language server is installed.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.autoEnable

Master auto-enable for consumers, analogous to Stylix’s stylix.autoEnable. When true, each consumer defaults to active whenever its program is enabled (devix.consumers.<name>.enable defaults to programs.<editor>.enable). Set to false to opt out of automatic per-consumer enabling; you can still force an individual consumer on via devix.consumers.<name>.enable = true.

Type: boolean

Default:

true

Declared by:

devix.consumers

Active editor/program consumers of the development configuration.

Type: submodule

Default:

{ }

Declared by:

devix.consumers.helix

Activation state for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.consumers.helix.enable

Whether the helix consumer (Helix text editor) is active. This defaults to the consumer’s own programs.*.enable; set it explicitly to force a consumer on or off regardless of the program.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.consumers.opencode

Activation state for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.consumers.opencode.enable

Whether the opencode consumer (OpenCode AI coding agent) is active. This defaults to the consumer’s own programs.*.enable; set it explicitly to force a consumer on or off regardless of the program.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.consumers.zed

Activation state for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.consumers.zed.enable

Whether the zed consumer (Zed editor) is active. This defaults to the consumer’s own programs.*.enable; set it explicitly to force a consumer on or off regardless of the program.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.defaultEditor

Preferred editor for EDITOR/VISUAL and future default-app integrations. The candidates are the consumers that declare an editorCommand. Generated editor configuration is controlled by programs.<editor>.enable.

Type: null or one of “helix”, “zed”

Default:

null

Declared by:

Language options

One entry per file in modules/devix/languages/. Everything except enable is defaulted from that file, so you only need to override what you want to change.

devix.languages.bash

Settings for bash (bash development environment). Every value below is defaulted from modules/devix/languages/bash.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.bash.enable

Whether to enable bash development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.bash.consumerMeta

Per-consumer metadata for bash, defaulted from languages/bash.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.bash.consumerMeta.opencode

How the opencode consumer handles bash. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".sh"
    ".bash"
  ];
}

Declared by:

devix.languages.bash.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.bash.consumerMeta.zed

How the zed consumer handles bash. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "..."
  ];
  name = "Shell Script";
}

Declared by:

devix.languages.bash.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.bash.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.bash.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.bash.consumers

Per-consumer exposure for the bash language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip bash in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.bash.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.bash.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.bash.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.bash.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.bash.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.bash.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.bash.formatters

Formatters (keys into devix.formatters) used for bash.

Type: list of string

Default:

[
  "shfmt"
]

Declared by:

devix.languages.bash.lspServers

Language servers (keys into devix.lsps) used for bash.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.fish

Settings for fish (fish development environment). Every value below is defaulted from modules/devix/languages/fish.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fish.enable

Whether to enable fish development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.fish.consumerMeta

Per-consumer metadata for fish, defaulted from languages/fish.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.fish.consumerMeta.opencode

How the opencode consumer handles fish. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".fish"
  ];
}

Declared by:

devix.languages.fish.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.fish.consumerMeta.zed

How the zed consumer handles fish. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    "fish"
  ];
  languageServers = [
    "fish-lsp"
    "..."
  ];
  name = "Fish";
}

Declared by:

devix.languages.fish.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.fish.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.fish.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.fish.consumers

Per-consumer exposure for the fish language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip fish in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fish.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fish.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.fish.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fish.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.fish.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fish.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.fish.formatters

Formatters (keys into devix.formatters) used for fish.

Type: list of string

Default:

[
  "fish-indent"
]

Declared by:

devix.languages.fish.lspServers

Language servers (keys into devix.lsps) used for fish.

Type: list of string

Default:

[
  "fish-lsp"
]

Declared by:

devix.languages.fortran

Settings for fortran (fortran development environment). Every value below is defaulted from modules/devix/languages/fortran.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fortran.enable

Whether to enable fortran development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.fortran.consumerMeta

Per-consumer metadata for fortran, defaulted from languages/fortran.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.fortran.consumerMeta.opencode

How the opencode consumer handles fortran. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".f90"
    ".f95"
    ".f03"
    ".f"
    ".for"
  ];
}

Declared by:

devix.languages.fortran.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.fortran.consumerMeta.zed

How the zed consumer handles fortran. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

null

Declared by:

devix.languages.fortran.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.fortran.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.fortran.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.fortran.consumers

Per-consumer exposure for the fortran language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip fortran in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fortran.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fortran.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.fortran.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fortran.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.fortran.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.fortran.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.fortran.formatters

Formatters (keys into devix.formatters) used for fortran.

Type: list of string

Default:

[
  "fprettify"
]

Declared by:

devix.languages.fortran.lspServers

Language servers (keys into devix.lsps) used for fortran.

Type: list of string

Default:

[
  "fortls"
]

Declared by:

devix.languages.go

Settings for go (go development environment). Every value below is defaulted from modules/devix/languages/go.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.go.enable

Whether to enable go development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.go.consumerMeta

Per-consumer metadata for go, defaulted from languages/go.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.go.consumerMeta.opencode

How the opencode consumer handles go. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".go"
  ];
}

Declared by:

devix.languages.go.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.go.consumerMeta.zed

How the zed consumer handles go. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "gopls"
    "..."
  ];
  name = "Go";
}

Declared by:

devix.languages.go.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.go.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.go.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.go.consumers

Per-consumer exposure for the go language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip go in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.go.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.go.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.go.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.go.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.go.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.go.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.go.formatters

Formatters (keys into devix.formatters) used for go.

Type: list of string

Default:

[
  "gofmt"
]

Declared by:

devix.languages.go.lspServers

Language servers (keys into devix.lsps) used for go.

Type: list of string

Default:

[
  "gopls"
  "golangci-lint-langserver"
]

Declared by:

devix.languages.json

Settings for json (json development environment). Every value below is defaulted from modules/devix/languages/json.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.json.enable

Whether to enable json development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.json.consumerMeta

Per-consumer metadata for json, defaulted from languages/json.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.json.consumerMeta.opencode

How the opencode consumer handles json. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".json"
    ".jsonc"
  ];
}

Declared by:

devix.languages.json.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.json.consumerMeta.zed

How the zed consumer handles json. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "..."
  ];
  name = "JSON";
}

Declared by:

devix.languages.json.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.json.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.json.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.json.consumers

Per-consumer exposure for the json language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip json in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.json.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.json.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.json.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.json.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.json.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.json.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.json.formatters

Formatters (keys into devix.formatters) used for json.

Type: list of string

Default:

[
  "prettier-json"
]

Declared by:

devix.languages.json.lspServers

Language servers (keys into devix.lsps) used for json.

Type: list of string

Default:

[
  "vscode-json-languageserver"
]

Declared by:

devix.languages.julia

Settings for julia (julia development environment). Every value below is defaulted from modules/devix/languages/julia.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.julia.enable

Whether to enable julia development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.julia.consumerMeta

Per-consumer metadata for julia, defaulted from languages/julia.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.julia.consumerMeta.opencode

How the opencode consumer handles julia. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".jl"
  ];
}

Declared by:

devix.languages.julia.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.julia.consumerMeta.zed

How the zed consumer handles julia. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

null

Declared by:

devix.languages.julia.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.julia.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.julia.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.julia.consumers

Per-consumer exposure for the julia language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip julia in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.julia.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.julia.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.julia.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.julia.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.julia.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.julia.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.julia.formatters

Formatters (keys into devix.formatters) used for julia.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.julia.lspServers

Language servers (keys into devix.lsps) used for julia.

Type: list of string

Default:

[
  "julia-ls"
]

Declared by:

devix.languages.latex

Settings for latex (latex development environment). Every value below is defaulted from modules/devix/languages/latex.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.latex.enable

Whether to enable latex development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.latex.consumerMeta

Per-consumer metadata for latex, defaulted from languages/latex.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.latex.consumerMeta.opencode

How the opencode consumer handles latex. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".tex"
    ".sty"
    ".cls"
  ];
}

Declared by:

devix.languages.latex.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.latex.consumerMeta.zed

How the zed consumer handles latex. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    "latex"
  ];
  languageServers = [
    "texlab"
    "..."
  ];
  name = "LaTeX";
}

Declared by:

devix.languages.latex.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.latex.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.latex.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.latex.consumers

Per-consumer exposure for the latex language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip latex in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.latex.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.latex.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.latex.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.latex.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.latex.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.latex.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.latex.formatters

Formatters (keys into devix.formatters) used for latex.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.latex.lspServers

Language servers (keys into devix.lsps) used for latex.

Type: list of string

Default:

[
  "texlab"
]

Declared by:

devix.languages.markdown

Settings for markdown (markdown development environment). Every value below is defaulted from modules/devix/languages/markdown.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.markdown.enable

Whether to enable markdown development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.markdown.consumerMeta

Per-consumer metadata for markdown, defaulted from languages/markdown.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.markdown.consumerMeta.opencode

How the opencode consumer handles markdown. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".md"
    ".markdown"
  ];
}

Declared by:

devix.languages.markdown.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.markdown.consumerMeta.zed

How the zed consumer handles markdown. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "..."
  ];
  name = "Markdown";
}

Declared by:

devix.languages.markdown.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.markdown.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.markdown.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.markdown.consumers

Per-consumer exposure for the markdown language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip markdown in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.markdown.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.markdown.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.markdown.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.markdown.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.markdown.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.markdown.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.markdown.formatters

Formatters (keys into devix.formatters) used for markdown.

Type: list of string

Default:

[
  "prettier-markdown"
]

Declared by:

devix.languages.markdown.lspServers

Language servers (keys into devix.lsps) used for markdown.

Type: list of string

Default:

[
  "marksman"
  "markdown-oxide"
  "iwe"
]

Declared by:

devix.languages.matlab

Settings for matlab (matlab development environment). Every value below is defaulted from modules/devix/languages/matlab.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.matlab.enable

Whether to enable matlab development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.matlab.consumerMeta

Per-consumer metadata for matlab, defaulted from languages/matlab.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.matlab.consumerMeta.opencode

How the opencode consumer handles matlab. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".m"
  ];
}

Declared by:

devix.languages.matlab.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.matlab.consumerMeta.zed

How the zed consumer handles matlab. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

null

Declared by:

devix.languages.matlab.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.matlab.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.matlab.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.matlab.consumers

Per-consumer exposure for the matlab language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip matlab in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.matlab.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.matlab.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.matlab.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.matlab.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.matlab.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.matlab.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.matlab.formatters

Formatters (keys into devix.formatters) used for matlab.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.matlab.lspServers

Language servers (keys into devix.lsps) used for matlab.

Type: list of string

Default:

[
  "matlab-ls"
]

Declared by:

devix.languages.nix

Settings for nix (nix development environment). Every value below is defaulted from modules/devix/languages/nix.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nix.enable

Whether to enable nix development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.nix.consumerMeta

Per-consumer metadata for nix, defaulted from languages/nix.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.nix.consumerMeta.opencode

How the opencode consumer handles nix. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".nix"
  ];
}

Declared by:

devix.languages.nix.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.nix.consumerMeta.zed

How the zed consumer handles nix. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    "nix"
  ];
  languageServers = [
    "nil"
    "nixd"
    "..."
  ];
  name = "Nix";
}

Declared by:

devix.languages.nix.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.nix.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.nix.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.nix.consumers

Per-consumer exposure for the nix language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip nix in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nix.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nix.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.nix.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nix.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.nix.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nix.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.nix.formatters

Formatters (keys into devix.formatters) used for nix.

Type: list of string

Default:

[
  "nixfmt"
]

Declared by:

devix.languages.nix.lspServers

Language servers (keys into devix.lsps) used for nix.

Type: list of string

Default:

[
  "nixd"
  "nil"
]

Declared by:

devix.languages.nu

Settings for nu (nu development environment). Every value below is defaulted from modules/devix/languages/nu.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nu.enable

Whether to enable nu development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.nu.consumerMeta

Per-consumer metadata for nu, defaulted from languages/nu.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.nu.consumerMeta.opencode

How the opencode consumer handles nu. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".nu"
  ];
}

Declared by:

devix.languages.nu.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.nu.consumerMeta.zed

How the zed consumer handles nu. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    "nu"
  ];
  languageServers = [
    "..."
  ];
  name = "Nu";
}

Declared by:

devix.languages.nu.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.nu.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.nu.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.nu.consumers

Per-consumer exposure for the nu language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip nu in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nu.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nu.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.nu.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nu.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.nu.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.nu.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.nu.formatters

Formatters (keys into devix.formatters) used for nu.

Type: list of string

Default:

[
  "nufmt"
]

Declared by:

devix.languages.nu.lspServers

Language servers (keys into devix.lsps) used for nu.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.python

Settings for python (python development environment). Every value below is defaulted from modules/devix/languages/python.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.python.enable

Whether to enable python development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.python.consumerMeta

Per-consumer metadata for python, defaulted from languages/python.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.python.consumerMeta.opencode

How the opencode consumer handles python. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".py"
    ".pyi"
  ];
}

Declared by:

devix.languages.python.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.python.consumerMeta.zed

How the zed consumer handles python. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "pyright"
    "..."
  ];
  name = "Python";
}

Declared by:

devix.languages.python.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.python.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.python.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.python.consumers

Per-consumer exposure for the python language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip python in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.python.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.python.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.python.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.python.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.python.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.python.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.python.formatters

Formatters (keys into devix.formatters) used for python.

Type: list of string

Default:

[
  "ruff-check"
  "ruff-format"
]

Declared by:

devix.languages.python.lspServers

Language servers (keys into devix.lsps) used for python.

Type: list of string

Default:

[
  "pyright"
]

Declared by:

devix.languages.rust

Settings for rust (rust development environment). Every value below is defaulted from modules/devix/languages/rust.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.rust.enable

Whether to enable rust development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.rust.consumerMeta

Per-consumer metadata for rust, defaulted from languages/rust.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.rust.consumerMeta.opencode

How the opencode consumer handles rust. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".rs"
  ];
}

Declared by:

devix.languages.rust.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.rust.consumerMeta.zed

How the zed consumer handles rust. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "rust-analyzer"
    "..."
  ];
  name = "Rust";
}

Declared by:

devix.languages.rust.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.rust.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.rust.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.rust.consumers

Per-consumer exposure for the rust language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip rust in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.rust.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.rust.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.rust.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.rust.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.rust.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.rust.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.rust.formatters

Formatters (keys into devix.formatters) used for rust.

Type: list of string

Default:

[
  "rustfmt"
]

Declared by:

devix.languages.rust.lspServers

Language servers (keys into devix.lsps) used for rust.

Type: list of string

Default:

[
  "rust-analyzer"
]

Declared by:

devix.languages.toml

Settings for toml (toml development environment). Every value below is defaulted from modules/devix/languages/toml.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.toml.enable

Whether to enable toml development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.toml.consumerMeta

Per-consumer metadata for toml, defaulted from languages/toml.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.toml.consumerMeta.opencode

How the opencode consumer handles toml. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".toml"
  ];
}

Declared by:

devix.languages.toml.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.toml.consumerMeta.zed

How the zed consumer handles toml. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "taplo"
    "..."
  ];
  name = "TOML";
}

Declared by:

devix.languages.toml.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.toml.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.toml.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.toml.consumers

Per-consumer exposure for the toml language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip toml in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.toml.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.toml.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.toml.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.toml.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.toml.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.toml.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.toml.formatters

Formatters (keys into devix.formatters) used for toml.

Type: list of string

Default:

[
  "taplo-fmt"
]

Declared by:

devix.languages.toml.lspServers

Language servers (keys into devix.lsps) used for toml.

Type: list of string

Default:

[
  "taplo"
]

Declared by:

devix.languages.typst

Settings for typst (typst development environment). Every value below is defaulted from modules/devix/languages/typst.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.typst.enable

Whether to enable typst development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.typst.consumerMeta

Per-consumer metadata for typst, defaulted from languages/typst.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.typst.consumerMeta.opencode

How the opencode consumer handles typst. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".typ"
  ];
}

Declared by:

devix.languages.typst.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.typst.consumerMeta.zed

How the zed consumer handles typst. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    "typst"
  ];
  languageServers = [
    "tinymist"
    "..."
  ];
  name = "Typst";
}

Declared by:

devix.languages.typst.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.typst.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.typst.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.typst.consumers

Per-consumer exposure for the typst language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip typst in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.typst.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.typst.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.typst.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.typst.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.typst.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.typst.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.typst.formatters

Formatters (keys into devix.formatters) used for typst.

Type: list of string

Default:

[
  "typstyle"
]

Declared by:

devix.languages.typst.lspServers

Language servers (keys into devix.lsps) used for typst.

Type: list of string

Default:

[
  "tinymist"
]

Declared by:

devix.languages.xml

Settings for xml (xml development environment). Every value below is defaulted from modules/devix/languages/xml.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.xml.enable

Whether to enable xml development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.xml.consumerMeta

Per-consumer metadata for xml, defaulted from languages/xml.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.xml.consumerMeta.opencode

How the opencode consumer handles xml. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".xml"
  ];
}

Declared by:

devix.languages.xml.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.xml.consumerMeta.zed

How the zed consumer handles xml. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    "xml"
  ];
  languageServers = [
    "lemminx"
    "..."
  ];
  name = "XML";
}

Declared by:

devix.languages.xml.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.xml.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.xml.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.xml.consumers

Per-consumer exposure for the xml language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip xml in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.xml.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.xml.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.xml.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.xml.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.xml.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.xml.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.xml.formatters

Formatters (keys into devix.formatters) used for xml.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.xml.lspServers

Language servers (keys into devix.lsps) used for xml.

Type: list of string

Default:

[
  "lemminx"
]

Declared by:

devix.languages.yaml

Settings for yaml (yaml development environment). Every value below is defaulted from modules/devix/languages/yaml.nix, so you only need to set what you want to change.

Type: submodule

Default:

{ }

Declared by:

devix.languages.yaml.enable

Whether to enable yaml development environment.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.languages.yaml.consumerMeta

Per-consumer metadata for yaml, defaulted from languages/yaml.nix. Only consumers that need metadata appear here; each one types its own shape (see the consumer’s metaOptions in consumers/<name>/default.nix).

Type: submodule

Default:

{ }

Declared by:

devix.languages.yaml.consumerMeta.opencode

How the opencode consumer handles yaml. null means opencode cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [
    ".yaml"
    ".yml"
  ];
}

Declared by:

devix.languages.yaml.consumerMeta.opencode.extensions

File extensions (leading dot) OpenCode should treat as this language.

Type: list of string

Default:

[ ]

Example:

[
  ".py"
  ".pyi"
]

Declared by:

devix.languages.yaml.consumerMeta.zed

How the zed consumer handles yaml. null means zed cannot configure this language and skips it.

Type: null or (submodule)

Default:

{
  extensions = [ ];
  languageServers = [
    "yaml-lsp"
    "..."
  ];
  name = "YAML";
}

Declared by:

devix.languages.yaml.consumerMeta.zed.extensions

Zed extensions to install for this language.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.yaml.consumerMeta.zed.languageServers

The curated, ordered language_servers list Zed should use. May contain the literal “…” token (Zed’s “then the defaults” marker) and may deliberately omit devix servers that Zed handles better with its own built-ins. Only the servers named here get a lsp.<id>.binary override.

Type: list of string

Default:

[ ]

Declared by:

devix.languages.yaml.consumerMeta.zed.name

Zed’s display name for the language; the key under languages in its settings.

Type: string

Declared by:

devix.languages.yaml.consumers

Per-consumer exposure for the yaml language. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to skip yaml in Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.languages.yaml.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.yaml.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.yaml.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.yaml.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.yaml.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.languages.yaml.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.languages.yaml.formatters

Formatters (keys into devix.formatters) used for yaml.

Type: list of string

Default:

[
  "yamlfmt"
]

Declared by:

devix.languages.yaml.lspServers

Language servers (keys into devix.lsps) used for yaml.

Type: list of string

Default:

[
  "yaml-lsp"
]

Declared by:

Addon options

One entry per file in modules/devix/addons/. An addon contributes language servers to the languages it names rather than being a language itself.

devix.addons.ai

Settings for the ai addon (AI completion language servers), defaulted from modules/devix/addons/ai.nix. An addon contributes its language servers to the languages it names instead of being a language.

Type: submodule

Default:

{ }

Declared by:

devix.addons.ai.enable

Whether to enable AI completion language servers.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.addons.ai.consumers

Per-consumer exposure for the ai addon. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to keep this addon’s servers out of Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.addons.ai.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.addons.ai.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.addons.ai.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.addons.ai.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.addons.ai.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.addons.ai.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.addons.ai.languages

Languages these servers attach to, keyed by devix.languages.<name>. The single entry “*” attaches to every enabled language.

Type: list of string

Default:

[
  "*"
]

Example:

[
  "markdown"
  "latex"
]

Declared by:

devix.addons.ai.lspServers

Language servers (keys into devix.lsps) this addon attaches. The addon may define more servers than it attaches — the extras stay available in the registry for you to opt into.

Type: list of string

Default:

[
  "copilot"
  "lsp-ai"
]

Declared by:

devix.addons.grammar

Settings for the grammar addon (spelling, grammar and style checking), defaulted from modules/devix/addons/grammar.nix. An addon contributes its language servers to the languages it names instead of being a language.

Type: submodule

Default:

{ }

Declared by:

devix.addons.grammar.enable

Whether to enable spelling, grammar and style checking.

Type: boolean

Default:

false

Example:

true

Declared by:

devix.addons.grammar.consumers

Per-consumer exposure for the grammar addon. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to keep this addon’s servers out of Zed only.

Type: submodule

Default:

{ }

Declared by:

devix.addons.grammar.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.addons.grammar.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.addons.grammar.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.addons.grammar.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.addons.grammar.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.addons.grammar.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.addons.grammar.languages

Languages these servers attach to, keyed by devix.languages.<name>. The single entry “*” attaches to every enabled language.

Type: list of string

Default:

[
  "markdown"
  "latex"
  "typst"
]

Example:

[
  "markdown"
  "latex"
]

Declared by:

devix.addons.grammar.lspServers

Language servers (keys into devix.lsps) this addon attaches. The addon may define more servers than it attaches — the extras stay available in the registry for you to opt into.

Type: list of string

Default:

[
  "ltex"
  "codebook"
]

Declared by:

Registry options

The shared language-server and formatter registries. Languages and addons refer to entries here by name, so overriding one entry changes it for every editor at once.

devix.formatters

Reusable formatter registry.

Type: attribute set of (submodule)

Default:

{ }

Declared by:

devix.formatters.<name>.enable

Enable this formatter.

Type: boolean

Default:

true

Declared by:

devix.formatters.<name>.package

Package providing this formatter.

Type: null or package

Default:

null

Declared by:

devix.formatters.<name>.args

Arguments passed to this formatter.

Type: list of string

Default:

[ ]

Declared by:

devix.formatters.<name>.command

Command used to run this formatter. Derived from package; set it explicitly when the binary is not the package’s main program.

Type: string

Default:

lib.getExe package, or the registry key when there is no package

Declared by:

devix.formatters.<name>.consumers

Per-consumer exposure for this formatter (see lsps.<name>.consumers).

Type: submodule

Default:

{ }

Declared by:

devix.formatters.<name>.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.formatters.<name>.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.formatters.<name>.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.formatters.<name>.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.formatters.<name>.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.formatters.<name>.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.lsps

Reusable language server registry.

Type: attribute set of (submodule)

Default:

{ }

Declared by:

devix.lsps.<name>.enable

Enable this language server.

Type: boolean

Default:

true

Declared by:

devix.lsps.<name>.package

Package providing this language server.

Type: null or package

Default:

null

Declared by:

devix.lsps.<name>.args

Arguments passed to this language server.

Type: list of string

Default:

[ ]

Declared by:

devix.lsps.<name>.command

Command used to start this language server. Derived from package, so pointing package at a different build (an unstable one, say) is normally all you need. Set this explicitly when the binary is not the package’s main program.

Type: string

Default:

lib.getExe package, or the registry key when there is no package

Declared by:

devix.lsps.<name>.config

Editor-specific configuration passed to this language server.

Type: attribute set of anything

Default:

{ }

Declared by:

devix.lsps.<name>.consumers

Per-consumer exposure for this language server. Each consumer defaults to enabled; set e.g. consumers.zed.enable = false to keep this server out of Zed while leaving it available to Helix/OpenCode.

Type: submodule

Default:

{ }

Declared by:

devix.lsps.<name>.consumers.helix

Exposure toggle for the helix consumer.

Type: submodule

Default:

{ }

Declared by:

devix.lsps.<name>.consumers.helix.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.lsps.<name>.consumers.opencode

Exposure toggle for the opencode consumer.

Type: submodule

Default:

{ }

Declared by:

devix.lsps.<name>.consumers.opencode.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.lsps.<name>.consumers.zed

Exposure toggle for the zed consumer.

Type: submodule

Default:

{ }

Declared by:

devix.lsps.<name>.consumers.zed.enable

Whether this is exposed to / configured for this consumer.

Type: boolean

Default:

true

Declared by:

devix.lsps.<name>.environment

Literal environment variables to set when launching this server. Consumers that support it wrap the command in a shell launcher.

Type: attribute set of string

Default:

{ }

Declared by:

devix.lsps.<name>.environmentScript

Shell snippet prepended to the server launcher (e.g. to read a secret into an env var). Used for AI servers; see lib/opencode.nix.

Type: strings concatenated with “\n”

Default:

""

Declared by:

devix.lsps.<name>.kind

Classification of this server, used by consumers to decide how to attach it (e.g. AI/grammar servers may be handled specially).

Type: one of “language”, “grammar”, “tool”, “ai”

Default:

"language"

Declared by:

Daily Usage

Task runner (just)

Common commands live in the repo’s justfile. Run just --list to see them all (just is available in the nix develop .#nix shell). The essentials:

just switch          # build + activate this host (NixOS or macOS)
just home            # build + activate your home-manager config (standalone)
just update          # update all flake inputs
just fmt             # format all nix files
just check           # nix flake check
just docs            # serve these docs locally
just iso <host>      # build an installer ISO (Linux)
just deploy-tag nas  # colmena-deploy every host tagged `nas`
just bump packages/top-level/<pkg>   # bump a custom package with nix-update

The recipes wrap nh, nix, colmena, and sops — read them in the justfile to see the exact commands.

Nix Helper (nh)

nh is a convenience wrapper around common Nix operations. The flake sets NH_FLAKE to ~/.config/flake, so these work from anywhere:

nh os switch      # Update NixOS
nh home switch    # Update Home Manager
nh clean all      # Garbage collection

To point at a different checkout, override NH_FLAKE or pass the flake path explicitly:

nh os switch ~/.config/flake#<device-name>
nh home switch ~/.config/flake#<username>

Clean-up

nix-collect-garbage --delete-older-than 30d
nh clean all

Git Fetchers

When adding a package from a git source, you need the commit and the Nix hash.

nix run nixpkgs#nix-prefetch-git https://github.com/EliverLara/candy-icons

Alternatively, leave the hash field empty in your derivation, attempt a build, and copy the hash from the error message.

Remote Builds

Use a more powerful machine (like kuchiki) to build heavy packages (e.g., Rust projects):

nix build --builders "ssh://mirza@kuchiki.sparrow-yo.ts.net x86_64-linux" \
  -L .#nixosConfigurations.sado.config.services.stump.package

Prerequisites

The Nix daemon runs as root, so root needs SSH access to the remote machine:

# Run once to add kuchiki's host key to root's known_hosts
sudo ssh mirza@kuchiki.sparrow-yo.ts.net

After that, remote builds will work without further configuration.

Options

  • --max-jobs 0 — disable local builds entirely, force everything to remote
  • Multiple builders: --builders "ssh://host1 ... ; ssh://host2 ..."

Dev Shells

Available shells (see shells/):

nix develop .#go        # Go toolchain
nix develop .#website   # Hugo, for the website
nix develop .#nix       # just + statix, deadnix, nixfmt (the repo dev shell)

Workflows & Automation

GitHub Workflow Token

If you edit the CI workflows, your token needs the workflow scope:

gh auth status       # Check current scopes
gh auth login --scopes workflow

Formatting

nix fmt runs whatever package the flake’s formatter output points at (flake.nix’s formatter.${system}), currently nixfmt-tree. Three different tools are involved and it’s easy to mix them up:

  • nixfmt — the official NixOS Foundation formatter. It formats a single file (or stdin), which makes it the right thing to point your editor’s format-on-save at.
  • treefmt — a multi-language formatter orchestrator by numtide. It walks the whole repo tree and dispatches each file to the formatter configured for its type.
  • nixfmt-tree — a small nixpkgs package that is not the upstream version of Numtide’s treefmt-nix (that’s a separate flake module numtide also publishes for configuring treefmt from Nix; unused here). It’s just treefmt pre-wired to run nixfmt on every *.nix file, i.e. “zero-setup nix fmt for a Nix repo”.

So nix fmt == treefmt-wide formatting using nixfmt under the hood, while nixfmt on its own is the single-file tool for IDE integration.

The pre-commit hook (.pre-commit-config.yaml, run via prek) invokes nix fmt -- --fail-on-change --no-cache: it reformats any unformatted files in place and fails the commit if anything changed, so re-stage and commit again. treefmt has no dry-run/check flag that skips writing.

Facter

Generate a hardware report for a new system:

sudo nix run \
  --option experimental-features "nix-command flakes" \
  --option extra-substituters https://numtide.cachix.org \
  --option extra-trusted-public-keys numtide.cachix.org-1:2ps1kLBUWjxIneOy1Ik6cQjb41X0iXVXeHigGmycPPE= \
  github:numtide/nixos-facter -- -o facter.json

Place the output in systems/<arch>/<host>/facter.json.

Networking

Networking in this flake is split into small, focused modules under modules/nixos/services/network/.

Use this section for host ingress, tunnels, and service exposure patterns.

Cloudflared

This flake uses Cloudflare Tunnel (cloudflared) to expose selected services without opening direct inbound ports on the origin hosts.

Module Location

  • Base wrapper module: modules/nixos/services/network/cloudflared/default.nix
  • Cloudflared service module: modules/nixos/services/network/cloudflared/new.nix

One-Time Tunnel Bootstrap

Run these commands on the host where you manage tunnels:

cloudflared login
cloudflared tunnel create <name>
sudo mkdir -p /etc/cloudflared
sudo cp /home/mirza/.cloudflared/cert.pem /etc/cloudflared/cert.pem

Notes:

  • cloudflared login creates ~/.cloudflared/cert.pem.
  • cloudflared tunnel create <name> creates tunnel credentials JSON under ~/.cloudflared/.
  • The cert file is needed for declarative tunnel management workflows.

Secrets Wiring

Store tunnel credentials in secrets/secrets.yaml under:

  • config.cloudflared.<host>

Example existing keys:

  • config.cloudflared.sado
  • config.cloudflared.kuchiki
  • config.cloudflared.madara

For a new ingress host (for example aizen), add:

  • config.cloudflared.aizen

The module reads from config/cloudflared/${config.networking.hostName}.

Host Configuration Pattern

Enable cloudflared on the host and define ordered ingress rules:

services.cloudflared = {
  enable = true;
  defaultDomain = "arnaut.me";
  tunnels."${config.networking.hostName}".ingress = [
    {
      hostname = "arr.${config.services.cloudflared.defaultDomain}";
      path = "/radarr.*";
      service = "http://kuchiki.${config.services.tailscale.tailnet}.ts.net:${builtins.toString config.services.radarr.settings.server.port}";
    }
    {
      hostname = "arr.${config.services.cloudflared.defaultDomain}";
      path = "/sonarr.*";
      service = "http://kuchiki.${config.services.tailscale.tailnet}.ts.net:${builtins.toString config.services.sonarr.settings.server.port}";
    }
    {
      hostname = "arr.${config.services.cloudflared.defaultDomain}";
      path = "/lidarr.*";
      service = "http://sado.${config.services.tailscale.tailnet}.ts.net:${builtins.toString config.services.lidarr.settings.server.port}";
    }
    {
      hostname = "arr.${config.services.cloudflared.defaultDomain}";
      path = "/prowlarr.*";
      service = "http://shinji.${config.services.tailscale.tailnet}.ts.net:${builtins.toString config.services.prowlarr.settings.server.port}";
    }
  ];
};

Important details:

  • Rules are matched in order.
  • path supports regex matching (for example /radarr.*).
  • A default catch-all service (http_status:404) is configured by module defaults.

Deploy and Verify

After secrets + host config are in place:

sudo nixos-rebuild switch --flake ~/.config/flake#<host>

Check service status:

systemctl status cloudflared-tunnel-<host>

Verify external routes:

  • https://arr.arnaut.me/radarr
  • https://arr.arnaut.me/sonarr
  • https://arr.arnaut.me/lidarr
  • https://arr.arnaut.me/prowlarr

Troubleshooting

  • Missing or wrong secret path: verify config.cloudflared.<host> exists in secrets/secrets.yaml.
  • Service unreachable: verify Tailnet DNS/host reachability from ingress host.
  • Path not matching: confirm hostname and regex path values in ingress rules.
  • Auth behavior unexpected: check Cloudflare Access app/policy scope for the hostname and path.

Tips & Resources

Tutorials & Guides

Vimjoyer (YouTube)

Other

Nix Language

High-Level Libraries

Updating Custom Packages

Use the bump recipe, which wraps nix-update and figures out the attribute path and platform for you:

just bump packages/top-level/<pkg>       # or packages/custom/<pkg>

Under the hood it runs scripts/bump-package.sh; extra flags are passed straight through to nix-update, e.g. just bump packages/top-level/<pkg> --version=1.2.3.

ZFS

Dev Tools

Handy terminal tools available via nix run nixpkgs#<name>.

PackageDescriptionRepo
brootInteractive directory tree navigatorhttps://github.com/Canop/broot
glowMarkdown viewer for the terminalhttps://github.com/charmbracelet/glow
hexylColored hex dump viewerhttps://github.com/sharkdp/hexyl
millerCSV, JSON, TSV processor (mlr)https://github.com/johnkerl/miller
ncduNCurses disk usage analyzerhttps://dev.yorhel.nl/ncdu
ouchMulti-format archiver (zip, tar, 7z, …)https://github.com/ouch-org/ouch
slidesTerminal-based presentation toolhttps://github.com/maaslalani/slides
poppler-utilsPDF rendering tools (pdftotext, pdftoppm, …)https://gitlab.freedesktop.org/poppler/poppler
qSQL-like queries on CSV/TSV fileshttps://github.com/harelba/q
upUltimate Plumber — interactive pipe viewerhttps://github.com/akavel/up

Also gone (no longer enabled by development tag): browsh, firefox.

Maintainer Notes

TODO

  • Integrate disko for each host
  • Manage host types via Colmena host tags for finer-grained control

Fixes

Thick black borders in GNOME apps

Set GSK_RENDERER=gl. Tracked at GTK#6890.

Credits

  • use-the-fork — help moving from standalone Home Manager to module-based setup
  • u/paulgdpadvice on detecting nixosConfig in module context
  • olmokramerexample using lib.genAttrs for host generation