Summary
The desktop app shows the crash screen while the supervised daemon is alive and well. The daemon's /api/health intermittently takes 0.5–15 s to answer while idle (0% CPU, nothing in its log), and the desktop monitor treats three missed 1.5 s probes as a dead daemon. Two things make this trip on a loaded Mac: the launchd unit runs the daemon as ProcessType=Background (scheduler priority 4), and the probe budget is 1.5 s × 3 attempts × 3 consecutive misses.
Environment
- Executor desktop 1.6.10, packaged, macOS 27.2 (Darwin 27.2.0), arm64
- Daemon: bundled
executor daemon run --foreground under sh.executor.daemon (Bun v1.3.11 binary)
- Machine under heavy load at the time: load average 39 / 83 / 115 on 10 cores, 26 GB in the memory compressor
What the logs show
~/Library/Logs/Executor/main.log over 2026-10-01 → 10-02:
showCrashScreen fired five times on 10-01 (08:14, 19:46, 21:30, 21:33, 21:36) while the manifest pid stayed 1141 the whole two days.
- Hundreds of
supervised daemon at http://localhost:4789 (pid 1141) did not answer the health probe; keeping its manifest because the process is still alive, in clusters lasting 1–5 minutes.
- No Crashpad dumps, no macOS DiagnosticReports for the daemon.
Live measurement against the idle daemon
$ for i in $(seq 6); do curl -s -o /dev/null -w 'connect=%{time_connect} ttfb=%{time_starttransfer}\n' http://127.0.0.1:4789/api/health; done
connect=0.000826 ttfb=7.343603
connect=0.000318 ttfb=0.812192
connect=0.000374 ttfb=0.547723
connect=0.000606 ttfb=0.084973
connect=0.001535 ttfb=5.085419
connect=0.000723 ttfb=1.041224
During those seconds: top reports the daemon at 0.0% CPU, state sleeping; daemon.log gets no new lines; sample shows the main thread parked in _pthread_cond_wait / syscall_thread_switch inside the executor binary (no libsql.node or keyring.node frames on the main thread). A 75-probe run at 250 ms spacing: 4 probes over 0.5 s, all in one 7-second window with no daemon activity logged. A later 60-probe run at 1 s spacing: 13 over 0.5 s, max 9.1 s, one earlier probe took 15.3 s.
ps -o pri for the daemon reports 4 (launchd Background class); the Executor GUI process reports 46, a user-launched bun server 37. taskpolicy -B -p <pid> does not change it for a launchd-managed job.
Why this looks like a crash to the user
apps/desktop/src/main/index.ts: SUPERVISED_MONITOR_MISSES_BEFORE_DOWN = 3, polled every 10 s, each poll isDaemonReachable = three fetch('/api/health') attempts with a 1.5 s abort. A daemon that stalls for 30 s is declared down and the crash screen replaces the UI. The user then restarts, which triggers the full tool sync again (1–5 min with a dozen remote MCP connections), and the cycle repeats.
Asks
- Drop
ProcessType=Background from the generated plist in apps/cli/src/service.ts (or make it configurable). The daemon serves interactive UI and MCP calls; background class starves it on a busy machine.
- Give the supervised monitor a more forgiving budget (e.g. 5 s probe timeout, or require the manifest pid to be gone before showing the crash screen), and say "daemon unresponsive" rather than "crashed" when the pid is alive.
- Separately: the idle-time main-thread stall itself. Happy to run anything that would help pin it (the shipped binary has no symbols).
Diagnostics export (Export Diagnostics…) available on request; it contains no secrets but I would rather attach it to a maintainer than post it publicly.
Confirmation
Removing ProcessType=Background from the installed plist and re-bootstrapping the unit moved the daemon from priority 4 to 20. With the machine even busier (load average 557–589), 60 probes at 1 s spacing: median 14 ms, max 0.56 s, one over 0.5 s. Under the Background class at lower load: 13 of 35 probes over 0.5 s, max 15.3 s.
Summary
The desktop app shows the crash screen while the supervised daemon is alive and well. The daemon's
/api/healthintermittently takes 0.5–15 s to answer while idle (0% CPU, nothing in its log), and the desktop monitor treats three missed 1.5 s probes as a dead daemon. Two things make this trip on a loaded Mac: the launchd unit runs the daemon asProcessType=Background(scheduler priority 4), and the probe budget is 1.5 s × 3 attempts × 3 consecutive misses.Environment
executor daemon run --foregroundundersh.executor.daemon(Bun v1.3.11 binary)What the logs show
~/Library/Logs/Executor/main.logover 2026-10-01 → 10-02:showCrashScreenfired five times on 10-01 (08:14, 19:46, 21:30, 21:33, 21:36) while the manifest pid stayed 1141 the whole two days.supervised daemon at http://localhost:4789 (pid 1141) did not answer the health probe; keeping its manifest because the process is still alive, in clusters lasting 1–5 minutes.Live measurement against the idle daemon
During those seconds:
topreports the daemon at 0.0% CPU, state sleeping;daemon.loggets no new lines;sampleshows the main thread parked in_pthread_cond_wait/syscall_thread_switchinside the executor binary (no libsql.node or keyring.node frames on the main thread). A 75-probe run at 250 ms spacing: 4 probes over 0.5 s, all in one 7-second window with no daemon activity logged. A later 60-probe run at 1 s spacing: 13 over 0.5 s, max 9.1 s, one earlier probe took 15.3 s.ps -o prifor the daemon reports 4 (launchd Background class); the Executor GUI process reports 46, a user-launched bun server 37.taskpolicy -B -p <pid>does not change it for a launchd-managed job.Why this looks like a crash to the user
apps/desktop/src/main/index.ts:SUPERVISED_MONITOR_MISSES_BEFORE_DOWN = 3, polled every 10 s, each pollisDaemonReachable= threefetch('/api/health')attempts with a 1.5 s abort. A daemon that stalls for 30 s is declared down and the crash screen replaces the UI. The user then restarts, which triggers the full tool sync again (1–5 min with a dozen remote MCP connections), and the cycle repeats.Asks
ProcessType=Backgroundfrom the generated plist inapps/cli/src/service.ts(or make it configurable). The daemon serves interactive UI and MCP calls; background class starves it on a busy machine.Diagnostics export (
Export Diagnostics…) available on request; it contains no secrets but I would rather attach it to a maintainer than post it publicly.Confirmation
Removing
ProcessType=Backgroundfrom the installed plist and re-bootstrapping the unit moved the daemon from priority 4 to 20. With the machine even busier (load average 557–589), 60 probes at 1 s spacing: median 14 ms, max 0.56 s, one over 0.5 s. Under the Background class at lower load: 13 of 35 probes over 0.5 s, max 15.3 s.