lema · docs · api
Check
The never-reopen surface. /check-approach adjudicates one named direction against your recorded deliberation and returns a typed verdict — a recorded rejection with its cited why-not, or an honest unknown. /closed-atoms hands you the entire closed set instead, so a local guard can run on every edit without a network call.
POST
/check-approach
/check-approachCheck an approach
Adjudicates one named approach against your own recorded deliberation. Exactly two verdicts can fire on this surface: ruled_out — a recorded rejection governs, with the cited why-not — or no_recorded_ruling, the honest unknown. When nothing was ruled out but the record holds the reasoning, the no_recorded_ruling carries a cited why: the recorded rationale, kept distinct from a ruling.
Request body
approachstringrequired- The direction to check against your record.
workspace_idsstring[]- Optional workspace UUIDs to check against. Omitted, every workspace you can see.
Response
repostring- The scope label the check ran over.
approachstring- Your approach, echoed.
verdictstring- ruled_out or no_recorded_ruling — nothing else fires on this surface.
why_notstring · optional- On ruled_out only: the recorded why-not, summarized and cited. Never co-present with why.
whystring · optional- On no_recorded_ruling only, when the record holds reasoning: the recorded rationale — not a ruling, not approval.
sourcesobject[]- The citations behind the verdict: n, ref, type, text (summarized), plus optional url, binding_cosine (relevance, not confidence — measured per call), decision_id.
howobject- The forward pointer, when the record holds one: guidance and/or the sanctioned alternative, with its own citation when grounded.
notestring · optional- The honesty note telling the agent how to treat the verdict.
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.
Errors
400approach 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.
Precision-safe by construction: an ungrounded match degrades to the honest no_recorded_ruling — never an ungrounded ruled_out over your record.
why_not and why are mutually exclusive: a ruled_out never carries why; a no_recorded_ruling never carries why_not.
A bare abstain returns sources: [] and the explicit note that absence is NOT approval.
decision_url is never set over a private corpus — decision_id is the stable key you keep.
$ curl https://api.lema.sh/check-approach \
-H "Authorization: Bearer $LEMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"approach": "re-merge the ledger service into the monolith"}'{
"repo": "<the workspaces checked>",
"approach": "re-merge the ledger service into the monolith",
"verdict": "ruled_out",
"why_not": "<the recorded why-not — summarized, never a verbatim quote>",
"sources": [
{
"n": 1,
"ref": "ADR-0019",
"type": "rejected",
"text": "<the killed option, with why it was killed>",
"decision_id": "<stable uuid>"
}
],
"how": { "guidance": "<the sanctioned alternative, when recorded>" },
"note": "this approach touches a recorded rejection — surface the
why-not and its citation, do not re-propose it",
"usage": { "atoms_tokens": …, "source_decisions": …, "source_tokens": …,
"tokens_saved": …, "compression_ratio": … },
"synthesis_tokens_in": …,
"synthesis_tokens_out": …
}GET
/closed-atoms
/closed-atomsThe closed set
Your org's CLOSED no-go set: every rejected alternative of an accepted, non-superseded decision, as one atom each. This is what hosted check_decided adjudicates against locally — fetch it once per session and the never-reopen guard runs without a network call per edit.
Query parameters
workspace_idsstring · repeatable or comma-joined- ?workspace_ids=A&workspace_ids=B or ?workspace_ids=A,B. Absent, every workspace you can see.
Response
atomsobject[]- The closed set, newest first, capped at 500.
atoms[].idstring- The atom id.
atoms[].typestring- The claim type — rejected, for this set.
atoms[].textstring- The recorded rejection, summarized.
atoms[].refstring- The governing decision ref.
atoms[].locatorstring · optional- A finer pointer into the source.
atoms[].closedboolean- Always true here — this is the never-reopen set.
atoms[].closed_notestring- The human explanation of why the option is closed.
atoms[].match_keystring- The killed option's name — the ONLY text the guard keys on, so rationale prose can never false-fire a block.
atoms[].workspacestring · optional- Which workspace it came from.
truncatedboolean · optional- Present and true only when the 500-atom cap was hit — a partial no-go set is never silently passed off as complete.
Errors
400a malformed workspace UUID.403a requested workspace exists but is not yours to see.429the daily MCP-query wallet is spent.
A caller with no workspaces gets 200 with atoms: [] — an empty record is a state, not an error.
$ curl "https://api.lema.sh/closed-atoms" \
-H "Authorization: Bearer $LEMA_API_TOKEN"{
"atoms": [
{
"id": "<atom id>",
"type": "rejected",
"text": "<the recorded rejection, summarized>",
"ref": "ADR-0019",
"closed": true,
"closed_note": "<why this option is closed>",
"match_key": "<the killed option's name>",
"workspace": "payments-api"
}
]
}