How to invoke script, installed with writeScriptBin inside other config file

I need to create shell script inside NixOS, and then use it declaratively. For such situation, NixOS can provision shell script inside the system, but I bumped into troubles of invoking this script after installation. For putting shell script inside the system, I used this code snippet:

{ pkgs, ... }:

let
  helloWorld = pkgs.writeScriptBin "helloWorld" ''
    #!${pkgs.stdenv.shell}
    echo Hello World
  '';

in {
  environment.systemPackages = [ helloWorld ];
}

package, named helloWorld successfully installed into the system, but then, when I try to put it inside another file, this way

environment.etc."webhook.conf".text = ''
[
  {
    "id": "webhook",
    "execute-command": "${pkgs.systemPackages}/bin/helloWorld",
    "command-working-directory": "/tmp"
  }
]

or

environment.etc."webhook.conf".text = ''
[
  {
    "id": "webhook",
    "execute-command": "${pkgs.helloWorld}/bin/helloWorld",
    "command-working-directory": "/tmp"
  }
]

on nixos-rebuild switch it bumps into this error: error: attribute 'systemPackages' missing (or error: attribute 'helloWorld' missing for second variant of invokation)

What I’m doing wrong? I need path to helloWorld package appear inside webhook.conf file in /etc directory

Well, pkgs doesn’t work like that, adding an element to the systemPackages option, does not add it as an entry in the pkgs attribute set.

I see two possible ways to accomplish this.

My preferred method, would be to just define the helloWorld script where you need it, like so:

environment.etc."webhook.conf".text = let
  helloWorld = pkgs.writeScriptBin "helloWorld" ''
    echo Hello World
  '';
in ''
  [
    {
      "id": "webhook",
      "execute-command": "${helloWorld}/bin/helloWorld",
      "command-working-directory": "/tmp"
    }
  ]
''

By doing so, the helloWorld store path is only known as the local variable helloWorld which you use to include it in the file in /etc.

Alternatively, you add the script to environment.systemPackages, which will make the helloWorld script available on the system path, so then you can just directly write helloWorld and rely on the standard path resolution to locate the script for you, like so:

environment.systemPackages = let
  helloWorld = pkgs.writeScriptBin "helloWorld" ''
    echo Hello World
  '';
in [ helloWorld ];

environment.etc."webhook.conf".text = ''
  [
    {
      "id": "webhook",
      "execute-command": "helloWorld",
      "command-working-directory": "/tmp"
    }
  ]
''

I think most people would use overlays, which do add stuff to pkgs.

{ pkgs, ... }:

{
  nixpkgs.overlays = [(self: super: {
    helloWorld = pkgs.writeScriptBin "helloWorld" ''
      #!${pkgs.stdenv.shell}
      echo Hello World
    '';
  })];

  environment.systemPackages = [ pkgs.helloWorld ];

  environment.etc."webhook.conf".text = ''
  [
    {
      "id": "webhook",
      "execute-command": "${pkgs.helloWorld}/bin/helloWorld",
      "command-working-directory": "/tmp"
    }
  ];
}