Recipes
Small scripts that put a line on the island: when a push is done, a command ends, the disk is filling up. Copy one, and it works. Each does one thing, and none of them updates itself or downloads anything.
Before you start
- Press Install next to Command under Build & Test in Settings, so the runnock command is there (it goes in ~/.local/bin).
- Check that External alerts is on in Settings under Notch.
- Every recipe first checks that runnock is installed and says nothing if it is not, so one that you keep never gets in the way of your own scripts.
A line when you commit
Shows the commit message on the island after every commit in a repository.
Save it as .git/hooks/post-commit in the repository and run chmod +x on it.
#!/bin/sh
# Runnock recipe: a line on the island after every commit.
# Save as .git/hooks/post-commit in the repository, then: chmod +x .git/hooks/post-commit
rn() { command -v runnock >/dev/null 2>&1 && runnock alert "$@" >/dev/null 2>&1; true; }
top=$(git rev-parse --show-toplevel)
subject=$(git log -1 --pretty=%s | cut -c1-70)
# "open" has to be under your home folder or /tmp, so leave it out for a repository kept anywhere else.
case "$top" in
"$HOME"/*|/tmp/*|/private/tmp/*) rn --id "git-commit" --title "committed" --body "$subject" --open "$top" ;;
*) rn --id "git-commit" --title "committed" --body "$subject" ;;
esac
Know when a push is done
gpush runs git push and says on the island whether it worked, for a slow remote you do not want to watch.
Add it to ~/.zshrc, open a new terminal, and use gpush where you would use git push.
# Runnock recipe: git push, and a line on the island when it is done.
# Add to ~/.zshrc, open a new terminal, and use `gpush` where you would use `git push`.
gpush() {
local branch; branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
if git push "$@"; then
command -v runnock >/dev/null 2>&1 && runnock alert --id "git-push" --title "pushed" --body "$branch" >/dev/null 2>&1
return 0
else
local code=$?
command -v runnock >/dev/null 2>&1 && runnock alert --id "git-push" --title "push failed" --body "$branch" --level fail >/dev/null 2>&1
return $code
fi
}
A line when any command ends
rn-after runs a command and says on the island how it ended and how long it took. A failure stays until you dismiss it.
Add it to ~/.zshrc, then run, for example, rn-after pnpm test. The command's own exit code is passed on.
# Runnock recipe: run a command, then say how it ended and how long it took.
# Add to ~/.zshrc, open a new terminal: rn-after pnpm test
rn-after() {
local started=$SECONDS name=${1:t}
"$@"
local code=$? took=$(( SECONDS - started ))
if command -v runnock >/dev/null 2>&1; then
if [ $code -eq 0 ]; then
runnock alert --title "${name:0:16}" --body "done in ${took}s" >/dev/null 2>&1
else
runnock alert --title "${name:0:16}" --body "failed (exit $code) after ${took}s" --level fail >/dev/null 2>&1
fi
fi
return $code
}
Wait for a GitHub Actions run
rn-gh-run watches a run with the gh CLI and says on the island whether it passed.
Needs the gh CLI signed in. Add it to ~/.zshrc, then rn-gh-run <run-id>, or with no id to pick one.
# Runnock recipe: watch a GitHub Actions run and say how it went. Needs the gh CLI, signed in.
# Add to ~/.zshrc: rn-gh-run <run-id> (without an id, gh lets you pick one)
rn-gh-run() {
local repo; repo=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)")
if gh run watch "$@" --exit-status; then
command -v runnock >/dev/null 2>&1 && runnock alert --id "gh-run" --title "CI passed" --body "$repo" >/dev/null 2>&1
else
local code=$?
command -v runnock >/dev/null 2>&1 && runnock alert --id "gh-run" --title "CI failed" --body "$repo" --level fail >/dev/null 2>&1
return $code
fi
}
A line when a download ends
rn-get downloads a file with curl and says on the island when it has finished or failed.
Add it to ~/.zshrc, then rn-get https://example.com/big.iso. The file goes in the current folder.
# Runnock recipe: download with curl, and a line on the island when it ends.
# Add to ~/.zshrc: rn-get https://example.com/big.iso
rn-get() {
local url=2877 file=${1:t}
if curl -fL --output "${file:-download}" "$url"; then
command -v runnock >/dev/null 2>&1 && runnock alert --id "rn-get" --title "downloaded" --body "${file:0:70}" --open "$PWD" >/dev/null 2>&1
else
local code=$?
command -v runnock >/dev/null 2>&1 && runnock alert --id "rn-get" --title "download failed" --body "${file:0:70}" --level fail >/dev/null 2>&1
return $code
fi
}
A timer on the island
rn-timer waits a number of minutes and then puts a line on the island that waits for you.
Add it to ~/.zshrc, then rn-timer 25 "stand up". It keeps running in the background, so the terminal is free.
# Runnock recipe: rn-timer <minutes> <text> e.g. rn-timer 25 "stand up"
# Add to ~/.zshrc. It runs in the background; the line stays on the island for 5 minutes.
rn-timer() {
local minutes=${1:?minutes} text=${2:-timer}
( sleep $(( minutes * 60 )) && command -v runnock >/dev/null 2>&1 && \
runnock alert --id "rn-timer" --title "timer" --body "${text:0:80}" --level action --ttl 300 >/dev/null 2>&1 ) &!
}
Warn before the disk fills up
Checks the free space on the startup disk and puts a line on the island when it falls below a limit. Run it on a schedule.
Save it somewhere (for example ~/bin/rn-disk-low), chmod +x it, and run it every hour with cron or launchd. The limit is the first argument in GB (default 15).
#!/bin/sh
# Runnock recipe: say so when the startup disk has less than N GB free (default 15).
# Run it every hour, e.g. with cron: 0 * * * * $HOME/bin/rn-disk-low 15
limit=${1:-15}
free_kb=$(df -k / | awk 'NR==2 {print undefined}')
free_gb=$(( free_kb / 1024 / 1024 ))
if [ "$free_gb" -lt "$limit" ] && command -v runnock >/dev/null 2>&1; then
runnock alert --id "disk-low" --title "disk space low" --body "${free_gb} GB free" --level action --ttl 3600 --open "$HOME" >/dev/null 2>&1
fi
exit 0
Low battery
Puts a line on the island when the battery is low and not charging. Run it every few minutes.
Save it (for example ~/bin/rn-battery-low), chmod +x it, and run it every 5 minutes with cron or launchd. The limit is the first argument in percent (default 15).
#!/bin/sh
# Runnock recipe: say so when the battery is below N percent (default 15) and not charging.
# Run it every 5 minutes, e.g. with cron: */5 * * * * $HOME/bin/rn-battery-low 15
limit=${1:-15}
status=$(pmset -g batt)
percent=$(printf '%s' "$status" | grep -Eo '[0-9]+%' | head -1 | tr -d '%')
if [ -n "$percent" ] && [ "$percent" -lt "$limit" ] && printf '%s' "$status" | grep -q 'discharging' && command -v runnock >/dev/null 2>&1; then
runnock alert --id "battery-low" --title "battery low" --body "${percent}% left" --level action --ttl 600 >/dev/null 2>&1
fi
exit 0
A certificate about to expire
Checks when the TLS certificate of a site expires and puts a line on the island when it is less than two weeks away.
Save it (for example ~/bin/rn-cert-expiry), chmod +x it, and run it once a day: rn-cert-expiry example.com. It connects to that site on port 443.
#!/bin/sh
# Runnock recipe: say so when a site's certificate expires in under 14 days.
# Run it once a day: rn-cert-expiry example.com
host=${1:?usage: rn-cert-expiry <host>}
end=$(printf '' | openssl s_client -servername "$host" -connect "$host:443" 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
[ -n "$end" ] || exit 0
end_epoch=$(date -j -f "%b %e %T %Y %Z" "$end" +%s 2>/dev/null) || exit 0
days=$(( (end_epoch - $(date +%s)) / 86400 ))
if [ "$days" -lt 14 ] && command -v runnock >/dev/null 2>&1; then
runnock alert --id "cert-$host" --title "cert expires" --body "$host in ${days} days" --level action --ttl 86400 >/dev/null 2>&1
fi
exit 0
From Shortcuts and automations
A runnock:// link does what the command does, so a Shortcut or an automation can put a line on the island.
In Shortcuts, add an Open URLs action with the link, and use it in a personal automation (a Focus ending, arriving somewhere, a time of day).
# Runnock recipe: links for Shortcuts and automations. Each one is a runnock://alert link.
# Parameters: title (1-16 characters), body (up to 80), level (info, action, fail), open (a path under your home folder or /tmp), id, ttl (seconds).
# A reminder that waits for you for 30 seconds:
runnock://alert?title=stand%20up&body=Time%20for%20a%20break&level=action
# After a Focus mode ends:
runnock://alert?title=focus%20over&body=Back%20to%20normal&id=focus
# Open a project folder from the island:
runnock://alert?title=ready&body=Open%20the%20project&open=/Users/YOU/Projects/app&level=action