ops-daemon

SkillFiles & storage

Check claude-ops background daemon end-to-end and auto-fix common issues. Detects stale plist paths after plugin upgrades, missing service commands, dead processes, corrupt health files, and bash version mismatches.

Use ops-daemon in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add ops-daemon and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the ops-daemon skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

ops-daemonStart free

What this skill tells your AI

The instructions your AI receives, as published by davepoon/buildwithclaude in plugins/claude-ops/skills/ops-daemon/SKILL.md and read by ahel’s review.

Runtime Context

Before diagnosing, load:

  1. Plugin root: echo "${CLAUDE_PLUGIN_ROOT:-$(ls -d "$HOME/.claude/plugins/cache/ops-marketplace/ops"/*/ 2>/dev/null | sort -V | tail -1)}" — newest installed version
  2. Daemon health: cat ${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/daemon-health.json — primary diagnostic input
  3. Services config: cat ${CLAUDE_PLUGIN_DATA_DIR}/daemon-services.json — per-service command + cron definitions
  4. OS: uname -s — daemon install is macOS-only (launchd). Linux/WSL/Windows fall back to manual invocation.

OPS ► DAEMON

Diagnostic + auto-fix surface for the background ops-daemon process. Acts like ops-doctor but scoped to the one subsystem users actually see break: the launchd daemon that keeps briefing-pre-warm, memory-extractor, message-listener, inbox-digest, and competitor-intel alive.

CLI/API Reference

bin/ops-daemon-manager.sh

CommandUsageOutput
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh statusEmit JSON snapshot{os, installed, running, pid, plist_version_match, health_fresh, ...}
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh installFirst-time install (idempotent)Writes plist, loads launchd
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh upgradeRe-point plist at current PLUGIN_ROOT + reloadFixes stale version paths
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh restartUnload + reload without reconfiguringClears stuck state
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh uninstallStop + remove plistReturns system to pre-install state

Accepts --plugin-root PATH to override auto-detection and --dry-run to preview without side effects.

Health file schema

${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json:

{
  "timestamp": "<ISO-8601 UTC>",
  "pid": <int>,
  "uptime_seconds": <int>,
  "services": {
    "<name>": {
      "status": "running|polling|scheduled|dead|needs_reauth",
      "pid": <int|null>,
      "last_health": "<string|null>",
      "last_run": "<ISO-8601|empty>",
      "next_run": "<ISO-8601|empty>",
      "restarts": <int>
    }
  },
  "action_needed": null | {"kind": "...", "service": "...", "message": "..."}
}

A healthy daemon refreshes this file every 30s. An mtime older than 120s is a strong fail signal.


Your task

Route on the first argument:

ArgumentAction
check (default)Run all diagnostics, print a colored report, exit 0 if green / 1 otherwise
fixRun check, then per detected issue ask the user for confirmation and apply the fix
restartCall ops-daemon-manager.sh restart
statusPrint the JSON output of ops-daemon-manager.sh status verbatim — consumed by other skills
uninstallAsk [Uninstall] / [Cancel] via AskUserQuestion, then call the manager

Diagnostic checklist

Run each check and track results as pass / fail / warn:

  1. Plugin root resolved — CLAUDE_PLUGIN_ROOT env var set OR ~/.claude/plugins/cache/ops-marketplace/ops/<version>/scripts/ops-daemon.sh exists.
  2. OS supported — uname -s is Darwin. On Linux/WSL print the manual invocation and exit 0 with a warn note. On native Windows print "not supported".
  3. Plist installed — ~/Library/LaunchAgents/com.claude-ops.daemon.plist exists.
  4. Plist points at current version — the second <string> inside ProgramArguments equals ${PLUGIN_ROOT}/scripts/ops-daemon.sh. Mismatch = stale after upgrade (the most common failure mode).
  5. Plist is valid XML — plutil -lint passes.
  6. Launchctl registered — launchctl list shows the label with a real PID (not -).
  7. Process alive — kill -0 <pid> succeeds.
  8. Bash binary exists — the first <string> in ProgramArguments is executable and reports BASH_VERSINFO >= 4 (required for declare -A in the daemon script).
  9. Health file fresh — daemon-health.json exists, mtime within last 120 seconds.
  10. Every service has a command — iterate daemon-services.json services; each enabled entry must have a non-empty command field. Missing command silently skips the service (historical bug).
  11. Running services alive — for each service in the health file with status=running|polling, verify kill -0 <pid> succeeds.
  12. Cron services have future next_run — scheduled services must have a next_run timestamp in the future.
  13. wacli-sync path resolves — if enabled, ~/.wacli/.health exists and is fresh. (Optional — mark warn not fail if missing.)
  14. No zombie children — no orphaned ops-message-listener.sh or wacli-keepalive.sh processes without a parent ops-daemon.sh.

Fix playbook

For each failed check, fix mode proposes a specific repair and asks the user with AskUserQuestion (max 4 options — always include [Skip]):

FailureFixDestructive?
Plist stale version pathops-daemon-manager.sh upgradeYes — unloads + reloads
Plist missingops-daemon-manager.sh installNo
Plist invalid XMLRegenerate via install (after backup)Yes — overwrites
Process dead but plist okops-daemon-manager.sh restartYes — restarts
Health file stale (>120s)ops-daemon-manager.sh restartYes
Service missing commandMerge from scripts/daemon-services.example.json into user's daemon-services.json after showing a diffYes — writes config
Bash binary missing/<4brew install bash on macOS; on Linux check $(command -v bash) version; ask user to installNo (reports only)
Zombie child processeskill <pid> with per-process confirmation (Rule 5)Yes
Services config corrupt JSONRestore from scripts/daemon-services.default.json after confirmation + backupYes

Never batch fixes. Per Rule 5, each destructive action needs its own AskUserQuestion with [Apply] / [Skip] options.

Output format for check

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► DAEMON CHECK
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 OS:           macos
 Plugin root:  ${CLAUDE_PLUGIN_ROOT}
 Daemon PID:   57004
 Uptime:       1h 12m

 ✓ Plist installed
 ✓ Plist points at current version
 ✓ Plist is valid XML
 ✓ Launchctl registered, PID alive
 ✓ Bash binary found (5.3)
 ✓ Health file fresh (mtime 23s ago)
 ✓ All 5 enabled services have commands
 ✓ Running services alive
 ✓ Cron services have future next_run

 STATUS: GREEN — daemon healthy

On failure, replace ✓ with ✗ and append a one-line remediation hint. Exit 1 so /ops:ops-status can surface red.

Output format for status

Print the JSON from ops-daemon-manager.sh status verbatim. No wrapping. This is the machine-readable contract consumed by ops-status, ops-go, and other skills.

Output format for fix

Render the check report, then for each failing check enter a confirmation loop:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► DAEMON FIX — 3 issues found
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 ✗ Plist points at old version 1.0.0
   → Proposed: ops-daemon-manager.sh upgrade

Then AskUserQuestion with [Apply fix] / [Skip this issue] / [Cancel all]. Repeat for each issue. After all actions, re-run check and print a before/after diff.

Cross-OS notes

  • macOS: full support via launchd. All subcommands available.
  • Linux / WSL: ops-daemon-manager.sh install exits EX_UNAVAILABLE (69) and prints the manual nohup invocation. check still validates the daemon script and services config.
  • Windows native: unsupported. Use WSL.

Do not hardcode launchctl in this SKILL — always route through the manager script so future systemd / Task Scheduler support is a one-line addition.

Examples

# Morning habit: confirm the daemon survived overnight
/ops:daemon check

# After a plugin upgrade (`/plugin upgrade claude-ops`):
/ops:daemon fix
# → detects stale plist, asks [Apply upgrade], reloads, verifies

# Embedded in another skill:
/ops:daemon status | jq -r '.health_fresh'

Signals

GitHub stars
4k
Forks
543
Last commit
Sep 2026

ahel review

  • K1binfo
    installs-packages

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
ops-daemon
Source
github.com/davepoon/buildwithclaude