Udev rule not executing

I want to be able to hotplug my external monitor that I use at home with my laptop and have xrandr respond by simply turning off the laptop display if it detects the external monitor. I have looked at the autorandr module and also the grobi option in home-manager but they both have a weird bug where they would try to reset the screens not just when the external monitor was plugged in/unplugged but also when it went blank (I have it set to go blank after 5 mins with xset).

I thought that I could get around this by simply having a script that did all the xrandr stuff and calling it whenever the external monitor was plugged/unplugged with a udev rule.

The script I’m calling is (pulled straight from the arch wiki with the added touch command for debugging purposes)

#!/usr/bin/env bash

touch /home/tom/Downloads/I_RAN


if xrandr | grep "$extern disconnected"; then
    sleep 1 ; xrandr --output "$extern" --off --output "$intern" --auto
    sleep 1 ; xrandr --output "$intern" --off --output "$extern" --auto

The udev rule in my configuration.nix is like

  services.udev.extraRules = ''
  ACTION=="change", SUBSYSTEM=="drm", RUN+="${pkgs.writeShellScriptBin "toggle_monitor" (builtins.readFile /home/tom/.dotfiles/toggle_monitor.sh)}"

But unfortunately it’s not executing when I plug/unplug my external monitor to my laptop. I’m on 23.11. Any help figuring out either the udev rule or the weird bug with autorandr/grobi would be very much appreciated!

writeShellScriptBin creates a directory:

$ nix repl ~/Projects/nixpkgs
nix-repl> :b pkgs.writeShellScriptBin "toggle_monitor" "foo"

This derivation produced the following outputs:
  out -> /nix/store/rfqwmrqibj7h9zh4zh5aqq4i1adj0lpc-toggle_monitor

$ eza -T /nix/store/rfqwmrqibj7h9zh4zh5aqq4i1adj0lpc-toggle_monitor
└── bin
   └── toggle_monitor

$ cat /nix/store/rfqwmrqibj7h9zh4zh5aqq4i1adj0lpc-toggle_monitor/bin/toggle_monitor 

Either use ${pkgs.writeShellScriptBin "toggle_monitor" …}/bin/toggle_monitor, or just writeShellScript.

Also, both of those already insert a shebang.

Okay so I’ve removed the shebang from the source file and changed the udev rule to

  services.udev.extraRules = ''
  ACTION=="change", SUBSYSTEM=="drm", RUN+="${pkgs.writeShellScriptBin "toggle_monitor" (builtins.readFile /home/tom/.dotfiles/toggle_monitor.sh)}/bin/toggle_monitor"

and I can see the script with the added shebang in the nix store. It’s still not executing when I plug/unplug my monitor though? I’ve executed the script from the nix store to make sure that it’s working correctly when it does get executed.