khive-runtime
Composable Service API used by khive's daemon, MCP server, and CLI: entity/note CRUD,
graph traversal, hybrid search, and curation, plus the pack registration and
verb-dispatch machinery that lets packs (kg, gtd, memory, …) extend the surface.
Features
KhiveRuntime— a cloneable handle wrapping akhive-db::StorageBackendwith namespace-scoped accessors for every storage capability, plus a lazily-configured embedder registryBlobHydrator— one store-paired, runtime-shared weighted byte budget for bounded, digest-verified whole-blob reads. Its non-cloneableVerifiedBlobkeeps admission until callers finish using the borrowed bytes, and tracked supervisors keep native work visible to daemon drain after request cancellation- Role-keyed attachments — main-backend-only record metadata over
ContentRef, atomic entity-plus-role publication, compatibilitycontent_refprojection, and transactional hard-delete cleanup VerbRegistry/VerbRegistryBuilder— registers packs (PackRuntimeimpls), an authorizationGate, an actor identity, and dispatches verbs by namePackRuntimetrait — the object-safe runtime counterpart tokhive-types::Pack; every pack declares handlers, owned entity/note kinds, edge-endpoint extensions, and an optional auxiliarySchemaPlan- Curation (
EntityPatch,NotePatch,EdgePatch,MergeSummary,MergeEdgeConflictPreimage,MergeEdgePreimage,EntityDedupMergePolicy) — update/merge semantics, including reversible natural-key edge-conflict drops, per ADR-014 - Retrieval objectives (
RrfFusionObjective,VectorSimilarityObjective,TextRelevanceObjective,TemporalRecencyObjective,AmplifiedDecayAwareSalienceObjective, …) composed into aMemoryRecallPipeline, plusDecayAwareSalienceObjectivefor standalone fixed-rate scoring - Graph traversal (
PathNode) and validation (ValidationRule,ValidationReport,Violation) for domain-specific graph-shape rules - Daemon (unix only) —
run_daemon, socket/pid path helpers, and the request/response frame types for the persistentkkernel mcp --daemonprocess
Usage
use ;
use Namespace;
// In-memory runtime (tests and pure local embedding). Production callers use
// khive-mcp/kkernel's async host builders so legacy V21 attachment cutover is
// completed before any runtime is exposed.
let runtime = new?;
// Every read/write is scoped by a NamespaceToken minted through the configured Gate.
let token = runtime.authorize?;
let entities = runtime.entities?; // Arc<dyn khive_storage::EntityStore>
let graph = runtime.graph?; // Arc<dyn khive_storage::GraphStore>
KhiveRuntime::new is suitable for fresh, exact-current, and in-memory
databases. It deliberately refuses a legacy V20 database that needs verified
application-assisted migration. Official production boot uses the async
khive_mcp::serve::build_single_backend_runtime or multi-backend builders and
then KhiveRuntime::from_prepared_backend. The infallible from_backend
constructor is a low-level assembly seam whose caller must already have
completed V21; it is not a migration or serving entrypoint.
Before any Phase-4b builder is deployed, the Phase-4a GC compatibility build must converge on every process sharing the database/blob root and all pre-Phase-4a processes must be drained. Phase 4a leaves V20 schema/data unchanged and only fail-closes transactional GC unless the database is exact completed V21. Every Phase-4a application-serving/read-write process must also be quiesced for cutover, or proven unable to access the database. Only a GC-only worker has narrow completed-V21 compatibility; start Phase-4b serving after exact-current topology validation.
Artifact publication uses create_entity_with_attachments; the former
single-column create_entity_with_content_ref seam is removed. Packs assigned
to a secondary database must call runtime.core().attachments() because only
the canonical main database participates in blob GC liveness.
Packs are composed through the builder, not KhiveRuntime directly:
use ;
use Arc;
let mut builder = new;
builder
.with_gate
.with_default_namespace;
// .register(KgPack::new(...)) // any Pack + PackRuntime impl
let registry = builder.build?;
let result = registry
.dispatch
.await?;
Architecture
KhiveRuntime::new(RuntimeConfig)
│
StorageBackend (khive-db)
│
┌──────────────────┼─────────────────────────────┐
authorize(ns) entities/graph/notes/… BlobHydrator / embedder(name)
│ (khive-storage traits) (bounded bytes / lattice-embed)
▼
NamespaceToken ──── VerbRegistryBuilder::register(pack) × N
│
VerbRegistryBuilder::build()
│
VerbRegistry::dispatch(verb, params)
│ │
Gate::check first pack whose handlers() match verb
(authoritative
Deny; errors
fail closed)
dispatch short-circuits to describe_verb when params["help"] == true, otherwise
resolves the request namespace (explicit namespace arg, else the registry default),
checks the Gate, and routes to the first registered pack whose HandlerDefs cover
the verb. KhiveRuntime::authorize mints a NamespaceToken whose read-visibility set
defaults to [ns]; authorize_with_visibility widens it for callers that read across
namespaces (e.g. an agent reading both its own and a shared namespace) while writes
stay pinned to the primary.
Where this sits
khive-runtime sits directly above khive-db/khive-query/khive-gate/khive-fusion
and below every pack crate:
types -> score -> storage -> db -> query -> runtime -> pack-kg / pack-gtd / … -> mcp
It re-exports the khive-db and khive-gate types packs need
(StorageBackend, ConnectionPool, Gate, GateDecision, ActorRef, …) so most
pack crates depend on khive-runtime alone rather than reaching past it. Governing
ADRs: pack contract and object-safe dispatch
(ADR-017),
verb surface, visibility and composition
(ADR-023),
dynamic pack loading via self-registration
(ADR-027),
pack-scoped backends and per-pack schema
(ADR-028),
and the authorization gate
(ADR-018).
License
Apache-2.0.