Skip to content

Bug: Daemon workers never execute on macOS due to unrealistic resource thresholds #1077

Description

@ezhilvendhan

Description

The daemon worker system (worker-daemon.js) has resource check thresholds (maxCpuLoad: 2.0 and minFreeMemoryPercent: 20) in canRunWorker() that are incompatible with macOS, causing all workers to be permanently deferred and never execute.

Root Cause

1. maxCpuLoad: 2.0 is too low for multi-core systems

On macOS (and Linux), os.loadavg()[0] returns the 1-minute system load average across all cores. On an 8-core Mac under normal development workload, load averages of 8-16 are typical. The default threshold of 2.0 means the daemon defers all workers with "CPU load too high" on any modern multi-core machine that isn't essentially idle.

Suggested fix: Use os.cpus().length * 2 (e.g., 16 on 8-core) or a much higher default like 20-24.

2. minFreeMemoryPercent: 20 is incompatible with macOS memory management

On macOS, os.freemem() returns only truly unused RAM (wired + active + speculative excluded), not including the large amount of reclaimable cached/purgeable memory. A typical Mac reports only 1-5% "free" memory even when plenty is available via cache reclamation. The 20% threshold means workers are always deferred with "Memory too low: 1.0% free" on macOS.

Suggested fix: Either:

  • Disable the memory check on macOS (process.platform === 'darwin')
  • Lower the threshold significantly (e.g., 1%)
  • Use vm_stat or a platform-aware memory check on macOS

3. Deadlock amplification

When all workers are deferred, they go into pendingWorkers queue. But processPendingWorkers() is only called in executeWorker()'s finally block. Since no worker ever executes, deferred workers are stuck forever. (Related to #1052 which fixes the busy-wait aspect, but not the root cause threshold issue.)

4. --quiet flag hardcoded in background spawn

In daemon.js line 186, the background daemon spawn hardcodes --quiet, suppressing all worker event output to the log file. This makes it impossible to diagnose why workers aren't running.

// daemon.js line 184-186
const child = spawn(process.execPath, [
    cliPath,
    'daemon', 'start', '--foreground', '--quiet'  // <-- --quiet hardcoded
], { ... });

Steps to Reproduce

  1. Run claude-flow daemon start on macOS
  2. Check daemon-state.json - all workers show runCount: 0
  3. Wait indefinitely - workers never execute

Expected Behavior

Workers should execute on their scheduled intervals on a typical macOS development machine.

Environment

  • macOS (tested on macOS 15.3, 8-core Apple Silicon)
  • Node.js v22.15.0
  • @claude-flow/cli v3.0.0 (alpha)

Proposed Fix

See PR (linked below) with:

  • maxCpuLoad changed from 2.0 to os.cpus().length * 3 (dynamic based on core count)
  • minFreeMemoryPercent changed from 20 to 1 (accommodates macOS memory reporting)
  • Removed hardcoded --quiet flag from background daemon spawn

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions