agent-watchdog

agent-watchdog

A macOS command-line daemon that watches coding-agent sessions running in cmux terminals, alerts before a session runs out of context or its prompt cache expires, and can optionally ask the agent to stop or write a handoff before that happens.

Claude Code and Codex are supported harnesses. Both share context alerts, status output and guarded messaging. Codex cache expiry is unavailable unless its backend exposes a usable deadline; the watchdog does not assume Claude cache behavior for Codex. See the architecture plan.

Codex messaging requires a verified cmux terminal owner. On cmux versions with agent.resolve_delivery_target, the watchdog checks live PID ownership against the hook store and verifies it again before sending. Missing or ambiguous ownership leaves the session visible with messaging disabled. Older rollout files are discovered progressively across daemon polls; one-shot commands scan only the first bounded page. See Codex parity details.

Prerequisites

  • macOS
  • cmux, since agent-watchdog reads cmux’s session store to find running sessions
  • Node 26, installed via nvm use (reads .nvmrc)
  • Yarn 4 is vendored in-repo — if a plain yarn command is not on your PATH, substitute node .yarn/releases/yarn-4.11.0.cjs everywhere below

Download a prebuilt build

On Apple silicon you do not need to clone or build anything:

curl -fsSL https://agent-watchdog-downloads.s3.us-east-2.amazonaws.com/agent-watchdog-darwin-arm64.tar.gz | tar -xz
./agent-watchdog/install.sh

See “Download a prebuilt build” in docs/usage.md, or the site, for requirements and what install.sh does. Quick start below is the from-source path.

Quick start

git clone [email protected]:Wholeclove/agent-watchdog.git
cd agent-watchdog
nvm use
yarn install
yarn build

Try it against your real cmux sessions before installing anything:

node apps/watchdog/dist/bin/agent-watchdog.js status

Symlink the built binary into ~/.local/bin, then run it directly (make sure ~/.local/bin is on your PATH):

yarn workspace @agent-watchdog/watchdog start link
agent-watchdog watch --once --dry-run

Install it as a background daemon (launchd agent, logs under ~/Library/Logs/agent-watchdog/):

agent-watchdog install

Settings live in ~/.config/agent-watchdog/config.json, not in the launch agent. Any settings flag you pass to install is written into that file; later, edit the file (or use the menu bar app’s settings window) and restart the daemon, with no reinstall:

agent-watchdog config validate
launchctl kickstart -k gui/$(id -u)/com.wholeclove.agent-watchdog

Want the menu bar app too? Build it and pass its binary to install (or link during development):

yarn workspace @agent-watchdog/menubar build
agent-watchdog install --menubar-bin apps/menubar/.build/release/agent-watchdog-menubar

For the step-by-step walkthrough of all of the above, the config file, every flag, the alert rules, and the menu bar app, see docs/usage.md.

See apps/watchdog/README.md for the full command and flag reference (watch, status, install/uninstall, link, config, and every threshold and action flag).

Features

  • Computes each watched session’s context-window usage and prompt-cache expiry from the agent’s own transcript.
  • Alerts through cmux notifications, a macOS notification fallback, and cmux sidebar status.
  • Can optionally inject a [agent-watchdog]-prefixed message into an agent’s terminal asking it to stop or write a handoff — off by default, gated behind explicit safety checks.
  • Zero runtime dependencies.
  • An optional native macOS menu bar app shows the same status at a glance: a status-item percentage plus a menu with daemon state, per-session rows, recent events, start/stop daemon, and open logs. Its settings window edits the daemon’s config file and restarts the daemon to apply it.

Repo layout

  • apps/watchdog — the daemon (@agent-watchdog/watchdog). See its own README.md for CLI and flag details.
  • apps/menubar — the menu bar app (@agent-watchdog/menubar), a Swift Package Manager project. Reads the status file the daemon writes; it does not compute anything itself.
  • apps/site — the docs and download site (@agent-watchdog/site), an Astro static site outside the tsc -b graph like the menu bar app. It renders this repo’s own markdown in place; see its own README.md.
  • packages/eslint-config — shared lint presets (@agent-watchdog/eslint-config).
  • tsconfig/ — shared TypeScript presets (base/lib/spec).
  • docs/ — repo-level notes; see docs/README.md.

Development commands

Run from the monorepo root:

yarn build       # tsc -b tsconfig.json (apps/watchdog only — apps/menubar (Swift) and apps/site (Astro) build separately)
yarn typecheck   # per-workspace typecheck
yarn lint        # per-workspace eslint
yarn test        # per-workspace jest / swift test
yarn format      # prettier --write .
yarn format:check

Or scope any of these to one workspace: yarn workspace @agent-watchdog/watchdog <script>, yarn workspace @agent-watchdog/menubar <script> (shells out to swift build / swift test, and no-ops on non-macOS), or yarn workspace @agent-watchdog/site <script> (Astro; see apps/site/README.md).

GitHub Actions is currently disabled on this repo (an org billing issue, not a repo decision) — .github/workflows/ci.yml is unused for now, so the commands above are the actual gate before pushing.

Agent tooling

This repo ships Claude Code skills under .claude/skills/ — agent-triggered guidance for the day-to-day workflow, not slash commands:

  • change-control — branch/PR/merge rules, why CI is currently disabled and what the local gate is instead, non-negotiable engineering rules.
  • conventional-commit — commit message format and scopes for this repo.
  • validation-and-qa — which test suite covers a change and what counts as evidence.
  • wip-to-pr — turning uncommitted working-tree changes into a branch, commits, and a PR.
  • workspace-docs — the generator behind the workspace command reference (below).
  • write-skill — authoring or improving a skill.

Workspace-docs generator. .claude/scripts/generate-workspace-docs.js (zero dependencies) reads every workspace’s package.json scripts and writes .claude-context/generated-workspace-commands.md — a gitignored command reference, regenerated by a SessionStart hook (.claude/settings.json) at the start of every agent session. Root CLAUDE.md pulls it in via @.claude-context/generated-workspace-commands.md.