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
yarncommand is not on your PATH, substitutenode .yarn/releases/yarn-4.11.0.cjseverywhere 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 ownREADME.mdfor 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 thetsc -bgraph like the menu bar app. It renders this repo’s own markdown in place; see its ownREADME.md.packages/eslint-config— shared lint presets (@agent-watchdog/eslint-config).tsconfig/— shared TypeScript presets (base/lib/spec).docs/— repo-level notes; seedocs/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.