diff --git a/pkgs/default.nix b/pkgs/default.nix
index c9e755a..03f9cc3 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -26,6 +26,8 @@ pkgs.lib.makeScope pkgs.newScope (pkgs: {
osc52 = pkgs.callPackage ./osc52 { };
+ osc777 = pkgs.callPackage ./osc777 { };
+
rbw-pass = pkgs.callPackage ./rbw-pass { };
unbound-zones-adblock = pkgs.callPackage ./unbound-zones-adblock { };
diff --git a/pkgs/osc777/default.nix b/pkgs/osc777/default.nix
new file mode 100644
index 0000000..6e9ce2e
--- /dev/null
+++ b/pkgs/osc777/default.nix
@@ -0,0 +1,41 @@
+{ lib, coreutils, makeWrapper, stdenvNoCC }:
+stdenvNoCC.mkDerivation rec {
+ pname = "osc777";
+ version = "0.1.0";
+
+ src = ./osc777;
+
+ nativeBuildInputs = [
+ makeWrapper
+ ];
+
+ dontUnpack = true;
+
+ dontBuild = true;
+
+ installPhase = ''
+ mkdir -p $out/bin
+ cp $src $out/bin/osc777
+ chmod a+x $out/bin/osc777
+ '';
+
+ wrapperPath = lib.makeBinPath [
+ coreutils
+ ];
+
+ fixupPhase = ''
+ patchShebangs $out/bin/osc777
+ wrapProgram $out/bin/osc777 --prefix PATH : "${wrapperPath}"
+ '';
+
+ meta = with lib; {
+ description = ''
+ A script to send notifications using the OSC777 escape sequence
+ '';
+ homepage = "https://git.belanyi.fr/ambroisie/nix-config";
+ license = with licenses; [ mit ];
+ mainProgram = "osc777";
+ maintainers = with maintainers; [ ambroisie ];
+ platforms = platforms.linux;
+ };
+}
diff --git a/pkgs/osc777/osc777 b/pkgs/osc777/osc777
new file mode 100755
index 0000000..83d066f
--- /dev/null
+++ b/pkgs/osc777/osc777
@@ -0,0 +1,126 @@
+#!/usr/bin/env bash
+
+# Whether to disable tmux/screen DCS escape sequences
+: "${OSC777_NO_DCS:=0}"
+
+die() {
+ echo "ERROR: $*"
+ exit 1
+}
+
+usage() {
+ if [ $# -gt 0 ]; then
+ exec 1>&2
+ fi
+
+ cat << EOF
+Usage: $0 [options]
+Send a notification (title and message) to the host system using the OSC 777
+escape sequence:
+Options:
+ -h, --help This screen.
+ -d, --no-dcs Disable tmux/screen specific DCS sequences, only use OSC 777
+ -- Stop options processing
+EOF
+
+ if [ $# -gt 0 ]; then
+ echo
+ die "$@"
+ else
+ exit 0
+ fi
+}
+
+tmux_seq() {
+ # shellcheck disable=1003
+ printf '\033Ptmux;\033%s\033\\' "$1"
+}
+
+screen_seq() {
+ # Screen limits the length of string sequences, so we have to break it up.
+ # Going by the screen history:
+ # (v4.2.1) Apr 2014 - today: 768 bytes
+ # Aug 2008 - Apr 2014 (v4.2.0): 512 bytes
+ # ??? - Aug 2008 (v4.0.3): 256 bytes
+ local limit=768
+ # We go 4 bytes under the limit because we're going to insert two bytes
+ # before (\eP) and 2 bytes after (\e\) each string.
+ printf '%s' "$1" |
+ sed -E "s:.{$((limit - 4))}:&\n:g" |
+ sed -E -e 's:^:\x1bP:' -e 's:$:\x1b\\:' |
+ tr -d '\n'
+}
+
+osc777_seq() {
+ printf '%s' "$1"
+}
+
+print_seq() {
+ local seq="$1"
+
+ if [ "${OSC777_NO_DCS}" != 0 ]; then
+ # Override TERM to avoid tmux/screen DCS escape logic
+ TERM=dummy
+ fi
+
+ case ${TERM-} in
+ screen*)
+ # Since tmux defaults to setting TERM=screen, special case it.
+ if [ -n "${TMUX-}" ]; then
+ tmux_seq "${seq}"
+ else
+ screen_seq "${seq}"
+ fi
+ ;;
+ tmux*)
+ tmux_seq "${seq}"
+ ;;
+ *)
+ osc777_seq "${seq}"
+ ;;
+ esac
+}
+
+notify() {
+ local title=$1
+ local message=$2
+
+ # shellcheck disable=1003
+ print_seq "$(printf '\033]777;notify;%s;%s\e\\' "${title}" "${message}")"
+}
+
+main() {
+ set -e
+
+ local args=()
+ while [ $# -gt 0 ]; do
+ case $1 in
+ -h | --help)
+ usage
+ ;;
+ -d | --no-dcs)
+ OSC777_NO_DCS=1
+ ;;
+ --)
+ shift
+ args+=("$@")
+ break
+ ;;
+ -*)
+ usage "Unknown option: $1"
+ ;;
+ *)
+ args+=("$1")
+ ;;
+ esac
+ shift
+ done
+
+ if [ "${#args[@]}" -ne 2 ]; then
+ usage "Supply exactly two arguments"
+ fi
+
+ notify "${args[@]}"
+}
+
+main "$@"