Skip to content

Usage

goodmorning-claude provides four subcommands for managing and firing the daily ping. All commands require macOS — the CLI refuses to run on any other platform.

install — Install the daily schedule

goodmorning-claude install [--time HH:MM ...]

Writes a LaunchAgent plist to ~/Library/LaunchAgents/com.waterjuice.goodmorning-claude.plist and loads it with launchctl bootstrap. The schedule fires at each specified wall-clock time every day. Default is 07:05 12:10 17:15 if --time is omitted — three pings spaced 5h05m apart, just over the 5-hour window length, so each one lands after the previous window has closed and opens a fresh one that carries through to the next.

# Default: 07:05, 12:10 and 17:15 every day
goodmorning-claude install

# A single custom time
goodmorning-claude install --time 06:30

# Several custom times (space-separated)
goodmorning-claude install --time 07:00 13:00 18:00

Times are sorted and de-duplicated, so order does not matter and repeats are collapsed.

Option Description
--time, -t One or more times in HH:MM (default: 07:05 12:10 17:15)

Install time also finds the absolute path to claude and pins it into the plist as the GOODMORNING_CLAUDE_BIN environment variable, which run prefers over a PATH lookup. That way the schedule keeps firing even though launchd never sources your shell init scripts — which is exactly where claude tends to come from (nvm, asdf, Homebrew path munging, etc.).

The pin follows the symlink rather than resolving through it: claude is normally ~/.local/bin/claude pointing into a versioned directory that Claude Code retargets whenever it updates itself, so pinning the resolved target would leave your schedule stuck on one version — and broken once that version is cleaned up. If a pin does go stale, run falls back to a PATH lookup and status tells you to re-pin.

install refuses to run from an ephemeral location — a uvx invocation, or anything under a temp directory — because the plist records an absolute path to the executable, and a path in uv's cache can be removed by uv cache prune. Install goodmorning-claude persistently (uv tool install or pip install) before scheduling it.

uninstall — Remove the daily schedule

goodmorning-claude uninstall

Unloads the LaunchAgent (launchctl bootout) and removes the plist. Safe to run even if nothing is installed.

status — Show the current schedule

goodmorning-claude status

Reports whether the schedule is installed and, if so, at what times it is set to fire.

Installed (launchd) — fires daily at 07:05, 12:10, 17:15.

status verifies the schedule can actually run, rather than just checking that the plist file exists. Three things have to hold, and each can fail on its own:

  • launchd has the job loaded (asked directly, via launchctl print);
  • the executable the plist points at still exists;
  • the pinned Claude binary still exists.

The second one is the subtle case: launchd registers a job by absolute path and only discovers the path is dead when it tries to spawn it. A schedule whose executable was deleted — by uv tool upgrade, a rebuilt venv, a moved install — still reports as loaded, and fails silently at every fire. When something is fatally wrong, status says so and exits 1:

Installed (launchd) — fires daily at 07:05, 12:10, 17:15.

WARNING: this schedule will NOT fire.
  - the scheduled executable no longer exists: /Users/you/.local/bin/goodmorning-claude — was goodmorning-claude upgraded, moved, or uninstalled?

Re-run `goodmorning-claude install` to repair it.

A stale Claude pin is reported as a note rather than a failure, because run falls back to a PATH lookup and the ping still fires.

This makes status safe to use as a health check (goodmorning-claude status || ...).

run — Fire the ping now

goodmorning-claude run

Invokes claude -p "hi" directly with a 120-second timeout. Normally called by the scheduler; run it manually to test your setup or to open the window on demand.

When the schedule is installed, run prefers the absolute claude path that was pinned at install time (via the GOODMORNING_CLAUDE_BIN env var the LaunchAgent sets). When run from a normal shell it falls back to a PATH lookup. If claude cannot be found, run fails with a clear error.

Output:

Pinging Claude via /opt/homebrew/bin/claude...
Ping succeeded in 1.8s.

Pass -v to also print the chosen binary, the full argv, and Claude's stdout.

Global Options

Option Description
--verbose, -v Show detailed logs of every action and subprocess call (stderr)
--version Show version and exit
--license Show licence information and exit
--help Show help and exit

-v may appear either before or after the subcommand:

goodmorning-claude -v install --time 07:05
goodmorning-claude install -v --time 07:05

File Locations

Path Purpose
~/Library/LaunchAgents/com.waterjuice.goodmorning-claude.plist LaunchAgent plist
~/Library/Logs/goodmorning-claude.log Ping stdout/stderr