loopctl-mcp-server 2.88.0 → 2.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/index.js +19 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -320,7 +320,7 @@ exhausting a paginated walk is not the same as the row being absent.
|
|
|
320
320
|
| `knowledge_conflicts` | List potential-conflict article pairs — published articles flagged "too similar to comfortably coexist" by the auto-linker / nightly lint sweep, highest-overlap first. The KB only FLAGS the pair; it does NOT decide redundancy-vs-contradiction — that's your call with live context. Each entry has both articles (id/title/status/category) + similarity. Then merge (supersede one, `knowledge_create` the merged article, or PATCH) or reconcile if they genuinely disagree. Paginated with `total_count` in meta. Agent role. Optional: `limit` (default 50, max 1000, clamped), `offset`, `origin` (`system` or `asserted` — asserted rows lead the default ordering, so pass `system` to review machine-flagged pairs alone). |
|
|
321
321
|
| `knowledge_assert_conflict` | **ASSERT** a conflict between two articles the system never flagged — the way to contest an article you just deliberately refuted. `knowledge_resolve_conflict` only reaches pairs the AUTO-LINKER flagged by similarity, which is exactly wrong for a correction: the pair is minutes old (the nightly linker has not run) and a good correction argues about the CONCLUSION, so it may never be similar enough to be flagged at all. The pair then appears in `knowledge_conflicts` with `origin: "asserted"` and your claim attached, and in both articles' `potential_conflicts`. **It retires, hides and down-ranks nothing**, and does not remove either article from curated answers (that still needs a system flag). **And you cannot judge your own assertion** — `knowledge_resolve_conflict` returns `409 self_asserted_conflict` to the asserting key, because you named both ids; another key decides. Idempotent per pair (`created: false` on a re-assert; never overwrites a system flag's provenance). Agent role. Required: `source_article_id`, `target_article_id`, `evidence`. Optional: `classification`, `proposed_authoritative_article_id`. |
|
|
322
322
|
| `knowledge_resolve_conflict` | Record YOUR verdict on a potential-conflict pair (from `knowledge_conflicts`). Dispositions: `dismiss` (false positive, drops from queue), `supersede` (one wins — pass `authoritative_article_id`; nightly executor links + retires loser, only at `confidence:"high"`, reversible/audited), `merge` (at high confidence an LLM synthesizes both into ONE new DRAFT, sources preserved, never auto-published). Non-destructive at agent role — you record intent, the privileged nightly job executes. Only pairs with a real flag are reachable; for a pair that was never flagged, use `knowledge_assert_conflict` first — and note that a DIFFERENT key must then record the verdict. Last-write-wins per pair. **`supersede` is the one disposition that retires an article unattended**, so its `confidence` is capped server-side: an agent-role `"high"` is recorded as `"medium"` (`data.requested_confidence` + `note` say so) and the pair stays in `knowledge_conflicts` until an orchestrator+ key records it at high; a `high` supersede also REQUIRES `evidence` (422 without it). `merge` is never capped. Sent on `LOOPCTL_AGENT_KEY`, so a pair YOU asserted answers `409 self_asserted_conflict` here by design — another principal (a second session, an orchestrator, a human operator) records that verdict. Required: `source_article_id`, `target_article_id`, `disposition`. Optional: `authoritative_article_id`, `classification`, `evidence` (required for a high supersede), `confidence`. |
|
|
323
|
-
| `knowledge_create` | Create a new knowledge article. File findings, document patterns, or record decisions. **Published immediately by default** (visible per `metadata.visibility` — default `owner` for agent authors, only visible to that agent; `shared` for visibility to all agents) — the response `note` says which outcome occurred. Pass `draft: true` to stage it for later review instead (publish afterwards with `knowledge_publish`). Pass `metadata: {visibility: "shared"}` to make the article visible to other agents; higher roles can set visibility and agent_id explicitly. Pass `idempotency_key` for idempotent capture (re-creating with the same key is a no-op returning the existing article — no partial duplicates). RESERVED TAG NAMESPACE: a tag starting with `idem-` must be `idem-<family>-<digest>` (digest = 12 or 40 lowercase hex chars, e.g. `idem-url-7ebe1ca33431`) or the write is rejected 422 — never silently rewritten; put topics outside that prefix and use `idempotency_key` for idempotent capture. Optional: `category`, `tags`, `project_id`, `draft`, `idempotency_key`, `source_type`, `source_id`, `metadata`. |
|
|
323
|
+
| `knowledge_create` | Create a new knowledge article. File findings, document patterns, or record decisions. **Published immediately by default** (visible per `metadata.visibility` — default `owner` for agent authors, only visible to that agent; `shared` for visibility to all agents) — the response `note` says which outcome occurred. Pass `draft: true` to stage it for later review instead (publish afterwards with `knowledge_publish`). Pass `metadata: {visibility: "shared"}` to make the article visible to other agents; higher roles can set visibility and agent_id explicitly. Pass `idempotency_key` for idempotent capture (re-creating with the same key is a no-op returning the existing article — no partial duplicates). A `deduplicated: true` response carries `content_drift` / `title_drift` when the server supports them (an older loopctl omits the keys — absent means UNKNOWN, never false; the keys' presence is the capability signal, there is no server version to compare against): true means the payload you just sent DIFFERED from the returned article and was discarded. Which side moved is not decidable from your end (the stored article may have been curated or machine-retitled since your last capture), so read it first, and use `knowledge_update` on the returned `data.id` only if that row is your own prior capture and your version is still the intended one. When `gate.verdict` is `duplicate` the returned row was matched by SIMILARITY with no self-exclusion — it may be an article you did not write, or your own earlier capture — so PATCH it only if it is your own prior capture, else merge into it or re-send under a DIFFERENT title with `force: true` (the same title answers 409 title_conflict). RESERVED TAG NAMESPACE: a tag starting with `idem-` must be `idem-<family>-<digest>` (digest = 12 or 40 lowercase hex chars, e.g. `idem-url-7ebe1ca33431`) or the write is rejected 422 — never silently rewritten; put topics outside that prefix and use `idempotency_key` for idempotent capture. Optional: `category`, `tags`, `project_id`, `draft`, `idempotency_key`, `source_type`, `source_id`, `metadata`. |
|
|
324
324
|
| `knowledge_update` | Edit an EXISTING article IN PLACE, **preserving its ID** (IDs are load-bearing — cited in project CLAUDE.mds and cross-links). Fold in a new fact, tidy a hub, retag, or reclassify without churning a new row. Send only the fields to change; `tags` REPLACES the whole array. A changed body/tags re-triggers embedding + auto-linking. Agent role — KB-content curation (non-destructive + audited; the in-place edit overwrites the prior body, so it is not reversible either); visibility-scoped, so another agent's private/owner memory 404s. The reserved `idem-` tag namespace applies here too (see `knowledge_create`). Required: `article_id`. Optional: `title`, `body`, `category`, `tags`, `metadata`. |
|
|
325
325
|
| `knowledge_okf_export` | **Requires `LOOPCTL_USER_KEY`.** Export the wiki as a portable OKF (Open Knowledge Format) v0.1 bundle of markdown files. Writes to `out_dir`, or returns `{files, meta}` inline. |
|
|
326
326
|
| `knowledge_okf_import` | **Requires `LOOPCTL_USER_KEY`.** Import an OKF v0.1 bundle from a local directory. Creates or (with `merge`) updates articles; tolerates and preserves unknown frontmatter. |
|
package/index.js
CHANGED
|
@@ -5267,7 +5267,21 @@ const TOOLS = [
|
|
|
5267
5267
|
"existing article with the same title AND an identical body (ignoring surrounding whitespace), the " +
|
|
5268
5268
|
"server returns that existing article idempotently (HTTP 200) instead of a 422. A same-title create " +
|
|
5269
5269
|
"with a DIFFERENT body returns 409 title_conflict — do not retry; choose a different title or PATCH " +
|
|
5270
|
-
"the existing article."
|
|
5270
|
+
"the existing article. CONTENT DRIFT: a `deduplicated: true` response carries " +
|
|
5271
|
+
"`content_drift` / `title_drift` when the server supports them (an older loopctl omits the " +
|
|
5272
|
+
"keys — treat ABSENT as unknown, never as false; presence of the keys IS the capability " +
|
|
5273
|
+
"signal, there is no server version to compare against); true means the payload you just " +
|
|
5274
|
+
"sent DIFFERS from the returned article and was DISCARDED. Which SIDE moved is not decidable " +
|
|
5275
|
+
"from your end — you may have edited, or the stored article may have been curated by someone " +
|
|
5276
|
+
"else or machine-retitled since your last capture — so READ the returned article first " +
|
|
5277
|
+
"(knowledge_get on `data.id`). Only THEN, and only if the returned row is your own prior " +
|
|
5278
|
+
"capture, apply your version with knowledge_update. When the response also carries " +
|
|
5279
|
+
"`gate.verdict: \"duplicate\"` the returned row was matched by SIMILARITY with no " +
|
|
5280
|
+
"self-exclusion, so it may be an article you did not write OR your own earlier capture: read " +
|
|
5281
|
+
"it, PATCH only your own prior capture, else merge into it or re-send under a DIFFERENT " +
|
|
5282
|
+
"title with force: true (the same title answers 409 title_conflict). Sending `body` as " +
|
|
5283
|
+
"null or a non-string also reports content_drift: the dedup short-circuits before validation, " +
|
|
5284
|
+
"so that is how a broken extraction surfaces instead of reading as in-sync.",
|
|
5271
5285
|
inputSchema: {
|
|
5272
5286
|
type: "object",
|
|
5273
5287
|
properties: {
|
|
@@ -5326,7 +5340,10 @@ const TOOLS = [
|
|
|
5326
5340
|
description:
|
|
5327
5341
|
"Optional: stable per-article key for idempotent capture (max 255). Re-creating " +
|
|
5328
5342
|
"with the same key is a no-op that returns a reference to the existing article " +
|
|
5329
|
-
"(deduplicated; id only, not its body) instead of a partial duplicate
|
|
5343
|
+
"(deduplicated; id only, not its body) instead of a partial duplicate — a changed " +
|
|
5344
|
+
"body is NOT applied and NOT refused, but IS reported as content_drift so a " +
|
|
5345
|
+
"re-running sourcer keeps working while a genuine edit is not lost silently (read the " +
|
|
5346
|
+
"stored article before overwriting it — the other side may have moved). Use a " +
|
|
5330
5347
|
"HIGH-ENTROPY value (e.g. a content hash) — it is a per-tenant lookup key, not a " +
|
|
5331
5348
|
"secret, so a guessable key lets another agent in your tenant probe which keys " +
|
|
5332
5349
|
"exist. Distinct from source_type/source_id (which mark a shared source).",
|