feat(worker): add CLAUDE_MEM_WORKER_AUTOSTART to opt out of hook worker lazy-spawn#2828
feat(worker): add CLAUDE_MEM_WORKER_AUTOSTART to opt out of hook worker lazy-spawn#2828surfingdoggo wants to merge 1 commit into
Conversation
…er lazy-spawn Hooks lazy-spawn the worker daemon via ensureWorkerAliveOnce() whenever the worker port is dead. That's correct for worker-runtime users, but server-beta or externally-managed deployments have no way to stop hook activity from resurrecting the worker daemon. Add CLAUDE_MEM_WORKER_AUTOSTART (default 'true'); when 'false', ensureWorkerAliveOnce() returns false without spawning. Default preserves existing behavior exactly — this is an opt-out for operators who don't use the worker-only features (data viewer, corpus/skills, semantic injection — all listed unsupported on server-beta in docs/server-beta-parity-map.md). - Unit tests for the opt-out, default, and explicit-true cases (adds a resetAliveCache() test helper mirroring clearPortCache()). - Documented in the configuration reference. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Greptile SummaryThis PR adds
Confidence Score: 3/5The opt-out flag works as advertised for ensureWorkerAliveOnce in isolation, but the false return flows directly into recordWorkerUnreachable() in executeWithWorkerFallback, generating blocking error alerts after only a handful of hook calls on any deployment that uses the new flag. The new short-circuit in ensureWorkerAliveOnce() returns false when AUTOSTART=false, but executeWithWorkerFallback treats any false return as a live worker failure: it calls recordWorkerUnreachable() unconditionally, and after FAIL_LOUD_DEFAULT_THRESHOLD (3) consecutive hook invocations the emitBlockingError path fires and exits the hook process with code 2. For a server-beta deployment that makes several hook calls per session, this happens almost immediately. The feature is usable today only on the default (true) path; the opt-out path reliably produces the very noise it was designed to suppress. src/shared/worker-utils.ts — specifically the interaction between ensureWorkerAliveOnce and executeWithWorkerFallback when AUTOSTART=false. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Hook invokes executeWithWorkerFallback] --> B[ensureWorkerAliveOnce]
B --> C{aliveCache !== null?}
C -- yes --> D[return cached value]
C -- no --> E{AUTOSTART == 'false'?}
E -- yes --> F[aliveCache = false\nreturn false]
E -- no --> G[ensureWorkerRunning]
G --> H[aliveCache = result\nreturn result]
D --> I{alive?}
F --> I
H --> I
I -- true --> J[Make HTTP request to worker]
I -- false --> K[recordWorkerUnreachable ⚠️\nfires even when AUTOSTART=false]
K --> L{consecutiveFailures\n>= threshold?}
L -- yes --> M[emitBlockingError\nexit 2 💥]
L -- no --> N[return WorkerFallback continue=true]
|
Problem
Hooks lazy-spawn the worker daemon via
ensureWorkerAliveOnce()whenever the worker port is dead. That's correct for worker-runtime users — but server-beta-only or externally-managed deployments have no way to stop hook activity from continually resurrecting the worker daemon.Fix
Add
CLAUDE_MEM_WORKER_AUTOSTART(defaulttrue). Whenfalse,ensureWorkerAliveOnce()returnsfalsewithout spawning.truepreserves existing behavior exactly — no-op for current users.false) is for operators who drive the worker out-of-band and knowingly give up worker-only features (data viewer, corpus/skills, semantic injection — already unsupported on server-beta perdocs/server-beta-parity-map.md).Changes
ensureWorkerAliveOnce()chokepoint.truecases, plus aresetAliveCache()test helper mirroring the existingclearPortCache().Note on CI
maincurrently has unrelated pre-existing failures (PID-file / process-manager and logger-standards tests, plus a duplicateModeManagerimport typecheck error). This change is isolated to the worker lazy-spawn path; the new test suite passes.🤖 Generated with Claude Code