Your application's domain can be asked questions in ordinary English. EARL answers only from the facts the domain learned from your documents, shows exactly which facts each answer rests on, and says plainly when it cannot answer. There is no language model in the loop and nothing leaves the platform: one short CPU process per question, typically a few milliseconds after the domain's facts are read.
Use it for the parts of your vertical where a person needs to ask rather than submit a claim: a help panel
next to a review screen ("what does a loan require?"), a pre-check before an action ("does a deployment need
approval?"), an explainer for an auditor ("why does consent enable a loan?"). Use evaluate when you already
have a claim and need a verdict; use ask when you have a question.
From your application, with the application's API key, on a bound workflow:
from earl_sdk import EarlClient
from earl_sdk.outcomes import Result, SemanticUncertainty, OperationalError
client = EarlClient("https://<your-platform-host>", API_KEY)
wf = client.workflow(WORKFLOW_ID) # the workflow over your trained domain (id from app.bind_workflow(), or the application page)
out = wf.ask("Is consent required for a loan?")
if isinstance(out, Result):
show(out.answer, read_as=out.interpretation["asked"], evidence=out.result["claims"])
elif isinstance(out, SemanticUncertainty):
show(out.answer) # a clarification or a declined request; out.reasons says which
elif isinstance(out, OperationalError):
log(out.code, out.message) # e.g. engine_binary_missing, faithfulness_gate_failed
Over HTTP it is POST /api/v1/workflows/{workflow_id}/language/ask with {"question": "...", "intent": "explain"},
returning the workflow record. Like every capability call, it is an append-only, Ed25519-signed record you can
verify offline (client.verify_offline(out)). intent is optional (explain, answer, teach, compare) and
only changes the wording's register, never the facts.
In the platform UI, the same question box is on the domain page (Ask) and in the application's capability console, so you can try questions while you author the corpus.
| Kind | Example | Answer |
|---|---|---|
| Yes / no | Does a loan need consent? · Is consent required for a loan? | Yes (taught or derived), a taught No, or cannot establish |
| List, forward | What does a loan require? · Which item does the register record? | every held answer, each labelled taught or derived |
| List, inverse | What requires consent? · What is enabled by consent? | every held answer |
| Why | Why does consent enable a loan? · How can review enable egress? | taught (no reason invented) or derived (the rule named) |
| Describe, relate, compare | Tell me about a replica. · How are a label and origin connected? | what is held about them — never an invented category |
The wording can vary. EARL reads passive voice, fronted phrases (For a loan, is consent needed?), a premise before the question (A label relates to origin; does it prove origin?), relative clauses (Is consent something a loan requires?), and the verbs your own corpus used. Direction is kept: Is consent required by a loan? and Does consent require a loan? are different questions with different answers.
EARL itself keeps nothing between questions. A workflow can still carry one thing forward: the concept a pronoun stands for, taken only from the workflow's own signed records.
wf.ask("What does the register record?") # Register records: loan. ...
wf.ask("Is it required by a loan?") # Reading "it" as "register". I cannot establish that a loan requires register ...
wf.ask("Does it prove ownership?") # asked back: the previous answer names "loan" and "register"
Every step is in the record under result.antecedent_resolution:
{"status": "applied", "pronoun": "it", "concept": "register", "candidates": ["register"],
"fitting": ["register"], "refusals": {}, "engine": {"applied": true, "refused": null, "...": "..."},
"source_record_id": "…", "source_sequence": 2, "first_reading": "UNRESOLVED reference (it)"}
status is one of applied, ambiguous, refused, none_fit, no_candidate, too_many_candidates or
no_prior_answer. The field is absent when the question needed no resolution. Show the answer as it is, since it
states the reading. To start fresh, use a new workflow.
Limits, measured on a developer-authored set (EVAL-10, not an independent measurement):
- No wrong referents after repair. When several concepts would fit, it asks rather than choosing by topic.
After "Why does an anomaly require review?", "Does it prove fraud?" asks back naming "anomaly" and "review",
where a person would assume the anomaly.
- One pronoun per question. "Why does it examine it?" is asked back.
- Needs a current engine. The NL engine's earl-api must report interpretation.unresolved. With an older
engine, pronouns are asked back as before.
requires, enables,
causes, prevents, part_of, special_case_of, …). Your domain's own verbs (examines, stores,
filters, …) are held and reported, and the answer says there are no rules to reason from them.authority.check) and a gateway.| outcome | when | what to do |
|---|---|---|
Result |
an answer: supported Yes, a list, a why, a taught No, or "cannot establish" | show answer; show interpretation["asked"] next to it; keep claims for audit |
SemanticUncertainty |
a clarification (unknown verb), a declined request (writing, advice, authorization), a question with no resolvable referent, or one EARL could not read; reasons carries language_<mode> |
show answer — it says why and suggests questions it can answer |
OperationalError |
the path could not run (engine_binary_missing, domain_not_trained, no_domain_facts, belief_store_unavailable, engine_unavailable, engine_timeout) or faithfulness_gate_failed |
do not show an answer; for faithfulness_gate_failed the answer was withheld by the platform — report it as a defect |
{
"answer": "Yes — a loan requires consent (taught directly).",
"mode": "yes_no",
"interpretation": {"asked": "whether(loan requires consent)", "resolved": "whether(loan requires consent)",
"resolved_against": null, "canonical": "is consent required for a loan?", "rewrites": [],
"arguments": ["loan", "consent"], "unresolved": null},
"claims": [{"s": "loan", "rel": "requires", "o": "consent", "provenance": "taught"}],
"gate": {"checked": 1, "passed": true, "unsupported": [], "misattributed": [], "prose_misattributed": [],
"checks": ["claim_support", "provenance_accuracy", "non_vacuity", "prose_origin"]},
"answer_withheld": false,
"facts_count": 20
}
answer — written to be shown as-is.interpretation.asked — how the question was read. Show it: it is the fastest way for a user to see a
misread question. resolved_against names a taught denial when one answered the question. arguments are
the concepts an answered question was about. unresolved ({"word", "named"}) is set when a pronoun was
asked back.claims — every fact the answer asserts, labelled taught (from your documents) or derived (by a stated
rule, e.g. enables as the inverse of requires).gate — a machine check that every asserted fact is held, correctly labelled, and not described in the
prose with the wrong origin. A passing gate does not prove the question was read correctly; that is what
interpretation is for.asked (engine rc44 and later) — for a yes/no question, the asked proposition and its status in this
answer: {"proposition": "loan requires consent", "status": "established"}. established means the answer asserts
it, denied its taught or told denial, contested both, and not_established neither. It is null for other
questions. Read this field, not derivable, to know what the answer says about the question.derivable — whether the answer asserts any claim, including context offered beside the asked
proposition. A "cannot establish that a worksheet requires approval" answer that also lists what the workflow
holds for that relation reads derivable: true with asked.status: "not_established". It is never support for the
asked proposition on its own.provenance: "held") are answered directly, as stated, and never chained through
taught facts or other told facts (engine rc43 and later). Told "a boiler requires certification", with
"certification requires approval" taught, the workflow does not answer "a boiler requires approval".The corpus rules, with measured before/after examples, are in authoring-domains §1. In short:
The answers can only be as good as what the domain learned. Before relying on questions, open the domain's
Knowledge graph › Beliefs (or GET /api/domains/{id}/kg/beliefs) and check that each fact you meant to teach
is there, with the right direction.
requires for prerequisites. Its inverse enables is then derived automatically ("consent enables a
loan", labelled derived; it means prerequisite — not cause, sufficiency or permission).purchase not_requires tender) beside a
fact that says the opposite. EARL then answers "I hold conflicting facts about this" and decides neither
way, and lists flag the item. That answer is correct; the fix is to split or reword the source sentence.wf.evaluate(claim) returns CONTESTED, ask wf.ask("Why does a loan require
consent?") to show the reviewer what the domain holds about the pair.wf.ask("Does a deployment require approval?") — act only on a Result whose
claims are the ones you expect; route everything else to a person.answer, interpretation.asked and the claims;
treat SemanticUncertainty answers as help text (they suggest questions EARL can answer).wf.records() lists
them in order.See capability-limitations for the measured status of language.ask and
sdk-reference for the method.