cb

Cloud backup and restore for Backblaze B2. Backs up directories with git-aware handling, executable permission tracking, and nightly runs via /etc/backup.d.
README

cb

Cloud backup and restore for Backblaze B2. Backs up directories with git-aware handling, executable permission tracking, and nightly runs via /etc/backup.d.

Requires uv to be installed. Credentials are read from /etc/backup (configurable).

Usage

cb [OPTIONS] <COMMAND>

Global Options

Option Description
-q, --quiet Warnings and errors only
--dry-run Print b2 commands without executing them
--config-file <FILE> Config filename (default: /etc/backup)

Commands

store — Backup to bucket

cb store <PATH> <BUCKET> [--dir <DIR>]

Uploads a local directory to a Backblaze B2 bucket. Git directories are handled specially: only .git/config is included. Directories containing a .no-backup file are skipped. Executable permissions are tracked and restored on download.

Argument Description
PATH Local directory to back up
BUCKET Destination bucket name (format: name:)
-d, --dir <DIR> Subdirectory within the bucket

restore — Restore from bucket

cb restore <BUCKET> <PATH> [--chown <OWNER>:<GROUP>]

Downloads a Backblaze B2 bucket to a local directory, creating it if needed.

Argument Description
BUCKET Source bucket name (format: name:)
PATH Destination directory
-c, --chown <OWNER:GROUP> Recursively set owner and group after restore

run — Run nightly backup

cb run [--path <PATH>] [--timestamp-file <FILE>]

Runs all .sh scripts in the backup directory in sorted order. The backup directory must have mode 700. Scripts are executed with /bin/sh.

Option Description
-p, --path <PATH> Path to backup scripts (default: /etc/backup.d)
-t, --timestamp-file <FILE> Write completion timestamp to this file; uploads to meta bucket if configured

Configuration

Credentials are stored in the config file (default /etc/backup). The BACKUP_QUIET environment variable suppresses output when set.

cronpad

Manages scheduled macOS launch agents from `~/Library/LaunchAgents`. Wraps `launchctl` to create, list, reload, and delete agents, and provides a `run` subcommand that captures output and emails it on completion (like cron).
README

cronpad

Manages scheduled macOS launch agents from ~/Library/LaunchAgents. Wraps launchctl to create, list, reload, and delete agents, and provides a run subcommand that captures output and emails it on completion (like traditional cron). macOS only.

Usage

cronpad [OPTIONS] <COMMAND>

Global Options

Option Description
-q, --quiet Warnings and errors only

Commands

list — List scheduled agents

cronpad list

Lists all StartCalendarInterval launch agents in ~/Library/LaunchAgents, showing their name, command, day of week, and scheduled time. Alias: ls.

new — Create a new agent

cronpad new [AGENT]

Interactive wizard that creates a new scheduled launch agent. Prompts for service ID, command, day of week, hour, and minute, then writes the plist and loads it immediately. Alias: add.

Argument Description
AGENT Initial service ID (optional; prompted if omitted)

The au.glob. prefix is added automatically if the name contains no dot. The generated plist calls cronpad run <command> so that output is captured and emailed automatically.

delete — Delete an agent

cronpad delete <AGENT>

Unloads and removes the agent's plist from ~/Library/LaunchAgents. Aliases: del, rm, unload.

Argument Description
AGENT Agent name, plist filename, or full service ID

reload — Load or reload an agent

cronpad reload <AGENT>

Unloads (ignoring errors) and reloads an agent's plist. Use this after editing a plist by hand. Alias: load.

Argument Description
AGENT Agent name, plist filename, or full service ID

edit — Edit an agent's plist and reload

cronpad edit <AGENT>

Opens the agent's plist file in $EDITOR, then automatically reloads the agent once the editor exits. Equivalent to manually editing the plist and running cronpad reload.

Argument Description
AGENT Agent name, plist filename, or full service ID

start — Start an agent immediately

cronpad start <AGENT>

Triggers the agent to run once immediately via launchctl kickstart, without waiting for its next scheduled time.

Argument Description
AGENT Agent name, plist filename, or full service ID

run — Execute a command (used by scheduled agents)

cronpad run <COMMAND>...

Runs a command with a standard PATH set, captures its combined stdout and stderr, and emails the output to the current user if the command produces any. The subject line follows the traditional cron format (Cron <host>: <command>), or Cron <host> FAILED: <command> on non-zero exit. The email is sent from "cronpad@<host>" <user@host>.

This subcommand is embedded in every plist created by cronpad new — it is not normally called directly.

Argument Description
COMMAND Command to execute

Notes

  • macOS only — relies on launchctl and ~/Library/LaunchAgents.
  • Agent lookup accepts the short name (e.g. au.glob.backup), the plist filename (e.g. au.glob.backup.plist), or the full service ID (e.g. gui/501/au.glob.backup).

ding

Plays an audio notification immediately or after executing a command, using success/error sounds based on exit code. Preserves exit code for pipeline use.
README

ding

Plays an audio notification immediately or after executing a command. Uses a success sound (ding) when the exit code is zero, or an error sound otherwise. Preserves the wrapped command's exit code for pipeline use.

Usage

ding [COMMAND...]

If no command is given, plays the success sound immediately.

Examples

# play success sound immediately
ding

# run a command and play success or error sound based on exit code
ding make build

# chain with other commands (exit code is preserved)
ding rsync -av src/ dst/ && echo "done"

Notes

  • Elapsed time is printed when the command takes longer than 5 seconds.
  • Sound playback is non-blocking — ding spawns a background process to play the sound so the exit code is returned immediately.
  • macOS only (requires audio hardware).

docker-run

Wrapper for running commands in Docker containers, simplifying cron execution. Handles volume mounts, naming, cleanup, and optional host networking.
README

docker-run

Wrapper for running commands in Docker containers, simplifying cron execution. Handles volume mounts, container naming, cleanup, and optional host networking.

Usage

docker-run [OPTIONS] <IMAGE> <COMMAND>...

Arguments

Argument Description
IMAGE Docker image to use
COMMAND Command to run inside the container

Options

Option Description
-m, --mount <HOST:CONTAINER> Bind mount a host path into the container (repeatable)
--hostname <HOSTNAME> Set container hostname
--user <USER> Set user inside the container
--random <SECONDS> Sleep a random duration (0 to SECONDS) before running
--host-network Use host network stack
--name <NAME> Container name (default: IMAGE.COMMAND)
--run-in-container Execute in an already-running container with the same name, if present
-q, --quiet Warnings and errors only

Examples

# run a command in a container, mounting /data
docker-run --mount /data:/data myimage mycommand --arg

# exec into a running container if it exists, otherwise start a new one
docker-run --run-in-container myimage mycommand

# randomise start time for cron use
docker-run --random 300 myimage backup.sh

Notes

  • Containers are run with --rm (removed on exit).
  • If stdin is a terminal, --tty --interactive is added automatically.
  • Container name defaults to IMAGE.COMMAND_BASENAME.

dot

Dotfiles manager that tracks configuration files in a git repo (~/.dotfiles) and creates symlinks from your home directory to the tracked files.
README

dot

Dotfiles manager that tracks configuration files in a git repository (~/.dotfiles) and creates symlinks from your home directory to the tracked files.

Usage

dot [OPTIONS] <COMMAND>

Global Options

Option Description
-q, --quiet Warnings and errors only

Commands

add — Track a file

dot add <HOME_FILE> [DOT_FILENAME]

Moves a file from your home directory into ~/.dotfiles, records it in the config, and creates a symlink back.

Argument Description
HOME_FILE File to start tracking (must be under ~)
DOT_FILENAME Override the name/path inside ~/.dotfiles

diff — Show pending changes

dot diff

Shows uncommitted changes to tracked dotfiles.

init — Initialise repository

dot init <REPOSITORY>

Creates ~/.dotfiles, initialises a git repo, and pushes to GitHub.

Argument Description
REPOSITORY GitHub repo as username/repo or a git SSH URL

list — List tracked files

dot list

Lists all tracked dotfiles and their symlink targets. Orphaned symlinks pointing into ~/.dotfiles are highlighted. Aliases: ls, st.

push — Push changes to GitHub

dot push

Stages all changes, generates a commit message (using Claude if available), and pushes to origin.

remove — Stop tracking a file

dot remove <DOT_FILE>

Removes a file from ~/.dotfiles management, restoring it as a regular file in ~. Accepts paths relative to ~, ~/.dotfiles, or the file's actual path. Aliases: rm, del.

Argument Description
DOT_FILE File to remove from tracking

update — Pull and re-link

dot update [--no-pull]

Pulls from git and ensures all symlinks from ~ to ~/.dotfiles are correct. Aliases: up, pull.

Option Description
-n, --no-pull Skip the git pull step

Notes

  • Warns after each command if there are unpushed changes.
  • Config is stored in ~/.dotfiles/dot.properties.

ff

FFmpeg and image wrapper with sensible defaults, progress tracking, and a filter DSL for querying media by attributes. Handles video/audio transcoding and JPEG conversion, optimisation, and resizing.
README

ff

FFmpeg and image wrapper with sensible defaults, progress tracking, and a filter DSL for querying media by attributes. Handles video/audio transcoding and JPEG conversion, optimisation, and resizing.

Requires ffmpeg and ffprobe to be installed.

Usage

ff [OPTIONS] <COMMAND> <FILES>...

Global Options

Option Description
-f, --filter <EXPR> Filter expression (see Filter DSL below)
-q, --quiet Warnings and errors only
--filter-help Print filter DSL syntax reference

Commands

info — Show metadata

ff info [--recurse] [--print0] [--precise] [--metadata] <FILES>...

Prints a summary of each media file: dimensions, size, duration, fps, and codecs.

Option Description
-r, --recurse Recurse into subdirectories
-0, --print0 Print filenames only, separated by NUL (for use with xargs -0)
-p, --precise Show precise values instead of rounded
-m, --metadata Show embedded metadata tags

hash — Generate perceptual or human-readable hash

ff hash [--rename] [<FILE>]

Computes a DCT-based perceptual hash of an image or video file, displayed as a human-readable word sequence. If no file is given, generates a random hash.

Option Description
-r, --rename Rename the file to its hash value

mp4 — Convert to MP4

ff mp4 [--replace] [--bitrate <RATE>] <FILES>...

Converts video files to H265/AAC MP4. Skips files already in MP4 format.

Option Description
-r, --replace Replace existing output
-b, --bitrate <RATE> Maximum bit-rate (e.g. 2M)

mp3 — Convert to MP3

ff mp3 [--replace] <FILES>...

Converts audio files to MP3. Skips files already in MP3 format.

Option Description
-r, --replace Replace existing output

recode — Recode in place

ff recode [--replace] [--replace-if-smaller] [--h264] [--bitrate <RATE>] <FILES>...

Re-encodes MP4 files (H265 by default) or optimises JPEG files in place.

Option Description
-r, --replace Replace existing output
-s, --replace-if-smaller Replace only if the result is smaller (MP4)
--h264 Encode as H264 instead of H265
-b, --bitrate <RATE> Maximum bit-rate (e.g. 2M)

crop — Crop video or image

ff crop [--size <W:H:X:Y>] [--letterbox <PX>] [--pillarbox <PX>] [--preview] [--replace] <FILES>...

Crops video or JPEG images to a specified region. Without --size, auto-detects black bars. For JPEG images the crop is applied directly; --preview is only applicable to video.

Option Description
-s, --size <W:H:X:Y> Explicit crop dimensions (width:height:x:y)
--letterbox <PX> Remove top/bottom black bars of given pixel height
--pillarbox <PX> Remove left/right black bars of given pixel width
-p, --preview Generate a JPEG preview of the crop region (video only)
-r, --replace Replace existing output

fix — Fix file extension and issues

ff fix [--replace] <FILES>...

Detects the true file format and corrects the extension. Also fixes filenames starting with - and corrects JPEG display aspect ratio (DAR) issues.

Option Description
-r, --replace Replace existing output

flip — Flip video

ff flip <FILES>...

Flips video horizontally or vertically using stream copy (no re-encode).

jpeg — Convert to JPEG

ff jpeg [--replace] <FILES>...

Converts images to JPEG. Skips files already in JPEG format.

Option Description
-r, --replace Replace existing output (removing original)

join — Join videos

ff join --output <FILE> [--replace] <FILES>...

Concatenates multiple MP4 files into one. All inputs must have the same dimensions.

Option Description
-o, --output <FILE> Output filename (required)
-r, --replace Replace existing output

levels — Auto-adjust colour levels

ff levels [--strength <F>] [--no-colour-correction] [--replace] <FILES>...

Auto-adjusts colour cast and contrast for MP4 video or JPEG images. Applies grey-edge colour cast correction followed by auto-levels normalisation.

Option Description
--strength <F> Normalisation strength, 0.0 to 1.0 (default 0.7)
--no-colour-correction Disable automatic colour cast correction
-r, --replace Replace existing output

mono — Stereo to mono

ff mono [--replace] <FILES>...

Converts stereo audio to mono by mixing channels.

Option Description
-r, --replace Replace existing output

normalise — Normalise audio levels

ff normalise [--check] [--replace] <FILES>...

Normalises MP3 audio loudness to EBU R128 targets (−13 LUFS integrated, −1.5 dBTP peak).

Option Description
-c, --check Report current levels without modifying
-r, --replace Replace existing output

organise — Normalise and organise media

ff organise [--max-height <H>] [--optimise] [<FILES>...]

Normalises media files in bulk: fixes file extensions, converts images to JPEG, converts video to H265/AAC MP4, downscales tall media, optimises JPEGs, and renames each file to its perceptual hash. Defaults to the current directory if no files are given.

Option Description
-m, --max-height <H> Downscale media taller than this height (default 1920)
-o, --optimise Force recoding/optimising even if already processed

ratio — Set display aspect ratio

ff ratio [--replace] <FILES>...

Corrects the display aspect ratio (DAR) metadata without re-encoding.

Option Description
-r, --replace Replace existing output

resize — Resize video or image

ff resize [--width <W>] [--height <H>] [--replace] [--smaller] <FILES>...

Resizes MP4 video or JPEG images. One of --width or --height is required; the other is calculated to preserve aspect ratio.

Option Description
-w, --width <W> Output width (must be divisible by 2)
-h, --height <H> Output height (must be divisible by 2)
-r, --replace Replace existing output
-s, --smaller Replace only if the result is smaller

rotate — Rotate video

ff rotate <ANGLE> [--replace] <FILES>...

Sets the display rotation metadata for MP4 files (stream copy, no re-encode).

Argument Description
ANGLE Rotation angle: 0, 90, 180, or 270
Option Description
-r, --replace Replace existing output

silence — Remove audio

ff silence [--replace] <FILES>...

Removes the audio track from video files (stream copy).

Option Description
-r, --replace Replace existing output

split — Split MP4

ff split [--at <TIMESTAMPS>] [--chapters] [--replace] <FILES>...

Splits MP4 files at specified timestamps or by chapter markers.

Option Description
--at <TIMESTAMPS> Comma-separated split points (seconds or hh:mm:ss)
--chapters Split at chapter boundaries
-r, --replace Replace existing output

subs — Embed SRT subtitles

ff subs <hard|soft> [--replace] <FILES>...

Embeds an .srt subtitle file (same name as the video) into the MP4.

Argument Description
hard Render subtitles into the video (burned in)
soft Embed as a selectable subtitle stream
Option Description
-r, --replace Replace existing output

trim — Trim start or end

ff trim [--start <TIME>] [--end <TIME>] [--duration <TIME>] [--intro] [--outro] [--threshold <F>] [--quick] [--replace] <FILES>...

Trims video from a start time, to an end time or duration. --intro and --outro auto-detect and remove mostly-black sections at the start or end.

Option Description
--start <TIME> Start time offset (seconds or hh:mm:ss)
--end <TIME> End time (seconds or hh:mm:ss)
--duration <TIME> Duration to keep
--intro Auto-detect and remove black intro
--outro Auto-detect and remove black outro
--threshold <F> Black detection threshold 0.01.0
--quick Trim to nearest keyframe (fast but imprecise)
-r, --replace Replace existing output

trim-silence — Trim silence from MP3

ff trim-silence [--replace] <FILES>...

Removes silence from the start and end of MP3 files.

Option Description
-r, --replace Replace existing output

Filter DSL

Use -f / --filter to select files by attributes before processing.

Fields and operators

Field Operators Example
bit_rate < <= = != >= > bit_rate > 5000
fps < <= = != >= > fps >= 25
duration < <= = != >= > duration < 5m
size < <= = != >= > size > 100m
width, height < <= = != >= > width >= 1920
ext = != in not in ext in mp4,mkv
video_codec = != in not in video_codec = h264
audio_codec = != in not in audio_codec in aac,mp3

Flags

has_video, no_video, has_audio, no_audio, has_dar, no_dar, is_image, no_image, has_chapters, no_chapters

Tags

Expression Description
tag:<name> File has a tag with the given name
tag:* File has any metadata tag
tag:<name> = value Named tag equals value (case-insensitive)
tag:<name> != value Named tag does not equal value
tag:<name> ~ value Named tag contains value (case-insensitive)
tag:<name> !~ value Named tag does not contain value
tag:* = value Any tag equals value
tag:* ~ value Any tag contains value

Tag names and values are case-insensitive. Values containing spaces must be quoted: tag:comment ~ "i like cheese".

Operators

and, or, not, parentheses for grouping.

Value formats

  • Duration: 5m, 1h30m, 01:30:00
  • Size: 500m, 1g, 100k
  • List: h264,h265
  • String: test, "i like cheese" (quote values containing spaces)

Examples

ff info *.mp4 -f 'fps >= 25 and no_audio'
ff mp4 videos/ -f 'video_codec in h264,hevc and duration > 1m'
ff info * -f 'is_image and size > 1m'
ff recode . -f '(video_codec = h264 or video_codec = vp9) and width >= 1920'
ff info * -f 'tag:comment ~ cheese'
ff info * -f 'tag:* ~ "i like cheese"'
ff info * -f 'not tag:comment'

All keywords, field names, tag names, and string values are case-insensitive. Field and flag names accept underscores or hyphens interchangeably (e.g. bit_rate and bit-rate are equivalent).

Run ff --filter-help for the full reference.


Notes

  • Output files are written to a .part temporary file and renamed atomically on success.
  • Source file modification times are preserved on output files.
  • Ctrl+C cleans up partial output files automatically.
  • Progress bars show size, estimated final size, and ETA during long operations.

find-hq-music

Searches YouTube for high-quality music videos, appending "hd remastered" to queries. Returns up to 15 results with colour-coded titles.
README

find-hq-music

Searches YouTube for high-quality music videos, appending hd remastered to the query automatically. Returns up to 15 results with colour-coded titles.

Usage

find-hq-music <QUERY>...

Arguments

Argument Description
QUERY Search terms (joined with spaces)

Output

Each result is printed as a YouTube URL followed by the channel name and title. Titles are colour-coded:

  • Bright blue — official releases (VEVO channels or licensed uploads)
  • Bright white — titles containing HD, HQ, or "remastered"
  • Dimmed — other results

Configuration

Requires a YouTube Data API v3 key in ~/.config/glob-util/youtube.properties:

api-key=YOUR_KEY_HERE

Example

find-hq-music li kwan point zero

git-auto-commit

Analyses Git changes and generates commit messages using Claude AI. Presents a proposed message for interactive review before committing.
README

git-auto-commit

Analyses staged or unstaged Git changes and generates a commit message using Claude AI. Presents the proposed message for interactive review before committing.

Usage

git-auto-commit [OPTIONS]

Options

Option Description
--cli Force use of the Claude CLI (even if an API key is configured)
--api Force use of the Claude API
-n, --no-verify Bypass pre-commit and commit-msg hooks
-p, --push Push after committing
--debug-prompt Print the prompt sent to Claude
--debug-request Print the full JSON request sent to Claude
--debug-response Print the full JSON response from Claude

Interactive Prompt

After generating a message, the following options are presented:

Key Action
y Accept and commit
n Abort
r Reroll (regenerate with a smarter model)
s / l Switch between single-line and multi-line format
e Edit the message inline
d Show the full diff
f Show all changed files (when list is truncated)
p Add extra context for the next generation

Configuration

Uses the Claude CLI by default. To use the API directly, set an API key in ~/.config/glob-util/claude.properties:

api-key=YOUR_KEY_HERE

Notes

  • If changes are not staged, the tool stages them automatically before committing.
  • Large diffs are reduced to fewer context lines; very large diffs prompt for confirmation.
  • Rerolls use a smarter Claude model for better results.
  • macOS only.

git-outgoing-list

Lists unpushed commits in the current repository, showing short SHAs and titles.
README

git-outgoing-list

Lists unpushed commits in the current repository, showing short SHAs and commit titles.

Usage

git-outgoing-list

No options. Discovers the repository from the current directory. macOS only.

Output

Each unpushed commit is printed as a short SHA (9 characters, yellow) followed by the commit title.

Example

a1b2c3d4e  fix typo in README
f6e5d4c3b  add new feature

git-outgoing-review

Shows full diffs for all unpushed commits in chronological order.
README

git-outgoing-review

Shows full diffs for all unpushed commits in chronological order, piped through less.

Usage

git-outgoing-review

No options. Discovers the repository from the current directory. macOS only.

Notes

  • Commits are shown in chronological order (oldest first).
  • Uses git show --pretty=medium --color for each commit.
  • Output is paged through less --raw-control-chars to preserve colour.
  • SIGPIPE (e.g. quitting less early) is handled gracefully.

git-todo

Lists open GitHub issues for the current repository with colour-coded output. Automatically discovers the repo from the current directory's git remote.
README

git-todo

Lists open GitHub issues for the current repository with colour-coded output. Automatically discovers the repository from the current directory's git remote.

Usage

git-todo [OPTIONS]

Options

Option Description
-n, --new Open the new issue page in a browser

Output

Each issue is displayed as:

<url> #<number> [label] title
  • URLs are shortened via s.glob.au if an API token is configured (and cached per-repo).
  • Issue numbers are green, labels are shown in brackets, titles are yellow.

Configuration

Requires a GitHub API token in ~/.config/glob-util/github.properties:

api-token=YOUR_TOKEN_HERE

macOS only.

Optionally, an s.glob.au API token for URL shortening in ~/.config/glob-util/s.glob.au.properties:

api-token=YOUR_TOKEN_HERE

git-url

Generates GitHub URLs for the current repository or current commit. Automatically discovers the repository from the git remote; optionally opens in a browser.
README

git-url

Generates the GitHub URL for the current repository or the current commit. Automatically discovers the repository from the git remote; optionally opens in a browser.

Usage

git-url [OPTIONS]

Options

Option Description
-o, --open Open the URL in the default browser
-c, --commit Output the URL for the current HEAD commit
-q, --quiet Warnings and errors only

macOS only.

Examples

# print repository URL
git-url

# print URL for current commit
git-url --commit

# open repository in browser
git-url --open

# open current commit in browser
git-url --commit --open

git-vendor

Manages vendored code from external git repositories, tracked in .gitvendor. Supports checking for updates, diffing against upstream, and updating in place.
README

git-vendor

Manages vendored code from external git repositories, tracked in .gitvendor. Supports adding, checking for updates, diffing against upstream, and updating in place.

Usage

git-vendor [OPTIONS] <COMMAND>

Global Options

Option Description
--repo-path <PATH> Path to repository (overrides current directory)
-q, --quiet Warnings and errors only

Commands

add — Add a vendored repository

git-vendor add <URL> <DST_PATH> [--path <SRC_PATH>] [--verbose]

Clones a repository and copies it (or a subdirectory) into the destination path.

Argument Description
URL Git repository URL
DST_PATH Local destination path
-p, --path <SRC_PATH> Subdirectory within the source repo to vendor
-v, --verbose Verbose output

check — Check for updates

git-vendor check

Reports which vendored repositories are out of date compared to their upstream.

diff — Show upstream diff

git-vendor diff [--no-pull] [--path <PATH>]

Shows the diff between the local vendored copy and the current upstream.

Option Description
-n, --no-pull Skip pulling from source
-p, --path <PATH> Check only the specified local path

list — List vendored repositories

git-vendor list

Lists all vendored repositories with their local paths, source repos, and status. Alias: ls.

remove — Remove a vendored repository

git-vendor remove <DST_PATH>

Removes a vendored repository from the local tree and from .gitvendor.

update — Update vendored repositories

git-vendor update [--force] [--path <PATH>] [--no-pull]

Pulls upstream changes and syncs them into the local vendored paths.

Option Description
-f, --force Overwrite local modifications
-p, --path <PATH> Update only the specified local path
-n, --no-pull Skip pulling from source

Notes

  • macOS only.
  • A .git-vendored file is written in each vendored directory recording the source URL and commit.
  • Local modifications to vendored files block updates unless --force is used.

is-alive

Network connectivity checker with DNS resolution and ICMP ping or TCP port testing. Supports wait modes to poll until a host comes online or goes offline.
README

is-alive

Network connectivity checker with DNS resolution and ICMP ping or TCP port testing. Supports wait modes to poll until a host comes online or goes offline.

Usage

is-alive [OPTIONS] <HOSTNAME> [PORT]

Arguments

Argument Description
HOSTNAME Hostname or IP address to check
PORT TCP port to test (uses ICMP ping if omitted)

Options

Option Description
-n, --nameserver <NS> DNS nameserver to use (default: 1.1.1.1)
-s, --system Use the system nameserver instead
-r, --no-ping Resolve only, skip connectivity test
-p, --no-resolve Skip DNS resolution, use hostname/IP directly
-w, --wait Poll until the host responds
--wait-offline Poll until the host stops responding
-d, --wait-delay <SECS> Seconds between polls in wait mode (default: 5)
-t, --times Show timestamps on each check
-q, --quiet Warnings and errors only

Examples

# check if host responds to ICMP ping
is-alive example.com

# check if TCP port 443 is open
is-alive example.com 443

# wait until host comes online, checking every 10 seconds
is-alive --wait --wait-delay 10 example.com

# wait until host goes offline
is-alive --wait-offline example.com

# resolve hostname only
is-alive --no-ping example.com

# use system DNS resolver
is-alive --system example.com

Notes

  • IP addresses passed as HOSTNAME trigger a reverse DNS lookup; the resolved hostname is displayed but the IP is used for connectivity testing.
  • Network operations time out after 2 seconds.
  • Exit code is non-zero if the host does not respond (in single-check mode).

monit-notify

Sends Slack notifications when a Monit service changes status, designed for cron use. Skips if offline or Monit is not running.
README

monit-notify

Sends Slack notifications when a Monit service changes status. Designed for cron use — silently skips if offline or Monit is not running.

Usage

monit-notify [OPTIONS] <URL>

Arguments

Argument Description
URL Slack incoming webhook URL (https://hooks.slack.com/...)

Options

Option Description
--quiet Warnings and errors only
--test Send a test notification and exit

How it works

On each run, monit-notify queries the Monit HTTP API (port 2812) for current service statuses and compares them against the previous state stored in ~/.monit-notify. Any services whose status has changed since the last run trigger a Slack notification.

Notification format:

[hostname] service-name: status

Notes

  • Silently exits if there is no internet connection or Monit is not listening on port 2812.
  • State is persisted between runs; only changes trigger notifications.
  • Use with cron, e.g. every 5 minutes: */5 * * * * monit-notify https://hooks.slack.com/...

mp3

Displays MP3 metadata (tags, duration, bitrate, sample rate) for files or directories. Supports recursion, summary statistics, and compact or detailed output.
README

mp3

MP3 utilities.

Sub-commands

info

Displays MP3 metadata (tags, duration, bitrate, sample rate) for files or directories. Supports recursion, summary statistics, and compact or detailed output.

fix

Cleans MP3 filenames and synchronises ID3 tags from the filename. Normalises whitespace, dashes, and capitalisation; removes (Original Mix); converts year format to [YYYY] brackets. Sets title, artist, album, author, and year tags from the filename, and strips all non-core tags.

Usage

mp3 info [OPTIONS] <FILES>...

Arguments

Argument Description
FILES MP3 files or directories to inspect

Options

Option Description
-r, --recurse Recurse into subdirectories
-l, --long Long format: show all tags, bitrate, and sample rate
-s, --summary Show a summary line after all files
-o, --only-summary Show summary only, suppress per-file output

Output formats

Default (one line per file):

filename: 3:45 8.5m

Long (-l):

filename.mp3
  Duration:    3:45
  Size:        8.5m
  Bit Rate:    320,000bps
  Sample Rate: 44,100Hz
  Artist:      ...
  Title:       ...
  ...

Summary (-s or -o):

Total: 12 files 45:30 102m

Notes

  • Non-MP3 files are silently skipped.
  • Hidden files and directories (starting with .) are skipped.
  • Files are processed in case-insensitive alphabetical order.
  • Tags displayed include: title, artist, album, track, date, genre, and many others.

fix

mp3 fix [OPTIONS] <FILES>...

Arguments

Argument Description
FILES MP3 files or directories to process

Options

Option Description
-r, --recurse Recurse into subdirectories
-y, --require-year Require a year in the filename; prompts interactively if missing
-a, --album <ALBUM> Set album tag: a literal string, a directory path, or an MP3 file to copy the album tag from
-f, --force Ignore filename validation errors and process the file anyway

Filename format

fix expects filenames in one of these forms:

Artist - Title [YYYY].mp3
Artist - Title.mp3

Tags are derived entirely from the filename stem. The artist field is also written to the author (lyricist) tag.

Filename normalisation

Before writing tags, fix renames the file if the stem needs cleaning:

  • Collapses multiple spaces and normalises em/en dashes to -
  • Applies title case to both the artist and title components
  • Removes (Original Mix) suffix
  • Converts (YYYY) year suffixes to [YYYY] bracket format
  • Ensures a space before a trailing [YYYY] bracket

Tag behaviour

  • Sets: Title, Artist, Album, Author (lyricist), and Year
  • Removes all other ID3 frames (cover art, comments, encoder info, etc.)
  • Tags are written as ID3v2.3

Validation

Filenames are checked for disallowed patterns before processing:

  • feat. / featuring
  • pres. / presents
  • More than one - separator (e.g. Artist - Title - Remix)
  • Missing title (filename does not match Artist - Title format)

Use -f / --force to skip validation and process the file regardless.

mtime-filename

Encodes file modification times into filenames, or decodes them back. Useful for preserving original mtimes when files must be edited.
README

mtime-filename

Encodes file modification times into filenames, or decodes them back. Useful for preserving original mtimes when files must be transferred through systems that don't preserve timestamps.

Usage

mtime-filename [OPTIONS] <FILES>...

Arguments

Argument Description
FILES Files or directories to process

Options

Option Description
-e, --encode Encode only (skip files that are already encoded)
-d, --decode Decode only (skip files that are not encoded)

Without --encode or --decode, both operations are applied as appropriate: un-encoded files are encoded, and encoded files are decoded.

Filename format

Encoded filenames have the form:

mtime(UNIX_TIMESTAMP)original-filename.ext

For example:

mtime(1700000000)photo.jpg

Behaviour

Encode: reads the file's mtime, prepends mtime(UNIX_TIMESTAMP) to the filename, and renames the file.

Decode: strips the mtime(...) prefix, sets the file's mtime to the encoded timestamp, and renames the file back to its original name.

Files are not overwritten if the target name already exists.

opt

Installs and manages tools in /opt from PyPI, NPM, crates.io, or GitHub. Creates virtualenvs, builds Rust projects, and manages /usr/local/bin symlinks.
README

opt

Installs and manages tools in /opt from PyPI, NPM, crates.io, or GitHub. Creates isolated environments (virtualenvs, Cargo builds), and manages /usr/local/bin symlinks.

Usage

opt [OPTIONS] <COMMAND>

Global Options

Option Description
-q, --quiet Warnings and errors only

Commands

add — Install a tool

opt add <SOURCE> [--name <NAME>] [--python-version <VER>]

Installs a tool from a package registry or GitHub. The source prefix determines the repository:

Prefix Repository Example
py: PyPI py:black
node: / npm: NPM node:prettier
rust: crates.io rust:ripgrep
GitHub URL GitHub releases https://github.com/user/repo
(no prefix) auto-detected black

If exactly one binary is installed, a symlink is created in /usr/local/bin automatically. Alias: install.

Option Description
-n, --name <NAME> Override the tool name
--python-version <VER> Python version to use for the virtualenv

delete — Remove a tool

opt delete <NAME>

Removes the tool directory and any /usr/local/bin symlinks. Aliases: del, uninstall, remove, rm.

link — Create symlinks

opt link <SCRIPTS>...

Creates /usr/local/bin symlinks for the specified scripts within a tool. Alias: ln.

unlink — Remove symlinks

opt unlink <SCRIPTS>...

Removes /usr/local/bin symlinks for the specified scripts.

list — List installed tools

opt list [--short] [--long]

Lists all tools managed by opt.

Option Description
-s, --short Names only
-l, --long Include repo, version, last-updated, and provided binaries

update — Update tools

opt update [<NAME>]

Updates all tools (or a specific tool) to their latest versions. Aliases: up, fix.

Notes

  • /opt must be owned by the current user.
  • Tool metadata is stored in /opt/opt.ini.

radio

Plays an internet radio stream (Icecast/Shoutcast) or local MP3 files in the terminal with a live spectrum visualiser.
README

radio

Plays an internet radio stream (Icecast/Shoutcast) or local MP3 files in the terminal with a live spectrum visualiser. Searches a station list by name, accepts a direct stream URL, or plays a local MP3 file or directory. Displays track titles, supports volume and pause, and reconnects automatically on disconnect.

Usage

radio [OPTIONS] [QUERY]...
radio --update
radio --control <COMMAND>

Arguments

Argument Description
QUERY Station name, direct stream URL, or path to an MP3 file or directory
--volume <N> Initial volume, 0–100 (default: 100)
--update Refresh the station list from remote sources
--list List all stations
--control <COMMAND> Send a command to the running instance

Valid control commands: pause, resume, quit, status

Status responses: stopped, connecting, playing, paused

Keys

Key Action
Space Pause / resume
Play/Pause media key Pause / resume
n Next track (file mode only)
- Volume down
= Volume up
r Reconnect
q / Esc Quit
Ctrl-C Quit

Examples

# search for a station by name
radio progressive

# multi-word search
radio liquid drum and bass

# play a direct stream URL
radio https://example.com/synthwave

# play a single MP3 file
radio ~/music/song.mp3

# play all MP3s in a directory (shuffled)
radio ~/music/albums/kraftwerk

# start at 50% volume
radio --volume 50 progressive

# refresh the station list
radio --update

# signal the first running instance
radio --control pause
radio --control resume
radio --control quit
radio --control status

Configuration

Station lists are loaded from ~/.config/glob-util/radio.toml. The file must contain an [Audio Addict] section with a listen_key for DI.FM and Radio Tunes access. Custom stations can be added as additional sections:

["Audio Addict"]
listen_key = "your-listen-key"

["My Station"]
url = "https://example.com/stream"
description = "An example station"
keywords = "example test"  # space delimited

Notes

  • If the query matches multiple stations, a list is shown instead of playing.
  • If the query is a valid HTTP/HTTPS URL it is used directly, bypassing the station list.
  • If the query is a path to a local .mp3 file or directory, it plays locally.
  • When playing a directory, all MP3 files are found recursively and shuffled; n advances to the next track.
  • The station list is cached and refreshed with --update; if no cache exists, an update runs automatically.
  • The stream name from ICY headers is shown on connect for streams; the filename stem is shown as the track title for local files.
  • Volume adjusts in 1% increments and is shown briefly in the display.
  • On stall or disconnect, reconnection is attempted with exponential backoff (up to 30s).
  • The Play/Pause media key works globally when the terminal app has Accessibility permission.
  • The first running radio instance creates $TMPDIR/radio.sock; later instances keep playing without a control socket.

sandbox

Runs a command within a macOS sandbox using layered profiles to restrict filesystem and network access, primarily for isolating AI agents such as Claude and Codex.
README

sandbox

Runs a command within a macOS sandbox using layered profiles to restrict filesystem and network access, primarily for isolating AI agents such as Claude and Codex.

Usage

sandbox [OPTIONS] <COMMAND>...

Arguments

Argument Description
COMMAND Command to run

Options

Option Description
-p, --profile <P> Custom profile to append (see Profiles below)

Profiles

Profiles are macOS sandbox policy files (.sb) stored in ~/.config/glob-util/sandbox/. Three layers are applied in order:

BASE

BASE.sb is overwritten on every run and exists only as a reference — do not edit it. It defines the core policy:

  • Denies everything by default.
  • Allows all network access.
  • Allows read access to system paths (/usr, /bin, /opt, etc.).
  • Allows read/write access to the current working directory, /tmp, and standard devices.

Ancestors of the current working directory are granted read access so processes can traverse the path.

default

default.sb is created in ~/.config/glob-util/sandbox/ if it does not already exist, and is applied after BASE on every run. Edit it to add permissions that should always be available. The shipped default grants read/write access to common tool data directories:

  • Git: ~/.gitconfig, ~/.config/git
  • gh CLI: ~/.config/gh
  • Claude: ~/.claude, ~/.cache/claude
  • Codex: ~/.codex
  • Rust: ~/.cargo, ~/.rustup
  • uv: ~/.cache/uv, ~/.local/share/uv

Custom profiles

A named profile can be appended after the default using --profile. The profile file must exist at ~/.config/glob-util/sandbox/<NAME>.sb.

sandbox --profile my-profile claude --dangerously-skip-permissions .

Use custom profiles to grant additional permissions for a specific agent or task without widening the default policy.

Examples

# run claude-code with default policy
sandbox claude --dangerously-skip-permissions .

# run codex with an additional profile granting extra access
sandbox --profile codex-extra codex

# run an arbitrary command in the sandbox
sandbox python3 script.py

Notes

  • macOS only — relies on sandbox-exec.
  • Network access is fully allowed by default; restrict it in a custom profile if needed.
  • BASE.sb is overwritten on every invocation — any edits will be lost.

shorten-url

Generates shortened URLs using the s.glob.au URL shortening service.
README

shorten-url

Generates shortened URLs using the s.glob.au URL shortening service.

Usage

shorten-url <URL>

Arguments

Argument Description
URL URL to shorten

Configuration

An API token is required in ~/.config/glob-util/s.glob.au.properties:

api-token=YOUR_TOKEN_HERE

Example

shorten-url https://example.com/some/very/long/path
# outputs: https://s.glob.au/abc123

sleep-random

Sleeps for a random duration (0 to max seconds) before executing a command. Useful for staggering cron tasks; preserves the command's exit code.
README

sleep-random

Sleeps for a random duration between 0 and the specified maximum, then executes a command. Useful for staggering cron tasks across multiple hosts to avoid thundering-herd problems. Preserves the command's exit code.

Usage

sleep-random <SECONDS> <COMMAND>...

Arguments

Argument Description
SECONDS Maximum number of seconds to sleep
COMMAND Command to run after sleeping

Example

# sleep 0–300 seconds, then run backup
sleep-random 300 /usr/local/bin/backup.sh

# in crontab (stagger a nightly job across multiple machines)
0 2 * * * sleep-random 3600 /usr/local/bin/nightly.sh

Notes

  • The sleep duration is chosen uniformly at random in [0, SECONDS].
  • The exit code of COMMAND is returned as the exit code of sleep-random.

slideshow

Finds image and video files and plays them in mpv as a slideshow. Supports shuffle/sort modes, filename filtering, and configurable image duration.
README

slideshow

Finds image and video files and plays them in mpv as a slideshow. Supports shuffle/sort modes, filename filtering, and configurable image duration.

Requires mpv to be installed. macOS only.

Usage

slideshow [OPTIONS] [ARGS]...

Arguments can be file paths, directory paths, or plain words treated as filename filters.

Paths

Option Description
-r, --recursive Scan directories recursively
ARGS Files, directories, or filename filter terms
-x, --exclude <PATH> Exclude path(s) from results (repeatable)
-o, --or Match files containing any filter term (default: all terms must match)

Type filter

Option Description
-i, --images Show only images (gif, png, jpeg, jpg, webp)
-v, --videos Show only videos (mp4, mkv, avi, etc.)

Sort order (mutually exclusive)

Option Description
--shuffle Random order (default)
-N, --name Alphabetical by filename
-n, --newest Newest files first (by modification time)
-S, --size Largest files first
-R, --reverse Reverse the sort order

Output

Option Description
-l, --loop Loop each video
-m, --mute Start muted
-w, --windowed Play in a window instead of fullscreen
-d, --delay <SECS> Seconds to display each image
-q, --quiet Warnings and errors only
--list Print filenames to stdout instead of launching mpv

Examples

# shuffle all media in current directory
slideshow

# show images from a directory, newest first
slideshow -i -n ~/Photos

# filter by filename (all terms must match)
slideshow holiday beach

# filter by filename (any term matches)
slideshow -o holiday beach

# recursive scan, largest videos first
slideshow -r -v -S ~/Videos

# list matching files without launching mpv
slideshow --list holiday

Notes

  • If no paths are given, the current directory is scanned.
  • Non-path arguments (words without /) are treated as filename filters.
  • Files are deduplicated by canonical path — overlapping directories and symlinks are handled correctly.
  • Directory scanning runs in parallel and shows a progress indicator if it takes longer than 500ms.
  • Supported video formats: 3gp, asf, avi, divx, flv, mkv, mp4, mpg, mpeg, mov, webm, wmv, and others.
  • Supported image formats: gif, png, jpeg, jpg, webp.

smb-mounter

Manages SMB/CIFS network share mounts with stored credentials for quick remounting after reboot or disconnection.
README

smb-mounter

Manages SMB/CIFS network share mounts with stored credentials for quick remounting after reboot or disconnection. Credentials are stored in the macOS keychain. macOS only.

Usage

smb-mounter [OPTIONS] <COMMAND>

Global Options

Option Description
-q, --quiet Warnings and errors only

Commands

add — Add and mount a share

smb-mounter add <MOUNT_PATH> <HOSTNAME> <SHARE> [--username <USER>]

Registers a new SMB share and mounts it immediately. Prompts for a password and stores it in the keychain.

Argument Description
MOUNT_PATH Local directory to mount the share on (must exist)
HOSTNAME Remote server hostname
SHARE Share name on the remote server
-u, --username <USER> Username (defaults to current user)

list — List configured mounts

smb-mounter list

Lists all configured mounts and their current state. Alias: ls.

mount — Mount shares

smb-mounter mount [MOUNT_PATH]

Mounts all configured shares (or a specific one). Already-mounted shares are skipped.

Argument Description
MOUNT_PATH Mount only this path (optional)

unmount — Unmount a share

smb-mounter unmount <MOUNT_PATH>

Unmounts the share at the given path.

remove — Remove a configured mount

smb-mounter remove <MOUNT_PATH>

Removes a mount from the configuration. Aliases: rm, del.

Notes

  • Mount options: noatime,nodev,nosuid,nobrowse.
  • If authentication fails during add, the password prompt is retried automatically.
  • Configuration is stored in ~/.config/smb-mounter/config.toml.

update-local-bin

wait-exists

Waits for files or glob patterns to exist (or not exist), polling every second. Exits successfully when the condition is met, or fails on timeout.
README

wait-exists

Waits for files or glob patterns to exist (or not exist), polling every second. Exits successfully when the condition is met, or fails on timeout.

Usage

wait-exists [OPTIONS] <FILES>...

Arguments

Argument Description
FILES File paths or glob patterns to wait for

Options

Option Description
-n, --not Wait for all files to be deleted rather than created
-t, --timeout <SECS> Fail after this many seconds (must be > 0)
-v, --verbose Print "waiting..." every 10 seconds

Examples

# wait for a file to appear
wait-exists /tmp/lock

# wait for a glob pattern to match
wait-exists /var/run/*.pid

# wait for a file to be deleted, with a 60-second timeout
wait-exists --not --timeout 60 /tmp/lock

# wait with verbose output
wait-exists --verbose /tmp/done

Notes

  • Polls every 1 second.
  • Glob patterns are expanded on each poll, so newly created matches are detected.
  • Without --timeout, waits indefinitely.
  • Exit code is non-zero on timeout.

youtube-dl

yt-dlp wrapper with sensible defaults for video downloads. Converts to MP4 and embeds English subtitles by default, accepts bare YouTube video IDs, and skips files that already exist.
README

youtube-dl

yt-dlp wrapper with sensible defaults for video downloads. Converts to MP4 and embeds English subtitles by default, accepts bare YouTube video IDs, and skips files that already exist.

Requires uv to be installed. yt-dlp is installed and updated automatically. aria2c is optional and enables threaded downloads with --threaded.

Usage

youtube-dl [OPTIONS] [URL|ID]...

URLs and bare 11-character YouTube video IDs are accepted. All other arguments are passed through to yt-dlp.

Defaults

The following are applied to every download:

  • Converts to MP4 (--recode-video mp4)
  • Embeds English subtitles (--write-sub --sub-lang en --embed-subs)
  • Names output files after the media title (%(title)s.%(ext)s)
  • Skips files that already exist

Site Defaults

Site Default
YouTube, youtu.be 1080p, unless --format, -f, --extract-audio, or -x is given
Vimeo 1080p, unless --format, -f, --extract-audio, or -x is given
SoundCloud MP3

YouTube URLs have time_continue and t query string parameters stripped automatically.

Options

Option Description
--mp3 Download and convert to MP3
--480, --480p Request 480p video
--720, --720p Request 720p video
--1080, --1080p Request 1080p video
--no-mp4, --nomp4 Retain original format; don't convert to MP4
--no-subs, --nosubs Don't download and embed subtitles
--threaded, --aria2, --aria2c Download multi-threaded using aria2
--expand-playlist, --playlist-urls Expand playlist into individual URLs
--test Print full yt-dlp command without executing

Examples

# download a YouTube video by URL
youtube-dl https://www.youtube.com/watch?v=dQw4w9WgXcQ

# download by bare video ID
youtube-dl dQw4w9WgXcQ

# download as MP3
youtube-dl --mp3 https://www.youtube.com/watch?v=dQw4w9WgXcQ

# download at 720p instead of the default 1080p
youtube-dl --720p https://www.youtube.com/watch?v=dQw4w9WgXcQ

# threaded download using aria2c
youtube-dl --threaded https://www.youtube.com/watch?v=dQw4w9WgXcQ

# preview the full yt-dlp command without running it
youtube-dl --test https://www.youtube.com/watch?v=dQw4w9WgXcQ

# expand a playlist into individual URLs
youtube-dl --expand-playlist https://www.youtube.com/playlist?list=PLxxx

Notes

  • yt-dlp is installed to a private cache directory via uv and updated automatically once per day.
  • On macOS, Deno is also installed automatically for yt-dlp's JavaScript engine support.
  • File info is displayed via ff info after a successful download if ff is installed.
  • Pass --update or -U to force an immediate update of yt-dlp.