Skip to content

Daemon Guide

auroracapital edited this page Apr 18, 2026 · 3 revisions

Daemon Guide

The background engine that keeps claude-ops fast.

Version Manager Services Pre-warm

Note

ops-daemon is a single launchd-managed process that supervises seven sub-services. It replaced per-service launchd agents in v0.5.0, then gained briefing-pre-warm (v0.6.0) and early-install (v0.8.0).


What the daemon does

flowchart LR
    D[ops-daemon] --> B[briefing-pre-warm<br/>every 2 min]
    D --> W[wacli-sync<br/>continuous]
    D --> M[memory-extractor<br/>every 30 min]
    D --> I[inbox-digest<br/>every 4 hours]
    D --> S[store-health<br/>daily 9am]
    D --> C[competitor-intel<br/>weekly Mon 10am]
    D --> L[message-listener<br/>continuous]

    B --> BC[daemon-cache.json]
    W --> WH[~/.wacli/.health]
    M --> ME[memories/]
    I --> IL[inbox log]
    S --> SR[store-health report]
    C --> CR[competitor report]
    L --> LL[message log]

    classDef svc fill:#6366f1,color:#fff,stroke:#4338ca
    classDef out fill:#22c55e,color:#fff,stroke:#15803d
    classDef root fill:#8b5cf6,color:#fff,stroke:#6d28d9
    class D root
    class B,W,M,I,S,C,L svc
    class BC,WH,ME,IL,SR,CR,LL out
Loading
Service Cadence Purpose
briefing-pre-warm every 2 min Runs bin/ops-gather and caches dashboard data for /ops:go
wacli-sync continuous Keeps WhatsApp Web connection alive, auto-backfills @lid chats
memory-extractor every 30 min Haiku 4.5 summarizes new wacli + gog data into memories/
inbox-digest every 4 hours Ranks unread messages across channels, writes digest
store-health daily at 09:00 Shopify inventory / order / fulfillment sanity check
competitor-intel weekly Mon 10:00 Scrapes competitor signals, writes weekly brief
message-listener continuous Polls wacli/Telegram for new messages, writes to local event log

Important

All services are local-only. message-listener never sends messages outbound on its own — it only writes to a log that the daemon reads. See Privacy and Security for the exact list of network targets.


Early install strategy (v0.8.0)

Pre-v0.8.0 the daemon was installed at Step 5b — after channels, MCPs, and registry. That meant users waited ~10s for their first /ops:go because the cache was empty.

v0.8.0 moved daemon install to Step 2c, immediately after CLIs. The briefing-pre-warm service starts working the moment the plist loads, and continues to warm the cache while the rest of the setup wizard runs.

sequenceDiagram
    autonumber
    participant U as User
    participant W as Setup Wizard
    participant D as ops-daemon
    participant G as ops-gather
    participant C as /ops:go

    U->>W: /ops:setup
    W->>W: Step 1 · Pick sections
    W->>W: Step 2 · Install CLIs
    W->>D: Step 2c · Install daemon (early!)
    activate D
    D->>G: briefing-pre-warm tick #1
    G-->>D: registry, PRs, CI, unread, revenue...
    Note over W,D: Wizard continues in parallel
    W->>W: Step 3 · Configure channels (60–180s)
    D->>G: briefing-pre-warm tick #2 (+2 min)
    W->>W: Step 4 · MCPs · 5 · Registry · 6 · Prefs
    D->>G: briefing-pre-warm tick #N
    W->>W: Step 5b · Reconcile daemon services
    W-->>U: Setup complete
    U->>C: /ops:go
    C->>D: read daemon-cache.json
    D-->>C: cached data (<3s)
    deactivate D
Loading

Tip

By the time the wizard finishes, the cache has 3–8 warm-up cycles banked. /ops:go loads from cache in under 3 seconds instead of cold-gathering in 10+.


Health file contract

Two health files, one per concern.

~/.wacli/.health

Written by wacli-sync on every successful poll.

{
  "status": "ok",
  "last_sync": "2026-04-14T07:45:00Z",
  "wacli_pid": 12345,
  "message_count": 1420
}
Field Meaning
status ok · degraded · down
last_sync ISO timestamp of last successful WhatsApp poll
wacli_pid PID of the running wacli process
message_count Total messages in local SQLite DB

daemon-health.json

Written by the supervisor. Lives at ~/.claude/plugins/data/ops-ops-marketplace/daemon-health.json.

{
  "supervisor_pid": 54321,
  "uptime_seconds": 87442,
  "services": {
    "briefing-pre-warm": { "status": "ok", "last_run": "2026-04-14T07:44:12Z" },
    "wacli-sync":        { "status": "ok", "last_run": "2026-04-14T07:45:00Z" },
    "memory-extractor":  { "status": "ok", "last_run": "2026-04-14T07:30:04Z" },
    "inbox-digest":      { "status": "ok", "last_run": "2026-04-14T04:00:00Z" },
    "store-health":      { "status": "ok", "last_run": "2026-04-14T09:00:00Z" },
    "competitor-intel":  { "status": "idle", "next_run": "2026-04-21T10:00:00Z" },
    "message-listener":  { "status": "ok", "last_event": "2026-04-14T07:44:58Z" }
  }
}

PreToolUse hook — ops-pretool-wacli-health

hooks/whatsapp-health-check.sh (registered in hooks.json) fires before any wacli command. It reads ~/.wacli/.health and:

Condition Behavior
status === "ok" AND last_sync < 10 min Proceeds silently
status === "degraded" OR last_sync >= 10 min Surfaces warning + restart instructions
Health file missing Surfaces "daemon not running" + install instructions

Warning

The hook fails closed. Skills warn instead of silently retrying with stale auth. This is intentional — per Rule 3 and the privacy policy, users must see every health regression rather than get misleading "no new messages" results.


Brain layer · briefing cache

bin/ops-brain runs inside briefing-pre-warm. Every 2 minutes it:

  1. Calls bin/ops-gather — which probes registry projects, GitHub PRs, CI, AWS ECS, Shopify, Klaviyo, Meta Ads, unread counts, GSD phases
  2. Writes the result to daemon-cache.json
  3. Detects urgent patterns (your name mentions, "urgent", "ASAP", "fire", "down", "broken") in unread messages
  4. Flips the urgent_flag in daemon-health.json so /ops:go can surface them instantly

Result: /ops:go reads one cached JSON file instead of spawning 8 parallel gather scripts.


Service reconciliation (Step 5b)

After channels + registry are configured, Step 5b reconciles the daemon:

  • Adds wacli-sync if WhatsApp is configured
  • Adds message-listener if WhatsApp OR Telegram is configured
  • Adds inbox-digest if >=2 channels are configured
  • Adds store-health if Shopify is configured
  • Adds competitor-intel if /ops:marketing is selected
  • Verifies all services launch, prints a green-check summary

Because the daemon was installed at Step 2c with a minimal service list, Step 5b's job is to add channel-dependent services — not reinstall everything from scratch.


Start · stop · restart

launchd (recommended — survives reboots)

# Start (first-time install or after edits)
launchctl load ~/Library/LaunchAgents/com.claude-ops.daemon.plist

# Stop
launchctl unload ~/Library/LaunchAgents/com.claude-ops.daemon.plist

# Force restart (common fix for stuck services)
launchctl kickstart -k gui/$UID/com.claude-ops.daemon

# Check status
launchctl list | grep claude-ops

Foreground (debug mode)

~/.claude/plugins/cache/ops-marketplace/ops/<version>/scripts/ops-daemon.sh start
~/.claude/plugins/cache/.../scripts/ops-daemon.sh status
~/.claude/plugins/cache/.../scripts/ops-daemon.sh stop

Via the plugin

/ops:setup daemon     # re-install, regenerate plist with current paths
/ops:doctor           # auto-repair (runs ops-autofix + kicks the daemon)

Logs

Primary log location:

~/.claude/plugins/data/ops-ops-marketplace/logs/ops-daemon.log

Follow live:

tail -f ~/.claude/plugins/data/ops-ops-marketplace/logs/ops-daemon.log

Filter by service:

grep briefing-pre-warm ~/.claude/plugins/data/ops-ops-marketplace/logs/ops-daemon.log
grep memory-extractor  ~/.claude/plugins/data/ops-ops-marketplace/logs/ops-daemon.log

Note

Logs are rotated at 10 MB with 3 backup files kept. Nothing in the log file is ever transmitted off-machine — see Privacy and Security.


What the daemon does NOT do

Explicit list of non-behaviors
  • No telemetry. No phone-home, no crash reports, no usage metrics.
  • No outbound network except to the user's own configured APIs (Anthropic for Haiku calls, WhatsApp's servers via wacli, the user's Shopify store, etc.)
  • No sending messages unless a skill (running in an interactive Claude Code session) explicitly calls send_message with user confirmation.
  • No disk-wide scans. Every read is a targeted path: registry projects, ~/.wacli/, ~/.claude/plugins/data/ops-ops-marketplace/.
  • No credential harvesting post-setup. Auto-scan runs only inside /ops:setup.

Troubleshooting cross-reference

Symptom See
/ops:go is slow (>10s) Troubleshooting#daemon — pre-warm cache not updating
launchctl load fails Troubleshooting#daemon — launchd errors
wacli health degraded warning Troubleshooting#daemon — health file stale
Memories not extracting Troubleshooting#memories-not-extracting + Memories System
Still stuck Run /ops:doctor --verbose

See also

Clone this wiki locally