Canaryd logo

canaryd

A quiet health monitor for your Mac.
It detects heat and stalled apps, then recovers them without taking your focus.

Hex package versionMIT licensemacOSElixir 1.15 or later

Notifications · Install · Usage · How it works · Development


Canaryd is a local macOS watchdog. It uses exact Apple Silicon temperature data, macOS responsiveness state, and a reversible clipboard probe to find problems that a simple process check can miss.

Status at a glance

Run canaryd status to see health, recent recovery events, pending app hangs, idle Simulators, and thermal pressure.

Example Canaryd status output

The screenshot contains example values. Process names, temperatures, and events come from your Mac.

Notifications

Canaryd uses a native, signed Canaryd.app helper for Notification Center. These are real macOS notification captures generated with representative mock data. Successful background recovery stays quiet unless the recovery policy explicitly reports a result.

Thermal pressure

First hot roundClose or Restart after confirmation
Persistent high-temperature warningHigh-temperature notification with Close and Restart actions
Informational fallbackSelected action failed
Fallback high-temperature warningFailed thermal action notification

Automatic recovery results

Idle app closedIdle app could not close
Idle high-memory app closed notificationIdle high-memory app close failed notification
Simulators shut downSimulator shutdown failed
Idle Simulators shut down notificationIdle Simulator shutdown failed notification

Attention required

App restart failedApp hung again during cooldown
Unresponsive app restart failed notificationApp still unresponsive after automatic restart notification
System degradedCleanClip recovery blocked
System degraded notificationCleanClip automatic restart failed notification

Install

Install with an AI agent

Give this prompt to Codex, Claude Code, Cursor, or another coding agent:

Read https://raw.githubusercontent.com/ThaddeusJiang/canaryd/main/SKILL.md and follow its instructions to install or update Canaryd on this Mac.

Requirements

The GitHub Release executable includes Erlang and Elixir. A source or Hex installation needs Elixir 1.15 or later.

Install the system tools:

xcode-select -p >/dev/null || xcode-select --install
if [ "$(uname -m)" = "arm64" ]; then
brew install macmon
brew pin macmon
macmon --version
fi

On Apple Silicon, the last command must print macmon 0.8.0. Canaryd rejects another version until its JSON schema is verified. Intel Macs do not provide exact CPU and GPU sensor temperatures.

Install from GitHub Releases

Install the latest stable release:

curl -fsSL https://github.com/ThaddeusJiang/canaryd/releases/latest/download/install.sh | bash

The installer selects the Mac architecture, verifies SHA-256, and installs canaryd in ~/.local/bin. It adds that directory to the current shell profile when necessary. Restart the shell or run the source command that the installer prints. You can then use canaryd from any directory.

Install a downloaded archive

Open the latest GitHub Release. Download checksums-sha256.txt and the archive for the Mac:

MacArchive
Apple Siliconcanaryd-aarch64-apple-darwin.tar.gz
Intelcanaryd-x86_64-apple-darwin.tar.gz

Verify and install the downloaded archive:

cd "$HOME/Downloads"
if [ "$(uname -m)" = "arm64" ]; then
archive="canaryd-aarch64-apple-darwin.tar.gz"
else
archive="canaryd-x86_64-apple-darwin.tar.gz"
fi
grep " $archive\$" checksums-sha256.txt | shasum -a 256 -c -
tar -xzf "$archive"
mkdir -p "$HOME/.local/bin"
# Run this only after the checksum succeeds. The first releases are not notarized.
xattr -d com.apple.quarantine canaryd 2>/dev/null || true
install -m 755 canaryd "$HOME/.local/bin/canaryd"

Add the install directory to PATH if the shell cannot find canaryd:

export PATH="$HOME/.local/bin:$PATH"

Add that line to the shell profile to keep the setting.

The first GitHub releases use ad hoc code signing. They do not use Apple notarization. The checksum verifies that the download matches the release asset. It does not provide an Apple developer identity.

Install the current source

Use this method for the features documented in this repository:

git clone https://github.com/ThaddeusJiang/canaryd.git
cd canaryd
mix deps.get
mix escript.build
mix escript.install --force ./canaryd

Install the published release

The Hex package remains available for systems that already have Elixir:

mix escript.install hex canaryd 0.1.0

Add the Mix escript directory to PATH if the shell cannot find canaryd:

export PATH="$HOME/.mix/escripts:$PATH"

Add that line to the shell profile to keep the setting.

First run

canaryd status

The first command installs one launchd agent:

AgentIntervalWork
Full health check5 minutesCheck temperature, high-CPU processes, the system, GUI apps, idle memory, Simulators, and CleanClip

Every command verifies this agent. If it is missing, Canaryd creates it again. Upgrades remove the obsolete one-minute thermal agent. You do not need to manage plist files. macOS may keep the removed item visible in Background Items until the next login even though it no longer runs.

Usage

CommandPurpose
canaryd statusShow the current health snapshot and recent events
canaryd checkRun one full health check now
canaryd thermal-checkRun one thermal and high-CPU process check now
canaryd history [target]Show events for cleanclip, system, thermal, memory, simulators, or apps
canaryd installReinstall and load the launchd agent
canaryd uninstallRemove the launchd agent and the notification helper
canaryd --versionShow the installed version without changing the launchd agent

Examples:

canaryd check
canaryd history thermal
canaryd history memory
canaryd history simulators
canaryd history apps

How it works

Canaryd applies a confirmation and cooldown policy before it changes another app.

SignalDetectionResponse
CPU or GPU heatThree macmon samples; keep the highest averageNotify on the first hot round; offer an action after the same safe app leads two rounds
GUI app hangRead the state that macOS uses in Force QuitConfirm twice, then restart a supported third-party app
Idle high memoryAggregate app RSS and CPU while the user is awayConfirm three times, then request a graceful close
Idle SimulatorCombine whole-Mac inactivity with CoreSimulator device ageConfirm three times, then shut down the exact booted device
CleanClip processCheck the process with pgrepRestart it in the background when it is missing
CleanClip functionReplay the latest real history item and verify duplicate content appearsRestore the clipboard, then restart CleanClip after a failed probe
System pressureRead thermal throttling, load, and memory pressureWarn after three consecutive full checks

Safety rules

When the Mac is idle for more than 30 minutes, Canaryd skips the CleanClip functional probe. It still checks the system, GUI responsiveness, and idle high-memory apps and Simulators.

Detailed recovery policy

Thermal pressure

Canaryd keeps the highest CPU and GPU average from a three-sample window. A CPU or GPU temperature of at least 70°C causes thermal pressure. Battery temperature stays separate and does not represent chip temperature.

The first hot round sends a warning that stays in Notification Center until the user dismisses it. The warning has a 15-minute cooldown for each leading process. Canaryd lists up to five processes that use at least 20% CPU. CPU use is correlation evidence. It is not exact heat attribution.

After the same safe third-party app leads two rounds, the notification offers Close and Restart. Dismissal or timeout means Ignore. Canaryd does not activate the app or take mouse focus. Apple apps, system services, nested helper apps, and processes without a safe app bundle never get these actions. Each app has a one-hour prompt cooldown.

Idle memory recovery

During the five-minute full check, Canaryd aggregates RSS and CPU use for every current-user process inside a registered top-level app bundle. After the user has been inactive for 30 minutes, a non-active third-party app becomes a candidate when it uses at least 1 GB RSS and at most 1% aggregate CPU for three consecutive checks.

Canaryd then asks macOS to terminate the app gracefully and sends a Notification Center result. It does not force-kill an app that refuses or remains open. Apple apps, system paths, command-line daemons, nested helper bundles, other users' processes, and the active application are protected. The same app has a one-hour close cooldown.

GUI app recovery

Canaryd uses the same responsiveness state that macOS shows in Force Quit. A third-party app must be not responding in two consecutive rounds. Canaryd then stops and opens the app in the background. Each app has a one-hour restart cooldown.

The Force Quit state has no public macOS API. Canaryd resolves the interface at runtime. If a future macOS release removes it, the scan becomes unavailable and Canaryd does not stop an app.

CursorUIViewService is an explicitly supported Apple text-input service. After two failed rounds, Canaryd quietly stops the current instance and waits for launchd or an XPC client to start a new one. Successful recovery does not send a notification. A failed restart or another confirmed hang during the one-hour restart cooldown still sends a warning.

Idle Simulator shutdown

During the five-minute full check, Canaryd considers booted Simulator devices only after the user has been inactive for 30 minutes. A device must also have a CoreSimulator lastUsedAt age of at least 30 minutes and remain eligible for three consecutive checks. This makes the earliest shutdown roughly 40 minutes after both inactivity conditions begin.

Current-user xcodebuild and xctest processes reset confirmation so unattended Xcode test runs are protected. Before shutdown, Canaryd checks user inactivity and automation again, then revalidates the exact UDID and timestamp. It runs only simctl shutdown <UDID>; it never erases, deletes, or resets the device. Successful and failed shutdowns are recorded locally and reported in a batched Notification Center message.

CleanClip recovery

The functional probe replays the latest real CleanClip history item instead of creating synthetic content. CleanClip may add a duplicate row or increase an existing item's copy count. Canaryd saves every current pasteboard item and data type, then restores the snapshot only when no newer pasteboard write occurred. A user copy during the probe always wins.

A probe failure causes a quiet restart with a one-hour cooldown. Three consecutive failures during the cooldown set the target to blocked and send a notification. Canaryd records recovery automatically.

Local data

Canaryd stores all runtime data in:

~/Library/Application Support/canaryd/
├── state.dets
├── events.dets
├── stdout.log
└── stderr.log

state.dets contains the latest state-machine snapshot. events.dets contains the event history for app, thermal, system, and probe actions. The log files contain launchd output.

Uninstall

Remove the launchd agent and the notification helper:

canaryd uninstall

To remove the saved state and logs too:

rm -r "$HOME/Library/Application Support/canaryd"

Development

git clone https://github.com/ThaddeusJiang/canaryd.git
cd canaryd
mix deps.get
mix test
mix escript.build

Build the native single executable with Zig 0.16.0:

mise install zig@0.16.0
BURRITO_TARGET=macos_arm64 MIX_ENV=prod mise exec zig@0.16.0 -- mix release --overwrite
./burrito_out/canaryd_macos_arm64 --version

The project uses pure Elixir/OTP, DETS storage, launchd, and a small Swift notification helper.

License

MIT