feat(mcp): khived daemon — persistent warm runtime (ADR-049)#598
Merged
Conversation
…ADR-049) Eliminates the repeated cold-start regression where every /mcp reconnect paid 50-120s deserializing the 350MB Vamana ANN snapshot. A long-lived daemon now owns the warm registry; the stdio MCP client auto-spawns it on first request and forwards via length-prefixed frames. Three changes, one binary: - VerbRegistry::call_warm_all() mirrors call_register_embedders (runtime) - ensure_ann_background fire-once guard: search never blocks on ANN rebuild, returns FTS-only until warm completes (knowledge pack) - khive-mcp --daemon mode: binds ~/.khive/khived.sock, background warm, signal-driven lifecycle; stdio mode forwards or falls back to local dispatch on any failure (KHIVE_NO_DAEMON=1, sandbox, namespace mismatch) Closes #532 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-mcp The daemon server (socket bind, accept, lifecycle, framing, warm) is a runtime concern, not MCP-specific. This moves it to khive-runtime::daemon behind a DaemonDispatch trait so any future transport (CLI, HTTP) can reuse the warm-state server without depending on the MCP crate. - khive-runtime: new daemon module with DaemonDispatch trait, run_daemon, framing (read_frame/write_frame), socket lifecycle, path resolution - khive-mcp: daemon.rs slimmed to client-only (forward_or_spawn, map_response, spawn_daemon) + DaemonDispatch impl for KhiveMcpServer - Also fixes suggest() ANN path from #562 rebase (ann.read → ann.index.read, ensure_ann → ensure_ann_background) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The daemon client's forward_or_spawn attempts auto-spawn on CI where no daemon socket exists, causing a 5s polling delay per request and potential DB mismatch (spawned daemon uses default DB, not :memory:). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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
/mcpreconnect paid 50-120s deserializing the 350MB Vamana ANN snapshotkhive-mcp --daemon) owns the warm registry over a Unix socket; the stdio MCP client auto-spawns it on first request and forwards via length-prefixed framesChanges
VerbRegistry::call_warm_all()— invokes each pack'swarm()hookensure_ann_backgroundfire-once guard replaces inline blockingensure_ann().awaiton search path;indexreindex handler stays synchronousdaemon.rs(420 lines) — socket framing, client (forward_or_spawnwith auto-spawn), server (run_daemonwith lifecycle/drain);--daemonflag;dispatch_request_localextraction;KHIVE_NO_DAEMON=1escape hatchdisable_daemon()guard so tests never attempt daemon forwardingVerified
/mcpreconnects, ANN warm completes in background, RSS ~59 MB idle (0.2% of 32 GB)cargo fmt,cargo clippy -D warnings,cargo check --workspace— all cleanKHIVE_NO_DAEMONin test helpers)Test plan
cargo test -p khive-mcp— 106 pass (92 existing + 14 new)cargo test -p khive-pack-knowledge -p khive-runtime— 421 passknowledge.searchreturns instantly on cold start/mcpreconnectsKHIVE_NO_DAEMON=1forces local dispatchtests/smoke_test.py(daemonless, existing behavior preserved)Closes #532
🤖 Generated with Claude Code