API Reference

khive exposes exactly one MCP tool, request. Everything else — 75 verbs across 9 production packs — is dispatched through that single tool via a small request DSL. This page documents the DSL grammar, the response envelope, and every verb’s full parameter contract, so an agent can call khive correctly without reading Rust source.

This page is verified against the live registry (request(ops="verbs()"), run 2026-07-07) and the pack source (crates/khive-pack-*/src/*.rs HandlerDef/ParamDef struct literals). Verb count: 75, matching both the live registry total field and the sum of the 9 pack counts below. If your server reports a different total, your KHIVE_PACKS configuration loads a different pack set than the default — run request(ops="verbs()") against your own server to get the authoritative list.

An always-machine-readable copy of this page is at /md/api-reference.md. The site also publishes /llms.txt (a short index) and /llms-full.txt (every guide page concatenated) for agents that prefer one fetch over several.

Packs at a glance

Pack Verbs Load with Optional?
kg 17 KHIVE_PACKS=kg (default) No — base substrate
gtd 5 KHIVE_PACKS=kg,gtd Yes
memory 5 KHIVE_PACKS=kg,memory Yes
brain 14 KHIVE_PACKS=kg,brain Yes
comm 7 KHIVE_PACKS=kg,comm Yes
schedule 4 KHIVE_PACKS=kg,schedule Yes
knowledge 19 KHIVE_PACKS=kg,knowledge Yes
session 4 KHIVE_PACKS=kg,session Yes
git 0 KHIVE_PACKS=kg,git Yes

git contributes zero verbs — it registers the commit / issue / pull_request note kinds and a batch ingester (crates/khive-pack-git/src/ingest.rs), consumed outside the request DSL, not new MCP-callable verbs.

The default binary (no KHIVE_PACKS/--pack override) loads all 9 packs: 17 + 5 + 5 + 14 + 7 + 4 + 19 + 4 + 0 = 75 verbs.

Verb names in the kg pack are bare (create, search, link, …). Every other pack namespaces its verbs with a pack. prefix (gtd.assign, memory.recall, brain.feedback, comm.send, schedule.remind, knowledge.search, session.store).


DSL syntax

The request tool takes one string argument, ops, in one of four forms.

Single op

request(ops="search(kind=\"entity\", query=\"LoRA\")")

Parallel batch

Up to 100 ops, run with no ordering guarantee between them:

request(ops="[memory.recall(query=\"x\"), memory.remember(content=\"y\")]")

Chain

Ops separated by | run sequentially; $prev resolves against the immediately preceding op’s result (not any earlier op — non-adjacent dependencies require splitting into separate request calls):

request(ops="create(kind=\"concept\", name=\"X\") | link(source_id=$prev.id, target_id=\"<uuid>\", relation=\"extends\")")

$prev path extraction:

Form Meaning
$prev the full prior result
$prev.field a nested object field
$prev.items[0].id array index then field
$prev[2] top-level array index

A quoted string containing $prev is promoted to a substitution automatically (id="$prev.id" behaves the same as id=$prev.id). To pass the literal four characters $prev, escape it: "\\$prev".

JSON form

Equivalent to parallel batch, for callers that prefer to build JSON directly:

request(ops="[{\"tool\":\"search\",\"args\":{\"kind\":\"entity\",\"query\":\"LoRA\"}}]")

JSON form only supports independent ops — a literal $prev anywhere in JSON form is a parse error (DslError::PrevRefInJsonForm), since JSON form has no chain syntax.

Parser constraints (source: khive-request, ADR-016)

  • MAX_OPS = 100 per request; exceeding it is DslError::TooManyOps.
  • $prev is chain-only. Using it outside a | chain, or anywhere in JSON form, is rejected at parse time.
  • Write-key conflict detection: a parallel batch where two ops target the same UUID via update/delete (id), merge (into_id/from_id), or link (source_id/target_id) is rejected before any op dispatches, rather than racing.
  • RESERVED_ENVELOPE_ARGS (presentation, presentation_per_op) are envelope-level fields on the request tool call itself; passing them inside a verb’s own argument list is rejected (DslError::ReservedEnvelopeArg).
  • Mixing , and | at the top level is rejected (DslError::MixedSeparators).
  • Only single-level pack.verb names are supported — a.b.c is DslError::UnsupportedVerbNesting.
  • Argument values are JSON literals. Strings must be double-quoted, including inside DSL function-call form — a bare word as a value fails at the assignment, even standalone.

Response envelope

Every op returns its own ok/error outcome; a batch’s per-op failure does not abort its siblings (chain failures do abort the remainder of the chain):

{
  "results": [
    { "ok": true, "tool": "search", "result": { "...": "..." } },
    { "ok": false, "tool": "get", "error": "not found: ..." }
  ],
  "summary": { "total": 2, "succeeded": 1, "failed": 1, "aborted": 0 }
}

aborted counts ops skipped after an earlier failure in a | chain; it is always 0 for parallel batches, since parallel failures do not cascade.


kg pack — 17 verbs

Base substrate verbs, bare names (no kg. prefix). Category is the illocutionary act (Searle 1976): Assertive = retrieves state, Commissive = commits a persistent change, Declaration = changes institutional status by fiat.

create — Commissive

Create an entity or note (singleton) or a batch of entities (bulk via items).

Param Type Required Notes
kind string conditional Substrate (entity|note) or granular kind (concept, document, observation, …). Required for the singleton path; not required when items is present.
name string no Entity name (singleton).
entity_kind string no concept|document|dataset|project|person|org|artifact|service|resource (when kind="entity").
note_kind string no observation|insight|question|decision|reference (when kind="note").
content string no Note body text (singleton notes).
description string no Entity free-text description.
tags array<string> no Tag list.
entity_type string no First-class type tag, e.g. "paper", "algorithm", "tool".
properties object no Arbitrary JSON properties.
items array<object> no Bulk entity creation, each {kind, name, entity_kind?, entity_type?, description?, properties?, tags?}. Capped at 1000/request. Bulk-created entities skip embedding until a later reindex.
atomic bool no Bulk path. Default true = all-or-nothing; false = per-item errors collected.
verbose bool no Bulk path. When true, response includes full entity objects.
request(ops="create(kind=\"concept\", name=\"RoPE\", description=\"Rotary position embedding\")")

get — Assertive

Fetch any record by UUID (auto-detects entity/note/edge/event/proposal).

Param Type Required Notes
id uuid yes Full UUID or short hex prefix (min 8 chars).
include_deleted bool no Return soft-deleted records too (default false); requires a full UUID.
request(ops="get(id=\"3f2a9c1e\")")

list — Assertive

List records with optional filtering.

Param Type Required Notes
kind string yes entity|note|edge|event|proposal|message, or a granular kind.
limit integer no Default 20.
offset integer no Default 0.
entity_kind string no Filter when kind="entity".
entity_type string no Filter by type field when kind="entity".
note_kind string no Filter when kind="note".
tags array<string> no OR-match, kind="entity" only.
source_id / target_id uuid no Edge endpoint filters, kind="edge" only.
relations array<string> no Edge relation filter, kind="edge" only.
min_weight / max_weight number no Edge weight bounds, kind="edge" only.
event_kind / event_kinds string / array<string> no kind="event" only; additive.
thread_id string no kind="message" only; full UUID or 8-char prefix.
direction string no kind="message" only: inbound|outbound.
from / to string no kind="message" only, sender/recipient filter.
read bool no kind="message" only.
delivered bool no kind="message" only.
request(ops="list(kind=\"entity\", entity_kind=\"concept\", limit=20)")

stats — Assertive

Return aggregate KG substrate counts (entities, edges, notes). No params.

request(ops="stats()")

update — Declaration

Patch entity, note, or edge fields. Field set depends on substrate: entities accept name/description/properties/tags; notes accept name/content/salience/decay_factor/properties; edges accept relation/weight/properties.

Param Type Required Notes
id uuid yes Record to patch.
kind string no Substrate hint (entity|note|edge); omit to resolve from the UUID.
name string no Entities and notes.
description string no Entities only.
content string no Notes only (body text).
salience number no Notes only, 0.0–1.0.
decay_factor number no Notes only, >= 0.
relation string no Edges only, one of the 17 canonical relations.
weight number no Edges only, 0.0–1.0.
properties object no Shallow-merged in.
tags array<string> no Replaces the tag list.
request(ops="update(id=\"<uuid>\", salience=0.7)")

delete — Declaration

Soft or hard delete a record.

Param Type Required Notes
id uuid yes Record to delete.
kind string no Substrate hint; omit to resolve from the UUID.
hard bool no Default false (soft delete). True permanently removes with edge cascade.
request(ops="delete(id=\"<uuid>\")")

merge — Declaration

Deduplicate two entities. Returns {kept_id, removed_id, edges_rewired, properties_merged, tags_unioned, content_appended, dry_run} — chain with $prev.kept_id, not $prev.id (merge has no top-level id field).

Param Type Required Notes
into_id uuid yes Entity that survives the merge (canonical).
from_id uuid yes Entity merged from; soft-deleted afterward.
request(ops="merge(into_id=\"<canonical-uuid>\", from_id=\"<dup-uuid>\")")

search — Assertive

Hybrid FTS + vector search with RRF fusion.

Param Type Required Notes
kind string yes Substrate or granular kind to search.
query string yes Free-text query.
limit integer no Default 10.
entity_kind string no kind="entity" only.
entity_type string no kind="entity" only.
note_kind string no kind="note" only.
include_superseded bool no kind="note" only; default false excludes notes targeted by a supersedes edge.
properties object no Match records whose properties contain all listed key=value pairs, applied before result truncation inside a bounded candidate window.
tags array no OR-match against tags; entity tags matched at the SQL level, note tags read from properties.tags.
min_score number no Score floor 0.0–1.0. No server default; RRF rank-1 scores on small corpora are typically 0.013–0.033.
request(ops="search(kind=\"entity\", query=\"knowledge graph runtime\", limit=10)")

Create a typed directed edge.

Param Type Required Notes
source_id uuid yes Source node.
target_id uuid yes Target node.
relation string yes One of the 17 canonical relations: contains|part_of|instance_of|extends|variant_of|introduced_by|supersedes|derived_from|precedes|depends_on|enables|implements|competes_with|composed_with|annotates|supports|refutes.
weight number no Default 1.0. 1.0=definitional, 0.7-0.9=strong, 0.4-0.6=plausible.
request(ops="link(source_id=\"<uuid-a>\", target_id=\"<uuid-b>\", relation=\"extends\")")

neighbors — Assertive

Immediate graph neighbors.

Param Type Required Notes
node_id uuid yes Node whose neighbors to return.
direction string no outgoing|incoming|both (default both).
relations array<string> no Restrict to these relation types.
min_weight number no Exclude edges below this weight.
request(ops="neighbors(node_id=\"<uuid>\", direction=\"both\")")

traverse — Assertive

Multi-hop BFS traversal.

Param Type Required Notes
roots array<uuid> yes Starting node UUIDs.
max_depth integer no Default 3.
relations array<string> no Restrict traversal to these relations.
request(ops="traverse(roots=[\"<uuid>\"], max_depth=2)")

context — Assertive

Entity-anchored graph context in one call (ADR-089). Resolves anchors from query and/or entity_ids, expands 1-2 hops via the same runtime op behind neighbors, and assembles a budgeted, deterministically-ordered response — replacing a caller-side search | neighbors chain with a single round-trip. direction defaults to "both", matching neighbors and traverse (outgoing/incoming on request). At least one of query/entity_ids is required. One embedding inference when query is used; zero for a pure entity_ids call.

Param Type Required Notes
query string no* Semantic anchor selection via hybrid search; adds anchors after entity_ids.
entity_ids array<string> no* Explicit anchor UUIDs/prefixes/slugs. Honored in full, never clamped by limit.
hops integer no Expansion depth, clamped 0..=2 (default 1).
budget integer no Output budget in Unicode scalars of compact JSON, clamped 256..=65536 (default 4096).
relations array<string> no Edge-relation filter applied during expansion.
direction string no outgoing|incoming|both (default both).
limit integer no Max anchors from the query leg, clamped 1..=20 (default 5).
fanout integer no Max neighbors per expanded node per hop, clamped 1..=50 (default 10).

* at least one of query/entity_ids required.

request(ops="context(query=\"rotary position embedding\", hops=1, budget=4096)")

Response shape:

{
  "anchors": [
    {
      "entity": { "id": "…", "name": "…", "kind": "concept", "description": "…", "properties": {} },
      "neighbors": [
        {
          "id": "…",
          "name": "…",
          "relation": "extends",
          "direction": "outgoing",
          "weight": 0.9,
          "hop": 1,
          "via": null,
          "description": "…"
        }
      ]
    }
  ],
  "truncated": false,
  "dropped": { "anchors": 0, "neighbors": 0 }
}

query — Assertive

GQL or SPARQL pattern matching (read-only). Write-shaped input (SPARQL INSERT/DELETE/LOAD/WITH…DELETE, GQL/Cypher CREATE/DELETE/DETACH DELETE/SET/MERGE) is rejected — use create/update/link/merge/delete to mutate the graph. Queries that mix fixed-length and variable-length chains are not compiled in one call; split them into separate query() calls.

Param Type Required Notes
query string yes GQL or SPARQL pattern string, read-only.
limit integer no Default 500, hard cap 10,000.
request(ops="query(query=\"MATCH (c:concept)-[:extends]->(d:concept) RETURN c, d LIMIT 20\")")

propose — Commissive

Create an event-sourced change proposal. Returns {id, status, proposer, title} — chain with $prev.id, not $prev.proposal_id. The changeset field has nested objects and cannot be expressed in function-call DSL form; use JSON form.

Param Type Required Notes
title string yes Non-empty short title.
description string yes Non-empty full description.
changeset object yes Discriminated by kind: add_entity, update_entity, add_edge, add_note, merge_entities, supersede_entity, compound (nested steps).
reviewers array<string> no Actor IDs requested as reviewers.
expiry integer no Expiry timestamp, microseconds since epoch.
parent_id uuid no Parent proposal this supersedes or extends.
request(ops="[{\"tool\":\"propose\",\"args\":{\"title\":\"Add GQE\",\"description\":\"Register the GQE concept\",\"changeset\":{\"kind\":\"add_entity\",\"entity\":{\"kind\":\"concept\",\"name\":\"GQE\"}}}}]")

review — Declaration

Approve, reject, comment, or request changes on a proposal.

Param Type Required Notes
id uuid yes Full UUID or 8-char short ID of the proposal.
decision string yes approve|reject|comment|request_changes.
comment string no Reviewer comment.
request(ops="review(id=\"<proposal-id>\", decision=\"approve\")")

withdraw — Commissive

Withdraw an open proposal (proposer-only).

Param Type Required Notes
id uuid yes Full UUID or 8-char short ID of the open proposal.
rationale string no Reason for withdrawing.
request(ops="withdraw(id=\"<proposal-id>\")")

verbs — Assertive

List all MCP-callable verbs registered on this server. Internal subhandlers are excluded.

Param Type Required Notes
category string no Filter: Assertive|Commissive|Declaration|Directive.
pack string no Filter by pack name (kg, gtd, memory, brain, comm, schedule, knowledge, session).
request(ops="verbs()")

gtd pack — 5 verbs

GTD task lifecycle over notes (kind="task"). Optional; load with KHIVE_PACKS=kg,gtd.

gtd.assign — Directive

Create a GTD task (note with kind=task).

Param Type Required Notes
title string yes Task title.
status string no inbox|next|waiting|someday|active (default inbox). Aliases: todo=inbox, in_progress=active, blocked=waiting, later=someday, finished=done.
priority string no p0|p1|p2|p3 (default p2).
assignee string no Assignee identifier.
due string no ISO-8601 due date.
depends_on array<uuid> no Blocking task UUIDs.
context_entity_id uuid no Full UUID of a related KG entity.
tags array<string> no Tag list.
request(ops="gtd.assign(title=\"Ship API reference\", priority=\"p1\", assignee=\"agent:docs\")")

gtd.next — Assertive

List actionable tasks (status next or active) by priority.

Param Type Required Notes
limit integer no Default 10.
assignee string no Filter to this assignee.
request(ops="gtd.next(assignee=\"agent:docs\", limit=10)")

gtd.complete — Declaration

Mark a task done (or cancelled) with an optional result note.

Param Type Required Notes
id uuid yes Task to complete.
result string no Completion note.
status string no Terminal status: done (default) or cancelled.
request(ops="gtd.complete(id=\"<task-id>\", result=\"shipped in PR #600\")")

gtd.tasks — Assertive

List tasks filtered by status, assignee, priority.

Param Type Required Notes
status string no inbox|next|waiting|someday|active|done|cancelled (aliases as in gtd.assign).
assignee string no Filter by assignee.
priority string no p0|p1|p2|p3.
limit integer no Default 20.
offset integer no Default 0.
request(ops="gtd.tasks(status=\"active\", assignee=\"agent:docs\")")

gtd.transition — Declaration

Explicit GTD status transition with lifecycle validation.

Param Type Required Notes
id uuid yes Task to transition.
status string yes Target status (same set/aliases as above).
note string no Note attached to the transition.
request(ops="gtd.transition(id=\"<task-id>\", status=\"active\")")

memory pack — 5 verbs

Salience- and decay-weighted memory notes. Optional; load with KHIVE_PACKS=kg,memory.

memory.remember — Commissive

Create a memory note with salience and decay.

Param Type Required Notes
content string yes Memory content.
salience number no 0.0–1.0. Type-differentiated default: episodic=0.3, semantic=0.5.
decay_factor number no >= 0. Type-differentiated default: episodic=0.02 (~35d half-life), semantic=0.005 (~139d half-life). Higher = faster decay.
memory_type string no episodic|semantic (default episodic); no other values accepted.
source_id string no UUID or 8-char short ID of the entity/note this memory annotates.
embedding_model string no Registered model name; defaults to pack config.
tags array no Stored in properties.tags.
namespace string no Write namespace override. Default: episodic → caller’s namespace, semantic → local.
request(ops="memory.remember(content=\"ADR-016 fixes the DSL grammar\", salience=0.7, memory_type=\"semantic\")")

memory.recall — Assertive

Recall memory notes with decay-aware hybrid ranking. Each hit carries resolved (read-model) values — memory_type defaults to episodic when unset; salience and decay_factor reflect the effective defaults used for ranking.

Param Type Required Notes
query string yes Semantic recall query.
limit integer no Default 10.
top_k integer no Overrides limit (max 100).
min_score number no Composite score floor, always in [0,1]. Typical production floor 0.3–0.7.
score_floor number no Alias for min_score.
min_salience number no Salience floor.
memory_type string no Filter to this type.
fusion_strategy string no rrf|weighted|union|vector_only|keyword_only.
embedding_model string no Registered model name; defaults to pack config.
include_breakdown bool no Include per-component score breakdown.
entity_names array no Names to boost; matches get a 1.3x multiplier.
full_content bool no Default true; false truncates content to 200 chars.
tags array no Filter by properties.tags.
tag_mode string no any (default, OR) or all (AND).
request(ops="memory.recall(query=\"ADR-016 DSL grammar\", limit=5, min_score=0.3)")

memory.feedback — Commissive

Emit explicit feedback on a recalled entity; updates recall-domain posteriors.

Param Type Required Notes
target_id string yes UUID of the recalled entity or memory.
signal string yes useful|not_useful|wrong|explicit_positive|explicit_negative|implicit_positive|implicit_negative|correction.
request(ops="memory.feedback(target_id=\"<uuid>\", signal=\"useful\")")

memory.prune — Commissive

Soft-delete memories below a salience threshold and/or past expires_at (curation-layer, ADR-014).

Param Type Required Notes
min_salience number no Soft-delete memories strictly below this value.
before integer no Soft-delete memories expired at/before this Unix microsecond timestamp; defaults to now; 0 skips the expiry filter.
namespace string no Defaults to local.
dry_run bool no Default false; when true, counts candidates without deleting.
request(ops="memory.prune(min_salience=0.2, dry_run=true)")

memory.vacuum — Commissive

Run SQLite VACUUM to reclaim space freed by soft-deleted rows. No params.

request(ops="memory.vacuum()")

brain pack — 14 verbs

Recall-tuning profiles: Beta-posterior scoring, profile lifecycle, and the actor/ namespace/consumer-kind resolution table that picks which profile serves a given caller. Optional; load with KHIVE_PACKS=kg,brain.

brain.profiles — Assertive

List profiles, optionally filtered by lifecycle.

Param Type Required Notes
lifecycle string no active|inactive|archived; omit for all.
request(ops="brain.profiles(lifecycle=\"active\")")

brain.profile — Assertive

Profile metadata, latest snapshot, current state summary.

Param Type Required Notes
profile_id string yes Profile ID string (e.g. "balanced-recall-v1") — not a UUID.
request(ops="brain.profile(profile_id=\"implementer-recall-v1\")")

brain.resolve — Assertive

Show which profile would serve a caller context.

Param Type Required Notes
consumer_kind string yes Verb/operation type about to be performed (e.g. "recall").
actor string no Default * (wildcard match).
namespace string no Default * (wildcard match).
request(ops="brain.resolve(consumer_kind=\"recall\", actor=\"agent:docs\")")

brain.activate — Commissive

Move a profile to Active (starts the live update loop).

Param Type Required Notes
profile_id string yes Profile to activate.
request(ops="brain.activate(profile_id=\"implementer-recall-v1\")")

brain.deactivate — Commissive

Move a profile to Inactive (stop live updates, retain state).

Param Type Required Notes
profile_id string yes Profile to deactivate.
request(ops="brain.deactivate(profile_id=\"implementer-recall-v1\")")

brain.archive — Declaration

Move a profile to Archived (read-only, audit-retained).

Param Type Required Notes
profile_id string yes Profile to archive.
request(ops="brain.archive(profile_id=\"deprecated-recall-v0\")")

brain.reset — Declaration

Reset posteriors to priors (preserves event history).

Param Type Required Notes
profile_id string no Must exist and be active. Defaults to "balanced-recall-v1".
request(ops="brain.reset(profile_id=\"implementer-recall-v1\")")

brain.feedback — Commissive

Emit a FeedbackExplicit event into the shared log.

Param Type Required Notes
target_id uuid yes Memory note or entity the feedback applies to.
signal string yes Same signal set as memory.feedback.
served_by_profile_id string no Profile that served the rated result.
section_signals object no Per-section signals for knowledge_compose profiles: {"section_name": "useful"\|"not_useful"\|"wrong"}.
scorer_run_id string no ADR-081 scorer-pass id; must pair with serve_ledger_id.
serve_ledger_id string no ADR-081 brain_serve_ledger row id; must pair with scorer_run_id.
request(ops="brain.feedback(target_id=\"<uuid>\", signal=\"useful\")")

brain.auto_feedback — Commissive

Emit implicit feedback for recall results supplied by an agent — the convenience verb to call right after memory.recall instead of hand-building brain.feedback.

Param Type Required Notes
query string yes The recall query that produced the results.
results array yes Recall result objects; the first object’s id is credited.
signal string no Defaults to implicit_positive.
served_by_profile_id string no Profile that served the recall.
scorer_run_id string no Forwarded verbatim to brain.feedback; pairs with serve_ledger_id.
serve_ledger_id string no Forwarded verbatim to brain.feedback; pairs with scorer_run_id.
request(ops="memory.recall(query=\"x\", limit=5) | brain.auto_feedback(query=\"x\", results=[{\"id\": \"$prev.items[0].id\"}])")

brain.bind — Declaration

Write a row in the profile resolution table.

Param Type Required Notes
profile_id string yes Must exist.
actor string no Default * (all actors).
namespace string no Default * (all namespaces).
consumer_kind string no Default * (all kinds).
priority integer no Higher wins on multiple matches (default 0).
request(ops="brain.bind(profile_id=\"implementer-recall-v1\", actor=\"role:implementer\")")

brain.unbind — Declaration

Remove rows from the profile resolution table. At least one filter is required.

Param Type Required Notes
profile_id string no AND-combined with other filters.
actor string no  
namespace string no  
consumer_kind string no  
request(ops="brain.unbind(actor=\"role:implementer\")")

brain.bindings — Assertive

List rows in the profile resolution table, optionally filtered.

Param Type Required Notes
profile_id string no  
actor string no  
namespace string no  
consumer_kind string no  
request(ops="brain.bindings(consumer_kind=\"recall\")")

brain.create_profile — Declaration

Create a new brain profile with a given name and optional seed priors.

Param Type Required Notes
name string yes Profile ID (alphanumeric + hyphens), must be unique.
description string no Human-readable description.
consumer_kind string no Default "recall".
seed_priors object no For knowledge_compose: {"section_posteriors": {"overview": {"alpha": 2.0, "beta": 2.0}, ...}}; for recall: {"relevance": {"alpha": 7.0, "beta": 3.0}, ...}.
request(ops="brain.create_profile(name=\"implementer-recall-v2\", consumer_kind=\"recall\")")

brain.register_adapter — Declaration

Register an adapter integrity record so the router only composes adapters matching the active base model revision.

Param Type Required Notes
adapter_id string yes Stable adapter identifier (used as the entity name).
content_hash string yes Content hash of the adapter weights.
base_model_revision string yes Must match the active revision or registration is rejected.
metadata object no Merged into entity properties.
request(ops="brain.register_adapter(adapter_id=\"lora-v3\", content_hash=\"<sha256>\", base_model_revision=\"2026-07-01\")")

comm pack — 7 verbs

Actor-to-actor messaging with threading. Optional; load with KHIVE_PACKS=kg,comm.

comm.send — Commissive

Send a message, optionally threaded.

Param Type Required Notes
to string yes Actor label, e.g. "lambda:leo". Both copies land in the caller’s namespace; no cross-namespace write occurs.
content string yes Non-empty message body.
subject string no Optional subject line.
thread_id uuid no Groups the message into an existing thread.
request(ops="comm.send(to=\"lambda:leo\", subject=\"PR ready\", content=\"#600 is open for review\")")

comm.inbox — Assertive

List inbound messages for the caller.

Param Type Required Notes
limit integer no Default 20, max 200.
status string no unread (default)|read|all.
request(ops="comm.inbox(limit=10)")

comm.read — Declaration

Mark an inbound message as read. Outbound messages cannot be marked read.

Param Type Required Notes
id string yes 8-char prefix or full UUID of the inbound message.
request(ops="comm.read(id=\"<message-id>\")")

comm.reply — Commissive

Reply to a message, threading linkage.

Param Type Required Notes
id string yes 8-char prefix or full UUID of the message being replied to.
content string yes Non-empty reply body.
request(ops="comm.reply(id=\"<message-id>\", content=\"On it.\")")

comm.thread — Assertive

Retrieve all messages in a conversation thread, ordered chronologically.

Param Type Required Notes
id string yes Thread root: 8-char prefix or full UUID of the originating message.
limit integer no Default 100, max 500.
request(ops="comm.thread(id=\"<thread-root-id>\")")

comm.probe — Assertive

Strictly read-only poll for new inbound message metadata and a stale-unread count. No read-flag mutation, no writes: designed for monitors polling every ~30 seconds, served by a single cheap indexed query. Returns a cursor_us high-water mark, a stale_unread_count of inbound messages unread past the staleness window, and a new_messages array of up to 100 inbound rows {id, created_at_us, from_actor, subject?} newer than since_us.

Param Type Required Notes
actor string yes Actor label whose inbound mail is probed.
since_us integer no Microsecond-epoch cursor; only newer rows returned.
stale_minutes integer no Staleness window for the unread count (default 20).
request(ops="comm.probe(actor=\"lambda:leo\", since_us=1751932800000000)")

comm.health — Assertive

Read-only per-channel health snapshot. Returns the daemon-persisted heartbeat row for every known channel: timestamps and consecutive-failure counts only, never a computed healthy bool. Health judgment belongs to the caller. Rows are read from the pinned operational namespace (local) unconditionally, regardless of the caller’s dispatch namespace. An empty channels array cannot distinguish “no daemon running” from “channels configured but never polled”. See the communication guide for the full response contract.

No parameters.

request(ops="comm.health()")

schedule pack — 4 verbs

Time-triggered reminders and deferred verb dispatch. Optional; load with KHIVE_PACKS=kg,schedule.

schedule.remind — Commissive

Create a time-triggered reminder.

Param Type Required Notes
content string yes Non-empty reminder message.
at string yes RFC 3339 trigger time, e.g. "2026-06-01T09:00:00Z".
repeat string no daily|weekly|monthly, or a limited 5-field cron form using only * or one in-range integer per field (steps/ranges/lists not accepted).
request(ops="schedule.remind(content=\"check PR #600 CI\", at=\"2026-07-05T09:00:00Z\")")

schedule.schedule — Commissive

Schedule a future verb dispatch.

Param Type Required Notes
action string yes Verb dispatch payload, e.g. "schedule.remind(content=\"hello\")".
at string yes RFC 3339 trigger time.
repeat string no Same recurrence grammar as schedule.remind.
request(ops="schedule.schedule(action=\"gtd.next(assignee=\\\"agent:docs\\\")\", at=\"2026-07-05T09:00:00Z\")")

schedule.agenda — Assertive

List upcoming scheduled events.

Param Type Required Notes
from string no RFC 3339 window start; omit to start from the earliest pending event.
to string no RFC 3339 window end; omit for all future events.
limit integer no Default 20, max 200.
request(ops="schedule.agenda(limit=10)")

schedule.cancel — Declaration

Cancel a scheduled event.

Param Type Required Notes
id string yes Full UUID of the scheduled event.
request(ops="schedule.cancel(id=\"<event-id>\")")

knowledge pack — 19 verbs

The knowledge-atom corpus: bulk ingest, TF-IDF + embedding search, domain composition, section-level review/dispute, and KG-sugar verbs for citing sources. Optional; load with KHIVE_PACKS=kg,knowledge.

knowledge.upsert_atoms — Commissive

Bulk insert or update knowledge atoms by slug.

Param Type Required Notes
atoms array<object> yes {slug, name, content, tags?, properties?, finalized?} per atom.
chunk_size integer no Client-side chunking hint, max 5000.
request(ops="[{\"tool\":\"knowledge.upsert_atoms\",\"args\":{\"atoms\":[{\"slug\":\"rope\",\"name\":\"RoPE\",\"content\":\"Rotary position embedding...\"}]}}]")

knowledge.upsert_domains — Commissive

Bulk insert or update domain groupings of atoms.

Param Type Required Notes
domains array<object> yes {slug, name, description?, tags?, members?} per domain.
request(ops="[{\"tool\":\"knowledge.upsert_domains\",\"args\":{\"domains\":[{\"slug\":\"attention\",\"name\":\"Attention mechanisms\"}]}}]")

knowledge.get — Assertive

Fetch a single atom or domain by UUID or slug.

Param Type Required Notes
id string yes Atom/domain UUID or slug.
include_sections bool no Include the atom’s sections under a sections key (ignored for domains). Each section: id, atom_id, namespace, section_type, heading, content, content_hash, status, tokens, sort_order, created_at, updated_at, ordered by sort_order, created_at, id. Default false.
request(ops="knowledge.get(id=\"rope\", include_sections=true)")

knowledge.list — Assertive

Paginated listing of atoms or domains.

Param Type Required Notes
type string no atom|domain (default atom).
limit integer no Default 20, max 500.
offset integer no Pagination offset.
request(ops="knowledge.list(type=\"domain\", limit=50)")

knowledge.delete_atoms — Commissive

Soft-delete atoms by slug or ID.

Param Type Required Notes
ids array<string> yes Atom slugs or UUIDs.
request(ops="knowledge.delete_atoms(ids=[\"stale-atom-slug\"])")

knowledge.stats — Assertive

Corpus statistics: atom count, domain count, coverage. No params.

request(ops="knowledge.stats()")

knowledge.index — Commissive

Backfill embeddings + FTS for atoms/domains.

Param Type Required Notes
ids array<string> no Atom slugs/IDs to index; omit to index all.
batch_size integer no Default 500, max 1000.
insert_only bool no Deprecated no-op, accepted for API compatibility only.
rebuild_ann bool no Rebuild the in-memory Vamana ANN index (default false).
request(ops="knowledge.index(rebuild_ann=true)")

knowledge.fold — Assertive

Budget-constrained knapsack selection of scored candidates.

Param Type Required Notes
candidates array<object> yes {id, score, size, content?, category?} per candidate.
budget integer yes Token/size budget for the selected set.
min_score number no Default 0.0.
category_weights object no Per-category score multipliers.
request(ops="[{\"tool\":\"knowledge.fold\",\"args\":{\"candidates\":[{\"id\":\"a\",\"score\":0.8,\"size\":400}],\"budget\":4000}}]")

knowledge.search — Assertive

TF-IDF ranked search over the knowledge corpus with embedding rerank (default when an embedder is configured). Draft and deprecated atoms are excluded by default. Score bands: score>=0.46 reliably on-target, 0.42<=score<0.46 mixed quality, score<0.42 mostly off-target.

Param Type Required Notes
query string yes Search query text.
type string no atom|domain (default both).
include_drafts bool no Default false; no-op when status is set.
status string no Exact status filter: draft|reviewed|deprecated; overrides include_drafts.
exclude_status string no Exclude an exact status; only used when status unset.
role string no Agent role hint, prepended to the query for scoring.
limit integer no Default 10, max 100.
min_score number no Default 0.0.
weights object no {w_name, w_tags, w_content, w_exact_name, w_bigram, expand_discount, coverage_alpha}.
decompose bool no Default false; enables query decomposition.
decompose_threshold integer no Default 4 non-stop terms to trigger decomposition.
intersection_bonus number no Default 0.25; score multiplier for multi-sub-query hits.
rerank bool no Default true; embedding rerank; no-op with no embedder configured.
rerank_alpha number no Default 0.7 (TF-IDF-dominant blend).
request(ops="knowledge.search(query=\"FastAPI JWT middleware\", rerank=true, limit=10)")

knowledge.suggest — Assertive

Suggest relevant knowledge domains for a query. Draft/deprecated domain atoms excluded by default.

Param Type Required Notes
query string yes Orientation query text.
role string no Agent role hint.
limit integer no Default 8, max 100.
request(ops="knowledge.suggest(query=\"async middleware retry circuit breaker patterns\", role=\"implementer\")")

knowledge.compose — Assertive

Compose a markdown briefing from selected knowledge domains and atoms.

Param Type Required Notes
domain_ids array<string> no Domain UUIDs/slugs whose member atoms to include.
atom_ids array<string> no Atom UUIDs/slugs to include directly.
query string yes Reranks the selected atom bodies.
request(ops="knowledge.compose(query=\"FastAPI JWT middleware validation patterns\", domain_ids=[\"attention\"])")

knowledge.edit — Commissive

Upsert sections for an atom without wiping other sections.

Param Type Required Notes
id string yes Atom UUID or slug.
sections array<object> yes [{section_type, content, heading?, sort_order?}]. section_type is a closed enum: overview|core_model|boundary_conditions|formalism|operational_guidance|examples|failure_modes|expert_lens|references|other. content must be >= 80 characters.
request(ops="[{\"tool\":\"knowledge.edit\",\"args\":{\"id\":\"rope\",\"sections\":[{\"section_type\":\"overview\",\"content\":\"Rotary position embedding rotates query/key vectors by an angle proportional to position...\"}]}}]")

knowledge.import — Commissive

Ingest atlas markdown file(s) as atoms with parsed sections.

Param Type Required Notes
path string yes Filesystem path to a markdown file or directory.
format string no Only atlas_md supported (default).
chunk_strategy string no section (default, one section per atom) or atom (whole file as one atom).
request(ops="knowledge.import(path=\"/path/to/atlas/rope.md\")")

knowledge.challenge — Commissive

Mark a section as disputed and increment the atom’s dispute_count.

Param Type Required Notes
atom_id string yes Atom UUID or slug.
section_type string yes Section type to challenge.
content_hash string no Required when more than one eligible section of that type exists.
reason string no Optional challenge reason.
request(ops="knowledge.challenge(atom_id=\"rope\", section_type=\"formalism\", reason=\"formula sign error\")")

knowledge.adjudicate — Commissive

Resolve a disputed section and decrement the atom’s dispute_count.

Param Type Required Notes
atom_id string yes Atom UUID or slug.
section_type string yes Section type to adjudicate.
content_hash string no Required when more than one disputed section of that type exists.
resolution string yes accept (marks verified) or reject (marks reviewed).
request(ops="knowledge.adjudicate(atom_id=\"rope\", section_type=\"formalism\", resolution=\"accept\")")

knowledge.learn — Commissive

Register a concept entity with optional domain and tags.

Param Type Required Notes
name string yes Concept name.
description string no Optional description.
domain string no Folded into properties.domain.
tags array<string> no Optional tag list.
request(ops="knowledge.learn(name=\"GQA\", domain=\"attention\", description=\"Grouped-query attention\")")

knowledge.cite — Commissive

Link a concept to the paper or source that introduced it.

Param Type Required Notes
concept_id uuid yes Concept entity ID.
source_id uuid yes Source entity ID; must be kind=document, kind=person, or kind=org (introduced_by edge rule).
weight float no Defaults to 1.0.
request(ops="knowledge.cite(concept_id=\"<concept-uuid>\", source_id=\"<paper-uuid>\")")

knowledge.topic — Assertive

List concepts filtered by domain or free-text query.

Param Type Required Notes
domain string no Filter to concepts tagged with this domain.
query string no Free-text search across name + description.
limit integer no Default 20, max 100.
request(ops="knowledge.topic(domain=\"attention\")")

knowledge.feedback — Commissive

Apply per-section feedback signals to update section posterior weights.

Param Type Required Notes
section_signals object yes {section_type: signal}, e.g. {"overview": "useful", "formalism": "not_useful"}. Signals: useful|not_useful|wrong.
target_id string no UUID of the rated atom/entity. When paired with a configured brain profile, also forwards to brain.feedback.
request(ops="knowledge.feedback(target_id=\"rope\", section_signals={\"overview\": \"useful\"})")

session pack — 4 verbs

Cross-provider agent-session continuity records. Optional; load with KHIVE_PACKS=kg,session.

session.store — Directive

Persist an agent-session record as a session note.

Param Type Required Notes
content string yes Verbatim transcript or summary content.
title string no Stored as note.name.
provider string no Provider label, e.g. codex, claude_code, openai.
provider_session_id string no Provider-native continuity anchor.
tags array<string> no Stored in properties.tags.
request(ops="session.store(content=\"...\", provider=\"claude_code\", title=\"pages revamp session\")")

session.list — Assertive

List stored sessions newest first.

Param Type Required Notes
limit integer no 1–200, default 20.
offset integer no Default 0.
provider string no Exact filter on properties.provider.
request(ops="session.list(provider=\"claude_code\", limit=10)")

session.resume — Assertive

Fetch one session’s full content by UUID or 8+ hex prefix.

Param Type Required Notes
id string yes Full UUID or 8+ hex short prefix.
request(ops="session.resume(id=\"<session-id>\")")

session.export — Assertive

Serialize one stored session as json or markdown.

Param Type Required Notes
id string yes Full UUID or 8+ hex short prefix.
format string no json|markdown, default json.
request(ops="session.export(id=\"<session-id>\", format=\"markdown\")")

Further reading


Raw markdown for this page: /md/api-reference.md