diff --git a/home/sam/bin/task-due-notify.sh b/home/sam/bin/task-due-notify.sh
index ccfb20f..f5e4321 100755
--- a/home/sam/bin/task-due-notify.sh
+++ b/home/sam/bin/task-due-notify.sh
@@ -1,11 +1,91 @@
-#!/usr/bin/env bash
+#!/nix/store/x12lw455sq6qy2wcya85d7rb88ybc3df-bash-interactive-5.3p9/bin/bash
-# Query tasks due soon (adjust filters as needed, e.g., due.before:now+1h for 1-hour reminders)
-DUE_TASKS=$(task due.before:now+1h status:pending export | jq -r '.[] | .description + " (due: " + .due + ")"')
+# Simple Taskwarrior Notification Script
+# Just checks: if time_until_due <= reminder_time, send notification
-if [ -n "$DUE_TASKS" ]; then
- while IFS= read -r task; do
- notify-send "Task Due Soon" "$task" # Local Mako pop-up
- curl -d "Task due soon: $task" https://ntfy.lab.audasmedia.com.au/tasks # Remote ntfy.sh (or swap to your Docker URL like http://YOUR_DOCKER_IP:PORT/task_topic)
- done <<< "$DUE_TASKS"
-fi
+NTFY_URL="https://ntfy.lab.audasmedia.com.au/tasks"
+NOW=$(date -u +%s)
+
+# Auto-add +notify to tasks with due dates or remind tags
+task status:pending '( due.any: or tags.has:remindMins or tags.has:remindHours or tags.has:remindDays or tags.has:remindWeeks or tags.has:remindMonths )' -notify export 2>/dev/null | \
+ /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -r '.[].uuid' 2>/dev/null | \
+ while read -r uuid; do
+ /nix/store/syqlfcifpih00fknzailx8xxn4cnv42d-taskwarrior-3.4.2/bin/task "$uuid" modify +notify 2>/dev/null
+ done
+
+# Process tasks with +notify
+task status:pending +notify export 2>/dev/null | \
+ /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -c '.[] | select(.due) | {uuid: .uuid, description: .description, due: .due, tags: .tags}' 2>/dev/null | \
+ while read -r task_json; do
+
+ uuid=$(echo "$task_json" | /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -r '.uuid')
+ desc=$(echo "$task_json" | /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -r '.description')
+ due_date=$(echo "$task_json" | /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -r '.due')
+ tags=$(echo "$task_json" | /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -r '.tags[]? // empty' 2>/dev/null)
+
+ # Convert due date (UTC) to epoch
+ formatted_date=$(echo "$due_date" | /nix/store/ryz8kcrm2bxpccllfqlb7qldsfnqp5c2-gnused-4.9/bin/sed 's/T/ /; s/Z$//; s/^\(....\)\(..\)\(..\)/\1-\2-\3/; s/ \(..\)\(..\)\(..\)$/ \1:\2:\3/')
+ due_epoch=$(/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin/date -d "$formatted_date UTC" +%s 2>/dev/null || echo 0)
+
+ if [ "$due_epoch" = "0" ]; then
+ continue
+ fi
+
+ time_until_due=$((due_epoch - NOW))
+
+ # Check reminder tags
+ echo "$tags" | /nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin/grep -E '^remind(Mins|Hours|Days|Weeks|Months)' 2>/dev/null | \
+ while read -r remind_tag; do
+
+ # Parse: remindMins2, remindHours1, etc
+ if [[ "$remind_tag" =~ ^remind(Mins|Hours|Days|Weeks|Months)([0-9]+)$ ]]; then
+ unit="${BASH_REMATCH[1]}"
+ num="${BASH_REMATCH[2]}"
+
+ # Convert to seconds
+ case "$unit" in
+ Mins) remind_secs=$((num * 60)); time_str="$num minutes" ;;
+ Hours) remind_secs=$((num * 3600)); time_str="$num hours" ;;
+ Days) remind_secs=$((num * 86400)); time_str="$num days" ;;
+ Weeks) remind_secs=$((num * 604800)); time_str="$num weeks" ;;
+ Months) remind_secs=$((num * 2592000)); time_str="$num months" ;;
+ esac
+
+ # SIMPLE: If time until due <= reminder time AND still in future, send it
+ if [ $time_until_due -le $remind_secs ] && [ $time_until_due -gt 0 ]; then
+ /nix/store/xgdl4gzjzwj7ixs83f17sqppd08lfd03-libnotify-0.8.7/bin/notify-send -u normal "Reminder" "๐ $desc - Due in $time_str"
+ /nix/store/jqfr3p49g3lch84y45jfzw9fshlv8jyp-curl-8.17.0-bin/bin/curl -s -d "Reminder: $desc - Due in $time_str" "$NTFY_URL" >/dev/null 2>&1 &
+ /nix/store/syqlfcifpih00fknzailx8xxn4cnv42d-taskwarrior-3.4.2/bin/task "$uuid" modify -"$remind_tag" 2>/dev/null
+ fi
+ fi
+ done
+
+ # Check if task is due (overdue)
+ if [ $time_until_due -le 0 ] && ! echo "$tags" | /nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin/grep -q "^notified$"; then
+ /nix/store/xgdl4gzjzwj7ixs83f17sqppd08lfd03-libnotify-0.8.7/bin/notify-send -u critical "Task Due" "โ ๏ธ $desc"
+ /nix/store/jqfr3p49g3lch84y45jfzw9fshlv8jyp-curl-8.17.0-bin/bin/curl -s -d "Task due: $desc" "$NTFY_URL" >/dev/null 2>&1 &
+ /nix/store/syqlfcifpih00fknzailx8xxn4cnv42d-taskwarrior-3.4.2/bin/task "$uuid" modify +notified 2>/dev/null
+ fi
+ done
+
+# Cleanup: Remove notification tags from completed/deleted tasks
+task '( status:completed or status:deleted )' '( +notify or +notified or tags.has:remindMins or tags.has:remindHours or tags.has:remindDays or tags.has:remindWeeks or tags.has:remindMonths )' export 2>/dev/null | \
+ /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -r '.[].uuid' 2>/dev/null | \
+ while read -r uuid; do
+ tags=$(/nix/store/syqlfcifpih00fknzailx8xxn4cnv42d-taskwarrior-3.4.2/bin/task "$uuid" export 2>/dev/null | /nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin/bin/jq -r '.[0].tags[]? // empty' 2>/dev/null)
+
+ remove_args=""
+ echo "$tags" | /nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin/grep -q "^notify$" && remove_args="$remove_args -notify"
+ echo "$tags" | /nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin/grep -q "^notified$" && remove_args="$remove_args -notified"
+
+ remind_tags=$(echo "$tags" | /nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin/grep "^remind(Mins|Hours|Days|Weeks|Months)" 2>/dev/null || true)
+ if [ -n "$remind_tags" ]; then
+ while read -r tag; do
+ remove_args="$remove_args -$tag"
+ done <<< "$remind_tags"
+ fi
+
+ if [ -n "$remove_args" ]; then
+ /nix/store/syqlfcifpih00fknzailx8xxn4cnv42d-taskwarrior-3.4.2/bin/task "$uuid" modify $remove_args 2>/dev/null
+ fi
+ done
diff --git a/home/sam/config/niri/config.kdl b/home/sam/config/niri/config.kdl
index aa05cff..bcca23d 100644
--- a/home/sam/config/niri/config.kdl
+++ b/home/sam/config/niri/config.kdl
@@ -76,6 +76,13 @@ input {
// https://yalter.github.io/niri/Configuration:-Outputs
// Remember to uncomment the node by removing "/-"!
+// input {
+// "*" allow
+// }
+// output {
+// "*" allow
+// }
+
environment {
MOZ_DBUS_REMOTE "1"
@@ -748,4 +755,6 @@ binds {
// Powers off the monitors. To turn them back on, do any input like
// moving the mouse or pressing any other key.
Mod+Shift+P { power-off-monitors; }
+ Mod+N { spawn "swaync-client" "-t"; }
+
}
diff --git a/home/sam/config/waybar/config.jsonc b/home/sam/config/waybar/config.jsonc
index 5d46247..43eadf6 100644
--- a/home/sam/config/waybar/config.jsonc
+++ b/home/sam/config/waybar/config.jsonc
@@ -6,6 +6,8 @@
"modules-left": ["niri/workspaces"],
"modules-center": ["niri/window"],
"modules-right": [
+ "custom/tasks", // <-- ADD THIS LINE
+ "custom/notification", // <-- ADD THIS
"keyboard-state",
"cpu",
"memory",
@@ -15,23 +17,60 @@
"clock"
],
- "clock": { "format": "{:%a %d %b %H:%M}" },
+"tray": {
+ "icon-size": 20,
+ "spacing": 8
+},
- "cpu": { "format": "๏ {usage}%" },
- "memory": { "format": "๓ฐ {percentage}%" },
- "network": {
- "format-wifi": "๏ซ {signalStrength}%",
- "format-ethernet": "๓ฐ",
- "format-disconnected": "๓ฐช"
- },
-
- "pulseaudio": {
- "format": "๏จ {volume}%",
- "format-muted": "๓ฐ"
+"clock": {
+ "format": "๓ฐฅ {:%a %d %b %H:%M}",
+ "on-click": "niri msg action spawn -- gnome-calendar",
+ "tooltip": true,
+ "tooltip-format": "{:%Y-%m-%d %H:%M:%S}"
+},
+
+"cpu": {
+ "format": "๏ {usage}%",
+ "on-click": "niri msg action spawn -- kitty -e btop",
+ "tooltip": true
+},
+
+"memory": {
+ "format": "๓ฐ {percentage}%",
+ "on-click": "niri msg action spawn -- kitty -e btop",
+ "tooltip": true
+},
+
+"network": {
+ "format-wifi": "๓ฐคจ {signalStrength}%",
+ "format-ethernet": "๓ฐ Wired",
+ "format-disconnected": "๓ฐช Offline",
+ "on-click": "nm-connection-editor",
+ "on-click-right": "nmcli networking toggle",
+ "tooltip": true,
+ "tooltip-format": "{essid}\nLeft-click: Network settings\nRight-click: Toggle networking"
+},
+
+
+"pulseaudio": {
+ "format": "{icon} {volume}%",
+ "format-muted": "๓ฐ Muted",
+ "format-icons": {
+ "default": ["๓ฐฟ", "๓ฐ", "๓ฐพ"],
+ "headphone": "๓ฐ",
+ "headset": "๓ฐ"
},
+ "on-click": "pavucontrol",
+ "on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
+ "on-scroll-up": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02+ -l 1.0",
+ "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02-",
+ "tooltip": true,
+ "tooltip-format": "{icon} {volume}%\nLeft-click: Mixer\nRight-click: Toggle mute\nScroll: Adjust volume"
+},
"keyboard-state": {
+ "device": "/dev/input/event*",
"numlock": true,
"capslock": true,
"format": "{name} {icon}",
@@ -39,5 +78,41 @@
"locked": "๏ฃ",
"unlocked": "๏"
}
- }
+ },
+
+"custom/tasks": {
+ "format": "{icon} {text}",
+ "format-icons": ["๏บ", "๏"],
+ "interval": 30,
+ "exec": "task status:pending count",
+ "exec-if": "which task",
+ "on-click": "niri msg action spawn -- kitty -e taskwarrior-tui",
+ "on-click-right": "niri msg action spawn -- kitty -e task add",
+ "tooltip": true,
+ "tooltip-format": "{} pending tasks\nLeft-click: Open TUI\nRight-click: Add task",
+ "min-length": 3,
+ "max-length": 20
+},
+"custom/notification": {
+ "tooltip": false,
+ "format": "{icon}",
+ "format-icons": {
+ "notification": "๓ฐ๏",
+ "none": "๓ฐ",
+ "dnd-notification": "๓ฐ๏",
+ "dnd-none": "๓ฐ"
+ },
+ "return-type": "json",
+ "exec-if": "which swaync-client",
+ "exec": "swaync-client -swb",
+ "on-click": "swaync-client -t -sw",
+ "on-click-right": "swaync-client -d -sw",
+ "escape": true
+}
+
+
+
+
+
+
}
diff --git a/home/sam/config/zsh/local.zsh b/home/sam/config/zsh/local.zsh
index 41eacfe..256bc31 100644
--- a/home/sam/config/zsh/local.zsh
+++ b/home/sam/config/zsh/local.zsh
@@ -13,6 +13,10 @@ export EDITOR="nvim"
export VISUAL="nvim"
+export TICKER_WATCH="^GSPC,^DJI,^IXIC,^AXJO,^AORD,CBA.AX,NAB.AX,WBC.AX,ANZ.AX,BHP.AX,RIO.AX,FMG.AX,NST.AX,^VIX,CL=F,NG=F,ZC=F,KE=F,^TNX,BDRY,BTC-USD,DX-Y.NYB,000001.SS,399001.SZ,^HSI,TIO=F,EURUSD=X,AUDUSD=X,GC=F,SI=F,AAPL,MSFT,GOOG,NVDA,AMZN,META,TSLA"
+export TICKER_REFRESH=120 # Refresh rate in seconds
+
+
# This must be at the top for Powerlevel10k Instant Prompt to work.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
diff --git a/home/sam/home.nix b/home/sam/home.nix
index e302be7..4c92cc0 100644
--- a/home/sam/home.nix
+++ b/home/sam/home.nix
@@ -29,6 +29,159 @@ home.stateVersion = "25.11";
+
+services.swaync = {
+ enable = true;
+ settings = {
+ positionX = "right";
+ positionY = "top";
+ control-center-margin-top = 10;
+ control-center-margin-right = 10;
+ control-center-width = 380;
+ notification-window-width = 400;
+ notification-icon-size = 64;
+ notification-body-image-height = 100;
+ notification-body-image-width = 200;
+ timeout = 10;
+ timeout-low = 5;
+ timeout-critical = 0;
+ widgets = [
+ "notifications"
+ "mpris"
+ "volume"
+ "backlight"
+ "buttons-grid"
+ ];
+ "widget-config" = {
+ notifications = {
+ "hide-on-clear" = false;
+ "hide-on-action" = true;
+ };
+ mpris = {
+ "image-size" = 96;
+ "image-radius" = 12;
+ };
+ volume = {
+ label = "๓ฐพ";
+ };
+ backlight = {
+ label = "๓ฐ";
+ };
+ "buttons-grid" = {
+ actions = [
+ {
+ label = "๓ฐฅ";
+ command = "systemctl poweroff";
+ }
+ {
+ label = "๓ฐ";
+ command = "systemctl reboot";
+ }
+ {
+ label = "๓ฐ";
+ command = "swaylock";
+ }
+ ];
+ };
+ };
+ };
+};
+
+
+
+# services.mako = {
+# enable = true;
+#
+# # Essential Wayland integration
+# layer = "overlay"; # Required for Niri
+# output = ""; # Shows on all outputs
+#
+# # Design (matches your Dunst preferences)
+# font = "JetBrainsMono Nerd Font 10";
+# backgroundColor = "#1e1e2e";
+# borderColor = "#89b4fa";
+# borderSize = 2;
+# borderRadius = 5;
+#
+# # Positioning
+# anchor = "top-right";
+# margin = "30,30"; # X,Y from anchor
+# width = 300;
+# height = 200;
+#
+# # Behavior
+# defaultTimeout = 10000; # ms
+# sort = "-time"; # Newest on top-right
+#
+# settings = {
+# "[urgency=high]" = {
+# background-color = "#f38ba8";
+# default-timeout = 0;
+# };
+# };
+# };
+
+
+# Deploy the script to ~/.local/bin (Nix handles creation/permissions)
+ home.file.".local/bin/task-due-notify" = {
+ source = ./bin/task-due-notify.sh;
+ executable = true;
+ };
+
+systemd.user.timers.task-due-notify = {
+ Unit = {
+ Description = "Timer for Taskwarrior due notifications";
+ };
+ Timer = {
+ OnBootSec = "1min";
+ OnCalendar = "*:*:0/1"; # Every 5 minutes
+ Persistent = true;
+ };
+ Install = {
+ WantedBy = ["timers.target"];
+ };
+ };
+
+# systemd.user.services.task-due-notify = {
+# Unit = {
+# Description = "Check for due Taskwarrior tasks and notify";
+# };
+# Service = {
+# Type = "oneshot";
+# ExecStart = "${pkgs.bash}/bin/bash${config.home.homeDirectory}/.local/bin/task-due-notify";
+# };
+# };
+ # Systemd user timer to run the service periodically
+# systemd.user.timers.task-due-notify = {
+# Unit = {
+# Description = "Timer for Taskwarrior due notifications";
+# };
+# Timer = {
+# OnBootSec = "1min";
+# OnUnitActiveSec = "1min";
+# AccuracySec = "30s";
+# Persistent = true;
+# };
+# Install = {
+# WantedBy = ["timers.target"];
+# };
+# };
+
+systemd.user.services.task-due-notify = {
+ Unit = {
+ Description = "Check for due Taskwarrior tasks and notify";
+ };
+ Service = {
+ Type = "oneshot";
+ ExecStart = "${pkgs.bash}/bin/bash ${config.home.homeDirectory}/.local/bin/task-due-notify";
+ Environment = [
+ "PATH=${pkgs.gnugrep}/bin:${pkgs.gnused}/bin:${pkgs.coreutils}/bin:${pkgs.taskwarrior3}/bin:${pkgs.jq}/bin:${pkgs.curl}/bin:${pkgs.libnotify}/bin:/usr/bin:/bin"
+ "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
+ ];
+ };
+ };
+
+
systemd.user.services.kdeconnect-indicator = {
Unit = {
Description = "KDE Connect indicator";
@@ -140,39 +293,87 @@ dconf.settings."org/gnome/desktop/interface" = {
extraPackages = with pkgs; [ tree-sitter gcc gnumake];
};
+
+ programs.yazi = {
+ enable = true;
+ enableZshIntegration = true;
+ enableBashIntegration = true;
+ # This sets the command name for the wrapper.
+ # Many people use 'y' or 'yy' for quick access.
+ shellWrapperName = "y";
+ };
+
+ home.sessionVariables = {
+ QT_QPA_PLATFORM = "wayland";
+ QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
+ };
+
+ gtk = {
+ enable = true;
+ theme = {
+ name = "Adwaita-dark";
+ package = pkgs.gnome-themes-extra;
+ };
+ iconTheme = {
+ name = "breeze-dark";
+ package = pkgs.kdePackages.breeze-icons;
+ };
+ };
+
+ qt = {
+ enable = true;
+ platformTheme.name = "gtk3";
+ style.name = "adwaita-dark";
+ };
+
+
+
# ---
# Packages (NOW list + a few safe essentials)
# ---
home.packages = with pkgs; [
+
+ # Input device support
+ libinput
+ seatd
+
+ # Audio controls
+ pamixer
+ playerctl
+
+ # Network
+ networkmanagerapplet
+
+ # System Monitoring
+ swaynotificationcenter # For notification daemon
+
+
+
+ libnotify
+
+ kdePackages.dolphin
+ kdePackages.kio-extras
+ kdePackages.kdegraphics-thumbnailers
+ kdePackages.ffmpegthumbs
+ kdePackages.ark
+
+ adwaita-qt
+ adwaita-qt6
+ kdePackages.breeze-icons
+
nushell
bun
pnpm
vite
- python3Packages.beautifulsoup4
- python3Packages.scrapy
- python3Packages.pillow
- python3Packages.playwright
-
-
- # Python AI/ML packages
- python3Packages.torch
- python3Packages.torchvision
- python3Packages.opencv4
- # python3Packages.mediapipe
# CLI tools
# python3Packages.autogpt
- vllm
# agentops
- apache-airflow
- python313Packages.langfuse
(callPackage ../../pkgs/cao-cli.nix { })
- (callPackage ../../pkgs/agentops.nix { })
- (callPackage ../../pkgs/mediapipe.nix { })
ollama
@@ -221,7 +422,7 @@ dconf.settings."org/gnome/desktop/interface" = {
zellij
tealdeer
navi
- yazi
+ # yazi
dua
jq