lema · docs · api

Ask & retrieve

Two ways to query the graph: /ask returns one synthesized answer whose every sentence is grounded in a numbered, cited claim — /retrievereturns the ranked claims themselves, for callers assembling their own context. Both carry the token-ROI meter: what was served against what you didn’t have to load.

POST

/ask

POST/ask

Ask your graph

One synthesized, cited answer over your decision graph. Every [n] marker in the answer maps to sources[n-1] — the claim it was grounded in, with its source ref and stable decision id. When nothing recorded answers the question, the answer says so plainly and sources is empty — the meter reads zero rather than dressing up a guess.

auth · decisions:readquota · Counts as one MCP query (the ask side of the daily wallet).

Request body

querystringrequired
The natural-language question about your decisions.
workspace_idsstring[]
Optional workspace UUIDs to focus the answer. Omitted, the answer draws on every workspace you can see.

Response

scopestring
The workspaces the answer drew on.
answerstring
The synthesized answer, with inline [n] citation markers.
sourcesobject[]
One entry per citation, ordered so sources[i].n = i+1. Always present — empty when the answer is an honest abstention.
sources[].ninteger
The citation number the answer refers to.
sources[].refstring
The source ref, e.g. an ADR number or PR.
sources[].typestring
The claim type: chosen, rejected, constraint, or consequence.
sources[].textstring
The claim — summarized from the record, never a verbatim quote.
sources[].statusstring
The decision status, e.g. accepted or superseded.
sources[].workspacestring
Which workspace the claim came from.
sources[].locatorstring · optional
A finer pointer into the source, when one exists.
sources[].urlstring · optional
The source document URL, when known.
sources[].edgesobject[] · optional
Typed edges off the cited decision: { type, ref } — supersedes, superseded_by, depends_on, related_to.
sources[].rejected_alternativesstring[] · optional
The alternatives the cited decision ruled out.
sources[].relevancenumber · optional
Relevance to the query — relevance, not confidence. Measured per call.
sources[].decision_idstring · optional
The stable decision UUID. On this authed surface it is the key you keep — decision_url is never set over a private corpus.
usage.atoms_tokensinteger
Tokens in the claims actually served.
usage.source_decisionsinteger
How many source decisions those claims cite.
usage.source_tokensinteger
Tokens in the full source documents behind them — what you did not have to load.
usage.tokens_savedinteger
source_tokens minus atoms_tokens. Conservative: only sources lema can size are counted.
usage.compression_rationumber
source_tokens over atoms_tokens, measured per call.
synthesis_tokens_in / synthesis_tokens_outinteger
The synthesis cost of this call — the other side of the meter.

Errors

  • 400query missing, malformed workspace UUID, or an unknown JSON field.
  • 403a requested workspace exists but is not yours to see.
  • 429the daily MCP-query wallet is spent — the structured limit signal below.
  • 501this deployment is not configured to answer.

Honest abstention is first-class: when nothing recorded clears the relevance floor, the answer states the gap, sources is [], and the usage meter is zero — the citations never contradict the answer.

A caller with no workspaces yet gets a 200 with scope "no workspaces" and an explanatory answer, not an error.

$ curl https://api.lema.sh/ask \
  -H "Authorization: Bearer $LEMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "why is the ledger service split from the monolith?"}'
response shape
{
  "scope": "<the workspaces answered over>",
  "answer": "Split after the double-write incident: audit writes
             require serializable transactions [1]. Re-merging was
             argued and ruled out [2].",
  "sources": [
    {
      "n": 1,
      "ref": "ADR-0019",
      "type": "chosen",
      "text": "<summarized from the record — never a verbatim quote>",
      "status": "accepted",
      "workspace": "payments-api",
      "decision_id": "<stable uuid>"
    }
  ],
  "usage": {
    "atoms_tokens": …, "source_decisions": …, "source_tokens": …,
    "tokens_saved": …, "compression_ratio": …
  },
  "synthesis_tokens_in": …,
  "synthesis_tokens_out": …
}

POST

/retrieve

POST/retrieve

Retrieve raw claims

/ask minus the synthesis: the ranked, typed claims themselves plus the token-ROI meter, for callers that build their own context. No relevance floor is applied — you get the top-k as ranked and weigh relevance yourself.

auth · decisions:readquota · Counts as one MCP query (the retrieve side of the daily wallet).

Request body

querystringrequired
What to find.
workspace_idsstring[]
Optional workspace UUIDs to search. Omitted, every workspace you can see.
kinteger
Maximum claims to return. Default 8; values outside 1–50 fall back to the default.

Response

scopestring
The workspaces searched.
atomsobject[]
The ranked claims. Each carries type, ref, text (summarized, never quoted), and — when present — locator, status, workspace, edges, rejected_alternatives.
usage.atoms_tokensinteger
Tokens in the claims actually served.
usage.source_decisionsinteger
How many source decisions those claims cite.
usage.source_tokensinteger
Tokens in the full source documents behind them — what you did not have to load.
usage.tokens_savedinteger
source_tokens minus atoms_tokens. Conservative: only sources lema can size are counted.
usage.compression_rationumber
source_tokens over atoms_tokens, measured per call.

Errors

  • 400query missing, malformed workspace UUID, or an unknown JSON field.
  • 403a requested workspace exists but is not yours to see.
  • 429the daily MCP-query wallet is spent.
  • 501this deployment is not configured to answer.

The ROI baseline is conservative: it sizes only the source documents it can resolve (ADR-form refs), so tokens_saved understates rather than inflates.

$ curl https://api.lema.sh/retrieve \
  -H "Authorization: Bearer $LEMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "audit log constraints", "k": 8}'
response shape
{
  "scope": "<the workspaces searched>",
  "atoms": [
    {
      "type": "constraint",
      "ref": "ADR-0019",
      "text": "<summarized from the record — never a verbatim quote>",
      "status": "accepted",
      "workspace": "payments-api"
    }
  ],
  "usage": {
    "atoms_tokens": …, "source_decisions": …, "source_tokens": …,
    "tokens_saved": …, "compression_ratio": …
  }
}