Canaryd logo

canaryd

A quiet health monitor for developer Macs.
It catches stalled services, forgotten Simulators, silent utilities, heat, idle memory, and stale build output — then recovers what it safely can.

Hex package versionMIT licensemacOSElixir 1.15 or later

Stories · Status · Install · Commands · Safety

Canaryd recovers six common developer-Mac problems
The 20-second story reel plays inline. Click it for the MP4.


Canaryd is a local macOS watchdog. Every five minutes it checks real system and application behavior; once a day it reclaims validated stale build output. It confirms suspicious state before acting and keeps successful background recovery quiet. State, events, and logs stay on the Mac.

Why Canaryd exists

1. CursorUIViewService hangs again

CursorUIViewService is an Apple text-input XPC service. Despite its name, it is unrelated to the Cursor editor. When the service stalls, macOS marks it as Not Responding and ordinary process-liveness checks still see a running PID.

On one developer Mac, Canaryd recorded eight confirmed hangs and eight successful recoveries in a day. Canaryd matches the exact Apple service identity, confirms the hang twice, stops only the stale instance, and waits for a replacement PID. It does not restart the editor, switch apps, or show a foreground alert.

CursorUIViewService changes from Not Responding to a replacement process after quiet Canaryd recovery

2. An AI agent finishes, but its Simulators keep running

An AI coding agent can build and test several iOS device profiles, then leave the booted Simulators behind after the task ends. One real investigation found three booted devices that had been running for 15 hours to more than a day, with 742 processes across their Simulator trees.

Canaryd waits for sustained inactivity, pauses while the current user has an active xcodebuild or xctest process, and revalidates the exact device before running simctl shutdown <UDID>. It never erases, deletes, or resets the device or its data.

Canaryd notification showing idle Simulators shut down
Representative capture from macOS Notification Center.

3. CleanClip is alive, but it stopped recording

In a real failure, CleanClip stayed running with 0% CPU and no crash report, but its clipboard history had not changed for more than two days. New copy operations were no longer recorded. A process check said healthy; the feature was dead.

Canaryd replays the latest usable real CleanClip history item and verifies that matching content appears in history. It saves every current pasteboard item and data type first. If the user copies something during the probe, the newer user content always wins. A failed probe triggers a quiet restart.

Canaryd detects that CleanClip is alive but its history is stale, runs a reversible functional probe, and confirms recovery

4. An AI coding session heats the Mac

Xcode can keep indexing, compiling, or running build services long after the developer expected the expensive work to finish. Simulator processes can add more load at the same time. The result is a familiar developer-Mac problem: high CPU use, rising temperature, and no clear answer about which process is driving it.

On Apple Silicon, Canaryd takes three macmon 0.8.0 samples and keeps the highest CPU and GPU average. It also checks thermal throttling and system load, then lists up to five processes using at least 20% CPU. A safe top-level app can receive Close and Restart actions; a runtime or system process is reported as a suspect without an automatic action. CPU use is correlation evidence, not exact heat attribution.

Canaryd high-temperature notification showing Xcode and Simulator as CPU-related heat suspects with Close and Restart actions
Representative capture from macOS Notification Center.

5. Work is over, but a memory-heavy app is still open

Developer tools often use several processes, so one quiet application can hold far more memory than its main PID suggests. During one investigation, a Nowledge Mem background server stayed around 1 GB RSS and frequently fell to 0% CPU. Browser-style tools such as Dia and ChatGPT showed the same multi-process shape. These are typical candidates after the user walks away, not while they are active workspaces.

Canaryd aggregates an application's process tree. After 30 minutes of user inactivity, a non-active third-party app becomes eligible only when it stays at or above 1 GB RSS and at or below 1% CPU for three consecutive checks. Canaryd then requests a graceful close. It protects the active app, Apple apps, system processes, and helper bundles, and never escalates this recovery to SIGKILL.

Canaryd confirms that a third-party app is inactive, using more than one gigabyte of memory, and safe to close gracefully
Representative recovery flow based on a real high-memory candidate.

6. AI agents finish, but their build output stays

Parallel coding agents can leave Xcode DerivedData and Cargo target/ directories across projects and worktrees after their tasks are complete. The source may already be committed while reproducible build output continues to consume disk space.

At 04:00 local time, Canaryd checks fixed safe roots, validates every candidate, and requires the complete directory tree to be untouched for seven days. It skips Xcode cleanup while Xcode, Simulator, xcodebuild, or xctest is active, and skips Rust cleanup while cargo or rustc is active. It never follows symbolic links or removes source, Archives, Simulator data, or Cargo caches.

Canaryd validates stale Xcode DerivedData and Cargo target directories before removing only reproducible build output
Representative safety flow based on the maintained build-cleanup specification.

Status at a glance

Run canaryd status to see current temperatures, CleanClip health, recent recovery events, pending app hangs, idle high-memory apps, and idle Simulators.

Example Canaryd status output

The screenshot contains representative values. Process names, temperatures, and events come from the current Mac.

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 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 printed by the installer, then:

canaryd status

The first command installs two launchd agents:

AgentScheduleWork
Full health checkEvery 5 minutesCheck temperature, high-CPU processes, the system, GUI apps, idle memory, Simulators, and CleanClip
Build cleanupDaily at 04:00Remove validated Xcode DerivedData and Cargo target directories inactive for seven days

Every later command verifies and repairs both agents when necessary. You do not need to manage plist files.

Manual archive, source, and Hex installation

Install a downloaded archive

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

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

Verify and install it:

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. Current releases are not notarized.
xattr -d com.apple.quarantine canaryd 2>/dev/null || true
install -m 755 canaryd "$HOME/.local/bin/canaryd"

Current releases use ad hoc code signing and are not Apple-notarized. The checksum verifies the downloaded release asset; it does not provide an Apple Developer ID identity.

Install the current source

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

Install the published Hex release

mix escript.install hex canaryd 0.4.3

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

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

Commands

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 cleanRemove stale Xcode DerivedData and Cargo target directories now
canaryd history [target]Show events for cleanclip, system, thermal, memory, simulators, builds, or apps
canaryd installReinstall and load the launchd agents
canaryd uninstallRemove the launchd agents and the notification helper
canaryd --versionShow the installed version without changing the launchd agents

Examples:

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

Safety model

Canaryd confirms abnormal behavior before changing another process.

SignalConfirmationResponse
CPU or GPU heatThree temperature samples; two rounds for the same actionable leaderWarn first, then offer Close or Restart
GUI app hangmacOS Not Responding state in two consecutive roundsRestart a supported third-party app in the background
Idle high memory30 minutes of user inactivity and three low-CPU, 1 GB+ roundsRequest a graceful app close
Idle SimulatorSustained inactivity and three unchanged device observationsShut down the exact booted UDID
Stale build outputComplete tree inactive for seven days and related tools idleRemove a validated DerivedData or Cargo target directory
CleanClip process missingProcess checkStart it in the background
CleanClip function missingReversible real-history probeRestart quietly; notify only when recovery is blocked
System pressureThree consecutive full checksSend one system-degraded notification

The shared safety rules are:

For exact behavior, see the maintained feature specifications:

Local data

Canaryd stores runtime data only on the Mac:

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

state.dets contains current confirmation and cooldown state. events.dets contains the local recovery timeline, including build-cleanup actions. The log files contain launchd output. Canaryd does not store document content or process command-line arguments in its event history.

Uninstall

Remove the launchd agents and the notification helper:

canaryd uninstall

To remove 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 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 Elixir/OTP, DETS storage, launchd, and a small Swift notification helper.

License

MIT