ops-daemon
Runtime Context
Before diagnosing, load:
- 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 - Daemon health:
cat ${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/daemon-health.json— primary diagnostic input - Services config:
cat ${CLAUDE_PLUGIN_DATA_DIR}/daemon-services.json— per-service command + cron definitions - 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
| Command | Usage | Output |
|---|---|---|
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh status |
Emit JSON snapshot | {os, installed, running, pid, plist_version_match, health_fresh, ...} |
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh install |
First-time install (idempotent) | Writes plist, loads launchd |
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh upgrade |
Re-point plist at current PLUGIN_ROOT + reload | Fixes stale version paths |
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh restart |
Unload + reload without reconfiguring | Clears stuck state |
${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon-manager.sh uninstall |
Stop + remove plist | Returns 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:
| Argument | Action |
|---|---|
check (default) |
Run all diagnostics, print a colored report, exit 0 if green / 1 otherwise |
fix |
Run check, then per detected issue ask the user for confirmation and apply the fix |
restart |
Call ops-daemon-manager.sh restart |
status |
Print the JSON output of ops-daemon-manager.sh status verbatim — consumed by other skills |
uninstall |
Ask [Uninstall] / [Cancel] via AskUserQuestion, then call the manager |
Diagnostic checklist
Run each check and track results as pass / fail / warn:
- Plugin root resolved —
CLAUDE_PLUGIN_ROOTenv var set OR~/.claude/plugins/cache/ops-marketplace/ops/<version>/scripts/ops-daemon.shexists. - OS supported —
uname -sisDarwin. On Linux/WSL print the manual invocation and exit 0 with awarnnote. On native Windows print "not supported". - Plist installed —
~/Library/LaunchAgents/com.claude-ops.daemon.plistexists. - Plist points at current version — the second
<string>insideProgramArgumentsequals${PLUGIN_ROOT}/scripts/ops-daemon.sh. Mismatch = stale after upgrade (the most common failure mode). - Plist is valid XML —
plutil -lintpasses. - Launchctl registered —
launchctl listshows the label with a real PID (not-). - Process alive —
kill -0 <pid>succeeds. - Bash binary exists — the first
<string>inProgramArgumentsis executable and reportsBASH_VERSINFO >= 4(required fordeclare -Ain the daemon script). - Health file fresh —
daemon-health.jsonexists,mtimewithin last 120 seconds. - Every service has a command — iterate
daemon-services.jsonservices; each enabled entry must have a non-emptycommandfield. Missingcommandsilently skips the service (historical bug). - Running services alive — for each service in the health file with
status=running|polling, verifykill -0 <pid>succeeds. - Cron services have future
next_run—scheduledservices must have anext_runtimestamp in the future. - wacli-sync path resolves — if enabled,
~/.wacli/.healthexists and is fresh. (Optional — mark warn not fail if missing.) - No zombie children — no orphaned
ops-message-listener.shorwacli-keepalive.shprocesses without a parentops-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]):
| Failure | Fix | Destructive? |
|---|---|---|
| Plist stale version path | ops-daemon-manager.sh upgrade |
Yes — unloads + reloads |
| Plist missing | ops-daemon-manager.sh install |
No |
| Plist invalid XML | Regenerate via install (after backup) |
Yes — overwrites |
| Process dead but plist ok | ops-daemon-manager.sh restart |
Yes — restarts |
| Health file stale (>120s) | ops-daemon-manager.sh restart |
Yes |
Service missing command |
Merge from scripts/daemon-services.example.json into user's daemon-services.json after showing a diff |
Yes — writes config |
| Bash binary missing/<4 | brew install bash on macOS; on Linux check $(command -v bash) version; ask user to install |
No (reports only) |
| Zombie child processes | kill <pid> with per-process confirmation (Rule 5) |
Yes |
| Services config corrupt JSON | Restore from scripts/daemon-services.default.json after confirmation + backup |
Yes |
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 installexitsEX_UNAVAILABLE(69) and prints the manualnohupinvocation.checkstill 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'
More from davepoon/buildwithclaude
file-organizer
Intelligently organizes your files and folders across your computer by understanding context, finding duplicates, suggesting better structures, and automating cleanup tasks. Reduces cognitive load and keeps your digital workspace tidy without manual effort.
212xlsx
Comprehensive spreadsheet creation, editing, and analysis with support for formulas, formatting, data analysis, and visualization. When Claude needs to work with spreadsheets (.xlsx, .xlsm, .csv, .tsv, etc) for: (1) Creating new spreadsheets with formulas and formatting, (2) Reading or analyzing data, (3) Modify existing spreadsheets while preserving formulas, (4) Data analysis and visualization in spreadsheets, or (5) Recalculating formulas
187content-research-writer
Assists in writing high-quality content by conducting research, adding citations, improving hooks, iterating on outlines, and providing real-time feedback on each section. Transforms your writing process from solo effort to collaborative partnership.
141docx
Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks
122auth-patterns
This skill should be used when the user asks about "authentication in Next.js", "NextAuth", "Auth.js", "middleware auth", "protected routes", "session management", "JWT", "login flow", or needs guidance on implementing authentication and authorization in Next.js applications.
104server-actions
This skill should be used when the user asks about "Server Actions", "form handling in Next.js", "mutations", "useFormState", "useFormStatus", "revalidatePath", "revalidateTag", or needs guidance on data mutations and form submissions in Next.js App Router.
100