Let daemon sleep with idle MCP wrappers#48
Open
Marsu6996 wants to merge 1 commit into
Open
Conversation
5a5bbc3 to
10c811a
Compare
Keep wrapper heartbeats and watchdog probes from pinning the daemon awake, and wake the launchd-managed daemon on demand before MCP tool calls. Reduce recall CPU by limiting the max-node community gate to the current candidate embeddings, while preserving deterministic ordering and non-finite embedding guards. Cover wrapper wake gating, readiness timeout, recall concurrency, and max-node gate edge cases. Designed by Marsu — Refined by Codex. Co-Authored-By: Codex <codex@openai.com>
10c811a to
fd99547
Compare
This was referenced Jul 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes a daemon sleep regression where idle MCP wrappers/control-plane probes could keep the daemon awake indefinitely, and adds an on-demand wake path for launchd-managed daemons after sleep/hibernation.
Problem
Long-lived MCP sessions keep wrapper heartbeat files fresh, while watchdog/status probes arrive frequently. The daemon was treating those presence/control-plane signals as real activity, so the idle cycle could stay in WAKE and repeatedly do expensive wake-time work even when no memory operation was running.
There was also a recall hot path where the max-node community gate could scan the full assignment instead of only the current recall candidates.
Changes
tools/callwhen using the default macOS/Windows endpoint:wake.signalbefore kickstartIAI_MCP_DISABLE_DAEMON_AUTOSTART=1RECALL_CONCURRENCY_DEFAULT=2for multi-agent setups.lifecycle_state.jsonover stale legacy in-memory state, sodaemon statusdoes not report WAKE while the lifecycle FSM is DROWSY/SLEEP.Validation
Passed:
npm run typecheck && npm testinmcp-wrapper— 51 passedruff check src/iai_mcp/concurrency.py src/iai_mcp/pipeline.py src/iai_mcp/socket_server.py tests/test_concurrency_session_open.py tests/test_mosaic_max_node_gate.py tests/test_recall_shared_cosine.py tests/test_socket_server_dispatch.pyLive local smoke after installing the patch over the active daemon runtime:
memory_recallreturned non-error resultsFull local pytest was also run earlier. It reached 3640 passed, 122 skipped, 1 xfailed, with 2 local/environment failures unrelated to this diff:
tests/test_mosaicsigma_native_import.py::test_both_submodules_share_one_sobecause the active site-packages directory contains several extension modules, not justiai_mcp_native.tests/test_watchdog_phys_footprint.py::test_phys_footprint_not_above_rss_on_clean_processunder macOS memory-pressure/measurement conditions.Review
Reviewed with an aggressive Claude pass. Initial blockers were addressed:
Relationship with other open PRs
save_statesnapshot race. This PR no longer includes that fix.Operational notes
Attribution
Designed by Marsu — Refined by Codex.
Co-Authored-By: Codex codex@openai.com
CI follow-up
tests/test_runtime_graph_centrality_child.py::test_parent_rss_lower_with_centrality_childwithin_parent_delta=63.3MBandisolated_delta=65.0MB.168.5MB/49.4MB,167.1MB/47.9MB), so the failure was a strict RSS allocator-noise assertion, not a runtime regression.