MCP tools
The canonical MCP tool catalog, onboarding contract, and schemas exposed by the Kibi MCP server.
The Kibi Model Context Protocol (MCP) server is a peer public interface alongside the CLI's dedicated JSON routes. It serves MCP-capable agents over stdio and receives JSON-RPC 2.0 requests; operation schemas and executors are shared with the CLI.
Public Tools
The public MCP surface is intentionally curated. Agents can call exact lookup, discovery/reporting, mutation, and validation tools through MCP, with equivalent operation access through kibi <route> --input <file|->. Every MCP tool also accepts workspaceRoot, the directory the call is about; see Workspace Routing.
Response envelope
Every tool except kb_job_status returns structuredContent as a protocol 1
envelope: { kibiProtocol, operation, status, data, effects, diagnostics, nextActions } (plus error on failure). The operation's result fields sit
under data. Field paths written structuredContent.<field> in this
reference (structuredContent.bindingHints, structuredContent.actions,
structuredContent.relationshipPlan, structuredContent.receipt,
structuredContent.warnings, structuredContent.violations[],
structuredContent.qualityDiagnostics[], ...) are shorthand for
structuredContent.data.<field>. The CLI JSON routes print the same envelope.
A tool that rejects its input or fails with a Kibi error code (for example
VALIDATION_FAILED for a clauses entry that is not a verbatim fragment)
answers with isError: true and an error envelope: status: "error" and
error: { code, message, retryable }, the same error the CLI JSON route
prints for that input. The text content reads
Tool <name> failed: [<code>] <message>. A failure that carries no Kibi code
is still raised as a tool error with the text Tool <name> failed: <message>
and no envelope.
The discovery tools (kb_query, kb_search, kb_status,
kb_prepare_impact_review) also put the data JSON in front of their text
summary, for hosts that hide structuredContent from the agent. On Claude
Code, which shows structuredContent, the text is the summary alone, so each
result is sent once. KIBI_MCP_STRUCTURED_TEXT=omit or embed overrides that
choice for any host (see Diagnostic usage log).
Tool list
The server registers 16 tools by default:
| Area | Tools |
|---|---|
| Discovery and reporting | kb_query, kb_search, kb_status, kb_find_gaps, kb_coverage, kb_graph |
| Skills | kb_skills |
| Modeling (read-only) | kb_model |
| Mutation and validation | kb_upsert (also the dryRun: true preflight), kb_delete, kb_check, kb_ingest_proof |
| Planning and review | kb_prepare_impact_review, kb_plan_bootstrap, kb_compile_intent, kb_apply_plan |
Two more tools are opt-in. Set KIBI_MCP_OPTIONAL_TOOLS in the server
environment to a comma-separated list of names, or all:
kb_sparql_remote: remote SPARQLSELECTqueries (below).kb_job_status: pollskb_checkandkb_apply_planjobs started withasync: true(below). Without it, both tools ignoreasync: trueand run synchronously.
Catalog operations, MCP calls, and CLI routes
The shared operation catalog is larger than the MCP tool list. Narrow
operations stay in the catalog and on the CLI; MCP reaches them through a
consolidated tool so hosts load fewer tool definitions. Result payloads still
name catalog operations, for example recommended_tools: ["kb_model_requirement"],
suggested_next_tool, suggested_next_tools, and repair-plan workflowSteps.
Translate them with this table:
| Catalog operation | MCP call | CLI route |
|---|---|---|
kb_skills_list |
kb_skills with action: "list" |
kibi skills list / skills-list, or kibi skill with "action":"list" |
kb_skills_load |
kb_skills with action: "load", id |
kibi skills load / skills-load, or kibi skill |
kb_skills_read |
kb_skills with action: "read", id, resource |
kibi skills read / skills-read, or kibi skill |
kb_semantic_advisor |
kb_model with mode: "analyze" |
kibi semantic-advisor, or kibi model with "mode":"analyze" |
kb_model_requirement |
kb_model with mode: "requirement" |
kibi model-requirement, or kibi model |
kb_suggest_predicates |
kb_model with mode: "predicates" |
kibi suggest-predicates, or kibi model |
kb_validate_upsert |
kb_upsert with dryRun: true |
kibi validate-upsert, or kibi upsert with "dryRun": true |
kb_sparql_remote |
kb_sparql_remote (opt-in) |
kibi sparql-remote |
kb_job_status |
kb_job_status (opt-in) |
none: jobs live in the server process |
Every other operation has an MCP tool and a CLI route of the same name (for
example kb_check and kibi check). With diagnostic logging on,
.kb/usage.log records a kb_model call under its routed operation (mode: "predicates" logs as kb_suggest_predicates) and a kb_upsert dry run as
kb_validate_upsert.
Host-visible tool names
The canonical MCP names in this reference use the kb_* form. Some hosts display tools with the configured MCP server name prefixed. In OpenCode, the same tools commonly appear as kibi_kb_search, kibi_kb_query, kibi_kb_upsert, kibi_kb_check, and kibi_kb_plan_bootstrap. Use the host-visible prefixed name when an agent must reference an exact tool identifier; the semantics are identical to the canonical kb_* names documented here.
Generic-agent onboarding
For a copy-paste discovery snippet, see generic-agent onboarding. Bundled skills are the canonical agent-guidance source; do not copy a long operating manual into the agent.
MCP-capable agents should use the standard tools/list capability discovery step, then follow Kibi's progressive-disclosure path instead of assuming that a package skills/ directory is loaded by the host:
- Call
kb_skillswithaction: "list"to obtain the bundled skill manifests. - Call
kb_skillswithaction: "load"and a returnedid, normallykibi-usagefor general Kibi workflow guidance. Loadkibi-bootstrap,kibi-freshness,kibi-traceability,kibi-decisions(a stated rule, a firm-requirement edit or a conflict with a recorded rule),kibi-commit-review(a blocked commit or an impact review), orkibi-provable-code(designing code that implements a requirement, a refused source read, or generated code) when the task matches those workflows. - Call
kb_skillswithaction: "read"only for resource paths declared by that manifest.
These skill operations are local, read-only, and do not require Prolog. They return a human-readable content item plus structured data for clients that support structured tool results. The kb_skills registration advertises readOnlyHint: true, destructiveHint: false, idempotentHint: true, and openWorldHint: false as client-facing behavior hints. Clients must treat annotations and skill text as untrusted guidance: authorization, schema validation, approval gates, and mutation sequencing remain enforced by the server and repository workflow.
The CLI is a peer surface with the same skill operations through structured JSON routes (select by what the host exposes):
printf '%s\n' '{}' | kibi skills-list --input -
printf '%s\n' '{"id":"kibi-usage"}' | kibi skills-load --input -
printf '%s\n' '{"id":"kibi-usage","resource":"resources/workflows.md"}' | kibi skills-read --input -
printf '%s\n' '{"action":"load","id":"kibi-usage"}' | kibi skill --input -If neither a visible Kibi MCP surface nor a trusted local CLI is available, the agent must stop and ask the operator to enable one; it must not infer availability from configuration files or read .kb/ directly.
Day-0 bootstrap uses the kibi-bootstrap bundled skill and kb_plan_bootstrap: inspect kb_status.bootstrap, follow its typed next action, interview the human about knowledge sources outside the code and pass them with cited intentClaims in bootstrapContext, review the deterministic kibi.bootstrap-plan.v1, ask only further questions returned by a needs_context result, get explicit approval for its hash, then pass the unchanged plan to kb_apply_plan. Hosts that support it also expose /kibi-bootstrap.
kb_plan_bootstrap
Discover existing repository evidence and return a deterministic, snapshot-bound
kibi.bootstrap-plan.v1. Use this as the backend for the interactive
/kibi-bootstrap onboarding workflow. It never mutates the KB.
Parameters:
includeGenericMarkdown(optional): Include generic Markdown content as candidate evidence. Defaults totrue, or tofalsewhenbootstrapContextdeclaresintentClaims(a diagnostic says so); set it explicitly to override.minConfidence(optional): Minimum confidence threshold for generated candidates.maxCandidates(optional): Budget for candidates Kibi discovers itself (symbols, tests, repository documents), default 50. DeclaredintentClaimssit outside it: they are never capped and never use its slots, so a long claim list still leaves the full budget for discovered candidates. Candidates with a claim take the budget before provenance stubs (below), so raising it only admits more stubs once every candidate with a claim is planned.entityTypes(optional): Limit generation to selected entity types.bootstrapContext(optional): Declared project summary, source-of-truth paths/notes, priority roots, verification anchors, and the outcome of the source interview:knowledgeSources: sources outside the code the human confirmed, each withid,kind(issue_tracker,wiki,specification,design,decision_log,support,chat,repository_docs,other),title,locator,authority(authoritative,supporting,stale), an optionalconnector, and an optionalcomponentits claims are about.intentClaims: statements the agent read in those sources, each withstatement,sourceId, an exactreference(ticket key, page URL, section), anexcerpt(required forintentandobservationclaims, optional foropen_question), an optionalkind:intent(default, intended behavior),observation(how things are today, without stating intent) oropen_question(something the sources leave undecided), an optionalcomponentthat overrides the source's, and an optionalrationale(the reason the source or the human gave; it becomes the requirement'srationaleand its body's## Context).conflicts: contradictions between declared claims that the agent leaves for the human, each withclaimReferences(two to ten{ sourceId, reference }pairs that must match declared claims) and a one-sentencenote.
Kibi never contacts the declared sources. All three lists are part of
declaredContextand so ofplanHash;kindis omitted there when it isintent. A groundedintentclaim from an authoritative or supporting source becomes areqcandidate withsourceKind: intent_claim, citation evidence,text_ref: <sourceId>:<reference>,origin: {kind: import, ref: <sourceId>:<reference>},firmness: firm(normative lines from repository Markdown get the same withref: <path>#L<line>) and a body that persists the claim (statement, then## Sourcewith the blockquoted excerpt, source title and reference). Generated subject keys followcomponent.aspect[.sub]: the declaredcomponent(claim, then source; for repository Markdown, the file or directory name) is the first segment and the claim's subject the aspect; a one-word subject, or one equal to the component, makes the constrained property the aspect; an already dotted subject is kept. An aspect longer than four words or 40 characters is shortened deterministically to a noun phrase (the words before the first clause boundary such aswhen,while,for,and, without stop words; if still too long, its first and last content words), and asubject-key-shortened:diagnostic names the original and the chosen key so the operator can rename it. When shortening gives two different subjects the same key, the later one gets a third segment from its own wording (or a short digest) and asubject-key-disambiguated:diagnostic; claims about the same subject keep sharing one key, and the plan writes one subject fact for that key: every requirement about the subject links to it throughconstrains, the later sources' provenance is added to its tags and body, and asubject-key-shared:diagnostic names the key and its sources. A claim with no component and a multi-word subject is reported indiagnosticsand becomes an authoring follow-up rather than a requirement with a malformed subject key. A claim the strict modeler cannot ground becomes an authoring follow-up. Anobservationoropen_questionclaim never becomes a requirement: it becomes afact_kind: observationcandidate with the same citation evidence andtext_ref, and open questions are taggedreview:open-question. Each conflict becomes afact_kind: observationcandidate taggedreview:conflictthat cites every referenced claim; a conflict citing an undeclared claim is reported indiagnosticsand not planned. These facts pass the same write validation as every other candidate. Stale sources produce no candidates, and claims citing an undeclared source are reported indiagnostics. When no sources were declared, aneeds_contextplan asks for them.On a repository that already has a seeded knowledge base (
activationState: root_active_seeded,activationMode: attached_seeded_handoff), Kibi does not generate discovered candidates (repository documents, symbols, tests), but it still plans the declared claims. A claim whose entity is already in the KB is suppressed asentity_existsand counted as already in the KB; the rest become candidates exactly as on an unseeded KB. When the plan holds only claim-derived candidates,applyBlockedisfalse, the plan can bereadyandkb_apply_planapplies it after approval;handoffMessageandrecommendedActionssay so. Without declared claims, or when none can be planned, a seeded KB stays ahandoffplan whosehandoffMessagepoints atkb_search/kb_queryfor existing knowledge and atkb_compile_intentfor each remaining claim. A mode that plans no declared claims at all (vendored_blocked) keeps onesuppressed_by_activationrow per claim insuppressedCandidates.On any KB, an
intentclaim that restates a current requirement (statusopen,in_progressorclosed, or legacyactive/approved, and not superseded) is also suppressed asentity_existsand counted as already in the KB, even though its own derivedREQ-AUTO-…id is new. A restatement is a normalized exact match: the claim'sstatementorexcerpt, lowercased with punctuation and whitespace runs removed, equals the requirement'stitle, itssemantic_text, or one sentence of it. The row addsmatchedId(the requirement),matchedBy: "restatement"andmatchedField(titleorsemantic_text). A claim that only comes close (normalized token-set Jaccard of 0.8 or more against the title, the semantic text or one of its sentences, the same threshold the entity-context check uses for a restatement) is still planned: its evidence gainspossible_restatement:<id>and a diagnostic names the requirement and the overlap, so the reviewer can drop the claim or link the two withrestatesorsupersedes. Requirements are compared in id order, so the same KB and context give the same plan.A planned
intentclaim is checked for contradictions only against current requirements with a logical representation. For each planned claim, the plan names up to five current requirements on the same topic (intent-search score at least 0.1) that have none: the claim'sevidencegainsreview_against:<id>for each, and aconflict-review:diagnostic names the claim's citation and the requirements. Compare them before approval; on a contradiction show both to the human, then drop the claim or keep it and supersede the requirement after apply, and record a conflict the human has not decided as areview:conflictobservation fact. An intent claim the plan cannot model ("Intent claim needs authoring …") is ranked the same way: itsconflict-review:diagnostic names the prose-only requirements to compare it with when it is compiled withkb_compile_intent, which takes the verdicts throughconflictReviews, and the knowledge-source summary andrecommendedActionscount the authoring claims that need such a review.Each
Knowledge source …diagnostic counts a source's claims as planned, already in the KB, filtered out (filtered_by_entity_type,below_min_confidence) and not planned, and splits the not-planned count by its reason so the numbers add up: suppressed by the activation mode (compile them withkb_compile_intent), suppressed with a row insuppressedCandidates(for exampleinvalid_write,missing_excerpt,stale_knowledge_source), left as asourceOnlySignalsauthoring follow-up, or, when none of these applies, explained only indiagnostics.
Returns:
Evidence, bounded context questions, dependency-ordered actions, expected
snapshots/source hashes, payoff summary, diagnostics, and planHash. Every
suppressed candidate stays in suppressedCandidates; tldr and one diagnostic
summarize them as a count per reason (for example over_limit 290, duplicate_title 75). A deterministic provider candidate whose source states
no claim (source_symbols "Source module: …", repo_metadata, repo_layout,
and test_topology without a recognized framework) is a provenance stub:
it is written as fact_kind: meta tagged bootstrap:provenance-stub with a
body that says so, not as an observation. A test_topology entry that names
its framework states a claim and stays an observation. Stubs stay readable
through kb_query (filter by the tag) but kb_search ranks them after every
other match and drops them below the default threshold, the answer layer never
lists them as notes, kb_find_gaps skips them unless tags names the tag
(its summary.provenanceStubs counts the stubs that matched the filters either
way), and kb_coverage by: "type" counts them in summary.provenanceStubs
instead of the fact row. discoverySummary.candidatesWithClaims,
discoverySummary.provenanceStubs and
discoverySummary.suppressedProvenanceStubs report them apart from candidates
with claims; each over_limit row carries provenanceStub, and the
over_limit diagnostic and tldr say how many suppressed candidates are
stubs so nobody raises maxCandidates for them. Each candidate's writes are validated before it is
offered, with the same checks and semantic advisor the apply uses, so a
conditional claim ("If microphone access fails, the editor must …") is planned
like any other intent claim; a candidate that fails is suppressed as
invalid_write, and one that would write an entity another candidate already
writes with different content is suppressed as duplicate_entity. Only a
ready plan may be approved. Apply it with kb_apply_plan; do not replay raw
kb_upsert payloads.
pluginOffers lists optional plugins that fit the workspace and that
package.json neither activates in kibi.plugins nor lists in
kibi.declinedPlugins; each has package, capability, the mode to
activate it in, reason, fileCount and up to five evidence paths, and
recommendedActions repeats it as a plugin_offer action. Kibi offers
kibi-plugin-ui (augment) when production *.tsx, *.jsx or
*.component.ts files exist, and kibi-plugin-search-hints (replace) when
.kb/requirements/ holds 50 or more requirement documents. Offers are outside
the plan and its hash; the agent asks the human, and Kibi never edits
package.json itself.
Repository Ignore Policy
During read-only discovery (for example kb_plan_bootstrap) and other file-based inference, Kibi will exclude files and directories matched by the repository ignore policy:
- repository root
.gitignorefiles and nested.gitignorefiles in subdirectories .git/info/exclude
In addition to these repository-configured ignores, Kibi hard-denies a set of common tool/runtime directories that are never inspected for candidates:
.sisyphus/**.opencode/**.kb/**.git/**node_modules/**vendor/**third_party/**
Notes and migration limitations:
- Global Git excludes (for example
~/.config/git/ignore) are not read or honored. - When MCP tools return a non-null migration warning, run
kibi migrate --dry-run, thenkibi migrate --yesbefore relying on strict checks or automated writes. - Symbol granularity migration marks existing coarse file/module links as
legacy-link; new MCPkb_upsertcalls must target the narrow behavioral symbol when one exists, or provide an explicitgranularity_reason. Interfaces, type aliases, and enums aretype-shapesymbols and do not by themselves block a coarse behavioral link.
When using discovery tools, agents and operators should assume that ignored paths are not considered as evidence for candidate entities and that any candidates requiring approval will come from non-ignored sources only.
Semantic Modeling Quick Path
When prose contains a machine-checkable rule, do not store it only in text_ref or freeform links. Use the concise decision tree in docs/modeling-cheatsheet.md.
- Call
kb_modelwithmode: "analyze"and the complete body when starting from raw prose, or runkb_upsertwithdryRun: truebefore the realkb_upsertfor new or updated normative requirements. Verify the returned atomic clause inventory; supplyclauseswhen automatic decomposition is incomplete. - For property/value requirements, call
kb_modelwithmode: "requirement"or create afact_kind: subjectfact plus afact_kind: property_valuefact. Link the requirement withconstrainsandrequires_property. - Model every assertive proposition: use
kb_modelwithmode: "predicates"for approved ground ontology claims, strict facts for scalar claims, andkb_modelwithmode: "requirement"and a validatedkibi.logic.v1object for conditions, exceptions, modalities, quantifiers, cardinality, or bounded temporal rules. Preserveclaim_keyandclaim_texton each ground fact/rule, replace stale manifests with the exact current assertive key set, persist the completesemantic_inventoryplus itsinventory_contract, and link withrequires_predicate,requires_property, orrequires_rule. Ambiguity, ontology gaps, and missing interpretations remain explicitly unresolved. - Use snake_case field names exactly as the MCP schema shows.
kb_upsert.propertiesrejects camelCase aliases such assubjectKey,propertyKey,predicateName, and genericvalue.
Semantic advisor modeling suggestions remain advisory and do not auto-create facts. The proposition ledger is a mutation contract for current requirements: the advisor canonicalizes repeated identical normalized claims to one proposition at the first source occurrence; kb_upsert (dry run or real) still rejects source/hash/span drift, duplicate identities in a submitted ledger, omitted assertions, invalid nonlogical classifications, and modeled entries whose linked fact claim keys do not match. Review every proposition and still run kb_check; successful ingestion proves accounting integrity, not domain truth or contradiction safety.
kb_model
Turn requirement prose into checkable structure without writing the KB. One
tool covers three read-only modes, selected by the required mode field; the
other fields are the inputs of the mode's catalog operation, and the result is
that operation's payload plus mode. Apply any returned plan with sequential
kb_upsert calls.
mode |
Catalog operation | CLI route | Use it to |
|---|---|---|---|
analyze |
kb_semantic_advisor |
semantic-advisor |
Get the clause ledger, grounding, ambiguity, and modeling suggestions for prose. |
requirement |
kb_model_requirement |
model-requirement |
Turn one claim (or a typed logic object) into a strict write set or rule plan. |
predicates |
kb_suggest_predicates |
suggest-predicates |
Rank ontology predicate schemas and get a predicate-fact plan or ontology-gap observation. |
text is required in every mode. A parameter that only another mode
accepts is ignored and named in the result's warnings (and text content),
with the equivalent parameter of the chosen mode when there is one
(subjectKey in mode requirement is subjectHint in mode predicates).
kibi model --input - accepts the same object on the CLI:
printf '%s\n' '{"mode":"analyze","text":"Sessions expire after at most 30 minutes."}' | kibi model --input -mode: "requirement" (kb_model_requirement)
Model a normative requirement claim into a deterministic strict write-set or a validated kibi.logic.v1 rule plan for contradiction-ready KB persistence. Accepts an LLM-supplied semantic claim (or a typed logic object) and returns a ready-to-apply sequence of req, fact_kind: subject, fact_kind: property_value, rule_schema, and rule entities with typed relationships. Raw Prolog is rejected.
High-confidence scalar claims (≥ 0.7) produce a strict write-set: one req, one fact_kind: subject, one fact_kind: property_value, and two typed relationships. A valid logic input produces a rule_schema, a rule with canonical JSON/full hash/semantic key, and requires_rule. A conditional clause ("X may happen only when C", "X only if C", "X must not happen unless C") without explicit claim fields is modeled the same way: when C is one comparison on one subject property ("the cart total is positive"), Kibi builds a forbid rule on the action with C as its exception (confidence 0.8). A conditional it cannot translate (several conditions, pronouns, relations) returns no observation and no strict facts: the plan is empty, or with requirementId a requirement update that records the clause as ontology_gap, plus an unresolved_conditional_clause warning asking for a typed logic rule. Other low-confidence claims (< 0.7) produce a single fact_kind: observation artifact tagged review:ontology-gap that does not enter the contradiction lane and carries no claim key (it does not ground the clause), plus a warning explaining how to retry with explicit claim fields.
Parameters:
text(required): One atomic plain-language normative clause to model.source/sourceFiles(optional): Provenance used for stable IDs and references.confidence(optional): Claim confidence; values below0.70produce observation review output.subjectKey,propertyKey,operator, andvalue(optional as a complete set): Explicit semantic claim fields. When all are supplied, heuristic extraction is skipped.provenance(optional): Exact source anchor for the clause.existingLogicClaims(optional): Existing requirement claim keys. The returned req update merges the new key rather than replacing previously modeled clauses.requirementId(optional): The requirement the plan updates. The strict write set uses this id for thereqstep and itsconstrains/requires_propertylinks instead of mintingREQ-AUTO-<hash>; fact ids,subject_keyand the claim key stay derived from the claim. A typedlogicrule attaches itsrequires_rulelink to it, and an untranslatable conditional records itsontology_gapon it.logic(optional): Typedkibi.logic.v1IR. Kibi validates range restriction, modalities, units, temporal bounds, closed-world negation, and resource-safe structure before returning a rule plan.
Returns:
A writeSet discriminated union:
isStrict: true— includesreq,subjectFact,propertyFact,relationships, and anapplyPlanready for sequentialkb_upsertcalls.isStrict: false— includes a singleobservationFactfor non-normative or low-confidence input.
Also returns the stable claimKey, merged logicClaims, and migrationWarning when the workspace KB schema is outdated.
For strict claims, vocabularyAlignment reports how the clause subject was resolved against the existing KB vocabulary:
subject.decisionisreuse_existingordeclare_new, withsubject.candidatesranked deterministically (IDF-weighted token overlap over subject keys, subject titles, and titles of requirements already constraining each subject; requirement-derived subjects are never offered). When reusing, the plan links the existing subject fact throughconstrainsinstead of creating a duplicate subject fact, andwriteSet.subjectFactnames that fact: itsidand itssource(.kb/facts/<id>.md, the existing fact's own file). A heuristic subject converges onto the chosen existing subject; an explicitly providedsubjectKeyis kept, and asubject_reuse_reviewwarning names the better existing subject when there is one. A declared new subject is taggedvocabulary:new-subject, andsubject_key_shape_reviewfires when it is not dottedcomponent.aspect[.sub].redundancyCandidateslists existing claims on the same subject whose wording may state the same obligation, andreviewPlanholds an optionalreview:possible-duplicateobservation step to record that for review. These are candidates, never verdicts; exact duplicates are reported by the deterministicdomain-redundancycheck.stamps,fallbackUsed, anddiagnosticsdisclose the provider. The builtin provider is always available; an activatedkibi.vocabulary-alignment.v1plugin (for examplekibi-plugin-jev) may refine the decision inreplace,augment, orshadowmode and falls back to builtin on any failure.
The modeling call is read-only. Applying its plan is a separate mutation and must follow the caller's authorization boundary. The write-set is deterministic and idempotent—the same claim produces the same stable entity IDs. Apply authorized writes through sequential kb_upsert calls.
mode: "predicates" (kb_suggest_predicates)
Suggest ontology predicate candidates for a prose requirement before an agent writes freeform ontology notes. Agents should spell out the requirement claim, call this mode, then either apply a returned fact_kind: predicate plan linked with requires_predicate, supply exact argumentBindings when a fitting schema still has unbound arguments, or record the returned review:ontology-gap observation when no predicate fits. The gap observation is a review note, not a semantic claim: it quotes the claim in claim_text without a claim_key, carries review:ontology-gap and needs_schema_extension in tags (a tag is not an entity, so no relationship points at it), explains in document.body that no predicate schema fits, and stays queryable by tag without entering the contradiction lane. Apply it with kb_upsert exactly as returned.
When a project-local schema declares argument_constants, bound values that are aliases are rewritten to their declared constant and any other undeclared value leaves that argument unbound, so the candidate lists the allowed constants instead of producing an applicable plan with a new atom. kb_upsert enforces the same vocabulary for predicate facts.
The tool ranks project-local fact_kind: predicate_schema facts when available and falls back to Kibi's built-in predicate catalog covering state, transitions, guards, exceptions, mutual exclusion, dependencies, ownership, retry policies, escalation rules, availability SLAs, notification routing, idempotency, data residency, audit logging, consent, lifecycle actions, conflict resolution, fallback behavior, batch operations, consistency rules, build constraints, environment safety rules, schema invariants, coding standards, migration boundaries, absence/removal requirements, offline behavior, release gates, platform consistency, preservation rules, abstraction boundaries, security configuration, ordered strategies, refresh policies, scoped authorization, documentation standards, warmup policies, visual layout rules, enforcement-location rules, reconciliation rules, throttling policies, persistence/save/discard behavior, accessibility, retention, resource constraints, feature gates, events, permissions, defaults, uniqueness, state memberships, temporal ordering, conditional behavior, rate limits, acceptance outcomes, reusable launcher contracts (dependency_resolution_policy, ordered_resolution_strategy, resolution_failure_policy, process_delegation_contract, and failure_behavior), plus consumer-escalated families for fail-closed authorization, deployment preconditions, data-migration sequencing, diagnostic visibility, mutation authority, request deduplication, async boundaries, canonical identifiers, responsive breakpoints, and operational pauses. Built-in candidates include usage hints (use_when / do_not_use_when) so agents can choose precise predicates instead of matching keywords blindly.
Candidate diagnostics are additive: each candidate may report eligibility (eligible or rejected), rejection_reasons, a conservative aggregate binding_provenance (the least-reviewable provenance across arguments), per-argument binding_provenance_by_argument (explicit, extracted, inferred, or placeholder), applicability_score, and deterministic score components. Retrieval and argument binding do not by themselves make a candidate applicable; negative evidence and margin-based abstention can reject weak or near-tied candidates. When no schema is genuinely eligible, the response uses record_ontology_gap and includes a non-null recommendedPredicateSchema draft with proposed name, ordered arguments, extracted bindings, unresolved bindings, rationale, and reuse scope for review. Draft schemas are never applied automatically.
Parameters:
text(required): Prose requirement or claim to classify into ontology predicates.requirementId(optional): Existing requirement ID. When present, the response includes arelationshipPlandescribing therequires_predicatelink to attach after preserving existing requirement metadata.source(optional): Provenance/text reference for generated predicate facts or ontology-gap observations.subjectHint(optional): Canonical subject key the predicate is about. It binds the argument the schema namessubject, wherever that argument sits; for a schema without asubjectargument it becomes the planned fact'ssubject_key. Without it, arequirementIdwhose requirementconstrainsexactly one subject fact binds that fact'ssubject_keythe same way (provenancerequirement); with several subject facts their keys are listed first in the subject'sbindingHints[].examples. A requirement without a subject fact leavessubjectunbound; only free text withoutrequirementIdfalls back to keyword guesses. For a requirement that is not written yet or constrains nothing, an explicitsubjectHintis the planned subject: the candidate'ssubject_keyis set from it andsubject_pairingis computed against it, so the planned fact pairs with the subject fact once the requirementconstrainsit. The parameter issubjectHint, notsubjectKey(amode: "requirement"parameter): a parameter that belongs to anotherkb_modelmode is ignored and named inwarnings(subjectKey is a mode: requirement argument; mode: predicates ignored it. Use subjectHint in mode: predicates.).maxCandidates(optional): Maximum ranked predicate candidates to return.minScore(optional): Minimum candidate score; higher values make ontology-gap fallback more likely.includeExistingSchemas(optional): Include project-local predicate schema facts alongside built-ins.schemaId(optional): Select an exact reviewed built-in or project-local schema ID instead of accepting lexical rank order. An unavailable ID returnsresolve_schema_referencewith no write or ontology-gap plan.argumentBindings(optional): Exact values keyed by the candidate schema's orderedargument_names, taken from the claim text. Use this to resolve an incomplete candidate; unbound values are never emitted as an applicable predicate fact. A value that only repeats its own or another argument name (after snake-case normalization, for examplebefore_event: "before_event") unless the claim itself names it, or a bare stop word or trivial verb (be,is,do,have,the,a, ...), counts as a placeholder and leaves the argument unbound.true,falseand the schema's declaredargument_constantsare always accepted.polarityHint(optional): Reviewedassertordenyoverride for negation-scope false positives. Use only after reviewing the complete claim and selected schema.existingLogicClaims(optional): Existing requirement claim keys. Returned relationship guidance merges the new key rather than replacing earlier clauses.
Returns:
candidates: Ranked predicate suggestions with schema signature, usage hints, orderedpredicate_args,binding_status,unbound_arguments,canonical_key, score, and rationale. With arequirementIdthat constrains subject facts (or, when nothing is constrained yet, an explicitsubjectHint),subject_keyis the subject the predicate is about (the value of itssubjectargument, or for a schema without one such aspermission_rule(actor, action, resource, decision)the requirement's subject) andsubject_pairingsays whether that is one of the constrained subjects (paired,unpaired, ornot_requiredwhen the requirement constrains none). Anunpairedcandidate is incomplete: itsunbound_argumentsincludesubject(orsubject_keyfor a schema without asubjectargument), becausekb_checkwould keep reportingstrict-req-fact-pairingafter the link. The planned predicate fact recordssubject_keywhenever it is known, so the strict lane pairs it with the subject fact whatever argument holds the subject. A value for an entity-, actor- or resource-like argument taken from the claim text that is longer than three words (a clause such as everything before the modal verb) is not a binding: it stays unbound with abindingHintsreason; short nouns still bind.recommendedAction: names the predicate state whether or not the claim is already grounded.apply_requires_predicatewhen the top or explicitly selected candidate fits, every argument is bound, the predicate pairs with the requirement's subject (seesubject_pairing) and the claim is not yet grounded;replace_groundingwhen such a candidate fits butrequirementIdalready grounds this claim (sameclaim_key) throughrequires_property,requires_predicateorrequires_rule;keep_existing_groundingwhenrequirementIdalready links a predicate fact with the recommended candidate'scanonical_key(the same predicate tuple stated in other words, or the same claim again; the candidate's decision may still be inferred): nothing is written or swapped, andexistingGrounding[].matchedBysays whether the fact matched byclaim_keyorcanonical_key;extend_requirementwhen such a candidate fits and the claim is not grounded, but the stored requirement's proposition ledger (semantic_inventory) has no entry for this text: a requirement grounds only the propositions its prose states, so no fact is planned (it would stay unlinked) and the prose has to be extended with the clause (kb_modelmode: "requirement", orkb_upsertwith the extendedsemantic_textand the ledgermode: "analyze"returns) beforemode: "predicates"is called again;provide_argument_bindingswhen its schema fits but exact values are missing or the predicate is not about a subject the requirement constrains (the summary,candidates[].unbound_argumentsandbindingHintslist them, and a warning says when the schema does not name the requirement's subject);resolve_schema_referencewhen an explicitly selected schema is unavailable;review_nonlogicalwhen the semantic advisor classifies the input as nonlogical (rationale, example, or subjective context); otherwiserecord_ontology_gap.record_ontology_gapis also returned when the top candidate is incomplete solely because the claim names no participant for itsactor,actor_scope,roleorownerargument (the value is empty, the requirement's subject key or a clause of the claim that opens with a gerund such as "Discarding a draft while …", and none of the argument's declared constants or schema example values occurs in the claim text): such a schema does not fit the claim, so thereview:ontology-gapobservation is planned inapplyPlan, while the candidate stays incandidatesasincompleteandbindingHintsstill explains the unbound argument. A claim that names a participant in other words, or an argument unbound for another reason (a value outsideallowedValues, a value the claim does not contain), keepsprovide_argument_bindings. A non-emptyexistingGroundingis the "already grounded" signal and lists the links found (matchedBy, the fact's storedclaimKeyandcanonicalKey). When no hash-boundplanwas compiled (the ledger lacks the claim, the requirement is not stored, or the call passed norequirementId),decisionConflictslists the stored decision facts of current requirements that agree with the complete candidate on its key arguments and decide the opposite (requirementId,factId,effect,proposedEffect,canonicalKey), and a warning names each one; with aplan, itscontradictionAnalysiscarries the same information anddecisionConflictsis empty. An already grounded claim never gets a predicateapplyPlanorrelationshipPlan, because a modeled claim takes exactly one grounding relationship and a second link fails the proposition-complete rule; onreplace_grounding,replacementPlangives the ordered swap (upsert the predicate fact,kb_deletethe old grounding relationship, then upsert the requirement with therequires_predicatelink) andrelationshipTargetnames the planned fact. Each step'sinputis a complete payload to apply unchanged: the requirement step restates the storedtitle,status,priorityandtags(kb_upsert keeps the stored proposition ledger). The order is forced and the steps must run back to back: linkingrequires_predicatebefore the retraction is rejected because the claim would have two groundings, and between the retraction and the link the claim is ungrounded, so akb_checkin between reportslogic-coveragefor the requirement. If the last step fails, applyreplacementPlan.rollback, which restores the retracted link. Onrecord_ontology_gapthereview:ontology-gapobservation plan andrecommendedPredicateSchemaare returned even for a grounded claim, since the observation is not a grounding relationship.structuredContent.actions: A ready-to-applykb_upsertpayload for a completely bound top predicate fact, an empty list for an incomplete binding, or an explicitfact_kind: observationtaggedreview:ontology-gapandneeds_schema_extension, withclaim_text,value_string,text_ref(whensourceis given), adocument.bodyand no relationships.structuredContent.bindingHints: Onprovide_argument_bindings, one entry per unbound argument of the recommended candidate:argument,position,type(fromargument_types),descriptionwhen the schema has one,allowedValues(the declaredargument_constants) when the vocabulary is closed,examples(forsubject, and for anentityargument of a schema without one, the requirement's constrained subject keys first; then constants, then the values at that position in the schema'sexamples; asubject_keyhint,position-1, lists the constrained subject keys to pass assubjectHint), the rejectedcurrentValuewith itsprovenance, and areason. A participant argument (actor,actor_scope,role,owner) is never offered the subject keys: the subject is what the claim is about, not who acts on it, and the planned fact already carries it assubject_key. An explicit binding of such an argument to a constrained subject key stays unbound (placeholder) with a reason, so the candidate cannot becomecompletethrough a vacuous actor; when the claim names no participant, the hint says so and points torecord_ontology_gap, because a schema whose actor the claim never names does not fit the claim. Bind from the claim text using these instead of copying field names. Also returned on arecord_ontology_gapthat was decided for a matched but unfitting candidate; empty for every other action. Built-in schemas close the arguments with a natural vocabulary:triggerofcommit_action,discard_actionandtransition(escape,cancel,submit,navigation,click,timeout),decisionofpermission_ruleandscoped_authorization_rule(allow,deny),policyofrefresh_policy_rule(automatic,manual,on_demand),decisionofenvironment_safety_rule(allowed,forbidden,read-only),operatorofresource_constraint,unitofretention_policy(days,months,years),actionofcoding_standard_rule(use,avoid) and oflifecycle_rule(archived,deleted,expired). A claim that names a constant in other words (times out,must be denied) binds it, and aliases such asnavigateconverge onto the constant.structuredContent.replacementPlan: Onreplace_grounding, the orderedsteps(write the predicate fact,kb_deletethe old grounding link, upsert the requirement withrequires_predicate), arollbackupsert that restores the old link,instructions, andexpected:kbCheckAfterSteplists thekb_checkfindings for the requirement after each step by rule name ([[], ["logic-coverage", "strict-req-fact-pairing"], []]: between the retraction and the link the claim is ungrounded and its subject fact unpaired, so both rules fire),kbCheckAfterLastStepis[], androllbackWhenis "kb_check after the last step is not clean". Violations carry the rule asrule, quality diagnostics asrule.<name>.structuredContent.relationshipPlan: WhenrequirementIdis supplied and a predicate fits, the req -> factrequires_predicatelink plus the mergedlogicClaimsmanifest to apply after querying/preserving the existing requirement entity. This is separate fromapplyPlanso the tool never emits a foreign-source relationship thatkb_upsertwould reject.structuredContent.relationshipTargetnames the planned predicate fact id (FACT-PRED-…) that therequires_predicatelink must target;candidates[].id(SUGGEST-…) values are never relationship targets.structuredContent.plan: WhenrequirementIdis supplied, the candidate is complete and the claim is not yet grounded, the hash-boundkibi.compile-plan.v1behindapplyPlanandrelationshipPlan: step 1 writes the predicate fact, step 2 upserts the requirement with its stored title, status, priority, owner and tags, the mergedlogic_claimsmanifest and therequires_predicatelink. Apply it withkb_apply_plan(approvedPlanHash: plan.planHash): both steps are validated together and committed in one transaction, and the requirement's authored body is kept.plan.contradictionAnalysisis the what-if over the current KB plus these steps, so a decision conflict with a permission fact that is already stored (an allow and a deny on the same key) is reported here before any write; the plan is thenblocked, a warning names the witnesses, andapplyPlanstill shows the fact.nullwhen no plan applies (incomplete binding, already grounded, norequirementId, or the requirement is not stored; a warning says why) and for ontology-gap observations, whichkb_upsertapplies as before.
Example:
{
"mode": "predicates",
"text": "When the user navigates away with unsaved annotation edits, the editor must auto-save the draft and return to idle mode.",
"requirementId": "REQ-EDITOR-004",
"source": "requirements/editor.md#L12",
"subjectHint": "editor.annotation"
}mode: "analyze" (kb_semantic_advisor)
Analyze requirement prose without mutating the KB. Use this before constructing a kb_upsert payload when you have raw requirement text and want modeling suggestions.
Parameters:
text(required): Requirement prose to inspect.type(optional): Entity type context. Currentlyreqis supported.id(optional): Requirement ID used for draft relationship guidance.title(optional): Requirement title for draft apply plans.source(optional): Provenance for draft suggestions.status(optional): Requirement status for draft suggestions.clauses(optional): Caller-reviewed atomic proposition split. Use it when a sentence contains multiple obligations, conditions, exceptions, definitions, or qualifiers. Each clause must be a verbatim fragment oftext(whitespace layout, a leading list marker and closing punctuation may differ); a clause that does not occur intext, such as a paraphrase, fails the call withVALIDATION_FAILEDnaming the clause.interpretations(optional, maximum 3): Typedkibi.logic.v1alternatives withclaim_key,claim_text, andir. Kibi canonicalizes and structurally compares them; materially different valid alternatives remain unresolved and confidence never selects one.
Returns:
structuredContent.receipt: Semantic advisor receipt with detected signals, a proposition ledger (propositions[]), a versionedinventory_contractcontaining the semantic source field and SHA-256 hash, typed interpretation results, deterministic shadow cues, modeling suggestions, candidate lane, payload hash, and suggested next tools.structuredContent.warnings: Non-blocking warning strings explaining why the prose is not yet contradiction-checkable.
The receipt returns stable provenance claim_key values, claim_text, exact UTF-8 byte spans, per-clause suggestion indexes, and a logic_coverage manifest comparison. Proposition statuses are modeled, ambiguous, ontology_gap, nonlogical, or missing; an assertive span is never silently dropped. Observation apply plans carry their review category in tags (for example review:ambiguity or review:ontology-gap; a tag is not an entity, so no relationship points at it) and a document.body that quotes the prose, so kb_upsert accepts them as returned; they remain outside contradiction checks. Suggestion kinds include strict_property, predicate, rule, ambiguity_observation, and ontology_gap. Supported deterministic suggestions include multi-claim prose, cardinality, thresholds with units, retention/expiry durations, booleans, enum sets, permissions and prohibitions, defaults, uniqueness constraints, state memberships, state transitions, exception rules, mutual exclusion, dependency rules, ownership, retry policies, escalation, availability SLAs, notification routing, idempotency, data residency, audit logging, consent, lifecycle, conflict-resolution, fallback/degradation, batch constraints, cross-entity consistency, conditional behavior, temporal ordering, comparative numeric constraints, rate limits, and ambiguity observations.
For exact predicate suggestions, the receipt candidate_lane and suggested_next_tools follow the generated suggestion rather than the weaker signal heuristic. For example, a lifecycle rule containing a number still routes to kb_suggest_predicates (kb_model mode predicates), not kb_model_requirement (mode requirement), when the advisor can ground it as a predicate fact. These receipt fields name catalog operations; see the mapping table.
kb_query
Retrieve entities by type, id, tags, or sourceFile, or ask typed questions about modeled facts. Supports limit and offset pagination.
Entity filters:
type(optional): Entity type (req,scenario,test,adr,flag,event,symbol,fact)id(optional): Entity ID (exact match)tags(optional): Tag list for filteringsourceFile(optional): Source-file substring filterlimit(optional): Maximum number of resultsoffset(optional): Number of results to skipincludeBody(optional, defaultfalse): withidonly, also return the entity's authored Markdown body
Returns:
Array of matching entities (entities) with deterministic ordering and the total count.
Entity rows carry front matter only. With includeBody: true the answer adds body: { id, path, text }: the prose after the front matter of the entity's authored document, so an agent can see and correct a statement the body makes that the fields do not; kb_upsert document.body replaces it. text is null when the entity has no authored Markdown document inside the workspace (a symbol, for example), and a body longer than 32 000 characters is cut with truncated: true. includeBody without id is refused.
Example:
{
"type": "req",
"sourceFile": "src/auth/login.ts",
"limit": 20
}Typed fact questions: instead of searching prose, ask the KB about the facts it models. These filters apply to fact entities only and cannot be combined with id, tags or sourceFile.
factKind: list facts of one kind (subject,property_value,predicate,predicate_schema,observation,meta,rule,rule_schema) with their typed fields.factKind: "predicate_schema"is the catalog of askable predicates: each row names the predicate, its argument names and types, declaredargumentConstants, key arguments, examples and how many facts use it. Every row carriesid,builtinandstored: a project schema is a stored entity (builtin: false,stored: true, itsidanswerskb_query({ "id": ... })); a built-in decision predicate such aspermission_rule(actor, action, resource, decision)appears withbuiltin: true,stored: falseand the catalogidthatkb_modelaccepts asschemaId(FACT-SCHEMA-PERMISSION-RULE), which no stored entity carries, so akb_queryby that id returns nothing.predicate(+ optionalnamespace): every stored fact of that predicate. Narrow it withwhere, an order-free object of argument name to value resolved through the schema ({"actor": "admin", "decision": "allow"}), or with positionalargswherenullmatches anything.polaritykeepsassertordenyfacts,scope: "current_requirements"keeps only facts a current requirement requires, anddistinctnames an argument whose distinct values are counted. Rows carryarguments(named),polarity, the effectiveeffect(allow/deny) for decision predicates, thecanonicalKey,claimTextand the requirements that require the fact with their current/superseded status.subjectKey(+ optionalpropertyKey): the strict property facts stated about a subject, each withoperator,valueType,value,unitand the requirements that require it;subjectFactsnames the subject fact itself.
where, args, polarity, distinct, namespace and propertyKey refine one of those three questions and are refused with a message when sent without one or with the wrong one, and kb_query rejects positional args that do not cover the predicate's full arity. Every typed answer returns the rows in entities plus factQuery: the mode, the question as understood, the schema used, distinct counts, suggestions (when nothing matched a where, the values that do exist per bound argument), warnings (an argument name the schema does not declare, with the declared names) and next, the exact follow-up kb_query calls that make sense, so the agent never has to guess the next step.
{ "predicate": "has_role", "where": { "user": "alice" }, "distinct": "role" }answers "how many roles does alice have?" with the facts and factQuery.distinct.values;
{ "predicate": "permission_rule", "where": { "actor": "admin" } }answers "what may an admin do?" with each rule's effect;
{ "subjectKey": "user.role_assignment", "propertyKey": "max_roles" }answers "what is the role limit?" with the operator and value. Start from { "factKind": "predicate_schema" } when you do not know the predicate names. kb_search answers already point here: each linked fact in the answer layer carries its typed claim (has_role(alice, admin), user.role_assignment max_roles lte 2) and the ask call that reproduces the fact's own tuple: { "subjectKey", "propertyKey" } for a property fact, { "subjectKey" } for a subject, and for a predicate fact the predicate (with its namespace when it is not default) plus where over its key arguments when a project predicate_schema or the built-in signature declares them (the schema's key_arguments, else the argument named subject, else the first argument: { "predicate": "has_role", "where": { "user": "alice" } }, { "predicate": "permission_rule", "where": { "actor": "admin", "action": "read", "resource": "analysis_request" } }), otherwise its full positional args. Pasted, the call returns that fact and only the facts sharing those key arguments.
kb_search
Ask the KB a question or search it. The default intent-v1 ranking accepts natural-language questions ("what governs checkout rounding?"), deterministic host-agent facets, and changed-code source locations, returns bounded traceability evidence, and abstains explicitly below its confidence threshold. Superseded and deprecated entities are demoted in the ranking (half their score). A closed requirement may be done and still hold, so it stays current but ranks at three quarters of its score, with the reason demoted: closed, below a current requirement that matches as well. Set rankingMode: "legacy" for the older lexical ranking.
Parameters:
query(required): Free-text querytype(optional): Entity type filterlimit(optional, default10): Maximum number of ranked results per page;countandtruncatedsay when to page withoffsetor raise itoffset(optional): Number of results to skiprankingMode(optional):intent-v1(default) orlegacyanswer(optional, defaulttrue): Intent mode, first page only. Adds the answer layer described below.hints(optional, defaulttrue): Intent mode, first page only. With akibi.search-hints.v1plugin activated, a weak or abstained answer addsqueryAnalysis.hints, described below.semanticFacets(optional): Host-providedactors,actions,objects,constraints, oraliasesarrayssourceLocations(optional): Workspace-relative{path, line?, column?, symbol?}locations for changed code. The symbols at those locations match, and so do the requirements theyimplements, even when the question shares no word with them (theirsourceMatchesname the implementing symbol withdistance: 3and the reasonimplemented at the source location).minScore(optional): Intent acceptance threshold between0and1; defaults to0.18fields(optional):summary(default) orfull
Returns:
Ranked results with match reasons and optional snippets. count is the number of matches in the whole ranking, before limit and offset; returned is the number of rows on this page; truncated says whether more pages remain.
By default each result carries identifying metadata only — id, type, title, status, priority, tags, source, and updated_at — alongside its score, reasons, and snippet. Search is a discovery step, so complete entity bodies are withheld until the caller has chosen what to open: request them with fields: "full", or follow up with kb_query for the exact ids. Ranking, ordering, count and returned are identical in both modes.
Candidate retrieval is paged internally, so a large KB no longer serializes its entire matching corpus into one Prolog response.
Intent-mode results additionally carry evidence for matched facets, source locations, graph paths, and normalized score. The payload includes queryAnalysis with candidate/accepted counts, top score, topTwoMargin, topRivalMargin, ranking mode, abstained and ambiguous, plus truncated. ambiguous reads topRivalMargin: the margin between the top match and the best match it is not linked to in the traceability graph, so a requirement tying with its own scenario, facts or tests is not an ambiguous answer, while two unrelated requirements that close are. A negative-path fact (a fact that a scenario expecting rejection or error assumes and on which no requirement grounds a claim) describes a situation that must not happen, so its title read alone states the opposite of the requirement it guards. Its result row carries negativePath (polarity: "forbidden" and guards, the current requirements whose rejecting scenarios assume it), the text names it as a forbidden situation, and when a requirement it guards also matched, it ranks directly below that requirement (its own score is kept) and is never that requirement's rival for ambiguous. An abstention is an explicit no-answer signal, not a successful empty lexical search; its text says to ask again in the words and language the KB is written in. A code identifier in the question is read word by word (canExport as can export), words the question writes in backticks weigh twice as much as the words around them, and a path the call also passes in sourceLocations is dropped from the question's words, since it already counts as source evidence. A question with several clauses ("user roles: how many can a user hold, support role") is also ranked clause by clause, so one clause's words do not hide a requirement another clause matches. A question about contradictions or conflicts also gets a text pointer to kb_check with domain-contradictions (stored requirements) and to kb_model mode predicates or a kb_upsert dryRun (a proposed rule).
Every response carries branch, the Kibi branch whose store was searched (null when the runtime attached none), whatever the result count. When that store was never compiled for the branch (a new branch created without the post-checkout hook) while .kb/ holds authored sources, the response also carries branchStore (state: "not_compiled", code: "branch_store_not_compiled", path, detail, remediation.command_argv: ["kibi", "sync"]) and the text says to run kibi sync before relying on the results: an empty result from that store says nothing about the authored requirements.
On the first intent-mode page, data.answer (kibi.search-answer.v1) turns the matches into what an agent asking "what governs this?" needs:
governing: current requirements matched by the query or linked to a matched entity, a closed requirement after a current one reached as well (its score carries the same three-quarter factor). A superseded requirement's replacement is added withvia: "supersedes <id>"only when the superseded requirement scored at least 0.8 of the best candidate's score, so a weak match on an old requirement does not fill a slot with its replacement. Each hasscore,via(how it was reached), and its linkedfacts(withfactKind, and for typed facts theclaimthey state and thekb_querycall inaskthat selects the fact by its own key arguments, as described underkb_query),scenarios,tests, andadrs. Facts list a fact the query matched first, then the facts grounding a clause (requires_*), then the constrained subject, at most eight per requirement; when more are linked, or the byte bound cut some,moreFactsgives thecountleft out and theask(kb_queryby the requirement'sid) that lists every link. Tests include those that verify the requirement's scenarios; each test'sviaisdirector the scenario it was reached through. Each requirement also carries:verdict: what the existing checks report about it.statusiscontradiction(a domain-contradiction witness names it),infeasible(a scenario-feasibility witness: a success scenario it specifies assumes a value a current requirement forbids, or it forbids another requirement's scenario),unknown(onlyunknownsbelow), ornone.witnesseslists each blocking finding with itscheck,status, the other requirement (with), thescenario, thefactsinvolved and adetail.nonemeans no check named the requirement, not that it is proven; proof-ladder status stays inkb_coverage.exceptions: requirements thatexemptsit, each withapprovedBywhen a human approved the exception.unknowns: what the checks could not decide, each with akindanddetail:contradiction_unresolved(a rule overlap the checks could not classify),feasibility_unknown(a success scenario whose assumptions no current requirement constrains),unresolved_proposition(a clause stillambiguousor anontology_gap),analysis_incomplete(no complete clause ledger), orverdict_unavailable(the checks could not run).
rationale: ADRs that explain the decisions, each with itssourcepath and anexcerpt: the opening sentences of its Decision section (falling back to Rationale, then the first paragraph), at most 280 characters.notGoverning: superseded or deprecated requirements, withsupersededBywhen known. They are listed so they are never read as current policy.observations: observation/meta facts, labelled as notes rather than rules.ungoverned: matched facts, scenarios, symbols and tests that no requirement owns (a fact that a requirement's scenario assumes, such as its failure side, is lifted to that requirement instead), each with itstype, its 1-basedrankin the results and, for typed facts, theclaimandaskabove. An unlinked predicate fact that states the same predicate and key arguments as a governing requirement's fact, with another value or polarity, carriesoverriddenBy(fact,requirement,claim) naming the fact that holds, and thenotenames the pair. A negative-path fact listed here (no current requirement specifies the scenarios that assume it) carriesnegativePathand a title prefixedForbidden:. When the top-ranked match is one of them, thenotesays so first: thegoverninglist, if any, was reached through lower-ranked matches and is not the top match's requirement.scope: the KB the answer was computed from:branch,snapshotId, andsyncedAt.kb_statussays whether that snapshot is stale.truncated:truewhen a size bound cut the layer short. The whole answer stays under 16 KB: long titles, excerpts and details are clipped, then ADR excerpts are dropped, then each requirement keeps only its first scenario and test, then lower-ranked requirements and list entries; a verdict keeps itsstatuswhen its witnesses are dropped.note: how to read the layer. An emptygoverninglist is not evidence that nothing governs the change.
The answer layer is graph traversal plus the existing checks scoped to the governing requirements: discovery, not proof. Use kb_check and kb_coverage for full consistency and proof status. Pass answer: false to skip it.
When the project activates a kibi.search-hints.v1 provider (such as kibi-plugin-search-hints) and the intent answer abstained or its top score is below 0.44, queryAnalysis.hints lists what the question may mean, found by meaning rather than shared words. It has trigger (abstained or weak), the provider stamp (with its model), and items: up to ten current requirements with id, title and score. A hit on a scenario, test or fact is shown as the current requirement linked to it, with the matched entity under via; one no requirement owns is shown as itself. A hit on a negative-path fact is shown as the current requirements it guards (via names the fact); one that guards no current requirement is shown as itself with a title prefixed Forbidden: and negativePath. The answer's top three governing requirements are left out. Shadow providers appear under shadow only, and diagnostics names a provider that failed, timed out, returned an invalid result or could not load; the search answers as usual in every case. The text names the first five hints. Hints never change the results, the answer layer or abstention: re-ask in a hint's words or pass them as semanticFacets.aliases, then read the requirement with kb_query. Pass hints: false to skip them.
Example:
{
"query": "what governs the login flow?",
"type": "req",
"limit": 10
}kb_compile_intent
Compile complete post-change intent into a deterministic, snapshot-bound plan without mutating the KB. The compiler reuses intent-aware discovery and the semantic advisor, accounts for every proposition, checks current contradiction witnesses, proposes canonical traceability links, and emits dependency-ordered kb_upsert-style steps only for resolved typed claims. A conditional clause ("only when", "only if", "must not ... unless") on one subject property compiles to a forbid rule linked by requires_rule; one the advisor cannot translate stays an ontology_gap proposition and the plan needs_resolution.
Parameters:
intent(required): Complete desired behavior, not a patch fragment.context(required when the plan creates a new requirement, otherwise optional): Why the requirement exists, who asked and constraints, in the requester's words. Rendered as the## Contextsection of the requirement body; on update the statement is replaced and every existing context section is kept byte for byte unlesscontext(or the source) is supplied, which replaces that section; a missing value is a validation error naming the field. Write "Reason not stated" rather than inventing one.sourceExcerpt,sourceReference(optional): A verbatim quote and where it came from, rendered as a blockquoted## Sourcesection.mode(required):createorupdate.requirementId(optional): Exact update target; automatic update selection is gated by score and runner-up margin.title,clauses,semanticFacets,sourceLocations,interpretations(optional): Context for title, proposition decomposition, host-agent facets, changed-code evidence, and typed rule IR. Eachclausesentry must be a verbatim fragment ofintent(whitespace may differ); a clause that does not occur inintentfails the call withVALIDATION_FAILEDnaming it, instead of producing a proposition over unrelated text.scenarioDrafts,testDrafts(optional): Draft traceability artifacts. Each draft'sbodyis carried as the step'sdocument.body, not as an entity property. Tests are linked through scenarios withverified_by(the scenario step carries the link, and tests are ordered before the scenarios that link to them; the requirement step carriesspecified_by); when multiple scenarios are supplied, each test must declare stablescenarioIds(a single scenario remains backward-compatible). Draft tests default to ancillaryintegration/internalevidence; explicitly declareend_to_end/consumerwhen that is the intended proof-bearing scope.proposalDecisions(optional): Explicitaccept/rejectdecisions for returned traceability proposals; pending proposals are excluded from executable steps.conflictReviews(optional): Your verdict on eachcontradictionAnalysis.reviewCandidatesentry of an earlier compile, as{requirementId, verdict: "conflict" | "no_conflict", note?}. Aconflictverdict makes the outcomeconflictand the planblocked; ano_conflictverdict clears that candidate. A verdict may name a current requirement discovery did not rank; one that names no current requirement is ignored with a diagnostic.
Returns:
kibi.compile-plan.v1 with planHash, status (ready, needs_resolution, or blocked), branch/KB/workspace snapshot bindings, discovery candidates, proposition ledger, contradiction analysis, traceability proposals, dependency-ordered steps, source before-hashes, and diagnostics. The plan is a review artifact; it is not a mutation request.
Every non-symbol step of a ready plan carries document.path, the authored document kb_apply_plan writes that entity to (the same canonical path kb_upsert would pick). The requirement's document is the first sourceLocations entry when it is a .md/.mdx file outside .kb/, otherwise its existing document or .kb/requirements/<id>.md; its document.body is the intent, then ## Context with context, then ## Source when sourceExcerpt or sourceReference is given, and semantic_text is written explicitly so the context never changes the checked meaning. Code sourceLocations are evidence only and are never write targets. sourceWrites is empty for compile plans. A step that cannot be applied as written (it fails entity validation or its document path cannot be resolved) makes the plan needs_resolution with the diagnostic A plan step cannot be applied as written: ….
contradictionAnalysis stages the plan in a rolled-back transaction and compares it with the current KB: introduced, removed and unchanged list full contradiction and scenario-infeasibility witnesses (kind property, predicate, rule or scenario_feasibility; a scenario witness carries scenario, requirements, assumedFacts and requirementFacts). Any introduced contradiction or infeasible scenario makes the plan blocked, whichever requirements it names; a pre-existing one blocks only when it names the target requirement. witnesses lists the ones that decided outcome.
outcome is no_conflict only when the check could decide. The checker compares only requirements with a logical representation (constrains, requires_property, requires_predicate or requires_rule links), so no witness does not mean no conflict. reasons lists what it could not check, each with the ids involved: unmodeled_target (claim keys of target propositions that are ontology_gap or ambiguous), unmodeled_related (related current requirements from discovery that have no logic, when the target is modeled) and analysis_unavailable (the staged check could not run). Any reason makes the outcome unresolved. reviewCandidates lists up to five related current requirements (discovery score at least 0.1; any related requirement when the target is unmodeled, only prose-only ones otherwise), each with requirementId, title, the sentence sharing the most terms with the intent, its statement, score, modeled and review (pending, conflict or no_conflict). nextAction tells the agent what to do while the outcome is not decided: compare the pending candidates and compile again with conflictReviews, resolve a conflict it reported (ask the human which rule holds, then supersede or change the requirement, or change the intent), or model the unmodeled claims. Pending reviews do not change the plan status: a plan with a modeled target stays ready with the outcome unresolved and the diagnostic Contradiction check incomplete: …, and becomes no_conflict once every candidate is reviewed no_conflict. A plan with an unmodeled target is already needs_resolution, and its outcome stays unresolved after review, because a review is not a logical check.
Example:
{
"intent": "Customer data must be retained for 7 years.",
"mode": "create",
"sourceLocations": [{"path": "src/retention/policy.ts", "symbol": "retentionYears"}]
}kb_apply_plan
Apply an approved kibi.compile-plan.v1 after revalidating its canonical hash, branch/KB/workspace snapshots, source before-hashes, and entity/relationship shapes. Every step runs through the same validation chain as kb_upsert (schema, proof receipts, relationship sources and targets, strict-lane pairing, supersedes direction, proposition-complete ingestion, grounding claim keys, predicate argument vocabulary), with entities and relationships created by earlier steps treated as present, and the whole plan is staged in a rolled-back transaction before the first write; a plan whose staged state introduces a contradiction or an infeasible success scenario is refused with nothing written.
A compile plan then applies all-or-nothing:
- Before the first write, Kibi writes a durable journal (
plan-apply-<hash>) next to the branch store (under.kb/recovery/plan-apply/until the store exists). The journal records the plan hash, the exact before and after bytes and hashes of every workspace file the plan changes (itssourceWrites, each step's entity document, and the relationship shards its steps append), every store upsert, and a fingerprint of the store entities the plan touches. Plans without source writes get a journal too. - Files are published with temp-file + rename, fsynced where the host supports it.
- All steps commit in one store transaction. That transaction is the only commit point. Each entity is committed with its authored document as its source, so
kibi sync --rebuildkeeps every entity and relationship the plan applied.
Any failure before the commit restores every file from the journal and leaves the store untouched; the error says no change was applied and the plan can be applied again. If the process dies mid-application, the next kb_apply_plan, kb_upsert or kb_delete call (or kb_apply_plan with that recoveryJournalId) finishes the journal before doing anything else. A journal interrupted before the store commit was submitted is rolled back. One interrupted during the commit is decided by the store fingerprint: unchanged means roll back, changed means complete. One whose commit was accepted is completed. Recovery is idempotent, and it refuses (PARTIAL_COMMIT_REPAIR_REQUIRED), changing nothing, when a journaled file holds neither its journaled before nor after bytes. Mutating calls on that branch then fail until an operator resolves it. kibi sync does not yet settle pending plan journals; run a mutating call or the explicit recovery first.
A bootstrap plan (kibi.bootstrap-plan.v1) applies its actions one at a time, checkpointing each in a bootstrap-<hash> journal under .kb/recovery/. Large bootstrap plans take a while (a few hundred actions can run past a minute), so:
- A synchronous apply sends MCP
notifications/progressafter each action when the request carries aprogressToken. Clients that reset their request timeout on progress (the MCP SDK'sresetTimeoutOnProgress) keep waiting, and the server's ownKIBI_MCP_TOOL_TIMEOUT_MSthen bounds the time between progress reports rather than the whole apply. async: truereturns akibi.job.v1receipt immediately and runs the apply as a background job; pollkb_job_statusfor the result. This needsKIBI_MCP_OPTIONAL_TOOLS=kb_job_status; without it the apply runs synchronously.- The plan is checked before any action runs. An invalid plan, or a missing or wrong
approvedPlanHash, fails the call itself (also withasync: true) instead of surfacing later in the job, and approval stays bound to the exact KB snapshot, including the journal generation and revision. A deterministic failure after application began (BOOTSTRAP_PLAN_REJECTED) is terminal and needs a corrected plan. - If the server dies mid-apply, call
kb_apply_planwith the journal'srecoveryJournalId. A journal stillapplyingwhose active action has no checkpoint is resumed without edits: the drift since the last checkpoint is attributed to that action, which is re-applied, and the result notes it. A source lock left by the dead process is reclaimed and recorded in the journal (lockReclaims); a lock whose holder is still alive keeps blocking. Any other drift since the last checkpoint is still refused. Never edit the journal by hand.
Parameters:
plan(required): Complete plan returned bykb_compile_intent.approvedPlanHash(required): Exact reviewedplanHash.recoveryJournalId(instead ofplan): Aplan-apply-*journal to complete or roll back, or another typed recovery journal returned by acommitted_with_repairsresult. Recovery never replays the original plan request.async(optional, defaultfalse): Start the apply as a background job and return akibi.job.v1receipt; see above. The CLI ignores it.
Returns:
kibi.plan-apply-result.v1 with entity/relationship counts, final snapshots, validation counts, changed paths (every source write and entity document the plan wrote), recoveryJournalId, and notes. outcome is applied when this call committed the plan, or replayed / rolled_back when a recovery completed or rolled back an interrupted application. Recoveries a call performed before its own work are listed in validationSummary.recoveredJournals and in the text content. If the call then fails, its error text ends with [settled before this failure: ...]. A store that reports a failure but shows the batch committed yields committed_with_repairs with STORE_COMMIT_REPORTED_FAILURE. A pending-source receipt failure after the commit yields committed_with_repairs with PENDING_SOURCE_RECEIPT_FAILED and a kb_apply_plan recovery next action; further writes fail with PLAN_APPLY_RECOVERY_REQUIRED until that journal is recovered. Re-applying a committed plan fails with MUTATION_ALREADY_COMMITTED. It also accepts kibi.migration-plan.v2; migration application requires approvedActionIds, an exact approvedPlanHash, and rejects blocked actions and review actions Kibi cannot execute. A review action with a cli invocation that Kibi can execute (semantic_inventory_rederive_drop_grounding, req_status_vocabulary_map, and a semantic_inventory_rederive that waits on a status mapping) runs only when its id is in approvedActionIds; kibi migrate --apply-safe without --approved-action selects automatic actions alone. The integrationPlan from kibi proof inspect --json is such a plan: its proof_integration_configure action writes .kb/proof/integrations.json, refusing a create once the file exists and any plan whose source files (package.json, lockfiles, runner configs) changed since planning. Migration results (kibi.migration-apply-result.v1) report per-action outcomes (applied, failed, skipped, each with a detail) and an overall outcome:
applied: every approved action applied (closeout.taskOutcome: complete).partially_applied: some actions applied before one failed; the rest were skipped (closeout.taskOutcome: interim).refused: nothing was applied and every failure was a refusal, a precondition that failed before the action changed anything (for example a proof-integration create plan whose file already exists, a source that changed since planning, or an action with no automatic executor). The workspace is unchanged, so there is nothing to reconcile: obtain a new plan. The envelope is an error (status: "error", MCPisError: true, CLI exit code 1) with codeMIGRATION_PLAN_REFUSEDwhose message carries the refused action'sdetail;closeout.taskOutcomeisblocked.reconciliation_required: nothing was applied but an action failed without being refused, so its partial effect must be inspected before retrying (closeout.taskOutcome: blocked).
After an applied migration on a healthy store, remainingPlan (kibi.migration-plan-digest.v2) reports what is left without repeating the whole plan: the merged plan's planHash, status, expected, scope, summary and diagnostics, the first 20 automatic actions as { id, code, state, autoApplicable, dependsOn } (automaticActions), counts of all automatic actions (automaticSummary: total, ready, blocked, and omitted for those past the first 20), and every other action counted by code, safety and state (actionGroups). A digest cannot be applied; kb_status, kb_check and kb_coverage (or kibi migrate) return the full plan with each action's details. When an automatic action in the digest is blocked, its next text says so: the action waits for the actions in its dependsOn and needs no approval until a later plan shows it ready.
Engine daemon after a session. MCP calls that use the branch store (for example kb_apply_plan, kb_upsert, kb_check) run in the workspace's engine daemon, a detached engine-daemon process with its own SWI-Prolog child that holds the branch store's rdf/lock. It is shared: later MCP sessions and CLI calls for the same workspace and branch reuse it. After the MCP server exits, the daemon and its lock stay until the daemon has been idle for 10 minutes (KIBI_ENGINE_IDLE_TIMEOUT_MS overrides this), then it exits and releases the lock (idle time is measured on the wall clock, so time the host spent suspended counts). A stopping daemon saves the store and detaches it, which removes rdf/lock and the ownership journal, before its SWI-Prolog child exits. A lock held by a live daemon is expected, not a stale lock: kibi engine status shows it and kibi engine stop ends it early. A lock whose process is gone is reclaimed automatically when the next engine starts, and kb_status reports the takeover in notices (store_lock_taken_over). A client only uses a daemon started with the same Kibi package versions (kibi-cli@…,kibi-core@…) and SWI-Prolog as its own: the daemon reports both in its handshake and refuses other requests from a client that differs, and the client stops such a daemon (for example one an older install started from a git hook) and starts its own. kibi doctor reports the package versions of the daemon that is running.
kb_ingest_proof
Ingest a producer-emitted kibi.proof-run.v1 artifact and evaluate it against each selected test's kibi.proof-contract.v1 proof obligations. Kibi rechecks the live workspace snapshot, integration command binding, run-level outcome, attempt history, success policy, and proof history ordering, then derives and appends idempotent kibi.proof-receipt.v1 receipts and compacts each history to the receipts that can still decide proof (kibi.proof-receipt-compaction.v1; kept receipts are never edited or reordered). Producers report what happened; Kibi evaluates proof. Caller-authored receipts and trusted outcomes are rejected.
Parameters:
snapshot(required): Workspace snapshot captured immediately before execution.artifact(required): Producer artifact containingversion,producer,integration,command_argv,code_snapshot, typedenvironment, run-levelrunoutcome, andproof_results(each withsymbol_id,target,outcome,binding, and factualattempts).testIds(optional): Existing test entities withkibi.proof-contract.v1. Omit to evaluate every test contracted to the artifact's integration.
Returns:
Per-test outcomes, receipt ids, applied/duplicate flags, receipt counts, the number of superseded receipts compacted away (compacted), expected-versus-received gap reports, the contract's proof kind, the evidenceLevel the receipt supports (proved only when its certificate re-checked), certificateRejection when it did not, and claimBindings, plus the artifact digest and Kibi-derived environment hash. A changed snapshot, unknown integration, command drift, run-level failure, failed success policy, or append-only violation fails before mutation.
kb_status
Return branch, snapshot, and freshness metadata for the attached KB, plus the deterministic workspace snapshot used to validate execution receipts.
Returns:
Branch name, KB snapshot ID, sync state, dirty flag, KB path metadata, and proofSnapshot evidence (available, dirty, file count, and kibi.workspace-snapshot.v2 version). An unavailable workspace snapshot is reported as unknown and cannot prove the proof stage. Receipt-only frontmatter edits do not change the v2 hash.
The response also includes exact branchAttachment metadata, bounded sorted
staleReasons (with affected entity IDs and truncation totals), and
proofSnapshotChanges. Editor/config paths are reported as ordinary
workspace changes; they are not silently ignored.
When migration is needed, the response includes schemaStatus and a typed
migrationPlan (kibi.migration-plan.v2) with canonical hash, scope
completeness, dependencies, safety classes, exact invocations, evidence, and
postconditions. Status never mutates and remains available without Prolog for
missing or damaged stores. The schema-config-upgrade action runs
kibi migrate --yes and lists every file that run writes, .gitignore
included; on the canonical .kb/ layout the source rewrites it performs
(such as symbol-legacy-link-mark on .kb/symbols.yaml, origin backfill and
lifecycle repairs) are separate actions it depends on, so they must be
approved with it. kb_apply_plan reports the upgrade's detail from the
migration audit record (schema versions, legacy-link marks, origin backfill,
lifecycle repairs, whether .gitignore changed).
kb_status remains diagnostic when the branch store is missing, incomplete,
or unreadable: it reports branchStore and a structured stale reason instead
of initialising or repairing storage. Status itself never creates a store,
but a call that attaches the engine does (kb_check and other tools that
need the engine over MCP, kibi check on the CLI, and kibi branch ensure),
and that store stays empty until kibi sync compiles it. An incomplete or unreadable exact store is rebuilt only through the
previewed kibi branch recover --apply workflow. A store that is missing or
empty (journal sequence 0) while .kb/ holds authored sources, the state of
a new branch created without the post-checkout hook, is one blocking stale
reason, branch_store_not_compiled (blocking: true, authoredSources,
remediation kibi sync), and the migrationPlan adds the automatic
branch-store-compile action (kibi sync) after branch-store-ensure;
syncState is then "stale", whether the store is missing or empty. A
missing store with no authored sources, and an incomplete or unreadable one,
report syncState: "unknown". kb_check over MCP and kibi check alike then
return the single branch-store-not-compiled violation (MCP uses the
runtime's branch attachment, including a KIBI_BRANCH override), and
kb_apply_plan's closeout.kbState reads stale (not not_evaluated)
while the store stays uncompiled.
An authored .kb/ file that the last kibi sync could not extract (an
invalid front matter field, such as a legacy requirement status: implemented) is a blocking stale reason, source_extraction_failed (path,
detail with the extraction error, remediation), for as long as the file
still has the bytes that failed; syncState is then "stale" and dirty is
true, because what the file declares is missing from the KB. kb_check
reports the same file as a blocking source-relationship-parity violation,
and the migrationPlan lists it as a review action. Editing the file and
running kibi sync clears it.
The Prolog freshness check compares file modification times with the
compiled snapshot. A fresh clone or a checkout rewrites every mtime without
changing content, so before reporting indexed_source_newer,
knowledge_source_newer or documentation_source_newer, kb_status
compares the file's sha256 with the hashes the last compilation recorded (the
store's sync-cache.json, a symbol manifest's composite hash of the sources
it references, or the per-symbol sourceHash in
.kb/symbol-coordinates.yaml). The coordinate artifact counts as evidence on
its own, so code files referenced only by symbols that kb_upsert wrote into
an untracked .kb/symbols.yaml are confirmed even though sync never hashed
that manifest. A file whose content matches is dropped, and when nothing else
remains the branch is fresh. A file with no recorded evidence keeps its
reason. Sources whose content did change become one automatic
freshness-resync action (kibi sync) in the migrationPlan, which
kb_apply_plan runs. The same action covers compiler_changed, which a
branch store compiled by a Kibi CLI with a different entity schema reports
once after an upgrade: the sync re-imports every source and stamps the
current schema, so that reason clears without a review action. When an
untracked .kb/symbols.yaml has no pending-source receipt (as older Kibi
versions left it) but declares symbols the branch store already holds,
kibi sync writes the receipt kb_upsert would have written, compiles the
manifest and records its content hash.
notices lists informational, non-blocking observations that never make the
KB stale. store_lock_taken_over (with brokenPid, reason and at)
reports that Kibi broke a branch-store lock whose holder was no longer
running and reattached: a crashed or killed engine or kibi prove run held
the store. A lock and ownership journal copied in with the .kb directory
(for example by cp -a while another workspace's engine held its own store)
is taken over the same way, with reason journal belongs to another workspace <path>, because a copied file never carries its advisory lock.
It is recorded in <store>/.kibi-lock-takeover.json, shown for 24 hours
(and by kibi doctor's branch-store check), replaced by the next takeover,
and deleted by kibi engine janitor --apply once it is older than that.
Example:
{}Engine cancellation limits
MCP tool timeouts abort the operation AbortSignal, which adaptProlog forwards
to EngineClient (query, queryEntities, searchEntities, queryStatusJson,
save). The client rejects pending RPCs and sends a best-effort cancel
frame. Queued daemon requests on that connection are skipped before
handle(). Cancel marks are per-connection (request ids are not global).
SWI-Prolog cannot cancel a running interactive goal, so when the cancelled
request is the one running, or its client disconnects while it runs, the
daemon stops its Prolog session; the next request restarts the session and
reattaches the branch store, and requests queued behind it run there. The
engine's own 120 s query timeout stops the session the same way. Read-tool
timeouts still must not call resetProlog / terminate() on the client,
so siblings do not fail with Kibi engine connection closed.
To keep one read from holding the queue, set KIBI_ENGINE_READ_TIME_LIMIT_MS
and/or KIBI_ENGINE_READ_INFERENCE_LIMIT in the MCP server's environment (see
engine read limits). A bounded read runs
under SWI-Prolog call_with_time_limit/2 and call_with_inference_limit/3, so
the engine stops it itself and serves the next queued request. A tool whose
read hit its limit returns an error envelope with error.code
QUERY_LIMIT_EXCEEDED and error.details.limitExceeded
({ "kind": "time" | "inferences", "limit": <n> }); it never returns a partial
answer. Write requests are never bounded, but the read-only queries a write
tool such as kb_upsert runs before it writes are reads: under a limit they can
stop it with QUERY_LIMIT_EXCEEDED before anything is written.
On a detached HEAD that no single local branch points at, read tools answer
from a read-only snapshot of the checkout and add a detached_head_read_only
warning diagnostic (commit, branches at HEAD, store path, writes: "refused"); write tools fail with instructions to check out a branch or set
KIBI_BRANCH. See kibi branch.
Discovery tools (kb_query, kb_search, kb_status) may opt into
agentVisibleStructuredData so envelope data is also embedded in content
text for hosts that hide structuredContent.
kb_skills
Read bundled Kibi agent skills for progressive disclosure. Read-only; does not mutate the KB or require Prolog. The CLI peer is kibi skill --input -; the narrower skills-list, skills-load, and skills-read routes remain.
Parameters:
action(required):list,load, orread.id(required forloadandread): Bundled skill ID. Example:'kibi-usage'.resource(required forread): Manifest-declared resource path. Example:'resources/fact-lanes.md'. Arbitrary file paths are not exposed.
Returns:
The payload of the routed operation plus action:
list: skill manifests withid,name,version,description, and declaredresources.load: the skill bundle withmanifest,body,resources,hash, andsourceType. The visible text lists the declared resources so agents can discover follow-upreadcalls without guessing paths.read: the resource contents as text.
Example:
{
"action": "read",
"id": "kibi-usage",
"resource": "resources/fact-lanes.md"
}kb_find_gaps
Run curated missing/present relationship analysis over KB entities.
Parameters:
type(optional): Entity type filtermissingRelationships(optional): Required-to-be-absent relationship typespresentRelationships(optional): Required-to-be-present relationship types. In both lists a relationship counts in either direction, andverified_byandvalidates(its documented inverse for req/scenario ↔ test links) satisfy each other: a requirement whose testvalidatesit is not averified_bygap.relationshipCountsstill counts each relationship name separately.tags(optional): Tag filtersourceFile(optional): Source-file substring filterlimit/offset(optional): Pagination controls
Returns:
rows (the requested page, each with its relationship counts), count (matching rows before pagination), summary (total, the same number, and provenanceStubs: the bootstrap facts tagged bootstrap:provenance-stub that match the filters but are counted apart from knowledge and left out of rows unless tags names that tag), and meta (status metadata).
Example:
{
"type": "req",
"missingRelationships": ["specified_by", "verified_by"],
"sourceFile": "src/auth"
}kb_coverage
Generate curated structural coverage and conservative end-to-end requirement proof reports.
Parameters:
by(optional):req,symbol, ortypetags(optional): Tag filterincludePassing(optional): Include requirements with a tested or not-applicable proof outcome in addition to rows that still require repairstatuses(optional, req mode): Requirement proof-status filter (tested,missing,unresolved,not_applicable); selecting statuses implies include-passing and returns only rows whoseproofStatusis listed.not_applicablerows carry their typed applicability reason inproofStages.applicability.reason. The summary always reflects the whole KB.includeTransitive(optional): Include transitive symbol coverageincludeMigrationPreview(optional): Add a deterministic read-only legacy proposition migration previewmigrationLimit/migrationOffset(optional): Page ready semantic-inventory requirement batches; the default limit is one and the maximum is tenmigrationPredicateLimit/migrationPredicateMinScore(optional): Bound exact predicate-schema candidates retained per propositionlimit/offset(optional): Pagination controls
Returns:
Coverage summary rows, status metadata, and—when by: "req"—a deterministic kibi.repair-plan.v1 read-only migration plan.
For requirement coverage, summaries distinguish evaluated must-priority requirements from rows marked notApplicable. Requirement rows retain compatibility-oriented coverageStatus and add a separate kibi.requirement-proof.v5 result with evidenceLevel (proved, tested, asserted or unverified, with the evidence[] entries that earned it; the summary counts them under evidenceLevels), per-claim claimEvidence[] with claimSummary and unprovedClaims (proved needs a derived certificate binding for every applicable claim; the summary totals them under proofClaims), evidenceFloor (required, source, status; the summary counts current requirements with a floor under evidenceFloors as met, below and pendingReproof), proofStatus (tested, named proven before v4, unresolved, missing, or not_applicable for a non-current requirement), inspectable proofStages, blocking proofGaps, non-blocking proofAdvisories, and ranked proofRepairs. A row is proven only when semantic inventory and grounding, contradiction analysis, every linked scenario's qualifying fresh passing E2E receipt evidence, executable test symbols, production ownership/coverage, and exact source coordinates all pass. Every linked E2E proof-bearing test is mandatory: missing, stale, failed, invalid, snapshot-unavailable, or contract-mismatched evidence remains a blocking proofGap, with per-scenario diagnostics in proofStages.passingE2e.scenarioObligations. Unit/integration-only ancillary evidence remains nonblocking when the scenario has qualifying E2E evidence. A proven row never includes blocking proofGaps.
repairPlan turns those row-local gaps into dependency-ordered batches across the returned requirement scope. Each batch identifies one requirement and phase, groups same-phase repairs, declares state: ready|blocked, lists prior dependsOn batches, and carries workflowSteps, targeted validationRules, and a conservative write policy. Plans are always readOnly: true; batches are always autoApplicable: false, so callers must query current endpoints, review semantic choices, validate payloads, and execute upserts sequentially. scope.complete: false and status: partial mean pagination omitted actionable requirements; rerun with offset: 0 and a larger limit before treating the result as a project migration plan. planId remains stable for the same snapshot, filters, proof evidence, and gaps while volatile receipt age/check-time fields are ignored.
With includeMigrationPreview: true, legacyMigrationPlan adds the versioned kibi.legacy-migration-plan.v1 review surface. It selects only ready semantic-inventory repair batches, defaults to one requirement, binds normalized authored Markdown to an exact SHA-256 hash and UTF-8 spans, and gives every proposition one recommended lane or explicit unresolved disposition. Ranked candidates preserve exact schema identity, signature, origin, polarity, binding status, and unbound arguments, but never produce an applicable write. Authored prose is previewed in requirement-only semantic_text, while an independent text_ref remains unchanged; a differing pre-existing semantic_text blocks the batch as semantic source drift.
The passing-E2E stage evaluates append-only proof-receipt history. New evidence is produced by kibi prove as kibi.proof-receipt.v1. A current receipt must bind the test and its typed scope, integration command argv, contract hash, execution fingerprint, deterministic current code snapshot, canonical environment hash, timestamps, outcome, artifact digest, and observed proof results. The newest receipt for the live snapshot, current contract hash, and current fingerprint must be passing and no older than seven days. Missing, wrong-snapshot, stale, failed, malformed, mismatched, future-dated, or snapshot-unavailable evidence cannot prove the requirement; durable test status remains structural metadata.
Symbol rows distinguish production symbols from executable test symbols. Executable-only symbols are not applicable to production coverage; mixed-role symbols are uncovered and carry an explicit role error.
Example:
{
"by": "req",
"includePassing": false,
"includeTransitive": true
}kb_graph
Run bounded graph traversal from one or more seed IDs.
Parameters:
seedIds(required): Starting IDsrelationships(optional): Relationship filterdirection(optional):outgoing,incoming, orbothdepth(optional): Maximum traversal depthentityTypes(optional): Filter returned nodes by typemaxNodes/maxEdges(optional): Traversal bounds
Returns: Nodes, edges, truncation flag, and status metadata.
Example:
{
"seedIds": ["REQ-cli-gc"],
"direction": "both",
"depth": 2,
"maxNodes": 100,
"maxEdges": 200
}kb_sparql_remote
Registered only when KIBI_MCP_OPTIONAL_TOOLS names it (or is all); the kibi sparql-remote CLI route is always available.
Run an opt-in SPARQL SELECT query against an external HTTP(S) SPARQL endpoint. This tool is remote-only: it does not query Kibi's local RDF store directly, does not start a local SPARQL endpoint, and does not store credentials.
Parameters:
endpoint(required): Remote SPARQL endpoint URL. Must start withhttp://orhttps://; local file paths are rejected.query(required): SPARQLSELECTquery text.timeoutMs(optional): Positive timeout in milliseconds for the remote request.
Returns: Rows returned by the remote endpoint, serialized as structured MCP content. Network availability, endpoint rate limits, and remote endpoint authentication requirements are outside Kibi's control.
Example:
{
"endpoint": "https://query.wikidata.org/sparql",
"query": "SELECT ?item WHERE { ?item wdt:P31 wd:Q146 . } LIMIT 5",
"timeoutMs": 15000
}Internal Prolog Implementation Notes
Kibi's Prolog core may use maintained SWI-Prolog libraries such as library(aggregate) for count/reporting helpers and library(chr) for isolated derived-fact pilots. These are internal implementation details and do not change public KB semantics, MCP response shapes, or the canonical validation rules unless a future release explicitly documents such a change.
kb_upsert
Create or update a single entity and optional relationships in one call. When the caller has a filesystem-capable context, the mutation is source-first: the tracked entity document and relationship shard are authored transactionally, then the compiled branch store is updated. Kibi never stages or commits those working-tree files for Git.
Parameters:
type: Entity type enumid: Entity IDproperties: Entity fields, including requiredtitleandstatus(status values depend on entity type; legacy values may still be accepted for compatibility). Forsymbolentities this may includesourceFile,symbol_role, andgranularity_reason; forfactentities this includes typed fact fields such asfact_kind,subject_key,property_key,operator,value_type, and one matchingvalue_*field.relationships(optional): Relationship rows with enum-backedtype,from, andtodryRun(optional, defaultfalse): Validate the payload and write nothing. See Dry run.document(optional):{ path?, body? }for an explicit tracked source target. Existing entities preserve their current body whenbodyis omitted; new requirements default the body tosemantic_text. New entities without a unique configured target must providedocument.path. Updating an existing Markdown document rewrites only the frontmatter keys whose value changes (new keys are appended); every other key keeps its authored bytes, including quoting, unquoted timestamps, flow lists and indentation.
symbol_role values are behavioral, structural, type-shape, config, module, and unknown. Use behavioral for manual anchors when behavior is hidden inside factory/expression composition and the extractor cannot create a narrower symbol.
properties.origin (optional, every type) records provenance: {kind: human|agent|migration|import, ref?, approved_by?, recorded_at?}. A new entity written without it is recorded as {kind: agent, recorded_at: <write time>} (a dry run validates a supplied origin but does not add the default to normalizedPreview). An update without it never changes the stored origin, and an entity that has none keeps none. A supplied origin is written as given; a missing recorded_at gets the write time. See docs/entity-schema.md#entity-origin.
properties.firmness (optional, req and adr only) is firm, default or exploratory; absent reads as default when the entity's origin.kind is agent (a new entity written without origin is recorded as agent) and as firm otherwise. A firm write needs origin.ref (or approval_ref on a requirement) pointing at the human words that state the rule, or it is rejected. A write that changes the title, stated meaning, ADR body or firmness of a current firm decision is rejected unless it cites new human words (a changed origin.ref, or approval_ref on a requirement); supersede the decision instead when the person agreed to a replacement. See docs/entity-schema.md#decision-firmness.
For current requirement writes with assertive prose, mutation fails closed unless the payload preserves the complete advisor ledger and source contract. A relationship-only update of an existing requirement does not need to resend the ledger: when the payload carries no semantic_* or logic_claims field and any title or text_ref it sends equals the stored value, Kibi merges the stored ledger (semantic_text, semantic_clauses, semantic_inventory, semantic_inventory_version, semantic_source_field, semantic_source_hash, logic_claims) and the stored text_ref when the payload omits it under the payload, then runs the proposition-complete check on the merged requirement. For example, {"type":"req","id":"REQ-x","properties":{"title":"<stored title>","status":"open"},"relationships":[{"type":"specified_by","from":"REQ-x","to":"SCEN-x"}]} links a scenario and keeps the ledger. A payload that supplies any ledger field, or changes title or text_ref, is checked exactly as sent. An update of a stored requirement is also checked as its authored file will read after the write: the stored status, prose and ledger with the payload's fields on top. When that requirement is current (open, in_progress, closed, active, approved) and lacks a complete ledger, the update fails with Proposition-complete ingestion failed: <id> would be written as a current requirement without a complete proposition inventory (...), the error kibi sync would otherwise report later; for example {"status":"closed"} on a draft requirement that never had an inventory. Supply the inventory contract that kb_model mode analyze returns for the requirement's id and complete semantic_text in the same write, or retire the requirement through a superseding one. A requirement that was already current with the same prose keeps accepting updates that change neither. When the store does not hold the entity but the file the write would merge into exists and declares it (a file kibi sync could not extract, or one written since the last sync), that file's front matter is the stored state for these checks, so the write is judged as an update of what the file says; a write that would leave the file uncompilable is refused with Upsert of <id> refused: <id> exists in <file> but is not compiled (...), naming the extraction error, and a successful one returns a warning that it updated that file. The Proposition-complete ingestion failed error ends with that contract as JSON (semantic_inventory_version, semantic_source_field, semantic_source_hash, semantic_inventory, logic_claims), keeping any inventory status the payload set for the same claim_key, so merging it into properties and resending needs no separate kb_model call. Every assertive claim key must appear exactly once in logic_claims; every modeled entry must have exactly one logical relationship whose target fact carries that same key. Explicit unresolved statuses are accepted as honest inventory states but do not make the requirement proof-complete.
Returns:
Confirmation of entity creation/update and relationship creation counts. Successful responses may also include structuredContent.semanticAdvisor (requirements only) and structuredContent.warnings. Modeling suggestions remain reviewable, while proposition accounting and source/grounding integrity are blocking for applicable requirement writes. A symbol payload with an implements edge but neither covered_by nor executable_for (and no covered_by edge already stored for that symbol) returns a warning, on dryRun and on the write, that kb_check will report symbol-coverage until the symbol gets covered_by to a test that covers the requirement.
Dry run validation
A committed fact write that carries claim_text returns the stored claimKey (derived from claim_text when the payload did not supply claim_key), so the writer can link requires_predicate or requires_property and read the key back without a kb_query; a dry run shows the same key in normalizedPreview.claim_key.
Proof-receipt history is append-only: an update of a test that sends proof_receipts must keep every stored receipt unchanged and in order. An update that omits proof_receipts keeps the stored history (and the stored verification_scope and verification_perspective when it omits those too), so a test's title or links can change without resending its receipts.
Call kb_upsert with dryRun: true to validate a payload without mutating the KB (catalog operation kb_validate_upsert; CLI kibi upsert with "dryRun": true, or kibi validate-upsert). This read-only preflight returns valid, errors, warnings, semanticAdvisor, and normalizedPreview, plus dryRun: true and skippedEffects: ["kb-write", "workspace-write"]. With a store attached it runs exactly the validation a real kb_upsert runs before its first write: schema, append-only proof receipts, relationship sources and live targets, symbol granularity, strict-lane pairing, supersedes direction, proposition completeness, grounding claim keys and predicate argument vocabulary. For a req it then previews the commit-time contradiction check: the entity and its relationships are staged in a transaction that is always rolled back and check_req_contradiction runs against that staged store, so a payload the commit would refuse with Contradiction detected … (stage=contradiction_check) is reported valid: false with the same message (_skipContradictionCheck skips the preview as it skips the commit check). A dry run therefore rejects what the write would reject as far as the store can tell. It writes nothing, so it cannot report what only a write reveals: DOCUMENT_PATH_REQUIRED, filesystem, lock and pending-receipt failures, a concurrent writer, or findings of kb_check-only rules such as logic-coverage and scenario-feasibility. Without a store it runs only the store-independent checks. A payload the dry run finds invalid makes the envelope an error (status: "error", MCP isError: true, CLI exit code 1) with code UPSERT_DRY_RUN_INVALID, whose message carries the validation errors; data still reports valid: false, errors and dryRun: true, and both write effects are not_applicable. The symbol granularity check judges the symbol as it will be stored: a payload that only adds implements or covered_by links to an existing symbol is checked against the stored sourceFile and granularity_reason, and a class-level symbol whose public members are behavioral symbols is refused as coarse, as the staged hook and kibi check (symbol-granularity) refuse it.
semanticAdvisor describes requirement prose, so it is null on the preflight of any other entity type (and absent from its write result): analysing a fact's title would report claim keys nothing declares, while the fact's own claim_key is in normalizedPreview. For a requirement it includes a version, payload hash, source-bound inventory contract, proposition ledger, logic readiness, candidate lane, detected signals, ambiguity witnesses, modeling suggestions, and suggested next tools. A valid preflight proves source accounting at the ingestion boundary; contradiction checks and proof evidence are still separate proof stages.
plannedFacts (dry run only) stages fact writes that have not happened yet: pass the applyPlan entries kb_model returned (type, id, properties, optional relationships). The planned facts are validated in order, each against the KB plus the facts before it, exactly as kb_apply_plan validates a plan's steps, so the payload's requires_predicate or requires_property target resolves and its claim_key is read from the plan instead of failing with logical grounding target … must declare a claim_key. The contradiction preview then stages the planned facts and the payload together in one rolled-back transaction and compares the witnesses with the current KB's: a contradiction or infeasible scenario the batch would introduce is refused with Contradiction detected for requirement … (stage=contradiction_check, plannedFacts staged) and the witness reason (for example Decision conflict on default:permission_rule(coach,read,unassigned_analysis_request)); otherwise the result adds stagedFacts (the planned ids in order) and whatIf (introduced, removed, unchanged witnesses). A planned entry that is not a fact, reuses the payload's id or fails its own validation is reported as planned fact <id> is invalid: …. plannedFacts on a real write is rejected: write the facts first, with kb_upsert or the kb_model plan through kb_apply_plan.
When invoked through MCP, the dry run also attaches to Prolog and validates live relationship endpoint types before mutation. Invalid tuples such as verified_by fact -> test are rejected in preflight with the same relationship guidance kb_upsert would return.
kb_delete
Delete one or more entities by ID, or retract exact relationship triples. The two modes are mutually exclusive. Relationship deletion preflights the whole batch, preserves endpoints and unrelated edges, and handles legacy relationship shards through Kibi internals.
Parameters:
ids: Array of entity IDs to deleterelationships: Array of exact{type, from, to}triples to retractdryRun(optional): Preview the delete and write nothing (see below).approvedPlanHash(optional,idsonly): Apply the authored-entity deletion plan whoseplanHashthis is, in the same call (see below). Not allowed withrelationshipsordryRun: true.
Provide exactly one non-empty array; ids and relationships cannot be mixed.
Returns:
A direct delete returns deleted, skipped and errors (per-id failures
such as a missing entity or one with dependents); a relationship delete adds
relationships_deleted, per-selector relationship_results, and
sourceWrites when a canonical shard or authored source was patched. Never
edit .kb/relationships directly. Any call that is not a direct delete
carries an outcome:
outcome |
When | What to do next |
|---|---|---|
plan_returned |
An id is authored in a Markdown or YAML source. Nothing is written: deletionPlan is a hash-bound kibi.entity-deletion-plan.v1 and skippedEffects lists kb-write and workspace-write. |
Review the plan, then run nextActions[0]: {operation: "kb_apply_plan", input: {plan, approvedPlanHash}, required: true}. Pass input unmodified. Or repeat the kb_delete call with approvedPlanHash: deletionPlan.planHash. |
supersession_required |
An id is an authored requirement. Requirements evolve append-only and are never deleted; nothing is written. | nextActions[0] is a kb_upsert template: upsert a replacement requirement with a supersedes relationship to the old one, then upsert the old requirement with status: closed. |
plan_applied |
approvedPlanHash matched the freshly computed plan. |
The plan went through kb_apply_plan's validation, journal and recovery path. deleted, planHash, sourcePaths and recoveryJournalId report what changed; status: committed_with_repairs with a kb_apply_plan recovery nextActions entry means the compiled retraction needs repair. |
dry_run |
dryRun: true on a relationship or direct entity delete. |
Nothing is written. wouldDelete counts what a commit would remove (entities and ids, or relationships and compiledEdges), sourceWrites lists the shard and authored-source writes with their before and after hashes, and relationship_results describe the planned effect per selector. |
errors lists only real per-id failures. A returned plan is not an error, and
the call reports status: "success". An id that was resolved but not covered by
the plan (a non-authored id in the same call as authored ones) is listed in
errors and must be deleted in a separate call.
dryRun: true on authored ids returns the same plan as without it, with
dryRun: true, since that path never writes.
approvedPlanHash recomputes the plan from the current sources and applies it
only when its hash still equals the approved one. A different or stale hash
fails with DELETE_PLAN_HASH_MISMATCH and writes nothing. A plan that requires
supersession fails with REQUIREMENT_SUPERSESSION_REQUIRED. Approval also
fails (VALIDATION_FAILED) when an id was not resolved into the plan, or when
no id produced an authored plan.
kb_check
Run KB validation rules after mutations. Agents can also opt into read-only changed-file impact diagnostics for source edits while the edit context is still fresh. The MCP tool and CLI JSON route are peer interactive gates; CLI staged checks and git hooks remain the commit-time enforcement gate.
Parameters:
rules(optional): Validation rule subset. The allowed names are maintained inpackages/core/schema/rule-registry.json(single source for the tool schema, the TS rule registry, and the Prolog check dispatch):must-priority-coverage,symbol-coverage,symbol-traceability,no-dangling-refs,source-relationship-parity,branch-store-not-compiled,source-path-dangling,no-cycles,required-fields,deprecated-adr-no-successor,superseded-requirement-open,scenario-feasibility,scenario-feasibility-unknown,exception-claim-keys,numeric-string-value,rule-key-arguments-missing,domain-contradictions,logic-coverage,rule-safety,rule-verifiability,query-plan-safety,req-status-vocabulary,retired-reason-missing,retired-owner-only,strict-fact-shape,strict-req-fact-pairing,predicate-verifiability,strict-readiness,semantic-completeness,related-requirement-unmodeled,proof-contract-symbols,entity-id-style,domain-redundancy,domain-implication,subject-key-identity,subject-key-shape,ontology-quality,exception-unapproved,exception-approval-self-attested,agent-requirement-unapproved,requirement-rationale-missing,entity-context-missing,entity-context-acknowledged,decision-firm-unreferenced,decision-firm-superseded,decision-firm-edited,supersedes-reason-missing,supersedes-reason-acknowledged,symbol-owner-superseded,adr-unlinked,adr-proposed,predicate-schema-conformance,policy-ownership,policy-markers. Canonical rules populate blockingviolations[].must-priority-coveragecounts only current must-priority requirements: one that another requirement supersedes, one with a retired status, or oneclosedwithout theimplementedtag owes no scenario or test (seedocs/inference-rules.md). When the current branch's store was never compiled (missing, or empty at journal sequence 0) while.kb/holds authored sources,kb_checkreturns only thebranch-store-not-compiledviolation, namingkibi sync, plus amigrationPlanwhose automaticbranch-store-compileaction runs it; every other rule would read an empty KB. The vocabulary-convergence rules (entity-id-style,domain-redundancy,subject-key-identity,subject-key-shape,predicate-schema-conformanceas warnings;domain-implication,ontology-qualityas info) are advisory, run by default, and report non-blockingqualityDiagnosticswhoseevidence.witnessescarry exact requirement IDs, fact IDs, and signatures; seedocs/cli-reference.mdfor their precise definitions.kb_checknever imports capability plugins, so these results are deterministic and offline.policy-ownershipandpolicy-markersare canonical but inert unless a package is activated forkibi.check-policy.v1(such as the experimentalkibi-plugin-ui); Kibi then reads that package's policy JSON as data and blocks production symbols in the policy's file set that implement no current requirement grounded in its predicates (policy-ownership), and implementing files that lack a marker the KB declares for their requirement's pattern (policy-markers). An activated policy that cannot be read blocks under the first selected policy rule.domain-redundancyis suppressed for pairs linked bysupersedesorrestates.req-status-vocabularyrejects requirement statuses outside the canonical+legacy vocabulary (open,in_progress,closed,retired; legacyactive,approved) — e.g. ADR vocabulary such asacceptedcompiles but silently falls out of the proof ladder.retired-reason-missingblocks aretiredrequirement withoutretired_reason, andretired-owner-onlyblocks a current fact, scenario or test whose every owning requirement is retired (seedocs/entity-schema.md, Retired requirements).scenario-feasibilityblocks on a success scenario whose assumed values cannot hold, alone or together, with what the current requirements governing it require throughrequires_propertyfacts or typedrequires_rulerules, within each constraint's scope and validity window (each witness names a minimal set of requirements, assumption facts and requirement facts), unless an exception requirement with a non-emptyapproved_byexempts the requirement (only the clauses in itsexempts_claims, when set);scenario-feasibility-unknownis advisory and lists success scenarios whose feasibility cannot be decided (noassumes, assumptions that contradict each other, an assumed property no governing requirement constrains, a type, unit or operator that cannot be compared, governing requirements with no common value, a governing rule the assumptions neither satisfy nor refute, or a conflict only with constraints whose validity window may not cover the scenario).exception-claim-keysblocks on an exception whoseexempts_claimsnames a key that is not a claim of a requirement it exempts.numeric-string-valueis advisory and listsproperty_valuefacts that store a plain decimal asvalue_type: stringwhere the comparison is numeric, since strings are never coerced and such facts drop out of contradiction and feasibility checks.exception-unapproved(an exception thatexemptsa requirement but has noapproved_by),exception-approval-self-attested(an agent-authored exception whoseapproved_byis not corroborated byorigin.approved_byandapproval_ref) andagent-requirement-unapproved(info; agent-authored current requirements withoutorigin.approved_by, at most 25 per check plus one summary) are advisory approval checks.superseded-requirement-openblocks a requirement that another requirementsupersedesunless its status isclosed, and reports requirements that supersede each other (directly or through a chain) once per cycle, naming every member;no-cyclesfollows onlydepends_on.source-path-danglingblocks an authoredsourcefield that names neither an existing workspace path (a#anchorsuffix is ignored), an existing entity id, nor an http(s) URL; a missingsourceis allowed. The authored field is dead data (the compiledsourceis always the entity's own file andkb_upsertnever writes the field), so each finding names its automatic fix:evidence.rewritefor a pre-canonicaldocumentation/<lane>/...or<lane>/...value whose file exists under.kb/<lane>/and is not the entity's own file, otherwiseevidence.remove(selffor a value naming the entity's own file,danglingfor one Kibi cannot map), plusevidence.refusedwhen the edit is not safe. It also blocks atext_refshaped like one workspace file path that names no file (evidence.field: text_ref); such a value is rewritten only to a moved.kb/file and is otherwise refused for a person, never removed. The migration plan turns superseded requirements into aclose_superseded_requirementsautomatic action plus onereview_supersession_cycleper cycle, and dangling sources into the automaticsource_path_rewriteaction (whose evidence listsrewritesandremovals); only a value withevidence.refusedbecomes areview_source_path_danglingreview.symbol-owner-superseded(a symbol whose everyimplementstarget is superseded, deprecated or retired; at most 25 per check plus one summary),adr-unlinked(an accepted ADR no requirement or ADR links with, in either direction),adr-proposed(info: an ADR stillproposedand not superseded) andrequirement-rationale-missing(a current requirement withorigin.kindhumanoragentand norationalefield, no## Rationale/## Whysection and no ADR link; at most 25 per check plus one summary) are advisory lifecycle checks.entity-context-missingis canonical and blocks a currentreq,scenario,test,adror observation/metafactwith no body context (seedocs/entity-schema.md, Body contract);entity-context-acknowledged(info) counts the entities the schema 8 migration acknowledged (taggedreview:context-missingand listed in.kb/manifest.json); the tag on any other entity is a violation.kb_upsertreturns the same finding as a warning, including on dryRun.decision-firm-unreferenced,decision-firm-superseded,decision-firm-editedandsupersedes-reason-missingare canonical (KB schema 9): a current requirement or ADR markedfirmness: firmmust cite the human words it rests on (origin.ref, orapproval_refon a requirement;kb_upsertrejects such a write up front), only a firm decision may supersede a firm one (retired superseders included; from KB schema 10 a decision withoutfirmnessis firm unless an agent wrote it, and the supersedes of such decisions recorded earlier are acknowledged in.kb/manifest.jsonfirmSupersedeAcknowledged), a current decision that was firm atHEADmust not have its claim (title, stated meaning, an ADR's body, or its firmness) changed in the working tree unless the edit cites new human words (kb_upsertrefuses such a write up front, dryRun included), and a current superseding requirement or ADR needs a## Why this changedsection of at least 12 words;supersedes-reason-acknowledged(info) counts the decisions whose supersede edges the schema 9 migration acknowledged in.kb/manifest.json; Kibi cannot verify that a reference points at a real person's words (seedocs/entity-schema.md, Decision firmness).subject-key-identityalso reports one subject or claim minted as several active facts (the samesubject_key, or the samesubject_key,property_key,operator,polarity(absent meansrequire), typed value andunit; facts linked only by superseded or deprecated requirements are not counted), andsubject-key-shapealso reports property keys that number a clause (clause_03_...).rule-key-arguments-missingis advisory and names, for each opposing rule pair that isunresolvedonly because a condition predicate declares nokey_arguments, the predicate (namespace:name/arity) and the key positions that would decide the pair.strict-fact-shapeis a canonical blocking check as of schema 7.strict-req-fact-pairing,predicate-verifiability, andproof-contract-symbolsare advisory modeling checks: they run by default and report as non-blockingqualityDiagnostics. A requirement thatconstrainsa subject fact is paired either by arequires_propertyfact on the samesubject_keyor by arequires_predicatefact about thatsubject_key(the grounding areplace_groundingplan leaves): the predicate fact's ownsubject_key, else the argument its project-localpredicate_schemanamessubject(any position), else its first argument when neither is declared, sostrict-req-fact-pairingandstrict-readinessreport neither.proof-contract-symbolsreports unresolvedrequired_proofs.symbol_idvalues, type-shape required proofs, andproof_bindings.source_filedisagreement with the named symbolsourceFile; Kibi does not infer TEST names from filenames. Migration diagnostics (strict-readiness,semantic-completeness) run only when explicitly selected.related-requirement-unmodeledis canonical and blocks a current requirement whose ledger still hasstatus: missingpropositions while itrelates_to(either direction) a current requirement modeled with strict property or ground predicate facts; the finding names the modeled keys and asks for those propositions to be modeled against them or for asupersedesdecision (requirements without a ledger, classified ledgers, unmodeled neighbours and superseded neighbours are not reported).logic-coverageis enabled by default, validates explicitly declared requirement manifests against linked ground facts, and leaves requirements without a manifest as gradual-backfill debt reported by quality diagnostics.domain-contradictionscompares strict property constraints and exact opposite predicate polarities over the same namespace, predicate name, and ordered arguments. It does not infer arbitrary equivalence between differently shaped predicates.sourceFiles(optional): Repo-relative source paths to inspect for changed-file impact diagnostics.staged(optional): Inspect staged source changes when building impact diagnostics.includeWorkingTreeDiff(optional): Include unstaged working-tree content/diffs for the suppliedsourceFiles.includeImpactDiagnostics(optional): Include changed-file diagnostics such assymbol_granularity_violation,symbol_semantic_review_needed,source_file_unownedandrequirement_statement_unverifiedin structured output.maxDiagnostics(optional): Cap returned impact diagnostics. Graph validation violations are not capped by this value.workspaceRoot(optional): Workspace root for impact diagnostics. Defaults to the MCP server workspace.async(optional, defaultfalse): Start the check as a background job and return akibi.job.v1receipt (jobId,status: "running",pollWith: "kb_job_status") immediately instead of holding the request until the tool timeout. Use for full checks on large KBs that would exceedKIBI_MCP_TOOL_TIMEOUT_MS. This needs the opt-inkb_job_statustool (KIBI_MCP_OPTIONAL_TOOLS=kb_job_status); without it,async: trueis ignored and the check runs synchronously. Pollkb_job_statusuntilstatusissucceeded(full result underresult) orfailed(error undererror). Jobs are process-local: they are not persisted and are dropped on server restart.
Returns:
Validation report with any hard violations found and suggested fixes. structuredContent.evaluated says what the run evaluated: rules, the rule names that ran (only branch-store-not-compiled when the branch store was never compiled, none when rules: []), and for domain-contradictions domainContradictions.factPairsExamined, the number of distinct pairs of requirement facts the rule compared (strict property facts of two current requirements on the same subject and property, predicate facts with the same namespace, name and arguments, and decision facts agreeing on every key argument). The text summary repeats it, so "No violations found" over zero pairs reads as nothing to compare, not as consistency. structuredContent.violations[] is the blocking correctness lane: graph, schema, contradiction, query-plan, and staged enforcement failures live there and continue to drive count and failure status. structuredContent.qualityDiagnostics[] is the additive audit-quality lane for non-blocking modeling, coverage-depth, symbol fanout, duplicate-coordinate, broad-requirement, status, strict-fact, and telemetry-acceptance review signals.
Rule filtering affects the audit-quality lane. When rules is omitted, MCP runs the normal full validation profile and also performs the full-KB audit-quality scan that populates qualityDiagnostics[]. When rules is supplied, MCP preserves the requested scoped validation and skips that full-KB advisory scan so iteration stays fast and predictable. Source impact diagnostics are independent: pass includeImpactDiagnostics: true with sourceFiles or staged: true when you need changed-file review during a filtered check. When sourceFiles is supplied, qualityDiagnostics[] lists only the advisory findings that concern those files (findings on the files, on their symbols, or on the entities those symbols link to); the KB-wide rest is reduced to one scoped_check_omitted_quality info diagnostic with per-rule counts. Run kb_check without sourceFiles for the full audit.
When diagnostic mode has produced .kb/usage.log, the unfiltered scan evaluates kibi.telemetry-acceptance.v1 over its latest 200 events. It ranks advisor/preflight bypasses, edits of requirement-linked files that no lookup preceded (from host hook rows), source lookup misses, stalled proof-gap recovery, receipt gaps, and repeated mutation failures as category: telemetry recommendations. Diagnostic callers may supply opaque session_id and actor_id metadata; when both evidence records expose an identifier, advisor/preflight correlation requires equality and never borrows evidence across an explicit boundary. Stale or incomplete evidence stays insufficient_evidence; absence of observable fields is never interpreted as a pass. A missing log is skipped because MCP diagnostic logging is opt-in. Use the CLI-only kibi usage-metrics --format json --require-acceptance route when a hard completion gate is required, and kibi usage-remediation --format json for exact read-only repair evidence.
Quality diagnostics use explicit severity and blocking fields. severity: "review" and severity: "info" are advisory and do not fail checks by default; severity: "warning" is still non-blocking unless blocking: true; severity: "error" or blocking: true is a hard failure signal. Existing hard violations remain in violations[] rather than being downgraded into the advisory lane.
When impact diagnostics are enabled, structuredContent also includes impactDiagnostics, sourceFiles, extractedSymbols, linkedEntities, and nextActions. Each impact diagnostic is returned once: it is in impactDiagnostics and not repeated in qualityDiagnostics, the migrationPlan review action for it carries evidence.diagnostic as { id, entityId, listedIn: "impactDiagnostics" }, and the text content writes a suggestion that several diagnostics share once, above their messages. Impact diagnostics follow the same blocking convention: advisory unless their severity is error or blocking is true. symbol_granularity_violation means a changed behavioral symbol has only coarse ownership when a narrower anchor is available and remains blocking. symbol_semantic_review_needed can fire even when graph coverage already exists; it tells the agent to inspect whether linked requirements, scenarios, and tests actually cover the changed behavior or UI copy. On a changed behavioral symbol in a file that no manifest symbol links to a requirement, the same warning says no recorded intent covers it and asks the agent to link it to an existing requirement or record a new requirement with a scenario, unless the change leaves behavior unchanged; recording it is part of finishing the change. source_file_unowned (info) fires for each file named in sourceFiles that no manifest symbol links to a requirement, including files Kibi does not extract symbols from (HTML templates): it says that no link does not mean no rule and lists in evidence.candidates the current requirements whose titles share the file's path words (layout words such as src, app and pages and file extensions are ignored), or a kb_search call when none does. The match is lexical; candidates are to confirm with kb_query, not owners. Kibi reports the linked entities and suggested MCP calls, but it does not prove prose semantics.
Kibi's rules compare links, coverage and facts, never code with a requirement's prose, so a change that contradicts a requirement can pass them all. For every current requirement a changed behavioral symbol implements (by manifest implements link), an impact-enabled kb_check emits requirement_statement_unverified (warning, not blocking): it names the changed symbols, quotes the requirement's semantic_text and gives its firmness, and the text summary then opens with "No structural violations found" and the requirement ids instead of "No violations found". A requirement whose own document changed in the same change is left to the firmness and supersede checks; closed, superseded and deprecated requirements are skipped. If the changed code no longer does what a quoted requirement says, the request conflicts with a recorded rule: ask the person before keeping the change.
The structured check response also includes migrationPlan. Treat its actions
as typed evidence, not prose suggestions; apply only ready automatic actions
with an explicit hash/action approval through kb_apply_plan.
Example:
{
"sourceFiles": ["src/app/pages/upload/upload-page.component.ts"],
"includeImpactDiagnostics": true,
"includeWorkingTreeDiff": true
}kb_job_status
Registered only when KIBI_MCP_OPTIONAL_TOOLS names it (or is all).
Poll a background job started by a long-running operation called with
async: true (kb_check and kb_apply_plan). This tool is MCP-server-native: jobs
live in the server process, so there is no CLI counterpart and no persistence
across restarts.
Parameters:
jobId(required): ThejobIdfrom thekibi.job.v1receipt returned by the async call.
Returns:
A kibi.job.v1 object: status is running, succeeded (full result
envelope under result), failed (error message under error), or
unknown (no such job in this server process).
Example:
{ "kb_check": { "async": true } }
{ "kb_job_status": { "jobId": "job-kb_check-1-9f2a" } }
{ "kb_apply_plan": { "plan": { "...": "..." }, "approvedPlanHash": "<64 hex>", "async": true } }
{ "kb_job_status": { "jobId": "job-kb_apply_plan-2-4c1d" } }Diagnostic usage log (opt-in)
This local log is separate from the anonymous usage statistics described in
Usage telemetry, and is never sent. Kibi writes no diagnostic
log by default. Installing a host plugin, enabling it, or running the MCP
server never turns logging on. Until an operator opts in,
.kb/usage.log is not created and no row is written.
Opt in per workspace with either signal:
--diagnostic-modeon the MCP command line, when you own that command line.KIBI_DIAGNOSTIC_MODE=1in the server environment, for hosts where a plugin owns the command line. Set it in the host's MCP serverenvblock.
KIBI_DIAGNOSTIC_MODE is shared by every surface: the MCP server, the CLI JSON
routes (kibi <route> --input), and the Claude Code plugin hooks all honor it,
so exporting it once in the environment your agent host inherits covers all of
them. The older CLI-only KIBI_CLI_DIAGNOSTIC_MODE=1 still works.
Opting out is removing the signal; no other state persists.
While opted in, every row carries interface, host, package_version, and
workspace_root so rows stay attributable across worktrees, hosts, and Kibi
versions. Host plugins set KIBI_MCP_HOST for attribution only; it is not an
opt-in signal and never enables logging on its own. The same value decides
whether the discovery tools repeat their data JSON in the text part:
claude-code (or a client that calls itself claude-code on initialize) gets
the text summary alone because the host shows structuredContent, and every
other host keeps the JSON copy. KIBI_MCP_STRUCTURED_TEXT=omit or embed
overrides that for any host. CLI rows take host from
KIBI_HOST (or KIBI_MCP_HOST) and recognize Claude Code shells; otherwise
they record unknown. Rows record business arguments and agent-supplied
telemetry metadata, and the log stays local to the workspace under
.kb/usage.log.
The host plugin hooks (Claude Code, Cursor, Codex, ZCode, and OpenCode) add
rows with interface: "hook" under the same opt-in. They record the agent
activity around Kibi calls rather than Kibi operations, and every row names its
host and the host session_id, so one session's lookups and edits can be put
in order. All hosts write two kinds of row:
hook_action: "kb_usage"when a tool call ran a Kibi operation, through MCP or akibi <route>shell command, with the canonical name inkb_operation(kb_search,kb_query, …);hook_action: "edited"for each source, test, or.kb/file an edit tool changed (path,path_kind), with the requirements the file's symbols implement inrequirement_ids. Docs, config, and generated paths are not recorded.
The Claude Code plugin also records whether a requirement snippet was shown or
suppressed and whether the session had used Kibi yet (kb_used_before).
Hook rows never enter the bounded window of operation events, so a busy
editing session never pushes operations out of it. The only metric that reads
them is lookup_before_first_edit: per host session, did a kb_search or
kb_query run before the first edit of a file with non-empty
requirement_ids? It is not_applicable when no hook recorded such an edit.
Counts are only recorded when they can be read. A call whose payload cannot be
parsed records result_count: null rather than zero, and acceptance metrics
treat unreadable counts as insufficient evidence instead of a pass.
Discoverability
- MCP clients discover available tools through
tools/list. - MCP clients discover available prompts through
prompts/listandprompts/get. - Allowed static values are encoded directly in each tool's
inputSchemaenums. - There are no separate runtime listing tools for entity or relationship types.
Public Prompts
/kibi-bootstrap
Interactive onboarding workflow for day-0 KB activation. It guides agents to interview the human about knowledge sources outside the code, call kb_plan_bootstrap with the declared sources and cited intent claims, ask at most four further bounded questions when requested by the planner, present the complete hash-bound plan for approval, call kb_apply_plan once, and finish with kb_check/kb_status.
Branch Behavior
- The server attaches to the exact active Git branch name, or
KIBI_BRANCHwhen set. Git-valid slash, Unicode,@, and#names are preserved verbatim. - The compiled store lives at
.kb/branches/<sha256(exact-branch)>/and is verified by a versionedbranch.json. A missing store is compiled from the current checkout's tracked sources; Kibi never copies another branch store. - Git remains the merge and conflict authority. Unresolved authored-file conflicts block compilation; Kibi does not select merge winners.
- Branch KBs are revalidated and updated automatically on branch change—no server restart is required for normal branch operations.
- You can override the branch selection by setting
KIBI_BRANCHbefore starting the server; the value is validated without normalization. - Branch garbage collection is not part of the public MCP interface. Use
kibi gcor automation hooks; deleted stores are quarantined before any explicit purge.
KB Auto-Refresh
For same-branch workflows, MCP validates the attached branch KB against filesystem stat metadata before attach-sensitive operations. When MCP detects a KB replacement for the same branch, it triggers a controlled re-attach flow.
- The session stores an
attachedBranchStampat attachment time. - MCP recomputes the latest branch stamp with
readBranchKbStampand compares it withsameBranchKbStamp. - If stale, MCP runs a full
refreshAttachedBranchKbattempt. - For transient refresh failures, MCP retries through
refreshAttachedBranchKbWithRetry. - If recovery fails, MCP returns a
KbRefreshErrorand the operation fails closed.
This behavior is important after external branch operations such as kibi sync --rebuild, where the branch KB snapshot can be replaced while the MCP process stays running.
Workspace Routing
Hosts start an MCP server once per project and then let the agent work elsewhere, most often in a git worktree. A server that stayed attached to the checkout it started in would answer from another branch, and nothing in the result would say so. Every Kibi tool call is therefore answered from the workspace the caller is working in, decided per call:
- An explicit
workspaceRootargument (every tool accepts it): the absolute path of the directory the call is about. Host plugins with pre-tool hooks (Claude Code, Codex, Cursor, ZCode) fill it in from the agent's current directory; any agent in any harness can pass its working directory. - Otherwise the client's MCP roots, when the client declares the
rootscapability: the first root that lies in a Kibi workspace. Roots are cached while the client reportsnotifications/roots/list_changedand asked for per call otherwise. - Otherwise the workspace the server is attached to.
A different workspace is served by a child kibi-mcp started there: the
workspace's own project-local install when it has one, so the child matches
that branch's code, else this server's entry. Children are pooled (at most
four), reused across calls, and retired after ten idle minutes; the first call
into a workspace pays its start (one to two seconds) and, for a branch store
that was never compiled, the compile that any attach pays. An async kb_check
started in a child is polled by kb_job_status in the same child. A routed call
is logged, in diagnostic mode, by the child in that workspace's .kb/usage.log.
Routing is limited to worktrees of the attached repository (same git common
directory), directories under the client's declared roots, and the
KIBI_MCP_ROUTABLE_ROOTS allowlist (path-delimited). Anything else, a directory
no Kibi workspace owns, or a child that fails to start is answered from the
attached workspace with a workspace_mismatch diagnostic:
{
"code": "workspace_mismatch",
"severity": "warning",
"message": "Answered from /repo, not from the requested workspace /other: ...",
"detail": {
"requested": "/other",
"resolved": "/other",
"answeredFrom": "/repo",
"reason": "not_routable"
}
}reason is one of pinned, not_a_kibi_workspace, not_routable, or
unavailable. A successful route adds nothing to the result; the tool list is
always the attached server's.
KIBI_WORKSPACE (or KIBI_PROJECT_ROOT, KIBI_ROOT) pins the server to one
workspace and disables routing; KIBI_MCP_ROUTING=0 disables it without
pinning. Host plugin launchers set KIBI_MCP_ATTACH_ROOT to the session's
workspace and start the server there; unlike the pinning variables it leaves
routing enabled. Routed children run with KIBI_MCP_ROUTED=1 and never route further.
For kb_check, a workspaceRoot that no Kibi workspace owns keeps its older
meaning: the tree to inspect for impact diagnostics. The CLI JSON routes do not
take workspaceRoot; they run in the current directory, which makes them the
fallback when a result reports a mismatch.
KB Dependencies
A project can read the knowledge bases of other repositories it depends on,
such as a library it calls or the other services that share a user journey,
without mixing them into its own KB. The read tools kb_search, kb_query,
kb_status, kb_find_gaps, kb_coverage and kb_graph accept a kb
argument: the name of a dependency declared in .kb/dependencies.json and
pinned in .kb/dependencies.lock.json (see
kibi deps).
{ "query": "how are refunds approved", "kb": "billing-service" }The call is answered by that repository's own KB at the pinned commit:
- The pinned commit is fetched once into a shared cache
(
$KIBI_DEPENDENCY_CACHE, else$XDG_CACHE_HOME/kibi/dependencies, else~/.cache/kibi/dependencies) as a detached checkout, and compiled into that checkout's own read-only snapshot store on first read. - A child
kibi-mcpstarted in the checkout (this server's own entry, withKIBI_KB_DEPENDENCY=<name>@<commit>) answers it, pooled and retired like the children of Workspace Routing. This server's engine, branch store and sync never see the dependency, so its size never slows this project's KB. - The result carries a
detached_head_read_onlydiagnostic naming the dependency and its store. - A dependency is never written. Tools without a
kbinput (kb_upsert,kb_delete,kb_apply_planand the other writes) refuse a call that names one with "<tool>does not take a kb scope: KB dependency '<name>' is read-only", instead of droppingkband acting on this project's KB. - With
workspaceRoot, the dependencies of that workspace are used. KIBI_WORKSPACEandKIBI_MCP_ROUTING=0do not block a dependency read: the caller asked for it by name.
Dependencies must carry KB schema 6 or newer, and no newer than this Kibi
reads. The answer is only as complete as the dependency's committed KB at the
pinned commit: Kibi reads its .kb/ sources as they are, so a release made
before that repository wrote any requirements answers with nothing. An unknown,
unpinned or stale dependency fails the call with its code
(DEPENDENCY_UNKNOWN, DEPENDENCY_NOT_LOCKED, DEPENDENCY_LOCK_STALE, and
the others in the
error reference) instead
of answering from this project's KB. The CLI read commands take the same scope
as --kb <name>, and their JSON routes accept kb in the input.
Recommended Agent Workflow
- Interactive Bootstrap: Start with the
/kibi-bootstrapworkflow, inspect typed status, and letkb_plan_bootstrapreturn any bounded context questions. Always preview candidates for user approval before applying. - Gather Context: Use
kb_searchfor discovery (ask it a direct question or decompose broad tasks into focused probes; readdata.answerfor the governing requirements) andkb_queryfor exact follow-up. - Inspect Freshness: Use
kb_statuswhen branch or stale-state confidence matters. - Analyze: Use
kb_find_gaps,kb_coverage, andkb_graphfor curated reporting. - Check Source Impact: After meaningful source edits, run
kb_checkwithsourceFiles,includeImpactDiagnostics: true, andincludeWorkingTreeDiff: truebefore deciding whether requirements/tests/symbol links need updates. - Execute Changes: Model prose with
kb_model, preflight withkb_upsertanddryRun: true, then usekb_upsertto create/update entities and relationships. - Validate: Run
kb_checkafter structural changes. Use explicitrulesduring iteration for scoped validation; run an unfilteredkb_checkbefore completion to include the full-KBqualityDiagnostics[]audit scan. - Clean Up: Use
kb_deleteonly for intentional removals after validating dependencies.
Modeling note: Use flag for runtime/config gates. Bug and workaround notes belong in fact entities, usually with fact_kind: observation or meta. Strict facts drive contradiction checks; observation/meta are non-blocking notes.
Error Handling
The MCP server returns structured errors for:
- Invalid parameters (missing required fields, invalid enum values)
- Referential integrity violations (attempting to delete entities with dependents)
- Branch KB startup/attach failures
- Validation failures
Always check error responses before proceeding with more mutations. For common validation failures and recovery payloads, see docs/error-reference.md. In particular, strict fact writes must use subject_key, property_key, value_type, and exactly one typed value_* field; do not use subjectKey, propertyKey, or generic value in kb_upsert.properties.
Determinism Guarantees
- Query results are sorted and de-duplicated for consistency
- MCP responses use explicit field names and fixed shapes
- Validation output is stable across repeated runs on unchanged KB state