Skip to content

feat(mcp): khived daemon — persistent warm runtime (ADR-049)#598

Merged
ohdearquant merged 4 commits into
mainfrom
feat/khived-daemon
May 31, 2026
Merged

feat(mcp): khived daemon — persistent warm runtime (ADR-049)#598
ohdearquant merged 4 commits into
mainfrom
feat/khived-daemon

Conversation

@ohdearquant
Copy link
Copy Markdown
Owner

Summary

  • Eliminates the repeated cold-start regression (Wire brain dispatch-hook + pack warm() at MCP boot (U10, vamana warm-load) #532) where every /mcp reconnect paid 50-120s deserializing the 350MB Vamana ANN snapshot
  • A persistent daemon (khive-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 frames
  • Search never blocks on ANN rebuild — returns FTS-only instantly, fuses ANN once background warm completes

Changes

  • khive-runtime: VerbRegistry::call_warm_all() — invokes each pack's warm() hook
  • khive-pack-knowledge: ensure_ann_background fire-once guard replaces inline blocking ensure_ann().await on search path; index reindex handler stays synchronous
  • khive-mcp: new daemon.rs (420 lines) — socket framing, client (forward_or_spawn with auto-spawn), server (run_daemon with lifecycle/drain); --daemon flag; dispatch_request_local extraction; KHIVE_NO_DAEMON=1 escape hatch
  • integration tests: disable_daemon() guard so tests never attempt daemon forwarding

Verified

  • Tested live: daemon auto-spawns, survives /mcp reconnects, ANN warm completes in background, RSS ~59 MB idle (0.2% of 32 GB)
  • 106 khive-mcp tests (11 new daemon tests including real socket round-trip), 77 knowledge, 344 runtime — all green
  • cargo fmt, cargo clippy -D warnings, cargo check --workspace — all clean
  • Critic review: APPROVE-WITH-FIXES (P1 fixed: KHIVE_NO_DAEMON in 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 pass
  • Live test: knowledge.search returns instantly on cold start
  • Live test: daemon survives multiple /mcp reconnects
  • Live test: KHIVE_NO_DAEMON=1 forces local dispatch
  • tests/smoke_test.py (daemonless, existing behavior preserved)

Closes #532

🤖 Generated with Claude Code

ohdearquant and others added 4 commits May 30, 2026 20:19
…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>
@ohdearquant ohdearquant merged commit eefe556 into main May 31, 2026
3 checks passed
@ohdearquant ohdearquant deleted the feat/khived-daemon branch May 31, 2026 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wire brain dispatch-hook + pack warm() at MCP boot (U10, vamana warm-load)

1 participant