Repository navigation
v0.17.0
khive v0.17.0
This release adds memory.apply_batch for checked, resumable memory rewrites, a properties object on memory.remember, owned namespaces for an actor's helper processes, a brain profile local_factor, and kkernel db import-notes and reindex --fts-only for moving a store. Semantic memories written without a namespace now go to the caller's actor namespace, and recalls served by a brain profile rank with the default weights. It also fixes thread visibility in comm.thread, lossy tool policy timestamps, a secret gate false refusal and daemon receipt matching, and hardens the supervisor marker lock.
Changes
Added
kkernel db import-notesrestores exported note rows (JSONL, one note per line) into an existing database with their original ids, namespaces and timestamps. A row whose id is already present is left unchanged and counted;--verifyreads every row back and fails when any differs. A row carrying a runtime-owned property key is refused before any row of its file is written. Restored keyed memories carry no write-epoch marker, so an exact replay of one's key returns the unavailable receipt error with reasonreceipt_epoch_unknown; recall is unchanged. (#6343)kkernel reindex --fts-onlyrebuilds entity and note FTS documents without any embedding model, so no vector is dropped or written and the knowledge pass is skipped. (#6343)memory.apply_batchrewrites a chunk of memories in one checked call. A call carries a batch name and 1 to 200 rows. Asupersederow writes a new memory with asupersedesedge to the old row and leaves the old row unchanged. Acreaterow writes a new memory. Askiprow writes nothing, and adelete-candidaterow writes nothing and is listed in the reply. Every row is checked before anything is written, and a refused row does not stop the others. The call is a dry run unlessdry_runisfalse. Each written row stores the batch name and an idempotency key derived from the batch, the old id andpart, so re-running a chunk writes only what is missing. An anonymous caller is refused. (#6358)memory.remembertakes an optionalpropertiesobject, stored besidememory_typeandtags. It holds at most 32 keys. Each key is 1 to 64 characters: a lowercase ASCII letter, then lowercase letters, digits or_. Each value is a string, a finite number, a boolean or an array of strings. The serialized object may be at most 8192 bytes, and a larger object is refused, not truncated. The keysmemory_type,tagsandattributionare reserved. (#6356)memory.recallhits reportnamespace,tags([]when none) andproperties({}when none). Existing hit fields keep their names and meanings. (#6356)memory.recallbreakdowns addweights_served,namespace,pre_entity_score,entity_term,local_factorandduplicate_penalty. (#6370)[actor] owned_namespacesinkhive.tomllists namespaces the actor owns, such as the namespaces its helper processes write into. Each entry must be a valid namespace other thanlocaland the actor's ownid, and entries must be unique. A non-empty list requires an explicitid. An invalid list is refused when the configuration loads.memory.apply_batchaccepts an old row in an owned namespace. Ownership grants no write access and widens no read. (#6369)brain.create_profiletakes an optionallocal_factor, a finite number from 0.5 to 1. Any other value is refused.brain.profilereports the factor besideposterior_means. Recall scales hits from the sharedlocalnamespace by a served profile's factor. A profile without one applies no factor. (#6370)moodboard.searchtakes an optionalrerankargument in the opt-in moodboard pack."visual", the default, is the exact image-embedding cosine ranking, and its reply is unchanged."fused"also ranks assets by how well their captions match the query asset's name and caption, then combines both rankings with weighted reciprocal-rank fusion.descriptor_weight(default 0.5, strictly between 0 and 1) sets the caption share of the score.rrf_k(default 60, from 1 to 10000) sets the fusion constant. Both are refused unlessrerankis"fused", and an unknownrerankvalue is refused. A fused reply adds arerankblock. Each hit reports its visual and caption rank and score, each null when the asset is absent from that ranking. A query asset with no caption returns the visual ranking. (#6354)
Changed
memory.rememberwithout anamespaceargument writes semantic memories to the caller's actor namespace, as episodic memories already did. Semantic memories used to go tolocal. A caller with no configured actor still writes tolocal. An explicitnamespacestill wins, and rows already inlocalstay where they are. A deployment that reads shared facts throughlocalmust list the writing actors invisible_namespacesor passnamespace="local".memory.prunestill defaults tolocal. (#6356)- A
memory.rememberwrite from a caller with no configured actor storesattribution: "unresolved"in its properties, with or without anamespaceargument. The reply then includes"attribution": "unresolved". (#6356) memory.recallwith a served brain profile ranks hits with the configured default weights. The weights the profile's posterior means project to are reported per hit asprofile_componentin the breakdown and no longer change the ranking. (#6370)- Per-entity brain posteriors move only on explicit feedback sent through
memory.feedback. A recall hit still moves the entity-blind relevance and temporal posteriors, but no per-entity posterior. A note read moves no per-entity posterior. On restart, replay routes each stored event to the profile that served it, as the live path does. (#6357)
Fixed
comm.threadanswers a root message oraftercursor outside the caller's mailbox view the same way it answers an unknown id. The not-found error no longer names the requested id, and a hidden cursor gets the invalid-input error an unknown cursor gets. Visible replies still resolve to their thread. (#6321)- Tool policy and grant timestamps stored as fractional or out-of-range numbers are no longer truncated or silently treated as absent. A numeric timestamp is accepted only when it converts to an integer without loss. A malformed row that the check consults is reported as an internal error that names the row and the column. (#6320)
- The secret gate no longer refuses a note that cites a line with a backtick-quoted reference such as
:1324, followed by a laterpath:linecitation near a trigger word. Assignments next to a quoted reference are still refused. (#6328) - A client whose configuration has no
[visibility_receipts]section now matches any daemon with a current receipt policy, so its requests reach the daemon instead of falling back to local dispatch. A client that declares a receipt ring still needs the daemon's ring. (#6365)
Security
- The supervisor's marker ownership lock is opened through the checked opener the daemon locks use. A symlink at the lock path is refused without touching its target. An existing lock file loses its group and other permission bits, and a new one is created with mode 0600. (#6344)
Compatibility changes (Rust crates)
- Public structs gained fields, so direct struct literals must set them:
khive_runtime::RuntimeConfig,khive_runtime::RequestIdentity,khive_runtime::DaemonRequestFrameandkhive_runtime::engine_config::ActorConfigaddowned_namespaces;khive_brain_core::ProfileRecordaddslocal_factor;khive_pack_memory::config::ScoreBreakdownaddsweights_served,namespace,pre_entity_score,entity_term,local_factorandduplicate_penalty; andkkernel::reindex::ReindexArgsaddsfts_only. (#6369 #6370 #6343)
Upgrade notes
- No database migration is added in this release.
memory.rememberwithout anamespacewrites semantic memories to the caller's actor namespace instead oflocal. A deployment that reads shared facts throughlocallists the writing actors invisible_namespacesor passesnamespace="local".memory.recallwith a served brain profile ranks hits with the configured default weights; the profile's projected weights are reported per hit and no longer change the order.
Included work (25)
Features
Fixes
Documentation
Benchmarks
Build and maintenance
Full change comparison: v0.16.0...v0.17.0