New: watch your coding agents work, step by step, on a live board. Try the demo, no account

Pushover alerts for blocked and finished tasks

By Jake Marsh, who builds Taskhold. Updated 2026-10-26. Facts about other tools checked 2026-10-26. 3 min read.

Pushover delivers reliable notifications to phones, watches and desktops. This script follows Taskhold's event stream and sends one when an agent needs an answer (high priority, so it breaks through quiet hours if you allow that) and one when it finishes a task. The notification links to the live board.

Other channels: ntfy, Slack, Discord.

What you get

One Pushover message when an agent blocks a task with a question, and one when it finishes a whole task (not each step). Each says which agent, the task title, the question or the summary, and links to the live board, where you reply. Your own changes never trigger a message.

Before you begin

  • A Pushover account and your user key.
  • A Pushover application token: create an application named Taskhold on pushover.net.
  • A Taskhold API key from Settings > API keys, named after this script so you can revoke it on its own.
  • bash, curl and jq on the machine that runs the script.

The script

Save this as taskhold-pushover.sh and make it executable (chmod +x). The top half is the Pushover part; the loop below it is the same for every notifier.

#!/bin/bash
# taskhold-pushover.sh: send a Pushover notification when an agent blocks or finishes a Taskhold task.
# Needs curl and jq. Run: TASKHOLD_API_KEY=atd_sk_... ./taskhold-pushover.sh
key=${TASKHOLD_API_KEY:?set TASKHOLD_API_KEY}
board=https://taskhold.com/dashboard/live
last=""

: "${PUSHOVER_TOKEN:?set PUSHOVER_TOKEN}" "${PUSHOVER_USER:?set PUSHOVER_USER}"
notify() { # kind, title, detail, agent
  if [ "$1" = blocked ]; then t="$4 needs you"; pr=1; else t="$4 finished a task"; pr=0; fi
  curl -s -o /dev/null --form-string "token=$PUSHOVER_TOKEN" --form-string "user=$PUSHOVER_USER" \
    --form-string "title=$t" --form-string "message=$2${3:+: $3}" --form-string "priority=$pr" \
    --form-string "url=$board" --form-string "url_title=Open the live board" \
    https://api.pushover.net/1/messages.json
}

while :; do
  while IFS= read -r line; do
    case "$line" in
      "id: "*) last=${line#id: } ;;
      "data: "*)
        e=${line#data: }
        # Agents only: a task (not a step) finished, or any task or step blocked.
        jq -e '.type == "task.status" and .actor == "agent" and (.data.to == "blocked" or (.data.to == "done" and .task_id == .root_task_id))' <<<"$e" >/dev/null || continue
        kind=$(jq -r .data.to <<<"$e")
        title=$(jq -r '.task_title // "a task"' <<<"$e")
        agent=$(jq -r '.actor_name // "An agent"' <<<"$e")
        detail=$(jq -r 'if .data.to == "blocked" then .data.blocked_reason else .data.completed_summary end // ""' <<<"$e")
        notify "$kind" "$title" "$detail" "$agent" ;;
    esac
  done < <(curl -sN https://taskhold.com/api/events/stream -H "Authorization: Bearer $key" ${last:+-H "Last-Event-ID: $last"})
  sleep 3
done

Run it anywhere a process can stay up, such as a spare terminal, a tmux window or a small server:

PUSHOVER_TOKEN=a... PUSHOVER_USER=u... TASKHOLD_API_KEY=atd_sk_... ./taskhold-pushover.sh

The server ends each stream after 10 minutes and the script reconnects with the last event id, so events that happen in between arrive once, in order. Details on the stream: events and the live stream.

One limit to know

Pushover is a paid app after its own trial, and its application tokens have a monthly message allowance. One message per blocked or finished task stays far below it, but don't widen the filter to progress events.

Share this page:XLinkedInBlueskyHacker News

See how far along your coding agents are.

$12/month or $120/year after the trial. Card up front. Cancel before day 7 and you pay nothing. Every agent you run is included.

Sources

Related

Updated 2026-10-26. Something wrong or out of date? Email hello@greatwork.company.