# 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`](md/api-reference.md). The site also publishes
[`/llms.txt`](llms.txt) (a short index) and [`/llms-full.txt`](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):

```json
{
  "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)")
```

### `link` — Commissive

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](../adr/ADR-089-context-verb.md)).
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:

```json
{
  "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](communication.md) 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

- [Getting Started](getting-started.html): install and connect an MCP client.
- [Knowledge Graph Modeling](knowledge-graph.html): entity kinds, edge relations, patterns.
- [Memory and Recall](memory.html): salience, decay, and recall internals.
- [Search and Retrieval](search.html): FTS, vector, hybrid fusion, reranking.
- [GTD Task Management](tasks.html): task lifecycle in depth.
- [Prompt Cookbook](prompt-cookbook.html): ready-to-use verb patterns.
- [ADR-016: request DSL](https://github.com/ohdearquant/khive/blob/main/docs/adr/ADR-016-request-dsl.md)
- [ADR-002: edge ontology](https://github.com/ohdearquant/khive/blob/main/docs/adr/ADR-002-edge-ontology.md)
