Knowledge graph API
Ask the knowledge graph over HTTP and read its markdown or agent-mode JSON answer line by line.
On for every workspace. GET /v1/knowledge-graph/ask needs the
knowledge:read scope and no plan feature. A workspace connected yesterday
has an almost empty graph, so early answers are thin.
nima keeps one knowledge graph per workspace. Its entities are the things a
product is made of, its relationships connect them, and each entity carries
sourced facts. This page is the reference for the one graph route a personal
API key or OAuth token can call. For what the graph is and how it learns, see
How nima knows your product. The same call
is the ask_knowledge_graph MCP tool, documented on
Knowledge tools.
The graph has 12 entity types: feature, user_need, technical_decision,
constraint, requirement, discovered_concept, person, customer,
product, goal, signal and organization. It has 17 relationship types:
implements, depends_on, requested, owns, part_of, prioritized_by,
signals, contacted_about, decided_by, constrained_by, specified_by,
contradicts, supersedes, relates_to, blocks, enables and serves.
Every fact names its source with one of 13 labels: SPEC, PR, COMMIT,
SIGNAL, SLACK, PR_REVIEW, QA_RESPONSE, CODE_INDEX, PM_INPUT,
MARKETING_PAGE, INFERRED, WEB_RESEARCH and CRM_RECORD.
Knowledge graph API operations at a glance
| Method | Path | Scope | MCP tool |
|---|---|---|---|
GET | /v1/knowledge-graph/ask | knowledge:read | ask_knowledge_graph |
Ask the knowledge graph over REST (GET /v1/knowledge-graph/ask)
/v1/knowledge-graph/askknowledge:readMCP toolask_knowledge_graphGET /v1/knowledge-graph/ask answers a natural-language question about your
product, customers and past decisions from the workspace's knowledge graph.
There is no workspace parameter: the answer covers the one workspace your
token belongs to. By default the response is text/markdown; charset=utf-8,
not JSON. With mode=agent it is compact JSON.
The route sits on the soft rate-limit tier, 300 requests per 10 seconds. The
path is relative to https://api.getnima.io, and the call carries
Authorization: Bearer <your key>. See
Authentication and
Scopes and permissions.
The markdown answer has no schema. It is a rendering: lines can be added and
their wording can change without a version bump, so parse it defensively, or
ask for mode=agent when the caller is a program.
Query parameters for the knowledge graph ask route
qstringrequiredSearched in English line.limitinteger8 by default. It counts entities, not facts.modestringagent is accepted. It returns compact JSON instead of markdown: no prose, no stale-summary line, no cap on facts or relations. Any other value is a 400.The workspace is always the caller's own. A token with no workspace gets 403
INSUFFICIENT_PERMISSIONS with the message Must belong to an organization.
Errors from the knowledge graph ask route
| Status | error | When |
|---|---|---|
400 | Bad Request | q missing, under 2 or over 500 characters; limit outside 1 to 20 or not a whole number; mode anything but agent. |
401 | TOKEN_INVALID | No token, or one that is malformed, expired or revoked. |
403 | INSUFFICIENT_PERMISSIONS | The token does not carry knowledge:read, or the token has no workspace. |
429 | RATE_LIMITED | Over 300 requests in 10 seconds. The response carries Retry-After. |
503 | SERVICE_UNAVAILABLE | Something nima depends on failed. Retry. |
Errors has the envelope and what is worth retrying; Rate limits has the bucket rules.
Knowledge graph markdown answer format
The default answer is markdown, and every line in it is one of the shapes below. They appear in this order for each entity, and only the lines that apply are printed.
The first lines describe the whole answer.
Searched in English: "…" (translated from …)preambleKnowledge graph results for: "…"title⚠ No entity in the graph is named "x". Everything below is a semantic neighbour…warningSCREAMING_SNAKE constant, a snake_case key, a ticket key such as BCN-23, "PR #80", or anything in quotes) and no returned entity carries it. The entities that follow are look-alikes, not the thing named.Then one block per entity.
### Name (type) [modality] (match tag) · id: uuidheadertype is one of the 12 entity types. The bracketed modality is one word and is left out when nima cannot judge: implemented or fixed means the graph has evidence the thing is in the code, proposal means it was asked for or specced and never confirmed built, problem means a report that something is wrong. The match tag is (exact), (exact: fact <key>) (for example (exact: fact owner)) when a fact carries the literal you named, (mentioned in fact <key>) when only a hyphenated lowercase word such as code-intel appears in a fact, (no exact match) when you named a literal and this entity is not it, and nothing for a question that named no literal. After the dot comes the entity's own uuid.References: N | Similarity: 0.NNNentity0.000 means the entity was found by literal text and has no embedding score.⚠ Superseded by names — the facts below describe how this used to work…banner⚠ NOT SHIPPED: this pull request was closed without merging…banner⚠ NOT SHIPPED YET: this pull request is still open…. A merged pull request prints nothing.Summary: …entity⚠ Summary is stale since timestamp; verify against the source facts.warningFacts:section … N more facts omitted. Facts carrying a literal you named come first. On customer and organization entities the account facts follow them, in this order: lifecycle, arr, plan, renewal_date, account_owner, segment. Bookkeeping facts from the code index (fileCount, cohesionScore, detectionMethod) are hidden. - key: value (source: …, learned YYYY-MM-DD)factTYPE https://… when the source has a single URL, as bare CODE_INDEX for code-index facts, and otherwise as TYPE:id.[customer] · [external] · [internal] · [internal channel]origin tagSIGNAL fact, and after the quoted evidence of a relation a signal asserted: who the signal came from. internal channel is a Slack signal nobody classified, which says where it was posted, not who wrote it.⚠ ASSUMED — the source hedged this; not confirmed by a humanfact suffix(confirmed) instead. A fact with neither has no suffix.— "…"fact suffix….⚠ contradicted: key "A" (source) vs "B" (source), YYYY-MM-DDwarning… N more unresolved conflicts omitted., flush left.Relations:section … N more relations omitted. - relation → Name (type) — "evidence"outgoing relation - ← Name (type) relation this — "evidence"incoming relation← Streaming importer (feature) supersedes this reads "Streaming importer supersedes this entity". Always read the arrow together with the words around it.⚠ NOT SHIPPED / NOT SHIPPED YET: asserted by a pull request…relation suffixKnowledge graph agent-mode JSON
mode=agent returns one JSON object. Its fields are the same information as
the markdown, without prose, without the five-line caps, and without raw
source ids.
querystringqueryTranslationobjectoriginal, english, translated (boolean) and sourceLanguage (string or null).identifiersstring[]match is exact means the graph does not hold the thing named.entitiesobject[]entities[].id, name, entityType, similarityfieldsentities[].summarystring | nullnull.entities[].modalitystringimplemented, fixed, proposal, problem or unknown.entities[].matchstringexact, semantic (the question named no literal, or only hyphenated lowercase words such as code-intel) or none (the question named a literal such as a path, symbol, constant, ticket key or quoted text, and this entity carries none of them). matchedFactKey names the fact that carried it, and matchVia: "fact_mention" marks a hyphenated lowercase word found only in a fact.entities[].supersededBystring[]entities[].prLifecyclestring | nullmerged, closed_unmerged or open when the entity is itself a pull request, otherwise null.entities[].factsobject[]key, value, confidence, sourceType, sourceUrl (or null), sourceExcerpt (or null), learnedAt (YYYY-MM-DD), confirmationState (assumed, confirmed or null) and, for a SIGNAL source, origin (customer, external, internal or internal_channel).entities[].relationsobject[]relationType, targetName, targetType, targetEntityId (or null), evidence, direction (out when this entity is the subject, in when it is the object), prLifecycle (merged, closed_unmerged, open or null), prMergeSha (or null) and optionally origin.entities[].conflictsobject[]key, valueA, valueB and detectedAt.If the question could not be embedded, agent mode answers 200 with
{"query": "…", "entities": [], "identifiers": []}.
Knowledge graph ranking and empty answers
Entities do not come back in strict order of similarity, and an empty answer
is a 200, not an error. Nima ranks by cosine similarity between your
question and each entity's summary, then adjusts.
- An entity whose name or alias appears in the question gets a large boost, and a near-miss spelling gets a smaller one.
- An entity whose facts all came from the code index is ranked lower, and so is an entity a newer one supersedes.
- When the question names a literal, every entity that carries it is returned first.
- Vector matches must reach a similarity of
0.6. Name and alias matches and exact-literal carriers skip that floor, and a literal-text fallback can return entities withSimilarity: 0.000. So a0.000hit is found by wording, not by meaning.
When nothing qualifies, the status is 200, the type is text/markdown, and
the body is:
No product entities found for: "why did we drop the legacy importer". The knowledge graph may not have information about this area yet.If the question could not be turned into a vector, the status is also 200
and the body is:
Could not generate an embedding for: "why did we drop the legacy importer". No knowledge graph results.Neither case is an error, so a client that only checks the status treats both
as an answer. Test for a line that starts with one of these two sentences (a translated question puts a Searched in English: line above it), or for the absence of a ### line.
Nothing coming back is not proof that nothing is there: the graph holds only
what your connected tools have told nima, and a proposal modality must not be
read as shipped.
Knowledge graph routes not reachable with a key
GET /v1/knowledge-graph/ask is the only knowledge graph route an API key or
OAuth token can use. The other graph routes take a signed-in browser session
only: a bearer token gets 403 INSUFFICIENT_PERMISSIONS with the message
This endpoint does not accept OAuth access tokens, whatever scopes it
carries. That covers drawing the graph, opening a single entity, searching
entities by name, and the change journal with its undo, which is limited to
workspace owners and admins. No route creates or edits a fact directly, and
the web app has no graph page. Ask the nima team if you need one of these.
The knowledge:read scope also opens code search, blast radius and data model
lookups under /v1/code-intel/. They answer JSON and are documented on
Code intelligence API.