Skip to content

feat(night-shift): default Night Shift to always on - #2091

Merged
shunkakinoki merged 2 commits into
mainfrom
night-shift-default-macos-791700
Jul 17, 2026
Merged

feat(night-shift): default Night Shift to always on#2091
shunkakinoki merged 2 commits into
mainfrom
night-shift-default-macos-791700

Conversation

@shunkakinoki

@shunkakinoki shunkakinoki commented Jul 17, 2026

Copy link
Copy Markdown
Owner

What

Makes Night Shift the default color mode on macOS: always on, rather than the previous sunset-to-sunrise schedule.

Adds a home-manager service at home-manager/services/night-shift/, wired into home-manager/services/default.nix, with a shellspec covering the apply script.

Why this shape

Night Shift state lives in the per-user CoreBrightness session and is not exposed through any plist system.defaults can write, so there is no declarative nix-darwin option for it. The only way to express "on by default" is to talk to that session, which is why this shells out to nightlight (in nixpkgs, darwin-only) from a launchd agent. Same reasoning as the keyboard module shelling out to hidutil.

It lives in home-manager rather than nix-darwin because the state is per-user, not system-wide.

Notes for reviewers

Two deliberate choices worth a look:

  • schedule stop before on. 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".
  • RunAtLoad with no StartInterval. This makes the setting a default rather than an enforcement — a manual toggle off sticks until the next login. A periodic re-assert would fight the user every few minutes.

Temperature is pinned at 100 (warmest), matching what the machine was already set to, so the mode is fully declarative rather than half-pinned.

Commits

  1. feat(night-shift): default Night Shift to always on — the change itself.
  2. style(gh): format extensions list — drive-by treefmt fix on home-manager/programs/gh/default.nix, unformatted on main since the gh-stack commit (797139f). Whitespace only, unrelated to Night Shift; separated out so it stays easy to skip.

Verification

  • spec/night_shift_spec.sh passes (4 examples, 0 failures); picked up by normal shellspec discovery.
  • nix build .#checks.aarch64-darwin.eval-darwin-default passes.
  • nix build .#checks.aarch64-darwin.treefmt passes (failed on main before commit 2).
  • Ran the built store script directly: status on until sunrise -> on, schedule sunset to sunrise -> off, temp 100.
  • Confirmed the darwin-only nightlight package does not break Linux evaluation — the Linux home config errors at the identical pre-existing docker.service platform mismatch (same drv hash) with and without this change.

Night Shift state lives in the per-user CoreBrightness session and is
not exposed through any plist system.defaults can write, so express it
as a home-manager launchd user agent that calls nightlight on login.

Clear the schedule before turning it on, since sunset-to-sunrise would
otherwise flip Night Shift back off at sunrise. RunAtLoad without a
StartInterval keeps this a default rather than an enforcement: a manual
toggle sticks until the next login.
@indent-zero

indent-zero Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor
PR Summary

Adds a home-manager service that defaults macOS Night Shift to always-on at max warmth by installing a Darwin-only launchd user agent that runs the nightlight CLI at login. Because Night Shift state lives in the per-user CoreBrightness session and cannot be written via system.defaults, this login-time approach is the only way to express "on by default"; RunAtLoad without a StartInterval intentionally keeps it a default (manual toggle sticks until next login) rather than an enforcement. A tag-along commit reformats an unrelated programs.gh.extensions list to satisfy treefmt.

  • Registers a new night-shift module in home-manager/services/default.nix.
  • Adds home-manager/services/night-shift/default.nix that wires a launchd.agents.night-shift user agent (Darwin-only via mkIf) running a pkgs.replaceVars-substituted shell script.
  • Adds home-manager/services/night-shift/apply-night-shift.sh, which runs nightlight schedule stop (so a sunset-to-sunrise schedule does not later flip Night Shift off), then nightlight temp 100, then nightlight on.
  • Adds spec/night_shift_spec.sh shellspec tests validating the shebang, strict-mode pragma, bash -n syntax, and the exact schedule stop → temp 100 → on call order against a mock nightlight binary.
  • Reformats home-manager/programs/gh/default.nix extensions list to one-entry-per-line (treefmt cleanup, no functional change).

Issues

1 potential issue found:

  • Temperature is re-applied on every login, not just Night Shift on/off — apply-night-shift.sh unconditionally runs temp 100 before on, so any manual nightlight temp <n> a user sets between logins gets silently reverted, which is not covered by the PR description's "a manual toggle sticks until the next login" framing. → Autofix

CI Checks

Waiting for CI checks...


⚡ Autofix All Issues

@cursor

cursor Bot commented Jul 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@shunkakinoki, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 21 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 18ffd0ac-e70e-4e67-98ae-dc443edda514

📥 Commits

Reviewing files that changed from the base of the PR and between 9feacad and a8f2cdf.

📒 Files selected for processing (5)
  • home-manager/programs/gh/default.nix
  • home-manager/services/default.nix
  • home-manager/services/night-shift/apply-night-shift.sh
  • home-manager/services/night-shift/default.nix
  • spec/night_shift_spec.sh
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch night-shift-default-macos-791700

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

❤️ Share

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

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new night-shift service for macOS (Darwin) systems, which configures a launchd agent to set a default screen temperature and enable Night Shift on login. It includes a shell script to apply the settings and a shell spec test suite to verify its behavior. Feedback on the pull request highlights two important issues in the Nix configuration: static log paths in /tmp that can cause permission conflicts on multi-user systems, and top-level evaluation of Darwin-only packages on non-Darwin platforms. A refactoring is suggested to wrap the module in a Darwin-conditional block and remove the static log paths.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +1 to +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";
StandardErrorPath = "/tmp/night-shift.error.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.

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;
      };
    };
  }
)

@mesa-dot-dev mesa-dot-dev Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Performed full review of 9feacad...f165c67

Analysis

No significant architectural issues identified. The PR implements a well-structured macOS service module with appropriate boundary selection (home-manager vs system-level), proper platform gating, deterministic dependency injection, and a pragmatic imperative bridge pattern consistent with existing precedent. The design appropriately respects user preferences while providing sensible defaults, and includes test coverage for implementation verification.

Tip

Help

Slash Commands:

  • /review - Request a full code review
  • /review latest - Review only changes since the last review
  • /describe - Generate PR description. This will update the PR body or issue comment depending on your configuration
  • /help - Get help with Mesa commands and configuration options

0 files reviewed | 0 comments | Edit Agent SettingsRead Docs

# 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.

@mesa-dot-dev

mesa-dot-dev Bot commented Jul 17, 2026

Copy link
Copy Markdown

Mesa Description

TL;DR

Defaults macOS Night Shift to "always on" (warmest temperature, no schedule) via a per-user home-manager service that runs once at login.

What changed?

  • home-manager/services/default.nix: Enables the new night-shift service.
  • home-manager/services/night-shift/apply-night-shift.sh: Script that uses the nightlight CLI to clear schedules, set temperature, and turn Night Shift on.
  • home-manager/services/night-shift/default.nix: Defines the macOS-only service and configures a login-time launchd agent.
  • spec/night_shift_spec.sh: Adds ShellSpec tests using mocked nightlight commands to verify script behaviors.

Description generated by Mesa. Update settings

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 4 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="home-manager/services/night-shift/default.nix">

<violation number="1" location="home-manager/services/night-shift/default.nix:26">
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`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

"${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>

treefmt expands multi-element lists one entry per line. Unformatted
since the gh-stack extension was added in 797139f.
@shunkakinoki
shunkakinoki merged commit 8649777 into main Jul 17, 2026
29 of 30 checks passed
@shunkakinoki
shunkakinoki deleted the night-shift-default-macos-791700 branch July 17, 2026 04:40
shunkakinoki added a commit that referenced this pull request Jul 17, 2026
Closes the shell-test failure introduced in #2091, which added
apply-night-shift.sh and its spec without registering the script in
coverage_spec.sh.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant