Skip to main content
Glama
littlebigbrains

@littlebigbrain/mcp

@littlebigbrain/mcp

Model Context Protocol (MCP) server for little big brain, a search platform for AI applications such as chatbots, search tools, and agents.

Connect an MCP client to search your data, follow relationships, and read the facts behind an answer. The tools also let you load data and define validation rules.

Documentation · Quickstart · Issues

Connect

Create a stack in the console, then choose a hosted connection or a local process.

Hosted connection

For clients that support remote MCP with OAuth, use this URL and sign in with your little big brain account. Replace <stack-slug> with your stack's slug:

https://mcp.littlebigbrain.com/mcp/<stack-slug>

For clients that use an mcpServers JSON configuration:

{
  "mcpServers": {
    "lbb": {
      "url": "https://mcp.littlebigbrain.com/mcp/<stack-slug>"
    }
  }
}

This connection uses account sign-in and does not require a stack API key. The connection guide includes client-specific setup, including the origin URL and X-LBB-Stack header for Codex.

Local process

Requires Node.js 18+. Copy the complete endpoint and a stack API key from Connect in the console, then add them to your client's MCP configuration:

{
  "mcpServers": {
    "lbb": {
      "command": "npx",
      "args": ["-y", "@littlebigbrain/mcp"],
      "env": {
        "LBB_BASE_URL": "https://<your-complete-stack-host>",
        "LBB_API_KEY": "<your-stack-api-key>"
      }
    }
  }
}

The client starts the server and communicates through standard input and output (stdio). Keep the key in your local configuration. Set LBB_GRAPH to change the default graph from main.

Related MCP server: RDF4J MCP Server

Run a first query

This example stores three facts in a graph named quickstart: a service writes to a database, and each has a label. The graph is created on its first write.

Ask your client to call lbb_rdf with these arguments:

{
  "action": "import",
  "graph": "quickstart",
  "format": "ntriples",
  "source": "<https://example.org/auth-service> <https://example.org/writesTo> <https://example.org/user-db> .\n<https://example.org/auth-service> <http://www.w3.org/2000/01/rdf-schema#label> \"Auth Service\" .\n<https://example.org/user-db> <http://www.w3.org/2000/01/rdf-schema#label> \"User Database\" .",
  "idempotency_key": "mcp-quickstart-v1"
}

Now ask which database does Auth Service write to? The lbb_query call is:

{
  "mode": "sparql",
  "graph": "quickstart",
  "consistency": "strong",
  "query": "SELECT ?database WHERE { <https://example.org/auth-service> <https://example.org/writesTo> ?db . ?db <http://www.w3.org/2000/01/rdf-schema#label> ?database } ORDER BY ?database LIMIT 10"
}

The result contains one row on a fresh graph:

database

User Database

The query follows a stored relationship to its database label. Strong consistency lets it read the import without waiting for a background index job.

An agent without a SPARQL query can pass the question in plain words:

{
  "mode": "question",
  "graph": "quickstart",
  "question": "Which database does Auth Service write to?"
}

The server answers in plain words (POST /v1/query/ask). A router model picks the kind of question. A reasoning model runs queries in a bounded loop, reads their rows, and answers. The result holds answer (text, citations, the IRIs the answer names, and chart, how to draw the rows, when the server gave one), steps, the route, and the query and rows the answer stands on. next continues that query with mode: "sparql". A question takes about 8 s. Each question uses model tokens and counts toward a daily limit of the stack, so the tool does not retry a failed call.

The server finds the names in the question in the graph and lists them in linked. When the question is about records you already know, pass their IRIs in anchor (at most 10): the queries use them directly. A question about a date reads the last commit written by the end of that day; pass timeline ([{date, as_of_commit_seq, label?}]) when the commits stand for other dates. A question that asks what changed returns history.added, history.removed and history.changed, with history.totals.

When the tool call carries a _meta.progressToken, the server sends a progress notification for each step, for example Route: lookup (router, 0.92) or Step 2, sparql SELECT ?db: 1 row. The result is the same. Cancel the call to stop the server's work.

To write the queries yourself, use names, describe, commit_at and compare, then mode: "sparql".

For your own data, start with lbb_inspect using action: "guide" or action: "ontology". Imported Resource Description Framework (RDF) data keeps its original identifiers; inspect it with SPARQL when choosing query predicates.

Tools

Tool

Purpose

lbb_inspect

Read the schema, graph status, and entities.

lbb_query

Ask a question in plain words, run SPARQL queries, search by meaning (also inside a SPARQL query with search:similarTo), or request summary statistics. Four modes help an agent write its own queries: names (the IRIs of the names in a text), describe (the classes and properties a question needs, with how many instances hold each property and the values of small classes), commit_at (the commit of a date) and compare (one query at two points, the rows paired by entity).

lbb_rdf

Import RDF documents or add facts with SPARQL INSERT DATA.

lbb_embeddings

Inspect search setup and preview the text to embed.

lbb_embeddings_manage

Set up or refresh embeddings, or change the embedding model.

lbb_embeddings_delete

Delete an embedding and its stored vectors.

lbb_fit_sources

Inspect fit from text and preview the text the fit reads.

lbb_fit_sources_manage

Declare, dry-run or refresh a fit source.

lbb_fit_sources_delete

Delete a fit source; its suggestions stay.

lbb_workflows

List the starter workflows this server offers and the workflows created from them on a graph (triggered workflows), read one with its status, and preview a new one. Read the workflows with triggers (target type, shards, routing, window, trigger) and what each watch has not sent yet, with origins.

lbb_workflows_manage

Create a workflow from a starter workflow on a class (a developer workflow with its workflow type, owned outputs and batch), ask it to run now, or pause and resume a developer workflow. Define a workflow with triggers of your worker (shards, routing field, window) and run it now.

lbb_workflows_delete

Delete a triggered workflow, or a workflow with triggers by its name. What it wrote stays.

lbb_files

List the files of a graph, and read the parsed pages of one: each line with its id, its box on the page and its text.

lbb_commit

Write or retract JSON facts, or record search feedback.

lbb_configure

Define record types and relationships, list and apply ontology starters (CRM, documents, work), publish validation rules, or keep the graph's notes and worked examples for questions in plain words (get_rewrite_profile, set_rewrite_profile).

lbb_evals

Label query results and check whether later queries return the expected answers. Read the model checks of a graph, and agree with or correct a check that the user confirmed.

lbb_model_choice

Read which model each use runs (question answers, query routing, search rerank, ontology fit, eval labels), and the trials that test other models against the graph's ground truth.

lbb_model_choice_manage

Start or stop a trial, switch a use to a tested model that meets the bar, or revert to LBB's model.

lbb_models

Compare retrieval settings, read model training datasets, or read a month of managed-model activity.

See search by meaning for embedding setup. To define constraints with the Shapes Constraint Language (SHACL), see query and validation.

RDF imports and JSON facts use different write workflows. A graph first written through lbb_rdf does not accept JSON fact writes through lbb_commit. Choose the workflow when creating the graph. RDF updates support additive INSERT DATA; see the RDF guide for format and update limits.

Pages and saved queries

When a result includes next, pass those arguments to the same tool to read the next page. Continue until next is absent. row_limit sets a maximum; large values can make a page shorter.

SPARQL queries keep the same commit across pages. Save the query and its returned commit sequence to check an answer later, then use as_of_commit_seq to select that version. See history and replay for retention and evidence handling.

Embed the server

To serve the tools from your own Node.js process:

import { createMcpHttpServer } from "@littlebigbrain/mcp";

createMcpHttpServer({
  baseUrl: process.env.LBB_BASE_URL!,
  mcpPath: "/mcp",
  allowedHosts: ["127.0.0.1", "localhost", "::1"],
}).listen(8080, "127.0.0.1");

Clients connect to http://127.0.0.1:8080/mcp and send a stack API key in Authorization: Bearer <key>. See the Node.js integration guide for HTTP options and integration with an existing MCP server.

Development

From a clone of this repository:

npm ci
npm run build
npm run typecheck
npm test

License

Apache-2.0.

Available Tools

19 tools
lbb_commitA
Idempotent

Write graph facts, retract them, or label ranked results. mode=facts writes triplets/embeddings/properties; mode=retract removes a wrongly-added fact (by edge or by entity) without a full reset; mode=search_feedback stores query/result relevance labels (Feedback grades: 3=ideal/good, 1=partial, 0=bad; include query, search_id when available, target, rank, score). Explicit idempotency_key wins; when omitted, MCP derives a stable content hash so content-identical retries dedupe. Facts mode defaults edge_idempotency to append; pass skip_unchanged for re-runnable backfills.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNo
graphNoGraph to target; defaults to the connection's graph
dry_runNoValidate a facts commit and return its structured SHACL report without writing. Only supported for mode=facts.
tripletsNo
observed_atNoBackfill timestamp (RFC3339). Records this commit AS OF that instant: stamps transaction time and defaults each triplet's valid_time.start. Replay history in order with observed_at per commit so as-of reads by date work. Omit for live writes.
retract_edgesNomode=retract: specific edges to remove, matched by (source, relation, target).
idempotency_keyNo
search_feedbackNo
edge_idempotencyNoDefaults to append in MCP. Use skip_unchanged for backfills; it skips exact current-edge duplicates and drops evidence-only repeats.
retract_entitiesNomode=retract: entities whose every current edge is removed (a current-state tombstone; the record and its history are kept for as_of reads).
entity_embeddingsNo
entity_propertiesNoTyped scalar attributes per entity. Each item is { type, name, properties }. `properties` is a flat map of field -> value, e.g. { "type": "PERSON", "name": "Ada Lovelace", "properties": { "h_index": 52, "title": "VP", "last_contact": "2026-06-26" } }. Values are coerced to each field's declared type, so a string like "2026-06-26" lands in a date_time field and "52" in an i64 field. (The verbose form [{ field, value: { i64: 52 } }] is also accepted.) Register a field first with lbb_configure evolve_ontology add_property; the commit response echoes written_properties so you can confirm what landed.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description adds valuable behavior: explicit idempotency_key wins, omitted keys derive a stable content hash for dedupe, facts mode defaults to append, and retract supports both edge and entity removal. It does not spell out every side effect in the top-level text, but the schema covers tombstone/history preservation for retract_entities.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but economical: five sentences front-load the mode enum, then cover idempotency, feedback grading, and backfill defaults without repetition or filler. Every clause adds operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 12-parameter tool with no output schema, the description covers mode semantics, idempotency, dry_run, backfill timestamps, and feedback labels well. However, mode itself is not required in the schema and the description never states what happens when mode is omitted, nor what the commit returns. Those gaps matter for an agent deciding whether and how to invoke the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description meaningfully explains the mode enum, idempotency semantics, edge_idempotency behavior, and even the feedback grading scale. Combined with schema descriptions for dry_run, observed_at, retract_edges, and entity_properties, most parameters are actionable. Some params like triplets and entity_embeddings rely on mode prose rather than dedicated descriptions, but the context is sufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Write graph facts, retract them, or label ranked results.' It then enumerates three distinct modes with concrete behaviors, making the tool immediately distinguishable from read/schema siblings like lbb_query and lbb_configure.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly says when each mode is appropriate: retract is for removing wrongly-added facts without a full reset, search_feedback is for storing relevance labels, and skip_unchanged is for re-runnable backfills. It also indirectly points to lbb_configure for registering fields. It stops short of a fully explicit when-not-to-use or comparison with every sibling, so it is not a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_configureA

Manage native schema metadata. Actions: define_ontology (friendly spec with super_types), evolve_ontology (ordered edits including add_super_types), list_starters (the base ontologies crm, documents and work, each with its status on the graph: absent, partial or applied, what applying adds, and conflicts), apply_starter (add what the graph lacks of a starter in one ontology version; a relation the graph has is widened; refused with starter_conflict when the graph holds a term differently; dry_run previews), publish_schema (SHACL activation), suggest_ontology_change (file a change for a person to review instead of applying it; prefer it when the graph's owner reviews ontology changes, and list the result with lbb_inspect action=ontology_suggestions; facts files graph facts for review, which accepting commits after the change, and change may be empty when facts is set), get_rewrite_profile and set_rewrite_profile (the graph's notes and up to 20 worked question-to-SPARQL examples that lbb_query mode=question reads for every question; pass the version you read as expected_version). define, evolve, publish and set_rewrite_profile support dry_run previews. Definition/import here extracts native metadata; it does NOT store the complete RDF/OWL document as queryable graph facts. Use lbb_rdf import for full OWL and lbb_rdf update for additive INSERT DATA revisions; RDF deletions are unsupported. Publish_schema accepts unchanged ontology plus shapes; use define/evolve for native ontology changes. Publication enqueues durable conformance; a preview does not validate the whole graph.

ParametersJSON Schema
NameRequiredDescriptionDefault
keyNoIdempotency key ([A-Za-z0-9-_.:/]); filing again with the same key revises the suggestion
opsNoOntology changes to apply in order (additive, in-place edits, or subtractive)
agentNoYour name as the producer, shown to reviewers
factsNoGraph facts a person confirms: accepting commits them after the change (at most 200 triplets and property rows together). Records graphs only
graphNoGraph to create or redefine
notesNoWhat the data means for questions: which property holds the current state, what 'me' or 'my' means, which records to leave out. At most 8,000 characters
titleNoShort imperative text, e.g. 'Add class Contractor'
actionYesSelects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change, get_rewrite_profile, set_rewrite_profile).
anchorNoThe class, property or relation the change is about
changeNoThe ontology operations a person applies by accepting, in order (same shapes as evolve_ontology ops). Up to 128; may be empty or absent when facts is set
formatNo
shapesNo
sourceNo
dry_runNoPreview the exact definition without creating a graph or writing metadata.
starterNoStarter id: crm, documents or work (list_starters names them)
evidenceNoWhat you saw: record count, fields, up to 20 sample records
examplesNoUp to 20 worked examples: a question and the query that answers it on this graph
ontologyNo
rationaleNoWhy the ontology needs the change; cite what you saw
relationsNo
desired_modeNo
entity_typesNo
merge_defaultNo
expected_versionNoThe version get_rewrite_profile returned (0 for none): another stored version answers 409 conflict and stores nothing
confirm_restrictiveNo
allow_data_conflictsNoDeprecated compatibility flag; does not bypass conflicts. Preview subtractive changes with dry_run=true, repair the reported conflicts, then apply.
expected_ontology_versionNoRefuse when the graph's ontology version differs

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (readOnlyHint=false, openWorldHint=false, destructiveHint=false): conflict refusal ('refused with starter_conflict when the graph holds a term differently'), dry_run behavior per action, the 409 version-conflict outcome for expected_version, idempotent key semantics, and 'Publication enqueues durable conformance; a preview does not validate the whole graph'. It also flags the critical boundary that native import 'does NOT store the complete RDF/OWL document as queryable graph facts'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loading is good ('Manage native schema metadata. Actions: ...'), but the body is one very long, unbroken sentence listing eight actions with parenthetical asides, which hurts scanability. Most content earns its place, yet the structure could be far clearer for a multi-action tool of this size.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given eight actions, 27 params, 67% schema coverage and no output schema, the description covers the important decision points and cross-tool boundaries well. Some variant-specific parameter details (e.g. confirm_restrictive, allow_data_conflicts, desired_mode) are left to the schema, so it is not entirely exhaustive, but it is complete enough to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% across 27 params, and the description adds real meaning beyond it: it explains the action variants the params serve, the dry_run preview scope, expected_version's conflict behavior, and that facts may accompany an empty change. It doesn't exhaustively explain every nested op/field, but it goes beyond the schema in the areas that matter for correct invocation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Manage native schema metadata') and then enumerates all eight action variants with concrete verbs and objects (define_ontology, apply_starter, publish_schema, suggest_ontology_change, get/set_rewrite_profile). It actively differentiates from siblings, e.g. 'Use lbb_rdf import for full OWL' and 'list the result with lbb_inspect action=ontology_suggestions'. An agent can select the right action without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing rules throughout: 'Use lbb_rdf import for full OWL and lbb_rdf update for additive INSERT DATA revisions', 'prefer it when the graph's owner reviews ontology changes', and 'Publish_schema accepts unchanged ontology plus shapes; use define/evolve for native ontology changes'. It also names the alternatives (lbb_rdf, lbb_inspect, lbb_query, lbb_commit) and the conditions that select them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_embeddingsA
Read-only

Search setup, read only: embeddings declared on classes (an embedding on a class covers its subclasses; one model per graph). list shows each embedding's status (serving and building version, backfill progress, lag) and the graph's model; get shows one; preview shows every candidate fact of a class with its coverage and examples, and the exact text of sample instances, and stores nothing. Declare, refresh, or change the model with lbb_embeddings_manage; search with lbb_query mode=search. list is the first step of planning a search (lbb_inspect action=guide has the recipe).

ParametersJSON Schema
NameRequiredDescriptionDefault
dimNo
fromNopreview/declare: the fields, e.g. ["label", "description", "calls/label"]. Omit for the automatic choice; on an existing embedding, omit to keep its fields.
irisNopreview: the instances to show instead of a sample.
nameNoget: the embedding name.
classNopreview/declare: the class IRI.
graphNoGraph to target; defaults to the connection's graph
modelNomodel: the graph's new model. preview/declare: omit it; a graph has one model (the graph's, or the platform's default for the first embedding).
titleNopreview/declare: the field that names each hit, e.g. "display_name". Omit for the ontology's name property (skos:prefLabel, a property declared rdfs:subPropertyOf rdfs:label, else rdfs:label); on an existing embedding, omit to keep its name. preview reports title_source and, when the labels read as keys, title_suggestion.
actionYes
detailNoResponse detail level. Defaults to compact.
sampleNo
excludeNopreview/declare: fields to drop from the automatic choice.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, but the description adds valuable context: preview 'stores nothing', embeddings on a class cover subclasses, and one model per graph. It also explains the status fields shown by list and the exact behavior of preview. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a dense single paragraph, front-loaded with 'Search setup, read only'. It packs key facts (coverage semantics, action outputs, alternative tools) without excessive verbosity, though it could be broken into shorter sentences for easier scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 12 parameters and no output schema, the description covers the main actions and clarifies core semantics, but omits details on dim, sample, detail, and exclude. It also does not describe return formats, leaving some agent decisions to inference. Adequate but not fully comprehensive.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75% (missing descriptions for dim, sample, and action). The description explains the action parameter implicitly through list/get/preview and references class/name, but it does not clarify dim or sample. It partially compensates for the schema gap but leaves two parameters ambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Search setup, read only' for embeddings, and differentiates the three actions (list, get, preview) with distinct behaviors. It also names sibling tools (lbb_embeddings_manage, lbb_query) to avoid ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use this tool: 'list is the first step of planning a search' and provides the recipe location (lbb_inspect action=guide). It also directs mutation tasks to lbb_embeddings_manage and search to lbb_query, making the usage boundary clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_embeddings_deleteA
DestructiveIdempotent

Delete an embedding: its name and its vectors (index-gc removes the stored runs). Its class stops being searchable until it is declared and built again. Ask the user first; confirm must repeat the name.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesThe embedding name.
graphNoGraph to target; defaults to the connection's graph
detailNoResponse detail level. Defaults to compact.
confirmYesThe same name again, to confirm.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark destructiveHint=true and idempotentHint=true, but the description adds valuable context: index-gc removes stored runs and the embedding class becomes non-searchable until rebuilt. This discloses side effects beyond the annotation flags and does not contradict any annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with no wasted words. The primary action is front-loaded, and subsequent sentences add crucial details (index-gc, searchability, user confirmation) in a logical order. It is efficient yet thorough.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive operation with four parameters and no output schema, the description covers what happens (deletion, vector removal, searchability impact) and the required confirmation flow. It gives an agent everything needed to invoke it correctly and understand the consequences, making it complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with detailed parameter descriptions, so the schema already explains each parameter. The description adds context about the confirm requirement and its effect, but those are already present in the schema's description for 'confirm'. It does not introduce new parameter-level semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (delete an embedding) and its effects (removes name and vectors, stops searchability). It goes beyond a simple verb+resource by explaining the consequence that the class must be redeclared and rebuilt, making the purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit guidance on usage: ask the user first and require confirmation via repeating the name. It does not compare directly with sibling tools like lbb_embeddings_manage, but the unique destructive nature and safety instructions provide clear context for when it should be used.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_embeddings_manageA

Declare or refresh an embedding, or change the graph's model. Run lbb_embeddings action=preview first and show the user the text it will embed. declare sets the class, the fields (one-hop property paths such as label, description, calls/label; omit for an automatic choice); a new embedding takes the graph's model, and another model is refused. On an existing embedding it changes only what you name, and a changed recipe builds a new version while the old one serves. model moves every embedding of the graph to model: each builds a new version, and the graph switches when all are ready (a search never mixes two models). refresh runs one step of the embed job now (it also runs by itself after each published commit).

ParametersJSON Schema
NameRequiredDescriptionDefault
dimNo
fromNopreview/declare: the fields, e.g. ["label", "description", "calls/label"]. Omit for the automatic choice; on an existing embedding, omit to keep its fields.
nameNoThe embedding name (refresh: required).
classNopreview/declare: the class IRI.
graphNoGraph to target; defaults to the connection's graph
modelNomodel: the graph's new model. preview/declare: omit it; a graph has one model (the graph's, or the platform's default for the first embedding).
titleNopreview/declare: the field that names each hit, e.g. "display_name". Omit for the ontology's name property (skos:prefLabel, a property declared rdfs:subPropertyOf rdfs:label, else rdfs:label); on an existing embedding, omit to keep its name. preview reports title_source and, when the labels read as keys, title_suggestion.
actionYes
detailNoResponse detail level. Defaults to compact.
excludeNopreview/declare: fields to drop from the automatic choice.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations only say non-read-only and non-destructive; the description adds crucial behavior: a changed recipe builds a new version while the old one serves, the graph switches only when all versions are ready so searches never mix models, and a differing model is refused. This is substantial transparency beyond the flags.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but front-loaded: overview first, then the preview prerequisite, then action-by-action behavior. Every sentence carries distinct information and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with ten parameters, three actions, and no output schema, it thoroughly covers action semantics and constraints. The main gaps are the undocumented dim parameter and the meaning of the detail response levels.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents most parameters, and the description adds extra meaning by defining from as one-hop property paths and explaining how model relates to graph-wide behavior. However, dim is undocumented in both the schema and description, so it falls short of 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names the three distinct actions with a verb and resource: declare/refresh an embedding or change the graph's model. This distinguishes it from lbb_embeddings_delete and from lbb_embeddings, which the description itself points to for preview.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit precondition: run lbb_embeddings action=preview first and show the user the text. It also explains when declare can use the graph's model, when refresh is appropriate, and that refresh also runs automatically after published commits.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_evalsA

Managed evals: ground truth for the questions an app asks and the searches it runs. A query run with request (lbb_query, also mode=question) records a trace: the question, the query that answered it, the type of that query (query_type: sparql, hybrid = search by meaning with conditions, search = search by meaning alone) and one item per result (hit or row); trace reads it back with the item ids. label has two forms. On a question's trace, valid alone judges the whole answer: valid=true makes the trace's query the golden query of the question; valid=false with sparql gives the right query, which becomes the golden query; valid=false alone marks the answer wrong; route with valid=true (or valid=false with sparql) names the route the question expects, and valid=true alone takes the trace's route. item + valid (or items) judges one result, a citation of the answer: the ground truth of the hits of a search by meaning, and a result marked wrong must not come back for any type. golden freezes a stored query or a search (every result it returns now is relevant). run checks every golden at the current commit: a question is asked again through the query rewriter, then the type of the query it wrote is compared with the expected type, its rows with the rows of the golden query at the same commit (query_check), and its results with the judged results, and the router's pick with the golden's route (route_check, which does not change the verdict); a search is done again; new results open a review trace. run_answers checks your own app's answers instead: ask each question golden's request with your own loop, then send answers=[{golden, sparql, route}] (route = the route of lbb_query mode=question with route mode, sparql absent for an unanswerable question, error for a failure); the server runs each query and checks it the same way, and the runs form the app's own series (runner; results with runner reads them). judge lets the platform's judge model (the hosted frontier model) label unlabeled results. summary, traces, goldens, results, and settings read state. Model checks: a judge model checks a sample of the model calls LBB makes for the graph (rerank, route, ask = the answer of a question, rewrite, fit, propose, label). checks_summary reads a month per job and model (checks, score, right, partly, wrong, reviews) and the judge's agreement with people; checks lists the month's checks, newest first, with the judge's verdict, score and reason and the ground truth (truth). review_check records a person's review of one check (call_id): agree=true keeps the judge's verdict; agree=false with verdict (and an optional score, reference and note) corrects it. The review becomes the call's ground truth, so show the check to the user and review only what the user confirmed.

ParametersJSON Schema
NameRequiredDescriptionDefault
byNolabel: who labels (an agent name).
jobNochecks: only the checks of one job.
itemNolabel: the result id (a hit's `id`, or an item id from trace) to label with `valid`.
noteNolabel / review_check: why. review_check: at most 2,000 characters.
afterNochecks: the next_after of the previous page.
agreeNoreview_check: true = the judge is right, false = correct it with verdict.
graphNoGraph to target; defaults to the connection's graph
itemsNolabel: several results at once.
limitNo
monthNochecks_summary / checks: the month, yyyy-mm (UTC). Defaults to the current month.
routeNolabel: with valid=true, or valid=false with sparql, the route the question expects.
scoreNoreview_check with agree=false: the right score, 0 to 1. Omit for the judge's score of that verdict.
top_kNogolden: the top_k of a search golden.
validNolabel: true = the result answers the request (thumbs up), false = it does not. Without item or items, on a question's trace: the whole answer is right (true) or wrong (false).
actionYes
detailNoResponse detail level. Defaults to compact.
runnerNorun_answers / results: your app's name, lower-case letters, digits and -, at most 40 characters (default app). results without runner reads the server's runs.
sparqlNogolden: the query to freeze (the search text for surface=search). label: with valid=false and no item, the right query for the question; the server checks and runs it once.
answersNorun_answers: one answer per question golden your app asked: golden (its id), sparql (the query whose rows hold the answer; leave it out when the question is unanswerable), entailment, as_of_commit_seq, route (as the router returned it), reply, error (your app failed), cost_micro_usd.
call_idNoreview_check: the check's `call` id, from checks.
requestNogolden: the user's words the query answers.
surfaceNogolden: which surface the query runs on (default sparql).
verdictNochecks: only the checks whose ground truth has this verdict. review_check with agree=false: the right verdict.
reviewedNochecks: true = only the checks a person reviewed, false = only the others.
trace_idNotrace / label / judge: the trace id from lbb_query.
embeddingNogolden: the embedding, for surface=search.
golden_idNoaccept / delete: the golden id.
referenceNoreview_check with agree=false: the right answer. A rerank or label check: {"grades": {"<hit id>": 0..3}}; a route or fit check: {"picks": {"<question id>": "<option>"}}.
unlabeledNotraces: only traces without a label.
consistencyNorun / run_answers / accept: strong reads the head, eventual the last published commit.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false, destructiveHint=false, openWorldHint=false and the description goes well beyond them: label makes a query the golden query, golden 'freezes' a stored query, run opens a review trace, review_check 'becomes the call's ground truth', and note is capped at 2,000 characters. It does not disclose permissions, auth, or the irreversibility of the delete action, which is a gap for a mutating tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the purpose and nearly every sentence carries information, so there is little filler. But the entire definition is a single unstructured block covering 16 actions and 30 parameters with no separators or headings, which makes scanning for one action costly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 16-action, 30-parameter tool with no output schema, the description is unusually complete: it explains every major action and even summarizes return shapes ('checks_summary reads a month per job and model ... checks lists the month's checks, newest first'). The accept and delete actions defined in the enum are never described, which is the main remaining gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 93%, so the baseline is 3, but the description adds real meaning: the two forms of label, how valid interacts with the trace, the structure of answers=[{golden, sparql, route}] and its route kinds, and the sparql semantics for golden vs label. This meaningfully complements the schema rather than restating it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening 'Managed evals: ground truth for the questions an app asks and the searches it runs' states a clear domain and the resource being managed, and the body breaks this into concrete actions (label, golden, run, run_answers, checks, review_check). An agent knows what the tool does. However, it never names or distinguishes itself from sibling tools like lbb_inspect, lbb_query, or lbb_models, so there is no sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly routes between internal alternatives: 'run checks every golden at the current commit' vs 'run_answers checks your own app's answers instead', and 'judge lets the platform's judge model ... label unlabeled results'. review_check even carries a usage constraint ('show the check to the user and review only what the user confirmed'). There are no explicit when-not conditions or cross-tool references.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_filesA
Read-only

Files of the graph, read only. A file is a document the graph holds (its bytes and a Document entity); the documents.parse workflow (lbb_workflows) reads the text layer of each PDF into pages with every line and its box. list shows the files with their sha256, name, size, Document IRI and parse (status parsed, unsupported or failed, page_count). pages reads parsed pages of one file (sha256, or name for an exact file name): from is the first 0-based page index (the page of a region and of a DocEntry or DocMention), to the page after the last one (default from+1). Each line comes as <line id> [x0,y0,x1,y1] <text>: the id is p-l, both from 1, and the box is normalized to the page (0 to 1, origin top left). contains keeps the lines that hold a text; max_lines caps the lines (default 200). When lines were left out, next names the from and line_offset of the next call. A file not parsed yet answers file_not_parsed.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNopages: the page index after the last one. Default from+1; at most 50 pages per call.
fromNopages: the first page index, 0-based. Default 0.
nameNopages: the file's exact name, when you do not have its sha256.
graphNoGraph to target; defaults to the connection's graph
actionYes
detailNoResponse detail level. Defaults to compact.
sha256Nopages: the file's SHA-256 (64 hex characters).
containsNopages: only the lines whose text holds this, ignoring case.
max_linesNopages: the most lines to return. Default 200.
line_offsetNopages: lines of the first page to skip, from a previous call's next.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true, and the description corroborates this ("read only") while adding real behavioral context: the parse-status values (parsed/unsupported/failed), the file_not_parsed error condition, and the pagination contract via next (from + line_offset). It does not describe the parsed-text return shape in full, but the error and continuation behavior are meaningfully disclosed beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It front-loads the resource definition and read-only nature before the action details, and every sentence carries information an agent needs (line-id format, box normalization, pagination). It is dense and slightly overpacked for a single paragraph, but there is little waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and 10 parameters, the description compensates by spelling out the list fields and the line output format (`<line id> [x0,y0,x1,y1] <text>` with normalized boxes) plus the file_not_parsed error. The main omissions are the meaning of the detail levels and a fuller description of the pages envelope, but the inputs and returns are otherwise adequately covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already high (90%), so the baseline is 3, but the description adds genuine semantics on top: from is the 0-based first page, to is the page after the last with default from+1, contains matches case-insensitively, max_lines defaults to 200, and next feeds back into from/line_offset. The only gap is the detail enum (compact/standard/full), which the description never explains.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource and scope ("Files of the graph, read only") and defines what a file is (bytes + a Document entity), then names the two actions, list and pages. It also positions the tool against its sibling by pointing to the documents.parse workflow in lbb_workflows, so an agent can tell what this tool owns versus what the workflow tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for each action: list enumerates files with their parse status, pages reads the parsed pages of one file, and it warns that a file not parsed yet answers file_not_parsed. It routes the agent to lbb_workflows for the parse step, but there is no explicit when-not-to-use versus siblings like lbb_query or lbb_inspect.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_fit_sourcesA
Read-only

Fit from text, read only: fit sources declared on classes. A fit source names the fields of a class that hold text (transcripts, documents); the server reads every instance, proposes ontology changes (classes, properties, relations) with verbatim quotes, checks them, and files them as ontology suggestions with origin id fit:. list shows each source's status (progress, lag, instances read, proposals kept and dropped, suggestions per status, this month's spend, last error) and the stack's monthly budget; get shows one; preview shows the fields, every candidate field of the class and the text of sample instances, calls no model and stores nothing. Declare, refresh or dry-run with lbb_fit_sources_manage; list the suggestions with lbb_inspect action=ontology_suggestions.

ParametersJSON Schema
NameRequiredDescriptionDefault
fromNopreview/declare/dry_run: the fields that hold the text, as embedding paths (transcript, label, about/label, <https://…>). Omit for the long text facts of the class.
irisNopreview: the instances to show instead of a sample.
nameNoget: the fit source name.
classNopreview/declare/dry_run: the class IRI whose instances hold the text.
graphNoGraph to target; defaults to the connection's graph
actionYes
detailNoResponse detail level. Defaults to compact.
sampleNo
contextNopreview/declare/dry_run: one sentence about the text, e.g. "interviews with employees about their work processes" (at most 500 characters).
excludeNopreview/declare/dry_run: fields to drop from the automatic choice.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only readOnlyHint=true in annotations, the description carries the behavioral load and does well: preview 'calls no model and stores nothing', and list exposes spend, budget, lag, error state and per-status suggestion counts. The pipeline sentence (reads every instance, proposes changes, files suggestions) describes fit-source processing generally and could momentarily be read as this tool's own effect, a small ambiguity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Information is front-loaded and dense, but the long opening sentences bundle background about the fit-source pipeline that is more relevant to lbb_fit_sources_manage than to a read-only viewer. The parenthetical enumerations are useful but make it run long for a list/get/preview tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description's enumeration of what list and get return (progress, lag, instances read, proposals kept/dropped, spend, budget, last error) is necessary and supplied. For a 10-parameter tool at 80% schema coverage, this is close to complete, with only minor gaps around sample/detail behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 80%, and the description still adds meaning by mapping each action to its inputs and outputs (e.g. preview takes fields/instances, get takes a name). The from/exclude/context params are only summarized implicitly, but the action-driven semantics are clarified beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description identifies the resource (fit sources declared on classes) and scopes the tool to read-only views via the list/get/preview actions, and it names the sibling that handles writes (lbb_fit_sources_manage). The opening 'Fit from text, read only' is jargon-heavy and slightly indirect about the verb, which keeps it below 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly allocates the three supported actions (list shows all, get shows one, preview shows fields/samples) and routes declare/refresh/dry-run to lbb_fit_sources_manage and suggestion inspection to lbb_inspect action=ontology_suggestions. When-to-use and where-not-to-go are fully stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_fit_sources_deleteA
DestructiveIdempotent

Delete a fit source: the fit stops reading its class. The suggestions it filed stay. Ask the user first; confirm must repeat the name.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesThe fit source name.
graphNoGraph to target; defaults to the connection's graph
detailNoResponse detail level. Defaults to compact.
confirmYesThe same name again, to confirm.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, idempotentHint=true and readOnlyHint=false, so the safety profile is covered. The description goes beyond that by disclosing the blast radius ('the suggestions it filed stay') and the required user-confirmation protocol. It stops short of describing error behavior (e.g., unknown name) or permission requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the action and its consequence, then the safety protocol. No filler; each sentence carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive mutation with annotation coverage and no output schema, the description is largely sufficient: it conveys the side effect, the data that survives, and the confirmation requirement. Only minor gaps remain (permission prerequisites, behavior on an invalid name).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters are already documented, including confirm ('The same name again, to confirm'). The description reinforces the confirm constraint but adds no new syntax or meaning beyond what the schema states, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Delete a fit source') and immediately characterizes the scope of the deletion: the fit stops reading its class, but filed suggestions persist. This lets an agent distinguish it from siblings like lbb_fit_sources and lbb_fit_sources_manage without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit procedural guidance ('Ask the user first; confirm must repeat the name'), which is exactly the when/how context needed for a destructive action. It does not, however, name an alternative path such as disabling the source via lbb_fit_sources_manage instead of deleting.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_fit_sources_manageA

Declare, dry-run or refresh a fit source (fit from text). Run lbb_fit_sources action=preview first and show the user the text the fit reads. dry_run runs the models on the first part of up to 3 instances (at most 60 s; truncated when one did not finish) and returns every proposal with its quote, its support score and what the checks made of it; it files nothing but spends model budget. declare sets the class, the fields and the context; the job then reads every instance and files suggestions (an existing source changes only what you name). refresh asks the job to run now and returns the status at once; the job also runs by itself after each published commit, so poll lbb_fit_sources action=get for progress. Nothing changes the ontology until a person accepts a suggestion.

ParametersJSON Schema
NameRequiredDescriptionDefault
fromNopreview/declare/dry_run: the fields that hold the text, as embedding paths (transcript, label, about/label, <https://…>). Omit for the long text facts of the class.
nameNoThe fit source name (refresh: required).
classNopreview/declare/dry_run: the class IRI whose instances hold the text.
graphNoGraph to target; defaults to the connection's graph
actionYes
detailNoResponse detail level. Defaults to compact.
contextNopreview/declare/dry_run: one sentence about the text, e.g. "interviews with employees about their work processes" (at most 500 characters).
excludeNopreview/declare/dry_run: fields to drop from the automatic choice.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint=false, openWorldHint=false, destructiveHint=false; the description adds substantial context beyond that – dry_run spends model budget but files nothing, declare files suggestions and only alters what you name, refresh is fire-and-return with the job also auto-running after each published commit, and nothing reaches the ontology until a human accepts. This is exactly the kind of side-effect and cost disclosure the annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The workflow prerequisite is front-loaded and each sentence carries real information (action semantics, cost, polling, safety). It is dense and on the long side for one paragraph, but there is essentially no filler to cut.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a multi-action mutation tool with no output schema, the description covers everything an agent needs: prerequisites, the return shape of dry_run (proposals with quote, support score, checks), background/polling behavior, and the human-acceptance gate. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 88% (baseline 3), but the description earns extra credit by explaining the semantics of the three action values, which the schema's enum leaves entirely undocumented. It also clarifies declare's modify-only-what-you-name behavior and dry_run's truncation/60s scope, though it adds little on from/context/exclude beyond the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the specific resource (a fit source, i.e. fit-from-text) and enumerates the three concrete verbs it supports (declare, dry_run, refresh), each with a distinct function. It also distinguishes itself from the sibling lbb_fit_sources by pointing to its preview and get actions, so an agent can route correctly without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit prerequisite/workflow ordering ("Run lbb_fit_sources action=preview first and show the user the text") and names the sibling actions used for previewing and polling progress. It clearly implies which action to pick (dry_run to trial cheaply, declare to persist, refresh to force a run), though it never states an explicit when-not-to-use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_inspectA
Read-only

Read graph context and exact graph facts. Actions: guide, graphs, publication, ontology, ontology_conformance, schema, ontology_search, metadata, entity, ontology_suggestions. graphs works before bootstrap; ontology_suggestions lists the ontology change suggestions that wait for review (or were decided); fact_count is how many graph facts (triplets and entity property rows) accepting one commits, and identity_count how many identities it links. publication reports whether writes are queryable. ontology and schema return complete entries with page_size, section and cursor; follow next until absent. schema reads active native ontology/SHACL metadata without running validation. Query asserted RDF/OWL axioms separately with lbb_query. ontology_conformance serves the durable report referenced by the pinned published root. entity returns one node's attributes and current relationships from the RDF read. For a node's past values, run SPARQL with as_of_commit_seq through lbb_query. Use lbb_query with SPARQL property paths for precise path selection.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNo
as_ofNoUnsupported for entity; use as_of_commit_seq for a retained commit snapshot.
graphNoGraph to target; defaults to the connection's graph
limitNo
queryNoOntology concept, term, or relation to search
top_kNo
actionYesSelects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, ontology_suggestions, entity).
cursorNoOpaque lbb_inspect continuation. Repeat action and pass the returned next arguments; rejects changed metadata.
detailNoResponse detail level. Defaults to compact.
statusNoOnly suggestions in this state; default all
sectionNoOptional top-level array to inspect, e.g. entity_type_defs, relation_defs, property_defs, classes, or relations. Omit to page through all sections.
entity_idNoEntity id (hex); alternative to entity_type+name
page_sizeNoMaximum complete metadata entries per page; defaults to 50. Nested fields are never truncated; an oversized single entry returns serialized_json fragments to concatenate and parse.
entity_typeNo
as_of_commit_seqNoSnapshot pin: reproduce the node's attributes and relationships as of this commit_seq.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation the description discloses real behavior: ontology/schema pagination via next until absent, schema reads metadata without running validation, publication reports whether writes are queryable, and fact_count/identity_count describe the size of a suggestion decision. These are traits an agent could not infer from the annotations. It loses a point for not describing the response shape of most actions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and action list are front-loaded, and most sentences carry information. However the body is a dense wall of run-on prose with no per-action grouping, so an agent must re-read to map behavior to the correct variant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a ten-action, fifteen-parameter tool with no output schema, the description covers roughly half the actions and never states which parameters apply to which action. It is adequate for orientation but leaves an agent guessing about guide, metadata, ontology_search and the entity argument combinations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

At 73% schema coverage the schema already documents most parameters, so the baseline is 3. The description adds the as_of vs as_of_commit_seq distinction and ties page_size/section/cursor to the paging loop, but it never explains the bare name, query, top_k, limit, detail or entity_type parameters that lack schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb and resource (read graph context / exact graph facts) and the action list defines the tool's scope. It differentiates from siblings by repeatedly naming lbb_query as the tool for axioms and precise path selection. It falls short of 5 because the ten-action enumeration is a grab bag and several actions (guide, metadata) are named without any statement of what they return.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing is present: axioms go to lbb_query, historical node values go to lbb_query with as_of_commit_seq, path selection goes to lbb_query with SPARQL property paths, and ontology_suggestions is scoped to suggestions awaiting review. The 'graphs works before bootstrap' note is a genuinely useful precondition. It stops short of 5 because most individual actions have no stated when-to-use or when-not-to-use condition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_model_choiceA
Read-only

Model choice, read only: which model each use of a model on the graph runs, and trials that test other models against the graph's ground truth (the checked calls: a person's review, else the judge's verdict). options shows per use the model it runs now (current), LBB's model (default), a switch (switched), its checked calls, and the models a trial can test with their efforts, prices and whether the server holds their key; available=false with a reason when trials cannot run. trials lists the trials, newest first, each with its report: calls compared, both models' right share, mean score (0 to 1), cost per call and median time, the difference with its 95% interval (delta, ci_low, ci_high), outcome (too_few, better, same, worse) and qualifies (meets the bar: at least 20 calls, at most 5 points worse at the low end, no more failures, cheaper or better). trial reads one trial with its compared calls; trial_call reads one call with both answers and the ground truth. switches lists the switched uses. Start, stop, switch or revert with lbb_model_choice_manage.

ParametersJSON Schema
NameRequiredDescriptionDefault
jobNotrials: only the trials of this use.
graphNoGraph to target; defaults to the connection's graph
limitNotrials: at most this many, newest first (default 20).
actionYes
detailNoResponse detail level. Defaults to compact.
call_idNotrial_call: a call id from the trial's calls.
trial_idNotrial / trial_call: the trial id.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true, and the description reinforces 'read only' consistently while adding substantial context: what options shows (current/default/switched, key availability, available=false with a reason), what trials reports (delta, ci interval, outcome values, the qualifies bar), and that results are newest-first. It stops short of documenting auth/rate-limit or pagination traits, so 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a dense run-on paragraph with no line breaks or front-loading; the single-sentence opening is buried in clauses about ground truth and checked calls. Information is relevant but the structure makes it hard to scan, which is a conciseness/structure failure rather than under-specification.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so thoroughly (per-action outputs, outcome enum meanings, the qualifies criteria). Combined with 86% schema coverage and readOnlyHint, an agent has enough to call it correctly; only minor gaps like pagination/ordering for non-trial actions remain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 86%, so the schema already documents job, limit, call_id, trial_id, graph, and detail. The description only loosely ties fields to actions (e.g., 'newest first' matching limit) and adds no syntax or format meaning beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource ('Model choice, read only') and enumerates exactly what each action exposes (options, trials, trial, trial_call, switches). It also explicitly distinguishes itself from the sibling mutation tool lbb_model_choice_manage, so an agent can tell the two apart without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear routing guidance for the write path ('Start, stop, switch or revert with lbb_model_choice_manage') and describes what each read action returns, implying when each is used. It does not give explicit when-not conditions or a crisp decision rule among the five read actions, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_model_choice_manageA

Model choice, writes. start tests a candidate model on the uses in jobs (without jobs, every use it can do that has checked calls): the server answers those checked calls again with the candidate and scores it and the model in use against the same ground truth. It changes no model and spends at most the trial budget ($3.00 by default) of model and judge cost; an open trial of the same use and candidate comes back as it is. Pick candidates from lbb_model_choice action=options (provider anthropic with an effort, or typesafe jev-latest). A trial runs by itself: poll lbb_model_choice action=trial until its status is no longer running. stop ends a trial; it keeps what it compared. switch makes the trial's use run its candidate on this graph from the next call on; only a trial that qualifies and compared with the model in use switches (ask to a Claude model, route to a Jev model). Show the user the trial's report (score, difference and interval, cost per call, time) and switch only what the user confirmed. revert puts the use back on LBB's model.

ParametersJSON Schema
NameRequiredDescriptionDefault
jobNorevert: the use to put back on LBB's model.
daysNostart: the days the trial takes new checks (default 14).
jobsNostart: the uses to test it on.
graphNoGraph to target; defaults to the connection's graph
modelNostart: the candidate model id, e.g. claude-haiku-5-5 or jev-latest.
actionYes
detailNoResponse detail level. Defaults to compact.
effortNostart: the effort of a Claude candidate.
targetNostart: the calls to compare (default 40).
providerNostart: the candidate's provider.
trial_idNostop / switch: the trial id.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (which only say non-read-only, non-destructive) by disclosing the trial budget cap ($3.00 default), that start mutates no model, idempotency of an open trial, that stop preserves comparisons, and that switch only applies to a qualifying trial already compared against the incumbent. This is exactly the mutation/state semantics an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Information-dense and largely front-loaded, but it is delivered as a single run-on paragraph with nested parentheticals and colons that make per-action scanning hard. The content earns its place; the structure does not.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 11 params and no output schema, it covers the important gaps: async polling lifecycle, budget ceiling, user-confirmation gate, and even the report contents (score, difference and interval, cost per call, time). It omits any auth/permission note, but is otherwise sufficient for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 91% with action-scoped prefixes, so the baseline is 3. The description adds genuine meaning on top: candidates are provider anthropic with an effort setting, or typesafe jev-latest, clarifying how provider/effort/model interact beyond the raw enum lists.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a terse 'Model choice, writes' but then defines each of the four actions (start/stop/switch/revert) with concrete behavior, so an agent can grasp the resource and operations. It implicitly distinguishes itself from the sibling lbb_model_choice (which serves options/trial reads), though it never states that contrast in so many words.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing: pick candidates from lbb_model_choice action=options, poll lbb_model_choice action=trial until status leaves running, and switch only what the user confirmed. It names the alternative tool call and the condition that selects it, plus the confirmation prerequisite.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_modelsB
Read-only

Read model-training inputs or compare retrieval configurations over one pinned published snapshot, or read what the managed models did. shadow_eval takes the API ShadowEvalRequest body; dataset actions return bounded training examples at an optional signal split. activity reads one month of the stack's model use (all graphs): calls, items, estimated tokens and cost per feature (index, search, fit, judge, training, rerank, rewrite, trial, workflows) and model, by day and by graph, the workflows' calls per workflow and job (by_workflow), the months with activity, and the model each feature uses now.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNo
graphNoGraph to target; defaults to the connection's graph
limitNo
monthNoactivity: the month, yyyy-mm (UTC). Defaults to the current month.
actionYes
detailNoResponse detail level. Defaults to compact.
split_seqNo

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already tells the agent this is a safe read. The description adds useful behavioral detail beyond that: the comparison is pinned to one published snapshot, training examples are bounded, and activity is scoped to a single month across all graphs. It stops short of disclosing pagination, response size behavior, or whether any action has side effects, which keeps it at a solid but not rich 3.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence, but the activity clause collapses into a single sprawling run-on listing nine features and four breakdown dimensions. Every element is informative, yet the density hurts scannability for an agent deciding which action to invoke.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so well for 'activity' (calls, items, tokens, cost by feature/model/day/graph, plus by_workflow). It leaves what shadow_eval and the dataset actions actually return largely unspecified, and says nothing about auth or rate behavior for a 7-parameter tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 43%, but the description compensates for several gaps: 'body' is tied to the ShadowEvalRequest shape, 'split_seq' to the optional signal split, 'limit' to the bounded example count, and 'month' to the activity window. It says nothing about 'graph' or how 'detail' interacts with the reported output, so roughly half the gap remains unfilled.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names concrete verbs and resources: reading model-training inputs, comparing retrieval configurations over a pinned published snapshot, and reading managed-model activity. It is specific enough that an agent understands the domain, but it never distinguishes this tool from models-adjacent siblings such as lbb_evals, lbb_model_choice, or lbb_model_choice_manage, so an agent must still guess at boundaries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives per-action context ('shadow_eval takes the API ShadowEvalRequest body', 'dataset actions return bounded training examples', 'activity reads one month of the stack's model use'), which implies when each action is appropriate. However, it offers no explicit when-not guidance and no routing to sibling tools, so the agent has to infer selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_queryA
Read-only

Analytical and expert reads. Modes: question (a question in plain words), structured (SPARQL-subset JSON body), sparql (SPARQL text), search (instances by meaning over every searchable class; filter narrows by class and relationship; every hit checked against the graph), analyze, and four tools for writing your own queries: names, describe, commit_at, compare. names: before a query that names an entity (a person, a company), find its IRI with text=; use the first candidate, not a CONTAINS match on the name. describe: before a query on classes or properties you have not seen, read them with question= (or classes/properties as IRIs): how many sampled instances hold each property (a filter on a rare one returns few rows), the values of small classes such as stages, examples and schema statements. commit_at: for a question about a date, find the commit of date=YYYY-MM-DD (or moment=RFC 3339), then run mode=sparql as_of_commit_seq=. compare: for what changed between two points, run one SELECT at before and after (default the latest) with key=[the entity variable]; added, removed and changed come with totals and pages (next). Use mode=question when you have a question in plain words and no SPARQL query: the server picks the kind of question (route), runs queries in a bounded loop, reads their rows, and answers in plain words (about 8 s). The result holds the answer with citations and a chart hint (kind, x, y: columns of the rows), the steps, the route, and the query and rows the answer stands on. Continue or correct that query with mode=sparql. Each question uses model tokens and counts toward a daily limit of the stack. SPARQL is the query language; search finds what the words describe. SPARQL text can also search by meaning inside the query with ?x https://littlebigbrain.com/search#similarTo "words", so the other patterns filter and join the hits in one query; the result's search field reports the plan. To plan a search: lbb_embeddings action=list, then SPARQL for a class's relationships on a sample, then mode=search with explain=true to check the resolved filter before the real search (lbb_inspect action=guide has the queries). Relations are https://littlebigbrain.com/r/NAME and types https://littlebigbrain.com/class/NAME (both lowercased); entities are content-addressed, so anchor a named one by its rdfs:label rather than building its IRI. Structured and text queries pin one published watermark for the request.

ParametersJSON Schema
NameRequiredDescriptionDefault
keyNocompare: the variables that identify a row's entity, e.g. ["contact"]. With a key the rows are paired: added and removed hold the entities at one point only, changed the entities whose values differ. Without one whole rows are compared.
bodyNoStructured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: "x" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { "compare": { "op": <op>, "left": <term>, "right": <term> } } (or { "and": [<filter>…] }, { "or": [<filter>…] }, { "not": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { "var": "x" }, { "property": { "var": "x", "field": "amount" } } (a typed scalar attribute), or { "value": <typed> } — and <typed> is exactly one wrapper: { "str": "…" }, { "i64": 5 }, { "f64": 0.9 }, { "bool": true }, { "date_time": "2026-01-01" } (RFC3339), or { "entity": { "entity_type": "T", "name": "N" } }. Complete runnable example — deals whose amount ≥ 1000000: { "patterns": [{ "subject": { "var": "d" }, "predicate": "for_client", "object": { "var": "c" } }], "filters": [{ "compare": { "op": "ge", "left": { "property": { "var": "d", "field": "amount" } }, "right": { "value": { "f64": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: ["s"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { "patterns": [{ "subject": { "var": "c" }, "predicate": "committed_to", "object": { "var": "repo" } }], "group_keys": [{ "date_bucket": { "var": "c", "field": "committed_at", "granularity": "month", "as": "m" } }, { "property": { "var": "c", "field": "area", "as": "area" } }], "aggregates": [{ "func": "count", "as": "n" }], "order_by": [{ "var": "m" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { "compare": { "op": "gt", "left": { "var": "n" }, "right": { "value": { "i64": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { "compare": { "op": "eq", "left": { "var": "n" }, "right": { "value": { "i64": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning use the top-level `as_of_commit_seq` argument or the same body field. Valid-time `as_of` and `as_of_valid_time` selectors are unsupported and rejected before HTTP.
dateNocommit_at: YYYY-MM-DD; the last commit written by the end of that day (UTC).
modeYesSelects the variant (one of: structured, sparql, question, search, analyze, names, describe, commit_at, compare).
textNosearch: the query text (required); embedded with the graph's model. names: the question, or the names, to find (required).
afterNocompare: the later point; defaults to the latest commit.
as_ofNoUnsupported in structured and SPARQL text modes; use as_of_commit_seq for a retained commit snapshot.
chartNo
fieldNo
graphNoGraph to target; defaults to the connection's graph
limitNoquestion: rows each query of the server's loop returns, 1 to 1,000. Defaults by detail: compact=20, standard=100, full=1000. names: candidates per name, 1 to 10 (default 5). compare: entries of each list per page, 1 to 1,000 (defaults by detail: 20, 100, 500).
probeNoClusters to read (default 4·√clusters, at least 8). More reads cost latency and find more.
queryNoSPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> "Acme"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10. Search by meaning inside the query (the graph needs an embedding; see lbb_embeddings action=list): PREFIX search: <https://littlebigbrain.com/search#> SELECT ?x ?score WHERE { ?x search:similarTo "card payments" ; search:score ?score . ?x <https://littlebigbrain.com/r/calls> ?y } ORDER BY DESC(?score) LIMIT 5. The other patterns filter and join the hits. One search:similarTo per query, with a variable subject, in the main group (not inside OPTIONAL, UNION, MINUS or a subquery). The object is text, an entity IRI (records like that one) or a vector literal. search:top N sets the hits (1 to 1000; default the query LIMIT, then 10) and search:embedding "name" searches one embedding. FILTER(?score > 0.8) keeps close hits. The result's search field reports the plan (nearest, filter_first or search_first), the hits and complete. For a question in words, add search:rerank true ; search:relevance ?r and ORDER BY DESC(?r): the rerank model (Jev) reads the best hits with the text, keeps the top that answer it and binds its answer (0 to 1); search.rerank reports the status. Only a text query reranks. compare: the SELECT to run at both points; leave out LIMIT.
routeNoquestion: the kind of question, when you know it. Omit it and the router model picks it.
top_kNo
anchorNoquestion: entity IRIs the question is about, at most 10 (for example the record the user has open). The server reads each one, and its queries use these IRIs directly instead of matching their names.
beforeNocompare: the earlier point (required): {"as_of_commit_seq": n}, {"date": "YYYY-MM-DD"} or {"moment": "RFC 3339"}.
cursorNoOpaque cursor from a previous lbb_query row page; reruns the original query at the next offset.
detailNoResponse detail level. Defaults to compact.
filterNoConditions every hit must meet: {"class": …} or {"via": …, "to": …}. The response's filter shows how each condition resolved; an unknown relationship or name answers with the options.
metricNo
momentNocommit_at: RFC 3339, e.g. 2026-06-18T12:00:00Z; the last commit written at or before it.
rerankNotrue: the managed rerank model (Jev) orders the best hits by how well each answers the text, and each hit gets its relevance (0 to 1); adds about 0.3 s. false: the similarity order. Omit it to follow the graph's search setting.
sparqlNo
classesNodescribe: class IRIs to describe, at most 20.
contextNoquestion: notes for the model, at most 8,000 characters: what the data means, units, names to prefer.
explainNoPlan without running: the scope, the resolved filter, and the allowed count. No model call.
includeNotext: return the embedded text of each hit.
requestNoThe user's own words behind this query (managed evals). When present the server records an eval trace and the result carries its trace_id; label the rows valid or not with lbb_evals action=label. Omit on continuation pages.
max_rowsNocompare: rows to read per point, 1 to 50,000 (default 20,000). Past it the result says truncated.
questionNoquestion: the question in plain words (required), 1 to 4,000 characters. The server's model runs queries on this graph, reads their rows, and answers. describe: the question whose classes and properties to describe.
timelineNoquestion: dated points that stand for the graph's commits, at most 200. A question about a date reads the commit of the latest point on or before it. Use it when the commits stand for other dates than the days they were written (a demo's milestones, an import of old records); without it the server reads the last commit written by the end of that day.
embeddingNoOne embedding by name (see lbb_embeddings action=list). Omit it to search every searchable class of the graph; each hit names its class.
row_limitNoMaximum query rows to return in this page. Defaults by detail: compact=20, standard=100, full=1000.
entailmentNoReasoning over the pinned RDF generation. Defaults to none. owl includes RDFS, inverse relationships and the supported OWL profile.
propertiesNodescribe: property IRIs to describe, at most 50.
consistencyNoRead consistency. strong requires publication through head; a pending response is retryable.
compare_cursorNocompare: the cursor of the page before, from next; pass it with the same arguments.
min_indexed_seqNoRead-after-write publication floor. Preserved across cursor pages.
as_of_commit_seqNoSnapshot pin: evaluate the body as of this commit_seq, hiding later commits. Errors if past head. Top-level alias for the body's `as_of_commit_seq` (either works for this one).

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true, but the description adds substantial behavioral context: 'Each question uses model tokens and counts toward a daily limit of the stack', the ~8s latency of question mode, that structured/text queries 'pin one published watermark', and that the server auto-lowercases /r/, /class/, /p/ IRIs and emits a notes entry. This is well beyond the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The mode list is front-loaded and each mode's guidance earns its place, but the body is a dense, run-on wall of prose with repeated IRI-scheme explanations and clause-stacked sentences that are hard to scan. For a 40-parameter tool length is justified, but the structure is not as clean as it could be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries return-value burden and does describe result shape (answer with citations, chart hint, steps, route, query and rows; search field reporting the plan; row_page.total for counts) plus pagination via cursor. Coverage is good, though several modes' return shapes (e.g. analyze, describe) are left largely implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 88%, so the schema already documents most parameters and a baseline of 3 applies. The description still adds real meaning beyond the schema: how mode values combine with anchor/route/context, the compare key semantics, and the commit_at + as_of_commit_seq workflow. It does not re-specify every field, which is appropriate given the schema's coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Despite a terse opener ('Analytical and expert reads'), the description immediately enumerates the nine modes with a specific verb+resource for each (question, structured, sparql, search, names, describe, commit_at, compare) and routes the agent to sibling tools (lbb_inspect action=guide, lbb_embeddings action=list) for adjacent tasks. An agent can tell this apart from lbb_rdf, lbb_inspect, and lbb_embeddings without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use guidance is given per mode, e.g. 'Use mode=question when you have a question in plain words and no SPARQL query' and 'Continue or correct that query with mode=sparql', plus named alternatives and prerequisites (lbb_embeddings action=list, then SPARQL, then mode=search with explain=true). It even states the planning sequence for search, which is exactly the routing an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_rdfA
DestructiveIdempotent

Store and extend complete RDF/OWL documents through MCP. import accepts Turtle/N-Triples/N-Quads/TriG without conversion; update executes INSERT DATA for additive edits. Replacing/removing axioms is unsupported; use a new versioned LBB graph for a revised document. Named RDF graphs are unsupported; Turtle/N-Triples use the default graph, and dataset formats must contain only default-graph quads. These write graph facts, distinct from lbb_configure's native schema metadata. A first RDF write selects RDF-native storage, which refuses later property-graph commits; choose the write workflow before bootstrap. Retries deduplicate by content unless idempotency_key is supplied. A completed write schedules publication; inspect action=publication and verify using lbb_query entailment=owl.

ParametersJSON Schema
NameRequiredDescriptionDefault
graphNoGraph to target; defaults to the connection's graph
actionYesSelects the variant (one of: import, update).
detailNoResponse detail level. Defaults to compact.
formatNo
sourceNoComplete RDF document. Preserves OWL axioms, RDF lists, labels, comments, and external IRIs as graph facts.
updateNoSPARQL INSERT DATA text to add axioms. Submitted unchanged. DELETE/WHERE/CLEAR and named graphs are currently unsupported and fail without mutation.
base_iriNo
idempotency_keyNo
blank_node_scopeNoStable document scope for blank labels across import chunks.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the annotations: import accepts formats without conversion, update is additive INSERT DATA, the first RDF write locks storage mode and refuses later property-graph commits, retries deduplicate by content unless idempotency_key is supplied, and completed writes schedule publication. These details align with the write-oriented annotations and explain important side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence carries an operational constraint or decision point. It is front-loaded with the core purpose, then efficiently covers formats, unsupported operations, storage implications, retry behavior, and publication without filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex write tool with nine parameters and no output schema, the description covers most critical context: supported actions, formats, unsupported operations, storage-mode consequences, retries, and post-write publication/verification. The remaining gap is the lack of guidance on base_iri and the meaning of detail levels, so it is not fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema descriptions already cover several parameters, and the description adds meaning for format by listing accepted RDF formats and the default-graph restriction, and for idempotency_key by explaining content-deduplication behavior. However, base_iri remains undocumented in both the schema and description, so parameter semantics are strong but not complete.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific action: store and extend complete RDF/OWL documents via MCP, with the two variants import and update acting on RDF graph facts. It also distinguishes the tool from sibling lbb_configure, which handles native schema metadata, so an agent can tell them apart.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use and when-not-to-use guidance: replacing/removing axioms is unsupported and should instead use a new versioned LBB graph; named RDF graphs are unsupported; and verification should use lbb_query entailment=owl. This clearly routes an agent away from misuse.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_workflowsA
Read-only

Starter workflows and triggered workflows, read only. A starter workflow is a template; a triggered workflow is a workflow created from one on the graph. It watches a class: when a published commit adds or changes instances of the class (or changes the watched fields), the workflow reads them and does its work. search.embed keeps an embedding of the class (the same as lbb_embeddings); ontology.fit reads text fields and files ontology suggestions (the same as lbb_fit_sources); workflow (a developer workflow) sends the new and changed instances to a workflow of the developer's worker as trigger messages, and that code writes the facts the workflow owns. documents.parse reads uploaded PDF files into pages with line boxes, documents.link connects mentions of the same thing across the documents (it writes DocEntry and DocMention instances and links each mention to the entry that defines or describes it), documents.map proposes each link as a FactProposal in the graph's own ontology (fact_subject, fact_predicate, fact_object, fact_confidence, fact_evidence) for a review workflow, and values.extract fills chosen properties from text, each value with a quote; read the files and their pages with lbb_files. starters lists the starter workflows this server offers with their group, settings and whether each can run here. list shows every triggered workflow of the graph with its state (backfilling, ready, paused, failed, unavailable), lag, counters, this month's spend and last error; get shows one (starter and name) with its own status in details (for workflow: the messages sent, the instances waiting, the message in flight and whether it is paused). preview shows what creating one would do (the resolved watch, the instance count and the workflow's own preview; for workflow, the first messages it would send), calls no model and stores nothing. workflows lists the same workflows as workflows with triggers (/v1/workflows/named): each one's target workflow type (LBB's own are lbb.* types), its shards (engine identities starter. and starter..), its routing field, its window, its one watch trigger, its status and each shard's inbox; name for one. queue (name) shows what a workflow's watch has not sent yet: each waiting instance with its shard and its origin (a backfill, a commit range with the watched fields and the requests that changed it, a run now, a schema change), the pass in progress, and per shard its message in flight and its first unfinished turns with their origins; page with after and limit. Message workflows of the workflow engine are not listed here. Create, refresh, pause or resume with lbb_workflows_manage; delete with lbb_workflows_delete.

ParametersJSON Schema
NameRequiredDescriptionDefault
irisNopreview: the instances to show instead of a sample.
nameNoget: the triggered workflow's name. preview: the name a new workflow would get. workflows: one workflow's name (omit for all). queue: required.
ownsNopreview/use, developer workflow only: what your code writes. classes it creates instances of, relations it writes as out-edges of the watched instances, properties it writes on them. Owned outputs never trigger the workflow itself.
afterNoqueue: the position to start from (next_after).
batchNopreview/use, developer workflow only: instances per message, 1 to 64 (default 16).
classNopreview/use: the class whose instances the workflow watches (an IRI, or a name the ontology knows). Required unless the starter workflow's watch is fixed.
graphNoGraph to target; defaults to the connection's graph
limitNoqueue: items per page, 1 to 100 (default 50).
actionYes
detailNoResponse detail level. Defaults to compact.
fieldsNopreview/use: the fields whose change triggers the workflow, as embedding paths (transcript, label, about/label, <https://…>). Omit for the starter workflow's own choice.
paramsNopreview/use: the starter workflow's own settings, as listed in its catalog entry: search.embed takes model, dim and title; ontology.fit takes context (one sentence about the text, e.g. {"context": "interviews with employees"}); workflow takes none.
sampleNopreview: how many sample instances to show.
excludeNopreview/use: fields to drop from the automatic choice.
starterNoThe starter workflow's catalog id from action=starters, e.g. search.embed (embeddings on a class), ontology.fit (fit from text) or workflow (a developer workflow: your worker's workflow gets the instances). get/preview/use/refresh: required. pause/resume: omit to name a workflow with triggers.
triggerNodefine: the watch trigger's id (default watch). queue: the trigger whose queue to read.
workflowNopreview/use, developer workflow (starter=workflow) only, required there: the workflow of your worker that receives the messages. Creating it creates the instance starter.<name>.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true is reinforced by 'read only', and the description adds real behavioral context beyond the annotation: preview 'calls no model and stores nothing', queue exposes in-flight messages and unfinished turns, and message workflows are out of scope. That is more than the annotation alone conveys, though mutating-adjacent behaviors (e.g. what preview's side-effect-free guarantee excludes) are only partially spelled out.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the read-only framing and then walks the actions in order, which is good structure. However, the conceptual preamble on class watching and the very dense run-on sentences describing each action's output fields make it considerably longer than needed for a read-only query surface.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 17-parameter, nested-object, no-output-schema tool, the description covers each action's return shape (state, lag, counters, spend, inbox, waiting instances, origins) reasonably well and pairs with the 94%-covered schema. Minor gaps remain around actions not discussed parameter-wise (graph, detail), but nothing critical to correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 94%, so the schema already documents nearly every parameter, including action-specific usage notes. The description reinforces a few of these ('page with after and limit', the starter catalog ids) but adds little syntax or meaning beyond the structured fields. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the resource (starter and triggered workflows) and enumerates every action the tool dispatches (starters, list, get, preview, workflows, queue) with a one-line purpose for each. It explicitly separates itself from lbb_workflows_manage (create/refresh/pause/resume) and lbb_workflows_delete (delete), so an agent can place it among siblings. It loses a point only because the opening frame is a domain lecture rather than a crisp 'what this tool does' verb.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit routing for mutating actions: 'Create, refresh, pause or resume with lbb_workflows_manage; delete with lbb_workflows_delete', and states a scope exclusion ('Message workflows of the workflow engine are not listed here'). What it does not clarify is the boundary between the near-identical 'list' and 'workflows' actions, which an agent must infer for itself.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_workflows_deleteA
DestructiveIdempotent

Delete a triggered workflow: it stops following its class, and what it wrote stays. Deleting search.embed deletes the embedding and its vectors, so its class stops being searchable; the suggestions an ontology.fit filed stay; a developer workflow leaves its workflow instance and the facts its code wrote. Without starter it deletes a workflow with triggers by its name, and its shards stay. Ask the user first; confirm must repeat the name.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesThe triggered workflow's name.
graphNoGraph to target; defaults to the connection's graph
detailNoResponse detail level. Defaults to compact.
confirmYesThe same name again, to confirm.
starterNoThe starter workflow's catalog id, e.g. search.embed. Omit for a workflow with triggers.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is covered. The description adds genuine value beyond that by detailing exactly what is destroyed versus preserved (e.g. deleting search.embed removes the embedding and vectors and the class stops being searchable, while filed suggestions stay). This is exactly the kind of consequence disclosure a mutation tool needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The action is front-loaded, but the description is meandering, stacking multiple illustrative examples (search.embed, ontology.fit, developer workflow) in one run-on passage. It is informative but not tightly edited, and some clauses are ambiguous.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and a destructive mutation, the description adequately covers consequences, the confirmation requirement, and the starter distinction. It is complete enough for an agent to act correctly, though the reasoning about which workflow type applies could be clearer.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes further by explaining the semantics of starter ('Without starter it deletes a workflow with triggers by its name') and confirm ('confirm must repeat the name'), adding meaning beyond the schema strings.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause names a specific verb and resource ('Delete a triggered workflow') and distinguishes it from siblings like lbb_workflows_manage and lbb_embeddings_delete. The purpose is clear, though the sentence structure becomes convoluted with layered examples.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a direct instruction ('Ask the user first; confirm must repeat the name') and explains when to omit starter. However, it never states when to use this tool versus lbb_workflows_manage or other alternatives, so routing guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lbb_workflows_manageA

Create a workflow from a starter workflow, or refresh, pause or resume a triggered workflow. Run lbb_workflows action=preview first and show the user the watch and the instance count. use creates a workflow from a starter workflow of action=starters, under a name (default: the class's local name), with its watch (class, fields) and params; the workflow then reads every instance of the class and follows each published commit. A developer workflow (starter=workflow) also takes workflow (workflow_type and version of the developer's worker), owns and batch; it needs a server with the workflow engine. use again with the same starter and name changes only what you name, and the same request again changes nothing. A workflow that calls models (ontology.fit, documents.link, documents.map, values.extract) spends model budget as it reads. refresh asks the workflow to run now and returns at once with queued; poll lbb_workflows action=get for progress. pause stops a workflow (a developer workflow, documents.parse, documents.link, documents.map or values.extract) from reading and sending, and stops the claims of a developer workflow's shards; resume lets it catch up. Without starter, pause and resume name a workflow with triggers. search.embed and ontology.fit cannot be paused. define creates or changes a workflow with triggers of the developer's worker (/v1/workflows/named): name, workflow, class and fields (its watch trigger), owns, batch, and shards (engine identities, 1 to 16), route_by (a field that keeps work in order) and window (messages queued per shard, default 4); it needs a server with the workflow engine, and a change of shards waits for empty inboxes. run (name) runs a workflow with triggers now: its watch sends every instance again.

ParametersJSON Schema
NameRequiredDescriptionDefault
gateNouse: outputs below this confidence go to review instead of the graph, for a workflow with a review gate.
nameNoThe triggered workflow's name, [a-z0-9][a-z0-9-]{0,62} (refresh, pause, resume: required; use: omit for the class's local name).
ownsNopreview/use, developer workflow only: what your code writes. classes it creates instances of, relations it writes as out-edges of the watched instances, properties it writes on them. Owned outputs never trigger the workflow itself.
batchNopreview/use, developer workflow only: instances per message, 1 to 64 (default 16).
classNopreview/use: the class whose instances the workflow watches (an IRI, or a name the ontology knows). Required unless the starter workflow's watch is fixed.
graphNoGraph to target; defaults to the connection's graph
actionYes
detailNoResponse detail level. Defaults to compact.
fieldsNopreview/use: the fields whose change triggers the workflow, as embedding paths (transcript, label, about/label, <https://…>). Omit for the starter workflow's own choice.
paramsNopreview/use: the starter workflow's own settings, as listed in its catalog entry: search.embed takes model, dim and title; ontology.fit takes context (one sentence about the text, e.g. {"context": "interviews with employees"}); workflow takes none.
shardsNodefine: engine identities that receive the messages, 1 to 16 (default 1). A change needs every shard's inbox empty.
windowNodefine: messages the watch keeps queued per shard, 1 to 128 (default 4).
excludeNopreview/use: fields to drop from the automatic choice.
starterNoThe starter workflow's catalog id from action=starters, e.g. search.embed (embeddings on a class), ontology.fit (fit from text) or workflow (a developer workflow: your worker's workflow gets the instances). get/preview/use/refresh: required. pause/resume: omit to name a workflow with triggers.
triggerNodefine: the watch trigger's id (default watch). queue: the trigger whose queue to read.
route_byNodefine: a field of the class whose value keeps work in order: the changes of one value go to one shard. Default: the instance.
workflowNopreview/use, developer workflow (starter=workflow) only, required there: the workflow of your worker that receives the messages. Creating it creates the instance starter.<name>.
budget_usd_per_monthNouse: a monthly model budget in USD for this workflow, below the stack's own.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations only say this is a non-read-only, non-destructive, non-open-world tool; the description adds substantial behavioral facts beyond that: 'refresh ... returns at once with queued', workflows that call models 'spend model budget as it reads', 'pause ... stops the claims of a developer workflow's shards', and 'a change of shards waits for empty inboxes'. These are exactly the operational traits an agent needs and cannot infer from the schema or annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the body is a dense, semicolon-chained wall of text packed with six actions' worth of detail and no headings or bullet structure, making it hard to scan. Most sentences do carry information, so it is not padding, but the presentation hurts usability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 18-parameter, six-action tool with no output schema, the description covers each action, its key parameters, and the handoff to lbb_workflows for progress polling. It leaves some response shapes (use/define results) unspecified, but with no output schema and a coverage-rich input schema the remaining gap is minor.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 94%, so the 3 baseline applies, but the description adds real semantics not present in the schema: idempotency ('use again with the same starter and name changes only what you name, and the same request again changes nothing'), which parameters bind to which action, and what gate/budget imply. It does not cover every one of the 18 parameters, so it is not a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states concrete verbs and the resource they act on for each mode: 'use' creates a workflow from a starter, 'refresh' runs it now, 'pause'/'resume' control it, 'define' creates or changes a triggered workflow, 'run' runs it. It implicitly distinguishes itself from the read-side sibling (lbb_workflows) by routing to it for preview/get. A sibling-specific exclusion is not spelled out, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit prerequisite workflow: 'Run lbb_workflows action=preview first and show the user the watch and the instance count.' It also distinguishes pause/resume with vs. without a starter and notes exceptions ('search.embed and ontology.fit cannot be paused'). It never states when *not* to reach for this tool versus lbb_workflows_delete or lbb_workflows, so it is clear context without full exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 12 tool updatesv0.14.0
    • Changedlbb_configure3 fields changed
      • changedInput schema / properties / change / description
        Previous value: -"The ontology operations a person applies by accepting, in order (same shapes as evolve_ontology ops)"New value: +"The ontology operations a person applies by accepting, in order (same shapes as evolve_ontology ops). Up to 128; may be empty or absent when facts is set"
      • removedInput schema / properties / change / minItems
        Removed value: -1
      • addedInput schema / properties / facts
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Graph facts a person confirms: accepting commits them after the change (at most 200 triplets and property rows together). Records graphs only",
        +  "properties": {
        +    "entity_properties": {
        +      "description": "Fields to commit, each { type, name, properties: { field: value } } as lbb_commit takes them",
        +      "items": {
        +        "$ref": "#/properties/entity_types/items/anyOf/1"
        +      },
        +      "maxItems": 200,
        +      "type": "array"
        +    },
        +    "replace_owned": {
        +      "additionalProperties": false,
        +      "description": "Replace the producer's owned edges and fields on its subjects in the same commit",
        +      "properties": {
        +        "properties": {
        +          "description": "Owned fields: the ones the facts do not set on a subject are removed",
        +          "items": {
        +            "type": "string"
        +          },
        +          "maxItems": 64,
        +          "type": "array"
        +        },
        +        "relations": {
        +          "description": "Owned relations: their current out-edges of the subjects that the facts do not write again are removed",
        +          "items": {
        +            "type": "string"
        +          },
        +          "maxItems": 64,
        +          "type": "array"
        +        },
        +        "retract_entities": {
        +          "description": "Records the producer made and no longer makes",
        +          "items": {
        +            "$ref": "#/properties/facts/properties/triplets/items/properties/source"
        +          },
        +          "maxItems": 1000,
        +          "type": "array"
        +        },
        +        "subjects": {
        +          "description": "The records this write is for",
        +          "items": {
        +            "$ref": "#/properties/facts/properties/triplets/items/properties/source"
        +          },
        +          "maxItems": 1000,
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "subjects"
        +      ],
        +      "type": "object"
        +    },
        +    "summary": {
        +      "description": "One line about the facts for the reviewer",
        +      "maxLength": 500,
        +      "type": "string"
        +    },
        +    "triplets": {
        +      "description": "Links to commit, as lbb_commit takes triplets",
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "confidence": {
        +            "maximum": 1,
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "evidence": {
        +            "description": "Why the link holds: a string, or { text, source_id } as lbb_commit takes it"
        +          },
        +          "relation": {
        +            "type": "string"
        +          },
        +          "source": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "key": {
        +                "description": "The record's external key, when it has one",
        +                "type": "string"
        +              },
        +              "name": {
        +                "type": "string"
        +              },
        +              "type": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "type",
        +              "name"
        +            ],
        +            "type": "object"
        +          },
        +          "target": {
        +            "$ref": "#/properties/facts/properties/triplets/items/properties/source"
        +          }
        +        },
        +        "required": [
        +          "source",
        +          "relation",
        +          "target"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 200,
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlbb_evals8 fields changed
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "summary",
        -  "traces",
        -  "trace",
        -  "label",
        -  "judge",
        -  "goldens",
        -  "golden",
        -  "accept",
        -  "delete",
        -  "run",
        -  "results",
        -  "settings",
        -  "checks_summary",
        -  "checks",
        -  "review_check"
        -]New value: +[
        +  "summary",
        +  "traces",
        +  "trace",
        +  "label",
        +  "judge",
        +  "goldens",
        +  "golden",
        +  "accept",
        +  "delete",
        +  "run",
        +  "run_answers",
        +  "results",
        +  "settings",
        +  "checks_summary",
        +  "checks",
        +  "review_check"
        +]
      • addedInput schema / properties / answers
        Added value: +{
        +  "description": "run_answers: one answer per question golden your app asked: golden (its id), sparql (the query whose rows hold the answer; leave it out when the question is unanswerable), entailment, as_of_commit_seq, route (as the router returned it), reply, error (your app failed), cost_micro_usd.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "as_of_commit_seq": {
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "cost_micro_usd": {
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "entailment": {
        +        "enum": [
        +          "none",
        +          "subclass",
        +          "rdfs",
        +          "owl"
        +        ],
        +        "type": "string"
        +      },
        +      "error": {
        +        "type": "string"
        +      },
        +      "golden": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "reply": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "citations": {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "text": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "text"
        +        ],
        +        "type": "object"
        +      },
        +      "route": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "by": {
        +            "enum": [
        +              "caller",
        +              "router",
        +              "rewriter"
        +            ],
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": "number"
        +          },
        +          "kind": {
        +            "enum": [
        +              "lookup",
        +              "aggregate",
        +              "search",
        +              "history",
        +              "schema",
        +              "unanswerable"
        +            ],
        +            "type": "string"
        +          },
        +          "probabilities": {
        +            "additionalProperties": {
        +              "type": "number"
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "kind",
        +          "confidence",
        +          "by"
        +        ],
        +        "type": "object"
        +      },
        +      "sparql": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "golden"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / consistency / description
        Previous value: -"run / accept: strong reads the head, eventual the last published commit."New value: +"run / run_answers / accept: strong reads the head, eventual the last published commit."
      • changedInput schema / properties / job / enum
        Previous value: -[
        -  "rerank",
        -  "route",
        -  "rewrite",
        -  "fit",
        -  "propose",
        -  "label"
        -]New value: +[
        +  "rerank",
        +  "route",
        +  "ask",
        +  "rewrite",
        +  "fit",
        +  "propose",
        +  "label"
        +]
      • addedInput schema / properties / route
        Added value: +{
        +  "description": "label: with valid=true, or valid=false with sparql, the route the question expects.",
        +  "enum": [
        +    "lookup",
        +    "aggregate",
        +    "search",
        +    "history",
        +    "schema",
        +    "unanswerable"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / runner
        Added value: +{
        +  "description": "run_answers / results: your app's name, lower-case letters, digits and -, at most 40 characters (default app). results without runner reads the server's runs.",
        +  "type": "string"
        +}
      • changedInput schema / properties / sparql / description
        Previous value: -"golden: the query to freeze (the search text for surface=search)."New value: +"golden: the query to freeze (the search text for surface=search). label: with valid=false and no item, the right query for the question; the server checks and runs it once."
      • changedInput schema / properties / valid / description
        Previous value: -"label: true = the result answers the request (thumbs up), false = it does not."New value: +"label: true = the result answers the request (thumbs up), false = it does not. Without item or items, on a question's trace: the whole answer is right (true) or wrong (false)."
    • Addedlbb_files
    • Addedlbb_fit_sources
    • Addedlbb_fit_sources_delete
    • Addedlbb_fit_sources_manage
    • Addedlbb_model_choice
    • Addedlbb_model_choice_manage
    • Changedlbb_query18 fields changed
      • addedInput schema / properties / after
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "compare: the later point; defaults to the latest commit.",
        +  "properties": {
        +    "as_of_commit_seq": {
        +      "$ref": "#/properties/before/properties/as_of_commit_seq"
        +    },
        +    "date": {
        +      "$ref": "#/properties/before/properties/date"
        +    },
        +    "moment": {
        +      "$ref": "#/properties/before/properties/moment"
        +    }
        +  },
        +  "type": "object"
        +}
      • changedInput schema / properties / anchor / description
        Previous value: -"question: entity IRIs the question is about, at most 10 (for example the record the user has open). The server reads each one, and the query uses these IRIs directly instead of matching their names."New value: +"question: entity IRIs the question is about, at most 10 (for example the record the user has open). The server reads each one, and its queries use these IRIs directly instead of matching their names."
      • addedInput schema / properties / before
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "compare: the earlier point (required): {\"as_of_commit_seq\": n}, {\"date\": \"YYYY-MM-DD\"} or {\"moment\": \"RFC 3339\"}.",
        +  "properties": {
        +    "as_of_commit_seq": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "date": {
        +      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +      "type": "string"
        +    },
        +    "moment": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / classes
        Added value: +{
        +  "description": "describe: class IRIs to describe, at most 20.",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 20,
        +  "type": "array"
        +}
      • addedInput schema / properties / compare_cursor
        Added value: +{
        +  "description": "compare: the cursor of the page before, from next; pass it with the same arguments.",
        +  "type": "string"
        +}
      • addedInput schema / properties / date
        Added value: +{
        +  "description": "commit_at: YYYY-MM-DD; the last commit written by the end of that day (UTC).",
        +  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +  "type": "string"
        +}
      • addedInput schema / properties / key
        Added value: +{
        +  "description": "compare: the variables that identify a row's entity, e.g. [\"contact\"]. With a key the rows are paired: added and removed hold the entities at one point only, changed the entities whose values differ. Without one whole rows are compared.",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 8,
        +  "type": "array"
        +}
      • changedInput schema / properties / limit / description
        Previous value: -"question: rows the run returns, 1 to 1,000. Defaults by detail: compact=20, standard=100, full=1000."New value: +"question: rows each query of the server's loop returns, 1 to 1,000. Defaults by detail: compact=20, standard=100, full=1000. names: candidates per name, 1 to 10 (default 5). compare: entries of each list per page, 1 to 1,000 (defaults by detail: 20, 100, 500)."
      • addedInput schema / properties / max_rows
        Added value: +{
        +  "description": "compare: rows to read per point, 1 to 50,000 (default 20,000). Past it the result says truncated.",
        +  "maximum": 50000,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedInput schema / properties / mode / description
        Previous value: -"Selects the variant (one of: structured, sparql, question, search, analyze)."New value: +"Selects the variant (one of: structured, sparql, question, search, analyze, names, describe, commit_at, compare)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "structured",
        -  "sparql",
        -  "question",
        -  "search",
        -  "analyze"
        -]New value: +[
        +  "structured",
        +  "sparql",
        +  "question",
        +  "search",
        +  "analyze",
        +  "names",
        +  "describe",
        +  "commit_at",
        +  "compare"
        +]
      • addedInput schema / properties / moment
        Added value: +{
        +  "description": "commit_at: RFC 3339, e.g. 2026-06-18T12:00:00Z; the last commit written at or before it.",
        +  "type": "string"
        +}
      • addedInput schema / properties / properties
        Added value: +{
        +  "description": "describe: property IRIs to describe, at most 50.",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 50,
        +  "type": "array"
        +}
      • changedInput schema / properties / query / description
        Previous value: -"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10. Search by meaning inside the query (the graph needs an embedding; see lbb_embeddings action=list): PREFIX search: <https://littlebigbrain.com/search#> SELECT ?x ?score WHERE { ?x search:similarTo \"card payments\" ; search:score ?score . ?x <https://littlebigbrain.com/r/calls> ?y } ORDER BY DESC(?score) LIMIT 5. The other patterns filter and join the hits. One search:similarTo per query, with a variable subject, in the main group (not inside OPTIONAL, UNION, MINUS or a subquery). The object is text, an entity IRI (records like that one) or a vector literal. search:top N sets the hits (1 to 1000; default the query LIMIT, then 10) and search:embedding \"name\" searches one embedding. FILTER(?score > 0.8) keeps close hits. The result's search field reports the plan (nearest, filter_first or search_first), the hits and complete. For a question in words, add search:rerank true ; search:relevance ?r and ORDER BY DESC(?r): the rerank model (Jev) reads the best hits with the text, keeps the top that answer it and binds its answer (0 to 1); search.rerank reports the status. Only a text query reranks."New value: +"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10. Search by meaning inside the query (the graph needs an embedding; see lbb_embeddings action=list): PREFIX search: <https://littlebigbrain.com/search#> SELECT ?x ?score WHERE { ?x search:similarTo \"card payments\" ; search:score ?score . ?x <https://littlebigbrain.com/r/calls> ?y } ORDER BY DESC(?score) LIMIT 5. The other patterns filter and join the hits. One search:similarTo per query, with a variable subject, in the main group (not inside OPTIONAL, UNION, MINUS or a subquery). The object is text, an entity IRI (records like that one) or a vector literal. search:top N sets the hits (1 to 1000; default the query LIMIT, then 10) and search:embedding \"name\" searches one embedding. FILTER(?score > 0.8) keeps close hits. The result's search field reports the plan (nearest, filter_first or search_first), the hits and complete. For a question in words, add search:rerank true ; search:relevance ?r and ORDER BY DESC(?r): the rerank model (Jev) reads the best hits with the text, keeps the top that answer it and binds its answer (0 to 1); search.rerank reports the status. Only a text query reranks. compare: the SELECT to run at both points; leave out LIMIT."
      • changedInput schema / properties / question / description
        Previous value: -"question: the question in plain words (required), 1 to 4,000 characters. The server writes the SPARQL query from a description of this graph, checks it, and runs it."New value: +"question: the question in plain words (required), 1 to 4,000 characters. The server's model runs queries on this graph, reads their rows, and answers. describe: the question whose classes and properties to describe."
      • changedInput schema / properties / route / description
        Previous value: -"question: the kind of query, when you know it. Omit it and the router model selects it."New value: +"question: the kind of question, when you know it. Omit it and the router model picks it."
      • removedInput schema / properties / run
        Removed value: -{
        -  "description": "question: run the query and return its rows. Defaults to true; false returns the query only.",
        -  "type": "boolean"
        -}
      • changedInput schema / properties / text / description
        Previous value: -"The query text (required); embedded with the graph's model."New value: +"search: the query text (required); embedded with the graph's model. names: the question, or the names, to find (required)."
    • Addedlbb_workflows
    • Addedlbb_workflows_delete
    • Addedlbb_workflows_manage
  2. 5 tool updatesv0.9.0
    • Changedlbb_configure5 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change)."New value: +"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change, get_rewrite_profile, set_rewrite_profile)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "define_ontology",
        -  "publish_schema",
        -  "evolve_ontology",
        -  "list_starters",
        -  "apply_starter",
        -  "suggest_ontology_change"
        -]New value: +[
        +  "define_ontology",
        +  "publish_schema",
        +  "evolve_ontology",
        +  "list_starters",
        +  "apply_starter",
        +  "suggest_ontology_change",
        +  "get_rewrite_profile",
        +  "set_rewrite_profile"
        +]
      • addedInput schema / properties / examples
        Added value: +{
        +  "description": "Up to 20 worked examples: a question and the query that answers it on this graph",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "note": {
        +        "maxLength": 1000,
        +        "type": "string"
        +      },
        +      "question": {
        +        "maxLength": 1000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "sparql": {
        +        "description": "A SELECT or ASK query with its PREFIX lines; the server parses it",
        +        "maxLength": 4000,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "question",
        +      "sparql"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 20,
        +  "type": "array"
        +}
      • addedInput schema / properties / expected_version
        Added value: +{
        +  "description": "The version get_rewrite_profile returned (0 for none): another stored version answers 409 conflict and stores nothing",
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / notes
        Added value: +{
        +  "description": "What the data means for questions: which property holds the current state, what 'me' or 'my' means, which records to leave out. At most 8,000 characters",
        +  "maxLength": 8000,
        +  "type": "string"
        +}
    • Changedlbb_evals11 fields changed
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "summary",
        -  "traces",
        -  "trace",
        -  "label",
        -  "judge",
        -  "goldens",
        -  "golden",
        -  "accept",
        -  "delete",
        -  "run",
        -  "results",
        -  "settings"
        -]New value: +[
        +  "summary",
        +  "traces",
        +  "trace",
        +  "label",
        +  "judge",
        +  "goldens",
        +  "golden",
        +  "accept",
        +  "delete",
        +  "run",
        +  "results",
        +  "settings",
        +  "checks_summary",
        +  "checks",
        +  "review_check"
        +]
      • addedInput schema / properties / after
        Added value: +{
        +  "description": "checks: the next_after of the previous page.",
        +  "type": "string"
        +}
      • addedInput schema / properties / agree
        Added value: +{
        +  "description": "review_check: true = the judge is right, false = correct it with verdict.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / call_id
        Added value: +{
        +  "description": "review_check: the check's `call` id, from checks.",
        +  "type": "string"
        +}
      • addedInput schema / properties / job
        Added value: +{
        +  "description": "checks: only the checks of one job.",
        +  "enum": [
        +    "rerank",
        +    "route",
        +    "rewrite",
        +    "fit",
        +    "propose",
        +    "label"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / month
        Added value: +{
        +  "description": "checks_summary / checks: the month, yyyy-mm (UTC). Defaults to the current month.",
        +  "pattern": "^\\d{4}-(0[1-9]|1[0-2])$",
        +  "type": "string"
        +}
      • addedInput schema / properties / note / description
        Added value: +"label / review_check: why. review_check: at most 2,000 characters."
      • addedInput schema / properties / reference
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "review_check with agree=false: the right answer. A rerank or label check: {\"grades\": {\"<hit id>\": 0..3}}; a route or fit check: {\"picks\": {\"<question id>\": \"<option>\"}}.",
        +  "type": "object"
        +}
      • addedInput schema / properties / reviewed
        Added value: +{
        +  "description": "checks: true = only the checks a person reviewed, false = only the others.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / score
        Added value: +{
        +  "description": "review_check with agree=false: the right score, 0 to 1. Omit for the judge's score of that verdict.",
        +  "maximum": 1,
        +  "minimum": 0,
        +  "type": "number"
        +}
      • addedInput schema / properties / verdict
        Added value: +{
        +  "description": "checks: only the checks whose ground truth has this verdict. review_check with agree=false: the right verdict.",
        +  "enum": [
        +    "right",
        +    "partly",
        +    "wrong"
        +  ],
        +  "type": "string"
        +}
    • Changedlbb_inspect1 field changed
      • changedInput schema / properties / as_of / description
        Previous value: -"Valid-time snapshot pin (RFC3339): reproduce the node as of this instant."New value: +"Unsupported for entity; use as_of_commit_seq for a retained commit snapshot."
    • Changedlbb_models2 fields changed
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "shadow_eval",
        -  "suggest_dataset",
        -  "extractor_dataset"
        -]New value: +[
        +  "shadow_eval",
        +  "suggest_dataset",
        +  "extractor_dataset",
        +  "activity"
        +]
      • addedInput schema / properties / month
        Added value: +{
        +  "description": "activity: the month, yyyy-mm (UTC). Defaults to the current month.",
        +  "pattern": "^\\d{4}-(0[1-9]|1[0-2])$",
        +  "type": "string"
        +}
    • Changedlbb_query11 fields changed
      • addedInput schema / properties / anchor
        Added value: +{
        +  "description": "question: entity IRIs the question is about, at most 10 (for example the record the user has open). The server reads each one, and the query uses these IRIs directly instead of matching their names.",
        +  "items": {
        +    "maxLength": 2000,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 10,
        +  "type": "array"
        +}
      • addedInput schema / properties / context
        Added value: +{
        +  "description": "question: notes for the model, at most 8,000 characters: what the data means, units, names to prefer.",
        +  "type": "string"
        +}
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "question: rows the run returns, 1 to 1,000. Defaults by detail: compact=20, standard=100, full=1000.",
        +  "maximum": 1000,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedInput schema / properties / mode / description
        Previous value: -"Selects the variant (one of: structured, sparql, search, analyze)."New value: +"Selects the variant (one of: structured, sparql, question, search, analyze)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "structured",
        -  "sparql",
        -  "search",
        -  "analyze"
        -]New value: +[
        +  "structured",
        +  "sparql",
        +  "question",
        +  "search",
        +  "analyze"
        +]
      • changedInput schema / properties / query / description
        Previous value: -"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10"New value: +"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10. Search by meaning inside the query (the graph needs an embedding; see lbb_embeddings action=list): PREFIX search: <https://littlebigbrain.com/search#> SELECT ?x ?score WHERE { ?x search:similarTo \"card payments\" ; search:score ?score . ?x <https://littlebigbrain.com/r/calls> ?y } ORDER BY DESC(?score) LIMIT 5. The other patterns filter and join the hits. One search:similarTo per query, with a variable subject, in the main group (not inside OPTIONAL, UNION, MINUS or a subquery). The object is text, an entity IRI (records like that one) or a vector literal. search:top N sets the hits (1 to 1000; default the query LIMIT, then 10) and search:embedding \"name\" searches one embedding. FILTER(?score > 0.8) keeps close hits. The result's search field reports the plan (nearest, filter_first or search_first), the hits and complete. For a question in words, add search:rerank true ; search:relevance ?r and ORDER BY DESC(?r): the rerank model (Jev) reads the best hits with the text, keeps the top that answer it and binds its answer (0 to 1); search.rerank reports the status. Only a text query reranks."
      • addedInput schema / properties / question
        Added value: +{
        +  "description": "question: the question in plain words (required), 1 to 4,000 characters. The server writes the SPARQL query from a description of this graph, checks it, and runs it.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / rerank
        Added value: +{
        +  "description": "true: the managed rerank model (Jev) orders the best hits by how well each answers the text, and each hit gets its relevance (0 to 1); adds about 0.3 s. false: the similarity order. Omit it to follow the graph's search setting.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / route
        Added value: +{
        +  "description": "question: the kind of query, when you know it. Omit it and the router model selects it.",
        +  "enum": [
        +    "lookup",
        +    "aggregate",
        +    "search",
        +    "history",
        +    "schema",
        +    "unanswerable"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / run
        Added value: +{
        +  "description": "question: run the query and return its rows. Defaults to true; false returns the query only.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / timeline
        Added value: +{
        +  "description": "question: dated points that stand for the graph's commits, at most 200. A question about a date reads the commit of the latest point on or before it. Use it when the commits stand for other dates than the days they were written (a demo's milestones, an import of old records); without it the server reads the last commit written by the end of that day.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "as_of_commit_seq": {
        +        "description": "The commit that holds the graph as it was on that date.",
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "date": {
        +        "description": "YYYY-MM-DD.",
        +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +        "type": "string"
        +      },
        +      "label": {
        +        "description": "A name for the point, such as a milestone.",
        +        "maxLength": 200,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "date",
        +      "as_of_commit_seq"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 200,
        +  "type": "array"
        +}
  3. 2 tool updatesv0.8.1
    • Changedlbb_configure11 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology)."New value: +"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "define_ontology",
        -  "publish_schema",
        -  "evolve_ontology"
        -]New value: +[
        +  "define_ontology",
        +  "publish_schema",
        +  "evolve_ontology",
        +  "list_starters",
        +  "apply_starter",
        +  "suggest_ontology_change"
        +]
      • addedInput schema / properties / agent
        Added value: +{
        +  "description": "Your name as the producer, shown to reviewers",
        +  "maxLength": 200,
        +  "type": "string"
        +}
      • addedInput schema / properties / anchor
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "The class, property or relation the change is about",
        +  "properties": {
        +    "kind": {
        +      "enum": [
        +        "ontology",
        +        "class",
        +        "property",
        +        "relation"
        +      ],
        +      "type": "string"
        +    },
        +    "name": {
        +      "maxLength": 200,
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "kind"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / change
        Added value: +{
        +  "description": "The ontology operations a person applies by accepting, in order (same shapes as evolve_ontology ops)",
        +  "items": {
        +    "$ref": "#/properties/ops/items"
        +  },
        +  "maxItems": 128,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / evidence
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "What you saw: record count, fields, up to 20 sample records",
        +  "properties": {
        +    "records": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "samples": {
        +      "items": {
        +        "$ref": "#/properties/entity_types/items/anyOf/1"
        +      },
        +      "maxItems": 20,
        +      "type": "array"
        +    },
        +    "source_fields": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "maxItems": 200,
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / expected_ontology_version
        Added value: +{
        +  "description": "Refuse when the graph's ontology version differs",
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / key
        Added value: +{
        +  "description": "Idempotency key ([A-Za-z0-9-_.:/]); filing again with the same key revises the suggestion",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / properties / rationale
        Added value: +{
        +  "description": "Why the ontology needs the change; cite what you saw",
        +  "maxLength": 4000,
        +  "type": "string"
        +}
      • addedInput schema / properties / starter
        Added value: +{
        +  "description": "Starter id: crm, documents or work (list_starters names them)",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "description": "Short imperative text, e.g. 'Add class Contractor'",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedlbb_inspect4 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, ontology_suggestions, entity)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "guide",
        -  "ontology",
        -  "ontology_conformance",
        -  "schema",
        -  "graphs",
        -  "publication",
        -  "ontology_search",
        -  "metadata",
        -  "entity"
        -]New value: +[
        +  "guide",
        +  "ontology",
        +  "ontology_conformance",
        +  "schema",
        +  "graphs",
        +  "publication",
        +  "ontology_search",
        +  "metadata",
        +  "ontology_suggestions",
        +  "entity"
        +]
      • addedInput schema / properties / limit
        Added value: +{
        +  "maximum": 500,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / status
        Added value: +{
        +  "description": "Only suggestions in this state; default all",
        +  "enum": [
        +    "open",
        +    "accepted",
        +    "dismissed",
        +    "superseded"
        +  ],
        +  "type": "string"
        +}
  4. 2 tool updatesv0.6.0
    • Changedlbb_inspect8 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity, state, history, why, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "guide",
        -  "ontology",
        -  "ontology_conformance",
        -  "schema",
        -  "graphs",
        -  "publication",
        -  "ontology_search",
        -  "metadata",
        -  "entity",
        -  "state",
        -  "history",
        -  "why",
        -  "transitions"
        -]New value: +[
        +  "guide",
        +  "ontology",
        +  "ontology_conformance",
        +  "schema",
        +  "graphs",
        +  "publication",
        +  "ontology_search",
        +  "metadata",
        +  "entity"
        +]
      • changedInput schema / properties / as_of_commit_seq / description
        Previous value: -"Snapshot pin: reproduce the node (state, edges, history) as of this commit_seq."New value: +"Snapshot pin: reproduce the node's attributes and relationships as of this commit_seq."
      • removedInput schema / properties / relation
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / source_name
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / source_type
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / target_name
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / target_type
        Removed value: -{
        -  "type": "string"
        -}
    • Changedlbb_models1 field changed
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "shadow_eval",
        -  "planner_dataset",
        -  "planner_preference_dataset",
        -  "suggest_dataset",
        -  "extractor_dataset"
        -]New value: +[
        +  "shadow_eval",
        +  "suggest_dataset",
        +  "extractor_dataset"
        +]
  5. 12 tool updatesv0.5.2
    • Removedlbb_branch
    • Changedlbb_commit1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Changedlbb_configure1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Addedlbb_embeddings
    • Addedlbb_embeddings_delete
    • Addedlbb_embeddings_manage
    • Addedlbb_evals
    • Changedlbb_inspect1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Changedlbb_models1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Removedlbb_observe
    • Changedlbb_query11 fields changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
      • addedInput schema / properties / embedding
        Added value: +{
        +  "description": "One embedding by name (see lbb_embeddings action=list). Omit it to search every searchable class of the graph; each hit names its class.",
        +  "type": "string"
        +}
      • addedInput schema / properties / explain
        Added value: +{
        +  "description": "Plan without running: the scope, the resolved filter, and the allowed count. No model call.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / filter
        Added value: +{
        +  "description": "Conditions every hit must meet: {\"class\": …} or {\"via\": …, \"to\": …}. The response's filter shows how each condition resolved; an unknown relationship or name answers with the options.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "class": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          }
        +        ],
        +        "description": "A class condition: one class IRI or a list (any of); subclasses too. One class condition per search."
        +      },
        +      "direction": {
        +        "description": "With via: out (default), the hit links to the entity; in, the entity links to the hit.",
        +        "enum": [
        +          "out",
        +          "in"
        +        ],
        +        "type": "string"
        +      },
        +      "to": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          }
        +        ],
        +        "description": "With via: the entity, an IRI or a name (its label; a spelling slip resolves when one entity is clearly closest), or a list (any of)."
        +      },
        +      "via": {
        +        "description": "A relationship condition: the relationship, a local name (calls), prefix:name, or <iri>.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / include
        Added value: +{
        +  "description": "text: return the embedded text of each hit.",
        +  "items": {
        +    "enum": [
        +      "text"
        +    ],
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / mode / description
        Previous value: -"Selects the variant (one of: structured, sparql, analyze)."New value: +"Selects the variant (one of: structured, sparql, search, analyze)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "structured",
        -  "sparql",
        -  "analyze"
        -]New value: +[
        +  "structured",
        +  "sparql",
        +  "search",
        +  "analyze"
        +]
      • addedInput schema / properties / probe
        Added value: +{
        +  "description": "Clusters to read (default 4·√clusters, at least 8). More reads cost latency and find more.",
        +  "exclusiveMinimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / request
        Added value: +{
        +  "description": "The user's own words behind this query (managed evals). When present the server records an eval trace and the result carries its trace_id; label the rows valid or not with lbb_evals action=label. Omit on continuation pages.",
        +  "type": "string"
        +}
      • addedInput schema / properties / text
        Added value: +{
        +  "description": "The query text (required); embedded with the graph's model.",
        +  "type": "string"
        +}
      • addedInput schema / properties / top_k / maximum
        Added value: +200
    • Changedlbb_rdf1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
  6. 5 tool updatesv0.5.1
    • Changedlbb_commit1 field changed
      • addedInput schema / properties / dry_run
        Added value: +{
        +  "description": "Validate a facts commit and return its structured SHACL report without writing. Only supported for mode=facts.",
        +  "type": "boolean"
        +}
    • Changedlbb_configure9 fields changed
      • changedInput schema / properties / allow_data_conflicts / description
        Previous value: -"Apply subtractive ops (narrow/remove) even when current data conflicts; affected records are kept and begin to warn. Default false rejects a conflicting subtractive request and reports the conflicts."New value: +"Deprecated compatibility flag; does not bypass conflicts. Preview subtractive changes with dry_run=true, repair the reported conflicts, then apply."
      • addedInput schema / properties / dry_run
        Added value: +{
        +  "description": "Preview the exact definition without creating a graph or writing metadata.",
        +  "type": "boolean"
        +}
      • removedInput schema / properties / entity_types / items / additionalProperties
        Removed value: -{}
      • addedInput schema / properties / entity_types / items / anyOf
        Added value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • removedInput schema / properties / entity_types / items / type
        Removed value: -"object"
      • changedInput schema / properties / ops / items / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "add_domain": {
        -        "description": "Entity-type names to add to the relation's domain (source types)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "add_range": {
        -        "description": "Entity-type names to add to the relation's range (target types)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "op": {
        -        "const": "widen_relation",
        -        "type": "string"
        -      },
        -      "relation": {
        -        "description": "Relation to widen, by name (case-insensitive)",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "relation"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "name": {
        -        "description": "Display name of the new entity type (idempotent if it exists)",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "add_entity_type",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "cardinality": {
        -        "description": "Defaults to many_to_many",
        -        "enum": [
        -          "one_to_one",
        -          "one_to_many",
        -          "many_to_one",
        -          "many_to_many"
        -        ],
        -        "type": "string"
        -      },
        -      "domain": {
        -        "description": "Entity-type names allowed as the source (domain); must already exist",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "inverse_name": {
        -        "description": "Optional inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Display name of the new relation, e.g. HAS_PHASE",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "add_relation",
        -        "type": "string"
        -      },
        -      "range": {
        -        "description": "Entity-type names allowed as the target (range); must already exist",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "reducer": {
        -        "description": "State-reducer token, e.g. append_only (default), latest_wins",
        -        "type": "string"
        -      },
        -      "symmetric": {
        -        "type": "boolean"
        -      },
        -      "temporal_semantics": {
        -        "description": "Defaults to bitemporal",
        -        "enum": [
        -          "atemporal",
        -          "valid_time",
        -          "commit_time",
        -          "bitemporal"
        -        ],
        -        "type": "string"
        -      },
        -      "transitive": {
        -        "type": "boolean"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "name": {
        -        "description": "Display name of the new scalar property field, e.g. status (idempotent if it exists)",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "add_property",
        -        "type": "string"
        -      },
        -      "required": {
        -        "description": "Advisory required flag (not enforced on commit)",
        -        "type": "boolean"
        -      },
        -      "value_type": {
        -        "description": "Scalar type; defaults to text. Lets a later lbb_commit set entity_properties[].field",
        -        "enum": [
        -          "bool",
        -          "i64",
        -          "f64",
        -          "date_time",
        -          "keyword",
        -          "text",
        -          "bytes"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "from": {
        -        "description": "Current entity-type name",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "rename_entity_type",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "New display name (stable id stays frozen; records keep resolving)",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "from",
        -      "to"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "from": {
        -        "description": "Current relation name",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "rename_relation",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "New display name (stable id stays frozen; edges keep resolving)",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "from",
        -      "to"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "inverse_name": {
        -        "description": "Inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "set_relation_inverse",
        -        "type": "string"
        -      },
        -      "relation": {
        -        "description": "Relation to set the inverse on, by name",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "relation",
        -      "inverse_name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "cardinality": {
        -        "enum": [
        -          "one_to_one",
        -          "one_to_many",
        -          "many_to_one",
        -          "many_to_many"
        -        ],
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "set_relation_cardinality",
        -        "type": "string"
        -      },
        -      "relation": {
        -        "description": "Relation to change, by name",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "relation",
        -      "cardinality"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "narrow_relation",
        -        "type": "string"
        -      },
        -      "relation": {
        -        "description": "Relation to narrow, by name",
        -        "type": "string"
        -      },
        -      "remove_domain": {
        -        "description": "Entity-type names to remove from the relation's domain (subtractive)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "remove_range": {
        -        "description": "Entity-type names to remove from the relation's range (subtractive)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "relation"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "name": {
        -        "description": "Entity type to tombstone — kept readable for old records, rejected for new commits",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "remove_entity_type",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "name": {
        -        "description": "Relation to tombstone — old edges stay readable, rejected for new commits",
        -        "type": "string"
        -      },
        -      "op": {
        -        "const": "remove_relation",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "entity_type": {
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "add_super_types",
        +        "type": "string"
        +      },
        +      "super_types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "minItems": 1,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "entity_type",
        +      "super_types"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "add_domain": {
        +        "description": "Entity-type names to add to the relation's domain (source types)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "add_range": {
        +        "description": "Entity-type names to add to the relation's range (target types)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "op": {
        +        "const": "widen_relation",
        +        "type": "string"
        +      },
        +      "relation": {
        +        "description": "Relation to widen, by name (case-insensitive)",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "relation"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "name": {
        +        "description": "Display name of the new entity type (idempotent if it exists)",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "add_entity_type",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "cardinality": {
        +        "description": "Defaults to many_to_many",
        +        "enum": [
        +          "one_to_one",
        +          "one_to_many",
        +          "many_to_one",
        +          "many_to_many"
        +        ],
        +        "type": "string"
        +      },
        +      "domain": {
        +        "description": "Entity-type names allowed as the source (domain); must already exist",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "inverse_name": {
        +        "description": "Optional inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Display name of the new relation, e.g. HAS_PHASE",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "add_relation",
        +        "type": "string"
        +      },
        +      "range": {
        +        "description": "Entity-type names allowed as the target (range); must already exist",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "reducer": {
        +        "description": "State-reducer token, e.g. append_only (default), latest_wins",
        +        "type": "string"
        +      },
        +      "symmetric": {
        +        "type": "boolean"
        +      },
        +      "temporal_semantics": {
        +        "description": "Defaults to bitemporal",
        +        "enum": [
        +          "atemporal",
        +          "valid_time",
        +          "commit_time",
        +          "bitemporal"
        +        ],
        +        "type": "string"
        +      },
        +      "transitive": {
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "name": {
        +        "description": "Display name of the new scalar property field, e.g. status (idempotent if it exists)",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "add_property",
        +        "type": "string"
        +      },
        +      "required": {
        +        "description": "Advisory required flag (not enforced on commit)",
        +        "type": "boolean"
        +      },
        +      "value_type": {
        +        "description": "Scalar type; defaults to text. Lets a later lbb_commit set entity_properties[].field",
        +        "enum": [
        +          "bool",
        +          "i64",
        +          "f64",
        +          "date_time",
        +          "keyword",
        +          "text",
        +          "bytes"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "from": {
        +        "description": "Current entity-type name",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "rename_entity_type",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "New display name (stable id stays frozen; records keep resolving)",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "from",
        +      "to"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "from": {
        +        "description": "Current relation name",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "rename_relation",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "New display name (stable id stays frozen; edges keep resolving)",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "from",
        +      "to"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "inverse_name": {
        +        "description": "Inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "set_relation_inverse",
        +        "type": "string"
        +      },
        +      "relation": {
        +        "description": "Relation to set the inverse on, by name",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "relation",
        +      "inverse_name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "cardinality": {
        +        "enum": [
        +          "one_to_one",
        +          "one_to_many",
        +          "many_to_one",
        +          "many_to_many"
        +        ],
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "set_relation_cardinality",
        +        "type": "string"
        +      },
        +      "relation": {
        +        "description": "Relation to change, by name",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "relation",
        +      "cardinality"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "narrow_relation",
        +        "type": "string"
        +      },
        +      "relation": {
        +        "description": "Relation to narrow, by name",
        +        "type": "string"
        +      },
        +      "remove_domain": {
        +        "description": "Entity-type names to remove from the relation's domain (subtractive)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "remove_range": {
        +        "description": "Entity-type names to remove from the relation's range (subtractive)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "relation"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "name": {
        +        "description": "Entity type to tombstone — kept readable for old records, rejected for new commits",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "remove_entity_type",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "name": {
        +        "description": "Relation to tombstone — old edges stay readable, rejected for new commits",
        +        "type": "string"
        +      },
        +      "op": {
        +        "const": "remove_relation",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
      • removedInput schema / properties / relations / $ref
        Removed value: -"#/properties/entity_types"
      • addedInput schema / properties / relations / items
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "$ref": "#/properties/entity_types/items/anyOf/1"
        +    }
        +  ]
        +}
      • addedInput schema / properties / relations / type
        Added value: +"array"
    • Changedlbb_inspect5 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity, state, history, why, transitions)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "guide",
        -  "ontology",
        -  "ontology_conformance",
        -  "schema",
        -  "ontology_search",
        -  "metadata",
        -  "entity",
        -  "state",
        -  "history",
        -  "why",
        -  "transitions"
        -]New value: +[
        +  "guide",
        +  "ontology",
        +  "ontology_conformance",
        +  "schema",
        +  "graphs",
        +  "publication",
        +  "ontology_search",
        +  "metadata",
        +  "entity",
        +  "state",
        +  "history",
        +  "why",
        +  "transitions"
        +]
      • addedInput schema / properties / cursor
        Added value: +{
        +  "description": "Opaque lbb_inspect continuation. Repeat action and pass the returned next arguments; rejects changed metadata.",
        +  "type": "string"
        +}
      • addedInput schema / properties / page_size
        Added value: +{
        +  "description": "Maximum complete metadata entries per page; defaults to 50. Nested fields are never truncated; an oversized single entry returns serialized_json fragments to concatenate and parse.",
        +  "maximum": 500,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / section
        Added value: +{
        +  "description": "Optional top-level array to inspect, e.g. entity_type_defs, relation_defs, property_defs, classes, or relations. Omit to page through all sections.",
        +  "type": "string"
        +}
    • Changedlbb_query6 fields changed
      • changedInput schema / properties / as_of / description
        Previous value: -"Snapshot pin (valid-time, RFC3339): evaluate the body as of this instant. Folded into the request's `as_of_valid_time`. Top-level here is the supported spelling — a bare `as_of` inside the body is rejected, since the server silently ignores it."New value: +"Unsupported in structured and SPARQL text modes; use as_of_commit_seq for a retained commit snapshot."
      • changedInput schema / properties / body / description
        Previous value: -"Structured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning prefer the top-level `as_of` / `as_of_commit_seq` arguments below; a bare `as_of` key inside the body is rejected (the body's valid-time field is `as_of_valid_time`)."New value: +"Structured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning use the top-level `as_of_commit_seq` argument or the same body field. Valid-time `as_of` and `as_of_valid_time` selectors are unsupported and rejected before HTTP."
      • addedInput schema / properties / consistency
        Added value: +{
        +  "description": "Read consistency. strong requires publication through head; a pending response is retryable.",
        +  "enum": [
        +    "eventual",
        +    "strong"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / entailment
        Added value: +{
        +  "description": "Reasoning over the pinned RDF generation. Defaults to none. owl includes RDFS, inverse relationships and the supported OWL profile.",
        +  "enum": [
        +    "none",
        +    "subclass",
        +    "rdfs",
        +    "owl"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / min_indexed_seq
        Added value: +{
        +  "description": "Read-after-write publication floor. Preserved across cursor pages.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • changedInput schema / properties / query / description
        Previous value: -"SPARQL 1.1 query text (SELECT or ASK). IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with rdfs:subClassOf closure on by default. Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10"New value: +"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10"
    • Addedlbb_rdf
  7. 5 tool updatesv0.4.2
    • Removedlbb_decode
    • Removedlbb_ground
    • Changedlbb_inspect5 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, traverse, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, transitions)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "guide",
        -  "ontology",
        -  "ontology_conformance",
        -  "schema",
        -  "ontology_search",
        -  "metadata",
        -  "entity",
        -  "state",
        -  "history",
        -  "why",
        -  "traverse",
        -  "transitions"
        -]New value: +[
        +  "guide",
        +  "ontology",
        +  "ontology_conformance",
        +  "schema",
        +  "ontology_search",
        +  "metadata",
        +  "entity",
        +  "state",
        +  "history",
        +  "why",
        +  "transitions"
        +]
      • removedInput schema / properties / direction
        Removed value: -{
        -  "enum": [
        -    "out",
        -    "in",
        -    "both"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / max_hops
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "maximum": 6,
        -  "type": "integer"
        -}
      • removedInput schema / properties / relations
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
    • Changedlbb_query2 fields changed
      • changedInput schema / properties / body / description
        Previous value: -"Structured SPARQL-subset or analytics request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }); it is evaluated only on this grouped path, NOT alongside `combinators` (UNION/OPTIONAL/MINUS), which route to the analytics engine. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning prefer the top-level `as_of` / `as_of_commit_seq` arguments below; a bare `as_of` key inside the body is rejected (the body's valid-time field is `as_of_valid_time`)."New value: +"Structured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning prefer the top-level `as_of` / `as_of_commit_seq` arguments below; a bare `as_of` key inside the body is rejected (the body's valid-time field is `as_of_valid_time`)."
      • changedInput schema / properties / metric / enum
        Previous value: -[
        -  "entity_types",
        -  "relations",
        -  "overview",
        -  "facets",
        -  "sparql"
        -]New value: +[
        +  "entity_types",
        +  "relations",
        +  "overview",
        +  "sparql"
        +]
    • Removedlbb_search
  8. 8 tool updatesv0.2.7
    • Removedlbb_ask
    • Changedlbb_configure6 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: define_ontology, define_rules, publish_schema, evolve_ontology)."New value: +"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "define_ontology",
        -  "define_rules",
        -  "publish_schema",
        -  "evolve_ontology"
        -]New value: +[
        +  "define_ontology",
        +  "publish_schema",
        +  "evolve_ontology"
        +]
      • removedInput schema / properties / confirm_empty
        Removed value: -{
        -  "type": "boolean"
        -}
      • changedInput schema / properties / desired_mode / enum
        Previous value: -[
        -  "warn",
        -  "reject"
        -]New value: +[
        +  "off",
        +  "warn",
        +  "reject"
        +]
      • removedInput schema / properties / preview_digest
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / rules
        Removed value: -{
        -  "items": {
        -    "additionalProperties": true,
        -    "properties": {
        -      "body": {
        -        "description": "The condition: a basic graph pattern over current edges (asserted + already-derived), joined on shared variables. Terms may be variables or fixed entities.",
        -        "items": {
        -          "additionalProperties": true,
        -          "properties": {
        -            "object": {
        -              "$ref": "#/properties/rules/items/properties/body/items/properties/subject",
        -              "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)"
        -            },
        -            "predicate": {
        -              "description": "Relation name. In a rule body, the reserved \"rdf:type\" makes a type-membership constraint: the object names a class ({ entity: { entity_type: \"Contact\" } }, no name) and matches every entity of that class and its subtypes (rdfs:subClassOf closure), so one rule keyed on a supertype fires for all subtypes. Not allowed in a head or an exists/not_exists filter.",
        -              "type": "string"
        -            },
        -            "subject": {
        -              "anyOf": [
        -                {
        -                  "additionalProperties": true,
        -                  "properties": {
        -                    "var": {
        -                      "description": "A variable, joined across patterns by name",
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "var"
        -                  ],
        -                  "type": "object"
        -                },
        -                {
        -                  "additionalProperties": true,
        -                  "properties": {
        -                    "entity": {
        -                      "additionalProperties": true,
        -                      "properties": {
        -                        "entity_id": {
        -                          "description": "Entity id (hex), as an alternative to type+name",
        -                          "type": "string"
        -                        },
        -                        "entity_type": {
        -                          "description": "Entity type name (with `name`, names a fixed entity)",
        -                          "type": "string"
        -                        },
        -                        "name": {
        -                          "description": "Entity name (paired with `entity_type`)",
        -                          "type": "string"
        -                        }
        -                      },
        -                      "type": "object"
        -                    }
        -                  },
        -                  "required": [
        -                    "entity"
        -                  ],
        -                  "type": "object"
        -                }
        -              ],
        -              "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)"
        -            }
        -          },
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "combinators": {
        -        "description": "exists/not_exists filters folded over the body. not_exists is stratified negation — it lets a rule express a universal condition, e.g. derive \"phase complete\" only when not_exists an incomplete deliverable. A negation cycle is rejected.",
        -        "items": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "properties": {
        -                "exists": {
        -                  "items": {
        -                    "$ref": "#/properties/rules/items/properties/body/items"
        -                  },
        -                  "type": "array"
        -                }
        -              },
        -              "required": [
        -                "exists"
        -              ],
        -              "type": "object"
        -            },
        -            {
        -              "additionalProperties": true,
        -              "properties": {
        -                "not_exists": {
        -                  "items": {
        -                    "$ref": "#/properties/rules/items/properties/body/items"
        -                  },
        -                  "type": "array"
        -                }
        -              },
        -              "required": [
        -                "not_exists"
        -              ],
        -              "type": "object"
        -            }
        -          ],
        -          "description": "An existence filter over the body solutions: { exists: [...] } (semijoin — keep rows with a compatible match) or { not_exists: [...] } (negation/antijoin — keep rows with none)"
        -        },
        -        "type": "array"
        -      },
        -      "head": {
        -        "$ref": "#/properties/rules/items/properties/body/items",
        -        "description": "The triple derived once per body solution. Every head variable must be bound by the body; a fixed-entity object derives a constant (e.g. set the rolled-up status to the Complete entity)."
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "order": {
        -        "description": "Run order, low to high (a determinism hint)",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
    • Changedlbb_decode5 fields changed
      • removedInput schema / properties / source_name / description
        Removed value: -"Source entity display name"
      • removedInput schema / properties / source_type / description
        Removed value: -"Source entity type; omit to have the DB recover it from the name"
      • removedInput schema / properties / target_name / description
        Removed value: -"Target entity display name"
      • removedInput schema / properties / target_type / description
        Removed value: -"Target entity type; omit to have the DB recover it from the name"
      • removedInput schema / properties / use_model_when_forced / description
        Removed value: -"Call the model even when the type pair forces one relation (default false — a forced pair is answered by the DB alone)"
    • Changedlbb_ground5 fields changed
      • removedInput schema / properties / action / description
        Removed value: -"complete = narrowed vocabulary autocomplete; resolve = snap free text to the nearest real vocabulary; audit = groundability report"
      • changedInput schema / properties / kinds / description
        Previous value: -"[complete/resolve] Restrict to these vocabulary kinds (default: all)"New value: +"Restrict to these vocabulary kinds (default: all)"
      • changedInput schema / properties / sample / description
        Previous value: -"[audit] Entities to sample for narrowing-recall"New value: +"[audit] Entities sampled for narrowing recall"
      • changedInput schema / properties / text / description
        Previous value: -"[resolve] Free text to snap to the nearest real vocabulary item"New value: +"[resolve] Free text to resolve"
      • changedInput schema / properties / top_k / description
        Previous value: -"[complete/resolve] Max results (default 8)"New value: +"Max results (default 8)"
    • Removedlbb_index
    • Changedlbb_inspect12 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, schema_audit, rules, schema_preview, ontology_search, metadata, entity, edges, state, history, why, traverse, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, traverse, transitions)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "guide",
        -  "ontology",
        -  "ontology_conformance",
        -  "schema",
        -  "schema_audit",
        -  "rules",
        -  "schema_preview",
        -  "ontology_search",
        -  "metadata",
        -  "entity",
        -  "edges",
        -  "state",
        -  "history",
        -  "why",
        -  "traverse",
        -  "transitions"
        -]New value: +[
        +  "guide",
        +  "ontology",
        +  "ontology_conformance",
        +  "schema",
        +  "ontology_search",
        +  "metadata",
        +  "entity",
        +  "state",
        +  "history",
        +  "why",
        +  "traverse",
        +  "transitions"
        +]
      • removedInput schema / properties / base_ontology_version
        Removed value: -{
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / base_shapes_version
        Removed value: -{
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / cursor
        Removed value: -{
        -  "description": "Opaque cursor from the previous page's `next_cursor`. The response is the unified list envelope { object:'list', data, has_more, next_cursor, total_count }; page a high-degree node (entity detail hard-caps its edge sample) by feeding next_cursor back here until has_more is false. Each row carries valid_time for a per-edge timeline.",
        -  "type": "string"
        -}
      • removedInput schema / properties / desired_mode
        Removed value: -{
        -  "enum": [
        -    "warn",
        -    "reject"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / direction / description
        Removed value: -"Edges out of / into / touching the entity (default both)."
      • removedInput schema / properties / offset
        Removed value: -{
        -  "description": "Legacy alias for `cursor` (still accepted); prefer paging with `cursor`.",
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / ontology
        Removed value: -{
        -  "additionalProperties": false,
        -  "properties": {
        -    "format": {
        -      "enum": [
        -        "auto",
        -        "turtle",
        -        "json_ld",
        -        "rdf_xml",
        -        "csv",
        -        "tsv",
        -        "lbb_json",
        -        "spec"
        -      ],
        -      "type": "string"
        -    },
        -    "source": {
        -      "description": "Ontology source text",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "source"
        -  ],
        -  "type": "object"
        -}
      • removedInput schema / properties / relation / description
        Removed value: -"Filter to a single relation name."
      • removedInput schema / properties / row_limit
        Removed value: -{
        -  "description": "Max edges returned this page (server caps at 1000; default 150).",
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / shapes
        Removed value: -{
        -  "additionalProperties": false,
        -  "properties": {
        -    "format": {
        -      "enum": [
        -        "auto",
        -        "turtle",
        -        "n_triples",
        -        "n_quads",
        -        "trig"
        -      ],
        -      "type": "string"
        -    },
        -    "source": {
        -      "description": "SHACL/RDF shape source text",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "source"
        -  ],
        -  "type": "object"
        -}
    • Addedlbb_models
    • Changedlbb_query16 fields changed
      • removedInput schema / properties / anchor_name
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / anchor_type
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / explain
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / include_derived
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / max_derived
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / max_premises
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / max_rounds
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / max_solutions
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • changedInput schema / properties / mode / description
        Previous value: -"Selects the variant (one of: structured, sparql, shacl, infer, retrieval_premises, analyze)."New value: +"Selects the variant (one of: structured, sparql, analyze)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "structured",
        -  "sparql",
        -  "shacl",
        -  "infer",
        -  "retrieval_premises",
        -  "analyze"
        -]New value: +[
        +  "structured",
        +  "sparql",
        +  "analyze"
        +]
      • removedInput schema / properties / query_top_k
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / relation
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / rules
        Removed value: -{
        -  "items": {
        -    "additionalProperties": true,
        -    "properties": {
        -      "body": {
        -        "description": "The condition: a basic graph pattern over current edges (asserted + already-derived), joined on shared variables. Terms may be variables or fixed entities.",
        -        "items": {
        -          "additionalProperties": true,
        -          "properties": {
        -            "object": {
        -              "$ref": "#/properties/rules/items/properties/body/items/properties/subject",
        -              "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)"
        -            },
        -            "predicate": {
        -              "description": "Relation name. In a rule body, the reserved \"rdf:type\" makes a type-membership constraint: the object names a class ({ entity: { entity_type: \"Contact\" } }, no name) and matches every entity of that class and its subtypes (rdfs:subClassOf closure), so one rule keyed on a supertype fires for all subtypes. Not allowed in a head or an exists/not_exists filter.",
        -              "type": "string"
        -            },
        -            "subject": {
        -              "anyOf": [
        -                {
        -                  "additionalProperties": true,
        -                  "properties": {
        -                    "var": {
        -                      "description": "A variable, joined across patterns by name",
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "var"
        -                  ],
        -                  "type": "object"
        -                },
        -                {
        -                  "additionalProperties": true,
        -                  "properties": {
        -                    "entity": {
        -                      "additionalProperties": true,
        -                      "properties": {
        -                        "entity_id": {
        -                          "description": "Entity id (hex), as an alternative to type+name",
        -                          "type": "string"
        -                        },
        -                        "entity_type": {
        -                          "description": "Entity type name (with `name`, names a fixed entity)",
        -                          "type": "string"
        -                        },
        -                        "name": {
        -                          "description": "Entity name (paired with `entity_type`)",
        -                          "type": "string"
        -                        }
        -                      },
        -                      "type": "object"
        -                    }
        -                  },
        -                  "required": [
        -                    "entity"
        -                  ],
        -                  "type": "object"
        -                }
        -              ],
        -              "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)"
        -            }
        -          },
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "combinators": {
        -        "description": "exists/not_exists filters folded over the body. not_exists is stratified negation — it lets a rule express a universal condition, e.g. derive \"phase complete\" only when not_exists an incomplete deliverable. A negation cycle is rejected.",
        -        "items": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": true,
        -              "properties": {
        -                "exists": {
        -                  "items": {
        -                    "$ref": "#/properties/rules/items/properties/body/items"
        -                  },
        -                  "type": "array"
        -                }
        -              },
        -              "required": [
        -                "exists"
        -              ],
        -              "type": "object"
        -            },
        -            {
        -              "additionalProperties": true,
        -              "properties": {
        -                "not_exists": {
        -                  "items": {
        -                    "$ref": "#/properties/rules/items/properties/body/items"
        -                  },
        -                  "type": "array"
        -                }
        -              },
        -              "required": [
        -                "not_exists"
        -              ],
        -              "type": "object"
        -            }
        -          ],
        -          "description": "An existence filter over the body solutions: { exists: [...] } (semijoin — keep rows with a compatible match) or { not_exists: [...] } (negation/antijoin — keep rows with none)"
        -        },
        -        "type": "array"
        -      },
        -      "head": {
        -        "$ref": "#/properties/rules/items/properties/body/items",
        -        "description": "The triple derived once per body solution. Every head variable must be bound by the body; a fixed-entity object derives a constant (e.g. set the rolled-up status to the Complete entity)."
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "order": {
        -        "description": "Run order, low to high (a determinism hint)",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedInput schema / properties / shacl_mode
        Removed value: -{
        -  "description": "select returns focus nodes; validate returns a report",
        -  "enum": [
        -    "select",
        -    "validate"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / shapes
        Removed value: -{
        -  "items": {
        -    "$ref": "#/properties/body"
        -  },
        -  "type": "array"
        -}
      • removedInput schema / properties / threshold
        Removed value: -{
        -  "maximum": 1,
        -  "minimum": 0,
        -  "type": "number"
        -}
  9. 11 tool updatesv0.2.1
    • First observedlbb_ask
    • First observedlbb_branch
    • First observedlbb_commit
    • First observedlbb_configure
    • First observedlbb_decode
    • First observedlbb_ground
    • First observedlbb_index
    • First observedlbb_inspect
    • First observedlbb_observe
    • First observedlbb_query
    • First observedlbb_search

TDQS

A3.9/5.0

Scored across 19 tools

Disambiguation4/5

Each tool maps to a distinct domain (inspect, query, commit, workflows, fit sources, embeddings, evals, model choice) and read/manage/delete variants are explicitly separated, so misselection is limited. Some overlap remains between lbb_inspect and lbb_query for ontology/schema reads and among the model-related tools, but the descriptions provide clear routing guidance.

Naming Consistency4/5

All names use the lbb_ prefix and snake_case, and several domains follow a resource_then_manage/delete pattern (lbb_workflows, lbb_workflows_manage, lbb_workflows_delete). Deviations come from action-oriented names (lbb_inspect, lbb_query, lbb_commit, lbb_configure, lbb_rdf) that do not follow a strict verb_noun convention, but the set remains predictable.

Tool Count4/5

19 tools is slightly above the ideal 3-15 band but reasonable for a platform spanning graph reads, queries, writes, schema/RDF, workflows, embeddings, fit sources, evals, and model choice. The read/manage/delete splits add count but are functional rather than redundant.

Completeness4/5

The surface covers the main lifecycle areas: querying and inspection, fact/RDF writes, schema configuration, workflow/fit/embedding management, evals, and model trials. Minor gaps exist, such as no RDF deletion (additive updates only) and no full graph/fact deletion beyond single-fact retraction, but agents can work around them.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that enables AI-powered exploration of RDF data and SPARQL querying via RDF4J. It provides tools for executing queries, searching knowledge graph resources, and retrieving schema summaries.
    13
    1
    MIT