From e62b83a934ea44d6da145cfe02b2d401d95d174f Mon Sep 17 00:00:00 2001 From: Marwan Aljubeh Date: Tue, 7 Mar 2023 12:53:20 +0000 Subject: [PATCH 001/161] Fix system.patches Currently, `system.patches` doesn't work because it will attempt to first detect if the patch has already been applied by checking if it can be applied in reverse. However, when that happens, `patch` detects that the supplied patch is incorrectly reversed and attempts to ask the user if they want to "Ignore -R": ``` Unreversed (or previously applied) patch detected! Ignore -R? [y] ``` Because the output is piped to `/dev/null` the user will basically see nothing and `darwin-rebuild switch` will hang until the user presses "Enter" (possibly to check if the terminal is frozen). At which point, patch will ignore the --reverse and exit successfully, preventing the patch from being applied at all. This change fixes that bug by using `--force` which tells patch that we know what we're doing and prevents it from prompting the user if they want to ignore `--reverse`. --- modules/system/patches.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/patches.nix b/modules/system/patches.nix index 92f45c140..bb384e80c 100644 --- a/modules/system/patches.nix +++ b/modules/system/patches.nix @@ -62,7 +62,7 @@ in ${concatMapStringsSep "\n" (f: '' f="$(basename ${f})" - if ! patch --reverse --dry-run -d / -p1 < '${f}' &> /dev/null; then + if ! patch --force --reverse --dry-run -d / -p1 < '${f}' &> /dev/null; then patch --forward --backup -d / -p1 < '${f}' || true fi '') cfg.patches} From 42e0e4f3b4aadcae627f65a395600ea17fd6f9f0 Mon Sep 17 00:00:00 2001 From: Marwan Aljubeh Date: Tue, 7 Mar 2023 13:35:24 +0000 Subject: [PATCH 002/161] Add `--force` to all patch invocations --- modules/system/patches.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/system/patches.nix b/modules/system/patches.nix index bb384e80c..3b9d980b1 100644 --- a/modules/system/patches.nix +++ b/modules/system/patches.nix @@ -56,14 +56,14 @@ in for f in $(ls /run/current-system/patches 2> /dev/null); do if test ! -e "${config.system.build.patches}/patches/$f"; then - patch --reverse --backup -d / -p1 < "/run/current-system/patches/$f" || true + patch --force --reverse --backup -d / -p1 < "/run/current-system/patches/$f" || true fi done ${concatMapStringsSep "\n" (f: '' f="$(basename ${f})" if ! patch --force --reverse --dry-run -d / -p1 < '${f}' &> /dev/null; then - patch --forward --backup -d / -p1 < '${f}' || true + patch --force --forward --backup -d / -p1 < '${f}' || true fi '') cfg.patches} ''; From ca62d93c6c6bf89891aa24071ad312fe923801f1 Mon Sep 17 00:00:00 2001 From: Marwan Aljubeh Date: Tue, 7 Mar 2023 13:37:18 +0000 Subject: [PATCH 003/161] Only use `--force` for patches applied in reverse Using `--forward` already instructs `--patch` to ignore patches that it thinks are reversed or already applied. --- modules/system/patches.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/patches.nix b/modules/system/patches.nix index 3b9d980b1..452ed3bf2 100644 --- a/modules/system/patches.nix +++ b/modules/system/patches.nix @@ -63,7 +63,7 @@ in ${concatMapStringsSep "\n" (f: '' f="$(basename ${f})" if ! patch --force --reverse --dry-run -d / -p1 < '${f}' &> /dev/null; then - patch --force --forward --backup -d / -p1 < '${f}' || true + patch --forward --backup -d / -p1 < '${f}' || true fi '') cfg.patches} ''; From 9f93b195853a275668e013d330d7bdd59e6c4b49 Mon Sep 17 00:00:00 2001 From: Glib Shpychka <23005347+gshpychka@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:50:10 +0200 Subject: [PATCH 004/161] feat: support writing arrays to system defaults --- modules/system/defaults-write.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/system/defaults-write.nix b/modules/system/defaults-write.nix index 8d8f57e8d..defe41d9a 100644 --- a/modules/system/defaults-write.nix +++ b/modules/system/defaults-write.nix @@ -12,6 +12,7 @@ let if isInt value then "-int ${toString value}" else if isFloat value then "-float ${strings.floatToString value}" else if isString value then "-string '${value}'" else + if isList value then "-array ${concatStringsSep " " (map (v: writeValue v)value)}" else throw "invalid value type"; writeDefault = domain: key: value: From 8699abe98f93aca6733c7c694a908f4d25fc4d90 Mon Sep 17 00:00:00 2001 From: Vadim Date: Tue, 21 Mar 2023 13:23:16 +0300 Subject: [PATCH 005/161] fix(wg-quick): builtins function typo --- modules/services/wg-quick.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/services/wg-quick.nix b/modules/services/wg-quick.nix index b685f4eb5..787b6632c 100644 --- a/modules/services/wg-quick.nix +++ b/modules/services/wg-quick.nix @@ -142,7 +142,7 @@ let '' + optionalString (interfaceOpt.address != [ ]) ('' Address = ${concatStringsSep "," interfaceOpt.address} '') + optionalString (interfaceOpt.dns != [ ]) '' - DNS = ${concatStringsep "," interfaceOpt.dns} + DNS = ${concatStringsSep "," interfaceOpt.dns} '' + optionalString (interfaceOpt.listenPort != null) '' ListenPort = ${toString interfaceOpt.listenPort} '' + optionalString (interfaceOpt.mtu != null) '' From 0cf7d413898a975097a196e5ddb3f6a0f214234b Mon Sep 17 00:00:00 2001 From: Bernardo Meurer Date: Tue, 28 Mar 2023 14:41:04 -0300 Subject: [PATCH 006/161] fix(modules/fonts): ignore repeated fonts Without this, attempts to build the fonts dir with repeated font packages in `fonts.fonts` will yield: ``` ln: failed to create symbolic link '/nix/store/6im9rm87nxc82nqbv350hfp2w7ja1z47-fonts/Library/Fonts/IBMPlexSansThai-Thin.otf': File exists ``` --- modules/fonts/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/fonts/default.nix b/modules/fonts/default.nix index 44ea58bbe..0f4c269fd 100644 --- a/modules/fonts/default.nix +++ b/modules/fonts/default.nix @@ -38,7 +38,7 @@ in mkdir -p $out/Library/Fonts for path in $paths; do find -L $path/share/fonts -type f -print0 | while IFS= read -rd "" f; do - ln -s "$f" $out/Library/Fonts + ln -sf "$f" $out/Library/Fonts done done ''; From e5c994a6af7a1d4a7390f7145ef96057e07e12aa Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Wed, 29 Mar 2023 23:47:08 +1100 Subject: [PATCH 007/161] Improve Karabiner-Elements installer reliability Hopefully fixes #564 --- .../services/karabiner-elements/default.nix | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/modules/services/karabiner-elements/default.nix b/modules/services/karabiner-elements/default.nix index 395a2f85c..2f415b2d6 100644 --- a/modules/services/karabiner-elements/default.nix +++ b/modules/services/karabiner-elements/default.nix @@ -16,31 +16,37 @@ in config = mkIf cfg.enable { environment.systemPackages = [ pkgs.karabiner-elements ]; - system.activationScripts.extraActivation.text = '' + system.activationScripts.preActivation.text = '' rm -rf ${parentAppDir} mkdir -p ${parentAppDir} # Kernel extensions must reside inside of /Applications, they cannot be symlinks cp -r ${pkgs.karabiner-elements.driver}/Applications/.Karabiner-VirtualHIDDevice-Manager.app ${parentAppDir} ''; + system.activationScripts.postActivation.text = '' + echo "attempt to activate karabiner system extension and start daemons" >&2 + launchctl unload /Library/LaunchDaemons/org.nixos.start_karabiner_daemons.plist + launchctl load -w /Library/LaunchDaemons/org.nixos.start_karabiner_daemons.plist + ''; + # We need the karabiner_grabber and karabiner_observer daemons to run after the # Nix Store has been mounted, but we can't use wait4path as they need to be # executed directly for the Input Monitoring permission. We also want these # daemons to auto restart but if they start up without the Nix Store they will # refuse to run again until they've been unloaded and loaded back in so we can - # use a helper daemon to start them. + # use a helper daemon to start them. We also only want to run the daemons after + # the system extension is activated, so we can call activate from the manager + # which will block until the system extension is activated. launchd.daemons.start_karabiner_daemons = { serviceConfig.ProgramArguments = [ "/bin/sh" "-c" "/bin/wait4path /nix/store && ${pkgs.writeScript "start_karabiner_daemons" '' + ${parentAppDir}/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager activate launchctl kickstart system/org.pqrs.karabiner.karabiner_grabber launchctl kickstart system/org.pqrs.karabiner.karabiner_observer ''}" ]; - # Due to the daemons being loaded in alphabetical order during darwin-rebuild switch - # we need to set the label so that this daemon will be loaded after karabiner_grabber - # and karabiner_observer so that no reboot is required to start these daemons. - serviceConfig.Label = "org.xyz.start_karabiner_daemons"; + serviceConfig.Label = "org.nixos.start_karabiner_daemons"; serviceConfig.RunAtLoad = true; }; @@ -86,9 +92,8 @@ in serviceConfig.RunAtLoad = true; }; - # We can't put this inside the extraActivation script as /run gets nuked - # every reboot and the extraActivation script only gets run on darwin-rebuild - # switch. + # We need this to run every reboot as /run gets nuked so we can't put this + # inside the preActivation script as it only gets run on darwin-rebuild switch. launchd.daemons.setsuid_karabiner_session_monitor = { serviceConfig.ProgramArguments = [ "/bin/sh" "-c" From 90b36a5efe003a388451af2e0f41774bcdc0d658 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Tue, 18 Apr 2023 12:01:31 +0900 Subject: [PATCH 008/161] synergy: add options for TLS --- modules/services/synergy/default.nix | 43 ++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/modules/services/synergy/default.nix b/modules/services/synergy/default.nix index 71418a680..f7503da23 100644 --- a/modules/services/synergy/default.nix +++ b/modules/services/synergy/default.nix @@ -48,6 +48,21 @@ in type = types.bool; description = "Whether the Synergy client should be started automatically."; }; + tls = { + enable = mkEnableOption '' + Whether TLS encryption should be used. + + Using this requires a TLS certificate that can be + generated by starting the Synergy GUI once and entering + a valid product key. + ''; + cert = mkOption { + type = types.nullOr types.str; + default = null; + example = "~/.synergy/SSL/Synergy.pem"; + description = "The TLS certificate to use for encryption."; + }; + }; }; server = { @@ -81,6 +96,21 @@ in type = types.bool; description = "Whether the Synergy server should be started automatically."; }; + tls = { + enable = mkEnableOption '' + Whether TLS encryption should be used. + + Using this requires a TLS certificate that can be + generated by starting the Synergy GUI once and entering + a valid product key. + ''; + cert = mkOption { + type = types.nullOr types.str; + default = null; + example = "~/.synergy/SSL/Synergy.pem"; + description = "The TLS certificate to use for encryption."; + }; + }; }; }; @@ -92,8 +122,13 @@ in launchd.user.agents."synergy-client" = { path = [ config.environment.systemPath ]; serviceConfig.ProgramArguments = [ - "${cfg.package}/bin/synergyc" "-f" "${cfg.client.serverAddress}" - ] ++ optionals (cfg.client.screenName != "") [ "-n" cfg.client.screenName ]; + "${cfg.package}/bin/synergyc" "-f" + ] ++ optionals (cfg.client.tls.enable) [ "--enable-crypto" ] + ++ optionals (cfg.client.tls.cert != null) [ "--tls-cert" cfg.client.tls.cert ] + ++ optionals (cfg.client.screenName != "") [ "-n" cfg.client.screenName ] + ++ [ + cfg.client.serverAddress + ]; serviceConfig.KeepAlive = true; serviceConfig.RunAtLoad = cfg.client.autoStart; serviceConfig.ProcessType = "Interactive"; @@ -105,7 +140,9 @@ in path = [ config.environment.systemPath ]; serviceConfig.ProgramArguments = [ "${cfg.package}/bin/synergys" "-c" "${cfg.server.configFile}" "-f" - ] ++ optionals (cfg.server.screenName != "") [ "-n" cfg.server.screenName ] + ] ++ optionals (cfg.server.tls.enable) [ "--enable-crypto" ] + ++ optionals (cfg.server.tls.cert != null) [ "--tls-cert" cfg.server.tls.cert ] + ++ optionals (cfg.server.screenName != "") [ "-n" cfg.server.screenName ] ++ optionals (cfg.server.address != "") [ "-a" cfg.server.address ]; serviceConfig.KeepAlive = true; serviceConfig.RunAtLoad = cfg.server.autoStart; From 73ab8e0d702c9cdda3a92ba3ff95024ff2e70448 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Wed, 19 Apr 2023 15:56:46 -0400 Subject: [PATCH 009/161] Add/fix some launchd.plist options --- modules/launchd/launchd.nix | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/modules/launchd/launchd.nix b/modules/launchd/launchd.nix index cceaaf06f..727db951e 100644 --- a/modules/launchd/launchd.nix +++ b/modules/launchd/launchd.nix @@ -686,7 +686,7 @@ with lib; MachServices = mkOption { default = null; - example = { ResetAtClose = true; }; + example = { "org.nixos.service" = { ResetAtClose = true; }; }; description = '' This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system. Each key in this dictionary should be the name of service to be advertised. The value of the key must @@ -695,7 +695,7 @@ with lib; Finally, for the job itself, the values will be replaced with Mach ports at the time of check-in with launchd. ''; - type = types.nullOr (types.submodule { + type = types.nullOr (types.attrsOf (types.either types.bool (types.submodule { options = { ResetAtClose = mkOption { type = types.nullOr types.bool; @@ -719,7 +719,7 @@ with lib; ''; }; }; - }); + }))); }; LaunchEvents = mkOption { @@ -747,6 +747,26 @@ with lib; }; }; + ServiceIPC = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + This optional key specifies whether the job participates in advanced + communication with launchd. The default is false. This flag is + incompatible with the inetdCompatibility key. + ''; + }; + + SessionCreate = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + This key specifies that the job should be spawned into a new security + audit session rather than the default session for the context is belongs + to. See auditon(2) for details. + ''; + }; + Sockets = mkOption { default = null; description = '' From 8c9337e28685448882142302b45daef38a127df4 Mon Sep 17 00:00:00 2001 From: Jan Schmitt Date: Wed, 26 Apr 2023 23:00:58 +0200 Subject: [PATCH 010/161] ci: bump actions to most recent version * use checkout@v3 and install-nix-action@20 --- .github/workflows/build.yml | 4 ++-- .github/workflows/debug.yml | 4 ++-- .github/workflows/test.yml | 12 ++++++------ .github/workflows/update-manual.yml | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f9b8f2aeb..ed66317e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: macos-12 steps: - - uses: actions/checkout@v2 - - uses: cachix/install-nix-action@v17 + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v20 - run: | nix build ${{ github.event.client_payload.args }} -vL diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 6c4311e5c..3abe115bb 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -12,8 +12,8 @@ jobs: debug: runs-on: macos-12 steps: - - uses: actions/checkout@v2 - - uses: cachix/install-nix-action@v17 + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v20 - run: | nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs nix-channel --update diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cab17e898..bf5b6498e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,8 +7,8 @@ jobs: runs-on: macos-12 timeout-minutes: 30 steps: - - uses: actions/checkout@v2 - - uses: cachix/install-nix-action@v17 + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v20 - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.05-darwin -I darwin=. -A tests - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.05-darwin -I darwin=. -A manpages - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.05-darwin -I darwin=. -A examples.simple @@ -16,8 +16,8 @@ jobs: runs-on: macos-12 timeout-minutes: 30 steps: - - uses: actions/checkout@v2 - - uses: cachix/install-nix-action@v17 + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v20 - run: | nix-channel --add https://nixos.org/channels/nixpkgs-22.05-darwin nixpkgs nix-channel --update @@ -42,10 +42,10 @@ jobs: runs-on: macos-12 timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: cachix/install-nix-action@v17 + - uses: cachix/install-nix-action@v20 with: install_url: https://github.com/numtide/nix-flakes-installer/releases/download/nix-2.10.0pre20220808_73fde9e/install extra_nix_config: | diff --git a/.github/workflows/update-manual.yml b/.github/workflows/update-manual.yml index 488ca2f8d..6ef90ffe8 100644 --- a/.github/workflows/update-manual.yml +++ b/.github/workflows/update-manual.yml @@ -17,7 +17,7 @@ jobs: fetch-depth: 0 - name: Install Nix - uses: cachix/install-nix-action@v17 + uses: cachix/install-nix-action@v20 with: extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} From a379f9afe7f80b137d66fbbeeb81da9b29b519da Mon Sep 17 00:00:00 2001 From: Jan Schmitt Date: Fri, 28 Apr 2023 13:26:04 +0200 Subject: [PATCH 011/161] docs: update flake snippet to 22.11 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19b5605b8..87a9786ff 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ A minimal example of using an existing configuration.nix: description = "John's darwin system"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-22.05-darwin"; + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-22.11-darwin"; darwin.url = "github:lnl7/nix-darwin/master"; darwin.inputs.nixpkgs.follows = "nixpkgs"; }; From d222200091f2d739bf811b98056fbd0062ea0789 Mon Sep 17 00:00:00 2001 From: Jan Schmitt Date: Fri, 28 Apr 2023 13:26:11 +0200 Subject: [PATCH 012/161] ci: use latest stable channel 22.05 -> 22.11 * use matrix build to run tests against latest stable and unstable channel * add descriptions to github action steps --- .github/workflows/test.yml | 105 ++++++++++++++++++++++------ .github/workflows/update-manual.yml | 2 +- 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bf5b6498e..57cd01b31 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,33 +2,74 @@ name: "Test" on: pull_request: push: + jobs: tests: + strategy: + fail-fast: true + matrix: + channel: [nixpkgs-22.11-darwin, nixpkgs-unstable] runs-on: macos-12 timeout-minutes: 30 steps: - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 - - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.05-darwin -I darwin=. -A tests - - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.05-darwin -I darwin=. -A manpages - - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.05-darwin -I darwin=. -A examples.simple + - name: Install nix corresponding to latest stable channel + uses: cachix/install-nix-action@v20 + with: + install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + if: ${{ matrix.channel == 'nixpkgs-22.11-darwin' }} + - name: Install nix from current unstable channel + uses: cachix/install-nix-action@v20 + with: + nix_path: nixpkgs=channel:${{ matrix.channel }} + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + if: ${{ matrix.channel == 'nixpkgs-unstable' }} + - run: nix-build ./release.nix -I nixpkgs=channel:${{ matrix.channel }} -I darwin=. -A tests + - run: nix-build ./release.nix -I nixpkgs=channel:${{ matrix.channel }} -I darwin=. -A manpages + - run: nix-build ./release.nix -I nixpkgs=channel:${{ matrix.channel }} -I darwin=. -A examples.simple + install: + strategy: + fail-fast: true + matrix: + channel: [nixpkgs-22.11-darwin, nixpkgs-unstable] runs-on: macos-12 timeout-minutes: 30 steps: - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 - - run: | - nix-channel --add https://nixos.org/channels/nixpkgs-22.05-darwin nixpkgs + - name: Install nix corresponding to latest stable channel + uses: cachix/install-nix-action@v20 + with: + install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install + nix_path: nixpkgs=channel:${{ matrix.channel }} + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + if: ${{ matrix.channel == 'nixpkgs-22.11-darwin' }} + - name: Install nix from current unstable channel + uses: cachix/install-nix-action@v20 + with: + nix_path: nixpkgs=channel:${{ matrix.channel }} + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + if: ${{ matrix.channel == 'nixpkgs-unstable' }} + - name: Install ${{ matrix.channel }} channel + run: | + nix-channel --add https://nixos.org/channels/${{ matrix.channel }} nixpkgs nix-channel --update - - run: | + - name: Install nix-darwin and test + run: | export NIX_PATH=$HOME/.nix-defexpr/channels nix-shell -A installer nix-shell -A installer.check - - run: | + - name: Build and activate default derivation + run: | . /etc/static/bashrc darwin-rebuild switch -I darwin=. - - run: | + - name: Test uninstallation of nix-darwin + run: | export NIX_PATH=$HOME/.nix-defexpr/channels nix-shell -A uninstaller nix-shell -A uninstaller.check @@ -38,30 +79,48 @@ jobs: timeout-minutes: 15 with: limit-access-to-actor: true + install-flake: + strategy: + fail-fast: true + matrix: + channel: [nixpkgs-22.11-darwin, nixpkgs-unstable] runs-on: macos-12 - timeout-minutes: 60 + timeout-minutes: 30 steps: - uses: actions/checkout@v3 + - name: Install nix version corresponding to latest stable channel + uses: cachix/install-nix-action@v20 with: - fetch-depth: 0 - - uses: cachix/install-nix-action@v20 + install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install + nix_path: nixpkgs=channel:${{ matrix.channel }} + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + if: ${{ matrix.channel == 'nixpkgs-22.11-darwin' }} + - name: Install nix from current unstable channel + uses: cachix/install-nix-action@v20 with: - install_url: https://github.com/numtide/nix-flakes-installer/releases/download/nix-2.10.0pre20220808_73fde9e/install - extra_nix_config: | - experimental-features = nix-command flakes - access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - - run: | - nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs + nix_path: nixpkgs=channel:${{ matrix.channel }} + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + if: ${{ matrix.channel == 'nixpkgs-unstable' }} + - name: Install ${{ matrix.channel }} channel + run: | + nix-channel --add https://nixos.org/channels/${{ matrix.channel }} nixpkgs nix-channel --update - - run: | + - name: Install nix-darwin and test result + run: | export NIX_PATH=$HOME/.nix-defexpr/channels nix-shell -A installer - - run: | + nix-shell -A installer.check + - name: Build simple flake configuration + run: | nix build ./modules/examples#darwinConfigurations.simple.system --override-input darwin . - - run: | + - name: Activate derivation of simple flake build + run: | ./result/sw/bin/darwin-rebuild switch --flake ./modules/examples#simple --override-input darwin . - - run: | + - name: Rebuild and activate simple flake, but this time using nix-darwins flake interface + run: | . /etc/static/bashrc darwin-rebuild build --flake ./modules/examples#simple --override-input darwin . - name: Test git submodules diff --git a/.github/workflows/update-manual.yml b/.github/workflows/update-manual.yml index 6ef90ffe8..b6590640f 100644 --- a/.github/workflows/update-manual.yml +++ b/.github/workflows/update-manual.yml @@ -24,7 +24,7 @@ jobs: - name: Build manual run: | - nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.05-darwin -I darwin=. -A manualHTML + nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.11-darwin -I darwin=. -A manualHTML - name: Push update to manual run: | From fad0282b5fc9c05c2751be5df79ddb8c3f1c3452 Mon Sep 17 00:00:00 2001 From: Konrad Malik Date: Sat, 21 Jan 2023 15:01:07 +0100 Subject: [PATCH 013/161] add '://' to built flake uri --- pkgs/nix-tools/darwin-rebuild.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/nix-tools/darwin-rebuild.sh b/pkgs/nix-tools/darwin-rebuild.sh index 25d704fe6..b2b99f013 100644 --- a/pkgs/nix-tools/darwin-rebuild.sh +++ b/pkgs/nix-tools/darwin-rebuild.sh @@ -123,13 +123,13 @@ flakeFlags=(--extra-experimental-features 'nix-command flakes') if [ -n "$flake" ]; then # Offical regex from https://www.rfc-editor.org/rfc/rfc3986#appendix-B if [[ "${flake}" =~ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? ]]; then - scheme=${BASH_REMATCH[2]} - authority=${BASH_REMATCH[4]} - path=${BASH_REMATCH[5]} + scheme=${BASH_REMATCH[2]} # eg. http + authority=${BASH_REMATCH[4]} # eg. www.ics.uci.edu + path=${BASH_REMATCH[5]} # eg. /pub/ietf/uri/ queryWithQuestion=${BASH_REMATCH[6]} fragment=${BASH_REMATCH[9]} - flake=${scheme}${authority}${path}${queryWithQuestion} + flake=${scheme}://${authority}${path}${queryWithQuestion} flakeAttr=${fragment} fi if [ -z "$flakeAttr" ]; then From d0e36622c12f7a7fec2d46d60987f565f4cb3247 Mon Sep 17 00:00:00 2001 From: Konrad Malik Date: Sat, 21 Jan 2023 15:23:40 +0100 Subject: [PATCH 014/161] fix: in URI use proper groups --- pkgs/nix-tools/darwin-rebuild.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/nix-tools/darwin-rebuild.sh b/pkgs/nix-tools/darwin-rebuild.sh index b2b99f013..ca0b266b1 100644 --- a/pkgs/nix-tools/darwin-rebuild.sh +++ b/pkgs/nix-tools/darwin-rebuild.sh @@ -123,13 +123,13 @@ flakeFlags=(--extra-experimental-features 'nix-command flakes') if [ -n "$flake" ]; then # Offical regex from https://www.rfc-editor.org/rfc/rfc3986#appendix-B if [[ "${flake}" =~ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? ]]; then - scheme=${BASH_REMATCH[2]} # eg. http - authority=${BASH_REMATCH[4]} # eg. www.ics.uci.edu + scheme=${BASH_REMATCH[1]} # eg. http: + authority=${BASH_REMATCH[3]} # eg. //www.ics.uci.edu path=${BASH_REMATCH[5]} # eg. /pub/ietf/uri/ queryWithQuestion=${BASH_REMATCH[6]} fragment=${BASH_REMATCH[9]} - flake=${scheme}://${authority}${path}${queryWithQuestion} + flake=${scheme}${authority}${path}${queryWithQuestion} flakeAttr=${fragment} fi if [ -z "$flakeAttr" ]; then From 597c723f1c2b70697f1de84802c25daaf22a166c Mon Sep 17 00:00:00 2001 From: Konrad Malik Date: Wed, 5 Apr 2023 19:14:46 +0200 Subject: [PATCH 015/161] test: added a test to run build with git+file schema Based on a PR by @reckenrode --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cab17e898..21976df5b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -114,3 +114,7 @@ jobs: darwin-rebuild build \ --flake /tmp/test-nix-darwin-submodules?submodules=1#simple \ --override-input darwin . + # Should also succeed + darwin-rebuild build \ + --flake git+file:///tmp/test-nix-darwin-submodules?submodules=1#simple \ + --override-input darwin . From 2303eed571946c367d134dd39d017e3bb3517241 Mon Sep 17 00:00:00 2001 From: Julien Brochet Date: Sun, 23 Apr 2023 14:11:44 +0200 Subject: [PATCH 016/161] feat(screensaver): add support of askForPassword and askForPasswordDelay --- modules/module-list.nix | 1 + modules/system/defaults-write.nix | 3 +++ modules/system/defaults/screensaver.nix | 24 ++++++++++++++++++++++++ tests/system-defaults-write.nix | 4 ++++ 4 files changed, 32 insertions(+) create mode 100644 modules/system/defaults/screensaver.nix diff --git a/modules/module-list.nix b/modules/module-list.nix index 1be337d08..2869f2dc2 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -19,6 +19,7 @@ ./system/defaults/dock.nix ./system/defaults/finder.nix ./system/defaults/screencapture.nix + ./system/defaults/screensaver.nix ./system/defaults/alf.nix ./system/defaults/loginwindow.nix ./system/defaults/magicmouse.nix diff --git a/modules/system/defaults-write.nix b/modules/system/defaults-write.nix index 8d8f57e8d..ac9b0240e 100644 --- a/modules/system/defaults-write.nix +++ b/modules/system/defaults-write.nix @@ -34,6 +34,7 @@ let magicmouse = defaultsToList "com.apple.AppleMultitouchMouse" cfg.magicmouse; magicmouseBluetooth = defaultsToList "com.apple.driver.AppleMultitouchMouse.mouse" cfg.magicmouse; screencapture = defaultsToList "com.apple.screencapture" cfg.screencapture; + screensaver = defaultsToList "com.apple.screensaver" cfg.screensaver; spaces = defaultsToList "com.apple.spaces" cfg.spaces; trackpad = defaultsToList "com.apple.AppleMultitouchTrackpad" cfg.trackpad; trackpadBluetooth = defaultsToList "com.apple.driver.AppleBluetoothMultitouch.trackpad" cfg.trackpad; @@ -84,6 +85,7 @@ in magicmouse magicmouseBluetooth screencapture + screensaver spaces trackpad trackpadBluetooth @@ -104,6 +106,7 @@ in ${concatStringsSep "\n" magicmouse} ${concatStringsSep "\n" magicmouseBluetooth} ${concatStringsSep "\n" screencapture} + ${concatStringsSep "\n" screensaver} ${concatStringsSep "\n" spaces} ${concatStringsSep "\n" trackpad} ${concatStringsSep "\n" trackpadBluetooth} diff --git a/modules/system/defaults/screensaver.nix b/modules/system/defaults/screensaver.nix new file mode 100644 index 000000000..3e5032b5c --- /dev/null +++ b/modules/system/defaults/screensaver.nix @@ -0,0 +1,24 @@ +{ config, lib, ... }: + +with lib; + +{ + options = { + + system.defaults.screensaver.askForPassword = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + If true, the user is prompted for a password when the screen saver is unlocked or stopped. The default is false. + ''; + }; + + system.defaults.screensaver.askForPasswordDelay = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + The number of seconds to delay before the password will be required to unlock or stop the screen saver (the grace period). + ''; + }; + }; +} diff --git a/tests/system-defaults-write.nix b/tests/system-defaults-write.nix index 344c44049..0f94d175f 100644 --- a/tests/system-defaults-write.nix +++ b/tests/system-defaults-write.nix @@ -41,6 +41,8 @@ system.defaults.dock.autohide-delay = 0.24; system.defaults.dock.orientation = "left"; system.defaults.screencapture.location = "/tmp"; + system.defaults.screensaver.askForPassword = true; + system.defaults.screensaver.askForPasswordDelay = 5; system.defaults.smb.NetBIOSName = "IMAC-000000"; system.defaults.smb.ServerDescription = ''Darwin\\\\U2019s iMac''; system.defaults.universalaccess.reduceTransparency = true; @@ -104,6 +106,8 @@ grep "defaults write com.apple.dock 'appswitcher-all-displays' -bool NO" ${config.out}/activate-user grep "defaults write com.apple.dock 'orientation' -string 'left'" ${config.out}/activate-user grep "defaults write com.apple.screencapture 'location' -string '/tmp'" ${config.out}/activate-user + grep "defaults write com.apple.screensaver 'askForPassword' -bool YES" ${config.out}/activate-user + grep "defaults write com.apple.screensaver 'askForPasswordDelay' -int 5" ${config.out}/activate-user grep "defaults write com.apple.universalaccess 'reduceTransparency' -bool YES" ${config.out}/activate-user grep "defaults write com.apple.universalaccess 'closeViewScrollWheelToggle' -bool YES" ${config.out}/activate-user grep "defaults write com.apple.universalaccess 'closeViewZoomFollowsFocus' -bool YES" ${config.out}/activate-user From fa97d795677432ceea46df9a6f609efbe3dbe90c Mon Sep 17 00:00:00 2001 From: Andrew Marshall Date: Thu, 4 May 2023 23:53:14 -0400 Subject: [PATCH 017/161] nix: Fix registry extra attrs not being applied This was mkDefault { } // filterAttrs () x which is interpreted as (mkDefault { }) // (filterAttrs () x) but the intention is mkDefault ({ } // filterAttrs () x) Resulting in lastModified, rev, etc. not being included. This is essentially just bringing this clause up-to-date with the one from NixOS. --- modules/nix/default.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/nix/default.nix b/modules/nix/default.nix index 8a5bb181c..cd66c590a 100644 --- a/modules/nix/default.nix +++ b/modules/nix/default.nix @@ -444,13 +444,14 @@ in }; config = { from = mkDefault { type = "indirect"; id = name; }; - to = mkIf (config.flake != null) (mkDefault + to = mkIf (config.flake != null) (mkDefault ( { type = "path"; path = config.flake.outPath; } // filterAttrs - (n: _: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash") - config.flake); + (n: _: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash") + config.flake + )); }; } )); From da2c0a74ca7aa2472cf2bc819ce8af53530b3bd8 Mon Sep 17 00:00:00 2001 From: Roman Melnikov Date: Wed, 10 May 2023 13:36:03 +0800 Subject: [PATCH 018/161] buildkite-agent: update module Update module to look it similar to what it currently present in 'nixpkgs'. Mainly, to provide support for running multiple buildkite-agents. --- modules/module-list.nix | 2 +- modules/services/buildkite-agent.nix | 253 ---------------------- modules/services/buildkite-agents.nix | 293 ++++++++++++++++++++++++++ tests/services-buildkite-agent.nix | 11 +- 4 files changed, 299 insertions(+), 260 deletions(-) delete mode 100644 modules/services/buildkite-agent.nix create mode 100644 modules/services/buildkite-agents.nix diff --git a/modules/module-list.nix b/modules/module-list.nix index 1be337d08..a226bbaa9 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -44,7 +44,7 @@ ./launchd ./services/activate-system ./services/autossh.nix - ./services/buildkite-agent.nix + ./services/buildkite-agents.nix ./services/chunkwm.nix ./services/cachix-agent.nix ./services/dnsmasq.nix diff --git a/modules/services/buildkite-agent.nix b/modules/services/buildkite-agent.nix deleted file mode 100644 index ace89ec36..000000000 --- a/modules/services/buildkite-agent.nix +++ /dev/null @@ -1,253 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.buildkite-agent; - - mkHookOption = { name, description, example ? null }: { - inherit name; - value = mkOption { - default = null; - inherit description; - type = types.nullOr types.lines; - } // (if example == null then {} else { inherit example; }); - }; - mkHookOptions = hooks: listToAttrs (map mkHookOption hooks); - - hooksDir = let - mkHookEntry = name: value: { - inherit name; - path = pkgs.writeScript "buildkite-agent-hook-${name}" '' - #! ${pkgs.stdenv.shell} - set -e - ${value} - ''; - }; - in pkgs.linkFarm "buildkite-agent-hooks" - (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks)); - -in - -{ - options = { - services.buildkite-agent.enable = mkEnableOption "buildkite-agent"; - - services.buildkite-agent.package = mkOption { - default = pkgs.buildkite-agent; - defaultText = "pkgs.buildkite-agent"; - description = "Which buildkite-agent derivation to use"; - type = types.package; - }; - - services.buildkite-agent.dataDir = mkOption { - default = "/var/lib/buildkite-agent"; - description = "The workdir for the agent"; - type = types.str; - }; - - services.buildkite-agent.runtimePackages = mkOption { - default = [ pkgs.bash pkgs.nix ]; - defaultText = "[ pkgs.bash pkgs.nix ]"; - description = "Add programs to the buildkite-agent environment"; - type = types.listOf types.package; - }; - - services.buildkite-agent.tokenPath = mkOption { - type = types.path; - description = '' - The token from your Buildkite "Agents" page. - - A run-time path to the token file, which is supposed to be provisioned - outside of Nix store. - ''; - }; - - services.buildkite-agent.name = mkOption { - type = types.str; - default = "%hostname-%n"; - description = '' - The name of the agent. - ''; - }; - - services.buildkite-agent.meta-data = mkOption { - type = types.str; - default = ""; - example = "queue=default,docker=true,ruby2=true"; - description = '' - Meta data for the agent. This is a comma-separated list of - key=value pairs. - ''; - }; - - services.buildkite-agent.extraConfig = mkOption { - type = types.lines; - default = ""; - example = "debug=true"; - description = '' - Extra lines to be added verbatim to the configuration file. - ''; - }; - services.buildkite-agent.preCommands = mkOption { - type = types.lines; - default = ""; - description = '' - Extra commands to run before starting buildkite. - ''; - }; - - services.buildkite-agent.openssh = - { privateKeyPath = mkOption { - type = types.path; - description = '' - Private agent key. - - A run-time path to the key file, which is supposed to be provisioned - outside of Nix store. - ''; - }; - publicKeyPath = mkOption { - type = types.path; - description = '' - Public agent key. - - A run-time path to the key file, which is supposed to be provisioned - outside of Nix store. - ''; - }; - }; - - services.buildkite-agent.hooks = mkHookOptions [ - { name = "checkout"; - description = '' - The `checkout` hook script will replace the default checkout routine of the - bootstrap.sh script. You can use this hook to do your own SCM checkout - behaviour - ''; } - { name = "command"; - description = '' - The `command` hook script will replace the default implementation of running - the build command. - ''; } - { name = "environment"; - description = '' - The `environment` hook will run before all other commands, and can be used - to set up secrets, data, etc. Anything exported in hooks will be available - to the build script. - - Note: the contents of this file will be copied to the world-readable - Nix store. - ''; - example = '' - export SECRET_VAR=`head -1 /run/keys/secret` - ''; } - { name = "post-artifact"; - description = '' - The `post-artifact` hook will run just after artifacts are uploaded - ''; } - { name = "post-checkout"; - description = '' - The `post-checkout` hook will run after the bootstrap script has checked out - your projects source code. - ''; } - { name = "post-command"; - description = '' - The `post-command` hook will run after the bootstrap script has run your - build commands - ''; } - { name = "pre-artifact"; - description = '' - The `pre-artifact` hook will run just before artifacts are uploaded - ''; } - { name = "pre-checkout"; - description = '' - The `pre-checkout` hook will run just before your projects source code is - checked out from your SCM provider - ''; } - { name = "pre-command"; - description = '' - The `pre-command` hook will run just before your build command runs - ''; } - { name = "pre-exit"; - description = '' - The `pre-exit` hook will run just before your build job finishes - ''; } - ]; - }; - - config = mkIf config.services.buildkite-agent.enable { - users.users.buildkite-agent = - { name = "buildkite-agent"; - home = cfg.dataDir; - description = "Buildkite agent user"; - }; - users.groups.buildkite-agent = - { name = "buildkite-agent"; - description = "Buildkite agent user group"; - }; - - environment.systemPackages = [ cfg.package ]; - - launchd.daemons.buildkite-agent = - { - path = cfg.runtimePackages ++ [ pkgs.coreutils cfg.package ] - ++ (if pkgs.stdenv.isDarwin then [ pkgs.darwin.DarwinTools ] else []); - environment = { - HOME = cfg.dataDir; - NIX_SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; - } // (if config.nix.useDaemon then { NIX_REMOTE = "daemon"; } else {}); - - ## NB: maximum care is taken so that secrets (ssh keys and the CI token) - ## don't end up in the Nix store. - script = let - sshDir = "${cfg.dataDir}/.ssh"; - in - '' - mkdir -m 0700 -p "${sshDir}" - cp -f "${toString cfg.openssh.privateKeyPath}" "${sshDir}/id_rsa" - cp -f "${toString cfg.openssh.publicKeyPath}" "${sshDir}/id_rsa.pub" - chmod 600 "${sshDir}"/id_rsa* - - cat > "${cfg.dataDir}/buildkite-agent.cfg" < $out/${name} <<'EOF' + #! ${pkgs.runtimeShell} + set -e + ${value} + EOF + chmod 755 $out/${name} + ''; + in pkgs.runCommand "buildkite-agent-hooks" { preferLocalBuild = true; } '' + mkdir $out + ${concatStringsSep "\n" (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks))} + ''; + + buildkiteOptions = { name ? "", config, ... }: { + options = { + enable = mkOption { + default = true; + type = types.bool; + description = mdDoc "Whether to enable this buildkite agent"; + }; + + package = mkOption { + default = pkgs.buildkite-agent; + defaultText = literalExpression "pkgs.buildkite-agent"; + description = mdDoc "Which buildkite-agent derivation to use"; + type = types.package; + }; + + dataDir = mkOption { + default = "/var/lib/buildkite-agent-${name}"; + description = mdDoc "The workdir for the agent"; + type = types.str; + }; + + runtimePackages = mkOption { + default = [ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]; + defaultText = literalExpression "[ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]"; + description = mdDoc "Add programs to the buildkite-agent environment"; + type = types.listOf types.package; + }; + + tokenPath = mkOption { + type = types.path; + description = mdDoc '' + The token from your Buildkite "Agents" page. + + A run-time path to the token file, which is supposed to be provisioned + outside of Nix store. + ''; + }; + + name = mkOption { + type = types.str; + default = "%hostname-${name}-%n"; + description = mdDoc '' + The name of the agent as seen in the buildkite dashboard. + ''; + }; + + tags = mkOption { + type = types.attrsOf (types.either types.str (types.listOf types.str)); + default = {}; + example = { queue = "default"; docker = "true"; ruby2 ="true"; }; + description = mdDoc '' + Tags for the agent. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = "debug=true"; + description = mdDoc '' + Extra lines to be added verbatim to the configuration file. + ''; + }; + + preCommands = mkOption { + type = types.lines; + default = ""; + description = '' + Extra commands to run before starting buildkite. + ''; + }; + + privateSshKeyPath = mkOption { + type = types.nullOr types.path; + default = null; + ## maximum care is taken so that secrets (ssh keys and the CI token) + ## don't end up in the Nix store. + apply = final: if final == null then null else toString final; + + description = mdDoc '' + OpenSSH private key + + A run-time path to the key file, which is supposed to be provisioned + outside of Nix store. + ''; + }; + + hooks = mkHookOptions [ + { name = "checkout"; + description = '' + The `checkout` hook script will replace the default checkout routine of the + bootstrap.sh script. You can use this hook to do your own SCM checkout + behaviour + ''; } + { name = "command"; + description = '' + The `command` hook script will replace the default implementation of running + the build command. + ''; } + { name = "environment"; + description = '' + The `environment` hook will run before all other commands, and can be used + to set up secrets, data, etc. Anything exported in hooks will be available + to the build script. + + Note: the contents of this file will be copied to the world-readable + Nix store. + ''; + example = '' + export SECRET_VAR=`head -1 /run/keys/secret` + ''; } + { name = "post-artifact"; + description = '' + The `post-artifact` hook will run just after artifacts are uploaded + ''; } + { name = "post-checkout"; + description = '' + The `post-checkout` hook will run after the bootstrap script has checked out + your projects source code. + ''; } + { name = "post-command"; + description = '' + The `post-command` hook will run after the bootstrap script has run your + build commands + ''; } + { name = "pre-artifact"; + description = '' + The `pre-artifact` hook will run just before artifacts are uploaded + ''; } + { name = "pre-checkout"; + description = '' + The `pre-checkout` hook will run just before your projects source code is + checked out from your SCM provider + ''; } + { name = "pre-command"; + description = '' + The `pre-command` hook will run just before your build command runs + ''; } + { name = "pre-exit"; + description = '' + The `pre-exit` hook will run just before your build job finishes + ''; } + ]; + + hooksPath = mkOption { + type = types.path; + default = hooksDir config; + defaultText = literalMD "generated from {option}`services.buildkite-agents..hooks`"; + description = mdDoc '' + Path to the directory storing the hooks. + Consider using {option}`services.buildkite-agents..hooks.` + instead. + ''; + }; + + shell = mkOption { + type = types.str; + default = "${pkgs.bash}/bin/bash -e -c"; + defaultText = literalExpression ''"''${pkgs.bash}/bin/bash -e -c"''; + description = mdDoc '' + Command that buildkite-agent 3 will execute when it spawns a shell. + ''; + }; + }; + }; + enabledAgents = lib.filterAttrs (n: v: v.enable) cfg; + mapAgents = function: lib.mkMerge (lib.mapAttrsToList function enabledAgents); +in +{ + options.services.buildkite-agents = mkOption { + type = types.attrsOf (types.submodule buildkiteOptions); + default = {}; + description = mdDoc '' + Attribute set of buildkite agents. + The attribute key is combined with the hostname and a unique integer to + create the final agent name. This can be overridden by setting the `name` + attribute. + ''; + }; + + config.users.users = mapAgents (name: cfg: { + "buildkite-agent-${name}" = { + name = "buildkite-agent-${name}"; + home = cfg.dataDir; + createHome = true; + description = "Buildkite agent user"; + }; + }); + config.users.groups = mapAgents (name: cfg: { + "buildkite-agent-${name}" = {}; + }); + + config.launchd.daemons = mapAgents (name: cfg: { + "buildkite-agent-${name}" = + { path = cfg.runtimePackages ++ [ cfg.package pkgs.coreutils pkgs.darwin.DarwinTools ]; + environment = { + HOME = cfg.dataDir; + }// (if config.nix.useDaemon then { NIX_REMOTE = "daemon"; } else {}); + + ## NB: maximum care is taken so that secrets (ssh keys and the CI token) + ## don't end up in the Nix store. + script = let + sshDir = "${cfg.dataDir}/.ssh"; + tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags); + in + optionalString (cfg.privateSshKeyPath != null) '' + mkdir -m 0700 -p "${sshDir}" + install -m600 "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa" + '' + '' + cat > "${cfg.dataDir}/buildkite-agent.cfg" <' are mutually exclusive. + ''; + } + ]); + + imports = [ + (mkRemovedOptionModule [ "services" "buildkite-agent"] "services.buildkite-agent has been moved to an attribute set at services.buildkite-agents") + ]; +} diff --git a/tests/services-buildkite-agent.nix b/tests/services-buildkite-agent.nix index 4ca89b8f1..557aad233 100644 --- a/tests/services-buildkite-agent.nix +++ b/tests/services-buildkite-agent.nix @@ -6,22 +6,21 @@ let in { - services.buildkite-agent = { + services.buildkite-agents.test = { enable = true; package = buildkite-agent; extraConfig = "yolo=1"; - openssh.privateKeyPath = "/dev/null"; - openssh.publicKeyPath = "/dev/null"; + privateSshKeyPath = "/dev/null"; hooks.command = "echo test hook"; inherit tokenPath; }; test = '' - echo "checking buildkite-agent service in /Library/LaunchDaemons" >&2 - grep "org.nixos.buildkite-agent" ${config.out}/Library/LaunchDaemons/org.nixos.buildkite-agent.plist + echo "checking buildkite-agent-test service in /Library/LaunchDaemons" >&2 + grep "org.nixos.buildkite-agent-test" ${config.out}/Library/LaunchDaemons/org.nixos.buildkite-agent-test.plist echo "checking creation of buildkite-agent service config" >&2 - script=$(cat ${config.out}/Library/LaunchDaemons/org.nixos.buildkite-agent.plist | awk -F'[< ]' '$3 ~ "^/nix/store/.*" {print $3}') + script=$(cat ${config.out}/Library/LaunchDaemons/org.nixos.buildkite-agent-test.plist | awk -F'[< ]' '$3 ~ "^/nix/store/.*" {print $3}') grep "yolo=1" "$script" grep "${tokenPath}" "$script" From 64a15676ac5b7cb8990d683f19ad78ac9a6bc4ef Mon Sep 17 00:00:00 2001 From: sbh69840 Date: Tue, 9 May 2023 15:57:49 +0530 Subject: [PATCH 019/161] support authorized_keys for users --- modules/lib/write-text.nix | 8 +++++ modules/programs/ssh/default.nix | 61 ++++++++++++++++++++++++++++---- modules/system/etc.nix | 14 ++++++-- 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/modules/lib/write-text.nix b/modules/lib/write-text.nix index ddf407691..2fe02aff7 100644 --- a/modules/lib/write-text.nix +++ b/modules/lib/write-text.nix @@ -45,6 +45,14 @@ in ''; }; + copy = mkOption { + type = types.bool; + default = false; + description = '' + Whether this file should be copied instead of symlinking. + ''; + }; + knownSha256Hashes = mkOption { internal = true; type = types.listOf types.str; diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix index f93890fbc..2c0117c3c 100644 --- a/modules/programs/ssh/default.nix +++ b/modules/programs/ssh/default.nix @@ -47,10 +47,56 @@ let hostNames = mkDefault [ name ]; }; }; + userOptions = { + + options.openssh.authorizedKeys = { + keys = mkOption { + type = types.listOf types.str; + default = []; + description = '' + A list of verbatim OpenSSH public keys that should be added to the + user's authorized keys. The keys are added to a file that the SSH + daemon reads in addition to the the user's authorized_keys file. + You can combine the keys and + keyFiles options. + Warning: If you are using NixOps then don't use this + option since it will replace the key required for deployment via ssh. + ''; + }; + + keyFiles = mkOption { + type = types.listOf types.path; + default = []; + description = '' + A list of files each containing one OpenSSH public key that should be + added to the user's authorized keys. The contents of the files are + read at build time and added to a file that the SSH daemon reads in + addition to the the user's authorized_keys file. You can combine the + keyFiles and keys options. + ''; + }; + }; + + }; + authKeysFiles = let + mkAuthKeyFile = u: nameValuePair "ssh/authorized_keys.d/${u.name}" { + text = '' + ${concatStringsSep "\n" u.openssh.authorizedKeys.keys} + ${concatMapStrings (f: readFile f + "\n") u.openssh.authorizedKeys.keyFiles} + ''; + }; + usersWithKeys = attrValues (flip filterAttrs config.users.users (n: u: + length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0 + )); + in listToAttrs (map mkAuthKeyFile usersWithKeys); in { options = { + + users.users = mkOption { + type = with types; attrsOf (submodule userOptions); + }; programs.ssh.knownHosts = mkOption { default = {}; @@ -80,12 +126,13 @@ in (data.publicKey != null && data.publicKeyFile == null); message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; }); - - environment.etc."ssh/ssh_known_hosts".text = (flip (concatMapStringsSep "\n") knownHosts - (h: assert h.hostNames != []; - concatStringsSep "," h.hostNames + " " - + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) - )) + "\n"; - + + environment.etc = authKeysFiles // + { "ssh/ssh_known_hosts".text = (flip (concatMapStringsSep "\n") knownHosts + (h: assert h.hostNames != []; + concatStringsSep "," h.hostNames + " " + + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) + )) + "\n"; + }; }; } diff --git a/modules/system/etc.nix b/modules/system/etc.nix index cccb2b032..a27e49ec0 100644 --- a/modules/system/etc.nix +++ b/modules/system/etc.nix @@ -12,6 +12,7 @@ let hasDir = path: length (splitString "/" path) > 1; etc = filter (f: f.enable) (attrValues config.environment.etc); + etcCopy = filter (f: f.copy) (attrValues config.environment.etc); etcDirs = filter (attr: hasDir attr.target) (attrValues config.environment.etc); in @@ -38,6 +39,7 @@ in cd $out/etc ${concatMapStringsSep "\n" (attr: "mkdir -p $(dirname '${attr.target}')") etc} ${concatMapStringsSep "\n" (attr: "ln -s '${attr.source}' '${attr.target}'") etc} + ${concatMapStringsSep "\n" (attr: "touch '${attr.target}'.copy") etcCopy} ''; system.activationScripts.etc.text = '' @@ -63,7 +65,11 @@ in for h in ''${etcSha256Hashes["$l"]}; do if [ "$o" = "$h" ]; then mv "$l" "$l.orig" - ln -s "$f" "$l" + if [ -e "$f".copy ]; then + cp "$f" "$l" + else + ln -s "$f" "$l" + fi break else h= @@ -77,7 +83,11 @@ in fi fi else - ln -s "$f" "$l" + if [ -e "$f".copy ]; then + cp "$f" "$l" + else + ln -s "$f" "$l" + fi fi done From ecb5840f6bc2cdb453bbc0dbbd8f63ec441808d6 Mon Sep 17 00:00:00 2001 From: sbh69840 Date: Wed, 10 May 2023 19:35:23 +0530 Subject: [PATCH 020/161] enable copy --- modules/programs/ssh/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix index 2c0117c3c..7797e4d3e 100644 --- a/modules/programs/ssh/default.nix +++ b/modules/programs/ssh/default.nix @@ -80,6 +80,7 @@ let }; authKeysFiles = let mkAuthKeyFile = u: nameValuePair "ssh/authorized_keys.d/${u.name}" { + copy = true; text = '' ${concatStringsSep "\n" u.openssh.authorizedKeys.keys} ${concatMapStrings (f: readFile f + "\n") u.openssh.authorizedKeys.keyFiles} From ccaa942888f53404b56d979cb3a0a5c9f18a1faa Mon Sep 17 00:00:00 2001 From: sbh69840 Date: Wed, 10 May 2023 20:03:21 +0530 Subject: [PATCH 021/161] don't check knownSha256 for authorized_keys files --- modules/system/etc.nix | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/modules/system/etc.nix b/modules/system/etc.nix index a27e49ec0..4b45e3a31 100644 --- a/modules/system/etc.nix +++ b/modules/system/etc.nix @@ -57,6 +57,10 @@ in if [ ! -e "$d" ]; then mkdir -p "$d" fi + if [ -e "$f".copy ]; then + cp "$f" "$l" + continue + fi if [ -e "$l" ]; then if [ "$(readlink "$l")" != "$f" ]; then if ! grep -q /etc/static "$l"; then @@ -65,11 +69,7 @@ in for h in ''${etcSha256Hashes["$l"]}; do if [ "$o" = "$h" ]; then mv "$l" "$l.orig" - if [ -e "$f".copy ]; then - cp "$f" "$l" - else - ln -s "$f" "$l" - fi + ln -s "$f" "$l" break else h= @@ -83,11 +83,7 @@ in fi fi else - if [ -e "$f".copy ]; then - cp "$f" "$l" - else - ln -s "$f" "$l" - fi + ln -s "$f" "$l" fi done From ab2e16159f5a04fd962f3d7de8dc4901d048db17 Mon Sep 17 00:00:00 2001 From: sbh69840 Date: Wed, 10 May 2023 21:16:52 +0530 Subject: [PATCH 022/161] authkeys path in sshd_config --- modules/programs/ssh/default.nix | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix index 7797e4d3e..b8baec6bf 100644 --- a/modules/programs/ssh/default.nix +++ b/modules/programs/ssh/default.nix @@ -90,6 +90,13 @@ let length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0 )); in listToAttrs (map mkAuthKeyFile usersWithKeys); + authKeysConfiguration = + { + "ssh/sshd_config.d/101-authorized-keys.conf" = { + copy = true; + text = "AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u"; + }; + }; in { @@ -128,7 +135,7 @@ in message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; }); - environment.etc = authKeysFiles // + environment.etc = authKeysFiles // authKeysConfiguration // { "ssh/ssh_known_hosts".text = (flip (concatMapStringsSep "\n") knownHosts (h: assert h.hostNames != []; concatStringsSep "," h.hostNames + " " From 4094dbccde0d00fd062d365b8c79526711a6bc95 Mon Sep 17 00:00:00 2001 From: sbh69840 Date: Wed, 10 May 2023 21:30:35 +0530 Subject: [PATCH 023/161] newline eof for authorized-keys conf --- modules/programs/ssh/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix index b8baec6bf..2d008df59 100644 --- a/modules/programs/ssh/default.nix +++ b/modules/programs/ssh/default.nix @@ -94,7 +94,7 @@ let { "ssh/sshd_config.d/101-authorized-keys.conf" = { copy = true; - text = "AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u"; + text = "AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u\n"; }; }; in From f781cb0ac5ea2daa5183b8df8f4de4ef0747f440 Mon Sep 17 00:00:00 2001 From: sbh69840 Date: Wed, 10 May 2023 21:39:27 +0530 Subject: [PATCH 024/161] give credits --- modules/programs/ssh/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix index 2d008df59..f1dde9ae9 100644 --- a/modules/programs/ssh/default.nix +++ b/modules/programs/ssh/default.nix @@ -47,6 +47,7 @@ let hostNames = mkDefault [ name ]; }; }; + # Taken from: https://github.com/NixOS/nixpkgs/blob/f4aa6afa5f934ece2d1eb3157e392d056be01617/nixos/modules/services/networking/ssh/sshd.nix#L46-L93 userOptions = { options.openssh.authorizedKeys = { From 3d22883cdb4226306be7583f5513b3ca23a72e24 Mon Sep 17 00:00:00 2001 From: sbh69840 Date: Sun, 14 May 2023 13:20:13 +0530 Subject: [PATCH 025/161] add tests --- tests/programs-ssh.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/programs-ssh.nix b/tests/programs-ssh.nix index 71f285c08..2928cfb63 100644 --- a/tests/programs-ssh.nix +++ b/tests/programs-ssh.nix @@ -6,9 +6,15 @@ publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=="; }; }; + users.users.foo.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAA..." ]; test = '' echo >&2 "checking for github.com in /etc/ssh/ssh_known_hosts" grep 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' ${config.out}/etc/ssh/ssh_known_hosts + + echo >&2 "checking for authorized keys for foo in /etc/ssh/authorized_keys.d/foo" + grep 'ssh-ed25519 AAAA...' ${config.out}/etc/ssh/authorized_keys.d/foo + echo >&2 "checking for authorized keys' path in /etc/ssh/sshd_config.d/101-authorized-keys.conf" + grep 'AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u' ${config.out}/etc/ssh/sshd_config.d/101-authorized-keys.conf ''; } From f6b7489ddb316eb2b331e2f3a5ef43e11d8eff34 Mon Sep 17 00:00:00 2001 From: Hraban Luyat Date: Sat, 29 Apr 2023 23:09:11 -0400 Subject: [PATCH 026/161] feat: defaults write com.apple.menuextra.clock --- modules/module-list.nix | 1 + modules/system/defaults-write.nix | 3 ++ modules/system/defaults/clock.nix | 71 +++++++++++++++++++++++++++++++ tests/system-defaults-write.nix | 6 +++ 4 files changed, 81 insertions(+) create mode 100644 modules/system/defaults/clock.nix diff --git a/modules/module-list.nix b/modules/module-list.nix index 5cc6d2b91..034ea767a 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -16,6 +16,7 @@ ./system/defaults/NSGlobalDomain.nix ./system/defaults/GlobalPreferences.nix ./system/defaults/CustomPreferences.nix + ./system/defaults/clock.nix ./system/defaults/dock.nix ./system/defaults/finder.nix ./system/defaults/screencapture.nix diff --git a/modules/system/defaults-write.nix b/modules/system/defaults-write.nix index ac9b0240e..9bf19635b 100644 --- a/modules/system/defaults-write.nix +++ b/modules/system/defaults-write.nix @@ -29,6 +29,7 @@ let GlobalPreferences = defaultsToList ".GlobalPreferences" cfg.".GlobalPreferences"; LaunchServices = defaultsToList "com.apple.LaunchServices" cfg.LaunchServices; NSGlobalDomain = defaultsToList "-g" cfg.NSGlobalDomain; + clock = defaultsToList "com.apple.menuextra.clock" cfg.clock; dock = defaultsToList "com.apple.dock" cfg.dock; finder = defaultsToList "com.apple.finder" cfg.finder; magicmouse = defaultsToList "com.apple.AppleMultitouchMouse" cfg.magicmouse; @@ -80,6 +81,7 @@ in GlobalPreferences LaunchServices NSGlobalDomain + clock dock finder magicmouse @@ -101,6 +103,7 @@ in ${concatStringsSep "\n" GlobalPreferences} ${concatStringsSep "\n" LaunchServices} + ${concatStringsSep "\n" clock} ${concatStringsSep "\n" dock} ${concatStringsSep "\n" finder} ${concatStringsSep "\n" magicmouse} diff --git a/modules/system/defaults/clock.nix b/modules/system/defaults/clock.nix new file mode 100644 index 000000000..9ec0471b5 --- /dev/null +++ b/modules/system/defaults/clock.nix @@ -0,0 +1,71 @@ +{ config, lib, ... }: + +with lib; + +{ + options = { + + system.defaults.clock.IsAnalog = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Show an analog clock instead of a digital one. Default is null. + ''; + }; + + system.defaults.clock.Show24Hour = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Show a 24-hour clock, instead of a 12-hour clock. Default is null. + ''; + }; + + system.defaults.clock.ShowAMPM = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Show the AM/PM label. Useful if Show24Hour is false. Default is null. + ''; + }; + + system.defaults.clock.ShowDayOfMonth = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Show the day of the month. Default is null. + ''; + }; + + system.defaults.clock.ShowDayOfWeek = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Show the day of the week. Default is null. + ''; + }; + + system.defaults.clock.ShowDate = mkOption { + type = types.nullOr (types.enum [ 0 1 2 ]); + default = null; + description = '' + Show the full date. Default is null. + + 0 = Show the date + 1 = Don't show + 2 = Don't show + + TODO: I don't know what the difference is between 1 and 2. + ''; + }; + + system.defaults.clock.ShowSeconds = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Show the clock with second precision, instead of minutes. Default is null. + ''; + }; + + }; +} diff --git a/tests/system-defaults-write.nix b/tests/system-defaults-write.nix index 0f94d175f..5ba4ae54c 100644 --- a/tests/system-defaults-write.nix +++ b/tests/system-defaults-write.nix @@ -37,6 +37,9 @@ system.defaults.NSGlobalDomain."com.apple.springing.delay" = 0.0; system.defaults.NSGlobalDomain."com.apple.swipescrolldirection" = true; system.defaults.".GlobalPreferences"."com.apple.sound.beep.sound" = "/System/Library/Sounds/Funk.aiff"; + system.defaults.clock.Show24Hour = false; + system.defaults.clock.ShowDayOfWeek = true; + system.defaults.clock.ShowDate = 2; system.defaults.dock.appswitcher-all-displays = false; system.defaults.dock.autohide-delay = 0.24; system.defaults.dock.orientation = "left"; @@ -102,6 +105,9 @@ grep "defaults write -g 'com.apple.springing.delay' -float 0.0" ${config.out}/activate-user grep "defaults write -g 'com.apple.swipescrolldirection' -bool YES" ${config.out}/activate-user grep "defaults write .GlobalPreferences 'com.apple.sound.beep.sound' -string '/System/Library/Sounds/Funk.aiff'" ${config.out}/activate-user + grep "defaults write com.apple.menuextra.clock 'Show24Hour' -bool NO" ${config.out}/activate-user + grep "defaults write com.apple.menuextra.clock 'ShowDayOfWeek' -bool YES" ${config.out}/activate-user + grep "defaults write com.apple.menuextra.clock 'ShowDate' -int 2" ${config.out}/activate-user grep "defaults write com.apple.dock 'autohide-delay' -float 0.24" ${config.out}/activate-user grep "defaults write com.apple.dock 'appswitcher-all-displays' -bool NO" ${config.out}/activate-user grep "defaults write com.apple.dock 'orientation' -string 'left'" ${config.out}/activate-user From f1a562eef19a042a1b2693e412a1f95aad11eab6 Mon Sep 17 00:00:00 2001 From: Hraban Luyat Date: Mon, 15 May 2023 13:18:38 -0400 Subject: [PATCH 027/161] refactor: rename clock option menuExtraClock --- modules/system/defaults-write.nix | 6 +++--- modules/system/defaults/clock.nix | 14 +++++++------- tests/system-defaults-write.nix | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/system/defaults-write.nix b/modules/system/defaults-write.nix index 9bf19635b..9502f429c 100644 --- a/modules/system/defaults-write.nix +++ b/modules/system/defaults-write.nix @@ -29,7 +29,7 @@ let GlobalPreferences = defaultsToList ".GlobalPreferences" cfg.".GlobalPreferences"; LaunchServices = defaultsToList "com.apple.LaunchServices" cfg.LaunchServices; NSGlobalDomain = defaultsToList "-g" cfg.NSGlobalDomain; - clock = defaultsToList "com.apple.menuextra.clock" cfg.clock; + menuExtraClock = defaultsToList "com.apple.menuextra.clock" cfg.menuExtraClock; dock = defaultsToList "com.apple.dock" cfg.dock; finder = defaultsToList "com.apple.finder" cfg.finder; magicmouse = defaultsToList "com.apple.AppleMultitouchMouse" cfg.magicmouse; @@ -81,7 +81,7 @@ in GlobalPreferences LaunchServices NSGlobalDomain - clock + menuExtraClock dock finder magicmouse @@ -103,7 +103,7 @@ in ${concatStringsSep "\n" GlobalPreferences} ${concatStringsSep "\n" LaunchServices} - ${concatStringsSep "\n" clock} + ${concatStringsSep "\n" menuExtraClock} ${concatStringsSep "\n" dock} ${concatStringsSep "\n" finder} ${concatStringsSep "\n" magicmouse} diff --git a/modules/system/defaults/clock.nix b/modules/system/defaults/clock.nix index 9ec0471b5..ef2cac48a 100644 --- a/modules/system/defaults/clock.nix +++ b/modules/system/defaults/clock.nix @@ -5,7 +5,7 @@ with lib; { options = { - system.defaults.clock.IsAnalog = mkOption { + system.defaults.menuExtraClock.IsAnalog = mkOption { type = types.nullOr types.bool; default = null; description = '' @@ -13,7 +13,7 @@ with lib; ''; }; - system.defaults.clock.Show24Hour = mkOption { + system.defaults.menuExtraClock.Show24Hour = mkOption { type = types.nullOr types.bool; default = null; description = '' @@ -21,7 +21,7 @@ with lib; ''; }; - system.defaults.clock.ShowAMPM = mkOption { + system.defaults.menuExtraClock.ShowAMPM = mkOption { type = types.nullOr types.bool; default = null; description = '' @@ -29,7 +29,7 @@ with lib; ''; }; - system.defaults.clock.ShowDayOfMonth = mkOption { + system.defaults.menuExtraClock.ShowDayOfMonth = mkOption { type = types.nullOr types.bool; default = null; description = '' @@ -37,7 +37,7 @@ with lib; ''; }; - system.defaults.clock.ShowDayOfWeek = mkOption { + system.defaults.menuExtraClock.ShowDayOfWeek = mkOption { type = types.nullOr types.bool; default = null; description = '' @@ -45,7 +45,7 @@ with lib; ''; }; - system.defaults.clock.ShowDate = mkOption { + system.defaults.menuExtraClock.ShowDate = mkOption { type = types.nullOr (types.enum [ 0 1 2 ]); default = null; description = '' @@ -59,7 +59,7 @@ with lib; ''; }; - system.defaults.clock.ShowSeconds = mkOption { + system.defaults.menuExtraClock.ShowSeconds = mkOption { type = types.nullOr types.bool; default = null; description = '' diff --git a/tests/system-defaults-write.nix b/tests/system-defaults-write.nix index 5ba4ae54c..1c21ca854 100644 --- a/tests/system-defaults-write.nix +++ b/tests/system-defaults-write.nix @@ -37,9 +37,9 @@ system.defaults.NSGlobalDomain."com.apple.springing.delay" = 0.0; system.defaults.NSGlobalDomain."com.apple.swipescrolldirection" = true; system.defaults.".GlobalPreferences"."com.apple.sound.beep.sound" = "/System/Library/Sounds/Funk.aiff"; - system.defaults.clock.Show24Hour = false; - system.defaults.clock.ShowDayOfWeek = true; - system.defaults.clock.ShowDate = 2; + system.defaults.menuExtraClock.Show24Hour = false; + system.defaults.menuExtraClock.ShowDayOfWeek = true; + system.defaults.menuExtraClock.ShowDate = 2; system.defaults.dock.appswitcher-all-displays = false; system.defaults.dock.autohide-delay = 0.24; system.defaults.dock.orientation = "left"; From 6236fd19231394d74520274c457fd72cab569ab3 Mon Sep 17 00:00:00 2001 From: Roman Melnikov Date: Tue, 16 May 2023 15:58:30 +0800 Subject: [PATCH 028/161] buildkite-agent: allow 'types.path' in runtimePackages This might be useful when some non-nix packages need to be provided, e.g. 'brew'. --- modules/services/buildkite-agents.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/services/buildkite-agents.nix b/modules/services/buildkite-agents.nix index a8931bd11..7486161ce 100644 --- a/modules/services/buildkite-agents.nix +++ b/modules/services/buildkite-agents.nix @@ -56,7 +56,7 @@ let default = [ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]; defaultText = literalExpression "[ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]"; description = mdDoc "Add programs to the buildkite-agent environment"; - type = types.listOf types.package; + type = types.listOf (types.either types.package types.path); }; tokenPath = mkOption { From bc776e4940106a2578998dd3117a76d62ec0a8cc Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Wed, 19 Apr 2023 16:55:22 -0400 Subject: [PATCH 029/161] Match nixos handling of fonts.fonts by looking for .ttf, .ttc, and .otf files in any directory in the passed packages --- modules/fonts/default.nix | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/fonts/default.nix b/modules/fonts/default.nix index 0f4c269fd..9b33db0f0 100644 --- a/modules/fonts/default.nix +++ b/modules/fonts/default.nix @@ -33,13 +33,12 @@ in config = { system.build.fonts = pkgs.runCommand "fonts" - { paths = cfg.fonts; preferLocalBuild = true; } + { preferLocalBuild = true; } '' mkdir -p $out/Library/Fonts - for path in $paths; do - find -L $path/share/fonts -type f -print0 | while IFS= read -rd "" f; do - ln -sf "$f" $out/Library/Fonts - done + font_regexp='.*\.\(ttf\|ttc\|otf\)' + find -L ${toString cfg.fonts} -regex "$font_regexp" -type f -print0 | while IFS= read -rd "" f; do + ln -sf "$f" $out/Library/Fonts done ''; From ebdd18cdc169f680a1385c0d26dfe92dc5062ade Mon Sep 17 00:00:00 2001 From: Jan Schmitt Date: Fri, 19 May 2023 13:33:38 +0200 Subject: [PATCH 030/161] ci: refactor to several jobs to enable optional checks --- .github/workflows/test.yml | 167 +++++++++++++++++++++++++++++-------- 1 file changed, 133 insertions(+), 34 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 57cd01b31..c117a190e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,12 +3,11 @@ on: pull_request: push: +env: + CURRENT_STABLE_CHANNEL: nixpkgs-22.11-darwin + jobs: - tests: - strategy: - fail-fast: true - matrix: - channel: [nixpkgs-22.11-darwin, nixpkgs-unstable] + test-stable: runs-on: macos-12 timeout-minutes: 30 steps: @@ -19,23 +18,26 @@ jobs: install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.channel == 'nixpkgs-22.11-darwin' }} + - run: nix-build ./release.nix -I nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} -I darwin=. -A tests + - run: nix-build ./release.nix -I nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} -I darwin=. -A manpages + - run: nix-build ./release.nix -I nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} -I darwin=. -A examples.simple + + test-unstable: + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 - name: Install nix from current unstable channel uses: cachix/install-nix-action@v20 with: - nix_path: nixpkgs=channel:${{ matrix.channel }} + nix_path: nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.channel == 'nixpkgs-unstable' }} - - run: nix-build ./release.nix -I nixpkgs=channel:${{ matrix.channel }} -I darwin=. -A tests - - run: nix-build ./release.nix -I nixpkgs=channel:${{ matrix.channel }} -I darwin=. -A manpages - - run: nix-build ./release.nix -I nixpkgs=channel:${{ matrix.channel }} -I darwin=. -A examples.simple - - install: - strategy: - fail-fast: true - matrix: - channel: [nixpkgs-22.11-darwin, nixpkgs-unstable] + - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-unstable -I darwin=. -A tests + - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-unstable -I darwin=. -A manpages + - run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-unstable -I darwin=. -A examples.simple + + install-against-stable: runs-on: macos-12 timeout-minutes: 30 steps: @@ -44,20 +46,48 @@ jobs: uses: cachix/install-nix-action@v20 with: install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install - nix_path: nixpkgs=channel:${{ matrix.channel }} + nix_path: nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.channel == 'nixpkgs-22.11-darwin' }} + - name: Install ${{ env.CURRENT_STABLE_CHANNEL }} channel + run: | + nix-channel --add https://nixos.org/channels/${{ env.CURRENT_STABLE_CHANNEL }} nixpkgs + nix-channel --update + - name: Install nix-darwin and test + run: | + export NIX_PATH=$HOME/.nix-defexpr/channels + nix-shell -A installer + nix-shell -A installer.check + - name: Build and activate default derivation + run: | + . /etc/static/bashrc + darwin-rebuild switch -I darwin=. + - name: Test uninstallation of nix-darwin + run: | + export NIX_PATH=$HOME/.nix-defexpr/channels + nix-shell -A uninstaller + nix-shell -A uninstaller.check + - name: Debugging tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + timeout-minutes: 15 + with: + limit-access-to-actor: true + + install-against-unstable: + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 - name: Install nix from current unstable channel uses: cachix/install-nix-action@v20 with: - nix_path: nixpkgs=channel:${{ matrix.channel }} + nix_path: nixpkgs=channel:nixpkgs-unstable extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.channel == 'nixpkgs-unstable' }} - - name: Install ${{ matrix.channel }} channel + - name: Install nixpkgs-unstable channel run: | - nix-channel --add https://nixos.org/channels/${{ matrix.channel }} nixpkgs + nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs nix-channel --update - name: Install nix-darwin and test run: | @@ -80,11 +110,7 @@ jobs: with: limit-access-to-actor: true - install-flake: - strategy: - fail-fast: true - matrix: - channel: [nixpkgs-22.11-darwin, nixpkgs-unstable] + install-flake-against-stable: runs-on: macos-12 timeout-minutes: 30 steps: @@ -93,20 +119,93 @@ jobs: uses: cachix/install-nix-action@v20 with: install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install - nix_path: nixpkgs=channel:${{ matrix.channel }} + nix_path: nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.channel == 'nixpkgs-22.11-darwin' }} + - name: Install ${{ env.CURRENT_STABLE_CHANNEL }} channel + run: | + nix-channel --add https://nixos.org/channels/${{ env.CURRENT_STABLE_CHANNEL }} nixpkgs + nix-channel --update + - name: Install nix-darwin and test result + run: | + export NIX_PATH=$HOME/.nix-defexpr/channels + nix-shell -A installer + nix-shell -A installer.check + - name: Build simple flake configuration + run: | + nix build ./modules/examples#darwinConfigurations.simple.system --override-input darwin . + - name: Activate derivation of simple flake build + run: | + ./result/sw/bin/darwin-rebuild switch --flake ./modules/examples#simple --override-input darwin . + - name: Rebuild and activate simple flake, but this time using nix-darwins flake interface + run: | + . /etc/static/bashrc + darwin-rebuild build --flake ./modules/examples#simple --override-input darwin . + - name: Test git submodules + run: | + . /etc/static/bashrc + + mkdir -p /tmp/{test-nix-darwin-submodules,example-submodule} + + pushd /tmp/example-submodule + echo '"hello"' > hello.nix + git init + git add . + git commit -m "add a submodule we will import" + popd + + cp -a ./modules/examples/. /tmp/test-nix-darwin-submodules + + pushd /tmp/test-nix-darwin-submodules + /usr/bin/sed -i.bak \ + '\#modules = \[#s#darwin.darwinModules.simple#./simple.nix#' \ + ./flake.nix + /usr/bin/sed -i.bak \ + 's#pkgs.vim#pkgs."${import ./submodule-test/hello.nix}"#' \ + ./simple.nix + git init + git add flake.nix simple.nix + git \ + -c protocol.file.allow=always \ + submodule add /tmp/example-submodule submodule-test + popd + + # Should fail + darwin-rebuild build \ + --flake /tmp/test-nix-darwin-submodules#simple \ + --override-input darwin . \ + && { + printf 'succeeded while expecting failure due to submodule\n' >/dev/stderr + exit 1 + } + # Should also fail + darwin-rebuild build \ + --flake /tmp/test-nix-darwin-submodules?submodules=0#simple \ + --override-input darwin . \ + && { + printf 'succeeded while expecting failure due to submodule\n' >/dev/stderr + exit 1 + } + + # Should succeed + darwin-rebuild build \ + --flake /tmp/test-nix-darwin-submodules?submodules=1#simple \ + --override-input darwin . + + install-flake-against-unstable: + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 - name: Install nix from current unstable channel uses: cachix/install-nix-action@v20 with: - nix_path: nixpkgs=channel:${{ matrix.channel }} + nix_path: nixpkgs=channel:nixpkgs-unstable extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.channel == 'nixpkgs-unstable' }} - - name: Install ${{ matrix.channel }} channel + - name: Install nixpkgs-unstable channel run: | - nix-channel --add https://nixos.org/channels/${{ matrix.channel }} nixpkgs + nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs nix-channel --update - name: Install nix-darwin and test result run: | From 0ad226e8c37560c971672b87f6632a7bd328ab13 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 27 May 2023 00:13:47 +0800 Subject: [PATCH 031/161] feat: add `mouseDriverCursorSize` option --- modules/system/defaults/universalaccess.nix | 10 ++++++++++ tests/system-defaults-write.nix | 2 ++ 2 files changed, 12 insertions(+) diff --git a/modules/system/defaults/universalaccess.nix b/modules/system/defaults/universalaccess.nix index 85cae543f..029a96539 100644 --- a/modules/system/defaults/universalaccess.nix +++ b/modules/system/defaults/universalaccess.nix @@ -5,6 +5,16 @@ with lib; { options = { + system.defaults.universalaccess.mouseDriverCursorSize = mkOption { + type = types.nullOr float; + default = null; + example = 1.5; + description = '' + Set the size of cursor. 1 for normal, 4 for maximum. + The default is 1. + ''; + }; + system.defaults.universalaccess.reduceTransparency = mkOption { type = types.nullOr types.bool; default = null; diff --git a/tests/system-defaults-write.nix b/tests/system-defaults-write.nix index 1c21ca854..20ef4d6c8 100644 --- a/tests/system-defaults-write.nix +++ b/tests/system-defaults-write.nix @@ -48,6 +48,7 @@ system.defaults.screensaver.askForPasswordDelay = 5; system.defaults.smb.NetBIOSName = "IMAC-000000"; system.defaults.smb.ServerDescription = ''Darwin\\\\U2019s iMac''; + system.defaults.universalaccess.mouseDriverCursorSize = 1.5; system.defaults.universalaccess.reduceTransparency = true; system.defaults.universalaccess.closeViewScrollWheelToggle = true; system.defaults.universalaccess.closeViewZoomFollowsFocus = true; @@ -114,6 +115,7 @@ grep "defaults write com.apple.screencapture 'location' -string '/tmp'" ${config.out}/activate-user grep "defaults write com.apple.screensaver 'askForPassword' -bool YES" ${config.out}/activate-user grep "defaults write com.apple.screensaver 'askForPasswordDelay' -int 5" ${config.out}/activate-user + grep "defaults write com.apple.universalaccess 'mouseDriverCursorSize' -float 1.5" ${config.out}/activate-user grep "defaults write com.apple.universalaccess 'reduceTransparency' -bool YES" ${config.out}/activate-user grep "defaults write com.apple.universalaccess 'closeViewScrollWheelToggle' -bool YES" ${config.out}/activate-user grep "defaults write com.apple.universalaccess 'closeViewZoomFollowsFocus' -bool YES" ${config.out}/activate-user From 7bf15660ca1febda3b43390d10797e5ad6771323 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 27 May 2023 00:37:51 +0800 Subject: [PATCH 032/161] fix: type --- modules/system/defaults/universalaccess.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/defaults/universalaccess.nix b/modules/system/defaults/universalaccess.nix index 029a96539..6d6a974e3 100644 --- a/modules/system/defaults/universalaccess.nix +++ b/modules/system/defaults/universalaccess.nix @@ -6,7 +6,7 @@ with lib; options = { system.defaults.universalaccess.mouseDriverCursorSize = mkOption { - type = types.nullOr float; + type = types.nullOr types.float; default = null; example = 1.5; description = '' From ce785ccacf2723d3ffbcaf23e5a339b8c5ed88eb Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 27 May 2023 01:02:23 +0800 Subject: [PATCH 033/161] feat: add `AppleScrollerPagingBehavior` option --- modules/system/defaults/NSGlobalDomain.nix | 8 ++++++++ tests/system-defaults-write.nix | 2 ++ 2 files changed, 10 insertions(+) diff --git a/modules/system/defaults/NSGlobalDomain.nix b/modules/system/defaults/NSGlobalDomain.nix index 0224b705b..938b319b7 100644 --- a/modules/system/defaults/NSGlobalDomain.nix +++ b/modules/system/defaults/NSGlobalDomain.nix @@ -88,6 +88,14 @@ in { ''; }; + system.defaults.NSGlobalDomain.AppleScrollerPagingBehavior = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Jump to the spot that's clicked on the scroll bar. The default is false. + ''; + }; + system.defaults.NSGlobalDomain.NSAutomaticCapitalizationEnabled = mkOption { type = types.nullOr types.bool; default = null; diff --git a/tests/system-defaults-write.nix b/tests/system-defaults-write.nix index 1c21ca854..56cef4f29 100644 --- a/tests/system-defaults-write.nix +++ b/tests/system-defaults-write.nix @@ -10,6 +10,7 @@ system.defaults.NSGlobalDomain.ApplePressAndHoldEnabled = true; system.defaults.NSGlobalDomain.AppleShowAllExtensions = true; system.defaults.NSGlobalDomain.AppleShowScrollBars = "Always"; + system.defaults.NSGlobalDomain.AppleScrollerPagingBehavior = true; system.defaults.NSGlobalDomain.NSAutomaticCapitalizationEnabled = false; system.defaults.NSGlobalDomain.NSAutomaticDashSubstitutionEnabled = false; system.defaults.NSGlobalDomain.NSAutomaticPeriodSubstitutionEnabled = false; @@ -78,6 +79,7 @@ grep "defaults write -g 'ApplePressAndHoldEnabled' -bool YES" ${config.out}/activate-user grep "defaults write -g 'AppleShowAllExtensions' -bool YES" ${config.out}/activate-user grep "defaults write -g 'AppleShowScrollBars' -string 'Always'" ${config.out}/activate-user + grep "defaults write -g 'AppleScrollerPagingBehavior' -bool YES" ${config.out}/activate-user grep "defaults write -g 'NSAutomaticCapitalizationEnabled' -bool NO" ${config.out}/activate-user grep "defaults write -g 'NSAutomaticDashSubstitutionEnabled' -bool NO" ${config.out}/activate-user grep "defaults write -g 'NSAutomaticPeriodSubstitutionEnabled' -bool NO" ${config.out}/activate-user From df00ca18a35b0b9fdcdb1d862410af92582f5b61 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 27 May 2023 01:37:34 +0800 Subject: [PATCH 034/161] feat: add `AppleWindowTabbingMode` option --- modules/system/defaults/NSGlobalDomain.nix | 8 ++++++++ tests/system-defaults-write.nix | 2 ++ 2 files changed, 10 insertions(+) diff --git a/modules/system/defaults/NSGlobalDomain.nix b/modules/system/defaults/NSGlobalDomain.nix index 0224b705b..c9633c361 100644 --- a/modules/system/defaults/NSGlobalDomain.nix +++ b/modules/system/defaults/NSGlobalDomain.nix @@ -152,6 +152,14 @@ in { ''; }; + system.defaults.NSGlobalDomain.AppleWindowTabbingMode = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Sets the window tabbing when opening a new document: 'manual', 'always', or 'fullscreen'. The default is 'fullscreen'. + ''; + }; + system.defaults.NSGlobalDomain.NSNavPanelExpandedStateForSaveMode = mkOption { type = types.nullOr types.bool; default = null; diff --git a/tests/system-defaults-write.nix b/tests/system-defaults-write.nix index 1c21ca854..06268d021 100644 --- a/tests/system-defaults-write.nix +++ b/tests/system-defaults-write.nix @@ -18,6 +18,7 @@ system.defaults.NSGlobalDomain.NSAutomaticWindowAnimationsEnabled = false; system.defaults.NSGlobalDomain.NSDisableAutomaticTermination = true; system.defaults.NSGlobalDomain.NSDocumentSaveNewDocumentsToCloud = false; + system.defaults.NSGlobalDomain.AppleWindowTabbingMode = "always"; system.defaults.NSGlobalDomain.NSNavPanelExpandedStateForSaveMode = true; system.defaults.NSGlobalDomain.NSNavPanelExpandedStateForSaveMode2 = true; system.defaults.NSGlobalDomain.NSTableViewDefaultSizeMode = 2; @@ -86,6 +87,7 @@ grep "defaults write -g 'NSAutomaticWindowAnimationsEnabled' -bool NO" ${config.out}/activate-user grep "defaults write -g 'NSDisableAutomaticTermination' -bool YES" ${config.out}/activate-user grep "defaults write -g 'NSDocumentSaveNewDocumentsToCloud' -bool NO" ${config.out}/activate-user + grep "defaults write -g 'AppleWindowTabbingMode' -string 'always'" ${config.out}/activate-user grep "defaults write -g 'NSNavPanelExpandedStateForSaveMode' -bool YES" ${config.out}/activate-user grep "defaults write -g 'NSNavPanelExpandedStateForSaveMode2' -bool YES" ${config.out}/activate-user grep "defaults write -g 'NSTableViewDefaultSizeMode' -int 2" ${config.out}/activate-user From cfcfcc535e74ff41e07789625040f7c38a8d40d9 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 27 May 2023 01:42:42 +0800 Subject: [PATCH 035/161] feat: use enum instead of str for constraints nicer --- modules/system/defaults/NSGlobalDomain.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/defaults/NSGlobalDomain.nix b/modules/system/defaults/NSGlobalDomain.nix index c9633c361..5888d7c21 100644 --- a/modules/system/defaults/NSGlobalDomain.nix +++ b/modules/system/defaults/NSGlobalDomain.nix @@ -153,7 +153,7 @@ in { }; system.defaults.NSGlobalDomain.AppleWindowTabbingMode = mkOption { - type = types.nullOr types.str; + type = types.nullOr (types.enum [ "manual" "always" "fullscreen" ]); default = null; description = '' Sets the window tabbing when opening a new document: 'manual', 'always', or 'fullscreen'. The default is 'fullscreen'. From add08fcab07cea0db9b5403861d5ae81ee09f1ee Mon Sep 17 00:00:00 2001 From: John Soo Date: Fri, 17 Dec 2021 13:19:56 -0700 Subject: [PATCH 036/161] flakes: Do not verify channels when using flakes. --- modules/system/checks.nix | 8 +++++++- modules/system/flake-overrides.nix | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/system/checks.nix b/modules/system/checks.nix index 4ce69912b..bb1ed11eb 100644 --- a/modules/system/checks.nix +++ b/modules/system/checks.nix @@ -205,6 +205,12 @@ in description = "Whether to run the NIX_PATH validation checks."; }; + system.checks.verifyNixChannels = mkOption { + type = types.bool; + default = true; + description = "Whether to run the nix-channels validation checks."; + }; + system.checks.text = mkOption { internal = true; type = types.lines; @@ -222,7 +228,7 @@ in (mkIf (!config.nix.useDaemon) singleUser) nixStore (mkIf (config.nix.gc.automatic && config.nix.gc.user == null) nixGarbageCollector) - nixChannels + (mkIf cfg.verifyNixChannels nixChannels) nixInstaller (mkIf cfg.verifyNixPath nixPath) ]; diff --git a/modules/system/flake-overrides.nix b/modules/system/flake-overrides.nix index 67a7f794b..df3eb1686 100644 --- a/modules/system/flake-overrides.nix +++ b/modules/system/flake-overrides.nix @@ -9,6 +9,7 @@ in { config = { system.checks.verifyNixPath = mkDefault false; + system.checks.verifyNixChannels = mkDefault false; system.darwinVersionSuffix = ".${darwin.shortRev or "dirty"}"; system.darwinRevision = mkIf (darwin ? rev) darwin.rev; From d20ba9bf9c72835cc9b9ddf57adf527e7e2f504f Mon Sep 17 00:00:00 2001 From: David Baynard Date: Thu, 1 Jun 2023 22:16:57 +0100 Subject: [PATCH 037/161] Document font overriding behaviour --- modules/fonts/default.nix | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/fonts/default.nix b/modules/fonts/default.nix index 0f4c269fd..2739b7465 100644 --- a/modules/fonts/default.nix +++ b/modules/fonts/default.nix @@ -26,7 +26,12 @@ in type = types.listOf types.path; default = [ ]; example = literalExpression "[ pkgs.dejavu_fonts ]"; - description = "List of fonts to install."; + description = '' + List of fonts to install. + + Fonts present in later entries override those with the same filenames + in previous ones. + ''; }; }; From 9c7a07b8b2d476b6b9f574c8f35000c7c7fbbaf4 Mon Sep 17 00:00:00 2001 From: Cole Helbling Date: Mon, 5 Jun 2023 18:27:58 -0700 Subject: [PATCH 038/161] system/checks: allow disabling the buildUsers check This allows systems with auto-allocate-uids enabled to work (by disabling this check). --- modules/system/checks.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/system/checks.nix b/modules/system/checks.nix index bb1ed11eb..fa4b3ad52 100644 --- a/modules/system/checks.nix +++ b/modules/system/checks.nix @@ -211,6 +211,12 @@ in description = "Whether to run the nix-channels validation checks."; }; + system.checks.verifyBuildUsers = mkOption { + type = types.bool; + default = true; + description = "Whether to run the Nix build users validation checks."; + }; + system.checks.text = mkOption { internal = true; type = types.lines; @@ -224,7 +230,7 @@ in darwinChanges runLink oldBuildUsers - (mkIf config.nix.useDaemon buildUsers) + (mkIf (config.nix.useDaemon && cfg.verifyBuildUsers) buildUsers) (mkIf (!config.nix.useDaemon) singleUser) nixStore (mkIf (config.nix.gc.automatic && config.nix.gc.user == null) nixGarbageCollector) From 257b5c199490aa073ab60c1d22d213025661dd44 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Wed, 31 May 2023 22:22:02 +1000 Subject: [PATCH 039/161] ssh: fix public keys in home directory not working Added `services.openssh.authorizedKeysFiles` option from NixOS. --- modules/programs/ssh/default.nix | 51 +++++++++++++++++++++++++------- tests/programs-ssh.nix | 2 +- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix index f1dde9ae9..a230dde18 100644 --- a/modules/programs/ssh/default.nix +++ b/modules/programs/ssh/default.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, ... }: with lib; @@ -79,6 +79,7 @@ let }; }; + authKeysFiles = let mkAuthKeyFile = u: nameValuePair "ssh/authorized_keys.d/${u.name}" { copy = true; @@ -91,22 +92,33 @@ let length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0 )); in listToAttrs (map mkAuthKeyFile usersWithKeys); - authKeysConfiguration = - { - "ssh/sshd_config.d/101-authorized-keys.conf" = { - copy = true; - text = "AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u\n"; - }; - }; + + oldAuthorizedKeysHash = "5a5dc1e20e8abc162ad1cc0259bfd1dbb77981013d87625f97d9bd215175fc0a"; in { options = { - + users.users = mkOption { type = with types; attrsOf (submodule userOptions); }; + services.openssh.authorizedKeysFiles = mkOption { + type = types.listOf types.str; + default = []; + description = lib.mdDoc '' + Specify the rules for which files to read on the host. + + This is an advanced option. If you're looking to configure user + keys, you can generally use [](#opt-users.users._name_.openssh.authorizedKeys.keys) + or [](#opt-users.users._name_.openssh.authorizedKeys.keyFiles). + + These are paths relative to the host root file system or home + directories and they are subject to certain token expansion rules. + See AuthorizedKeysFile in man sshd_config for details. + ''; + }; + programs.ssh.knownHosts = mkOption { default = {}; type = types.attrsOf (types.submodule host); @@ -135,13 +147,30 @@ in (data.publicKey != null && data.publicKeyFile == null); message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; }); - - environment.etc = authKeysFiles // authKeysConfiguration // + + services.openssh.authorizedKeysFiles = [ "%h/.ssh/authorized_keys" "/etc/ssh/authorized_keys.d/%u" ]; + + environment.etc = authKeysFiles // { "ssh/ssh_known_hosts".text = (flip (concatMapStringsSep "\n") knownHosts (h: assert h.hostNames != []; concatStringsSep "," h.hostNames + " " + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) )) + "\n"; + + "ssh/sshd_config.d/101-authorized-keys.conf" = { + text = "AuthorizedKeysFile ${toString config.services.openssh.authorizedKeysFiles}\n"; + # Allows us to automatically migrate from using a file to a symlink + knownSha256Hashes = [ oldAuthorizedKeysHash ]; + }; }; + + # Clean up .orig file left over from using knownSha256Hashes + system.activationScripts.etc.text = '' + auth_keys_orig=/etc/ssh/sshd_config.d/101-authorized-keys.conf.orig + + if [ -e "$auth_keys_orig" ] && [ "$(shasum -a 256 $auth_keys_orig | cut -d ' ' -f 1)" = "${oldAuthorizedKeysHash}" ]; then + rm "$auth_keys_orig" + fi + ''; }; } diff --git a/tests/programs-ssh.nix b/tests/programs-ssh.nix index 2928cfb63..ad4f7ab6c 100644 --- a/tests/programs-ssh.nix +++ b/tests/programs-ssh.nix @@ -15,6 +15,6 @@ echo >&2 "checking for authorized keys for foo in /etc/ssh/authorized_keys.d/foo" grep 'ssh-ed25519 AAAA...' ${config.out}/etc/ssh/authorized_keys.d/foo echo >&2 "checking for authorized keys' path in /etc/ssh/sshd_config.d/101-authorized-keys.conf" - grep 'AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u' ${config.out}/etc/ssh/sshd_config.d/101-authorized-keys.conf + grep 'AuthorizedKeysFile %h/.ssh/authorized_keys /etc/ssh/authorized_keys.d/%u' ${config.out}/etc/ssh/sshd_config.d/101-authorized-keys.conf ''; } From 1ba9ae3d217c2285909232d635caeaf0e16ecd54 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Fri, 9 Jun 2023 15:25:55 +1000 Subject: [PATCH 040/161] darwin-installer: fix `/run` not getting created --- pkgs/darwin-installer/installer.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/darwin-installer/installer.nix b/pkgs/darwin-installer/installer.nix index 1c58976d3..485441bcc 100644 --- a/pkgs/darwin-installer/installer.nix +++ b/pkgs/darwin-installer/installer.nix @@ -40,8 +40,8 @@ with lib; if ! grep -q '^run\b' /etc/synthetic.conf 2>/dev/null; then echo "setting up /run via /etc/synthetic.conf..." echo -e "run\tprivate/var/run" | sudo tee -a /etc/synthetic.conf >/dev/null - /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B &>/dev/null || true - /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t &>/dev/null || true + sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B &>/dev/null || true + sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t &>/dev/null || true if ! test -L /run; then echo "warning: apfs.util failed to symlink /run" fi From 51b8bdfc0e43e24ebe097f167778d4e7fe88dd77 Mon Sep 17 00:00:00 2001 From: Cathal Mullan Date: Sat, 10 Jun 2023 13:41:13 +0100 Subject: [PATCH 041/161] nix: Add build machines protocol option. --- modules/nix/default.nix | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/nix/default.nix b/modules/nix/default.nix index cd66c590a..a88094137 100644 --- a/modules/nix/default.nix +++ b/modules/nix/default.nix @@ -227,6 +227,19 @@ in The hostname of the build machine. ''; }; + protocol = mkOption { + type = types.enum [ null "ssh" "ssh-ng" ]; + default = "ssh"; + example = "ssh-ng"; + description = lib.mdDoc '' + The protocol used for communicating with the build machine. + Use `ssh-ng` if your remote builder and your + local Nix version support that improved protocol. + + Use `null` when trying to change the special localhost builder + without a protocol which is for example used by hydra. + ''; + }; system = mkOption { type = types.nullOr types.str; default = null; @@ -679,7 +692,7 @@ in concatMapStrings (machine: (concatStringsSep " " ([ - "${optionalString (machine.sshUser != null) "${machine.sshUser}@"}${machine.hostName}" + "${optionalString (machine.protocol != null) "${machine.protocol}://"}${optionalString (machine.sshUser != null) "${machine.sshUser}@"}${machine.hostName}" (if machine.system != null then machine.system else if machine.systems != [ ] then concatStringsSep "," machine.systems else "-") (if machine.sshKey != null then machine.sshKey else "-") (toString machine.maxJobs) From 1fc5d125fb14835ee12122395adb85b26c8f732e Mon Sep 17 00:00:00 2001 From: Lauren Yim <31467609+cherryblossom000@users.noreply.github.com> Date: Mon, 12 Jun 2023 16:08:03 +1000 Subject: [PATCH 042/161] docs: clarify how to use inputs with flakes This commit clarifies that in order to access `inputs` in a host configuration, the `inputs` argument must be used. This commit also documents how `specialArgs` can be used to access the inputs as arguments directly. --- README.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 87a9786ff..e7865e37c 100644 --- a/README.md +++ b/README.md @@ -94,15 +94,30 @@ A minimal example of using an existing configuration.nix: } ``` -Inputs from the flake can also be passed to `darwinSystem`, these inputs are then -accessible as an argument, similar to pkgs and lib inside the configuration. +Inputs from the flake can also be passed to `darwinSystem`. These inputs are then +accessible as an argument `inputs`, similar to `pkgs` and `lib`, inside the configuration. ```nix darwin.lib.darwinSystem { system = "x86_64-darwin"; - modules = [ ... ]; + modules = [ ./configuration.nix ]; inputs = { inherit darwin dotfiles nixpkgs; }; } +# in configuration.nix: +{ pkgs, lib, inputs }: +# inputs.darwin, inputs.dotfiles, and inputs.nixpkgs can be accessed here +``` + +Alternatively, `specialArgs` could be used: + +```nix +darwin.lib.darwinSystem { + system = "x86_64-darwin"; + modules = [ ./configuration.nix ]; + specialArgs = { inherit darwin dotfiles nixpkgs; }; +} +# in configuration.nix: +{ pkgs, lib, darwin, dotfiles, nixpkgs }: ``` Since the installer doesn't work with flakes out of the box yet, nix-darwin will need to From fc955520dd26ddbed189f19edc438f7c408e470e Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 12 Jun 2023 10:47:21 +1000 Subject: [PATCH 043/161] flake: add template with basic flake config --- .github/workflows/test.yml | 14 ++++++++------ flake.nix | 5 +++++ modules/examples/{ => flake}/flake.nix | 0 3 files changed, 13 insertions(+), 6 deletions(-) rename modules/examples/{ => flake}/flake.nix (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 172e35c28..eafecb4fd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -133,14 +133,14 @@ jobs: nix-shell -A installer.check - name: Build simple flake configuration run: | - nix build ./modules/examples#darwinConfigurations.simple.system --override-input darwin . + nix build ./modules/examples/flake#darwinConfigurations.simple.system --override-input darwin . - name: Activate derivation of simple flake build run: | - ./result/sw/bin/darwin-rebuild switch --flake ./modules/examples#simple --override-input darwin . + ./result/sw/bin/darwin-rebuild switch --flake ./modules/examples/flake#simple --override-input darwin . - name: Rebuild and activate simple flake, but this time using nix-darwins flake interface run: | . /etc/static/bashrc - darwin-rebuild build --flake ./modules/examples#simple --override-input darwin . + darwin-rebuild build --flake ./modules/examples/flake#simple --override-input darwin . - name: Test git submodules run: | . /etc/static/bashrc @@ -155,6 +155,7 @@ jobs: popd cp -a ./modules/examples/. /tmp/test-nix-darwin-submodules + cp -a ./modules/examples/flake/flake.nix /tmp/test-nix-darwin-submodules pushd /tmp/test-nix-darwin-submodules /usr/bin/sed -i.bak \ @@ -214,14 +215,14 @@ jobs: nix-shell -A installer.check - name: Build simple flake configuration run: | - nix build ./modules/examples#darwinConfigurations.simple.system --override-input darwin . + nix build ./modules/examples/flake#darwinConfigurations.simple.system --override-input darwin . - name: Activate derivation of simple flake build run: | - ./result/sw/bin/darwin-rebuild switch --flake ./modules/examples#simple --override-input darwin . + ./result/sw/bin/darwin-rebuild switch --flake ./modules/examples/flake#simple --override-input darwin . - name: Rebuild and activate simple flake, but this time using nix-darwins flake interface run: | . /etc/static/bashrc - darwin-rebuild build --flake ./modules/examples#simple --override-input darwin . + darwin-rebuild build --flake ./modules/examples/flake#simple --override-input darwin . - name: Test git submodules run: | . /etc/static/bashrc @@ -236,6 +237,7 @@ jobs: popd cp -a ./modules/examples/. /tmp/test-nix-darwin-submodules + cp -a ./modules/examples/flake/flake.nix /tmp/test-nix-darwin-submodules pushd /tmp/test-nix-darwin-submodules /usr/bin/sed -i.bak \ diff --git a/flake.nix b/flake.nix index caad87578..3ce6db131 100644 --- a/flake.nix +++ b/flake.nix @@ -25,6 +25,11 @@ darwinModules.ofborg = ./modules/examples/ofborg.nix; darwinModules.simple = ./modules/examples/simple.nix; + templates.default = { + path = ./modules/examples/flake; + description = "nix flake init -t nix-darwin"; + }; + checks.x86_64-darwin.simple = (self.lib.darwinSystem { system = "x86_64-darwin"; modules = [ self.darwinModules.simple ]; diff --git a/modules/examples/flake.nix b/modules/examples/flake/flake.nix similarity index 100% rename from modules/examples/flake.nix rename to modules/examples/flake/flake.nix From f532e43f7efa58a0202956fac19f402893ae0ecd Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 12 Jun 2023 11:01:21 +1000 Subject: [PATCH 044/161] templates.flake: add contents of simple.nix --- .github/workflows/test.yml | 4 ++-- modules/examples/flake/flake.nix | 25 ++++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eafecb4fd..1e48cd68d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -159,7 +159,7 @@ jobs: pushd /tmp/test-nix-darwin-submodules /usr/bin/sed -i.bak \ - '\#modules = \[#s#darwin.darwinModules.simple#./simple.nix#' \ + '\#modules = \[#s#configuration#configuration ./simple.nix#' \ ./flake.nix /usr/bin/sed -i.bak \ 's#pkgs.vim#pkgs."${import ./submodule-test/hello.nix}"#' \ @@ -241,7 +241,7 @@ jobs: pushd /tmp/test-nix-darwin-submodules /usr/bin/sed -i.bak \ - '\#modules = \[#s#darwin.darwinModules.simple#./simple.nix#' \ + '\#modules = \[#s#configuration#configuration ./simple.nix#' \ ./flake.nix /usr/bin/sed -i.bak \ 's#pkgs.vim#pkgs."${import ./submodule-test/hello.nix}"#' \ diff --git a/modules/examples/flake/flake.nix b/modules/examples/flake/flake.nix index 2c5f90ecf..0ada85242 100644 --- a/modules/examples/flake/flake.nix +++ b/modules/examples/flake/flake.nix @@ -10,18 +10,33 @@ outputs = { self, darwin, nixpkgs }: let configuration = { pkgs, ... }: { - nix.package = pkgs.nixVersions.stable; + # List packages installed in system profile. To search by name, run: + # $ nix-env -qaP | grep wget + environment.systemPackages = + [ pkgs.vim + ]; - # FIXME: for github actions, this shouldn't be in the example. + # Auto upgrade nix package and the daemon service. services.nix-daemon.enable = true; + # nix.package = pkgs.nix; + + # Necessary for using flakes on this system. + nix.settings.experimental-features = "nix-command flakes"; + + # Create /etc/zshrc that loads the nix-darwin environment. + programs.zsh.enable = true; # default shell on catalina + # programs.fish.enable = true; + + # Used for backwards compatibility, please read the changelog before changing. + # $ darwin-rebuild changelog + system.stateVersion = 4; }; in { # Build darwin flake using: - # $ darwin-rebuild build --flake ./modules/examples#simple \ - # --override-input darwin . + # $ darwin-rebuild build --flake .#simple darwinConfigurations."simple" = darwin.lib.darwinSystem { - modules = [ configuration darwin.darwinModules.simple ]; + modules = [ configuration ]; system = "x86_64-darwin"; }; From 8d13a55f1c3020825400ef066ab13ef62ca441bf Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Sat, 17 Jun 2023 22:56:26 +1000 Subject: [PATCH 045/161] workflows: fix Nix install on `macos-12` --- .github/workflows/test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1e48cd68d..c351432fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install nix corresponding to latest stable channel - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v22 with: install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install extra_nix_config: | @@ -28,7 +28,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install nix from current unstable channel - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v22 with: nix_path: nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} extra_nix_config: | @@ -43,7 +43,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install nix corresponding to latest stable channel - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v22 with: install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install nix_path: nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} @@ -80,7 +80,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install nix from current unstable channel - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v22 with: nix_path: nixpkgs=channel:nixpkgs-unstable extra_nix_config: | @@ -116,7 +116,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install nix version corresponding to latest stable channel - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v22 with: install_url: https://github.com/nix-community/nix-unstable-installer/releases/download/nix-2.10.0pre20220822_7c3ab57/install nix_path: nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} @@ -199,7 +199,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install nix from current unstable channel - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v22 with: nix_path: nixpkgs=channel:nixpkgs-unstable extra_nix_config: | From 1711db734e29a2df3b1b72ec1e15bd50b0629fd1 Mon Sep 17 00:00:00 2001 From: Jack Maloney Date: Sun, 18 Jun 2023 00:25:24 -0500 Subject: [PATCH 046/161] add ipfs service --- modules/module-list.nix | 1 + modules/services/ipfs.nix | 70 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 modules/services/ipfs.nix diff --git a/modules/module-list.nix b/modules/module-list.nix index 034ea767a..6e36ef775 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -53,6 +53,7 @@ ./services/emacs.nix ./services/gitlab-runner.nix ./services/hercules-ci-agent + ./services/ipfs.nix ./services/karabiner-elements ./services/khd ./services/kwm diff --git a/modules/services/ipfs.nix b/modules/services/ipfs.nix new file mode 100644 index 000000000..df1f62e5a --- /dev/null +++ b/modules/services/ipfs.nix @@ -0,0 +1,70 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.ipfs; + +in +{ + meta.maintainers = [ "jmmaloney4" ]; + + options.services.ipfs = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the ipfs daemon."; + }; + + package = mkOption { + type = types.path; + default = pkgs.kubo; + # defaultText = "pkgs.kubo"; + description = '' + The ipfs package to use. + ''; + }; + + logFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/tmp/lorri.log"; + description = '' + The logfile to use for the ipfs service. Alternatively + sudo launchctl debug system/org.nixos.ipfs --stderr + can be used to stream the logs to a shell after restarting the service with + sudo launchctl kickstart -k system/org.nixos.ipfs. + ''; + }; + + ipfsPath = mkOption { + type = types.nullOr types.path; + default = null; + description = "Set the IPFS_PATH environment variable."; + }; + + enableGarbageCollection = mkOption { + type = types.bool; + default = false; + description = "Passes --enable-gc flag to ipfs daemon."; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.kubo ]; + launchd.user.agents.ipfs = { + # command = with pkgs; "${ipfs}/bin/ipfs daemon"; + serviceConfig = { + ProgramArguments = [ "${cfg.package}/bin/ipfs" "daemon" ] + ++ optionals (cfg.enableGarbageCollection) [ "--enable-gc" ]; + KeepAlive = true; + RunAtLoad = true; + ProcessType = "Background"; + StandardOutPath = cfg.logFile; + StandardErrorPath = cfg.logFile; + EnvironmentVariables = {} // (optionalAttrs (cfg.ipfsPath != null) { IPFS_PATH = cfg.ipfsPath; }); + }; + }; + }; +} From cd87d92320bb32f250aefb2bc039c43bb3ffb7e2 Mon Sep 17 00:00:00 2001 From: toonn Date: Sun, 18 Jun 2023 20:00:49 +0200 Subject: [PATCH 047/161] GHActions: Bump install-nix-action to v22 Not all workflows were updated but some were, this fixes the inconsistency. --- .github/workflows/build.yml | 2 +- .github/workflows/debug.yml | 2 +- .github/workflows/update-manual.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed66317e1..1cb24265b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,6 +13,6 @@ jobs: runs-on: macos-12 steps: - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 + - uses: cachix/install-nix-action@v22 - run: | nix build ${{ github.event.client_payload.args }} -vL diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 3abe115bb..7535f7134 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -13,7 +13,7 @@ jobs: runs-on: macos-12 steps: - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 + - uses: cachix/install-nix-action@v22 - run: | nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs nix-channel --update diff --git a/.github/workflows/update-manual.yml b/.github/workflows/update-manual.yml index b6590640f..7ba43e876 100644 --- a/.github/workflows/update-manual.yml +++ b/.github/workflows/update-manual.yml @@ -17,7 +17,7 @@ jobs: fetch-depth: 0 - name: Install Nix - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v22 with: extra_nix_config: | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} From f253b41de83c9f34fba9eda66cc42b90e10937c7 Mon Sep 17 00:00:00 2001 From: Roman Melnikov Date: Mon, 29 May 2023 13:50:59 +0800 Subject: [PATCH 048/161] buildkite-agent: fix launcd daemon environment Add missing 'NIX_SSL_CERT_FILE' --- modules/services/buildkite-agents.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/services/buildkite-agents.nix b/modules/services/buildkite-agents.nix index 7486161ce..dc7ef331e 100644 --- a/modules/services/buildkite-agents.nix +++ b/modules/services/buildkite-agents.nix @@ -228,7 +228,8 @@ in { path = cfg.runtimePackages ++ [ cfg.package pkgs.coreutils pkgs.darwin.DarwinTools ]; environment = { HOME = cfg.dataDir; - }// (if config.nix.useDaemon then { NIX_REMOTE = "daemon"; } else {}); + inherit (config.environment.variables) NIX_SSL_CERT_FILE; + } // (if config.nix.useDaemon then { NIX_REMOTE = "daemon"; } else {}); ## NB: maximum care is taken so that secrets (ssh keys and the CI token) ## don't end up in the Nix store. From 737cfdec9ce54eed56b4f9c281bbd892ebf5dc6b Mon Sep 17 00:00:00 2001 From: Emily Date: Wed, 21 Jun 2023 21:28:01 +0100 Subject: [PATCH 049/161] eval-config.nix: readd `lib.mdDoc` temporarily Fixes: #701 --- eval-config.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/eval-config.nix b/eval-config.nix index c30d88c7a..cc0772de4 100644 --- a/eval-config.nix +++ b/eval-config.nix @@ -46,6 +46,11 @@ let # Added in nixpkgs #136909, adds forward compatibility until 22.03 is deprecated. literalExpression = super.literalExpression or super.literalExample; literalDocBook = super.literalDocBook or super.literalExample; + + # Removed in nixpkgs #237557, readded to faciliate Markdown transition. + mdDoc = text: + if ! self.isString text then throw "mdDoc expects a string." + else { _type = "mdDoc"; inherit text; }; }); eval = libExtended.evalModules (builtins.removeAttrs args [ "lib" "inputs" "pkgs" "system" ] // { From fbb3ab94e67bab73e721d5bbbcc6b05b0cf60f2f Mon Sep 17 00:00:00 2001 From: zowoq <59103226+zowoq@users.noreply.github.com> Date: Fri, 23 Jun 2023 09:37:01 +1000 Subject: [PATCH 050/161] activity monitor: change settings to null treewide these seem to be the only settings that aren't unset by default which seems inconsistent --- modules/system/defaults/ActivityMonitor.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/system/defaults/ActivityMonitor.nix b/modules/system/defaults/ActivityMonitor.nix index 2f2f2d44a..d57c6c043 100644 --- a/modules/system/defaults/ActivityMonitor.nix +++ b/modules/system/defaults/ActivityMonitor.nix @@ -7,7 +7,7 @@ with lib; system.defaults.ActivityMonitor.ShowCategory = mkOption { type = types.nullOr (types.enum [100 101 102 103 104 105 106 107]); - default = 100; + default = null; description = '' Change which processes to show. 100: All Processes @@ -54,7 +54,7 @@ with lib; system.defaults.ActivityMonitor.OpenMainWindow = mkOption { type = types.nullOr types.bool; - default = true; + default = null; description = '' Open the main window when opening Activity Monitor. Default is true. ''; From b7ccefadf9aa3e2f7dfc60ed61bfa90d2d224c93 Mon Sep 17 00:00:00 2001 From: Emily Date: Wed, 21 Jun 2023 22:32:03 +0100 Subject: [PATCH 051/161] flake.nix: temporarily pin nixpkgs version This is the last bump of the nixpkgs-unstable channel before the DocBookalypse. --- flake.lock | 7 ++++--- flake.nix | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 2ce4242af..61540b7e2 100644 --- a/flake.lock +++ b/flake.lock @@ -2,15 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1668650906, - "narHash": "sha256-JuiYfDO23O8oxUUOmhQflmOoJovyC5G4RjcYQMQjrRE=", + "lastModified": 1687130670, + "narHash": "sha256-VKTdfsJe7sVTTqxTd3eRGPoUgEeJKD+kwS86B6TY874=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3a86856a13c88c8c64ea32082a851fefc79aa700", + "rev": "c1bca7fe84c646cfd4ebf3482c0e6317a0b13f22", "type": "github" }, "original": { "id": "nixpkgs", + "rev": "c1bca7fe84c646cfd4ebf3482c0e6317a0b13f22", "type": "indirect" } }, diff --git a/flake.nix b/flake.nix index 3ce6db131..c571bc5e4 100644 --- a/flake.nix +++ b/flake.nix @@ -2,6 +2,9 @@ # WARNING this is very much still experimental. description = "A collection of darwin modules"; + # Temporary pin for Markdown documentation transition. + inputs.nixpkgs.url = "nixpkgs/c1bca7fe84c646cfd4ebf3482c0e6317a0b13f22"; + outputs = { self, nixpkgs }: { lib = { # TODO handle multiple architectures. From b6893e7f6d8c8e0d86ab46ac69250d34fb716d21 Mon Sep 17 00:00:00 2001 From: Emily Date: Fri, 23 Jun 2023 00:20:58 +0100 Subject: [PATCH 052/161] eval-config: remove `lib.mdDoc` The temporarily pinned nixpkgs version already has this version, and where we're going, we don't need backports. This reverts commit 737cfdec9ce54eed56b4f9c281bbd892ebf5dc6b. --- eval-config.nix | 5 ----- 1 file changed, 5 deletions(-) diff --git a/eval-config.nix b/eval-config.nix index cc0772de4..c30d88c7a 100644 --- a/eval-config.nix +++ b/eval-config.nix @@ -46,11 +46,6 @@ let # Added in nixpkgs #136909, adds forward compatibility until 22.03 is deprecated. literalExpression = super.literalExpression or super.literalExample; literalDocBook = super.literalDocBook or super.literalExample; - - # Removed in nixpkgs #237557, readded to faciliate Markdown transition. - mdDoc = text: - if ! self.isString text then throw "mdDoc expects a string." - else { _type = "mdDoc"; inherit text; }; }); eval = libExtended.evalModules (builtins.removeAttrs args [ "lib" "inputs" "pkgs" "system" ] // { From f8c61f00980867ead1bebd81ded0272cbcb6febb Mon Sep 17 00:00:00 2001 From: Emily Date: Wed, 21 Jun 2023 22:32:19 +0100 Subject: [PATCH 053/161] flake.nix: add checks for the docs Except for `manualEpub`, which is going away. --- flake.nix | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/flake.nix b/flake.nix index c571bc5e4..5c95ac790 100644 --- a/flake.nix +++ b/flake.nix @@ -33,9 +33,18 @@ description = "nix flake init -t nix-darwin"; }; - checks.x86_64-darwin.simple = (self.lib.darwinSystem { - system = "x86_64-darwin"; - modules = [ self.darwinModules.simple ]; - }).system; + checks = nixpkgs.lib.genAttrs ["aarch64-darwin" "x86_64-darwin"] (system: let + simple = self.lib.darwinSystem { + inherit system; + modules = [ self.darwinModules.simple ]; + }; + in { + simple = simple.system; + + inherit (simple.config.system.build.manual) + optionsJSON + manualHTML + manpages; + }); }; } From 96cb49133b813d9902f6417e5b725a01bbaacb2f Mon Sep 17 00:00:00 2001 From: Emily Date: Thu, 22 Jun 2023 13:04:37 +0100 Subject: [PATCH 054/161] wq-quick: document `publicKey` option All exposed options should have documentation, and `nixosOptionDoc` will give an error if it's missing. --- modules/services/wg-quick.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/services/wg-quick.nix b/modules/services/wg-quick.nix index 787b6632c..40725ffb2 100644 --- a/modules/services/wg-quick.nix +++ b/modules/services/wg-quick.nix @@ -35,6 +35,7 @@ let publicKey = mkOption { default = null; type = types.str; + description = "The public key for this peer."; }; }; }; From 76ce9faca6e16d348afb9d78a1a13eb19c381b76 Mon Sep 17 00:00:00 2001 From: Emily Date: Thu, 22 Jun 2023 00:15:18 +0100 Subject: [PATCH 055/161] doc/manual: use `nixosOptionDoc` The only change to `options.json` are that the `declarations` fields now contain correct GitHub URLs. The changes to the HTML manual are all either strict improvements: * "Declared by:" links point to the correct URLs. * `lib.mdDoc` documentation is included. or else trivial: * Additional whitespace in the HTML source. * Some interchange of `
` and
  ``.
* Fancy quotes used in some type descriptions.

`optionsDocBook` is exported temporarily as it is used by
`nix-doc-munge` for the Markdown conversion process.

This drops support for building the manual on 22.11, which lacks a
complete implementation of this processor, and provides stubbed-out
manual packages with an explanation on that version.
---
 doc/manual/default.nix                        | 157 ++++--------
 doc/manual/options-to-docbook.xsl             | 237 ------------------
 .../postprocess-option-descriptions.xsl       | 115 ---------
 modules/documentation/default.nix             |  36 ++-
 4 files changed, 86 insertions(+), 459 deletions(-)
 delete mode 100644 doc/manual/options-to-docbook.xsl
 delete mode 100644 doc/manual/postprocess-option-descriptions.xsl

diff --git a/doc/manual/default.nix b/doc/manual/default.nix
index b5bdf6f11..3a5152eb6 100644
--- a/doc/manual/default.nix
+++ b/doc/manual/default.nix
@@ -1,99 +1,44 @@
-{ pkgs, options, config, version, revision, extraSources ? [] }:
+{ pkgs
+, options
+, config
+, version
+, revision
+, nixpkgsRevision
+, extraSources ? []
+, prefix ? ../..
+}:
 
 with pkgs;
 
 let
   lib = pkgs.lib;
 
-  # Remove invisible and internal options.
-  optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
-
-  # Replace functions by the string 
-  substFunction = x:
-    if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
-    else if builtins.isList x then map substFunction x
-    else if lib.isFunction x then ""
-    else x;
-
-  # Generate DocBook documentation for a list of packages. This is
-  # what `relatedPackages` option of `mkOption` from
-  # ../../../lib/options.nix influences.
-  #
-  # Each element of `relatedPackages` can be either
-  # - a string:  that will be interpreted as an attribute name from `pkgs`,
-  # - a list:    that will be interpreted as an attribute path from `pkgs`,
-  # - an attrset: that can specify `name`, `path`, `package`, `comment`
-  #   (either of `name`, `path` is required, the rest are optional).
-  genRelatedPackages = packages:
-    let
-      unpack = p: if lib.isString p then { name = p; }
-                  else if lib.isList p then { path = p; }
-                  else p;
-      describe = args:
-        let
-          title = args.title or null;
-          name = args.name or (lib.concatStringsSep "." args.path);
-          path = args.path or [ args.name ];
-          package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs);
-        in ""
-        + "${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})"
-        + lib.optionalString (!package.meta.available) " [UNAVAILABLE]"
-        + ": ${package.meta.description or "???"}."
-        + lib.optionalString (args ? comment) "\n${args.comment}"
-        # Lots of `longDescription's break DocBook, so we just wrap them into 
-        + lib.optionalString (package.meta ? longDescription) "\n${package.meta.longDescription}"
-        + "";
-    in "${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}";
-
-  optionsListDesc = lib.flip map optionsListVisible (opt: opt // {
-    # Clean up declaration sites to not refer to the NixOS source tree.
-    declarations = map stripAnyPrefixes opt.declarations;
-  }
-  // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
-  // lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
-  // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
-  // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; });
-
-  # We need to strip references to /nix/store/* from options,
-  # including any `extraSources` if some modules came from elsewhere,
-  # or else the build will fail.
-  #
-  # E.g. if some `options` came from modules in ${pkgs.customModules}/nix,
-  # you'd need to include `extraSources = [ pkgs.customModules ]`
-  prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources);
-  stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
-
-  # Custom "less" that pushes up all the things ending in ".enable*"
-  # and ".package*"
-  optionLess = a: b:
-    let
-      ise = lib.hasPrefix "enable";
-      isp = lib.hasPrefix "package";
-      cmp = lib.splitByAndCompare ise lib.compare
-                                 (lib.splitByAndCompare isp lib.compare lib.compare);
-    in lib.compareLists cmp a.loc b.loc < 0;
-
-  # Customly sort option list for the man page.
-  optionsList = lib.sort optionLess optionsListDesc;
-
-  # Convert the list of options into an XML file.
-  optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList);
-
-  optionsDocBook = runCommand "options-db.xml" {} ''
-    optionsXML=${optionsXML}
-    if grep /darwin/modules $optionsXML; then
-      echo "The manual appears to depend on the location of Darwin, which is bad"
-      echo "since this prevents sharing via a channel.  This is typically"
-      echo "caused by an option default that refers to a relative path (see above"
-      echo "for hints about the offending path)."
-      exit 1
-    fi
-    ${buildPackages.libxslt.bin}/bin/xsltproc \
-      --stringparam revision '${revision}' \
-      -o intermediate.xml ${./options-to-docbook.xsl} $optionsXML
-    ${buildPackages.libxslt.bin}/bin/xsltproc \
-      -o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml
-  '';
+  optionsDoc = buildPackages.nixosOptionsDoc {
+    inherit options revision;
+    transformOptions = opt: opt // {
+      # Clean up declaration sites to not refer to the nix-darwin source tree.
+      # TODO: handle `extraSources`? (it's not set anywhere)
+      declarations = map
+        (decl:
+          if lib.hasPrefix (toString prefix) (toString decl) then
+            let
+              subpath = lib.removePrefix "/"
+                (lib.removePrefix (toString prefix) (toString decl));
+            in {
+              url = "https://github.com/LnL7/nix-darwin/blob/${revision}/${subpath}";
+              name = "";
+            }
+          # TODO: handle this in a better way (may require upstream
+          # changes to nixpkgs)
+          else if decl == "lib/modules.nix" then
+            {
+              url = "https://github.com/NixOS/nixpkgs/blob/${nixpkgsRevision}/${decl}";
+              name = "";
+            }
+          else decl)
+        opt.declarations;
+    };
+  };
 
   sources = lib.sourceFilesBySuffices ./. [".xml"];
 
@@ -108,7 +53,7 @@ let
   generatedSources = runCommand "generated-docbook" {} ''
     mkdir $out
     ln -s ${modulesDoc} $out/modules.xml
-    ln -s ${optionsDocBook} $out/options-db.xml
+    ln -s ${optionsDoc.optionsDocBook} $out/options-db.xml
     printf "%s" "${version}" > $out/version
   '';
 
@@ -234,22 +179,23 @@ let
 in rec {
   inherit generatedSources;
 
-  # The NixOS options in JSON format.
-  optionsJSON = runCommand "options-json"
-    { meta.description = "List of NixOS options in JSON format";
-    }
+  # TODO: Use `optionsDoc.optionsJSON` directly once upstream
+  # `nixosOptionsDoc` is more customizable.
+  optionsJSON = runCommand "options.json"
+    { meta.description = "List of nix-darwin options in JSON format"; }
     ''
-      # Export list of options in different format.
-      dst=$out/share/doc/darwin
-      mkdir -p $dst
-
-      cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON
-        (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList))))
-      } $dst/options.json
+      mkdir -p $out/{share/doc,nix-support}
+      cp -a ${optionsDoc.optionsJSON}/share/doc/nixos $out/share/doc/darwin
+      substitute \
+        ${optionsDoc.optionsJSON}/nix-support/hydra-build-products \
+        $out/nix-support/hydra-build-products \
+        --replace \
+          '${optionsDoc.optionsJSON}/share/doc/nixos' \
+          "$out/share/doc/darwin"
+    '';
 
-      mkdir -p $out/nix-support
-      echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
-    ''; # */
+  # Temporary export for Markdown conversion.
+  inherit (optionsDoc) optionsDocBook;
 
   # Generate the NixOS manual.
   manualHTML = runCommand "darwin-manual-html"
@@ -341,4 +287,3 @@ in rec {
     '';
 
 }
-
diff --git a/doc/manual/options-to-docbook.xsl b/doc/manual/options-to-docbook.xsl
deleted file mode 100644
index 703a12ca7..000000000
--- a/doc/manual/options-to-docbook.xsl
+++ /dev/null
@@ -1,237 +0,0 @@
-
-
-
-
-  
-
-  
-  
-
-  
-    
-      Configuration Options
-      
-        
-        
-          
-            
-              
-              
-            
-
-            
-
-              
-                
-                  
-                
-              
-
-              
-                
-                  Type:
-                   
-                  
-                  
-                     
-                    (read only)
-                  
-                
-              
-
-              
-                
-                  Default:
-                   
-                  
-                
-              
-
-              
-                
-                  Example:
-                   
-                  
-                    
-                      
-                    
-                    
-                      
-                    
-                  
-                
-              
-
-              
-                
-                  Related packages:
-                   
-                  
-                
-              
-
-              
-                
-                  Declared by:
-                
-                
-              
-
-              
-                
-                  Defined by:
-                
-                
-              
-
-            
-
-          
-
-        
-
-      
-    
-  
-
-
-  
-    
-      
-
-''
-''
-      
-      
-        
-      
-    
-  
-
-
-  
-    null
-  
-
-
-  
-    
-      
-        ''''
-      
-      
-        ""
-      
-    
-  
-
-
-  
-    
-  
-
-
-  
-    true
-  
-
-
-  
-    false
-  
-
-
-  
-    [
-    
-      
-       
-    
-    ]
-  
-
-
-  
-    
-  
-
-
-  
-    {
-    
-      
-       = 
-      ; 
-    
-    }
-  
-
-
-  
-    (build of )
-  
-
-  
-    
-      
-        
-          
-          
-            
-              
-                
-                  https://github.com/LnL7/nix-darwin/blob/master/
-                
-                
-                  https://github.com/LnL7/nix-darwin/blob//
-                
-              
-            
-            
-              file://
-            
-          
-          
-          
-            
-              <>
-            
-            
-              
-            
-          
-        
-      
-    
-  
-
-
-  
-    λ
-  
-
-
-
diff --git a/doc/manual/postprocess-option-descriptions.xsl b/doc/manual/postprocess-option-descriptions.xsl
deleted file mode 100644
index 1201c7612..000000000
--- a/doc/manual/postprocess-option-descriptions.xsl
+++ /dev/null
@@ -1,115 +0,0 @@
-
-
-
-  
-
-  
-    
-      
-    
-  
-
-  
-    
-    
-
-    
-    
-
-    
-    
-    
-
-    
-      
-        
-        
-          
-          
-            
-          
-          
-          
-        
-        
-        
-        
-          
-          
-        
-        
-        
-          
-            
-          
-        
-        
-          
-          
-        
-      
-      
-      
-        
-          
-          
-          
-            
-              
-                
-              
-            
-            
-          
-        
-      
-      
-      
-        
-          
-        
-      
-    
-  
-
-  
-    
-      
-      
-        
-      
-      
-        
-          
-        
-      
-    
-  
-
-
diff --git a/modules/documentation/default.nix b/modules/documentation/default.nix
index 6bd341213..d741995c0 100644
--- a/modules/documentation/default.nix
+++ b/modules/documentation/default.nix
@@ -21,10 +21,11 @@ let
     It isn't perfect, but it seems to cover a vast majority of use cases.
     Caveat: even if the package is reached by a different means,
     the path above will be shown and not e.g. `${config.services.foo.package}`. */
-  manual = import ../../doc/manual rec {
+  realManual = import ../../doc/manual {
     inherit pkgs config;
     version = config.system.darwinVersion;
     revision = config.system.darwinRevision;
+    nixpkgsRevision = config.system.nixpkgsRevision;
     options =
       let
         scrubbedEval = evalModules {
@@ -43,6 +44,39 @@ let
       in scrubbedEval.options;
   };
 
+  # TODO: Remove this when dropping 22.11 support.
+  manual = realManual //
+    lib.optionalAttrs (lib.versionOlder lib.version "23.05-pre") rec {
+      optionsJSON = pkgs.writeTextFile {
+        name = "options.json-stub";
+        destination = "/share/doc/darwin/options.json";
+        text = "{}";
+      };
+      manpages = pkgs.writeTextFile {
+        name = "darwin-manpages-stub";
+        destination = "/share/man/man5/configuration.nix.5";
+        text = ''
+          .TH "CONFIGURATION\&.NIX" "5" "01/01/1980" "Darwin" "Darwin Reference Pages"
+          .SH "NAME"
+          \fIconfiguration\&.nix\fP \- Darwin system configuration specification
+          .SH "DESCRIPTION"
+          .PP
+          The nix\-darwin documentation now requires nixpkgs 23.05 to build.
+        '';
+      };
+      manualHTML = pkgs.writeTextFile {
+        name = "darwin-manual-html-stub";
+        destination = "/share/doc/darwin/index.html";
+        text = ''
+          
+          Darwin Configuration Options
+          The nix-darwin documentation now requires nixpkgs 23.05 to build.
+        '';
+      };
+      manual = manualHTML;
+      manualHTMLIndex = "${manualHTML}/share/doc/darwin/index.html";
+    };
+
   helpScript = pkgs.writeScriptBin "darwin-help"
     ''
       #! ${pkgs.stdenv.shell} -e

From b97c235e37c91511c2e7533ab6794480e4cc445a Mon Sep 17 00:00:00 2001
From: Emily 
Date: Thu, 22 Jun 2023 02:34:49 +0100
Subject: [PATCH 056/161] treewide: tweak DocBook docs for conversion

These help `nix-munge-doc` automate more of the Markdown conversion
process. See the following nixpkgs commits for explanations of many
of these changes:

* https://github.com/NixOS/nixpkgs/commit/275a34e0d8a937a81b267e47302dd8a92fa781df
* https://github.com/NixOS/nixpkgs/commit/694d5b19d30bf66687b42fb77f43ea7cd1002a62
* https://github.com/NixOS/nixpkgs/commit/f1d39b6d6187997b630647400c5efe5b01e06a23
* https://github.com/NixOS/nixpkgs/commit/16102dce2fbad670bd47dd75c860a8daa5fe47ad

I couldn't think of any particularly good way to format the
`system.defaults` breadcrumbs, so I just made them standalone
paragraphs. They weren't rendering correctly in DocBook anyway.
---
 modules/homebrew.nix                       | 75 +++++++++++-----------
 modules/nix/default.nix                    |  9 ++-
 modules/services/postgresql/default.nix    |  8 +--
 modules/services/synergy/default.nix       |  4 +-
 modules/system/defaults/NSGlobalDomain.nix | 12 ++--
 modules/system/defaults/alf.nix            | 15 +++--
 modules/system/defaults/loginwindow.nix    | 27 +++++---
 modules/system/defaults/spaces.nix         |  3 +-
 modules/system/patches.nix                 |  6 +-
 9 files changed, 87 insertions(+), 72 deletions(-)

diff --git a/modules/homebrew.nix b/modules/homebrew.nix
index 200e0d7d0..63f145092 100644
--- a/modules/homebrew.nix
+++ b/modules/homebrew.nix
@@ -31,9 +31,6 @@ let
 
   # Option and submodule helper functions ----------------------------------------------------------
 
-  mkDocOptionLink = optionName:
-    '''';
-
   mkNullOrBoolOption = args: mkOption (args // {
     type = types.nullOr types.bool;
     default = null;
@@ -104,7 +101,7 @@ let
 
           Although auto-updating is disabled by default during system activation, note that Homebrew
           will auto-update when you manually invoke certain Homebrew commands. To modify this
-          behavior see ${mkDocOptionLink "homebrew.global.autoUpdate"}.
+          behavior see .
         '';
       };
       upgrade = mkOption {
@@ -141,7 +138,7 @@ let
           the Nix store, when you manually invoke brew bundle.
 
           Enabling this option will change the default value of
-          ${mkDocOptionLink "homebrew.global.lockfiles"} to false since, with
+           to false since, with
           this option enabled, brew bundle [install] will default to using the
           Brewfile that this module generates in the Nix store, unless you explicitly point it at
           another Brewfile using the --file flag. As a result, it will try to
@@ -151,7 +148,7 @@ let
           Implementation note: when enabled, this option sets the
           HOMEBREW_BUNDLE_FILE environment variable to the path of the Brewfile
           that this module generates in the Nix store, by adding it to
-          ${mkDocOptionLink "environment.variables"}.
+          .
         '';
       };
       autoUpdate = mkOption {
@@ -166,14 +163,14 @@ let
           above if it's been more then 5 minutes since it last updated.
 
           You may want to consider disabling this option if you have
-          ${mkDocOptionLink "homebrew.onActivation.upgrade"} enabled, and
-          ${mkDocOptionLink "homebrew.onActivation.autoUpdate"} disabled, if you want to ensure that
+           enabled, and
+           disabled, if you want to ensure that
           your installed formulae will only be upgraded during nix-darwin system
           activation, after you've explicitly run brew update.
 
           Implementation note: when disabled, this option sets the
           HOMEBREW_NO_AUTO_UPDATE environment variable, by adding it to
-          ${mkDocOptionLink "environment.variables"}.
+          .
         '';
       };
       lockfiles = mkOption {
@@ -185,7 +182,7 @@ let
           brew bundle [install].
 
           This option will default to false if
-          ${mkDocOptionLink "homebrew.global.brewfile"} is enabled since, with that option enabled,
+           is enabled since, with that option enabled,
           brew bundle [install] will default to using the Brewfile that this
           module generates in the Nix store, unless you explicitly point it at another Brewfile
           using the --file flag. As a result, it will try to write the
@@ -194,7 +191,7 @@ let
 
           Implementation note: when disabled, this option sets the
           HOMEBREW_BUNDLE_NO_LOCK environment variable, by adding it to
-          ${mkDocOptionLink "environment.variables"}.
+          .
         '';
       };
 
@@ -265,70 +262,70 @@ let
         description = ''
           Target location for Applications.
 
-          Homebrew's default is /Applications.
+          Homebrew's default is /Applications.
         '';
       };
       colorpickerdir = mkNullOrStrOption {
         description = ''
           Target location for Color Pickers.
 
-          Homebrew's default is ~/Library/ColorPickers.
+          Homebrew's default is ~/Library/ColorPickers.
         '';
       };
       prefpanedir = mkNullOrStrOption {
         description = ''
           Target location for Preference Panes.
 
-          Homebrew's default is ~/Library/PreferencePanes.
+          Homebrew's default is ~/Library/PreferencePanes.
         '';
       };
       qlplugindir = mkNullOrStrOption {
         description = ''
           Target location for QuickLook Plugins.
 
-          Homebrew's default is ~/Library/QuickLook.
+          Homebrew's default is ~/Library/QuickLook.
         '';
       };
       mdimporterdir = mkNullOrStrOption {
         description = ''
           Target location for Spotlight Plugins.
 
-          Homebrew's default is ~/Library/Spotlight.
+          Homebrew's default is ~/Library/Spotlight.
         '';
       };
       dictionarydir = mkNullOrStrOption {
         description = ''
           Target location for Dictionaries.
 
-          Homebrew's default is ~/Library/Dictionaries.
+          Homebrew's default is ~/Library/Dictionaries.
         '';
       };
       fontdir = mkNullOrStrOption {
         description = ''
           Target location for Fonts.
 
-          Homebrew's default is ~/Library/Fonts.
+          Homebrew's default is ~/Library/Fonts.
         '';
       };
       servicedir = mkNullOrStrOption {
         description = ''
           Target location for Services.
 
-          Homebrew's default is ~/Library/Services.
+          Homebrew's default is ~/Library/Services.
         '';
       };
       input_methoddir = mkNullOrStrOption {
         description = ''
           Target location for Input Methods.
 
-          Homebrew's default is ~/Library/Input Methods.
+          Homebrew's default is ~/Library/Input Methods.
         '';
       };
       internet_plugindir = mkNullOrStrOption {
         description = ''
           Target location for Internet Plugins.
 
-          Homebrew's default is ~/Library/Internet Plug-Ins.
+          Homebrew's default is ~/Library/Internet Plug-Ins.
         '';
       };
       audio_unit_plugindir = mkNullOrStrOption {
@@ -336,28 +333,28 @@ let
           Target location for Audio Unit Plugins.
 
           Homebrew's default is
-          ~/Library/Audio/Plug-Ins/Components.
+          ~/Library/Audio/Plug-Ins/Components.
         '';
       };
       vst_plugindir = mkNullOrStrOption {
         description = ''
           Target location for VST Plugins.
 
-          Homebrew's default is ~/Library/Audio/Plug-Ins/VST.
+          Homebrew's default is ~/Library/Audio/Plug-Ins/VST.
         '';
       };
       vst3_plugindir = mkNullOrStrOption {
         description = ''
           Target location for VST3 Plugins.
 
-          Homebrew's default is ~/Library/Audio/Plug-Ins/VST3.
+          Homebrew's default is ~/Library/Audio/Plug-Ins/VST3.
         '';
       };
       screen_saverdir = mkNullOrStrOption {
         description = ''
           Target location for Screen Savers.
 
-          Homebrew's default is ~/Library/Screen Savers.
+          Homebrew's default is ~/Library/Screen Savers.
         '';
       };
       language = mkNullOrStrOption {
@@ -481,7 +478,7 @@ let
         visible = "shallow"; # so that options from `homebrew.caskArgs` aren't repeated.
         description = ''
           Arguments passed to brew install --cask when installing this cask. See
-          ${mkDocOptionLink "homebrew.caskArgs"} for the available options.
+           for the available options.
         '';
       };
       greedy = mkNullOrBoolOption {
@@ -523,12 +520,12 @@ in
       Note that enabling this option does not install Homebrew, see the Homebrew
       website for installation instructions.
 
-      Use the ${mkDocOptionLink "homebrew.brews"}, ${mkDocOptionLink "homebrew.casks"},
-      ${mkDocOptionLink "homebrew.masApps"}, and ${mkDocOptionLink "homebrew.whalebrews"} options
+      Use the , ,
+      , and  options
       to list the Homebrew formulae, casks, Mac App Store apps, and Docker containers you'd like to
-      install. Use the ${mkDocOptionLink "homebrew.taps"} option, to make additional formula
+      install. Use the  option, to make additional formula
       repositories available to Homebrew. This module uses those options (along with the
-      ${mkDocOptionLink "homebrew.caskArgs"} options) to generate a Brewfile that
+       options) to generate a Brewfile that
       nix-darwin passes to the brew bundle command during
       system activation.
 
@@ -536,10 +533,10 @@ in
       and all formulae, as well as upgrading anything that's already installed, so that repeated
       invocations of darwin-rebuild switch (without any change to the
       configuration) are idempotent. You can modify this behavior using the options under
-      ${mkDocOptionLink "homebrew.onActivation"}.
+      .
 
       This module also provides a few options for modifying how Homebrew commands behave when
-      you manually invoke them, under ${mkDocOptionLink "homebrew.global"}
+      you manually invoke them, under 
     '';
 
     brewPrefix = mkOption {
@@ -595,7 +592,7 @@ in
 
         Taps defined as strings, e.g., "user/repo", are a shorthand for:
 
-        { name = "user/repo"; }
+        { name = "user/repo"; }
       '';
     };
 
@@ -610,7 +607,7 @@ in
       '';
       description = ''
         Arguments passed to brew install --cask for all casks listed in
-        ${mkDocOptionLink "homebrew.casks"}.
+        .
       '';
     };
 
@@ -644,7 +641,7 @@ in
 
         Formulae defined as strings, e.g., "imagemagick", are a shorthand for:
 
-        { name = "imagemagick"; }
+        { name = "imagemagick"; }
       '';
     };
 
@@ -675,7 +672,7 @@ in
 
         Casks defined as strings, e.g., "google-chrome", are a shorthand for:
 
-        { name = "google-chrome"; }
+        { name = "google-chrome"; }
       '';
     };
 
@@ -692,12 +689,12 @@ in
         Applications to install from Mac App Store using mas.
 
         When this option is used, "mas" is automatically added to
-        ${mkDocOptionLink "homebrew.brews"}.
+        .
 
         Note that you need to be signed into the Mac App Store for mas to
         successfully install and upgrade applications, and that unfortunately apps removed from this
         option will not be uninstalled automatically even if
-        ${mkDocOptionLink "homebrew.onActivation.cleanup"} is set to "uninstall"
+         is set to "uninstall"
         or "zap" (this is currently a limitation of Homebrew Bundle).
 
         For more information on mas see:
@@ -713,7 +710,7 @@ in
         List of Docker images to install using whalebrew.
 
         When this option is used, "whalebrew" is automatically added to
-        ${mkDocOptionLink "homebrew.brews"}.
+        .
 
         For more information on whalebrew see:
         github.com/whalebrew/whalebrew.
diff --git a/modules/nix/default.nix b/modules/nix/default.nix
index a88094137..6c61acc11 100644
--- a/modules/nix/default.nix
+++ b/modules/nix/default.nix
@@ -173,11 +173,11 @@ in
       useDaemon = mkOption {
         type = types.bool;
         default = false;
-        description = "
+        description = ''
           If set, Nix will use the daemon to perform operations.
           Use this instead of services.nix-daemon.enable if you don't wan't the
           daemon service to be managed for you.
-        ";
+        '';
       };
 
       distributedBuilds = mkOption {
@@ -594,7 +594,7 @@ in
                 then Nix will use a binary from a binary cache if and only
                 if it is signed by any of the keys
                 listed here. By default, only the key for
-                cache.nixos.org is included.
+                cache.nixos.org is included.
               '';
             };
 
@@ -650,8 +650,7 @@ in
           
           for avalaible options.
           The value declared here will be translated directly to the key-value pairs Nix expects.
-          
-          
+
           Nix configurations defined under  will be translated and applied to this
           option. In addition, configuration specified in  which will be appended
           verbatim to the resulting config file.
diff --git a/modules/services/postgresql/default.nix b/modules/services/postgresql/default.nix
index bcaf95e2b..e6feb96e6 100644
--- a/modules/services/postgresql/default.nix
+++ b/modules/services/postgresql/default.nix
@@ -88,7 +88,7 @@ in
           via the Unix socket, and md5 password authentication will be
           used for users connecting via TCP. Any added rules will be
           inserted above the default rules. If you'd like to replace the
-          default rules entirely, you can use lib.mkForce in your
+          default rules entirely, you can use lib.mkForce in your
           module.
         '';
       };
@@ -159,7 +159,7 @@ in
                 For more information on how to specify the target
                 and on which privileges exist, see the
                 GRANT syntax.
-                The attributes are used as GRANT ''${attrValue} ON ''${attrName}.
+                The attributes are used as GRANT ''${attrValue} ON ''${attrName}.
               '';
               example = literalExpression ''
                 {
@@ -237,8 +237,8 @@ in
           for an overview of postgresql.conf.
 
           
-            String values will automatically be enclosed in single quotes. Single quotes will be
-            escaped with two single quotes as described by the upstream documentation linked above.
+          String values will automatically be enclosed in single quotes. Single quotes will be
+          escaped with two single quotes as described by the upstream documentation linked above.
           
         '';
         example = literalExpression ''
diff --git a/modules/services/synergy/default.nix b/modules/services/synergy/default.nix
index f7503da23..2ca97a063 100644
--- a/modules/services/synergy/default.nix
+++ b/modules/services/synergy/default.nix
@@ -23,9 +23,9 @@ in
         enable = mkOption {
           default = false;
           type = types.bool;
-          description = "
+          description = ''
             Whether to enable the Synergy client (receive keyboard and mouse events from a Synergy server).
-          ";
+          '';
         };
         screenName = mkOption {
           default = "";
diff --git a/modules/system/defaults/NSGlobalDomain.nix b/modules/system/defaults/NSGlobalDomain.nix
index 3fb8db0d2..a23737e95 100644
--- a/modules/system/defaults/NSGlobalDomain.nix
+++ b/modules/system/defaults/NSGlobalDomain.nix
@@ -229,7 +229,8 @@ in {
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Keyboard
+        Apple menu > System Preferences > Keyboard
+
         If you press and hold certain keyboard keys when in a text area, the key’s character begins to repeat.
         For example, the Delete key continues to remove text for as long as you hold it down.
 
@@ -241,7 +242,8 @@ in {
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Keyboard
+        Apple menu > System Preferences > Keyboard
+
         If you press and hold certain keyboard keys when in a text area, the key’s character begins to repeat.
         For example, the Delete key continues to remove text for as long as you hold it down.
 
@@ -285,7 +287,8 @@ in {
       type = types.nullOr floatWithDeprecationError;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Sound
+        Apple menu > System Preferences > Sound
+
         Sets the beep/alert volume level from 0.000 (muted) to 1.000 (100% volume).
 
         75% = 0.7788008
@@ -300,7 +303,8 @@ in {
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Sound
+        Apple menu > System Preferences > Sound
+
         Make a feedback sound when the system volume changed. This setting accepts
         the integers 0 or 1. Defaults to 1.
       '';
diff --git a/modules/system/defaults/alf.nix b/modules/system/defaults/alf.nix
index f62ead23c..96a980646 100644
--- a/modules/system/defaults/alf.nix
+++ b/modules/system/defaults/alf.nix
@@ -8,7 +8,8 @@ with lib;
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Security and Privacy > Firewall
+        Apple menu > System Preferences > Security and Privacy > Firewall
+
         Enable the internal firewall to prevent unauthorised applications, programs
         and services from accepting incoming connections.
 
@@ -22,7 +23,8 @@ with lib;
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Security and Privacy > Firewall
+        Apple menu > System Preferences > Security and Privacy > Firewall
+
         Allows any signed Application to accept incoming requests. Default is true.
 
         0 = disabled
@@ -34,7 +36,8 @@ with lib;
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Security and Privacy > Firewall
+        Apple menu > System Preferences > Security and Privacy > Firewall
+
         Allows any downloaded Application that has been signed to accept incoming requests. Default is 0.
 
         0 = disabled
@@ -46,7 +49,8 @@ with lib;
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Security and Privacy > Firewall
+        Apple menu > System Preferences > Security and Privacy > Firewall
+
         Enable logging of requests made to the firewall. Default is 0.
 
         0 = disabled
@@ -58,7 +62,8 @@ with lib;
       type = types.nullOr types.int;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Security and firewall
+        Apple menu > System Preferences > Security and firewall
+
         Drops incoming requests via ICMP such as ping requests. Default is 0.
 
         0 = disabled
diff --git a/modules/system/defaults/loginwindow.nix b/modules/system/defaults/loginwindow.nix
index 0194cc1d4..5f0491a23 100644
--- a/modules/system/defaults/loginwindow.nix
+++ b/modules/system/defaults/loginwindow.nix
@@ -8,7 +8,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Displays login window as a name and password field instead of a list of users.
         Default is false.
       '';
@@ -18,7 +19,8 @@ with lib;
       type = types.nullOr types.str;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Auto login the supplied user on boot. Default is Off.
       '';
     };
@@ -27,7 +29,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Allow users to login to the machine as guests using the Guest account. Default is true.
       '';
     };
@@ -44,7 +47,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Hides the Shut Down button on the login screen. Default is false.
       '';
     };
@@ -53,7 +57,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Hides the Sleep button on the login screen. Default is false.
       '';
     };
@@ -62,7 +67,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Hides the Restart button on the login screen. Default is false.
       '';
     };
@@ -71,7 +77,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Disables the "Shutdown" option when users are logged in. Default is false.
       '';
     };
@@ -80,7 +87,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         If set to true, the Power Off menu item will be disabled when the user is logged in. Default is false.
       '';
     };
@@ -89,7 +97,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Users and Groups > Login Options
+        Apple menu > System Preferences > Users and Groups > Login Options
+
         Disables the “Restart” option when users are logged in. Default is false.
       '';
     };
diff --git a/modules/system/defaults/spaces.nix b/modules/system/defaults/spaces.nix
index 8f256f3b0..ac2355bbb 100644
--- a/modules/system/defaults/spaces.nix
+++ b/modules/system/defaults/spaces.nix
@@ -8,7 +8,8 @@ with lib;
       type = types.nullOr types.bool;
       default = null;
       description = ''
-        # Apple menu > System Preferences > Mission Control
+        Apple menu > System Preferences > Mission Control
+
         Displays have separate Spaces (note a logout is required before
         this setting will take effect).
 
diff --git a/modules/system/patches.nix b/modules/system/patches.nix
index 452ed3bf2..0b5668174 100644
--- a/modules/system/patches.nix
+++ b/modules/system/patches.nix
@@ -29,9 +29,9 @@ in
       description = ''
         Set of patches to apply to /.
 
-        
-        This can modify everything so use with caution.
-        
+        
+        This can modify everything so use with caution.
+        
 
         Useful for safely changing system files.  Unlike the etc module this
         won't remove or modify files with unexpected content.

From c2716817a8e5fb47889aaf625aa13b89d786da51 Mon Sep 17 00:00:00 2001
From: Emily 
Date: Thu, 22 Jun 2023 07:06:54 +0100
Subject: [PATCH 057/161] {offlineimap,tailscale}: fix `enable` option docs

The argument to `mkEnableOption` is automatically wrapped in a full
sentence.
---
 modules/services/mail/offlineimap.nix | 2 +-
 modules/services/tailscale.nix        | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/modules/services/mail/offlineimap.nix b/modules/services/mail/offlineimap.nix
index 9d0d4dce6..4f76dc55e 100644
--- a/modules/services/mail/offlineimap.nix
+++ b/modules/services/mail/offlineimap.nix
@@ -7,7 +7,7 @@ let
 in {
 
   options.services.offlineimap = {
-    enable = mkEnableOption "Offlineimap, a software to dispose your mailbox(es) as a local Maildir(s).";
+    enable = mkEnableOption "Offlineimap, a software to dispose your mailbox(es) as a local Maildir(s)";
 
     package = mkOption {
       type = types.package;
diff --git a/modules/services/tailscale.nix b/modules/services/tailscale.nix
index 6e1a86d80..afe4382d7 100644
--- a/modules/services/tailscale.nix
+++ b/modules/services/tailscale.nix
@@ -24,7 +24,12 @@ in
     };
 
     magicDNS = {
-      enable = mkEnableOption "Whether to configure networking to work with Tailscale's MagicDNS.";
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = "Whether to configure networking to work with Tailscale's MagicDNS.";
+      };
     };
   };
 

From efe314cdbabaf5cd210d9c658b4ad540437b7ee5 Mon Sep 17 00:00:00 2001
From: Emily 
Date: Thu, 22 Jun 2023 09:05:03 +0100
Subject: [PATCH 058/161] treewide: manually convert some docs to Markdown

These all use DocBook markup too complex for `nix-doc-munge` to handle,
have syntax that clashes with Markdown, or already contain Markdown
syntax that currently isn't rendering correctly.

Converting DocBook list syntax makes me think that maybe Markdown
isn't so bad after all.
---
 modules/launchd/default.nix                 |   6 +-
 modules/launchd/launchd.nix                 |  28 ++---
 modules/networking/default.nix              |   6 +-
 modules/nix/default.nix                     |   2 +-
 modules/security/pam.nix                    |   4 +-
 modules/services/wg-quick.nix               |   8 +-
 modules/system/defaults/ActivityMonitor.nix |  30 +++---
 modules/system/defaults/dock.nix            | 112 +++++++++-----------
 modules/system/defaults/loginwindow.nix     |   4 +-
 modules/system/defaults/universalaccess.nix |   2 +-
 10 files changed, 99 insertions(+), 103 deletions(-)

diff --git a/modules/launchd/default.nix b/modules/launchd/default.nix
index f82df2a2f..ed85509c8 100644
--- a/modules/launchd/default.nix
+++ b/modules/launchd/default.nix
@@ -137,7 +137,7 @@ in
     launchd.agents = mkOption {
       default = {};
       type = types.attrsOf (types.submodule serviceOptions);
-      description = ''
+      description = lib.mdDoc ''
         Definition of per-user launchd agents.
 
         When a user logs in, a per-user launchd is started.
@@ -153,7 +153,7 @@ in
     launchd.daemons = mkOption {
       default = {};
       type = types.attrsOf (types.submodule serviceOptions);
-      description = ''
+      description = lib.mdDoc ''
         Definition of launchd daemons.
 
         After the system is booted and the kernel is running, launchd is run to finish the system initialization.
@@ -169,7 +169,7 @@ in
     launchd.user.agents = mkOption {
       default = {};
       type = types.attrsOf (types.submodule serviceOptions);
-      description = ''
+      description = lib.mdDoc ''
         Definition of per-user launchd agents.
 
         When a user logs in, a per-user launchd is started.
diff --git a/modules/launchd/launchd.nix b/modules/launchd/launchd.nix
index 727db951e..61a78d90d 100644
--- a/modules/launchd/launchd.nix
+++ b/modules/launchd/launchd.nix
@@ -633,27 +633,27 @@ with lib;
       type = types.nullOr (types.enum [ "Background" "Standard" "Adaptive" "Interactive" ]);
       default = null;
       example = "Background";
-      description = ''
+      description = lib.mdDoc ''
         This optional key describes, at a high level, the intended purpose of the job.  The system will apply
         resource limits based on what kind of job it is. If left unspecified, the system will apply light
         resource limits to the job, throttling its CPU usage and I/O bandwidth. The following are valid values:
 
-           Background
-           Background jobs are generally processes that do work that was not directly requested by the user.
-           The resource limits applied to Background jobs are intended to prevent them from disrupting the
-           user experience.
+        Background
+        : Background jobs are generally processes that do work that was not directly requested by the user.
+          The resource limits applied to Background jobs are intended to prevent them from disrupting the
+          user experience.
 
-           Standard
-           Standard jobs are equivalent to no ProcessType being set.
+        Standard
+        : Standard jobs are equivalent to no ProcessType being set.
 
-           Adaptive
-           Adaptive jobs move between the Background and Interactive classifications based on activity over
-           XPC connections. See xpc_transaction_begin(3) for details.
+        Adaptive
+        : Adaptive jobs move between the Background and Interactive classifications based on activity over
+          XPC connections. See `xpc_transaction_begin(3)` for details.
 
-           Interactive
-           Interactive jobs run with the same resource limitations as apps, that is to say, none. Interactive
-           jobs are critical to maintaining a responsive user experience, and this key should only be
-           used if an app's ability to be responsive depends on it, and cannot be made Adaptive.
+        Interactive
+        : Interactive jobs run with the same resource limitations as apps, that is to say, none. Interactive
+          jobs are critical to maintaining a responsive user experience, and this key should only be
+          used if an app's ability to be responsive depends on it, and cannot be made Adaptive.
       '';
     };
 
diff --git a/modules/networking/default.nix b/modules/networking/default.nix
index 46cd982e7..727933f59 100644
--- a/modules/networking/default.nix
+++ b/modules/networking/default.nix
@@ -29,7 +29,7 @@ in
       type = types.nullOr types.str;
       default = null;
       example = "John’s MacBook Pro";
-      description = ''
+      description = lib.mdDoc ''
         The user-friendly name for the system, set in System Preferences > Sharing > Computer Name.
 
         Setting this option is equivalent to running `scutil --set ComputerName`.
@@ -42,7 +42,7 @@ in
       type = types.nullOr (types.strMatching hostnameRegEx);
       default = null;
       example = "Johns-MacBook-Pro";
-      description = ''
+      description = lib.mdDoc ''
         The hostname of your system, as visible from the command line and used by local and remote
         networks when connecting through SSH and Remote Login.
 
@@ -56,7 +56,7 @@ in
       type = types.nullOr (types.strMatching hostnameRegEx);
       default = cfg.hostName;
       example = "Johns-MacBook-Pro";
-      description = ''
+      description = lib.mdDoc ''
         The local hostname, or local network name, is displayed beneath the computer's name at the
         top of the Sharing preferences pane. It identifies your Mac to Bonjour-compatible services.
 
diff --git a/modules/nix/default.nix b/modules/nix/default.nix
index 6c61acc11..cf71401b3 100644
--- a/modules/nix/default.nix
+++ b/modules/nix/default.nix
@@ -277,7 +277,7 @@ in
               type = types.nullOr types.str;
               default = null;
               example = "/root/.ssh/id_buildhost_builduser";
-              description = ''
+              description = lib.mdDoc ''
                 The path to the SSH private key with which to authenticate on
                 the build machine. The private key must not have a passphrase.
                 If null, the building user (root on NixOS machines) must have an
diff --git a/modules/security/pam.nix b/modules/security/pam.nix
index ac7603f25..0061fbacf 100644
--- a/modules/security/pam.nix
+++ b/modules/security/pam.nix
@@ -39,7 +39,7 @@ in
 
 {
   options = {
-    security.pam.enableSudoTouchIdAuth = mkEnableOption ''
+    security.pam.enableSudoTouchIdAuth = mkEnableOption (lib.mdDoc ''
       Enable sudo authentication with Touch ID
 
       When enabled, this option adds the following line to /etc/pam.d/sudo:
@@ -49,7 +49,7 @@ in
       (Note that macOS resets this file when doing a system update. As such, sudo
       authentication with Touch ID won't work after a system update until the nix-darwin
       configuration is reapplied.)
-    '';
+    '');
   };
 
   config = {
diff --git a/modules/services/wg-quick.nix b/modules/services/wg-quick.nix
index 40725ffb2..14568237d 100644
--- a/modules/services/wg-quick.nix
+++ b/modules/services/wg-quick.nix
@@ -113,8 +113,12 @@ let
       table = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description =
-          "Controls the routing table to which routes are added. There are two special values:  `off' disables  the  creation  of routes altogether, and `auto' (the default) adds routes to the default table and enables special handling of default routes.";
+        description = lib.mdDoc ''
+          Controls the routing table to which routes are added. There are two
+          special values: `off` disables the creation of routes altogether,
+          and `auto` (the default) adds routes to the default table and
+          enables special handling of default routes.
+        '';
       };
     };
   };
diff --git a/modules/system/defaults/ActivityMonitor.nix b/modules/system/defaults/ActivityMonitor.nix
index d57c6c043..270c67885 100644
--- a/modules/system/defaults/ActivityMonitor.nix
+++ b/modules/system/defaults/ActivityMonitor.nix
@@ -8,16 +8,16 @@ with lib;
     system.defaults.ActivityMonitor.ShowCategory = mkOption {
       type = types.nullOr (types.enum [100 101 102 103 104 105 106 107]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           Change which processes to show.
-            100: All Processes
-            101: All Processes, Hierarchally
-            102: My Processes
-            103: System Processes
-            104: Other User Processes
-            105: Active Processes
-            106: Inactive Processes
-            107: Windowed Processes
+          * 100: All Processes
+          * 101: All Processes, Hierarchally
+          * 102: My Processes
+          * 103: System Processes
+          * 104: Other User Processes
+          * 105: Active Processes
+          * 106: Inactive Processes
+          * 107: Windowed Processes
           Default is 100.
         '';
     };
@@ -25,13 +25,13 @@ with lib;
     system.defaults.ActivityMonitor.IconType = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           Change the icon in the dock when running.
-            0: Application Icon
-            2: Network Usage
-            3: Disk Activity
-            5: CPU Usage
-            6: CPU History
+          * 0: Application Icon
+          * 2: Network Usage
+          * 3: Disk Activity
+          * 5: CPU Usage
+          * 6: CPU History
           Default is null.
         '';
     };
diff --git a/modules/system/defaults/dock.nix b/modules/system/defaults/dock.nix
index ba62e7a40..82c8befbd 100644
--- a/modules/system/defaults/dock.nix
+++ b/modules/system/defaults/dock.nix
@@ -166,92 +166,84 @@ in {
     system.defaults.dock.wvous-tl-corner = mkOption {
       type = types.nullOr types.ints.positive;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Hot corner action for top left corner. Valid values include:
 
-        
-        1: Disabled
-        2: Mission Control
-        3: Application Windows
-        4: Desktop
-        5: Start Screen Saver
-        6: Disable Screen Saver
-        7: Dashboard
-        10: Put Display to Sleep
-        11: Launchpad
-        12: Notification Center
-        13: Lock Screen
-        14: Quick Note
-        
+        * `1`: Disabled
+        * `2`: Mission Control
+        * `3`: Application Windows
+        * `4`: Desktop
+        * `5`: Start Screen Saver
+        * `6`: Disable Screen Saver
+        * `7`: Dashboard
+        * `10`: Put Display to Sleep
+        * `11`: Launchpad
+        * `12`: Notification Center
+        * `13`: Lock Screen
+        * `14`: Quick Note
       '';
     };
 
     system.defaults.dock.wvous-bl-corner = mkOption {
       type = types.nullOr types.ints.positive;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Hot corner action for bottom left corner. Valid values include:
 
-        
-        1: Disabled
-        2: Mission Control
-        3: Application Windows
-        4: Desktop
-        5: Start Screen Saver
-        6: Disable Screen Saver
-        7: Dashboard
-        10: Put Display to Sleep
-        11: Launchpad
-        12: Notification Center
-        13: Lock Screen
-        14: Quick Note
-        
+        * `1`: Disabled
+        * `2`: Mission Control
+        * `3`: Application Windows
+        * `4`: Desktop
+        * `5`: Start Screen Saver
+        * `6`: Disable Screen Saver
+        * `7`: Dashboard
+        * `10`: Put Display to Sleep
+        * `11`: Launchpad
+        * `12`: Notification Center
+        * `13`: Lock Screen
+        * `14`: Quick Note
       '';
     };
 
     system.defaults.dock.wvous-tr-corner = mkOption {
       type = types.nullOr types.ints.positive;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Hot corner action for top right corner. Valid values include:
 
-        
-        1: Disabled
-        2: Mission Control
-        3: Application Windows
-        4: Desktop
-        5: Start Screen Saver
-        6: Disable Screen Saver
-        7: Dashboard
-        10: Put Display to Sleep
-        11: Launchpad
-        12: Notification Center
-        13: Lock Screen
-        14: Quick Note
-        
+        * `1`: Disabled
+        * `2`: Mission Control
+        * `3`: Application Windows
+        * `4`: Desktop
+        * `5`: Start Screen Saver
+        * `6`: Disable Screen Saver
+        * `7`: Dashboard
+        * `10`: Put Display to Sleep
+        * `11`: Launchpad
+        * `12`: Notification Center
+        * `13`: Lock Screen
+        * `14`: Quick Note
       '';
     };
 
     system.defaults.dock.wvous-br-corner = mkOption {
       type = types.nullOr types.ints.positive;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Hot corner action for bottom right corner. Valid values include:
 
-        
-        1: Disabled
-        2: Mission Control
-        3: Application Windows
-        4: Desktop
-        5: Start Screen Saver
-        6: Disable Screen Saver
-        7: Dashboard
-        10: Put Display to Sleep
-        11: Launchpad
-        12: Notification Center
-        13: Lock Screen
-        14: Quick Note
-        
+        * `1`: Disabled
+        * `2`: Mission Control
+        * `3`: Application Windows
+        * `4`: Desktop
+        * `5`: Start Screen Saver
+        * `6`: Disable Screen Saver
+        * `7`: Dashboard
+        * `10`: Put Display to Sleep
+        * `11`: Launchpad
+        * `12`: Notification Center
+        * `13`: Lock Screen
+        * `14`: Quick Note
       '';
     };
 
diff --git a/modules/system/defaults/loginwindow.nix b/modules/system/defaults/loginwindow.nix
index 5f0491a23..0fb709643 100644
--- a/modules/system/defaults/loginwindow.nix
+++ b/modules/system/defaults/loginwindow.nix
@@ -38,8 +38,8 @@ with lib;
     system.defaults.loginwindow.LoginwindowText = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
-        Text to be shown on the login window. Default is "\\U03bb".
+      description = lib.mdDoc ''
+        Text to be shown on the login window. Default is "\\\\U03bb".
       '';
     };
 
diff --git a/modules/system/defaults/universalaccess.nix b/modules/system/defaults/universalaccess.nix
index 6d6a974e3..bb4bec971 100644
--- a/modules/system/defaults/universalaccess.nix
+++ b/modules/system/defaults/universalaccess.nix
@@ -37,7 +37,7 @@ with lib;
     system.defaults.universalaccess.closeViewZoomFollowsFocus = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Follow the keyboard focus while zoomed in.
         Without setting `closeViewScrollWheelToggle` this has no effect.
         The default is false.

From e65131e69cab1b18fb49b572b983a18720502e1b Mon Sep 17 00:00:00 2001
From: Emily 
Date: Thu, 22 Jun 2023 12:21:32 +0100
Subject: [PATCH 059/161] treewide: convert all option docs to Markdown

This process was automated by [my fork of `nix-doc-munge`]; thanks
to @pennae for writing this tool! It automatically checks that the
resulting documentation doesn't change, although my fork loosens
this a little to ignore some irrelevant whitespace and typographical
differences.

As of this commit there is no DocBook remaining in the options
documentation.

You can play along at home if you want to reproduce this commit:

    $ NIX_PATH=nixpkgs=flake:nixpkgs/c1bca7fe84c646cfd4ebf3482c0e6317a0b13f22 \
      nix shell nixpkgs#coreutils \
      -c find . -name '*.nix' \
      -exec nix run github:emilazy/nix-doc-munge/0a7190f600027bf7baf6cb7139e4d69ac2f51062 \
      {} +

[my fork of `nix-doc-munge`]: https://github.com/emilazy/nix-doc-munge
---
 modules/documentation/default.nix             |  16 +-
 modules/environment/default.nix               |  32 +-
 modules/fonts/default.nix                     |   6 +-
 modules/homebrew.nix                          | 294 +++++++++---------
 modules/launchd/default.nix                   |  22 +-
 modules/launchd/launchd.nix                   | 262 ++++++++--------
 modules/lib/write-text.nix                    |  10 +-
 modules/meta.nix                              |   6 +-
 modules/misc/ids.nix                          |   4 +-
 modules/misc/lib.nix                          |   2 +-
 modules/networking/default.nix                |   8 +-
 modules/nix/default.nix                       | 144 ++++-----
 modules/nix/nixpkgs.nix                       |  12 +-
 modules/programs/bash/default.nix             |   6 +-
 modules/programs/fish.nix                     |  28 +-
 modules/programs/gnupg.nix                    |   4 +-
 modules/programs/info/default.nix             |   2 +-
 modules/programs/man.nix                      |   6 +-
 modules/programs/nix-index/default.nix        |   4 +-
 modules/programs/ssh/default.nix              |  26 +-
 modules/programs/tmux.nix                     |  16 +-
 modules/programs/vim.nix                      |  10 +-
 modules/programs/zsh/default.nix              |  24 +-
 modules/security/pki/default.nix              |  12 +-
 modules/security/sandbox/default.nix          |  14 +-
 modules/services/activate-system/default.nix  |   2 +-
 modules/services/autossh.nix                  |  10 +-
 modules/services/buildkite-agents.nix         |   2 +-
 modules/services/cachix-agent.nix             |  12 +-
 modules/services/chunkwm.nix                  |  16 +-
 modules/services/dnsmasq.nix                  |  10 +-
 modules/services/emacs.nix                    |   8 +-
 modules/services/gitlab-runner.nix            | 112 +++----
 .../services/hercules-ci-agent/default.nix    |   2 +-
 modules/services/ipfs.nix                     |  14 +-
 .../services/karabiner-elements/default.nix   |   2 +-
 modules/services/khd/default.nix              |   8 +-
 modules/services/kwm/default.nix              |   6 +-
 modules/services/lorri.nix                    |   8 +-
 modules/services/mail/offlineimap.nix         |  12 +-
 modules/services/monitoring/telegraf.nix      |  10 +-
 modules/services/mopidy.nix                   |   8 +-
 modules/services/netbird.nix                  |   4 +-
 modules/services/nextdns/default.nix          |   4 +-
 modules/services/nix-daemon.nix               |  12 +-
 modules/services/nix-gc/default.nix           |  10 +-
 modules/services/ofborg/default.nix           |   8 +-
 modules/services/postgresql/default.nix       |  66 ++--
 modules/services/privoxy/default.nix          |  12 +-
 modules/services/redis/default.nix            |  16 +-
 modules/services/skhd/default.nix             |   6 +-
 modules/services/spacebar/default.nix         |   8 +-
 modules/services/spotifyd.nix                 |   8 +-
 modules/services/synapse-bt.nix               |  10 +-
 modules/services/synergy/default.nix          |  32 +-
 modules/services/tailscale.nix                |   8 +-
 modules/services/wg-quick.nix                 |  36 +--
 modules/services/yabai/default.nix            |  10 +-
 modules/system/activation-scripts.nix         |   4 +-
 modules/system/checks.nix                     |   6 +-
 modules/system/default.nix                    |  10 +-
 modules/system/defaults/ActivityMonitor.nix   |   6 +-
 modules/system/defaults/CustomPreferences.nix |   4 +-
 modules/system/defaults/GlobalPreferences.nix |   4 +-
 modules/system/defaults/LaunchServices.nix    |   2 +-
 modules/system/defaults/NSGlobalDomain.nix    |  92 +++---
 modules/system/defaults/SoftwareUpdate.nix    |   2 +-
 modules/system/defaults/alf.nix               |  10 +-
 modules/system/defaults/clock.nix             |  14 +-
 modules/system/defaults/dock.nix              |  38 +--
 modules/system/defaults/finder.nix            |  20 +-
 modules/system/defaults/loginwindow.nix       |  20 +-
 modules/system/defaults/magicmouse.nix        |   2 +-
 modules/system/defaults/screencapture.nix     |   6 +-
 modules/system/defaults/screensaver.nix       |   4 +-
 modules/system/defaults/smb.nix               |   4 +-
 modules/system/defaults/spaces.nix            |   2 +-
 modules/system/defaults/trackpad.nix          |  14 +-
 modules/system/defaults/universalaccess.nix   |   6 +-
 modules/system/etc.nix                        |   4 +-
 modules/system/keyboard.nix                   |  14 +-
 modules/system/launchd.nix                    |  12 +-
 modules/system/patches.nix                    |  10 +-
 modules/system/shells.nix                     |   4 +-
 modules/system/version.nix                    |  18 +-
 modules/time/default.nix                      |   7 +-
 modules/users/default.nix                     |  10 +-
 modules/users/group.nix                       |   8 +-
 modules/users/user.nix                        |  20 +-
 89 files changed, 921 insertions(+), 918 deletions(-)

diff --git a/modules/documentation/default.nix b/modules/documentation/default.nix
index d741995c0..7712a1320 100644
--- a/modules/documentation/default.nix
+++ b/modules/documentation/default.nix
@@ -89,9 +89,9 @@ in
     documentation.enable = mkOption {
       type = types.bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether to install documentation of packages from
-         into the generated system path.
+        {option}`environment.systemPackages` into the generated system path.
 
         See "Multiple-output packages" chapter in the nixpkgs manual for more info.
       '';
@@ -101,8 +101,8 @@ in
     documentation.man.enable = mkOption {
       type = types.bool;
       default = true;
-      description = ''
-        Whether to install manual pages and the man command.
+      description = lib.mdDoc ''
+        Whether to install manual pages and the {command}`man` command.
         This also includes "man" outputs.
       '';
     };
@@ -110,8 +110,8 @@ in
     documentation.info.enable = mkOption {
       type = types.bool;
       default = true;
-      description = ''
-        Whether to install info pages and the info command.
+      description = lib.mdDoc ''
+        Whether to install info pages and the {command}`info` command.
         This also includes "info" outputs.
       '';
     };
@@ -119,8 +119,8 @@ in
     documentation.doc.enable = mkOption {
       type = types.bool;
       default = true;
-      description = ''
-        Whether to install documentation distributed in packages' /share/doc.
+      description = lib.mdDoc ''
+        Whether to install documentation distributed in packages' `/share/doc`.
         Usually plain text and/or HTML.
         This also includes "doc" outputs.
       '';
diff --git a/modules/environment/default.nix b/modules/environment/default.nix
index 1fed0f44f..c4883c395 100644
--- a/modules/environment/default.nix
+++ b/modules/environment/default.nix
@@ -21,57 +21,57 @@ in
       type = types.listOf types.package;
       default = [];
       example = literalExpression "[ pkgs.curl pkgs.vim ]";
-      description = ''
+      description = lib.mdDoc ''
         The set of packages that appear in
         /run/current-system/sw.  These packages are
         automatically available to all users, and are
         automatically updated every time you rebuild the system
         configuration.  (The latter is the main difference with
         installing them in the default profile,
-        /nix/var/nix/profiles/default.
+        {file}`/nix/var/nix/profiles/default`.
       '';
     };
 
     environment.systemPath = mkOption {
       type = types.listOf (types.either types.path types.str);
-      description = "The set of paths that are added to PATH.";
+      description = lib.mdDoc "The set of paths that are added to PATH.";
       apply = x: if isList x then makeDrvBinPath x else x;
     };
 
     environment.profiles = mkOption {
       type = types.listOf types.str;
-      description = "A list of profiles used to setup the global environment.";
+      description = lib.mdDoc "A list of profiles used to setup the global environment.";
     };
 
     environment.postBuild = mkOption {
       type = types.lines;
       default = "";
-      description = "Commands to execute when building the global environment.";
+      description = lib.mdDoc "Commands to execute when building the global environment.";
     };
 
     environment.extraOutputsToInstall = mkOption {
       type = types.listOf types.str;
       default = [];
       example = [ "doc" "info" "devdoc" ];
-      description = "List of additional package outputs to be symlinked into /run/current-system/sw.";
+      description = lib.mdDoc "List of additional package outputs to be symlinked into {file}`/run/current-system/sw`.";
     };
 
     environment.pathsToLink = mkOption {
       type = types.listOf types.str;
       default = [];
       example = [ "/share/doc" ];
-      description = "List of directories to be symlinked in /run/current-system/sw.";
+      description = lib.mdDoc "List of directories to be symlinked in {file}`/run/current-system/sw`.";
     };
 
     environment.darwinConfig = mkOption {
       type = types.either types.path types.str;
       default = "$HOME/.nixpkgs/darwin-configuration.nix";
-      description = ''
+      description = lib.mdDoc ''
         The path of the darwin configuration.nix used to configure the system,
         this updates the default darwin-config entry in NIX_PATH. Since this
         changes an environment variable it will only apply to new shells.
 
-        NOTE: Changing this requires running darwin-rebuild switch -I darwin-config=/path/to/configuration.nix
+        NOTE: Changing this requires running {command}`darwin-rebuild switch -I darwin-config=/path/to/configuration.nix`
         the first time to make darwin-rebuild aware of the custom location.
       '';
     };
@@ -79,14 +79,14 @@ in
     environment.loginShell = mkOption {
       type = types.str;
       default = "$SHELL -l";
-      description = "Configure default login shell.";
+      description = lib.mdDoc "Configure default login shell.";
     };
 
     environment.variables = mkOption {
       type = types.attrsOf (types.either types.str (types.listOf types.str));
       default = {};
       example = { EDITOR = "vim"; LANG = "nl_NL.UTF-8"; };
-      description = ''
+      description = lib.mdDoc ''
         A set of environment variables used in the global environment.
         These variables will be set on shell initialisation.
         The value of each variable can be either a string or a list of
@@ -100,7 +100,7 @@ in
       type = types.attrsOf types.str;
       default = {};
       example = { ll = "ls -l"; };
-      description = ''
+      description = lib.mdDoc ''
         An attribute set that maps aliases (the top level attribute names in
         this option) to command strings or directly to build outputs. The
         alises are added to all users' shells.
@@ -110,7 +110,7 @@ in
     environment.extraInit = mkOption {
       type = types.lines;
       default = "";
-      description = ''
+      description = lib.mdDoc ''
         Shell script code called during global environment initialisation
         after all variables and profileVariables have been set.
         This code is asumed to be shell-independent, which means you should
@@ -120,7 +120,7 @@ in
 
     environment.shellInit = mkOption {
       default = "";
-      description = ''
+      description = lib.mdDoc ''
         Shell script code called during shell initialisation.
         This code is asumed to be shell-independent, which means you should
         stick to pure sh without sh word split.
@@ -130,7 +130,7 @@ in
 
     environment.loginShellInit = mkOption {
       default = "";
-      description = ''
+      description = lib.mdDoc ''
         Shell script code called during login shell initialisation.
         This code is asumed to be shell-independent, which means you should
         stick to pure sh without sh word split.
@@ -140,7 +140,7 @@ in
 
     environment.interactiveShellInit = mkOption {
       default = "";
-      description = ''
+      description = lib.mdDoc ''
         Shell script code called during interactive shell initialisation.
         This code is asumed to be shell-independent, which means you should
         stick to pure sh without sh word split.
diff --git a/modules/fonts/default.nix b/modules/fonts/default.nix
index 2739b7465..ef6de1508 100644
--- a/modules/fonts/default.nix
+++ b/modules/fonts/default.nix
@@ -14,9 +14,9 @@ in
   options = {
     fonts.fontDir.enable = mkOption {
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable font management and install configured fonts to
-        /Library/Fonts.
+        {file}`/Library/Fonts`.
 
         NOTE: removes any manually-added fonts.
       '';
@@ -26,7 +26,7 @@ in
       type = types.listOf types.path;
       default = [ ];
       example = literalExpression "[ pkgs.dejavu_fonts ]";
-      description = ''
+      description = lib.mdDoc ''
         List of fonts to install.
 
         Fonts present in later entries override those with the same filenames
diff --git a/modules/homebrew.nix b/modules/homebrew.nix
index 63f145092..4951d7f6a 100644
--- a/modules/homebrew.nix
+++ b/modules/homebrew.nix
@@ -65,52 +65,52 @@ let
         type = types.enum [ "none" "uninstall" "zap" ];
         default = "none";
         example = "uninstall";
-        description = ''
+        description = lib.mdDoc ''
           This option manages what happens to formulae installed by Homebrew, that aren't present in
-          the Brewfile generated by this module, during nix-darwin system
+          the Brewfile generated by this module, during {command}`nix-darwin` system
           activation.
 
-          When set to "none" (the default), formulae not present in the generated
+          When set to `"none"` (the default), formulae not present in the generated
           Brewfile are left installed.
 
-          When set to "uninstall", nix-darwin invokes
-          brew bundle [install] with the --cleanup flag. This
+          When set to `"uninstall"`, {command}`nix-darwin` invokes
+          {command}`brew bundle [install]` with the {command}`--cleanup` flag. This
           uninstalls all formulae not listed in generated Brewfile, i.e.,
-          brew uninstall is run for those formulae.
+          {command}`brew uninstall` is run for those formulae.
 
-          When set to "zap", nix-darwin invokes
-          brew bundle [install] with the --cleanup --zap
+          When set to `"zap"`, {command}`nix-darwin` invokes
+          {command}`brew bundle [install]` with the {command}`--cleanup --zap`
           flags. This uninstalls all formulae not listed in the generated Brewfile, and if the
           formula is a cask, removes all files associated with that cask. In other words,
-          brew uninstall --zap is run for all those formulae.
+          {command}`brew uninstall --zap` is run for all those formulae.
 
-          If you plan on exclusively using nix-darwin to manage formulae
+          If you plan on exclusively using {command}`nix-darwin` to manage formulae
           installed by Homebrew, you probably want to set this option to
-          "uninstall" or "zap".
+          `"uninstall"` or `"zap"`.
         '';
       };
       autoUpdate = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable Homebrew to auto-update itself and all formulae during
-          nix-darwin system activation. The default is false
-          so that repeated invocations of darwin-rebuild switch are idempotent.
+          {command}`nix-darwin` system activation. The default is `false`
+          so that repeated invocations of {command}`darwin-rebuild switch` are idempotent.
 
           Note that Homebrew auto-updates when it's been more then 5 minutes since it last updated.
 
           Although auto-updating is disabled by default during system activation, note that Homebrew
           will auto-update when you manually invoke certain Homebrew commands. To modify this
-          behavior see .
+          behavior see [](#opt-homebrew.global.autoUpdate).
         '';
       };
       upgrade = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable Homebrew to upgrade outdated formulae and Mac App Store apps during
-          nix-darwin system activation. The default is false
-          so that repeated invocations of darwin-rebuild switch are idempotent.
+          {command}`nix-darwin` system activation. The default is `false`
+          so that repeated invocations of {command}`darwin-rebuild switch` are idempotent.
         '';
       };
 
@@ -133,65 +133,65 @@ let
       brewfile = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable Homebrew to automatically use the Brewfile that this module generates in
-          the Nix store, when you manually invoke brew bundle.
+          the Nix store, when you manually invoke {command}`brew bundle`.
 
           Enabling this option will change the default value of
-           to false since, with
-          this option enabled, brew bundle [install] will default to using the
+          [](#opt-homebrew.global.lockfiles) to `false` since, with
+          this option enabled, {command}`brew bundle [install]` will default to using the
           Brewfile that this module generates in the Nix store, unless you explicitly point it at
-          another Brewfile using the --file flag. As a result, it will try to
+          another Brewfile using the `--file` flag. As a result, it will try to
           write the lockfile in the Nix store, and complain that it can't (though the command will
           run successfully regardless).
 
           Implementation note: when enabled, this option sets the
-          HOMEBREW_BUNDLE_FILE environment variable to the path of the Brewfile
+          `HOMEBREW_BUNDLE_FILE` environment variable to the path of the Brewfile
           that this module generates in the Nix store, by adding it to
-          .
+          [](#opt-environment.variables).
         '';
       };
       autoUpdate = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable Homebrew to auto-update itself and all formulae when you manually invoke
-          commands like brew install, brew upgrade,
-          brew tap, and brew bundle [install].
+          commands like {command}`brew install`, {command}`brew upgrade`,
+          {command}`brew tap`, and {command}`brew bundle [install]`.
 
           Note that Homebrew auto-updates when you manually invoke commands like the ones mentioned
           above if it's been more then 5 minutes since it last updated.
 
           You may want to consider disabling this option if you have
-           enabled, and
-           disabled, if you want to ensure that
-          your installed formulae will only be upgraded during nix-darwin system
-          activation, after you've explicitly run brew update.
+          [](#opt-homebrew.onActivation.upgrade) enabled, and
+          [](#opt-homebrew.onActivation.autoUpdate) disabled, if you want to ensure that
+          your installed formulae will only be upgraded during {command}`nix-darwin` system
+          activation, after you've explicitly run {command}`brew update`.
 
           Implementation note: when disabled, this option sets the
-          HOMEBREW_NO_AUTO_UPDATE environment variable, by adding it to
-          .
+          `HOMEBREW_NO_AUTO_UPDATE` environment variable, by adding it to
+          [](#opt-environment.variables).
         '';
       };
       lockfiles = mkOption {
         type = types.bool;
         default = !config.brewfile;
         defaultText = literalExpression "!config.homebrew.global.brewfile";
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable Homebrew to generate lockfiles when you manually invoke
-          brew bundle [install].
+          {command}`brew bundle [install]`.
 
-          This option will default to false if
-           is enabled since, with that option enabled,
-          brew bundle [install] will default to using the Brewfile that this
+          This option will default to `false` if
+          [](#opt-homebrew.global.brewfile) is enabled since, with that option enabled,
+          {command}`brew bundle [install]` will default to using the Brewfile that this
           module generates in the Nix store, unless you explicitly point it at another Brewfile
-          using the --file flag. As a result, it will try to write the
+          using the `--file` flag. As a result, it will try to write the
           lockfile in the Nix store, and complain that it can't (though the command will run
           successfully regardless).
 
           Implementation note: when disabled, this option sets the
-          HOMEBREW_BUNDLE_NO_LOCK environment variable, by adding it to
-          .
+          `HOMEBREW_BUNDLE_NO_LOCK` environment variable, by adding it to
+          [](#opt-environment.variables).
         '';
       };
 
@@ -217,22 +217,22 @@ let
       name = mkOption {
         type = types.str;
         example = "homebrew/cask-fonts";
-        description = ''
-          When  is unspecified, this is the name of a formula
-          repository to tap from GitHub using HTTPS. For example, "user/repo"
+        description = lib.mdDoc ''
+          When {option}`clone_target` is unspecified, this is the name of a formula
+          repository to tap from GitHub using HTTPS. For example, `"user/repo"`
           will tap https://github.com/user/homebrew-repo.
         '';
       };
       clone_target = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Use this option to tap a formula repository from anywhere, using any transport protocol
-          that git handles. When  is specified, taps
+          that {command}`git` handles. When {option}`clone_target` is specified, taps
           can be cloned from places other than GitHub and using protocols other than HTTPS, e.g.,
           SSH, git, HTTP, FTP(S), rsync.
         '';
       };
       force_auto_update = mkNullOrBoolOption {
-        description = ''
+        description = lib.mdDoc ''
           Whether to auto-update the tap even if it is not hosted on GitHub. By default, only taps
           hosted on GitHub are auto-updated (for performance reasons).
         '';
@@ -259,106 +259,106 @@ let
   caskArgsOptions = { config, ... }: {
     options = {
       appdir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Applications.
 
-          Homebrew's default is /Applications.
+          Homebrew's default is {file}`/Applications`.
         '';
       };
       colorpickerdir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Color Pickers.
 
-          Homebrew's default is ~/Library/ColorPickers.
+          Homebrew's default is {file}`~/Library/ColorPickers`.
         '';
       };
       prefpanedir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Preference Panes.
 
-          Homebrew's default is ~/Library/PreferencePanes.
+          Homebrew's default is {file}`~/Library/PreferencePanes`.
         '';
       };
       qlplugindir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for QuickLook Plugins.
 
-          Homebrew's default is ~/Library/QuickLook.
+          Homebrew's default is {file}`~/Library/QuickLook`.
         '';
       };
       mdimporterdir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Spotlight Plugins.
 
-          Homebrew's default is ~/Library/Spotlight.
+          Homebrew's default is {file}`~/Library/Spotlight`.
         '';
       };
       dictionarydir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Dictionaries.
 
-          Homebrew's default is ~/Library/Dictionaries.
+          Homebrew's default is {file}`~/Library/Dictionaries`.
         '';
       };
       fontdir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Fonts.
 
-          Homebrew's default is ~/Library/Fonts.
+          Homebrew's default is {file}`~/Library/Fonts`.
         '';
       };
       servicedir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Services.
 
-          Homebrew's default is ~/Library/Services.
+          Homebrew's default is {file}`~/Library/Services`.
         '';
       };
       input_methoddir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Input Methods.
 
-          Homebrew's default is ~/Library/Input Methods.
+          Homebrew's default is {file}`~/Library/Input Methods`.
         '';
       };
       internet_plugindir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Internet Plugins.
 
-          Homebrew's default is ~/Library/Internet Plug-Ins.
+          Homebrew's default is {file}`~/Library/Internet Plug-Ins`.
         '';
       };
       audio_unit_plugindir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Audio Unit Plugins.
 
           Homebrew's default is
-          ~/Library/Audio/Plug-Ins/Components.
+          {file}`~/Library/Audio/Plug-Ins/Components`.
         '';
       };
       vst_plugindir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for VST Plugins.
 
-          Homebrew's default is ~/Library/Audio/Plug-Ins/VST.
+          Homebrew's default is {file}`~/Library/Audio/Plug-Ins/VST`.
         '';
       };
       vst3_plugindir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for VST3 Plugins.
 
-          Homebrew's default is ~/Library/Audio/Plug-Ins/VST3.
+          Homebrew's default is {file}`~/Library/Audio/Plug-Ins/VST3`.
         '';
       };
       screen_saverdir = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Target location for Screen Savers.
 
-          Homebrew's default is ~/Library/Screen Savers.
+          Homebrew's default is {file}`~/Library/Screen Savers`.
         '';
       };
       language = mkNullOrStrOption {
-        description = ''
+        description = lib.mdDoc ''
           Comma-separated list of language codes to prefer for cask installation. The first matching
           language is used, otherwise it reverts to the cask’s default language. The default value
           is the language of your system.
@@ -366,17 +366,17 @@ let
         example = "zh-TW";
       };
       require_sha = mkNullOrBoolOption {
-        description = ''
+        description = lib.mdDoc ''
           Whether to require cask(s) to have a checksum.
 
-          Homebrew's default is false.
+          Homebrew's default is `false`.
         '';
       };
       no_quarantine = mkNullOrBoolOption {
-        description = "Whether to disable quarantining of downloads.";
+        description = lib.mdDoc "Whether to disable quarantining of downloads.";
       };
       no_binaries = mkNullOrBoolOption {
-        description = "Whether to disable linking of helper executables.";
+        description = lib.mdDoc "Whether to disable linking of helper executables.";
       };
 
       brewfileLine = mkInternalOption { type = types.nullOr types.str; };
@@ -397,20 +397,20 @@ let
     options = {
       name = mkOption {
         type = types.str;
-        description = "The name of the formula to install.";
+        description = lib.mdDoc "The name of the formula to install.";
       };
       args = mkOption {
         type = with types; nullOr (listOf str);
         default = null;
-        description = ''
-          Arguments flags to pass to brew install. Values should not include the
-          leading "--".
+        description = lib.mdDoc ''
+          Arguments flags to pass to {command}`brew install`. Values should not include the
+          leading `"--"`.
         '';
       };
       conflicts_with = mkOption {
         type = with types; nullOr (listOf str);
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           List of formulae that should be unlinked and their services stopped (if they are
           installed).
         '';
@@ -418,26 +418,26 @@ let
       restart_service = mkOption {
         type = with types; nullOr (either bool (enum [ "changed" ]));
         default = null;
-        description = ''
-          Whether to run brew services restart for the formula and register it to
-          launch at login (or boot). If set to "changed", the service will only
+        description = lib.mdDoc ''
+          Whether to run {command}`brew services restart` for the formula and register it to
+          launch at login (or boot). If set to `"changed"`, the service will only
           be restarted on version changes.
 
-          Homebrew's default is false.
+          Homebrew's default is `false`.
         '';
       };
       start_service = mkNullOrBoolOption {
-        description = ''
-          Whether to run brew services start for the formula and register it to
+        description = lib.mdDoc ''
+          Whether to run {command}`brew services start` for the formula and register it to
           launch at login (or boot).
 
-          Homebrew's default is false.
+          Homebrew's default is `false`.
         '';
       };
       link = mkNullOrBoolOption {
-        description = ''
+        description = lib.mdDoc ''
           Whether to link the formula to the Homebrew prefix. When this option is
-          null, Homebrew will use it's default behavior which is to link the
+          `null`, Homebrew will use it's default behavior which is to link the
           formula if it's currently unlinked and not keg-only, and to unlink the formula if it's
           currently linked and keg-only.
         '';
@@ -470,19 +470,19 @@ let
     options = {
       name = mkOption {
         type = types.str;
-        description = "The name of the cask to install.";
+        description = lib.mdDoc "The name of the cask to install.";
       };
       args = mkOption {
         type = types.nullOr (types.submodule caskArgsOptions);
         default = null;
         visible = "shallow"; # so that options from `homebrew.caskArgs` aren't repeated.
-        description = ''
-          Arguments passed to brew install --cask when installing this cask. See
-           for the available options.
+        description = lib.mdDoc ''
+          Arguments passed to {command}`brew install --cask` when installing this cask. See
+          [](#opt-homebrew.caskArgs) for the available options.
         '';
       };
       greedy = mkNullOrBoolOption {
-        description = ''
+        description = lib.mdDoc ''
           Whether to always upgrade this cask regardless of whether it's unversioned or it updates
           itself.
         '';
@@ -513,31 +513,31 @@ in
   ];
 
   options.homebrew = {
-    enable = mkEnableOption ''
-      nix-darwin to manage installing/updating/upgrading Homebrew taps, formulae,
+    enable = mkEnableOption (lib.mdDoc ''
+      {command}`nix-darwin` to manage installing/updating/upgrading Homebrew taps, formulae,
       and casks, as well as Mac App Store apps and Docker containers, using Homebrew Bundle.
 
       Note that enabling this option does not install Homebrew, see the Homebrew
-      website for installation instructions.
+      [website](https://brew.sh) for installation instructions.
 
-      Use the , ,
-      , and  options
+      Use the [](#opt-homebrew.brews), [](#opt-homebrew.casks),
+      [](#opt-homebrew.masApps), and [](#opt-homebrew.whalebrews) options
       to list the Homebrew formulae, casks, Mac App Store apps, and Docker containers you'd like to
-      install. Use the  option, to make additional formula
+      install. Use the [](#opt-homebrew.taps) option, to make additional formula
       repositories available to Homebrew. This module uses those options (along with the
-       options) to generate a Brewfile that
-      nix-darwin passes to the brew bundle command during
+      [](#opt-homebrew.caskArgs) options) to generate a Brewfile that
+      {command}`nix-darwin` passes to the {command}`brew bundle` command during
       system activation.
 
       The default configuration of this module prevents Homebrew Bundle from auto-updating Homebrew
       and all formulae, as well as upgrading anything that's already installed, so that repeated
-      invocations of darwin-rebuild switch (without any change to the
+      invocations of {command}`darwin-rebuild switch` (without any change to the
       configuration) are idempotent. You can modify this behavior using the options under
-      .
+      [](#opt-homebrew.onActivation).
 
       This module also provides a few options for modifying how Homebrew commands behave when
-      you manually invoke them, under 
-    '';
+      you manually invoke them, under [](#opt-homebrew.global)
+    '');
 
     brewPrefix = mkOption {
       type = types.str;
@@ -546,8 +546,8 @@ in
         if pkgs.stdenv.hostPlatform.isAarch64 then "/opt/homebrew/bin"
         else "/usr/local/bin"
       '';
-      description = ''
-        The path prefix where the brew executable is located. This will be set to
+      description = lib.mdDoc ''
+        The path prefix where the {command}`brew` executable is located. This will be set to
         the correct value based on your system's platform, and should only need to be changed if you
         manually installed Homebrew in a non-standard location.
       '';
@@ -556,16 +556,16 @@ in
     onActivation = mkOption {
       type = types.submodule onActivationOptions;
       default = { };
-      description = ''
-        Options for configuring the behavior of the brew bundle command that
-        nix-darwin runs during system activation.
+      description = lib.mdDoc ''
+        Options for configuring the behavior of the {command}`brew bundle` command that
+        {command}`nix-darwin` runs during system activation.
       '';
     };
 
     global = mkOption {
       type = types.submodule globalOptions;
       default = { };
-      description = ''
+      description = lib.mdDoc ''
         Options for configuring the behavior of Homebrew commands when you manually invoke them.
       '';
     };
@@ -587,12 +587,12 @@ in
           }
         ]
       '';
-      description = ''
+      description = lib.mdDoc ''
         List of Homebrew formula repositories to tap.
 
-        Taps defined as strings, e.g., "user/repo", are a shorthand for:
+        Taps defined as strings, e.g., `"user/repo"`, are a shorthand for:
 
-        { name = "user/repo"; }
+        `{ name = "user/repo"; }`
       '';
     };
 
@@ -605,9 +605,9 @@ in
           require_sha = true;
         }
       '';
-      description = ''
-        Arguments passed to brew install --cask for all casks listed in
-        .
+      description = lib.mdDoc ''
+        Arguments passed to {command}`brew install --cask` for all casks listed in
+        [](#opt-homebrew.casks).
       '';
     };
 
@@ -636,12 +636,12 @@ in
           }
         ]
       '';
-      description = ''
+      description = lib.mdDoc ''
         List of Homebrew formulae to install.
 
-        Formulae defined as strings, e.g., "imagemagick", are a shorthand for:
+        Formulae defined as strings, e.g., `"imagemagick"`, are a shorthand for:
 
-        { name = "imagemagick"; }
+        `{ name = "imagemagick"; }`
       '';
     };
 
@@ -667,12 +667,12 @@ in
           }
         ]
       '';
-      description = ''
+      description = lib.mdDoc ''
         List of Homebrew casks to install.
 
-        Casks defined as strings, e.g., "google-chrome", are a shorthand for:
+        Casks defined as strings, e.g., `"google-chrome"`, are a shorthand for:
 
-        { name = "google-chrome"; }
+        `{ name = "google-chrome"; }`
       '';
     };
 
@@ -685,20 +685,20 @@ in
           Xcode = 497799835;
         }
       '';
-      description = ''
-        Applications to install from Mac App Store using mas.
+      description = lib.mdDoc ''
+        Applications to install from Mac App Store using {command}`mas`.
 
-        When this option is used, "mas" is automatically added to
-        .
+        When this option is used, `"mas"` is automatically added to
+        [](#opt-homebrew.brews).
 
-        Note that you need to be signed into the Mac App Store for mas to
+        Note that you need to be signed into the Mac App Store for {command}`mas` to
         successfully install and upgrade applications, and that unfortunately apps removed from this
         option will not be uninstalled automatically even if
-         is set to "uninstall"
-        or "zap" (this is currently a limitation of Homebrew Bundle).
+        [](#opt-homebrew.onActivation.cleanup) is set to `"uninstall"`
+        or `"zap"` (this is currently a limitation of Homebrew Bundle).
 
-        For more information on mas see:
-        github.com/mas-cli/mas.
+        For more information on {command}`mas` see:
+        [github.com/mas-cli/mas](https://github.com/mas-cli/mas).
       '';
     };
 
@@ -706,14 +706,14 @@ in
       type = with types; listOf str;
       default = [ ];
       example = [ "whalebrew/wget" ];
-      description = ''
-        List of Docker images to install using whalebrew.
+      description = lib.mdDoc ''
+        List of Docker images to install using {command}`whalebrew`.
 
-        When this option is used, "whalebrew" is automatically added to
-        .
+        When this option is used, `"whalebrew"` is automatically added to
+        [](#opt-homebrew.brews).
 
-        For more information on whalebrew see:
-        github.com/whalebrew/whalebrew.
+        For more information on {command}`whalebrew` see:
+        [github.com/whalebrew/whalebrew](https://github.com/whalebrew/whalebrew).
       '';
     };
 
@@ -724,12 +724,12 @@ in
         # 'brew cask install' only if '/usr/libexec/java_home --failfast' fails
         cask "java" unless system "/usr/libexec/java_home --failfast"
       '';
-      description = "Extra lines to be added verbatim to the bottom of the generated Brewfile.";
+      description = lib.mdDoc "Extra lines to be added verbatim to the bottom of the generated Brewfile.";
     };
 
     brewfile = mkInternalOption {
       type = types.str;
-      description = "String reprensentation of the generated Brewfile useful for debugging.";
+      description = lib.mdDoc "String reprensentation of the generated Brewfile useful for debugging.";
     };
   };
 
diff --git a/modules/launchd/default.nix b/modules/launchd/default.nix
index ed85509c8..d1b2b50aa 100644
--- a/modules/launchd/default.nix
+++ b/modules/launchd/default.nix
@@ -31,16 +31,16 @@ let
           type = types.attrsOf (types.either types.str (types.listOf types.str));
           default = {};
           example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
-          description = "Environment variables passed to the service's processes.";
+          description = lib.mdDoc "Environment variables passed to the service's processes.";
           apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
         };
 
         path = mkOption {
           type = types.listOf (types.either types.path types.str);
           default = [];
-          description = ''
-            Packages added to the service's PATH
-            environment variable.  Only the bin
+          description = lib.mdDoc ''
+            Packages added to the service's {env}`PATH`
+            environment variable.  Only the {file}`bin`
             and subdirectories of each package is added.
           '';
           apply = ps: if isList ps then (makeDrvBinPath ps) else ps;
@@ -49,13 +49,13 @@ let
         command = mkOption {
           type = types.either types.str types.path;
           default = "";
-          description = "Command executed as the service's main process.";
+          description = lib.mdDoc "Command executed as the service's main process.";
         };
 
         script = mkOption {
           type = types.lines;
           default = "";
-          description = "Shell commands executed as the service's main process.";
+          description = lib.mdDoc "Shell commands executed as the service's main process.";
         };
 
         # preStart = mkOption {
@@ -74,9 +74,9 @@ let
               KeepAlive = true;
             };
           default = {};
-          description = ''
+          description = lib.mdDoc ''
             Each attribute in this set specifies an option for a key in the plist.
-            
+            
           '';
         };
       };
@@ -100,7 +100,7 @@ in
     launchd.labelPrefix = mkOption {
       type = types.str;
       default = "org.nixos";
-      description = ''
+      description = lib.mdDoc ''
         The default prefix of the service label. Individual services can
         override this by setting the Label attribute.
       '';
@@ -110,7 +110,7 @@ in
       type = types.attrsOf (types.either types.str (types.listOf types.str));
       default = {};
       example = { LANG = "nl_NL.UTF-8"; };
-      description = ''
+      description = lib.mdDoc ''
         A set of environment variables to be set on all future
         processes launched by launchd in the caller's context.
         The value of each variable can be either a string or a list of
@@ -124,7 +124,7 @@ in
       type = types.attrsOf (types.either types.str (types.listOf types.str));
       default = {};
       example = { LANG = "nl_NL.UTF-8"; };
-      description = ''
+      description = lib.mdDoc ''
         A set of environment variables to be set on all future
         processes launched by launchd in the caller's context.
         The value of each variable can be either a string or a list of
diff --git a/modules/launchd/launchd.nix b/modules/launchd/launchd.nix
index 61a78d90d..b1a2d395b 100644
--- a/modules/launchd/launchd.nix
+++ b/modules/launchd/launchd.nix
@@ -6,24 +6,24 @@ with lib;
   options = {
     Label = mkOption {
       type = types.str;
-      description = "This required key uniquely identifies the job to launchd.";
+      description = lib.mdDoc "This required key uniquely identifies the job to launchd.";
     };
 
     Disabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
-        This optional key is used as a hint to launchctl(1) that it should not submit this job to launchd when
+      description = lib.mdDoc ''
+        This optional key is used as a hint to `launchctl(1)` that it should not submit this job to launchd when
         loading a job or jobs. The value of this key does NOT reflect the current state of the job on the running
         system. If you wish to know whether a job is loaded in launchd, reading this key from a configuration
         file yourself is not a sufficient test. You should query launchd for the presence of the job using
-        the launchctl(1) list subcommand or use the ServiceManagement framework's
-        SMJobCopyDictionary() method.
+        the `launchctl(1)` list subcommand or use the ServiceManagement framework's
+        `SMJobCopyDictionary()` method.
 
         Note that as of Mac OS X v10.6, this key's value in a configuration file conveys a default value, which
-        is changed with the [-w] option of the launchctl(1) load and unload subcommands. These subcommands no
+        is changed with the [-w] option of the `launchctl(1)` load and unload subcommands. These subcommands no
         longer modify the configuration file, so the value displayed in the configuration file is not necessarily
-        the value that launchctl(1) will apply. See launchctl(1) for more information.
+        the value that `launchctl(1)` will apply. See `launchctl(1)` for more information.
 
         Please also be mindful that you should only use this key if the provided on-demand and KeepAlive criteria
         are insufficient to describe the conditions under which your job needs to run. The cost to have a
@@ -35,7 +35,7 @@ with lib;
     UserName = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies the user to run the job as. This key is only applicable when launchd is
         running as root.
       '';
@@ -44,7 +44,7 @@ with lib;
     GroupName = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies the group to run the job as. This key is only applicable when launchd is
         running as root. If UserName is set and GroupName is not, the the group will be set to the default
         group of the user.
@@ -54,7 +54,7 @@ with lib;
     inetdCompatibility = mkOption {
       default = null;
       example = { Wait = true; };
-      description = ''
+      description = lib.mdDoc ''
         The presence of this key specifies that the daemon expects to be run as if it were launched from inetd.
       '';
       type = types.nullOr (types.submodule {
@@ -62,9 +62,9 @@ with lib;
           Wait = mkOption {
             type = types.nullOr (types.either types.bool types.str);
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               This flag corresponds to the "wait" or "nowait" option of inetd. If true, then the listening
-              socket is passed via the standard in/out/error file descriptors. If false, then accept(2) is
+              socket is passed via the standard in/out/error file descriptors. If false, then `accept(2)` is
               called on behalf of the job, and the result is passed via the standard in/out/error descriptors.
             '';
           };
@@ -75,35 +75,35 @@ with lib;
     LimitLoadToHosts = mkOption {
       type = types.nullOr (types.listOf types.str);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This configuration file only applies to the hosts listed with this key. Note: One should set kern.hostname
-        in sysctl.conf(5) for this feature to work reliably.
+        in `sysctl.conf(5)` for this feature to work reliably.
       '';
     };
 
     LimitLoadFromHosts = mkOption {
       type = types.nullOr (types.listOf types.str);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This configuration file only applies to hosts NOT listed with this key. Note: One should set kern.hostname
-        in sysctl.conf(5) for this feature to work reliably.
+        in `sysctl.conf(5)` for this feature to work reliably.
       '';
     };
 
     LimitLoadToSessionType = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This configuration file only applies to sessions of the type specified. This key is used in concert
-        with the -S flag to launchctl.
+        with the -S flag to {command}`launchctl`.
       '';
     };
 
     Program = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = ''
-        This key maps to the first argument of execvp(3).  If this key is missing, then the first element of
+      description = lib.mdDoc ''
+        This key maps to the first argument of `execvp(3)`.  If this key is missing, then the first element of
         the array of strings provided to the ProgramArguments will be used instead.  This key is required in
         the absence of the ProgramArguments key.
       '';
@@ -112,26 +112,26 @@ with lib;
     ProgramArguments = mkOption {
       type = types.nullOr (types.listOf types.str);
       default = null;
-      description = ''
-        This key maps to the second argument of execvp(3).  This key is required in the absence of the Program
-        key. Please note: many people are confused by this key. Please read execvp(3) very carefully!
+      description = lib.mdDoc ''
+        This key maps to the second argument of `execvp(3)`.  This key is required in the absence of the Program
+        key. Please note: many people are confused by this key. Please read `execvp(3)` very carefully!
       '';
     };
 
     EnableGlobbing = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
-        This flag causes launchd to use the glob(3) mechanism to update the program arguments before invocation.
+      description = lib.mdDoc ''
+        This flag causes launchd to use the `glob(3)` mechanism to update the program arguments before invocation.
       '';
     };
 
     EnableTransactions = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
-        This flag instructs launchd that the job promises to use vproc_transaction_begin(3) and
-        vproc_transaction_end(3) to track outstanding transactions that need to be reconciled before the
+      description = lib.mdDoc ''
+        This flag instructs launchd that the job promises to use `vproc_transaction_begin(3)` and
+        `vproc_transaction_end(3)` to track outstanding transactions that need to be reconciled before the
         process can safely terminate. If no outstanding transactions are in progress, then launchd is free to
         send the SIGKILL signal.
       '';
@@ -140,7 +140,7 @@ with lib;
     OnDemand = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This key was used in Mac OS X 10.4 to control whether a job was kept alive or not. The default was
         true.  This key has been deprecated and replaced in Mac OS X 10.5 and later with the more powerful
         KeepAlive option.
@@ -154,7 +154,7 @@ with lib;
           SuccessfulExit = mkOption {
             type = types.nullOr types.bool;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               If true, the job will be restarted as long as the program exits and with an exit status of zero.
               If false, the job will be restarted in the inverse condition.  This key implies that "RunAtLoad"
               is set to true, since the job needs to run at least once before we can get an exit status.
@@ -164,7 +164,7 @@ with lib;
           NetworkState = mkOption {
             type = types.nullOr types.bool;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               If true, the job will be kept alive as long as the network is up, where up is defined as at least
               one non-loopback interface being up and having IPv4 or IPv6 addresses assigned to them.  If
               false, the job will be kept alive in the inverse condition.
@@ -174,7 +174,7 @@ with lib;
           PathState = mkOption {
             type = types.nullOr (types.attrsOf types.bool);
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Each key in this dictionary is a file-system path. If the value of the key is true, then the job
               will be kept alive as long as the path exists.  If false, the job will be kept alive in the
               inverse condition. The intent of this feature is that two or more jobs may create semaphores in
@@ -185,7 +185,7 @@ with lib;
           OtherJobEnabled = mkOption {
             type = types.nullOr (types.attrsOf types.bool);
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Each key in this dictionary is the label of another job. If the value of the key is true, then
               this job is kept alive as long as that other job is enabled. Otherwise, if the value is false,
               then this job is kept alive as long as the other job is disabled.  This feature should not be
@@ -196,7 +196,7 @@ with lib;
           Crashed = mkOption {
             type = types.nullOr types.bool;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               If true, the the job will be restarted as long as it exited due to a signal which is typically
               associated with a crash (SIGILL, SIGSEGV, etc.). If false, the job will be restarted in the
               inverse condition.
@@ -211,7 +211,7 @@ with lib;
         };
       }));
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key is used to control whether your job is to be kept continuously running or to let
         demand and conditions control the invocation. The default is false and therefore only demand will start
         the job. The value may be set to true to unconditionally keep the job alive. Alternatively, a dictionary
@@ -226,7 +226,7 @@ with lib;
     RunAtLoad = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key is used to control whether your job is launched once at the time the job is loaded.
         The default is false.
       '';
@@ -235,23 +235,23 @@ with lib;
     RootDirectory = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
-        This optional key is used to specify a directory to chroot(2) to before running the job.
+      description = lib.mdDoc ''
+        This optional key is used to specify a directory to `chroot(2)` to before running the job.
       '';
     };
 
     WorkingDirectory = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
-        This optional key is used to specify a directory to chdir(2) to before running the job.
+      description = lib.mdDoc ''
+        This optional key is used to specify a directory to `chdir(2)` to before running the job.
       '';
     };
 
     EnvironmentVariables = mkOption {
       type = types.nullOr (types.attrsOf types.str);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key is used to specify additional environment variables to be set before running the
         job.
       '';
@@ -260,8 +260,8 @@ with lib;
     Umask = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
-        This optional key specifies what value should be passed to umask(2) before running the job. Known bug:
+      description = lib.mdDoc ''
+        This optional key specifies what value should be passed to `umask(2)` before running the job. Known bug:
         Property lists don't support octal, so please convert the value to decimal.
       '';
     };
@@ -269,7 +269,7 @@ with lib;
     TimeOut = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         The recommended idle time out (in seconds) to pass to the job. If no value is specified, a default time
         out will be supplied by launchd for use by the job at check in time.
       '';
@@ -278,7 +278,7 @@ with lib;
     ExitTimeOut = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         The amount of time launchd waits before sending a SIGKILL signal. The default value is 20 seconds. The
         value zero is interpreted as infinity.
       '';
@@ -287,7 +287,7 @@ with lib;
     ThrottleInterval = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This key lets one override the default throttling policy imposed on jobs by launchd.  The value is in
         seconds, and by default, jobs will not be spawned more than once every 10 seconds.  The principle
         behind this is that jobs should linger around just in case they are needed again in the near future.
@@ -299,8 +299,8 @@ with lib;
     InitGroups = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
-        This optional key specifies whether initgroups(3) should be called before running the job.  The default
+      description = lib.mdDoc ''
+        This optional key specifies whether `initgroups(3)` should be called before running the job.  The default
         is true in 10.5 and false in 10.4. This key will be ignored if the UserName key is not set.
       '';
     };
@@ -308,7 +308,7 @@ with lib;
     WatchPaths = mkOption {
       type = types.nullOr (types.listOf types.path);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key causes the job to be started if any one of the listed paths are modified.
       '';
     };
@@ -316,7 +316,7 @@ with lib;
     QueueDirectories = mkOption {
       type = types.nullOr (types.listOf types.str);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Much like the WatchPaths option, this key will watch the paths for modifications. The difference being
         that the job will only be started if the path is a directory and the directory is not empty.
       '';
@@ -325,7 +325,7 @@ with lib;
     StartOnMount = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key causes the job to be started every time a filesystem is mounted.
       '';
     };
@@ -333,7 +333,7 @@ with lib;
     StartInterval = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key causes the job to be started every N seconds.  If the system is asleep, the job will
         be started the next time the computer wakes up.  If multiple intervals transpire before the computer is
         woken, those events will be coalesced into one event upon wake from sleep.
@@ -343,9 +343,9 @@ with lib;
     StartCalendarInterval = mkOption {
       default = null;
       example = { Hour = 2; Minute = 30; };
-      description = ''
+      description = lib.mdDoc ''
         This optional key causes the job to be started every calendar interval as specified. Missing arguments
-        are considered to be wildcard. The semantics are much like crontab(5).  Unlike cron which skips job
+        are considered to be wildcard. The semantics are much like `crontab(5)`.  Unlike cron which skips job
         invocations when the computer is asleep, launchd will start the job the next time the computer wakes
         up.  If multiple intervals transpire before the computer is woken, those events will be coalesced into
         one event upon wake from sleep.
@@ -355,7 +355,7 @@ with lib;
           Minute = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The minute on which this job will be run.
             '';
           };
@@ -363,7 +363,7 @@ with lib;
           Hour = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The hour on which this job will be run.
             '';
           };
@@ -371,7 +371,7 @@ with lib;
           Day = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The day on which this job will be run.
             '';
           };
@@ -379,7 +379,7 @@ with lib;
           Weekday = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The weekday on which this job will be run (0 and 7 are Sunday).
             '';
           };
@@ -387,7 +387,7 @@ with lib;
           Month = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The month on which this job will be run.
             '';
           };
@@ -398,32 +398,32 @@ with lib;
     StandardInPath = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies what file should be used for data being supplied to stdin when using
-        stdio(3).
+        `stdio(3)`.
       '';
     };
 
     StandardOutPath = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = ''
-        This optional key specifies what file should be used for data being sent to stdout when using stdio(3).
+      description = lib.mdDoc ''
+        This optional key specifies what file should be used for data being sent to stdout when using `stdio(3)`.
       '';
     };
 
     StandardErrorPath = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = ''
-        This optional key specifies what file should be used for data being sent to stderr when using stdio(3).
+      description = lib.mdDoc ''
+        This optional key specifies what file should be used for data being sent to stderr when using `stdio(3)`.
       '';
     };
 
     Debug = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies that launchd should adjust its log mask temporarily to LOG_DEBUG while
         dealing with this job.
       '';
@@ -432,7 +432,7 @@ with lib;
     WaitForDebugger = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies that launchd should instruct the kernel to have the job wait for a debugger
         to attach before any code in the job is executed.
       '';
@@ -440,8 +440,8 @@ with lib;
 
     SoftResourceLimits = mkOption {
       default = null;
-      description = ''
-        Resource limits to be imposed on the job. These adjust variables set with setrlimit(2).  The following
+      description = lib.mdDoc ''
+        Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`.  The following
         keys apply:
       '';
       type = types.nullOr (types.submodule {
@@ -449,7 +449,7 @@ with lib;
           Core = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The largest size (in bytes) core file that may be created.
             '';
           };
@@ -457,7 +457,7 @@ with lib;
           CPU = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum amount of cpu time (in seconds) to be used by each process.
             '';
           };
@@ -465,16 +465,16 @@ with lib;
           Data = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum size (in bytes) of the data segment for a process; this defines how far a program may
-              extend its break with the sbrk(2) system call.
+              extend its break with the `sbrk(2)` system call.
             '';
           };
 
           FileSize = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The largest size (in bytes) file that may be created.
             '';
           };
@@ -482,7 +482,7 @@ with lib;
           MemoryLock = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum size (in bytes) which a process may lock into memory using the mlock(2) function.
             '';
           };
@@ -490,27 +490,27 @@ with lib;
           NumberOfFiles = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum number of open files for this process.  Setting this value in a system wide daemon
-              will set the sysctl(3) kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
-              value in addition to the setrlimit(2) values.
+              will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
+              value in addition to the `setrlimit(2)` values.
             '';
           };
 
           NumberOfProcesses = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum number of simultaneous processes for this user id.  Setting this value in a system
-              wide daemon will set the sysctl(3) kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
-              (HardResourceLimits) value in addition to the setrlimit(2) values.
+              wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
+              (HardResourceLimits) value in addition to the `setrlimit(2)` values.
             '';
           };
 
           ResidentSetSize = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum size (in bytes) to which a process's resident set size may grow.  This imposes a
               limit on the amount of physical memory to be given to a process; if memory is tight, the system
               will prefer to take memory from processes that are exceeding their declared resident set size.
@@ -520,7 +520,7 @@ with lib;
           Stack = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
               stack segment may be extended.  Stack extension is performed automatically by the system.
             '';
@@ -532,8 +532,8 @@ with lib;
     HardResourceLimits = mkOption {
       default = null;
       example = { NumberOfFiles = 4096; };
-      description = ''
-        Resource limits to be imposed on the job. These adjust variables set with setrlimit(2).  The following
+      description = lib.mdDoc ''
+        Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`.  The following
         keys apply:
       '';
       type = types.nullOr (types.submodule {
@@ -541,7 +541,7 @@ with lib;
           Core = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The largest size (in bytes) core file that may be created.
             '';
           };
@@ -549,7 +549,7 @@ with lib;
           CPU = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum amount of cpu time (in seconds) to be used by each process.
             '';
           };
@@ -557,16 +557,16 @@ with lib;
           Data = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum size (in bytes) of the data segment for a process; this defines how far a program may
-              extend its break with the sbrk(2) system call.
+              extend its break with the `sbrk(2)` system call.
             '';
           };
 
           FileSize = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The largest size (in bytes) file that may be created.
             '';
           };
@@ -574,35 +574,35 @@ with lib;
           MemoryLock = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
-              The maximum size (in bytes) which a process may lock into memory using the mlock(2) function.
+            description = lib.mdDoc ''
+              The maximum size (in bytes) which a process may lock into memory using the `mlock(2)` function.
             '';
           };
 
           NumberOfFiles = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum number of open files for this process.  Setting this value in a system wide daemon
-              will set the sysctl(3) kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
-              value in addition to the setrlimit(2) values.
+              will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
+              value in addition to the `setrlimit(2)` values.
             '';
           };
 
           NumberOfProcesses = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum number of simultaneous processes for this user id.  Setting this value in a system
-              wide daemon will set the sysctl(3) kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
-              (HardResourceLimits) value in addition to the setrlimit(2) values.
+              wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
+              (HardResourceLimits) value in addition to the `setrlimit(2)` values.
             '';
           };
 
           ResidentSetSize = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum size (in bytes) to which a process's resident set size may grow.  This imposes a
               limit on the amount of physical memory to be given to a process; if memory is tight, the system
               will prefer to take memory from processes that are exceeding their declared resident set size.
@@ -612,7 +612,7 @@ with lib;
           Stack = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
               stack segment may be extended.  Stack extension is performed automatically by the system.
             '';
@@ -624,7 +624,7 @@ with lib;
     Nice = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies what nice(3) value should be applied to the daemon.
       '';
     };
@@ -660,7 +660,7 @@ with lib;
     AbandonProcessGroup = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         When a job dies, launchd kills any remaining processes with the same process group ID as the job. Setting
         this key to true disables that behavior.
       '';
@@ -669,7 +669,7 @@ with lib;
     LowPriorityIO = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies whether the kernel should consider this daemon to be low priority when
         doing file system I/O.
       '';
@@ -678,7 +678,7 @@ with lib;
     LaunchOnlyOnce = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies whether the job can only be run once and only once.  In other words, if the
         job cannot be safely respawned without a full machine reboot, then set this key to be true.
       '';
@@ -687,7 +687,7 @@ with lib;
     MachServices = mkOption {
       default = null;
       example = { "org.nixos.service" = { ResetAtClose = true; }; };
-      description = ''
+      description = lib.mdDoc ''
         This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system.
         Each key in this dictionary should be the name of service to be advertised. The value of the key must
         be a boolean and set to true.  Alternatively, a dictionary can be used instead of a simple true value.
@@ -700,7 +700,7 @@ with lib;
           ResetAtClose = mkOption {
             type = types.nullOr types.bool;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               If this boolean is false, the port is recycled, thus leaving clients to remain oblivious to the
               demand nature of job. If the value is set to true, clients receive port death notifications when
               the job lets go of the receive right. The port will be recreated atomically with respect to bootstrap_look_up()
@@ -713,7 +713,7 @@ with lib;
           HideUntilCheckIn = mkOption {
             type = types.nullOr types.bool;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Reserve the name in the namespace, but cause bootstrap_look_up() to fail until the job has
               checked in with launchd.
             '';
@@ -725,7 +725,7 @@ with lib;
     LaunchEvents = mkOption {
       type = types.nullOr (types.attrs);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Specifies higher-level event types to be used as launch-on-demand event
         sources.  Each sub-dictionary defines events for a particular event
         subsystem, such as "com.apple.iokit.matching", which can be used to
@@ -750,7 +750,7 @@ with lib;
     ServiceIPC = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key specifies whether the job participates in advanced
         communication with launchd. The default is false. This flag is
         incompatible with the inetdCompatibility key.
@@ -760,7 +760,7 @@ with lib;
     SessionCreate = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This key specifies that the job should be spawned into a new security
         audit session rather than the default session for the context is belongs
         to. See auditon(2) for details.
@@ -769,7 +769,7 @@ with lib;
 
     Sockets = mkOption {
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         This optional key is used to specify launch on demand sockets that can be used to let launchd know when
         to run the job. The job must check-in to get a copy of the file descriptors using APIs outlined in
         launch(3).  The keys of the top level Sockets dictionary can be anything. They are meant for the application
@@ -779,14 +779,14 @@ with lib;
         to be effectively equivalent, even though each file descriptor likely represents a different networking
         protocol which conforms to the criteria specified in the job configuration file.
 
-        The parameters below are used as inputs to call getaddrinfo(3).
+        The parameters below are used as inputs to call `getaddrinfo(3)`.
       '';
       type = types.nullOr (types.attrsOf (types.submodule {
         options = {
           SockType = mkOption {
             type = types.nullOr (types.enum [ "stream" "dgram" "seqpacket" ]);
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               This optional key tells launchctl what type of socket to create. The default is "stream" and
               other valid values for this key are "dgram" and "seqpacket" respectively.
             '';
@@ -795,8 +795,8 @@ with lib;
           SockPassive = mkOption {
             type = types.nullOr types.bool;
             default = null;
-            description = ''
-              This optional key specifies whether listen(2) or connect(2) should be called on the created file
+            description = lib.mdDoc ''
+              This optional key specifies whether `listen(2)` or `connect(2)` should be called on the created file
               descriptor. The default is true ("to listen").
             '';
           };
@@ -804,23 +804,23 @@ with lib;
           SockNodeName = mkOption {
             type = types.nullOr types.str;
             default = null;
-            description = ''
-              This optional key specifies the node to connect(2) or bind(2) to.
+            description = lib.mdDoc ''
+              This optional key specifies the node to `connect(2)` or `bind(2)` to.
             '';
           };
 
           SockServiceName = mkOption {
             type = types.nullOr types.str;
             default = null;
-            description = ''
-              This optional key specifies the service on the node to connect(2) or bind(2) to.
+            description = lib.mdDoc ''
+              This optional key specifies the service on the node to `connect(2)` or `bind(2)` to.
             '';
           };
 
           SockFamily = mkOption {
             type = types.nullOr (types.enum [ "IPv4" "IPv6" ]);
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created.
             '';
           };
@@ -828,8 +828,8 @@ with lib;
           SockProtocol = mkOption {
             type = types.nullOr (types.enum [ "TCP" ]);
             default = null;
-            description = ''
-              This optional key specifies the protocol to be passed to socket(2).  The only value understood by
+            description = lib.mdDoc ''
+              This optional key specifies the protocol to be passed to `socket(2)`.  The only value understood by
               this key at the moment is "TCP".
             '';
           };
@@ -837,16 +837,16 @@ with lib;
           SockPathName = mkOption {
             type = types.nullOr types.path;
             default = null;
-            description = ''
-              This optional key implies SockFamily is set to "Unix". It specifies the path to connect(2) or
-              bind(2) to.
+            description = lib.mdDoc ''
+              This optional key implies SockFamily is set to "Unix". It specifies the path to `connect(2)` or
+              `bind(2)` to.
             '';
           };
 
           SecureSocketWithKey = mkOption {
             type = types.nullOr types.str;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               This optional key is a variant of SockPathName. Instead of binding to a known path, a securely
               generated socket is created and the path is assigned to the environment variable that is inherited
               by all jobs spawned by launchd.
@@ -856,7 +856,7 @@ with lib;
           SockPathMode = mkOption {
             type = types.nullOr types.int;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               This optional key specifies the mode of the socket. Known bug: Property lists don't support
               octal, so please convert the value to decimal.
             '';
@@ -865,18 +865,18 @@ with lib;
           Bonjour = mkOption {
             type = types.nullOr (types.either types.bool (types.listOf types.str));
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               This optional key can be used to request that the service be registered with the
-              mDNSResponder(8).  If the value is boolean, the service name is inferred from the SockServiceName.
+              `mDNSResponder(8)`.  If the value is boolean, the service name is inferred from the SockServiceName.
             '';
           };
 
           MulticastGroup = mkOption {
             type = types.nullOr types.str;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               This optional key can be used to request that the datagram socket join a multicast group.  If the
-              value is a hostname, then getaddrinfo(3) will be used to join the correct multicast address for a
+              value is a hostname, then `getaddrinfo(3)` will be used to join the correct multicast address for a
               given socket family.  If an explicit IPv4 or IPv6 address is given, it is required that the SockFamily
               family also be set, otherwise the results are undefined.
             '';
diff --git a/modules/lib/write-text.nix b/modules/lib/write-text.nix
index 2fe02aff7..b8f2ad55a 100644
--- a/modules/lib/write-text.nix
+++ b/modules/lib/write-text.nix
@@ -16,7 +16,7 @@ in
     enable = mkOption {
       type = types.bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether this file should be generated.
         This option allows specific files to be disabled.
       '';
@@ -25,7 +25,7 @@ in
     text = mkOption {
       type = types.lines;
       default = "";
-      description = ''
+      description = lib.mdDoc ''
         Text of the file.
       '';
     };
@@ -33,14 +33,14 @@ in
     target = mkOption {
       type = types.str;
       default = name;
-      description = ''
+      description = lib.mdDoc ''
         Name of symlink.  Defaults to the attribute name.
       '';
     };
 
     source = mkOption {
       type = types.path;
-      description = ''
+      description = lib.mdDoc ''
         Path of the source file.
       '';
     };
@@ -48,7 +48,7 @@ in
     copy = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Whether this file should be copied instead of symlinking.
       '';
     };
diff --git a/modules/meta.nix b/modules/meta.nix
index 4ce0efc2e..0adc3fb0b 100644
--- a/modules/meta.nix
+++ b/modules/meta.nix
@@ -35,13 +35,13 @@ in
         internal = true;
         default = [];
         example = [ lib.maintainers.all ];
-        description = ''
+        description = lib.mdDoc ''
           List of maintainers of each module.  This option should be defined at
           most once per module.
 
-          NOTE: lib comes from Nixpkgs, which can go out of
+          NOTE: `lib` comes from Nixpkgs, which can go out of
           sync with nix-darwin. For this reason, use definitions like
-          maintainers.alice or "alice".
+          `maintainers.alice or "alice"`.
         '';
       };
 
diff --git a/modules/misc/ids.nix b/modules/misc/ids.nix
index 07f1240b0..0bccdbc06 100644
--- a/modules/misc/ids.nix
+++ b/modules/misc/ids.nix
@@ -18,7 +18,7 @@ in
 
     ids.uids = lib.mkOption {
       internal = true;
-      description = ''
+      description = lib.mdDoc ''
         The user IDs used in NixOS.
       '';
       type = types.attrsOf types.int;
@@ -26,7 +26,7 @@ in
 
     ids.gids = lib.mkOption {
       internal = true;
-      description = ''
+      description = lib.mdDoc ''
         The group IDs used in NixOS.
       '';
       type = types.attrsOf types.int;
diff --git a/modules/misc/lib.nix b/modules/misc/lib.nix
index e50794ccc..3599661f6 100644
--- a/modules/misc/lib.nix
+++ b/modules/misc/lib.nix
@@ -7,7 +7,7 @@
 
       type = lib.types.attrsOf lib.types.attrs;
 
-      description = ''
+      description = lib.mdDoc ''
         This option allows modules to define helper functions, constants, etc.
       '';
     };
diff --git a/modules/networking/default.nix b/modules/networking/default.nix
index 727933f59..af82c39bd 100644
--- a/modules/networking/default.nix
+++ b/modules/networking/default.nix
@@ -74,11 +74,11 @@ in
       type = types.listOf types.str;
       default = [];
       example = [ "Wi-Fi" "Ethernet Adaptor" "Thunderbolt Ethernet" ];
-      description = ''
+      description = lib.mdDoc ''
         List of networkservices that should be configured.
 
         To display a list of all the network services on the server's
-        hardware ports, use networksetup -listallnetworkservices.
+        hardware ports, use {command}`networksetup -listallnetworkservices`.
       '';
     };
 
@@ -86,13 +86,13 @@ in
       type = types.listOf types.str;
       default = [];
       example = [ "8.8.8.8" "8.8.4.4" "2001:4860:4860::8888" "2001:4860:4860::8844" ];
-      description = "The list of dns servers used when resolving domain names.";
+      description = lib.mdDoc "The list of dns servers used when resolving domain names.";
     };
 
     networking.search = mkOption {
       type = types.listOf types.str;
       default = [];
-      description = "The list of search paths used when resolving domain names.";
+      description = lib.mdDoc "The list of search paths used when resolving domain names.";
     };
   };
 
diff --git a/modules/nix/default.nix b/modules/nix/default.nix
index cf71401b3..6a0515993 100644
--- a/modules/nix/default.nix
+++ b/modules/nix/default.nix
@@ -164,7 +164,7 @@ in
         type = types.package;
         default = pkgs.nix;
         defaultText = literalExpression "pkgs.nix";
-        description = ''
+        description = lib.mdDoc ''
           This option specifies the Nix package instance to use throughout the system.
         '';
       };
@@ -173,7 +173,7 @@ in
       useDaemon = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           If set, Nix will use the daemon to perform operations.
           Use this instead of services.nix-daemon.enable if you don't wan't the
           daemon service to be managed for you.
@@ -183,9 +183,9 @@ in
       distributedBuilds = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to distribute builds to the machines listed in
-          .
+          {option}`nix.buildMachines`.
 
           NOTE: This requires services.nix-daemon.enable for a
           multi-user install.
@@ -196,13 +196,13 @@ in
       daemonProcessType = mkOption {
         type = types.enum [ "Background" "Standard" "Adaptive" "Interactive" ];
         default = "Standard";
-        description = ''
+        description = lib.mdDoc ''
           Nix daemon process resource limits class. These limits propagate to
-          build processes. Standard is the default process type
+          build processes. `Standard` is the default process type
           and will apply light resource limits, throttling its CPU usage and I/O
           bandwidth.
 
-          See man launchd.plist for explanation of other
+          See {command}`man launchd.plist` for explanation of other
           process types.
         '';
       };
@@ -211,7 +211,7 @@ in
       daemonIOLowPriority = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether the Nix daemon process should considered to be low priority when
           doing file system I/O.
         '';
@@ -223,7 +223,7 @@ in
             hostName = mkOption {
               type = types.str;
               example = "nixbuilder.example.org";
-              description = ''
+              description = lib.mdDoc ''
                 The hostname of the build machine.
               '';
             };
@@ -244,10 +244,10 @@ in
               type = types.nullOr types.str;
               default = null;
               example = "x86_64-linux";
-              description = ''
+              description = lib.mdDoc ''
                 The system type the build machine can execute derivations on.
-                Either this attribute or systems must be
-                present, where system takes precedence if
+                Either this attribute or {var}`systems` must be
+                present, where {var}`system` takes precedence if
                 both are set.
               '';
             };
@@ -255,10 +255,10 @@ in
               type = types.listOf types.str;
               default = [ ];
               example = [ "x86_64-linux" "aarch64-linux" ];
-              description = ''
+              description = lib.mdDoc ''
                 The system types the build machine can execute derivations on.
-                Either this attribute or system must be
-                present, where system takes precedence if
+                Either this attribute or {var}`system` must be
+                present, where {var}`system` takes precedence if
                 both are set.
               '';
             };
@@ -266,11 +266,11 @@ in
               type = types.nullOr types.str;
               default = null;
               example = "builder";
-              description = ''
+              description = lib.mdDoc ''
                 The username to log in as on the remote host. This user must be
                 able to log in and run nix commands non-interactively. It must
                 also be privileged to build derivations, so must be included in
-                .
+                {option}`nix.settings.trusted-users`.
               '';
             };
             sshKey = mkOption {
@@ -290,7 +290,7 @@ in
             maxJobs = mkOption {
               type = types.int;
               default = 1;
-              description = ''
+              description = lib.mdDoc ''
                 The number of concurrent jobs the build machine supports. The
                 build machine will enforce its own limits, but this allows hydra
                 to schedule better since there is no work-stealing between build
@@ -300,7 +300,7 @@ in
             speedFactor = mkOption {
               type = types.int;
               default = 1;
-              description = ''
+              description = lib.mdDoc ''
                 The relative speed of this builder. This is an arbitrary integer
                 that indicates the speed of this builder, relative to other
                 builders. Higher is faster.
@@ -310,18 +310,18 @@ in
               type = types.listOf types.str;
               default = [ ];
               example = [ "big-parallel" ];
-              description = ''
+              description = lib.mdDoc ''
                 A list of features mandatory for this builder. The builder will
                 be ignored for derivations that don't require all features in
                 this list. All mandatory features are automatically included in
-                supportedFeatures.
+                {var}`supportedFeatures`.
               '';
             };
             supportedFeatures = mkOption {
               type = types.listOf types.str;
               default = [ ];
               example = [ "kvm" "big-parallel" ];
-              description = ''
+              description = lib.mdDoc ''
                 A list of features supported by this builder. The builder will
                 be ignored for derivations that require features not in this
                 list.
@@ -330,18 +330,18 @@ in
             publicHostKey = mkOption {
               type = types.nullOr types.str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 The (base64-encoded) public host key of this builder. The field
-                is calculated via base64 -w0 /etc/ssh/ssh_host_type_key.pub.
+                is calculated via {command}`base64 -w0 /etc/ssh/ssh_host_type_key.pub`.
                 If null, SSH will use its regular known-hosts file when connecting.
               '';
             };
           };
         });
         default = [ ];
-        description = ''
+        description = lib.mdDoc ''
           This option lists the machines to be used if distributed builds are
-          enabled (see ).
+          enabled (see {option}`nix.distributedBuilds`).
           Nix will perform derivations on those machines via SSH by copying the
           inputs to the Nix store on the remote machine, starting the build,
           then copying the output back to the local Nix store.
@@ -353,22 +353,22 @@ in
         type = types.attrs;
         internal = true;
         default = { };
-        description = "Environment variables used by Nix.";
+        description = lib.mdDoc "Environment variables used by Nix.";
       };
 
       # Not in NixOS module
       configureBuildUsers = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable configuration for nixbld group and users.
         '';
       };
 
       nrBuildUsers = mkOption {
         type = types.int;
-        description = ''
-          Number of nixbld user accounts created to
+        description = lib.mdDoc ''
+          Number of `nixbld` user accounts created to
           perform secure concurrent builds.  If you receive an error
           message saying that “all build users are currently in use”,
           you should increase this value.
@@ -378,9 +378,9 @@ in
       readOnlyStore = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           If set, Nix will enforce the immutability of the Nix store
-          by making /nix/store a read-only bind
+          by making {file}`/nix/store` a read-only bind
           mount.  Nix will automatically make the store writable when
           needed.
         '';
@@ -394,10 +394,10 @@ in
             { darwin-config = "${config.environment.darwinConfig}"; }
             "/nix/var/nix/profiles/per-user/root/channels"
           ];
-        description = ''
+        description = lib.mdDoc ''
           The default Nix expression search path, used by the Nix
           evaluator to look up paths enclosed in angle brackets
-          (e.g. <nixpkgs>).
+          (e.g. ``).
 
           Named entries can be specified using an attribute set, if an
           entry is configured multiple times the value with the lowest
@@ -408,7 +408,7 @@ in
       checkConfig = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           If enabled (the default), checks for data type mismatches and that Nix
           can parse the generated nix.conf.
         '';
@@ -430,28 +430,28 @@ in
               from = mkOption {
                 type = referenceAttrs;
                 example = { type = "indirect"; id = "nixpkgs"; };
-                description = "The flake reference to be rewritten.";
+                description = lib.mdDoc "The flake reference to be rewritten.";
               };
               to = mkOption {
                 type = referenceAttrs;
                 example = { type = "github"; owner = "my-org"; repo = "my-nixpkgs"; };
-                description = "The flake reference  is rewritten to.";
+                description = lib.mdDoc "The flake reference {option}`from` is rewritten to.";
               };
               flake = mkOption {
                 type = types.nullOr types.attrs;
                 default = null;
                 example = literalExpression "nixpkgs";
-                description = ''
-                  The flake input  is rewritten to.
+                description = lib.mdDoc ''
+                  The flake input {option}`from` is rewritten to.
                 '';
               };
               exact = mkOption {
                 type = types.bool;
                 default = true;
-                description = ''
-                  Whether the  reference needs to match exactly. If set,
-                  a  reference like nixpkgs does not
-                  match with a reference like nixpkgs/nixos-20.03.
+                description = lib.mdDoc ''
+                  Whether the {option}`from` reference needs to match exactly. If set,
+                  a {option}`from` reference like `nixpkgs` does not
+                  match with a reference like `nixpkgs/nixos-20.03`.
                 '';
               };
             };
@@ -469,7 +469,7 @@ in
           }
         ));
         default = { };
-        description = ''
+        description = lib.mdDoc ''
           A system-wide flake registry.
         '';
       };
@@ -481,7 +481,7 @@ in
           keep-outputs = true
           keep-derivations = true
         '';
-        description = "Additional text appended to nix.conf.";
+        description = lib.mdDoc "Additional text appended to {file}`nix.conf`.";
       };
 
       settings = mkOption {
@@ -493,7 +493,7 @@ in
               type = types.either types.int (types.enum [ "auto" ]);
               default = "auto";
               example = 64;
-              description = ''
+              description = lib.mdDoc ''
                 This option defines the maximum number of jobs that Nix will try to
                 build in parallel. The default is auto, which means it will use all
                 available logical cores. It is recommend to set it to the total
@@ -506,7 +506,7 @@ in
               type = types.bool;
               default = false;
               example = true;
-              description = ''
+              description = lib.mdDoc ''
                 If set to true, Nix automatically detects files in the store that have
                 identical contents, and replaces them with hard links to a single copy.
                 This saves disk space. If set to false (the default), you can still run
@@ -518,7 +518,7 @@ in
               type = types.int;
               default = 0;
               example = 64;
-              description = ''
+              description = lib.mdDoc ''
                 This option defines the maximum number of concurrent tasks during
                 one build. It affects, e.g., -j option for make.
                 The special value 0 means that the builder should use all
@@ -531,7 +531,7 @@ in
             sandbox = mkOption {
               type = types.either types.bool (types.enum [ "relaxed" ]);
               default = false;
-              description = ''
+              description = lib.mdDoc ''
                 If set, Nix will perform builds in a sandboxed environment that it
                 will set up automatically for each build. This prevents impurities
                 in builds by disallowing access to dependencies outside of the Nix
@@ -545,7 +545,7 @@ in
               type = types.listOf types.str;
               default = [ ];
               example = [ "/dev" "/proc" ];
-              description = ''
+              description = lib.mdDoc ''
                 Directories from the host filesystem to be included
                 in the sandbox.
               '';
@@ -553,7 +553,7 @@ in
 
             substituters = mkOption {
               type = types.listOf types.str;
-              description = ''
+              description = lib.mdDoc ''
                 List of binary cache URLs used to obtain pre-built binaries
                 of Nix packages.
 
@@ -565,21 +565,21 @@ in
               type = types.listOf types.str;
               default = [ ];
               example = [ "https://hydra.nixos.org/" ];
-              description = ''
+              description = lib.mdDoc ''
                 List of binary cache URLs that non-root users can use (in
                 addition to those specified using
-                ) by passing
-                --option binary-caches to Nix commands.
+                {option}`nix.settings.substituters`) by passing
+                `--option binary-caches` to Nix commands.
               '';
             };
 
             require-sigs = mkOption {
               type = types.bool;
               default = true;
-              description = ''
+              description = lib.mdDoc ''
                 If enabled (the default), Nix will only download binaries from binary caches if
                 they are cryptographically signed with any of the keys listed in
-                . If disabled, signatures are neither
+                {option}`nix.settings.trusted-public-keys`. If disabled, signatures are neither
                 required nor checked, so it's strongly recommended that you use only
                 trustworthy caches and https to prevent man-in-the-middle attacks.
               '';
@@ -588,13 +588,13 @@ in
             trusted-public-keys = mkOption {
               type = types.listOf types.str;
               example = [ "hydra.nixos.org-1:CNHJZBh9K4tP3EKF6FkkgeVYsS3ohTl+oS0Qa8bezVs=" ];
-              description = ''
+              description = lib.mdDoc ''
                 List of public keys used to sign binary caches. If
-                 is enabled,
+                {option}`nix.settings.trusted-public-keys` is enabled,
                 then Nix will use a binary from a binary cache if and only
-                if it is signed by any of the keys
+                if it is signed by *any* of the keys
                 listed here. By default, only the key for
-                cache.nixos.org is included.
+                `cache.nixos.org` is included.
               '';
             };
 
@@ -602,13 +602,13 @@ in
               type = types.listOf types.str;
               default = [ "root" ];
               example = [ "root" "alice" "@admin" ];
-              description = ''
+              description = lib.mdDoc ''
                 A list of names of users that have additional rights when
                 connecting to the Nix daemon, such as the ability to specify
                 additional binary caches, or to import unsigned NARs. You
                 can also specify groups by prefixing them with
-                @; for instance,
-                @admin means all users in the wheel
+                `@`; for instance,
+                `@admin` means all users in the wheel
                 group.
               '';
             };
@@ -632,27 +632,27 @@ in
               type = types.listOf types.str;
               default = [ "*" ];
               example = [ "@admin" "@builders" "alice" "bob" ];
-              description = ''
+              description = lib.mdDoc ''
                 A list of names of users (separated by whitespace) that are
                 allowed to connect to the Nix daemon. As with
-                , you can specify groups by
-                prefixing them with @. Also, you can
-                allow all users by specifying *. The
-                default is *. Note that trusted users are
+                {option}`nix.settings.trusted-users`, you can specify groups by
+                prefixing them with `@`. Also, you can
+                allow all users by specifying `*`. The
+                default is `*`. Note that trusted users are
                 always allowed to connect.
               '';
             };
           };
         };
         default = { };
-        description = ''
+        description = lib.mdDoc ''
           Configuration for Nix, see
-          
+          
           for avalaible options.
           The value declared here will be translated directly to the key-value pairs Nix expects.
 
-          Nix configurations defined under  will be translated and applied to this
-          option. In addition, configuration specified in  which will be appended
+          Nix configurations defined under {option}`nix.*` will be translated and applied to this
+          option. In addition, configuration specified in {option}`nix.extraOptions` which will be appended
           verbatim to the resulting config file.
         '';
       };
diff --git a/modules/nix/nixpkgs.nix b/modules/nix/nixpkgs.nix
index 9db3b6aa4..77f69b213 100644
--- a/modules/nix/nixpkgs.nix
+++ b/modules/nix/nixpkgs.nix
@@ -61,13 +61,13 @@ in
           }
         '';
       type = configType;
-      description = ''
+      description = lib.mdDoc ''
         The configuration of the Nix Packages collection.  (For
         details, see the Nixpkgs documentation.)  It allows you to set
         package configuration options, and to override packages
-        globally through the packageOverrides
+        globally through the {var}`packageOverrides`
         option.  The latter is a function that takes as an argument
-        the original Nixpkgs, and must evaluate
+        the *original* Nixpkgs, and must evaluate
         to a set of new or overridden packages.
       '';
     };
@@ -85,11 +85,11 @@ in
           };
         ) ]
       '';
-      description = ''
+      description = lib.mdDoc ''
         List of overlays to use with the Nix Packages collection.
         (For details, see the Nixpkgs documentation.)  It allows
         you to override packages globally. This is a function that
-        takes as an argument the original Nixpkgs.
+        takes as an argument the *original* Nixpkgs.
         The first argument should be used for finding dependencies, and
         the second should be used for overriding recipes.
       '';
@@ -98,7 +98,7 @@ in
     nixpkgs.system = mkOption {
       type = types.str;
       example = "x86_64-darwin";
-      description = ''
+      description = lib.mdDoc ''
         Specifies the Nix platform type for which NixOS should be built.
         If unset, it defaults to the platform type of your host system.
         Specifying this option is useful when doing distributed
diff --git a/modules/programs/bash/default.nix b/modules/programs/bash/default.nix
index 6ebd92368..47bd1f392 100644
--- a/modules/programs/bash/default.nix
+++ b/modules/programs/bash/default.nix
@@ -12,19 +12,19 @@ in
     programs.bash.enable = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to configure bash as an interactive shell.";
+      description = lib.mdDoc "Whether to configure bash as an interactive shell.";
     };
 
     programs.bash.interactiveShellInit = mkOption {
       default = "";
-      description = "Shell script code called during interactive bash shell initialisation.";
+      description = lib.mdDoc "Shell script code called during interactive bash shell initialisation.";
       type = types.lines;
     };
 
     programs.bash.enableCompletion = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enable bash completion for all interactive bash shells.
 
         NOTE. This doesn't work with bash 3.2, which is the default on macOS.
diff --git a/modules/programs/fish.nix b/modules/programs/fish.nix
index 7a1ba10d9..434449f75 100644
--- a/modules/programs/fish.nix
+++ b/modules/programs/fish.nix
@@ -51,7 +51,7 @@ in
 
       enable = mkOption {
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to configure fish as an interactive shell.
         '';
         type = types.bool;
@@ -60,15 +60,15 @@ in
       useBabelfish = mkOption {
         type = types.bool;
         default = false;
-        description = ''
-          If enabled, the configured environment will be translated to native fish using babelfish.
-          Otherwise, foreign-env will be used.
+        description = lib.mdDoc ''
+          If enabled, the configured environment will be translated to native fish using [babelfish](https://github.com/bouk/babelfish).
+          Otherwise, [foreign-env](https://github.com/oh-my-fish/plugin-foreign-env) will be used.
         '';
       };
 
       babelfishPackage = mkOption {
         type = types.package;
-        description = ''
+        description = lib.mdDoc ''
           The babelfish package to use when useBabelfish is
           set to true.
         '';
@@ -77,7 +77,7 @@ in
       vendor.config.enable = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether fish should source configuration snippets provided by other packages.
         '';
       };
@@ -85,7 +85,7 @@ in
       vendor.completions.enable = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether fish should use completion files provided by other packages.
         '';
       };
@@ -93,15 +93,15 @@ in
       vendor.functions.enable = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether fish should autoload fish functions provided by other packages.
         '';
       };
 
       shellAliases = mkOption {
         default = config.environment.shellAliases;
-        description = ''
-          Set of aliases for fish shell. See 
+        description = lib.mdDoc ''
+          Set of aliases for fish shell. See {option}`environment.shellAliases`
           for an option format description.
         '';
         type = types.attrs;
@@ -109,7 +109,7 @@ in
 
       shellInit = mkOption {
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Shell script code called during fish shell initialisation.
         '';
         type = types.lines;
@@ -117,7 +117,7 @@ in
 
       loginShellInit = mkOption {
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Shell script code called during fish login shell initialisation.
         '';
         type = types.lines;
@@ -125,7 +125,7 @@ in
 
       interactiveShellInit = mkOption {
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Shell script code called during interactive fish shell initialisation.
         '';
         type = types.lines;
@@ -133,7 +133,7 @@ in
 
       promptInit = mkOption {
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Shell script code used to initialise fish prompt.
         '';
         type = types.lines;
diff --git a/modules/programs/gnupg.nix b/modules/programs/gnupg.nix
index 4c451eca5..bd2f96c2a 100644
--- a/modules/programs/gnupg.nix
+++ b/modules/programs/gnupg.nix
@@ -13,7 +13,7 @@ in
     agent.enable = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enables GnuPG agent for every user session.
       '';
     };
@@ -21,7 +21,7 @@ in
     agent.enableSSHSupport = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enable SSH agent support in GnuPG agent. Also sets SSH_AUTH_SOCK
         environment variable correctly.
       '';
diff --git a/modules/programs/info/default.nix b/modules/programs/info/default.nix
index de4baa453..93aaf7c60 100644
--- a/modules/programs/info/default.nix
+++ b/modules/programs/info/default.nix
@@ -11,7 +11,7 @@ in
     programs.info.enable = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to enable info pages and the info command.";
+      description = lib.mdDoc "Whether to enable info pages and the {command}`info` command.";
     };
   };
 
diff --git a/modules/programs/man.nix b/modules/programs/man.nix
index 949e393a7..fd0e01868 100644
--- a/modules/programs/man.nix
+++ b/modules/programs/man.nix
@@ -8,9 +8,9 @@ with lib;
     programs.man.enable = mkOption {
       type = types.bool;
       default = true;
-      description = ''
-        Whether to enable manual pages and the man command.
-        This also includes "man" outputs of all systemPackages.
+      description = lib.mdDoc ''
+        Whether to enable manual pages and the {command}`man` command.
+        This also includes "man" outputs of all `systemPackages`.
       '';
     };
 
diff --git a/modules/programs/nix-index/default.nix b/modules/programs/nix-index/default.nix
index b6f86f59e..0685346c2 100644
--- a/modules/programs/nix-index/default.nix
+++ b/modules/programs/nix-index/default.nix
@@ -11,14 +11,14 @@ in
     programs.nix-index.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable nix-index and its command-not-found helper.";
+      description = lib.mdDoc "Whether to enable nix-index and its command-not-found helper.";
     };
 
     programs.nix-index.package = mkOption {
       type = types.package;
       default = pkgs.nix-index;
       defaultText = "pkgs.nix-index";
-      description = "This option specifies the nix-index package to use.";
+      description = lib.mdDoc "This option specifies the nix-index package to use.";
     };
   };
 
diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix
index a230dde18..e472d7be6 100644
--- a/modules/programs/ssh/default.nix
+++ b/modules/programs/ssh/default.nix
@@ -14,7 +14,7 @@ let
         hostNames = mkOption {
           type = types.listOf types.str;
           default = [];
-          description = ''
+          description = lib.mdDoc ''
             A list of host names and/or IP numbers used for accessing
             the host's ssh service.
           '';
@@ -23,9 +23,9 @@ let
           default = null;
           type = types.nullOr types.str;
           example = "ecdsa-sha2-nistp521 AAAAE2VjZHN...UEPg==";
-          description = ''
+          description = lib.mdDoc ''
             The public key data for the host. You can fetch a public key
-            from a running SSH server with the ssh-keyscan
+            from a running SSH server with the {command}`ssh-keyscan`
             command. The public key should not include any host names, only
             the key type and the key itself.
           '';
@@ -33,13 +33,13 @@ let
         publicKeyFile = mkOption {
           default = null;
           type = types.nullOr types.path;
-          description = ''
+          description = lib.mdDoc ''
             The path to the public key file for the host. The public
             key file is read at build time and saved in the Nix store.
             You can fetch a public key file from a running SSH server
-            with the ssh-keyscan command. The content
+            with the {command}`ssh-keyscan` command. The content
             of the file should follow the same format as described for
-            the publicKey option.
+            the `publicKey` option.
           '';
         };
       };
@@ -54,13 +54,13 @@ let
       keys = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           A list of verbatim OpenSSH public keys that should be added to the
           user's authorized keys. The keys are added to a file that the SSH
           daemon reads in addition to the the user's authorized_keys file.
-          You can combine the keys and
-          keyFiles options.
-          Warning: If you are using NixOps then don't use this
+          You can combine the `keys` and
+          `keyFiles` options.
+          Warning: If you are using `NixOps` then don't use this
           option since it will replace the key required for deployment via ssh.
         '';
       };
@@ -68,12 +68,12 @@ let
       keyFiles = mkOption {
         type = types.listOf types.path;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           A list of files each containing one OpenSSH public key that should be
           added to the user's authorized keys. The contents of the files are
           read at build time and added to a file that the SSH daemon reads in
           addition to the the user's authorized_keys file. You can combine the
-          keyFiles and keys options.
+          `keyFiles` and `keys` options.
         '';
       };
     };
@@ -122,7 +122,7 @@ in
     programs.ssh.knownHosts = mkOption {
       default = {};
       type = types.attrsOf (types.submodule host);
-      description = ''
+      description = lib.mdDoc ''
         The set of system-wide known SSH hosts.
       '';
       example = literalExpression ''
diff --git a/modules/programs/tmux.nix b/modules/programs/tmux.nix
index 04dce2965..7278479c0 100644
--- a/modules/programs/tmux.nix
+++ b/modules/programs/tmux.nix
@@ -46,47 +46,47 @@ in
     programs.tmux.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to configure tmux.";
+      description = lib.mdDoc "Whether to configure tmux.";
     };
 
     programs.tmux.enableSensible = mkOption {
       type = types.bool;
       default = false;
       example = true;
-      description = "Enable sensible configuration options for tmux.";
+      description = lib.mdDoc "Enable sensible configuration options for tmux.";
     };
 
     programs.tmux.enableMouse = mkOption {
       type = types.bool;
       default = false;
       example = true;
-      description = "Enable mouse support for tmux.";
+      description = lib.mdDoc "Enable mouse support for tmux.";
     };
 
     programs.tmux.enableFzf = mkOption {
       type = types.bool;
       default = false;
       example = true;
-      description = "Enable fzf keybindings for selecting tmux sessions and panes.";
+      description = lib.mdDoc "Enable fzf keybindings for selecting tmux sessions and panes.";
     };
 
     programs.tmux.enableVim = mkOption {
       type = types.bool;
       default = false;
       example = true;
-      description = "Enable vim style keybindings for copy mode, and navigation of tmux panes.";
+      description = lib.mdDoc "Enable vim style keybindings for copy mode, and navigation of tmux panes.";
     };
 
     programs.tmux.iTerm2 = mkOption {
       type = types.bool;
       default = false;
       example = true;
-      description = "Cater to iTerm2 and its tmux integration, as appropriate.";
+      description = lib.mdDoc "Cater to iTerm2 and its tmux integration, as appropriate.";
     };
 
     programs.tmux.defaultCommand = mkOption {
       type = types.either types.str types.package;
-      description = "The default command to use for tmux panes.";
+      description = lib.mdDoc "The default command to use for tmux panes.";
     };
 
     programs.tmux.tmuxOptions = mkOption {
@@ -98,7 +98,7 @@ in
     programs.tmux.extraConfig = mkOption {
       type = types.lines;
       default = "";
-      description = "Extra configuration to add to tmux.conf.";
+      description = lib.mdDoc "Extra configuration to add to {file}`tmux.conf`.";
     };
   };
 
diff --git a/modules/programs/vim.nix b/modules/programs/vim.nix
index 345532e51..d51d0ac3f 100644
--- a/modules/programs/vim.nix
+++ b/modules/programs/vim.nix
@@ -18,14 +18,14 @@ in
     programs.vim.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to configure vim.";
+      description = lib.mdDoc "Whether to configure vim.";
     };
 
     programs.vim.enableSensible = mkOption {
       type = types.bool;
       default = false;
       example = true;
-      description = "Enable sensible configuration options for vim.";
+      description = lib.mdDoc "Enable sensible configuration options for vim.";
     };
 
     programs.vim.extraKnownPlugins = mkOption {
@@ -46,14 +46,14 @@ in
           };
         }
         '';
-      description = "Custom plugin declarations to add to VAM's knownPlugins.";
+      description = lib.mdDoc "Custom plugin declarations to add to VAM's knownPlugins.";
     };
 
     programs.vim.plugins = mkOption {
       type = types.listOf types.attrs;
       default = [];
       example = [ { names = [ "surround" "vim-nix" ]; } ];
-      description = "VAM plugin dictionaries to use for vim_configurable.";
+      description = lib.mdDoc "VAM plugin dictionaries to use for vim_configurable.";
     };
 
     programs.vim.package = mkOption {
@@ -70,7 +70,7 @@ in
     programs.vim.vimConfig = mkOption {
       type = types.lines;
       default = "";
-      description = "Extra vimrcConfig to use for vim_configurable.";
+      description = lib.mdDoc "Extra vimrcConfig to use for vim_configurable.";
     };
   };
 
diff --git a/modules/programs/zsh/default.nix b/modules/programs/zsh/default.nix
index 14100d8e8..4eb40595e 100644
--- a/modules/programs/zsh/default.nix
+++ b/modules/programs/zsh/default.nix
@@ -18,13 +18,13 @@ in
     programs.zsh.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to configure zsh as an interactive shell.";
+      description = lib.mdDoc "Whether to configure zsh as an interactive shell.";
     };
 
     programs.zsh.variables = mkOption {
       type = types.attrsOf (types.either types.str (types.listOf types.str));
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         A set of environment variables used in the global environment.
         These variables will be set on shell initialisation.
         The value of each variable can be either a string or a list of
@@ -37,61 +37,61 @@ in
     programs.zsh.shellInit = mkOption {
       type = types.lines;
       default = "";
-      description = "Shell script code called during zsh shell initialisation.";
+      description = lib.mdDoc "Shell script code called during zsh shell initialisation.";
     };
 
     programs.zsh.loginShellInit = mkOption {
       type = types.lines;
       default = "";
-      description = "Shell script code called during zsh login shell initialisation.";
+      description = lib.mdDoc "Shell script code called during zsh login shell initialisation.";
     };
 
     programs.zsh.interactiveShellInit = mkOption {
       type = types.lines;
       default = "";
-      description = "Shell script code called during interactive zsh shell initialisation.";
+      description = lib.mdDoc "Shell script code called during interactive zsh shell initialisation.";
     };
 
     programs.zsh.promptInit = mkOption {
       type = types.lines;
       default = "autoload -U promptinit && promptinit && prompt walters";
-      description = "Shell script code used to initialise the zsh prompt.";
+      description = lib.mdDoc "Shell script code used to initialise the zsh prompt.";
     };
 
     programs.zsh.enableCompletion = mkOption {
       type = types.bool;
       default = true;
-      description = "Enable zsh completion for all interactive zsh shells.";
+      description = lib.mdDoc "Enable zsh completion for all interactive zsh shells.";
     };
 
     programs.zsh.enableBashCompletion = mkOption {
       type = types.bool;
       default = true;
-      description = "Enable bash completion for all interactive zsh shells.";
+      description = lib.mdDoc "Enable bash completion for all interactive zsh shells.";
     };
 
     programs.zsh.enableFzfCompletion = mkOption {
       type = types.bool;
       default = false;
-      description = "Enable fzf completion.";
+      description = lib.mdDoc "Enable fzf completion.";
     };
 
     programs.zsh.enableFzfGit = mkOption {
       type = types.bool;
       default = false;
-      description = "Enable fzf keybindings for C-g git browsing.";
+      description = lib.mdDoc "Enable fzf keybindings for C-g git browsing.";
     };
 
     programs.zsh.enableFzfHistory = mkOption {
       type = types.bool;
       default = false;
-      description = "Enable fzf keybinding for Ctrl-r history search.";
+      description = lib.mdDoc "Enable fzf keybinding for Ctrl-r history search.";
     };
 
     programs.zsh.enableSyntaxHighlighting = mkOption {
       type = types.bool;
       default = false;
-      description = "Enable zsh-syntax-highlighting.";
+      description = lib.mdDoc "Enable zsh-syntax-highlighting.";
     };
   };
 
diff --git a/modules/security/pki/default.nix b/modules/security/pki/default.nix
index 4f3cf303c..a92f2d5bb 100644
--- a/modules/security/pki/default.nix
+++ b/modules/security/pki/default.nix
@@ -25,12 +25,12 @@ in
       type = types.listOf types.path;
       default = [];
       example = literalExpression "[ \"\${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt\" ]";
-      description = ''
+      description = lib.mdDoc ''
         A list of files containing trusted root certificates in PEM
         format. These are concatenated to form
-        /etc/ssl/certs/ca-certificates.crt, which is
+        {file}`/etc/ssl/certs/ca-certificates.crt`, which is
         used by many programs that use OpenSSL, such as
-        curl and git.
+        {command}`curl` and {command}`git`.
       '';
     };
 
@@ -49,7 +49,7 @@ in
           '''
         ]
       '';
-      description = ''
+      description = lib.mdDoc ''
         A list of trusted root certificates in PEM format.
       '';
     };
@@ -62,10 +62,10 @@ in
         "CA WoSign ECC Root"
         "Certification Authority of WoSign G2"
       ];
-      description = ''
+      description = lib.mdDoc ''
         A list of blacklisted CA certificate names that won't be imported from
         the Mozilla Trust Store into
-        /etc/ssl/certs/ca-certificates.crt. Use the
+        {file}`/etc/ssl/certs/ca-certificates.crt`. Use the
         names from that file.
       '';
     };
diff --git a/modules/security/sandbox/default.nix b/modules/security/sandbox/default.nix
index d6987e65b..a80c9f6ff 100644
--- a/modules/security/sandbox/default.nix
+++ b/modules/security/sandbox/default.nix
@@ -27,37 +27,37 @@ let
           type = types.listOf types.package;
           default = [ ];
           apply = paths: pkgs.closureInfo { rootPaths = paths; };
-          description = "List of store paths to make accessible.";
+          description = lib.mdDoc "List of store paths to make accessible.";
         };
 
         readablePaths = mkOption {
           type = types.listOf types.path;
           default = [ ];
-          description = "List of paths that should be read-only inside the sandbox.";
+          description = lib.mdDoc "List of paths that should be read-only inside the sandbox.";
         };
 
         writablePaths = mkOption {
           type = types.listOf types.path;
           default = [ ];
-          description = "List of paths that should be read/write inside the sandbox.";
+          description = lib.mdDoc "List of paths that should be read/write inside the sandbox.";
         };
 
         allowSystemPaths = mkOption {
           type = types.bool;
           default = false;
-          description = "Whether to allow read access to FHS paths like /etc and /var.";
+          description = lib.mdDoc "Whether to allow read access to FHS paths like /etc and /var.";
         };
 
         allowLocalNetworking = mkOption {
           type = types.bool;
           default = false;
-          description = "Whether to allow localhost network access inside the sandbox.";
+          description = lib.mdDoc "Whether to allow localhost network access inside the sandbox.";
         };
 
         allowNetworking = mkOption {
           type = types.bool;
           default = false;
-          description = "Whether to allow network access inside the sandbox.";
+          description = lib.mdDoc "Whether to allow network access inside the sandbox.";
         };
       };
 
@@ -133,7 +133,7 @@ in
     security.sandbox.profiles = mkOption {
       type = types.attrsOf (types.submodule profile);
       default = { };
-      description = "Definition of sandbox profiles.";
+      description = lib.mdDoc "Definition of sandbox profiles.";
     };
   };
 
diff --git a/modules/services/activate-system/default.nix b/modules/services/activate-system/default.nix
index 5d720063c..90b7d3ce3 100644
--- a/modules/services/activate-system/default.nix
+++ b/modules/services/activate-system/default.nix
@@ -13,7 +13,7 @@ in
     services.activate-system.enable = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to activate system at boot time.";
+      description = lib.mdDoc "Whether to activate system at boot time.";
     };
   };
 
diff --git a/modules/services/autossh.nix b/modules/services/autossh.nix
index 2df74ec65..9905d6906 100644
--- a/modules/services/autossh.nix
+++ b/modules/services/autossh.nix
@@ -22,18 +22,18 @@ in
             name = mkOption {
               type = types.str;
               example = "socks-peer";
-              description = "Name of the local AutoSSH session";
+              description = lib.mdDoc "Name of the local AutoSSH session";
             };
             user = mkOption {
               type = types.str;
               example = "bill";
-              description = "Name of the user the AutoSSH session should run as";
+              description = lib.mdDoc "Name of the user the AutoSSH session should run as";
             };
             monitoringPort = mkOption {
               type = types.int;
               default = 0;
               example = 20000;
-              description = ''
+              description = lib.mdDoc ''
                 Port to be used by AutoSSH for peer monitoring. Note, that
                 AutoSSH also uses mport+1. Value of 0 disables the keep-alive
                 style monitoring
@@ -42,7 +42,7 @@ in
             extraArguments = mkOption {
               type = types.str;
               example = "-N -D4343 bill@socks.example.net";
-              description = ''
+              description = lib.mdDoc ''
                 Arguments to be passed to AutoSSH and retransmitted to SSH
                 process. Some meaningful options include -N (don't run remote
                 command), -D (open SOCKS proxy on local port), -R (forward
@@ -54,7 +54,7 @@ in
         });
 
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           List of AutoSSH sessions to start as systemd services. Each service is
           named 'autossh-{session.name}'.
         '';
diff --git a/modules/services/buildkite-agents.nix b/modules/services/buildkite-agents.nix
index 7486161ce..fd29227af 100644
--- a/modules/services/buildkite-agents.nix
+++ b/modules/services/buildkite-agents.nix
@@ -98,7 +98,7 @@ let
       preCommands = mkOption {
         type = types.lines;
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Extra commands to run before starting buildkite.
         '';
       };
diff --git a/modules/services/cachix-agent.nix b/modules/services/cachix-agent.nix
index e4d6c03f8..008dab8fe 100644
--- a/modules/services/cachix-agent.nix
+++ b/modules/services/cachix-agent.nix
@@ -9,23 +9,23 @@ in {
     enable = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enable to run Cachix Agent as a system service.
         
-        Read Cachix Deploy documentation for more information.
+        Read [Cachix Deploy](https://docs.cachix.org/deploy/) documentation for more information.
       '';
     };
 
     name = mkOption {
       type = types.str;
       default = config.networking.hostName;
-      description = ''
+      description = lib.mdDoc ''
         Agent name, usually the same as the hostname.
       '';
     };
 
     package = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Package containing cachix executable.
       '';
       type = types.package;
@@ -36,7 +36,7 @@ in {
     credentialsFile = mkOption {
       type = types.path;
       default = "/etc/cachix-agent.token";
-      description = ''
+      description = lib.mdDoc ''
         Required file that needs to contain CACHIX_AGENT_TOKEN=...
       '';
     };
@@ -44,7 +44,7 @@ in {
     logFile = mkOption {
       type = types.nullOr types.path;
       default = "/var/log/cachix-agent.log";
-      description = "Absolute path to log all stderr and stdout";
+      description = lib.mdDoc "Absolute path to log all stderr and stdout";
     };
   };
 
diff --git a/modules/services/chunkwm.nix b/modules/services/chunkwm.nix
index 3a592707a..a5955cc93 100644
--- a/modules/services/chunkwm.nix
+++ b/modules/services/chunkwm.nix
@@ -12,51 +12,51 @@ in
     services.chunkwm.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the chunkwm window manager.";
+      description = lib.mdDoc "Whether to enable the chunkwm window manager.";
     };
 
     services.chunkwm.package = mkOption {
       type = types.package;
       example = literalExpression "pkgs.chunkwm";
-      description = "This option specifies the chunkwm package to use.";
+      description = lib.mdDoc "This option specifies the chunkwm package to use.";
     };
 
     services.chunkwm.hotload = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to enable hotload.";
+      description = lib.mdDoc "Whether to enable hotload.";
     };
 
     services.chunkwm.extraConfig = mkOption {
       type = types.lines;
       default = "";
       example = ''chunkc tiling::rule --owner Emacs --state tile'';
-      description = "Additional commands for chunkwmrc.";
+      description = lib.mdDoc "Additional commands for {file}`chunkwmrc`.";
     };
 
     services.chunkwm.plugins.dir = mkOption {
       type = types.path;
       default = "/run/current-system/sw/lib/chunkwm/plugins";
-      description = "Chunkwm Plugins directory.";
+      description = lib.mdDoc "Chunkwm Plugins directory.";
     };
 
     services.chunkwm.plugins.list = mkOption {
       type = types.listOf (types.enum plugins);
       default = plugins;
       example = ["tiling"];
-      description = "Chunkwm Plugins to enable.";
+      description = lib.mdDoc "Chunkwm Plugins to enable.";
     };
 
     services.chunkwm.plugins."border".config = mkOption {
       type = types.lines;
       default = ''chunkc set focused_border_color   0xffc0b18b'';
-      description = "Optional border plugin configuration.";
+      description = lib.mdDoc "Optional border plugin configuration.";
     };
 
     services.chunkwm.plugins."tiling".config = mkOption {
       type = types.lines;
       example = ''chunkc set global_desktop_mode   bsp'';
-      description = "Optional tiling plugin configuration.";
+      description = lib.mdDoc "Optional tiling plugin configuration.";
     };
   };
 
diff --git a/modules/services/dnsmasq.nix b/modules/services/dnsmasq.nix
index 7ea674f85..03071dbc3 100644
--- a/modules/services/dnsmasq.nix
+++ b/modules/services/dnsmasq.nix
@@ -12,32 +12,32 @@ in
     services.dnsmasq.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable DNSmasq.";
+      description = lib.mdDoc "Whether to enable DNSmasq.";
     };
 
     services.dnsmasq.package = mkOption {
       type = types.path;
       default = pkgs.dnsmasq;
       defaultText = "pkgs.dnsmasq";
-      description = "This option specifies the dnsmasq package to use.";
+      description = lib.mdDoc "This option specifies the dnsmasq package to use.";
     };
 
     services.dnsmasq.bind = mkOption {
       type = types.str;
       default = "127.0.0.1";
-      description = "This option specifies the interface on which DNSmasq will listen.";
+      description = lib.mdDoc "This option specifies the interface on which DNSmasq will listen.";
     };
 
     services.dnsmasq.port = mkOption {
       type = types.int;
       default = 53;
-      description = "This option specifies port on which DNSmasq will listen.";
+      description = lib.mdDoc "This option specifies port on which DNSmasq will listen.";
     };
 
     services.dnsmasq.addresses = mkOption {
       type = types.attrs;
       default = {};
-      description = "List of domains that will be redirected by the DNSmasq.";
+      description = lib.mdDoc "List of domains that will be redirected by the DNSmasq.";
       example = literalExpression ''
         { localhost = "127.0.0.1"; }
         '';
diff --git a/modules/services/emacs.nix b/modules/services/emacs.nix
index 4b9a3cb07..88b5c8a65 100644
--- a/modules/services/emacs.nix
+++ b/modules/services/emacs.nix
@@ -12,20 +12,20 @@ in {
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether to enable the Emacs Daemon.";
+        description = lib.mdDoc "Whether to enable the Emacs Daemon.";
       };
 
       package = mkOption {
         type = types.path;
         default = pkgs.emacs;
-        description = "This option specifies the emacs package to use.";
+        description = lib.mdDoc "This option specifies the emacs package to use.";
       };
 
       additionalPath = mkOption {
         type = types.listOf types.str;
         default = [ ];
         example = [ "/Users/my_user_name" ];
-        description = ''
+        description = lib.mdDoc ''
           This option specifies additional PATH that the emacs daemon would have.
           Typically if you have binaries in your home directory that is what you would add your home path here.
           One caveat is that there won't be shell variable expansion, so you can't use $HOME for example
@@ -35,7 +35,7 @@ in {
       exec = mkOption {
         type = types.str;
         default = "emacs";
-        description = "Emacs command/binary to execute.";
+        description = lib.mdDoc "Emacs command/binary to execute.";
       };
     };
   };
diff --git a/modules/services/gitlab-runner.nix b/modules/services/gitlab-runner.nix
index b7b50bbad..7651ba52e 100644
--- a/modules/services/gitlab-runner.nix
+++ b/modules/services/gitlab-runner.nix
@@ -117,19 +117,19 @@ let
 in
 {
   options.services.gitlab-runner = {
-    enable = mkEnableOption "Gitlab Runner";
+    enable = mkEnableOption (lib.mdDoc "Gitlab Runner");
     configFile = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Configuration file for gitlab-runner.
 
-         takes precedence over .
-         and  will be ignored too.
+        {option}`configFile` takes precedence over {option}`services`.
+        {option}`checkInterval` and {option}`concurrent` will be ignored too.
 
-        This option is deprecated, please use  instead.
-        You can use  and
-        
+        This option is deprecated, please use {option}`services` instead.
+        You can use {option}`registrationConfigFile` and
+        {option}`registrationFlags`
         for settings not covered by this module.
       '';
     };
@@ -137,18 +137,18 @@ in
       type = types.int;
       default = 0;
       example = literalExpression "with lib; (length (attrNames config.services.gitlab-runner.services)) * 3";
-      description = ''
+      description = lib.mdDoc ''
         Defines the interval length, in seconds, between new jobs check.
         The default value is 3;
         if set to 0 or lower, the default value will be used.
-        See runner documentation for more information.
+        See [runner documentation](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#how-check_interval-works) for more information.
       '';
     };
     concurrent = mkOption {
       type = types.int;
       default = 1;
       example = literalExpression "config.nix.maxJobs";
-      description = ''
+      description = lib.mdDoc ''
         Limits how many jobs globally can be run concurrently.
         The most upper limit of jobs using all defined runners.
         0 does not mean unlimited.
@@ -158,7 +158,7 @@ in
       type = types.nullOr types.str;
       default = null;
       example = "https://public:private@host:port/1";
-      description = ''
+      description = lib.mdDoc ''
         Data Source Name for tracking of all system level errors to Sentry.
       '';
     };
@@ -166,7 +166,7 @@ in
       type = types.nullOr types.str;
       default = null;
       example = "localhost:8080";
-      description = ''
+      description = lib.mdDoc ''
         Address (<host>:<port>) on which the Prometheus metrics HTTP server
         should be listening.
       '';
@@ -178,7 +178,7 @@ in
             type = types.nullOr types.str;
             default = null;
             example = "0.0.0.0:8093";
-            description = ''
+            description = lib.mdDoc ''
               An internal URL to be used for the session server.
             '';
           };
@@ -186,16 +186,16 @@ in
             type = types.nullOr types.str;
             default = null;
             example = "runner-host-name.tld:8093";
-            description = ''
+            description = lib.mdDoc ''
               The URL that the Runner will expose to GitLab to be used
               to access the session server.
-              Fallbacks to  if not defined.
+              Fallbacks to {option}`listenAddress` if not defined.
             '';
           };
           sessionTimeout = mkOption {
             type = types.int;
             default = 1800;
-            description = ''
+            description = lib.mdDoc ''
               How long in seconds the session can stay active after
               the job completes (which will block the job from finishing).
             '';
@@ -208,16 +208,16 @@ in
           listenAddress = "0.0.0.0:8093";
         }
       '';
-      description = ''
+      description = lib.mdDoc ''
         The session server allows the user to interact with jobs
         that the Runner is responsible for. A good example of this is the
-        interactive web terminal.
+        [interactive web terminal](https://docs.gitlab.com/ee/ci/interactive_web_terminal/index.html).
       '';
     };
     gracefulTermination = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Finish all remaining jobs before stopping.
         If not set gitlab-runner will stop immediatly without waiting
         for jobs to finish, which will lead to failed builds.
@@ -227,7 +227,7 @@ in
       type = types.str;
       default = "infinity";
       example = "5min 20s";
-      description = ''
+      description = lib.mdDoc ''
         Time to wait until a graceful shutdown is turned into a forceful one.
       '';
     };
@@ -236,17 +236,17 @@ in
       default = pkgs.gitlab-runner;
       defaultText = "pkgs.gitlab-runner";
       example = literalExpression "pkgs.gitlab-runner_1_11";
-      description = "Gitlab Runner package to use.";
+      description = lib.mdDoc "Gitlab Runner package to use.";
     };
     extraPackages = mkOption {
       type = types.listOf types.package;
       default = [ ];
-      description = ''
+      description = lib.mdDoc ''
         Extra packages to add to PATH for the gitlab-runner process.
       '';
     };
     services = mkOption {
-      description = "GitLab Runner services.";
+      description = lib.mdDoc "GitLab Runner services.";
       default = { };
       example = literalExpression ''
         {
@@ -328,27 +328,27 @@ in
         options = {
           registrationConfigFile = mkOption {
             type = types.path;
-            description = ''
+            description = lib.mdDoc ''
               Absolute path to a file with environment variables
               used for gitlab-runner registration.
               A list of all supported environment variables can be found in
-              gitlab-runner register --help.
+              `gitlab-runner register --help`.
 
               Ones that you probably want to set is
 
-              CI_SERVER_URL=<CI server URL>
+              `CI_SERVER_URL=`
 
-              REGISTRATION_TOKEN=<registration secret>
+              `REGISTRATION_TOKEN=`
             '';
           };
           registrationFlags = mkOption {
             type = types.listOf types.str;
             default = [ ];
             example = [ "--docker-helper-image my/gitlab-runner-helper" ];
-            description = ''
+            description = lib.mdDoc ''
               Extra command-line flags passed to
-              gitlab-runner register.
-              Execute gitlab-runner register --help
+              `gitlab-runner register`.
+              Execute `gitlab-runner register --help`
               for a list of supported flags.
             '';
           };
@@ -356,25 +356,25 @@ in
             type = types.attrsOf types.str;
             default = { };
             example = { NAME = "value"; };
-            description = ''
+            description = lib.mdDoc ''
               Custom environment variables injected to build environment.
-              For secrets you can use 
-              with RUNNER_ENV variable set.
+              For secrets you can use {option}`registrationConfigFile`
+              with `RUNNER_ENV` variable set.
             '';
           };
           executor = mkOption {
             type = types.str;
             default = "docker";
-            description = ''
+            description = lib.mdDoc ''
               Select executor, eg. shell, docker, etc.
-              See runner documentation for more information.
+              See [runner documentation](https://docs.gitlab.com/runner/executors/README.html) for more information.
             '';
           };
           buildsDir = mkOption {
             type = types.nullOr types.path;
             default = null;
             example = "/var/lib/gitlab-runner/builds";
-            description = ''
+            description = lib.mdDoc ''
               Absolute path to a directory where builds will be stored
               in context of selected executor (Locally, Docker, SSH).
             '';
@@ -383,14 +383,14 @@ in
             type = types.nullOr types.str;
             default = null;
             example = "http://gitlab.example.local";
-            description = ''
+            description = lib.mdDoc ''
               Overwrite the URL for the GitLab instance. Used if the Runner can’t connect to GitLab on the URL GitLab exposes itself.
             '';
           };
           dockerImage = mkOption {
             type = types.nullOr types.str;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Docker image to be used.
             '';
           };
@@ -398,7 +398,7 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "/var/run/docker.sock:/var/run/docker.sock" ];
-            description = ''
+            description = lib.mdDoc ''
               Bind-mount a volume and create it
               if it doesn't exist prior to mounting.
             '';
@@ -406,14 +406,14 @@ in
           dockerDisableCache = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Disable all container caching.
             '';
           };
           dockerPrivileged = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Give extended privileges to container.
             '';
           };
@@ -421,7 +421,7 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "other-host:127.0.0.1" ];
-            description = ''
+            description = lib.mdDoc ''
               Add a custom host-to-IP mapping.
             '';
           };
@@ -429,7 +429,7 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "ruby:*" "python:*" "php:*" "my.registry.tld:5000/*:*" ];
-            description = ''
+            description = lib.mdDoc ''
               Whitelist allowed images.
             '';
           };
@@ -437,21 +437,21 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "postgres:9" "redis:*" "mysql:*" ];
-            description = ''
+            description = lib.mdDoc ''
               Whitelist allowed services.
             '';
           };
           preCloneScript = mkOption {
             type = types.nullOr types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Runner-specific command script executed before code is pulled.
             '';
           };
           preBuildScript = mkOption {
             type = types.nullOr types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Runner-specific command script executed after code is pulled,
               just before build executes.
             '';
@@ -459,7 +459,7 @@ in
           postBuildScript = mkOption {
             type = types.nullOr types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Runner-specific command script executed after code is pulled
               and just after build executes.
             '';
@@ -467,22 +467,22 @@ in
           tagList = mkOption {
             type = types.listOf types.str;
             default = [ ];
-            description = ''
+            description = lib.mdDoc ''
               Tag list.
             '';
           };
           runUntagged = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Register to run untagged builds; defaults to
-              true when  is empty.
+              `true` when {option}`tagList` is empty.
             '';
           };
           limit = mkOption {
             type = types.int;
             default = 0;
-            description = ''
+            description = lib.mdDoc ''
               Limit how many jobs can be handled concurrently by this service.
               0 (default) simply means don't limit.
             '';
@@ -490,14 +490,14 @@ in
           requestConcurrency = mkOption {
             type = types.int;
             default = 0;
-            description = ''
+            description = lib.mdDoc ''
               Limit number of concurrent requests for new jobs from GitLab.
             '';
           };
           maximumTimeout = mkOption {
             type = types.int;
             default = 0;
-            description = ''
+            description = lib.mdDoc ''
               What is the maximum timeout (in seconds) that will be set for
               job when using this Runner. 0 (default) simply means don't limit.
             '';
@@ -505,7 +505,7 @@ in
           protected = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               When set to true Runner will only run on pipelines
               triggered on protected branches.
             '';
@@ -513,9 +513,9 @@ in
           debugTraceDisabled = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               When set to true Runner will disable the possibility of
-              using the CI_DEBUG_TRACE feature.
+              using the `CI_DEBUG_TRACE` feature.
             '';
           };
         };
diff --git a/modules/services/hercules-ci-agent/default.nix b/modules/services/hercules-ci-agent/default.nix
index d9fbf37bc..538e10443 100644
--- a/modules/services/hercules-ci-agent/default.nix
+++ b/modules/services/hercules-ci-agent/default.nix
@@ -17,7 +17,7 @@ in
     logFile = mkOption {
       type = types.path;
       default = "/var/log/hercules-ci-agent.log";
-      description = "Stdout and sterr of hercules-ci-agent process.";
+      description = lib.mdDoc "Stdout and sterr of hercules-ci-agent process.";
     };
   };
 
diff --git a/modules/services/ipfs.nix b/modules/services/ipfs.nix
index df1f62e5a..8087ba460 100644
--- a/modules/services/ipfs.nix
+++ b/modules/services/ipfs.nix
@@ -14,14 +14,14 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether to enable the ipfs daemon.";
+        description = lib.mdDoc "Whether to enable the ipfs daemon.";
       };
 
       package = mkOption {
         type = types.path;
         default = pkgs.kubo;
         # defaultText = "pkgs.kubo";
-        description = ''
+        description = lib.mdDoc ''
           The ipfs package to use.
         '';
       };
@@ -30,24 +30,24 @@ in
         type = types.nullOr types.path;
         default = null;
         example =  "/var/tmp/lorri.log";
-        description = ''
+        description = lib.mdDoc ''
           The logfile to use for the ipfs service. Alternatively
-          sudo launchctl debug system/org.nixos.ipfs --stderr
+          {command}`sudo launchctl debug system/org.nixos.ipfs --stderr`
           can be used to stream the logs to a shell after restarting the service with
-          sudo launchctl kickstart -k system/org.nixos.ipfs.
+          {command}`sudo launchctl kickstart -k system/org.nixos.ipfs`.
         '';
       };
 
       ipfsPath = mkOption {
         type = types.nullOr types.path;
         default = null;
-        description = "Set the IPFS_PATH environment variable.";
+        description = lib.mdDoc "Set the IPFS_PATH environment variable.";
       };
 
       enableGarbageCollection = mkOption {
         type = types.bool;
         default = false;
-        description = "Passes --enable-gc flag to ipfs daemon.";
+        description = lib.mdDoc "Passes --enable-gc flag to ipfs daemon.";
       };
   };
 
diff --git a/modules/services/karabiner-elements/default.nix b/modules/services/karabiner-elements/default.nix
index 2f415b2d6..7c0636c67 100644
--- a/modules/services/karabiner-elements/default.nix
+++ b/modules/services/karabiner-elements/default.nix
@@ -10,7 +10,7 @@ in
 
 {
   options = {
-    services.karabiner-elements.enable = mkEnableOption "Karabiner-Elements";
+    services.karabiner-elements.enable = mkEnableOption (lib.mdDoc "Karabiner-Elements");
   };
 
   config = mkIf cfg.enable {
diff --git a/modules/services/khd/default.nix b/modules/services/khd/default.nix
index 45a389d9f..ef16a2bfb 100644
--- a/modules/services/khd/default.nix
+++ b/modules/services/khd/default.nix
@@ -13,27 +13,27 @@ in
     services.khd.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the khd hotkey daemon.";
+      description = lib.mdDoc "Whether to enable the khd hotkey daemon.";
     };
 
     services.khd.package = mkOption {
       type = types.package;
       default = pkgs.khd;
       defaultText = "pkgs.khd";
-      description = "This option specifies the khd package to use.";
+      description = lib.mdDoc "This option specifies the khd package to use.";
     };
 
     services.khd.khdConfig = mkOption {
       type = types.lines;
       default = "";
       example = "alt + shift - r   :   kwmc quit";
-      description = "Config to use for khdrc.";
+      description = lib.mdDoc "Config to use for {file}`khdrc`.";
     };
 
     services.khd.i3Keybindings = mkOption {
       type = types.bool;
       default = false;
-      description = "Wether to configure i3 style keybindings for kwm.";
+      description = lib.mdDoc "Wether to configure i3 style keybindings for kwm.";
     };
   };
 
diff --git a/modules/services/kwm/default.nix b/modules/services/kwm/default.nix
index 1d09e2386..c6603b945 100644
--- a/modules/services/kwm/default.nix
+++ b/modules/services/kwm/default.nix
@@ -11,21 +11,21 @@ in
     services.kwm.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the khd window manager.";
+      description = lib.mdDoc "Whether to enable the khd window manager.";
     };
 
     services.kwm.package = mkOption {
       type = types.path;
       default = pkgs.kwm;
       defaultText = "pkgs.kwm";
-      description = "This option specifies the kwm package to use.";
+      description = lib.mdDoc "This option specifies the kwm package to use.";
     };
 
     services.kwm.kwmConfig = mkOption {
       type = types.lines;
       default = "";
       example = ''kwmc rule owner="iTerm2" properties={role="AXDialog"}'';
-      description = "Config to use for kwmrc.";
+      description = lib.mdDoc "Config to use for {file}`kwmrc`.";
     };
   };
 
diff --git a/modules/services/lorri.nix b/modules/services/lorri.nix
index f637b9c73..246bcfa3f 100644
--- a/modules/services/lorri.nix
+++ b/modules/services/lorri.nix
@@ -11,18 +11,18 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether to enable the lorri service.";
+        description = lib.mdDoc "Whether to enable the lorri service.";
       };
       
       logFile = mkOption {
         type = types.nullOr types.path;
         default = null;
         example =  "/var/tmp/lorri.log";
-        description = ''
+        description = lib.mdDoc ''
           The logfile to use for the lorri service. Alternatively
-          sudo launchctl debug system/org.nixos.lorri --stderr
+          {command}`sudo launchctl debug system/org.nixos.lorri --stderr`
           can be used to stream the logs to a shell after restarting the service with
-          sudo launchctl kickstart -k system/org.nixos.lorri.
+          {command}`sudo launchctl kickstart -k system/org.nixos.lorri`.
         '';
       };
     };
diff --git a/modules/services/mail/offlineimap.nix b/modules/services/mail/offlineimap.nix
index 4f76dc55e..b7913cb44 100644
--- a/modules/services/mail/offlineimap.nix
+++ b/modules/services/mail/offlineimap.nix
@@ -7,32 +7,32 @@ let
 in {
 
   options.services.offlineimap = {
-    enable = mkEnableOption "Offlineimap, a software to dispose your mailbox(es) as a local Maildir(s)";
+    enable = mkEnableOption (lib.mdDoc "Offlineimap, a software to dispose your mailbox(es) as a local Maildir(s)");
 
     package = mkOption {
       type = types.package;
       default = pkgs.offlineimap;
       defaultText = "pkgs.offlineimap";
-      description = "Offlineimap derivation to use.";
+      description = lib.mdDoc "Offlineimap derivation to use.";
     };
 
     path = mkOption {
       type = types.listOf types.path;
       default = [];
       example = literalExpression "[ pkgs.pass pkgs.bash pkgs.notmuch ]";
-      description = "List of derivations to put in Offlineimap's path.";
+      description = lib.mdDoc "List of derivations to put in Offlineimap's path.";
     };
 
     startInterval = mkOption {
       type = types.nullOr types.int;
       default = 300;
-      description = "Optional key to start offlineimap services each N seconds";
+      description = lib.mdDoc "Optional key to start offlineimap services each N seconds";
     };
 
     runQuick = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Run only quick synchronizations.
         Ignore any flag updates on IMAP servers. If a flag on the remote IMAP changes, and we have the message locally, it will be left untouched in a quick run.
       '';
@@ -41,7 +41,7 @@ in {
     extraConfig = mkOption {
       type = types.lines;
       default = "";
-      description = "Additional text to be appended to offlineimaprc.";
+      description = lib.mdDoc "Additional text to be appended to {file}`offlineimaprc`.";
     };
   };
 
diff --git a/modules/services/monitoring/telegraf.nix b/modules/services/monitoring/telegraf.nix
index f40e01302..e3d32502e 100644
--- a/modules/services/monitoring/telegraf.nix
+++ b/modules/services/monitoring/telegraf.nix
@@ -10,12 +10,12 @@ let
 in {
   options = {
     services.telegraf = {
-      enable = mkEnableOption "telegraf agent";
+      enable = mkEnableOption (lib.mdDoc "telegraf agent");
 
       package = mkOption {
         default = pkgs.telegraf;
         defaultText = lib.literalExpression "pkgs.telegraf";
-        description = "Which telegraf derivation to use";
+        description = lib.mdDoc "Which telegraf derivation to use";
         type = types.package;
       };
 
@@ -23,7 +23,7 @@ in {
         type = types.listOf types.path;
         default = [ ];
         example = [ "/run/keys/telegraf.env" ];
-        description = ''
+        description = lib.mdDoc ''
           File to load as environment file.
           This is useful to avoid putting secrets into the nix store.
         '';
@@ -31,7 +31,7 @@ in {
 
       extraConfig = mkOption {
         default = { };
-        description = "Extra configuration options for telegraf";
+        description = lib.mdDoc "Extra configuration options for telegraf";
         type = settingsFormat.type;
         example = {
           outputs.influxdb = {
@@ -47,7 +47,7 @@ in {
 
       configUrl = mkOption {
         default = null;
-        description = "Url to fetch config from";
+        description = lib.mdDoc "Url to fetch config from";
         type = types.nullOr types.str;
       };
     };
diff --git a/modules/services/mopidy.nix b/modules/services/mopidy.nix
index be3c05e14..2fb9a1594 100644
--- a/modules/services/mopidy.nix
+++ b/modules/services/mopidy.nix
@@ -11,27 +11,27 @@ in
     services.mopidy.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the Mopidy Daemon.";
+      description = lib.mdDoc "Whether to enable the Mopidy Daemon.";
     };
 
     services.mopidy.package = mkOption {
       type = types.path;
       default = pkgs.mopidy;
       defaultText = "pkgs.mopidy";
-      description = "This option specifies the mopidy package to use.";
+      description = lib.mdDoc "This option specifies the mopidy package to use.";
     };
 
     services.mopidy.mediakeys.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the Mopidy OSX Media Keys support daemon.";
+      description = lib.mdDoc "Whether to enable the Mopidy OSX Media Keys support daemon.";
     };
 
     services.mopidy.mediakeys.package = mkOption {
       type = types.path;
       default = pkgs.pythonPackages.osxmpdkeys;
       defaultText = "pkgs.pythonPackages.osxmpdkeys";
-      description = "This option specifies the mediakeys package to use.";
+      description = lib.mdDoc "This option specifies the mediakeys package to use.";
     };
   };
 
diff --git a/modules/services/netbird.nix b/modules/services/netbird.nix
index 5bc8ebdf9..ad0bf3e49 100644
--- a/modules/services/netbird.nix
+++ b/modules/services/netbird.nix
@@ -5,12 +5,12 @@ let
 in
 {
   options.services.netbird = {
-    enable = mkEnableOption "Netbird daemon";
+    enable = mkEnableOption (lib.mdDoc "Netbird daemon");
     package = mkOption {
       type = types.package;
       default = pkgs.netbird;
       defaultText = literalExpression "pkgs.netbird";
-      description = "The package to use for netbird";
+      description = lib.mdDoc "The package to use for netbird";
     };
   };
   config = mkIf cfg.enable {
diff --git a/modules/services/nextdns/default.nix b/modules/services/nextdns/default.nix
index 23120965b..5ea5e75ac 100644
--- a/modules/services/nextdns/default.nix
+++ b/modules/services/nextdns/default.nix
@@ -13,13 +13,13 @@ in {
         type = types.bool;
         default = false;
         description =
-          "Whether to enable the NextDNS DNS/53 to DoH Proxy service.";
+          lib.mdDoc "Whether to enable the NextDNS DNS/53 to DoH Proxy service.";
       };
       arguments = mkOption {
         type = types.listOf types.str;
         default = [ ];
         example = [ "-config" "10.0.3.0/24=abcdef" ];
-        description = "Additional arguments to be passed to nextdns run.";
+        description = lib.mdDoc "Additional arguments to be passed to nextdns run.";
       };
     };
   };
diff --git a/modules/services/nix-daemon.nix b/modules/services/nix-daemon.nix
index 5e87e5139..35476a0af 100644
--- a/modules/services/nix-daemon.nix
+++ b/modules/services/nix-daemon.nix
@@ -11,31 +11,31 @@ in
     services.nix-daemon.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the nix-daemon service.";
+      description = lib.mdDoc "Whether to enable the nix-daemon service.";
     };
 
     services.nix-daemon.enableSocketListener = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to make the nix-daemon service socket activated.";
+      description = lib.mdDoc "Whether to make the nix-daemon service socket activated.";
     };
 
     services.nix-daemon.logFile = mkOption {
       type = types.nullOr types.path;
       default = null;
       example = "/var/log/nix-daemon.log";
-      description = ''
+      description = lib.mdDoc ''
         The logfile to use for the nix-daemon service. Alternatively
-        sudo launchctl debug system/org.nixos.nix-daemon --stderr
+        {command}`sudo launchctl debug system/org.nixos.nix-daemon --stderr`
         can be used to stream the logs to a shell after restarting the service with
-        sudo launchctl kickstart -k system/org.nixos.nix-daemon.
+        {command}`sudo launchctl kickstart -k system/org.nixos.nix-daemon`.
       '';
     };
 
     services.nix-daemon.tempDir = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = "The TMPDIR to use for nix-daemon.";
+      description = lib.mdDoc "The TMPDIR to use for nix-daemon.";
     };
   };
 
diff --git a/modules/services/nix-gc/default.nix b/modules/services/nix-gc/default.nix
index fca680378..3ca661053 100644
--- a/modules/services/nix-gc/default.nix
+++ b/modules/services/nix-gc/default.nix
@@ -24,28 +24,28 @@ in
       automatic = mkOption {
         default = false;
         type = types.bool;
-        description = "Automatically run the garbage collector at a specific time.";
+        description = lib.mdDoc "Automatically run the garbage collector at a specific time.";
       };
 
       # Not in NixOS module
       user = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "User that runs the garbage collector.";
+        description = lib.mdDoc "User that runs the garbage collector.";
       };
 
       interval = mkOption {
         type = types.attrs;
         default = { Hour = 3; Minute = 15; };
-        description = "The time interval at which the garbage collector will run.";
+        description = lib.mdDoc "The time interval at which the garbage collector will run.";
       };
 
       options = mkOption {
         default = "";
         example = "--max-freed $((64 * 1024**3))";
         type = types.str;
-        description = ''
-          Options given to nix-collect-garbage when the
+        description = lib.mdDoc ''
+          Options given to {file}`nix-collect-garbage` when the
           garbage collector is run automatically.
         '';
       };
diff --git a/modules/services/ofborg/default.nix b/modules/services/ofborg/default.nix
index 5bc0f9df0..6c9bac8ef 100644
--- a/modules/services/ofborg/default.nix
+++ b/modules/services/ofborg/default.nix
@@ -12,13 +12,13 @@ in
     services.ofborg.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the ofborg builder service.";
+      description = lib.mdDoc "Whether to enable the ofborg builder service.";
     };
 
     services.ofborg.package = mkOption {
       type = types.package;
       example = literalExpression "pkgs.ofborg";
-      description = ''
+      description = lib.mdDoc ''
         This option specifies the ofborg package to use. eg.
 
         (import <ofborg> {}).ofborg.rs
@@ -30,7 +30,7 @@ in
 
     services.ofborg.configFile = mkOption {
       type = types.path;
-      description = ''
+      description = lib.mdDoc ''
         Configuration file to use for ofborg.
 
         WARNING Don't use a path literal or derivation for this,
@@ -41,7 +41,7 @@ in
     services.ofborg.logFile = mkOption {
       type = types.path;
       default = "/var/log/ofborg.log";
-      description = "Whether to enable the khd window manager.";
+      description = lib.mdDoc "Whether to enable the khd window manager.";
     };
   };
 
diff --git a/modules/services/postgresql/default.nix b/modules/services/postgresql/default.nix
index e6feb96e6..018b46eb0 100644
--- a/modules/services/postgresql/default.nix
+++ b/modules/services/postgresql/default.nix
@@ -40,12 +40,12 @@ in
 
     services.postgresql = {
 
-      enable = mkEnableOption "PostgreSQL Server";
+      enable = mkEnableOption (lib.mdDoc "PostgreSQL Server");
 
       package = mkOption {
         type = types.package;
         example = literalExpression "pkgs.postgresql_11";
-        description = ''
+        description = lib.mdDoc ''
           PostgreSQL package to use.
         '';
       };
@@ -53,7 +53,7 @@ in
       port = mkOption {
         type = types.int;
         default = 5432;
-        description = ''
+        description = lib.mdDoc ''
           The port on which PostgreSQL listens.
         '';
       };
@@ -61,14 +61,14 @@ in
       checkConfig = mkOption {
         type = types.bool;
         default = true;
-        description = "Check the syntax of the configuration file at compile time";
+        description = lib.mdDoc "Check the syntax of the configuration file at compile time";
       };
 
       dataDir = mkOption {
         type = types.path;
         defaultText = literalExpression ''"/var/lib/postgresql/''${config.services.postgresql.package.psqlSchema}"'';
         example = "/var/lib/postgresql/11";
-        description = ''
+        description = lib.mdDoc ''
           The data directory for PostgreSQL. If left as the default value
           this directory will automatically be created before the PostgreSQL server starts, otherwise
           the sysadmin is responsible for ensuring the directory exists with appropriate ownership
@@ -79,16 +79,16 @@ in
       authentication = mkOption {
         type = types.lines;
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Defines how users authenticate themselves to the server. See the
-          
-          PostgreSQL documentation for pg_hba.conf
+          [
+          PostgreSQL documentation for pg_hba.conf](https://www.postgresql.org/docs/current/auth-pg-hba-conf.html)
           for details on the expected format of this option. By default,
           peer based authentication will be used for users connecting
           via the Unix socket, and md5 password authentication will be
           used for users connecting via TCP. Any added rules will be
           inserted above the default rules. If you'd like to replace the
-          default rules entirely, you can use lib.mkForce in your
+          default rules entirely, you can use `lib.mkForce` in your
           module.
         '';
       };
@@ -96,7 +96,7 @@ in
       identMap = mkOption {
         type = types.lines;
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Defines the mapping from system users to database users.
 
           The general form is:
@@ -109,8 +109,8 @@ in
         type = with types; listOf str;
         default = [];
         example = [ "--data-checksums" "--allow-group-access" ];
-        description = ''
-          Additional arguments passed to initdb during data dir
+        description = lib.mdDoc ''
+          Additional arguments passed to `initdb` during data dir
           initialisation.
         '';
       };
@@ -118,7 +118,7 @@ in
       initialScript = mkOption {
         type = types.nullOr types.path;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           A file containing SQL statements to execute on first startup.
         '';
       };
@@ -126,7 +126,7 @@ in
       ensureDatabases = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           Ensures that the specified databases exist.
           This option will never delete existing databases, especially not when the value of this
           option is changed. This means that databases created once through this option or
@@ -143,14 +143,14 @@ in
           options = {
             name = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Name of the user to ensure.
               '';
             };
             ensurePermissions = mkOption {
               type = types.attrsOf types.str;
               default = {};
-              description = ''
+              description = lib.mdDoc ''
                 Permissions to ensure for the user, specified as an attribute set.
                 The attribute names specify the database and tables to grant the permissions for.
                 The attribute values specify the permissions to grant. You may specify one or
@@ -158,8 +158,8 @@ in
 
                 For more information on how to specify the target
                 and on which privileges exist, see the
-                GRANT syntax.
-                The attributes are used as GRANT ''${attrValue} ON ''${attrName}.
+                [GRANT syntax](https://www.postgresql.org/docs/current/sql-grant.html).
+                The attributes are used as `GRANT ''${attrValue} ON ''${attrName}`.
               '';
               example = literalExpression ''
                 {
@@ -171,7 +171,7 @@ in
           };
         });
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           Ensures that the specified users exist and have at least the ensured permissions.
           The PostgreSQL users will be identified using peer authentication. This authenticates the Unix user with the
           same name only, and that without the need for a password.
@@ -200,7 +200,7 @@ in
       enableTCPIP = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether PostgreSQL should listen on all network interfaces.
           If disabled, the database can only be accessed via its Unix
           domain socket or via TCP connections to localhost.
@@ -211,9 +211,9 @@ in
         type = types.str;
         default = "[%p] ";
         example = "%m [%p] ";
-        description = ''
+        description = lib.mdDoc ''
           A printf-style string that is output at the beginning of each log line.
-          Upstream default is '%m [%p] ', i.e. it includes the timestamp. We do
+          Upstream default is `'%m [%p] '`, i.e. it includes the timestamp. We do
           not include the timestamp, because journal has it anyway.
         '';
       };
@@ -222,24 +222,26 @@ in
         type = types.listOf types.path;
         default = [];
         example = literalExpression "with pkgs.postgresql_11.pkgs; [ postgis pg_repack ]";
-        description = ''
+        description = lib.mdDoc ''
           List of PostgreSQL plugins. PostgreSQL version for each plugin should
-          match version for services.postgresql.package value.
+          match version for `services.postgresql.package` value.
         '';
       };
 
       settings = mkOption {
         type = with types; attrsOf (oneOf [ bool float int str ]);
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           PostgreSQL configuration. Refer to
-          
-          for an overview of postgresql.conf.
+          
+          for an overview of `postgresql.conf`.
 
-          
+          ::: {.note}
+          
           String values will automatically be enclosed in single quotes. Single quotes will be
           escaped with two single quotes as described by the upstream documentation linked above.
-          
+          
+          :::
         '';
         example = literalExpression ''
           {
@@ -255,8 +257,8 @@ in
       recoveryConfig = mkOption {
         type = types.nullOr types.lines;
         default = null;
-        description = ''
-          Contents of the recovery.conf file.
+        description = lib.mdDoc ''
+          Contents of the {file}`recovery.conf` file.
         '';
       };
 
@@ -265,7 +267,7 @@ in
         default = "postgres";
         internal = true;
         readOnly = true;
-        description = ''
+        description = lib.mdDoc ''
           PostgreSQL superuser account to use for various operations. Internal since changing
           this value would lead to breakage while setting up databases.
         '';
diff --git a/modules/services/privoxy/default.nix b/modules/services/privoxy/default.nix
index b3147232b..5f7780c37 100644
--- a/modules/services/privoxy/default.nix
+++ b/modules/services/privoxy/default.nix
@@ -10,40 +10,40 @@ in
     services.privoxy.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the privoxy proxy service.";
+      description = lib.mdDoc "Whether to enable the privoxy proxy service.";
     };
 
     services.privoxy.listenAddress = mkOption {
       type = types.str;
       default = "127.0.0.1:8118";
-      description = "The address and TCP port on which privoxy will listen.";
+      description = lib.mdDoc "The address and TCP port on which privoxy will listen.";
     };
 
     services.privoxy.package = mkOption {
       type = types.package;
       default = pkgs.privoxy;
       example = literalExpression "pkgs.privoxy";
-      description = "This option specifies the privoxy package to use.";
+      description = lib.mdDoc "This option specifies the privoxy package to use.";
     };
 
     services.privoxy.config = mkOption {
       type = types.lines;
       default = "";
       example = "forward / upstream.proxy:8080";
-      description = "Config to use for privoxy";
+      description = lib.mdDoc "Config to use for privoxy";
     };
 
     services.privoxy.templdir = mkOption {
       type = types.path;
       default = "${pkgs.privoxy}/etc/templates";
       defaultText = "\${pkgs.privoxy}/etc/templates";
-      description = "Directory for privoxy template files.";
+      description = lib.mdDoc "Directory for privoxy template files.";
     };
 
     services.privoxy.confdir = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = "Directory for privoxy files such as .action and .filter.";
+      description = lib.mdDoc "Directory for privoxy files such as .action and .filter.";
     };
   };
 
diff --git a/modules/services/redis/default.nix b/modules/services/redis/default.nix
index c6d434fa7..0fa0af7e3 100644
--- a/modules/services/redis/default.nix
+++ b/modules/services/redis/default.nix
@@ -11,52 +11,52 @@ in
     services.redis.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the redis database service.";
+      description = lib.mdDoc "Whether to enable the redis database service.";
     };
 
     services.redis.package = mkOption {
       type = types.path;
       default = pkgs.redis;
       defaultText = "pkgs.redis";
-      description = "This option specifies the redis package to use";
+      description = lib.mdDoc "This option specifies the redis package to use";
     };
 
     services.redis.dataDir = mkOption {
       type = types.nullOr types.path;
       default = "/var/lib/redis";
-      description = "Data directory for the redis database.";
+      description = lib.mdDoc "Data directory for the redis database.";
     };
 
     services.redis.port = mkOption {
       type = types.int;
       default = 6379;
-      description = "The port for Redis to listen to.";
+      description = lib.mdDoc "The port for Redis to listen to.";
     };
 
     services.redis.bind = mkOption {
       type = types.nullOr types.str;
       default = null; # All interfaces
-      description = "The IP interface to bind to.";
+      description = lib.mdDoc "The IP interface to bind to.";
       example = "127.0.0.1";
     };
 
     services.redis.unixSocket = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = "The path to the socket to bind to.";
+      description = lib.mdDoc "The path to the socket to bind to.";
       example = "/var/run/redis.sock";
     };
 
     services.redis.appendOnly = mkOption {
       type = types.bool;
       default = false;
-      description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
+      description = lib.mdDoc "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
     };
 
     services.redis.extraConfig = mkOption {
       type = types.lines;
       default = "";
-      description = "Additional text to be appended to redis.conf.";
+      description = lib.mdDoc "Additional text to be appended to {file}`redis.conf`.";
     };
   };
 
diff --git a/modules/services/skhd/default.nix b/modules/services/skhd/default.nix
index fed31f09e..4ec1e2bf1 100644
--- a/modules/services/skhd/default.nix
+++ b/modules/services/skhd/default.nix
@@ -11,20 +11,20 @@ in
     services.skhd.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable the skhd hotkey daemon.";
+      description = lib.mdDoc "Whether to enable the skhd hotkey daemon.";
     };
 
     services.skhd.package = mkOption {
       type = types.package;
       default = pkgs.skhd;
-      description = "This option specifies the skhd package to use.";
+      description = lib.mdDoc "This option specifies the skhd package to use.";
     };
 
     services.skhd.skhdConfig = mkOption {
       type = types.lines;
       default = "";
       example = "alt + shift - r   :   chunkc quit";
-      description = "Config to use for skhdrc.";
+      description = lib.mdDoc "Config to use for {file}`skhdrc`.";
     };
   };
 
diff --git a/modules/services/spacebar/default.nix b/modules/services/spacebar/default.nix
index a56dac537..eb06cada5 100644
--- a/modules/services/spacebar/default.nix
+++ b/modules/services/spacebar/default.nix
@@ -22,12 +22,12 @@ in
     services.spacebar.enable = mkOption {
       type = bool;
       default = false;
-      description = "Whether to enable the spacebar spacebar.";
+      description = lib.mdDoc "Whether to enable the spacebar spacebar.";
     };
 
     services.spacebar.package = mkOption {
       type = path;
-      description = "The spacebar package to use.";
+      description = lib.mdDoc "The spacebar package to use.";
     };
 
     services.spacebar.config = mkOption {
@@ -40,7 +40,7 @@ in
           foreground_color = "0xffa8a8a8";
         }
       '';
-      description = ''
+      description = lib.mdDoc ''
         Key/Value pairs to pass to spacebar's 'config' domain, via the configuration file.
       '';
     };
@@ -51,7 +51,7 @@ in
       example = literalExpression ''
         echo "spacebar config loaded..."
       '';
-      description = ''
+      description = lib.mdDoc ''
         Extra arbitrary configuration to append to the configuration file.
       '';
     };
diff --git a/modules/services/spotifyd.nix b/modules/services/spotifyd.nix
index 461d4dfec..2469a2458 100644
--- a/modules/services/spotifyd.nix
+++ b/modules/services/spotifyd.nix
@@ -19,7 +19,7 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable the spotifyd service.
         '';
       };
@@ -28,7 +28,7 @@ in
         type = types.path;
         default = pkgs.spotifyd;
         defaultText = "pkgs.spotifyd";
-        description = ''
+        description = lib.mdDoc ''
           The spotifyd package to use.
         '';
       };
@@ -40,8 +40,8 @@ in
           bitrate = 160;
           volume_normalisation = true;
         };
-        description = ''
-          Configuration for spotifyd, see 
+        description = lib.mdDoc ''
+          Configuration for spotifyd, see 
           for supported values.
         '';
       };
diff --git a/modules/services/synapse-bt.nix b/modules/services/synapse-bt.nix
index d85a2cd0f..3970cac76 100644
--- a/modules/services/synapse-bt.nix
+++ b/modules/services/synapse-bt.nix
@@ -26,32 +26,32 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether to run Synapse BitTorrent Daemon.";
+        description = lib.mdDoc "Whether to run Synapse BitTorrent Daemon.";
       };
 
       package = mkOption {
         type = types.package;
         default = pkgs.synapse-bt;
         defaultText = "pkgs.synapse-bt";
-        description = "Synapse BitTorrent package to use.";
+        description = lib.mdDoc "Synapse BitTorrent package to use.";
       };
 
       port = mkOption {
         type = types.int;
         default = 16384;
-        description = "The port on which Synapse BitTorrent listens.";
+        description = lib.mdDoc "The port on which Synapse BitTorrent listens.";
       };
 
       downloadDir = mkOption {
         type = types.path;
         default = "/var/lib/synapse-bt";
         example = "/var/lib/synapse-bt/downloads";
-        description = "Download directory for Synapse BitTorrent.";
+        description = lib.mdDoc "Download directory for Synapse BitTorrent.";
       };
 
       extraConfig = mkOption {
         default = {};
-        description = "Extra configuration options for Synapse BitTorrent.";
+        description = lib.mdDoc "Extra configuration options for Synapse BitTorrent.";
         type = types.attrs;
       };
     };
diff --git a/modules/services/synergy/default.nix b/modules/services/synergy/default.nix
index 2ca97a063..95daf377d 100644
--- a/modules/services/synergy/default.nix
+++ b/modules/services/synergy/default.nix
@@ -16,28 +16,28 @@ in
         default = pkgs.synergy;
         defaultText = "pkgs.synergy";
         type = types.package;
-        description = "The package used for the synergy client and server.";
+        description = lib.mdDoc "The package used for the synergy client and server.";
       };
 
       client = {
         enable = mkOption {
           default = false;
           type = types.bool;
-          description = ''
+          description = lib.mdDoc ''
             Whether to enable the Synergy client (receive keyboard and mouse events from a Synergy server).
           '';
         };
         screenName = mkOption {
           default = "";
           type = types.str;
-          description = ''
+          description = lib.mdDoc ''
             Use the given name instead of the hostname to identify
             ourselves to the server.
           '';
         };
         serverAddress = mkOption {
           type = types.str;
-          description = ''
+          description = lib.mdDoc ''
             The server address is of the form: [hostname][:port].  The
             hostname must be the address or hostname of the server.  The
             port overrides the default port, 24800.
@@ -46,21 +46,21 @@ in
         autoStart = mkOption {
           default = true;
           type = types.bool;
-          description = "Whether the Synergy client should be started automatically.";
+          description = lib.mdDoc "Whether the Synergy client should be started automatically.";
         };
         tls = {
-          enable = mkEnableOption ''
+          enable = mkEnableOption (lib.mdDoc ''
             Whether TLS encryption should be used.
 
             Using this requires a TLS certificate that can be
             generated by starting the Synergy GUI once and entering
             a valid product key.
-          '';
+          '');
           cert = mkOption {
             type = types.nullOr types.str;
             default = null;
             example = "~/.synergy/SSL/Synergy.pem";
-            description = "The TLS certificate to use for encryption.";
+            description = lib.mdDoc "The TLS certificate to use for encryption.";
           };
         };
       };
@@ -69,19 +69,19 @@ in
         enable = mkOption {
           default = false;
           type = types.bool;
-          description = ''
+          description = lib.mdDoc ''
             Whether to enable the Synergy server (send keyboard and mouse events).
           '';
         };
         configFile = mkOption {
           default = "/etc/synergy-server.conf";
           type = types.str;
-          description = "The Synergy server configuration file.";
+          description = lib.mdDoc "The Synergy server configuration file.";
         };
         screenName = mkOption {
           default = "";
           type = types.str;
-          description = ''
+          description = lib.mdDoc ''
             Use the given name instead of the hostname to identify
             this screen in the configuration.
           '';
@@ -89,26 +89,26 @@ in
         address = mkOption {
           default = "";
           type = types.str;
-          description = "Address on which to listen for clients.";
+          description = lib.mdDoc "Address on which to listen for clients.";
         };
         autoStart = mkOption {
           default = true;
           type = types.bool;
-          description = "Whether the Synergy server should be started automatically.";
+          description = lib.mdDoc "Whether the Synergy server should be started automatically.";
         };
         tls = {
-          enable = mkEnableOption ''
+          enable = mkEnableOption (lib.mdDoc ''
             Whether TLS encryption should be used.
 
             Using this requires a TLS certificate that can be
             generated by starting the Synergy GUI once and entering
             a valid product key.
-          '';
+          '');
           cert = mkOption {
             type = types.nullOr types.str;
             default = null;
             example = "~/.synergy/SSL/Synergy.pem";
-            description = "The TLS certificate to use for encryption.";
+            description = lib.mdDoc "The TLS certificate to use for encryption.";
           };
         };
       };
diff --git a/modules/services/tailscale.nix b/modules/services/tailscale.nix
index afe4382d7..da319ebee 100644
--- a/modules/services/tailscale.nix
+++ b/modules/services/tailscale.nix
@@ -11,16 +11,16 @@ in
     domain = mkOption {
       type = types.str;
       default = "";
-      description = "The Tailscale domain. This is displayed at the top left of https://login.tailscale.com/admin, next to the Tailscale logo.";
+      description = lib.mdDoc "The Tailscale domain. This is displayed at the top left of https://login.tailscale.com/admin, next to the Tailscale logo.";
     };
 
-    enable = mkEnableOption "Tailscale client daemon";
+    enable = mkEnableOption (lib.mdDoc "Tailscale client daemon");
 
     package = mkOption {
       type = types.package;
       default = pkgs.tailscale;
       defaultText = literalExpression "pkgs.tailscale";
-      description = "The package to use for tailscale";
+      description = lib.mdDoc "The package to use for tailscale";
     };
 
     magicDNS = {
@@ -28,7 +28,7 @@ in
         type = types.bool;
         default = false;
         example = true;
-        description = "Whether to configure networking to work with Tailscale's MagicDNS.";
+        description = lib.mdDoc "Whether to configure networking to work with Tailscale's MagicDNS.";
       };
     };
   };
diff --git a/modules/services/wg-quick.nix b/modules/services/wg-quick.nix
index 14568237d..1e0b86519 100644
--- a/modules/services/wg-quick.nix
+++ b/modules/services/wg-quick.nix
@@ -10,32 +10,32 @@ let
       allowedIPs = mkOption {
         type = types.listOf types.str;
         default = [ ];
-        description = "List of IP addresses associated with this peer.";
+        description = lib.mdDoc "List of IP addresses associated with this peer.";
       };
 
       endpoint = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "IP and port to connect to this peer at.";
+        description = lib.mdDoc "IP and port to connect to this peer at.";
       };
 
       persistentKeepalive = mkOption {
         type = types.nullOr types.int;
         default = null;
-        description = "Interval in seconds to send keepalive packets";
+        description = lib.mdDoc "Interval in seconds to send keepalive packets";
       };
 
       presharedKeyFile = mkOption {
         type = types.nullOr types.str;
         default = null;
         description =
-          "Optional, path to file containing the pre-shared key for this peer.";
+          lib.mdDoc "Optional, path to file containing the pre-shared key for this peer.";
       };
 
       publicKey = mkOption {
         default = null;
         type = types.str;
-        description = "The public key for this peer.";
+        description = lib.mdDoc "The public key for this peer.";
       };
     };
   };
@@ -45,69 +45,69 @@ let
       address = mkOption {
         type = types.nullOr (types.listOf types.str);
         default = [ ];
-        description = "List of IP addresses for this interface.";
+        description = lib.mdDoc "List of IP addresses for this interface.";
       };
 
       autostart = mkOption {
         type = types.bool;
         default = true;
         description =
-          "Whether to bring up this interface automatically during boot.";
+          lib.mdDoc "Whether to bring up this interface automatically during boot.";
       };
 
       dns = mkOption {
         type = types.listOf types.str;
         default = [ ];
-        description = "List of DNS servers for this interface.";
+        description = lib.mdDoc "List of DNS servers for this interface.";
       };
 
       listenPort = mkOption {
         type = types.nullOr types.int;
         default = null;
-        description = "Port to listen on, randomly selected if not specified.";
+        description = lib.mdDoc "Port to listen on, randomly selected if not specified.";
       };
 
       mtu = mkOption {
         type = types.nullOr types.int;
         default = null;
         description =
-          "MTU to set for this interface, automatically set if not specified";
+          lib.mdDoc "MTU to set for this interface, automatically set if not specified";
       };
 
       peers = mkOption {
         type = types.listOf (types.submodule peerOpts);
         default = [ ];
-        description = "List of peers associated with this interface.";
+        description = lib.mdDoc "List of peers associated with this interface.";
       };
 
       preDown = mkOption {
         type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
         default = "";
-        description = "List of commadns to run before interface shutdown.";
+        description = lib.mdDoc "List of commadns to run before interface shutdown.";
       };
 
       preUp = mkOption {
         type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
         default = "";
-        description = "List of commands to run before interface setup.";
+        description = lib.mdDoc "List of commands to run before interface setup.";
       };
 
       postDown = mkOption {
         type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
         default = "";
-        description = "List of commands to run after interface shutdown";
+        description = lib.mdDoc "List of commands to run after interface shutdown";
       };
 
       postUp = mkOption {
         type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
         default = "";
-        description = "List of commands to run after interface setup.";
+        description = lib.mdDoc "List of commands to run after interface setup.";
       };
 
       privateKeyFile = mkOption {
         type = types.str;
         default = null;
-        description = "Path to file containing this interface's private key.";
+        description = lib.mdDoc "Path to file containing this interface's private key.";
       };
 
       table = mkOption {
@@ -208,13 +208,13 @@ in {
       interfaces = mkOption {
         type = types.attrsOf (types.submodule interfaceOpts);
         default = { };
-        description = "Set of wg-quick interfaces.";
+        description = lib.mdDoc "Set of wg-quick interfaces.";
       };
 
       logDir = mkOption {
         type = types.str;
         default = "/var/log";
-        description = "Directory to save wg-quick logs to.";
+        description = lib.mdDoc "Directory to save wg-quick logs to.";
       };
     };
   };
diff --git a/modules/services/yabai/default.nix b/modules/services/yabai/default.nix
index e40b416df..06ef289e5 100644
--- a/modules/services/yabai/default.nix
+++ b/modules/services/yabai/default.nix
@@ -22,19 +22,19 @@ in
     services.yabai.enable = mkOption {
       type = bool;
       default = false;
-      description = "Whether to enable the yabai window manager.";
+      description = lib.mdDoc "Whether to enable the yabai window manager.";
     };
 
     services.yabai.package = mkOption {
       type = path;
       default = pkgs.yabai;
-      description = "The yabai package to use.";
+      description = lib.mdDoc "The yabai package to use.";
     };
 
     services.yabai.enableScriptingAddition = mkOption {
       type = bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable yabai's scripting-addition.
         SIP must be disabled for this to work.
       '';
@@ -56,7 +56,7 @@ in
           window_gap          = 10;
         }
       '';
-      description = ''
+      description = lib.mdDoc ''
         Key/Value pairs to pass to yabai's 'config' domain, via the configuration file.
       '';
     };
@@ -67,7 +67,7 @@ in
       example = literalExpression ''
         yabai -m rule --add app='System Preferences' manage=off
       '';
-      description = "Extra arbitrary configuration to append to the configuration file";
+      description = lib.mdDoc "Extra arbitrary configuration to append to the configuration file";
     };
   };
 
diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix
index 8ade8ed5e..d5ca292b1 100644
--- a/modules/system/activation-scripts.nix
+++ b/modules/system/activation-scripts.nix
@@ -22,12 +22,12 @@ in
       internal = true;
       type = types.attrsOf (types.submodule script);
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         A set of shell script fragments that are executed when a NixOS
         system configuration is activated.  Examples are updating
         /etc, creating accounts, and so on.  Since these are executed
         every time you boot the system or run
-        nixos-rebuild, it's important that they are
+        {command}`nixos-rebuild`, it's important that they are
         idempotent and fast.
       '';
     };
diff --git a/modules/system/checks.nix b/modules/system/checks.nix
index fa4b3ad52..b1571abba 100644
--- a/modules/system/checks.nix
+++ b/modules/system/checks.nix
@@ -202,19 +202,19 @@ in
     system.checks.verifyNixPath = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to run the NIX_PATH validation checks.";
+      description = lib.mdDoc "Whether to run the NIX_PATH validation checks.";
     };
 
     system.checks.verifyNixChannels = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to run the nix-channels validation checks.";
+      description = lib.mdDoc "Whether to run the nix-channels validation checks.";
     };
 
     system.checks.verifyBuildUsers = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to run the Nix build users validation checks.";
+      description = lib.mdDoc "Whether to run the Nix build users validation checks.";
     };
 
     system.checks.text = mkOption {
diff --git a/modules/system/default.nix b/modules/system/default.nix
index 629760c0e..58369a8b7 100644
--- a/modules/system/default.nix
+++ b/modules/system/default.nix
@@ -22,7 +22,7 @@ in
       internal = true;
       type = types.attrsOf types.unspecified;
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         Attribute set of derivation used to setup the system.
       '';
     };
@@ -30,7 +30,7 @@ in
     system.path = mkOption {
       internal = true;
       type = types.package;
-      description = ''
+      description = lib.mdDoc ''
         The packages you want in the system environment.
       '';
     };
@@ -38,7 +38,7 @@ in
     system.profile = mkOption {
       type = types.path;
       default = "/nix/var/nix/profiles/system";
-      description = ''
+      description = lib.mdDoc ''
         Profile to use for the system.
       '';
     };
@@ -48,7 +48,7 @@ in
       internal = true;
       default = [];
       example = [ { assertion = false; message = "you can't enable this for that reason"; } ];
-      description = ''
+      description = lib.mdDoc ''
         This option allows modules to express conditions that must
         hold for the evaluation of the system configuration to
         succeed, along with associated error messages for the user.
@@ -60,7 +60,7 @@ in
       default = [];
       type = types.listOf types.str;
       example = [ "The `foo' service is deprecated and will go away soon!" ];
-      description = ''
+      description = lib.mdDoc ''
         This option allows modules to show warnings to users during
         the evaluation of the system configuration.
       '';
diff --git a/modules/system/defaults/ActivityMonitor.nix b/modules/system/defaults/ActivityMonitor.nix
index 270c67885..9f4617cbe 100644
--- a/modules/system/defaults/ActivityMonitor.nix
+++ b/modules/system/defaults/ActivityMonitor.nix
@@ -39,7 +39,7 @@ with lib;
     system.defaults.ActivityMonitor.SortColumn = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           Which column to sort the main activity page (such as "CPUUsage"). Default is null.
         '';
     };
@@ -47,7 +47,7 @@ with lib;
     system.defaults.ActivityMonitor.SortDirection = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           The sort direction of the sort column (0 is decending). Default is null.
         '';
     };
@@ -55,7 +55,7 @@ with lib;
     system.defaults.ActivityMonitor.OpenMainWindow = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           Open the main window when opening Activity Monitor. Default is true.
         '';
     };
diff --git a/modules/system/defaults/CustomPreferences.nix b/modules/system/defaults/CustomPreferences.nix
index 1b4b99b19..134c8d025 100644
--- a/modules/system/defaults/CustomPreferences.nix
+++ b/modules/system/defaults/CustomPreferences.nix
@@ -14,7 +14,7 @@ with lib;
             true;
         };
       };
-      description = ''
+      description = lib.mdDoc ''
         Sets custom user preferences
       '';
     };
@@ -29,7 +29,7 @@ with lib;
             true;
         };
       };
-      description = ''
+      description = lib.mdDoc ''
         Sets custom system preferences
       '';
     };
diff --git a/modules/system/defaults/GlobalPreferences.nix b/modules/system/defaults/GlobalPreferences.nix
index 5cce41969..e6964aad6 100644
--- a/modules/system/defaults/GlobalPreferences.nix
+++ b/modules/system/defaults/GlobalPreferences.nix
@@ -19,7 +19,7 @@ in {
       mkOption {
         type = types.nullOr (types.path);
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           Sets the system-wide alert sound. Found under "Sound Effects" in the
           "Sound" section of "System Preferences". Look in
           "/System/Library/Sounds" for possible candidates.
@@ -30,7 +30,7 @@ in {
       mkOption {
         type = types.nullOr float;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           Sets the mouse tracking speed. Found in the "Mouse" section of
           "System Preferences". Set to -1 to disable mouse acceleration.
         '';
diff --git a/modules/system/defaults/LaunchServices.nix b/modules/system/defaults/LaunchServices.nix
index d9ffcdaff..b76231f4e 100644
--- a/modules/system/defaults/LaunchServices.nix
+++ b/modules/system/defaults/LaunchServices.nix
@@ -8,7 +8,7 @@ with lib;
     system.defaults.LaunchServices.LSQuarantine = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable quarantine for downloaded applications.  The default is true.
       '';
     };
diff --git a/modules/system/defaults/NSGlobalDomain.nix b/modules/system/defaults/NSGlobalDomain.nix
index a23737e95..4f08d4ade 100644
--- a/modules/system/defaults/NSGlobalDomain.nix
+++ b/modules/system/defaults/NSGlobalDomain.nix
@@ -11,7 +11,7 @@ in {
     system.defaults.NSGlobalDomain.AppleShowAllFiles = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to always show hidden files. The default is false.
       '';
     };
@@ -19,7 +19,7 @@ in {
     system.defaults.NSGlobalDomain.AppleEnableMouseSwipeNavigateWithScrolls = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Enables swiping left or right with two fingers to navigate backward or forward. The default is true.
       '';
     };
@@ -27,7 +27,7 @@ in {
     system.defaults.NSGlobalDomain.AppleEnableSwipeNavigateWithScrolls = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Enables swiping left or right with two fingers to navigate backward or forward. The default is true.
       '';
     };
@@ -35,7 +35,7 @@ in {
     system.defaults.NSGlobalDomain.AppleFontSmoothing = mkOption {
       type = types.nullOr (types.enum [ 0 1 2 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Sets the level of font smoothing (sub-pixel font rendering).
       '';
     };
@@ -43,7 +43,7 @@ in {
     system.defaults.NSGlobalDomain.AppleInterfaceStyle = mkOption {
       type = types.nullOr (types.enum [ "Dark" ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Set to 'Dark' to enable dark mode, or leave unset for normal mode.
       '';
     };
@@ -51,7 +51,7 @@ in {
     system.defaults.NSGlobalDomain.AppleInterfaceStyleSwitchesAutomatically = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to automatically switch between light and dark mode. The default is false.
       '';
     };
@@ -59,7 +59,7 @@ in {
     system.defaults.NSGlobalDomain.AppleKeyboardUIMode = mkOption {
       type = types.nullOr (types.enum [ 3 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Configures the keyboard control behavior.  Mode 3 enables full keyboard control.
       '';
     };
@@ -67,7 +67,7 @@ in {
     system.defaults.NSGlobalDomain.ApplePressAndHoldEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable the press-and-hold feature.  The default is true.
       '';
     };
@@ -75,7 +75,7 @@ in {
     system.defaults.NSGlobalDomain.AppleShowAllExtensions = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to show all file extensions in Finder. The default is false.
       '';
     };
@@ -83,7 +83,7 @@ in {
     system.defaults.NSGlobalDomain.AppleShowScrollBars = mkOption {
       type = types.nullOr (types.enum [ "WhenScrolling" "Automatic" "Always" ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         When to show the scrollbars. Options are 'WhenScrolling', 'Automatic' and 'Always'.
       '';
     };
@@ -91,7 +91,7 @@ in {
     system.defaults.NSGlobalDomain.AppleScrollerPagingBehavior = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Jump to the spot that's clicked on the scroll bar. The default is false.
       '';
     };
@@ -99,7 +99,7 @@ in {
     system.defaults.NSGlobalDomain.NSAutomaticCapitalizationEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable automatic capitalization.  The default is true.
       '';
     };
@@ -107,7 +107,7 @@ in {
     system.defaults.NSGlobalDomain.NSAutomaticDashSubstitutionEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable smart dash substitution.  The default is true.
       '';
     };
@@ -115,7 +115,7 @@ in {
     system.defaults.NSGlobalDomain.NSAutomaticPeriodSubstitutionEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable smart period substitution.  The default is true.
       '';
     };
@@ -123,7 +123,7 @@ in {
     system.defaults.NSGlobalDomain.NSAutomaticQuoteSubstitutionEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable smart quote substitution.  The default is true.
       '';
     };
@@ -131,7 +131,7 @@ in {
     system.defaults.NSGlobalDomain.NSAutomaticSpellingCorrectionEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable automatic spelling correction.  The default is true.
       '';
     };
@@ -139,7 +139,7 @@ in {
     system.defaults.NSGlobalDomain.NSAutomaticWindowAnimationsEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to animate opening and closing of windows and popovers.  The default is true.
       '';
     };
@@ -147,7 +147,7 @@ in {
     system.defaults.NSGlobalDomain.NSDisableAutomaticTermination = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to disable the automatic termination of inactive apps.
       '';
     };
@@ -155,7 +155,7 @@ in {
     system.defaults.NSGlobalDomain.NSDocumentSaveNewDocumentsToCloud = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to save new documents to iCloud by default.  The default is true.
       '';
     };
@@ -163,7 +163,7 @@ in {
     system.defaults.NSGlobalDomain.AppleWindowTabbingMode = mkOption {
       type = types.nullOr (types.enum [ "manual" "always" "fullscreen" ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Sets the window tabbing when opening a new document: 'manual', 'always', or 'fullscreen'.  The default is 'fullscreen'.
       '';
     };
@@ -171,7 +171,7 @@ in {
     system.defaults.NSGlobalDomain.NSNavPanelExpandedStateForSaveMode = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use expanded save panel by default.  The default is false.
       '';
     };
@@ -179,7 +179,7 @@ in {
     system.defaults.NSGlobalDomain.NSNavPanelExpandedStateForSaveMode2 = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use expanded save panel by default.  The default is false.
       '';
     };
@@ -187,7 +187,7 @@ in {
     system.defaults.NSGlobalDomain.NSTableViewDefaultSizeMode = mkOption {
       type = types.nullOr (types.enum [ 1 2 3 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Sets the size of the finder sidebar icons: 1 (small), 2 (medium) or 3 (large). The default is 3.
       '';
     };
@@ -195,7 +195,7 @@ in {
     system.defaults.NSGlobalDomain.NSTextShowsControlCharacters = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to display ASCII control characters using caret notation in standard text views. The default is false.
       '';
     };
@@ -203,7 +203,7 @@ in {
     system.defaults.NSGlobalDomain.NSUseAnimatedFocusRing = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable the focus ring animation. The default is true.
       '';
     };
@@ -211,7 +211,7 @@ in {
     system.defaults.NSGlobalDomain.NSScrollAnimationEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable smooth scrolling. The default is true.
       '';
     };
@@ -220,7 +220,7 @@ in {
       type = types.nullOr floatWithDeprecationError;
       default = null;
       example = 0.20;
-      description = ''
+      description = lib.mdDoc ''
         Sets the speed speed of window resizing. The default is given in the example.
       '';
     };
@@ -228,7 +228,7 @@ in {
     system.defaults.NSGlobalDomain.InitialKeyRepeat = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Keyboard
 
         If you press and hold certain keyboard keys when in a text area, the key’s character begins to repeat.
@@ -241,7 +241,7 @@ in {
     system.defaults.NSGlobalDomain.KeyRepeat = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Keyboard
 
         If you press and hold certain keyboard keys when in a text area, the key’s character begins to repeat.
@@ -254,7 +254,7 @@ in {
     system.defaults.NSGlobalDomain.PMPrintingExpandedStateForPrint = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use the expanded print panel by default. The default is false.
       '';
     };
@@ -262,7 +262,7 @@ in {
     system.defaults.NSGlobalDomain.PMPrintingExpandedStateForPrint2 = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use the expanded print panel by default. The default is false.
       '';
     };
@@ -270,7 +270,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.keyboard.fnState" = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Use F1, F2, etc. keys as standard function keys.
       '';
     };
@@ -278,7 +278,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.mouse.tapBehavior" = mkOption {
       type = types.nullOr (types.enum [ 1 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Configures the trackpad tap behavior.  Mode 1 enables tap to click.
       '';
     };
@@ -286,7 +286,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.sound.beep.volume" = mkOption {
       type = types.nullOr floatWithDeprecationError;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Sound
 
         Sets the beep/alert volume level from 0.000 (muted) to 1.000 (100% volume).
@@ -302,7 +302,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.sound.beep.feedback" = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Sound
 
         Make a feedback sound when the system volume changed. This setting accepts
@@ -313,7 +313,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.trackpad.enableSecondaryClick" = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable trackpad secondary click.  The default is true.
       '';
     };
@@ -321,7 +321,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.trackpad.trackpadCornerClickBehavior" = mkOption {
       type = types.nullOr (types.enum [ 1 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Configures the trackpad corner click behavior.  Mode 1 enables right click.
       '';
     };
@@ -329,7 +329,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.trackpad.scaling" = mkOption {
       type = types.nullOr floatWithDeprecationError;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Configures the trackpad tracking speed (0 to 3).  The default is "1".
       '';
     };
@@ -337,7 +337,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.springing.enabled" = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable spring loading (expose) for directories.
       '';
     };
@@ -346,7 +346,7 @@ in {
       type = types.nullOr floatWithDeprecationError;
       default = null;
       example = 1.0;
-      description = ''
+      description = lib.mdDoc ''
         Set the spring loading delay for directories. The default is given in the example.
       '';
     };
@@ -354,7 +354,7 @@ in {
     system.defaults.NSGlobalDomain."com.apple.swipescrolldirection" = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable "Natural" scrolling direction.  The default is true.
       '';
     };
@@ -362,7 +362,7 @@ in {
     system.defaults.NSGlobalDomain.AppleMeasurementUnits = mkOption {
       type = types.nullOr (types.enum [ "Centimeters" "Inches" ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use centimeters (metric) or inches (US, UK) as the measurement unit.  The default is based on region settings.
       '';
     };
@@ -370,7 +370,7 @@ in {
     system.defaults.NSGlobalDomain.AppleMetricUnits = mkOption {
       type = types.nullOr (types.enum [ 0 1 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use the metric system.  The default is based on region settings.
       '';
     };
@@ -378,7 +378,7 @@ in {
     system.defaults.NSGlobalDomain.AppleTemperatureUnit = mkOption {
       type = types.nullOr (types.enum [ "Celsius" "Fahrenheit" ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use Celsius or Fahrenheit.  The default is based on region settings.
       '';
     };
@@ -386,7 +386,7 @@ in {
     system.defaults.NSGlobalDomain.AppleICUForce24HourTime = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to use 24-hour or 12-hour time.  The default is based on region settings.
       '';
     };
@@ -394,7 +394,7 @@ in {
     system.defaults.NSGlobalDomain._HIHideMenuBar = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to autohide the menu bar.  The default is false.
       '';
     };
diff --git a/modules/system/defaults/SoftwareUpdate.nix b/modules/system/defaults/SoftwareUpdate.nix
index ec89bce56..2882e8c63 100644
--- a/modules/system/defaults/SoftwareUpdate.nix
+++ b/modules/system/defaults/SoftwareUpdate.nix
@@ -7,7 +7,7 @@ with lib;
     system.defaults.SoftwareUpdate.AutomaticallyInstallMacOSUpdates = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Automatically install Mac OS software updates. Defaults to false.
       '';
     };
diff --git a/modules/system/defaults/alf.nix b/modules/system/defaults/alf.nix
index 96a980646..6b82eca0f 100644
--- a/modules/system/defaults/alf.nix
+++ b/modules/system/defaults/alf.nix
@@ -7,7 +7,7 @@ with lib;
     system.defaults.alf.globalstate = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Security and Privacy > Firewall
 
         Enable the internal firewall to prevent unauthorised applications, programs
@@ -22,7 +22,7 @@ with lib;
     system.defaults.alf.allowsignedenabled = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Security and Privacy > Firewall
 
         Allows any signed Application to accept incoming requests. Default is true.
@@ -35,7 +35,7 @@ with lib;
     system.defaults.alf.allowdownloadsignedenabled = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Security and Privacy > Firewall
 
         Allows any downloaded Application that has been signed to accept incoming requests. Default is 0.
@@ -48,7 +48,7 @@ with lib;
     system.defaults.alf.loggingenabled = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Security and Privacy > Firewall
 
         Enable logging of requests made to the firewall. Default is 0.
@@ -61,7 +61,7 @@ with lib;
     system.defaults.alf.stealthenabled = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Security and firewall
 
         Drops incoming requests via ICMP such as ping requests. Default is 0.
diff --git a/modules/system/defaults/clock.nix b/modules/system/defaults/clock.nix
index ef2cac48a..cd5c0e847 100644
--- a/modules/system/defaults/clock.nix
+++ b/modules/system/defaults/clock.nix
@@ -8,7 +8,7 @@ with lib;
     system.defaults.menuExtraClock.IsAnalog = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show an analog clock instead of a digital one. Default is null.
       '';
     };
@@ -16,7 +16,7 @@ with lib;
     system.defaults.menuExtraClock.Show24Hour = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show a 24-hour clock, instead of a 12-hour clock. Default is null.
       '';
     };
@@ -24,7 +24,7 @@ with lib;
     system.defaults.menuExtraClock.ShowAMPM = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show the AM/PM label. Useful if Show24Hour is false. Default is null.
       '';
     };
@@ -32,7 +32,7 @@ with lib;
     system.defaults.menuExtraClock.ShowDayOfMonth = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show the day of the month. Default is null.
       '';
     };
@@ -40,7 +40,7 @@ with lib;
     system.defaults.menuExtraClock.ShowDayOfWeek = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show the day of the week. Default is null.
       '';
     };
@@ -48,7 +48,7 @@ with lib;
     system.defaults.menuExtraClock.ShowDate = mkOption {
       type = types.nullOr (types.enum [ 0 1 2 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show the full date. Default is null.
 
         0 = Show the date
@@ -62,7 +62,7 @@ with lib;
     system.defaults.menuExtraClock.ShowSeconds = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show the clock with second precision, instead of minutes. Default is null.
       '';
     };
diff --git a/modules/system/defaults/dock.nix b/modules/system/defaults/dock.nix
index 82c8befbd..34fc85799 100644
--- a/modules/system/defaults/dock.nix
+++ b/modules/system/defaults/dock.nix
@@ -11,7 +11,7 @@ in {
     system.defaults.dock.appswitcher-all-displays = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to display the appswitcher on all displays or only the main one. The default is false.
       '';
     };
@@ -19,7 +19,7 @@ in {
     system.defaults.dock.autohide = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to automatically hide and show the dock.  The default is false.
       '';
     };
@@ -28,7 +28,7 @@ in {
       type = types.nullOr floatWithDeprecationError;
       default = null;
       example = 0.24;
-      description = ''
+      description = lib.mdDoc ''
         Sets the speed of the autohide delay. The default is given in the example.
       '';
     };
@@ -37,7 +37,7 @@ in {
       type = types.nullOr floatWithDeprecationError;
       default = null;
       example = 1.0;
-      description = ''
+      description = lib.mdDoc ''
         Sets the speed of the animation when hiding/showing the Dock. The default is given in the example.
       '';
     };
@@ -45,7 +45,7 @@ in {
     system.defaults.dock.dashboard-in-overlay = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to hide Dashboard as a Space. The default is false.
       '';
     };
@@ -53,7 +53,7 @@ in {
     system.defaults.dock.enable-spring-load-actions-on-all-items = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Enable spring loading for all Dock items. The default is false.
       '';
     };
@@ -62,7 +62,7 @@ in {
       type = types.nullOr floatWithDeprecationError;
       default = null;
       example = 1.0;
-      description = ''
+      description = lib.mdDoc ''
         Sets the speed of the Mission Control animations. The default is given in the example.
       '';
     };
@@ -70,7 +70,7 @@ in {
     system.defaults.dock.expose-group-by-app = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to group windows by application in Mission Control's Exposé. The default is true.
       '';
     };
@@ -78,7 +78,7 @@ in {
     system.defaults.dock.launchanim = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Animate opening applications from the Dock. The default is true.
       '';
     };
@@ -86,7 +86,7 @@ in {
     system.defaults.dock.mineffect = mkOption {
       type = types.nullOr (types.enum [ "genie" "suck" "scale" ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Set the minimize/maximize window effect. The default is genie.
       '';
     };
@@ -94,7 +94,7 @@ in {
     system.defaults.dock.minimize-to-application = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to minimize windows into their application icon.  The default is false.
       '';
     };
@@ -102,7 +102,7 @@ in {
     system.defaults.dock.mouse-over-hilite-stack = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Enable highlight hover effect for the grid view of a stack in the Dock.
       '';
     };
@@ -110,7 +110,7 @@ in {
     system.defaults.dock.mru-spaces = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to automatically rearrange spaces based on most recent use.  The default is true.
       '';
     };
@@ -118,7 +118,7 @@ in {
     system.defaults.dock.orientation = mkOption {
       type = types.nullOr (types.enum [ "bottom" "left" "right" ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Position of the dock on screen.  The default is "bottom".
       '';
     };
@@ -126,7 +126,7 @@ in {
     system.defaults.dock.show-process-indicators = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show indicator lights for open applications in the Dock. The default is true.
       '';
     };
@@ -134,7 +134,7 @@ in {
     system.defaults.dock.showhidden = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to make icons of hidden applications tranclucent.  The default is false.
       '';
     };
@@ -142,7 +142,7 @@ in {
     system.defaults.dock.show-recents = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show recent applications in the dock. The default is true.
       '';
     };
@@ -150,7 +150,7 @@ in {
     system.defaults.dock.static-only = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show only open applications in the Dock. The default is false.
       '';
     };
@@ -158,7 +158,7 @@ in {
     system.defaults.dock.tilesize = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Size of the icons in the dock.  The default is 64.
       '';
     };
diff --git a/modules/system/defaults/finder.nix b/modules/system/defaults/finder.nix
index a4bfd2107..422e888cf 100644
--- a/modules/system/defaults/finder.nix
+++ b/modules/system/defaults/finder.nix
@@ -8,7 +8,7 @@ with lib;
     system.defaults.finder.AppleShowAllFiles = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to always show hidden files. The default is false.
       '';
     };
@@ -16,7 +16,7 @@ with lib;
     system.defaults.finder.ShowStatusBar = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show status bar at bottom of finder windows with item/disk space stats. The default is false.
       '';
     };
@@ -24,7 +24,7 @@ with lib;
     system.defaults.finder.ShowPathbar = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Show path breadcrumbs in finder windows. The default is false.
       '';
     };
@@ -32,7 +32,7 @@ with lib;
     system.defaults.finder.FXDefaultSearchScope = mkOption {
       type = types.nullOr types.string;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Change the default search scope. Use "SCcf" to default to current folder.
         The default is unset ("This Mac").
       '';
@@ -41,7 +41,7 @@ with lib;
     system.defaults.finder.FXPreferredViewStyle = mkOption {
       type = types.nullOr types.string;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Change the default finder view.
         "icnv" = Icon view, "Nlsv" = List view, "clmv" = Column View, "Flwv" = Gallery View
         The default is icnv.
@@ -51,7 +51,7 @@ with lib;
     system.defaults.finder.AppleShowAllExtensions = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to always show file extensions.  The default is false.
       '';
     };
@@ -59,7 +59,7 @@ with lib;
     system.defaults.finder.CreateDesktop = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to show icons on the desktop or not. The default is true.
       '';
     };
@@ -67,7 +67,7 @@ with lib;
     system.defaults.finder.QuitMenuItem = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to allow quitting of the Finder.  The default is false.
       '';
     };
@@ -75,7 +75,7 @@ with lib;
     system.defaults.finder._FXShowPosixPathInTitle = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to show the full POSIX filepath in the window title.  The default is false.
       '';
     };
@@ -83,7 +83,7 @@ with lib;
     system.defaults.finder.FXEnableExtensionChangeWarning = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to show warnings when change the file extension of files.  The default is true.
       '';
     };
diff --git a/modules/system/defaults/loginwindow.nix b/modules/system/defaults/loginwindow.nix
index 0fb709643..81f7dfa97 100644
--- a/modules/system/defaults/loginwindow.nix
+++ b/modules/system/defaults/loginwindow.nix
@@ -7,7 +7,7 @@ with lib;
     system.defaults.loginwindow.SHOWFULLNAME = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Displays login window as a name and password field instead of a list of users.
@@ -18,7 +18,7 @@ with lib;
     system.defaults.loginwindow.autoLoginUser = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Auto login the supplied user on boot. Default is Off.
@@ -28,7 +28,7 @@ with lib;
     system.defaults.loginwindow.GuestEnabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Allow users to login to the machine as guests using the Guest account. Default is true.
@@ -46,7 +46,7 @@ with lib;
     system.defaults.loginwindow.ShutDownDisabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Hides the Shut Down button on the login screen. Default is false.
@@ -56,7 +56,7 @@ with lib;
     system.defaults.loginwindow.SleepDisabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Hides the Sleep button on the login screen. Default is false.
@@ -66,7 +66,7 @@ with lib;
     system.defaults.loginwindow.RestartDisabled = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Hides the Restart button on the login screen. Default is false.
@@ -76,7 +76,7 @@ with lib;
     system.defaults.loginwindow.ShutDownDisabledWhileLoggedIn = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Disables the "Shutdown" option when users are logged in. Default is false.
@@ -86,7 +86,7 @@ with lib;
     system.defaults.loginwindow.PowerOffDisabledWhileLoggedIn = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         If set to true, the Power Off menu item will be disabled when the user is logged in. Default is false.
@@ -96,7 +96,7 @@ with lib;
     system.defaults.loginwindow.RestartDisabledWhileLoggedIn = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Users and Groups > Login Options
 
         Disables the “Restart” option when users are logged in. Default is false.
@@ -106,7 +106,7 @@ with lib;
     system.defaults.loginwindow.DisableConsoleAccess = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Disables the ability for a user to access the console by typing “>console”
         for a username at the login window. Default is false.
       '';
diff --git a/modules/system/defaults/magicmouse.nix b/modules/system/defaults/magicmouse.nix
index 9344ffeea..56d7f71c6 100644
--- a/modules/system/defaults/magicmouse.nix
+++ b/modules/system/defaults/magicmouse.nix
@@ -11,7 +11,7 @@ with lib;
         "TwoButton"
       ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         "OneButton": any tap is a left click.  "TwoButton": allow left-
         and right-clicking.
       '';
diff --git a/modules/system/defaults/screencapture.nix b/modules/system/defaults/screencapture.nix
index f7b926a94..4483fd630 100644
--- a/modules/system/defaults/screencapture.nix
+++ b/modules/system/defaults/screencapture.nix
@@ -8,7 +8,7 @@ with lib;
     system.defaults.screencapture.location = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           The filesystem path to which screencaptures should be written.
         '';
     };
@@ -16,7 +16,7 @@ with lib;
     system.defaults.screencapture.type = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           The image format to use, such as "jpg".
         '';
     };
@@ -24,7 +24,7 @@ with lib;
     system.defaults.screencapture.disable-shadow = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           Disable drop shadow border around screencaptures. The default is false.
         '';
     };
diff --git a/modules/system/defaults/screensaver.nix b/modules/system/defaults/screensaver.nix
index 3e5032b5c..68bd1e05e 100644
--- a/modules/system/defaults/screensaver.nix
+++ b/modules/system/defaults/screensaver.nix
@@ -8,7 +8,7 @@ with lib;
     system.defaults.screensaver.askForPassword = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           If true, the user is prompted for a password when the screen saver is unlocked or stopped. The default is false.
         '';
     };
@@ -16,7 +16,7 @@ with lib;
     system.defaults.screensaver.askForPasswordDelay = mkOption {
       type = types.nullOr types.int;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
           The number of seconds to delay before the password will be required to unlock or stop the screen saver (the grace period).
         '';
     };
diff --git a/modules/system/defaults/smb.nix b/modules/system/defaults/smb.nix
index 0bc8be550..b694059d9 100644
--- a/modules/system/defaults/smb.nix
+++ b/modules/system/defaults/smb.nix
@@ -7,13 +7,13 @@ with lib;
     system.defaults.smb.NetBIOSName = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = "Hostname to use for NetBIOS.";
+      description = lib.mdDoc "Hostname to use for NetBIOS.";
     };
 
     system.defaults.smb.ServerDescription = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = "Hostname to use for sharing services.";
+      description = lib.mdDoc "Hostname to use for sharing services.";
     };
   };
 }
diff --git a/modules/system/defaults/spaces.nix b/modules/system/defaults/spaces.nix
index ac2355bbb..4b535d1cf 100644
--- a/modules/system/defaults/spaces.nix
+++ b/modules/system/defaults/spaces.nix
@@ -7,7 +7,7 @@ with lib;
     system.defaults.spaces.spans-displays = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Apple menu > System Preferences > Mission Control
 
         Displays have separate Spaces (note a logout is required before
diff --git a/modules/system/defaults/trackpad.nix b/modules/system/defaults/trackpad.nix
index edb637543..ff5e2bb3c 100644
--- a/modules/system/defaults/trackpad.nix
+++ b/modules/system/defaults/trackpad.nix
@@ -8,7 +8,7 @@ with lib;
     system.defaults.trackpad.Clicking = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable trackpad tap to click.  The default is false.
       '';
     };
@@ -16,7 +16,7 @@ with lib;
     system.defaults.trackpad.Dragging = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable tap-to-drag. The default is false.
       '';
     };
@@ -24,7 +24,7 @@ with lib;
     system.defaults.trackpad.TrackpadRightClick = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable trackpad right click.  The default is false.
       '';
     };
@@ -32,7 +32,7 @@ with lib;
     system.defaults.trackpad.TrackpadThreeFingerDrag = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable three finger drag.  The default is false.
       '';
     };
@@ -40,7 +40,7 @@ with lib;
     system.defaults.trackpad.ActuationStrength = mkOption {
       type = types.nullOr (types.enum [ 0 1 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         0 to enable Silent Clicking, 1 to disable.  The default is 1.
       '';
     };
@@ -48,7 +48,7 @@ with lib;
     system.defaults.trackpad.FirstClickThreshold = mkOption {
       type = types.nullOr (types.enum [ 0 1 2 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         For normal click: 0 for light clicking, 1 for medium, 2 for firm.
         The default is 1.
       '';
@@ -57,7 +57,7 @@ with lib;
     system.defaults.trackpad.SecondClickThreshold = mkOption {
       type = types.nullOr (types.enum [ 0 1 2 ]);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         For force touch: 0 for light clicking, 1 for medium, 2 for firm.
         The default is 1.
       '';
diff --git a/modules/system/defaults/universalaccess.nix b/modules/system/defaults/universalaccess.nix
index bb4bec971..51a1fb7c3 100644
--- a/modules/system/defaults/universalaccess.nix
+++ b/modules/system/defaults/universalaccess.nix
@@ -9,7 +9,7 @@ with lib;
       type = types.nullOr types.float;
       default = null;
       example = 1.5;
-      description = ''
+      description = lib.mdDoc ''
         Set the size of cursor. 1 for normal, 4 for maximum.
         The default is 1.
       '';
@@ -18,7 +18,7 @@ with lib;
     system.defaults.universalaccess.reduceTransparency = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Disable transparency in the menu bar and elsewhere.
         Requires macOS Yosemite or later.
         The default is false.
@@ -28,7 +28,7 @@ with lib;
     system.defaults.universalaccess.closeViewScrollWheelToggle = mkOption {
       type = types.nullOr types.bool;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Use scroll gesture with the Ctrl (^) modifier key to zoom.
         The default is false.
       '';
diff --git a/modules/system/etc.nix b/modules/system/etc.nix
index 4b45e3a31..b6c5827ee 100644
--- a/modules/system/etc.nix
+++ b/modules/system/etc.nix
@@ -23,8 +23,8 @@ in
     environment.etc = mkOption {
       type = types.attrsOf (types.submodule text);
       default = { };
-      description = ''
-        Set of files that have to be linked in /etc.
+      description = lib.mdDoc ''
+        Set of files that have to be linked in {file}`/etc`.
       '';
     };
 
diff --git a/modules/system/keyboard.nix b/modules/system/keyboard.nix
index c637f0489..6e4275ed5 100644
--- a/modules/system/keyboard.nix
+++ b/modules/system/keyboard.nix
@@ -11,40 +11,40 @@ in
     system.keyboard.enableKeyMapping = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to enable keyboard mappings.";
+      description = lib.mdDoc "Whether to enable keyboard mappings.";
     };
 
     system.keyboard.remapCapsLockToControl = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to remap the Caps Lock key to Control.";
+      description = lib.mdDoc "Whether to remap the Caps Lock key to Control.";
     };
 
     system.keyboard.remapCapsLockToEscape = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to remap the Caps Lock key to Escape.";
+      description = lib.mdDoc "Whether to remap the Caps Lock key to Escape.";
     };
 
     system.keyboard.nonUS.remapTilde = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to remap the Tilde key on non-us keyboards.";
+      description = lib.mdDoc "Whether to remap the Tilde key on non-us keyboards.";
     };
 
     system.keyboard.swapLeftCommandAndLeftAlt = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to swap the left Command key and left Alt key.";
+      description = lib.mdDoc "Whether to swap the left Command key and left Alt key.";
     };
 
     system.keyboard.userKeyMapping = mkOption {
       internal = true;
       type = types.listOf (types.attrsOf types.int);
       default = [];
-      description = ''
+      description = lib.mdDoc ''
         List of keyboard mappings to apply, for more information see
-        .
+        .
       '';
     };
   };
diff --git a/modules/system/launchd.nix b/modules/system/launchd.nix
index e11c66399..7f6b4859a 100644
--- a/modules/system/launchd.nix
+++ b/modules/system/launchd.nix
@@ -59,24 +59,24 @@ in
     environment.launchAgents = mkOption {
       type = types.attrsOf (types.submodule text);
       default = { };
-      description = ''
-        Set of files that have to be linked in /Library/LaunchAgents.
+      description = lib.mdDoc ''
+        Set of files that have to be linked in {file}`/Library/LaunchAgents`.
       '';
     };
 
     environment.launchDaemons = mkOption {
       type = types.attrsOf (types.submodule text);
       default = { };
-      description = ''
-        Set of files that have to be linked in /Library/LaunchDaemons.
+      description = lib.mdDoc ''
+        Set of files that have to be linked in {file}`/Library/LaunchDaemons`.
       '';
     };
 
     environment.userLaunchAgents = mkOption {
       type = types.attrsOf (types.submodule text);
       default = { };
-      description = ''
-        Set of files that have to be linked in ~/Library/LaunchAgents.
+      description = lib.mdDoc ''
+        Set of files that have to be linked in {file}`~/Library/LaunchAgents`.
       '';
     };
 
diff --git a/modules/system/patches.nix b/modules/system/patches.nix
index 0b5668174..9ac15ecce 100644
--- a/modules/system/patches.nix
+++ b/modules/system/patches.nix
@@ -26,12 +26,14 @@ in
           '''')
         ]
       '';
-      description = ''
-        Set of patches to apply to /.
+      description = lib.mdDoc ''
+        Set of patches to apply to {file}`/`.
 
-        
+        ::: {.warning}
+        
         This can modify everything so use with caution.
-        
+        
+        :::
 
         Useful for safely changing system files.  Unlike the etc module this
         won't remove or modify files with unexpected content.
diff --git a/modules/system/shells.nix b/modules/system/shells.nix
index ac9d6197c..b3ecf30e4 100644
--- a/modules/system/shells.nix
+++ b/modules/system/shells.nix
@@ -12,9 +12,9 @@ in
       type = types.listOf (types.either types.shellPackage types.path);
       default = [];
       example = literalExpression "[ pkgs.bashInteractive pkgs.zsh ]";
-      description = ''
+      description = lib.mdDoc ''
         A list of permissible login shells for user accounts.
-        No need to mention /bin/sh
+        No need to mention `/bin/sh`
         and other shells that are available by default on
         macOS.
       '';
diff --git a/modules/system/version.nix b/modules/system/version.nix
index 7b9236d34..68019188e 100644
--- a/modules/system/version.nix
+++ b/modules/system/version.nix
@@ -35,7 +35,7 @@ in
     system.stateVersion = mkOption {
       type = types.int;
       default = 4;
-      description = ''
+      description = lib.mdDoc ''
         Every once in a while, a new NixOS release may change
         configuration defaults in a way incompatible with stateful
         data. For instance, if the default version of PostgreSQL
@@ -50,50 +50,50 @@ in
 
     system.darwinLabel = mkOption {
       type = types.str;
-      description = "Label to be used in the names of generated outputs.";
+      description = lib.mdDoc "Label to be used in the names of generated outputs.";
     };
 
     system.darwinVersion = mkOption {
       internal = true;
       type = types.str;
-      description = "The full darwin version (e.g. darwin4.master).";
+      description = lib.mdDoc "The full darwin version (e.g. `darwin4.master`).";
     };
 
     system.darwinVersionSuffix = mkOption {
       internal = true;
       type = types.str;
-      description = "The short darwin version suffix (e.g. .2abdb5a).";
+      description = lib.mdDoc "The short darwin version suffix (e.g. `.2abdb5a`).";
     };
 
     system.darwinRevision = mkOption {
       internal = true;
       type = types.str;
       default = "master";
-      description = "The darwin git revision from which this configuration was built.";
+      description = lib.mdDoc "The darwin git revision from which this configuration was built.";
     };
 
     system.nixpkgsRelease = mkOption {
       readOnly = true;
       type = types.str;
-      description = "The nixpkgs release (e.g. 16.03).";
+      description = lib.mdDoc "The nixpkgs release (e.g. `16.03`).";
     };
 
     system.nixpkgsVersion = mkOption {
       internal = true;
       type = types.str;
-      description = "The full nixpkgs version (e.g. 16.03.1160.f2d4ee1).";
+      description = lib.mdDoc "The full nixpkgs version (e.g. `16.03.1160.f2d4ee1`).";
     };
 
     system.nixpkgsVersionSuffix = mkOption {
       internal = true;
       type = types.str;
-      description = "The short nixpkgs version suffix (e.g. .1160.f2d4ee1).";
+      description = lib.mdDoc "The short nixpkgs version suffix (e.g. `.1160.f2d4ee1`).";
     };
 
     system.nixpkgsRevision = mkOption {
       internal = true;
       type = types.str;
-      description = "The nixpkgs git revision from which this configuration was built.";
+      description = lib.mdDoc "The nixpkgs git revision from which this configuration was built.";
     };
   };
 
diff --git a/modules/time/default.nix b/modules/time/default.nix
index 7cbe6bb06..09b02a55f 100644
--- a/modules/time/default.nix
+++ b/modules/time/default.nix
@@ -23,10 +23,9 @@ in
       type = types.nullOr types.str;
       default = null;
       example = "America/New_York";
-      description = ''
-        The time zone used when displaying times and dates. See 
-        or run sudo systemsetup -listtimezones
+      description = lib.mdDoc ''
+        The time zone used when displaying times and dates. See 
+        or run {command}`sudo systemsetup -listtimezones`
         for a comprehensive list of possible values for this setting.
       '';
     };
diff --git a/modules/users/default.nix b/modules/users/default.nix
index bb075ec45..571200248 100644
--- a/modules/users/default.nix
+++ b/modules/users/default.nix
@@ -31,7 +31,7 @@ in
     users.knownGroups = mkOption {
       type = types.listOf types.str;
       default = [];
-      description = ''
+      description = lib.mdDoc ''
         List of groups owned and managed by nix-darwin. Used to indicate
         what users are safe to create/delete based on the configuration.
         Don't add system groups to this.
@@ -41,7 +41,7 @@ in
     users.knownUsers = mkOption {
       type = types.listOf types.str;
       default = [];
-      description = ''
+      description = lib.mdDoc ''
         List of users owned and managed by nix-darwin. Used to indicate
         what users are safe to create/delete based on the configuration.
         Don't add the admin user or other system users to this.
@@ -51,13 +51,13 @@ in
     users.groups = mkOption {
       type = types.attrsOf (types.submodule group);
       default = {};
-      description = "Configuration for groups.";
+      description = lib.mdDoc "Configuration for groups.";
     };
 
     users.users = mkOption {
       type = types.attrsOf (types.submodule user);
       default = {};
-      description = "Configuration for users.";
+      description = lib.mdDoc "Configuration for users.";
     };
 
     users.gids = mkOption {
@@ -76,7 +76,7 @@ in
       internal = true;
       type = types.bool;
       default = false;
-      description = "Remove and recreate existing groups/users.";
+      description = lib.mdDoc "Remove and recreate existing groups/users.";
     };
   };
 
diff --git a/modules/users/group.nix b/modules/users/group.nix
index 1dc26f1f6..cfda76f34 100644
--- a/modules/users/group.nix
+++ b/modules/users/group.nix
@@ -6,7 +6,7 @@ with lib;
   options = {
     name = mkOption {
       type = types.str;
-      description = ''
+      description = lib.mdDoc ''
         The group's name. If undefined, the name of the attribute set
         will be used.
       '';
@@ -17,19 +17,19 @@ with lib;
         name = "gid";
         check = t: isInt t && t > 501;
       };
-      description = "The group's GID.";
+      description = lib.mdDoc "The group's GID.";
     };
 
     members = mkOption {
       type = types.listOf types.str;
       default = [];
-      description = "The group's members.";
+      description = lib.mdDoc "The group's members.";
     };
 
     description = mkOption {
       type = types.str;
       default = "";
-      description = "The group's description.";
+      description = lib.mdDoc "The group's description.";
     };
   };
 
diff --git a/modules/users/user.nix b/modules/users/user.nix
index 4060a65a3..60592fc4d 100644
--- a/modules/users/user.nix
+++ b/modules/users/user.nix
@@ -6,7 +6,7 @@ with lib;
   options = {
     name = mkOption {
       type = types.str;
-      description = ''
+      description = lib.mdDoc ''
         The name of the user account. If undefined, the name of the
         attribute set will be used.
       '';
@@ -16,7 +16,7 @@ with lib;
       type = types.str;
       default = "";
       example = "Alice Q. User";
-      description = ''
+      description = lib.mdDoc ''
         A short description of the user account, typically the
         user's full name.
       '';
@@ -24,19 +24,19 @@ with lib;
 
     uid = mkOption {
       type = types.int;
-      description = "The user's UID.";
+      description = lib.mdDoc "The user's UID.";
     };
 
     gid = mkOption {
       type = types.int;
       default = 20;
-      description = "The user's primary group.";
+      description = lib.mdDoc "The user's primary group.";
     };
 
     isHidden = mkOption {
       type = types.bool;
       default = true;
-      description = "Whether to make the user account hidden.";
+      description = lib.mdDoc "Whether to make the user account hidden.";
     };
 
     # extraGroups = mkOption {
@@ -48,29 +48,29 @@ with lib;
     home = mkOption {
       type = types.path;
       default = "/var/empty";
-      description = "The user's home directory.";
+      description = lib.mdDoc "The user's home directory.";
     };
 
     createHome = mkOption {
       type = types.bool;
       default = false;
-      description = "Create the home directory when creating the user.";
+      description = lib.mdDoc "Create the home directory when creating the user.";
     };
 
     shell = mkOption {
       type = types.either types.shellPackage types.path;
       default = "/sbin/nologin";
       example = literalExpression "pkgs.bashInteractive";
-      description = "The user's shell.";
+      description = lib.mdDoc "The user's shell.";
     };
 
     packages = mkOption {
       type = types.listOf types.package;
       default = [];
       example = literalExpression "[ pkgs.firefox pkgs.thunderbird ]";
-      description = ''
+      description = lib.mdDoc ''
         The set of packages that should be made availabe to the user.
-        This is in contrast to ,
+        This is in contrast to {option}`environment.systemPackages`,
         which adds packages to all users.
       '';
     };

From 2903ceabb5ffe0968199bf3db80a9c6dd1d3d6de Mon Sep 17 00:00:00 2001
From: Emily 
Date: Thu, 22 Jun 2023 13:05:45 +0100
Subject: [PATCH 060/161] doc/manual: remove `optionsDocBook` export

---
 doc/manual/default.nix | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/doc/manual/default.nix b/doc/manual/default.nix
index 3a5152eb6..2ebd51446 100644
--- a/doc/manual/default.nix
+++ b/doc/manual/default.nix
@@ -194,9 +194,6 @@ in rec {
           "$out/share/doc/darwin"
     '';
 
-  # Temporary export for Markdown conversion.
-  inherit (optionsDoc) optionsDocBook;
-
   # Generate the NixOS manual.
   manualHTML = runCommand "darwin-manual-html"
     { inherit sources;

From d37abf456b50b6252d1ca995b20a7add8c28cce6 Mon Sep 17 00:00:00 2001
From: Emily 
Date: Thu, 22 Jun 2023 13:06:04 +0100
Subject: [PATCH 061/161] flake.nix: remove the nixpkgs pin

The Markdown transition is over and our compatibility with
`nixpkgs-unstable` is restored.
---
 flake.lock | 12 +++++-------
 flake.nix  |  3 ---
 2 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/flake.lock b/flake.lock
index 61540b7e2..719cfe68b 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,16 +2,14 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1687130670,
-        "narHash": "sha256-VKTdfsJe7sVTTqxTd3eRGPoUgEeJKD+kwS86B6TY874=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "c1bca7fe84c646cfd4ebf3482c0e6317a0b13f22",
-        "type": "github"
+        "lastModified": 1687274257,
+        "narHash": "sha256-TutzPriQcZ8FghDhEolnHcYU2oHIG5XWF+/SUBNnAOE=",
+        "path": "/nix/store/22qgs3skscd9bmrxv9xv4q5d4wwm5ppx-source",
+        "rev": "2c9ecd1f0400076a4d6b2193ad468ff0a7e7fdc5",
+        "type": "path"
       },
       "original": {
         "id": "nixpkgs",
-        "rev": "c1bca7fe84c646cfd4ebf3482c0e6317a0b13f22",
         "type": "indirect"
       }
     },
diff --git a/flake.nix b/flake.nix
index 5c95ac790..38056aea6 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2,9 +2,6 @@
   # WARNING this is very much still experimental.
   description = "A collection of darwin modules";
 
-  # Temporary pin for Markdown documentation transition.
-  inputs.nixpkgs.url = "nixpkgs/c1bca7fe84c646cfd4ebf3482c0e6317a0b13f22";
-
   outputs = { self, nixpkgs }: {
     lib = {
       # TODO handle multiple architectures.

From 69648c6cbbecf34c327d73e36b5aed32edfb9ed9 Mon Sep 17 00:00:00 2001
From: Emily 
Date: Sat, 24 Jun 2023 05:09:22 +0100
Subject: [PATCH 062/161] doc/manual: use `nixos-render-docs`

Now that all the DocBook documentation is gone, we can switch to the
new NixOS documentation generator. No meaningful change in HTML output,
except that I removed the rather pointless preface and changed the
title accordingly. Manual page output is greatly improved; it was
kind of broken before. The `sed` hack is pretty gross but I have
confirmed that nixpkgs will be happy to accept a PR to make things
a little more customizable.

This also drops the `manual` alias (deprecated in nixpkgs in 2018
and imported into nix-darwin), and `manualEpub` (because the NixOS
documentation generator doesn't support it and also nobody wants this
as an ebook).
---
 doc/manual/default.nix            | 261 ++++++---------------------
 doc/manual/man-pages.xml          |  42 -----
 doc/manual/manual.md              |   8 +
 doc/manual/manual.xml             |  21 ---
 doc/manual/overrides.css          |   9 -
 doc/manual/style.css              | 291 ------------------------------
 modules/documentation/default.nix |   1 -
 release.nix                       |   1 -
 8 files changed, 66 insertions(+), 568 deletions(-)
 delete mode 100644 doc/manual/man-pages.xml
 create mode 100644 doc/manual/manual.md
 delete mode 100644 doc/manual/manual.xml
 delete mode 100644 doc/manual/overrides.css
 delete mode 100644 doc/manual/style.css

diff --git a/doc/manual/default.nix b/doc/manual/default.nix
index 2ebd51446..2225b5155 100644
--- a/doc/manual/default.nix
+++ b/doc/manual/default.nix
@@ -40,145 +40,7 @@ let
     };
   };
 
-  sources = lib.sourceFilesBySuffices ./. [".xml"];
-
-  modulesDoc = builtins.toFile "modules.xml" ''
-    
- ${(lib.concatMapStrings (path: '' - - '') (lib.catAttrs "value" (config.meta.doc or [])))} -
- ''; - - generatedSources = runCommand "generated-docbook" {} '' - mkdir $out - ln -s ${modulesDoc} $out/modules.xml - ln -s ${optionsDoc.optionsDocBook} $out/options-db.xml - printf "%s" "${version}" > $out/version - ''; - - copySources = - '' - cp -prd $sources/* . || true - ln -s ${generatedSources} ./generated - chmod -R u+w . - ''; - - toc = builtins.toFile "toc.xml" - '' - - - - - - - ''; - - manualXsltprocOptions = toString [ - "--param section.autolabel 1" - "--param section.label.includes.component.label 1" - "--stringparam html.stylesheet 'style.css overrides.css highlightjs/mono-blue.css'" - "--stringparam html.script './highlightjs/highlight.pack.js ./highlightjs/loader.js'" - "--param xref.with.number.and.title 1" - "--param toc.section.depth 3" - "--stringparam admon.style ''" - "--stringparam callout.graphics.extension .svg" - "--stringparam current.docid manual" - "--param chunk.section.depth 0" - "--param chunk.first.sections 1" - "--param use.id.as.filename 1" - "--stringparam generate.toc 'book toc appendix toc'" - "--stringparam chunk.toc ${toc}" - ]; - - manual-combined = runCommand "darwin-manual-combined" - { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; - meta.description = "The NixOS manual as plain docbook XML"; - } - '' - ${copySources} - - xmllint --xinclude --output ./manual-combined.xml ./manual.xml - xmllint --xinclude --noxincludenode \ - --output ./man-pages-combined.xml ./man-pages.xml - - # outputs the context of an xmllint error output - # LEN lines around the failing line are printed - function context { - # length of context - local LEN=6 - # lines to print before error line - local BEFORE=4 - - # xmllint output lines are: - # file.xml:1234: there was an error on line 1234 - while IFS=':' read -r file line rest; do - echo - if [[ -n "$rest" ]]; then - echo "$file:$line:$rest" - local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1)) - # number lines & filter context - nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p" - else - if [[ -n "$line" ]]; then - echo "$file:$line" - else - echo "$file" - fi - fi - done - } - - function lintrng { - xmllint --debug --noout --nonet \ - --relaxng ${docbook5}/xml/rng/docbook/docbook.rng \ - "$1" \ - 2>&1 | context 1>&2 - # ^ redirect assumes xmllint doesn’t print to stdout - } - - lintrng manual-combined.xml - lintrng man-pages-combined.xml - - mkdir $out - cp manual-combined.xml $out/ - cp man-pages-combined.xml $out/ - ''; - - olinkDB = runCommand "manual-olinkdb" - { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; - } - '' - xsltproc \ - ${manualXsltprocOptions} \ - --stringparam collect.xref.targets only \ - --stringparam targets.filename "$out/manual.db" \ - --nonet \ - ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \ - ${manual-combined}/manual-combined.xml - - cat > "$out/olinkdb.xml" < - - ]> - - - Allows for cross-referencing olinks between the manpages - and manual. - - - &manualtargets; - - EOF - ''; - in rec { - inherit generatedSources; - # TODO: Use `optionsDoc.optionsJSON` directly once upstream # `nixosOptionsDoc` is more customizable. optionsJSON = runCommand "options.json" @@ -194,10 +56,10 @@ in rec { "$out/share/doc/darwin" ''; - # Generate the NixOS manual. + # Generate the nix-darwin manual. manualHTML = runCommand "darwin-manual-html" - { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; + { nativeBuildInputs = [ buildPackages.nixos-render-docs ]; + styles = lib.sourceFilesBySuffices (pkgs.path + "/doc") [ ".css" ]; meta.description = "The Darwin manual in HTML format"; allowedReferences = ["out"]; } @@ -205,82 +67,75 @@ in rec { # Generate the HTML manual. dst=$out/share/doc/darwin mkdir -p $dst - xsltproc \ - ${manualXsltprocOptions} \ - --stringparam target.database.document "${olinkDB}/olinkdb.xml" \ - --stringparam id.warnings "1" \ - --nonet --output $dst/ \ - ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \ - ${manual-combined}/manual-combined.xml \ - |& tee xsltproc.out - grep "^ID recommended on" xsltproc.out &>/dev/null && echo "error: some IDs are missing" && false - rm xsltproc.out - - mkdir -p $dst/images/callouts - cp ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/ - cp ${./style.css} $dst/style.css - cp ${./overrides.css} $dst/overrides.css + cp $styles/style.css $dst + cp $styles/overrides.css $dst cp -r ${pkgs.documentation-highlighter} $dst/highlightjs + substitute ${./manual.md} manual.md \ + --replace '@DARWIN_VERSION@' "${version}"\ + --replace \ + '@DARWIN_OPTIONS_JSON@' \ + ${optionsJSON}/share/doc/darwin/options.json + + # TODO: --manpage-urls? + nixos-render-docs -j $NIX_BUILD_CORES manual html \ + --manpage-urls ${pkgs.writeText "manpage-urls.json" "{}"} \ + --revision ${lib.escapeShellArg revision} \ + --generator "nixos-render-docs ${pkgs.lib.version}" \ + --stylesheet style.css \ + --stylesheet overrides.css \ + --stylesheet highlightjs/mono-blue.css \ + --script ./highlightjs/highlight.pack.js \ + --script ./highlightjs/loader.js \ + --toc-depth 1 \ + --chunk-toc-depth 1 \ + ./manual.md \ + $dst/index.html + mkdir -p $out/nix-support echo "nix-build out $out" >> $out/nix-support/hydra-build-products echo "doc manual $dst" >> $out/nix-support/hydra-build-products - ''; # */ - - # Alias for backward compatibility. TODO(@oxij): remove eventually. - manual = manualHTML; + ''; - # Index page of the NixOS manual. + # Index page of the nix-darwin manual. manualHTMLIndex = "${manualHTML}/share/doc/darwin/index.html"; - manualEpub = runCommand "darwin-manual-epub" - { inherit sources; - buildInputs = [ libxml2.bin libxslt.bin zip ]; - } - '' - # Generate the epub manual. - dst=$out/share/doc/darwin - - xsltproc \ - ${manualXsltprocOptions} \ - --stringparam target.database.document "${olinkDB}/olinkdb.xml" \ - --nonet --xinclude --output $dst/epub/ \ - ${docbook_xsl_ns}/xml/xsl/docbook/epub/docbook.xsl \ - ${manual-combined}/manual-combined.xml - - mkdir -p $dst/epub/OEBPS/images/callouts - cp -r ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */ - echo "application/epub+zip" > mimetype - manual="$dst/darwin-manual.epub" - zip -0Xq "$manual" mimetype - cd $dst/epub && zip -Xr9D "$manual" * - - rm -rf $dst/epub + manualEpub = builtins.throw "The nix-darwin EPUB manual has been removed."; - mkdir -p $out/nix-support - echo "doc-epub manual $manual" >> $out/nix-support/hydra-build-products - ''; - - - # Generate the NixOS manpages. + # Generate the nix-darwin manpages. manpages = runCommand "darwin-manpages" - { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; + { nativeBuildInputs = [ buildPackages.nixos-render-docs ]; allowedReferences = ["out"]; } '' # Generate manpages. - mkdir -p $out/share/man - xsltproc --nonet \ - --maxdepth 6000 \ - --param man.output.in.separate.dir 1 \ - --param man.output.base.dir "'$out/share/man/'" \ - --param man.endnotes.are.numbered 0 \ - --param man.break.after.slash 1 \ - --stringparam target.database.document "${olinkDB}/olinkdb.xml" \ - ${docbook_xsl_ns}/xml/xsl/docbook/manpages/docbook.xsl \ - ${manual-combined}/man-pages-combined.xml + mkdir -p $out/share/man/man5 + nixos-render-docs -j $NIX_BUILD_CORES options manpage \ + --revision ${lib.escapeShellArg revision} \ + ${optionsJSON}/share/doc/darwin/options.json \ + $out/share/man/man5/configuration.nix.5 + + # TODO: get these parameterized in upstream nixos-render-docs + sed -i -e ' + /^\.TH / s|NixOS|Darwin|g + + /^\.SH "NAME"$/ { + N + s|NixOS|Darwin|g + } + + /^\.SH "DESCRIPTION"$/ { + N; N + s|/etc/nixos/configuration|configuration|g + s|NixOS|Darwin|g + s|nixos|darwin|g + } + + /\.SH "AUTHORS"$/ { + N; N + s|Eelco Dolstra and the Nixpkgs/NixOS contributors|Daiderd Jordan and the nix-darwin contributors|g + } + ' $out/share/man/man5/configuration.nix.5 ''; - } diff --git a/doc/manual/man-pages.xml b/doc/manual/man-pages.xml deleted file mode 100644 index 2490f6391..000000000 --- a/doc/manual/man-pages.xml +++ /dev/null @@ -1,42 +0,0 @@ - - Darwin Reference Pages - - DaiderdJordan - Author - - 2016-2019Daiderd Jordan - - - - - - configuration.nix - 5 - Darwin - - - - configuration.nix - Darwin system configuration specification - - - Description - - The file configuration.nix contains the - declarative specification of your Darwin system configuration. The command - darwin-rebuild takes this file and realises the system - configuration specified therein. - - - - Options - - You can use the following options in configuration.nix. - - - - - diff --git a/doc/manual/manual.md b/doc/manual/manual.md new file mode 100644 index 000000000..131df7d25 --- /dev/null +++ b/doc/manual/manual.md @@ -0,0 +1,8 @@ +# Darwin Configuration Options {#book-darwin-manual} +## Version @DARWIN_VERSION@ + +```{=include=} options +id-prefix: opt- +list-id: configuration-variable-list +source: @DARWIN_OPTIONS_JSON@ +``` diff --git a/doc/manual/manual.xml b/doc/manual/manual.xml deleted file mode 100644 index a334342d6..000000000 --- a/doc/manual/manual.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - Darwin Manual - Version - - - - Preface - Nix modules for darwin. - - - Configuration Options - - - - diff --git a/doc/manual/overrides.css b/doc/manual/overrides.css deleted file mode 100644 index 4c7d4a31b..000000000 --- a/doc/manual/overrides.css +++ /dev/null @@ -1,9 +0,0 @@ -.docbook .xref img[src^=images\/callouts\/], -.screen img, -.programlisting img { - width: 1em; -} - -.calloutlist img { - width: 1.5em; -} diff --git a/doc/manual/style.css b/doc/manual/style.css deleted file mode 100644 index 474dd32e3..000000000 --- a/doc/manual/style.css +++ /dev/null @@ -1,291 +0,0 @@ -/* Copied from http://bakefile.sourceforge.net/, which appears - licensed under the GNU GPL. */ - - -/*************************************************************************** - Basic headers and text: - ***************************************************************************/ - -body -{ - font-family: "Nimbus Sans L", sans-serif; - font-size: 1em; - background: white; - margin: 2em 1em 2em 1em; -} - -h1, h2, h3, h4 -{ - color: #005aa0; -} - -h1 /* title */ -{ - font-size: 200%; -} - -h2 /* chapters, appendices, subtitle */ -{ - font-size: 180%; -} - -div.book -{ - text-align: center; -} - -div.book > div -{ - /* - * based on https://medium.com/@zkareemz/golden-ratio-62b3b6d4282a - * we do 70 characters per line to fit code listings better - * 70 * (font-size / 1.618) - * expression for emacs: - * (* 70 (/ 1 1.618)) - */ - max-width: 43.2em; - text-align: left; - margin: auto; -} - -/* Extra space between chapters, appendices. */ -div.chapter > div.titlepage h2, div.appendix > div.titlepage h2 -{ - margin-top: 1.5em; -} - -div.section > div.titlepage h2 /* sections */ -{ - font-size: 150%; - margin-top: 1.5em; -} - -h3 /* subsections */ -{ - font-size: 125%; -} - -div.simplesect h2 -{ - font-size: 110%; -} - -div.appendix h3 -{ - font-size: 150%; - margin-top: 1.5em; -} - -div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */ -{ - margin-top: 1.4em; - font-size: 125%; -} - -div.refsection h3 -{ - font-size: 110%; -} - - -/*************************************************************************** - Examples: - ***************************************************************************/ - -div.example -{ - border: 1px solid #b0b0b0; - padding: 6px 6px; - margin-left: 1.5em; - margin-right: 1.5em; - background: #f4f4f8; - border-radius: 0.4em; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -div.example p.title -{ - margin-top: 0em; -} - -div.example pre -{ - box-shadow: none; -} - - -/*************************************************************************** - Screen dumps: - ***************************************************************************/ - -pre.screen, pre.programlisting -{ - border: 1px solid #b0b0b0; - padding: 3px 3px; - margin-left: 0.5em; - margin-right: 0.5em; - - background: #f4f4f8; - font-family: monospace; - border-radius: 0.4em; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -div.example pre.programlisting -{ - border: 0px; - padding: 0 0; - margin: 0 0 0 0; -} - -/*************************************************************************** - Notes, warnings etc: - ***************************************************************************/ - -.note, .warning -{ - border: 1px solid #b0b0b0; - padding: 3px 3px; - margin-left: 1.5em; - margin-right: 1.5em; - margin-bottom: 1em; - padding: 0.3em 0.3em 0.3em 0.3em; - background: #fffff5; - border-radius: 0.4em; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -div.note, div.warning -{ - font-style: italic; -} - -div.note h3, div.warning h3 -{ - color: red; - font-size: 100%; - padding-right: 0.5em; - display: inline; -} - -div.note p, div.warning p -{ - margin-bottom: 0em; -} - -div.note h3 + p, div.warning h3 + p -{ - display: inline; -} - -div.note h3 -{ - color: blue; - font-size: 100%; -} - -div.navfooter * -{ - font-size: 90%; -} - - -/*************************************************************************** - Links colors and highlighting: - ***************************************************************************/ - -a { text-decoration: none; } -a:hover { text-decoration: underline; } -a:link { color: #0048b3; } -a:visited { color: #002a6a; } - - -/*************************************************************************** - Table of contents: - ***************************************************************************/ - -div.toc -{ - font-size: 90%; -} - -div.toc dl -{ - margin-top: 0em; - margin-bottom: 0em; -} - - -/*************************************************************************** - Special elements: - ***************************************************************************/ - -tt, code -{ - color: #400000; -} - -.term -{ - font-weight: bold; - -} - -div.variablelist dd p, div.glosslist dd p -{ - margin-top: 0em; -} - -div.variablelist dd, div.glosslist dd -{ - margin-left: 1.5em; -} - -div.glosslist dt -{ - font-style: italic; -} - -.varname -{ - color: #400000; -} - -span.command strong -{ - font-weight: normal; - color: #400000; -} - -div.calloutlist table -{ - box-shadow: none; -} - -table -{ - border-collapse: collapse; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -table.simplelist -{ - text-align: left; - color: #005aa0; - border: 0; - padding: 5px; - background: #fffff5; - font-weight: normal; - font-style: italic; - box-shadow: none; - margin-bottom: 1em; -} - -div.navheader table, div.navfooter table { - box-shadow: none; -} - -div.affiliation -{ - font-style: italic; -} diff --git a/modules/documentation/default.nix b/modules/documentation/default.nix index 7712a1320..a49d27736 100644 --- a/modules/documentation/default.nix +++ b/modules/documentation/default.nix @@ -73,7 +73,6 @@ let The nix-darwin documentation now requires nixpkgs 23.05 to build. ''; }; - manual = manualHTML; manualHTMLIndex = "${manualHTML}/share/doc/darwin/index.html"; }; diff --git a/release.nix b/release.nix index 56a066352..f5a933550 100644 --- a/release.nix +++ b/release.nix @@ -89,7 +89,6 @@ let }; manualHTML = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manualHTML); - manualEpub = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manualEpub); manpages = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manpages); options = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.optionsJSON); From 42d1643e7a79aa9a0c6bf50e5944fec4e5c492f2 Mon Sep 17 00:00:00 2001 From: Emily Date: Thu, 22 Jun 2023 20:51:21 +0100 Subject: [PATCH 063/161] {ci,readme}: update stable nixpkgs to 23.05 22.11 is deprecated and can no longer generate the manual. --- .github/workflows/test.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c351432fa..c03bc931a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ on: push: env: - CURRENT_STABLE_CHANNEL: nixpkgs-22.11-darwin + CURRENT_STABLE_CHANNEL: nixpkgs-23.05-darwin jobs: test-stable: diff --git a/README.md b/README.md index e7865e37c..bc39b2d01 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ A minimal example of using an existing configuration.nix: description = "John's darwin system"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-22.11-darwin"; + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-23.05-darwin"; darwin.url = "github:lnl7/nix-darwin/master"; darwin.inputs.nixpkgs.follows = "nixpkgs"; }; From 9d6702cf2b81f5d0ef9d628d99e8deb45f84b454 Mon Sep 17 00:00:00 2001 From: Emily Date: Thu, 22 Jun 2023 13:08:42 +0100 Subject: [PATCH 064/161] eval-config: remove compatibility shims 20.03 and 22.03 are both deprecated. --- eval-config.nix | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/eval-config.nix b/eval-config.nix index c30d88c7a..4b713030e 100644 --- a/eval-config.nix +++ b/eval-config.nix @@ -42,24 +42,14 @@ let }; }; - libExtended = lib.extend (self: super: { - # Added in nixpkgs #136909, adds forward compatibility until 22.03 is deprecated. - literalExpression = super.literalExpression or super.literalExample; - literalDocBook = super.literalDocBook or super.literalExample; - }); - - eval = libExtended.evalModules (builtins.removeAttrs args [ "lib" "inputs" "pkgs" "system" ] // { + eval = lib.evalModules (builtins.removeAttrs args [ "lib" "inputs" "pkgs" "system" ] // { modules = modules ++ [ argsModule pkgsModule ] ++ baseModules; specialArgs = { modulesPath = builtins.toString ./modules; } // specialArgs; }); - - # Was moved in nixpkgs #82751, so both need to be handled here until 20.03 is deprecated. - # https://github.com/NixOS/nixpkgs/commits/dcdd232939232d04c1132b4cc242dd3dac44be8c - _module = eval._module or eval.config._module; in { - inherit (_module.args) pkgs; + inherit (eval._module.args) pkgs; inherit (eval) options config; system = eval.config.system.build.toplevel; From df03a145b36f4787ef033589159129a1c936a643 Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 25 Jun 2023 06:39:44 +0100 Subject: [PATCH 065/161] ci: update manual updater to 23.05 Fix https://github.com/LnL7/nix-darwin/issues/709. --- .github/workflows/update-manual.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-manual.yml b/.github/workflows/update-manual.yml index 7ba43e876..fdcfe7542 100644 --- a/.github/workflows/update-manual.yml +++ b/.github/workflows/update-manual.yml @@ -24,7 +24,7 @@ jobs: - name: Build manual run: | - nix-build ./release.nix -I nixpkgs=channel:nixpkgs-22.11-darwin -I darwin=. -A manualHTML + nix-build ./release.nix -I nixpkgs=channel:nixpkgs-23.05-darwin -I darwin=. -A manualHTML - name: Push update to manual run: | From a62f16b94dff6ad5835ec6beb992e09e76bc2fe6 Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 25 Jun 2023 06:41:51 +0100 Subject: [PATCH 066/161] readme: update links for redirect --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bc39b2d01..94ebdda47 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[logo](https://github.com/LnL7/nix-darwin) +[logo](https://github.com/LnL7/nix-darwin) # nix-darwin @@ -189,7 +189,7 @@ $ ## Documentation -Reference documentation of all the options is available [here](https://lnl7.github.io/nix-darwin/manual/index.html#sec-options). +Reference documentation of all the options is available [here](https://daiderd.com/nix-darwin/manual/index.html). This can also be accessed locally using `man 5 configuration.nix`. `darwin-help` will open a HTML version of the manpage in the default browser. From cb37c35e33239b844203987fff18f91370939921 Mon Sep 17 00:00:00 2001 From: Daiderd Jordan Date: Sun, 25 Jun 2023 13:03:49 +0200 Subject: [PATCH 067/161] fix darwin-option descriptions Also drops the eval hacks in favour of jq. --- modules/nix/nix-darwin.nix | 2 +- pkgs/nix-tools/darwin-option.sh | 21 +++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/modules/nix/nix-darwin.nix b/modules/nix/nix-darwin.nix index f86b15437..fceecc25d 100644 --- a/modules/nix/nix-darwin.nix +++ b/modules/nix/nix-darwin.nix @@ -16,8 +16,8 @@ let darwin-option = writeProgram "darwin-option" { - inherit (config.system) profile; inherit (stdenv) shell; + path = "${extraPath}:${config.environment.systemPath}"; } ../../pkgs/nix-tools/darwin-option.sh; diff --git a/pkgs/nix-tools/darwin-option.sh b/pkgs/nix-tools/darwin-option.sh index d6d466b23..8e40e93c0 100755 --- a/pkgs/nix-tools/darwin-option.sh +++ b/pkgs/nix-tools/darwin-option.sh @@ -4,26 +4,24 @@ set -o pipefail export PATH=@path@:$PATH evalNix() { - nix-instantiate --eval --strict "${extraEvalFlags[@]}" -E "with import {}; $*" + nix-instantiate --eval --strict "${extraEvalFlags[@]}" -E "with import {}; $*" 2>/dev/null } -evalAttrs() { - evalNix "builtins.concatStringsSep \"\\n\" (builtins.attrNames $*)" +evalOpt() { + evalNix "options.$option.$*" } -evalOpt() { - evalNix "options.$option.$*" 2>/dev/null +evalOptAttrs() { + evalNix "builtins.concatStringsSep \"\\n\" (builtins.attrNames $*)" | jq -r . } evalOptText() { - eval printf "$(evalNix "options.$option.$*" 2>/dev/null)" 2>/dev/null - echo + evalNix "options.$option.$*" | jq -r . } showSyntax() { echo "$0: [-I path]