Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion home-manager/programs/gh/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
{
programs.gh = {
enable = true;
extensions = with pkgs; [ gh-markdown-preview gh-stack ];
extensions = with pkgs; [
gh-markdown-preview
gh-stack
];
settings = {
editor = "nvim";
git_protocol = "https";
Expand Down
2 changes: 2 additions & 0 deletions home-manager/services/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ let
keydApplicationMapper = ./keyd-application-mapper;
makeUpdater = import ./make-updater { inherit pkgs; };
neversslKeepalive = import ./neverssl-keepalive { inherit pkgs; };
nightShift = import ./night-shift { inherit pkgs; };
obsidian = import ./obsidian { inherit config pkgs inputs; };
ollama = ./ollama;
qmd = ./qmd;
Expand All @@ -46,6 +47,7 @@ in
keydApplicationMapper
makeUpdater
neversslKeepalive
nightShift
obsidian
ollama
qmd
Expand Down
12 changes: 12 additions & 0 deletions home-manager/services/night-shift/apply-night-shift.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

set -euo pipefail

nightlight_bin="@nightlightBin@"
temperature=@temperature@

# A sunset-to-sunrise schedule turns Night Shift back off at sunrise, so the
# schedule has to be cleared before `on` can mean "stays on".
"$nightlight_bin" schedule stop
"$nightlight_bin" temp "$temperature"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Login resets temperature too, not just on/off: The PR description frames this agent as a default that a manual toggle can override until next login, and that's true for on/off — but this line unconditionally re-applies temp 100 at every login, so a manual nightlight temp 60 (or any other value) gets silently stomped on the next login. If that's intentional (i.e. the 'default' is really on @ temp=100, not just on), consider calling it out in the module comment; if not, gating the temp call on the current preference (or dropping it and relying on macOS to remember the last temp) would keep temperature adjustments sticky the same way on/off is.

"$nightlight_bin" on
30 changes: 30 additions & 0 deletions home-manager/services/night-shift/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{ pkgs }:
let
# 0 = least warm, 100 = warmest.
temperature = 100;

applyNightShiftScript = pkgs.replaceVars ./apply-night-shift.sh {
nightlightBin = "${pkgs.nightlight}/bin/nightlight";
inherit temperature;
};
in
{
# Night Shift state lives in the per-user CoreBrightness session and is not
# exposed through any plist `system.defaults` can write, so the only way to
# express "on by default" is to talk to that session on login.
#
# RunAtLoad without a StartInterval deliberately makes this a default rather
# than an enforcement: a manual toggle sticks until the next login.
launchd.agents.night-shift = pkgs.lib.mkIf pkgs.stdenv.isDarwin {
enable = true;
config = {
ProgramArguments = [
"${pkgs.bash}/bin/bash"
"${applyNightShiftScript}"
];
RunAtLoad = true;
StandardOutPath = "/tmp/night-shift.log";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Using fixed paths in /tmp for StandardOutPath and StandardErrorPath will cause permission conflicts on multi-user macOS systems. The first user's login creates these files with their ownership; subsequent users' launchd agents will fail to write to them. Since this is a simple run-once script, consider removing these log paths entirely (launchd will route output to the system log), or use a per-user path like ~/Library/Logs/night-shift.log.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/services/night-shift/default.nix, line 26:

<comment>Using fixed paths in `/tmp` for `StandardOutPath` and `StandardErrorPath` will cause permission conflicts on multi-user macOS systems. The first user's login creates these files with their ownership; subsequent users' launchd agents will fail to write to them. Since this is a simple run-once script, consider removing these log paths entirely (launchd will route output to the system log), or use a per-user path like `~/Library/Logs/night-shift.log`.</comment>

<file context>
@@ -0,0 +1,30 @@
+        "${applyNightShiftScript}"
+      ];
+      RunAtLoad = true;
+      StandardOutPath = "/tmp/night-shift.log";
+      StandardErrorPath = "/tmp/night-shift.error.log";
+    };
</file context>

StandardErrorPath = "/tmp/night-shift.error.log";
};
};
}
Comment on lines +1 to +30

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

This refactoring addresses two important issues:

  1. Multi-user Permission Conflicts: Writing logs to static paths in /tmp (like /tmp/night-shift.log) causes permission conflicts on multi-user macOS systems. When the first user logs in, the log file is created under their ownership. When a subsequent user logs in, their launchd agent will fail to start because they lack write permissions to the existing log file. Since this is a simple run-once script, we can safely remove StandardOutPath and StandardErrorPath entirely.
  2. Platform Evaluation Isolation: Defining applyNightShiftScript (which references pkgs.nightlight) in the top-level let block forces its evaluation even on non-Darwin systems (like Linux). Since nightlight is a Darwin-only package, this can cause evaluation or platform-support errors on Linux. Wrapping the entire module in pkgs.lib.optionalAttrs pkgs.stdenv.isDarwin ensures that Darwin-specific derivations are only evaluated on Darwin.
{ pkgs }:
pkgs.lib.optionalAttrs pkgs.stdenv.isDarwin (
  let
    # 0 = least warm, 100 = warmest.
    temperature = 100;

    applyNightShiftScript = pkgs.replaceVars ./apply-night-shift.sh {
      nightlightBin = "${pkgs.nightlight}/bin/nightlight";
      inherit temperature;
    };
  in
  {
    # Night Shift state lives in the per-user CoreBrightness session and is not
    # exposed through any plist `system.defaults` can write, so the only way to
    # express "on by default" is to talk to that session on login.
    #
    # RunAtLoad without a StartInterval deliberately makes this a default rather
    # than an enforcement: a manual toggle sticks until the next login.
    launchd.agents.night-shift = {
      enable = true;
      config = {
        ProgramArguments = [
          "${pkgs.bash}/bin/bash"
          "${applyNightShiftScript}"
        ];
        RunAtLoad = true;
      };
    };
  }
)

62 changes: 62 additions & 0 deletions spec/night_shift_spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# shellcheck disable=SC2329

Describe 'home-manager/services/night-shift/apply-night-shift.sh'
SCRIPT="$PWD/home-manager/services/night-shift/apply-night-shift.sh"

Describe 'script properties'
It 'uses bash shebang'
When run bash -c "head -1 '$SCRIPT'"
The output should include '#!/usr/bin/env bash'
End

It 'uses strict mode'
When run bash -c "head -5 '$SCRIPT'"
The output should include 'set -euo pipefail'
End

It 'passes bash syntax check after replacing placeholders'
When run bash -c "sed -e 's|@nightlightBin@|/usr/bin/true|g' -e 's|@temperature@|100|g' '$SCRIPT' | bash -n"
The status should be success
End
End

setup_night_shift_script() {
TEST_DIR=$(mktemp -d)
NIGHTLIGHT_LOG="$TEST_DIR/nightlight.log"
NIGHTLIGHT_BIN="$TEST_DIR/nightlight"
PREPROCESSED_SCRIPT="$TEST_DIR/apply-night-shift.sh"
: >"$NIGHTLIGHT_LOG"

cat >"$NIGHTLIGHT_BIN" <<'EOF'
#!/usr/bin/env bash
set -eu
printf '%s\n' "$*" >>"$NIGHTLIGHT_LOG"
EOF
chmod +x "$NIGHTLIGHT_BIN"

sed \
-e "s|@nightlightBin@|$NIGHTLIGHT_BIN|g" \
-e 's|@temperature@|100|g' \
"$SCRIPT" >"$PREPROCESSED_SCRIPT"
chmod +x "$PREPROCESSED_SCRIPT"
}

cleanup_night_shift_script() {
rm -rf "$TEST_DIR"
}

Describe 'applying the Night Shift default'
Before 'setup_night_shift_script'
After 'cleanup_night_shift_script'

It 'clears the schedule before turning Night Shift on'
When run bash -c ': >"'"$NIGHTLIGHT_LOG"'"; NIGHTLIGHT_LOG="'"$NIGHTLIGHT_LOG"'" "'"$PREPROCESSED_SCRIPT"'" >/dev/null && cat "'"$NIGHTLIGHT_LOG"'"'
The status should be success
The line 1 of output should eq 'schedule stop'
The line 2 of output should eq 'temp 100'
The line 3 of output should eq 'on'
End
End

End
Loading