Skip to main content
The flagship neuro-symbolic-recursive surface. Instead of generating free text, it returns an auditable decisionapproved | denied | refused — with a cited proof chain, a confidence, and a safe refusal when the engine cannot ground the answer well enough to be accountable. This is the use case where a pure LLM is unsafe: it will confidently approve actions that violate policy. The symbolic layer gives deterministic, provenance-traced decisions relative to the supplied facts and rules; the recursive layer handles multi-hop policy (transitive role access, bill-of-materials/recall explosion, chained eligibility); the neural layer reads messy natural-language requests. Every request also runs through the canonical Grounded Symbol System (GSS) and a tenant-scoped NSRMachine. Machine inference is mandatory for verified decisions — if the seed pack is unavailable or inference does not complete, the API fails closed with HTTP 503.
This page reflects NSR v0.9.6. Proof verification, negation and valid-time handling were tightened in v0.9.4 — see Behavior changes in v0.9.4 — and several rule-evaluation semantics were corrected earlier in v0.6.0 and v0.7.0. If you wrote rules or a proof verifier against earlier docs, read both sections.

Endpoints

These thirteen are the decision surface. The engine serves 259 operations in all — knowledge base, rules, NSR-L, machines, flywheel, billing and more — each with a generated reference page and playground under the NSR API tab.

Request

Rule effects

A rule may declare its policy intent explicitly via effect, which is authoritative over predicate-name conventions — better for tenant-specific or non-English vocabularies.
effect: "review" became a first-class declared effect in v0.6.0. Before that it was expressible only via predicate-name inference, and an inline rule declaring it would fail with a 422 “unknown variant”. Review rules are subject-bound in the same way deny rules are.

Negation-as-failure

A condition may set negated: true: the rule fires only when no fact matches the atom. A free variable in the negated atom is a wildcard, so not fraud_flagged(?o, ?r) fails whenever any fraud_flagged(?o, *) exists.
This field is required for negation to take effect. Before v0.6.0, request-scoped rule conditions carried no negated flag, so a negation was silently dropped and read as a positive condition — inverting the guard. A rule written as may_auto_refund(?o) :- refund_requested(?o), NOT fraud_flagged(?o,?r) would auto-refund exactly the fraud-flagged orders it was written to block.Organization rules on the batch endpoint always honored negation; inline rules — what the MCP nsr_decide tool uses — did not. If you authored inline rules against pre-v0.6.0 docs, audit them.
negated is serde-default and skipped when false, so existing payloads are unchanged.

Outcomes

Cited symbolic policy is evaluated after GSS safety gates but before conversational uncertainty and execution-runtime state. This matters when policy authorizes an action but answer composition is ambiguous or live runtime state disagrees.

Response

cited_rules is the audit trail, reduced to the backward dependency path. When the request carried inline policy, the proof also carries a SHA-256 over the canonicalized request-scoped facts and rules, pinning the decision to the exact policy inputs it was evaluated against.

Behavior changes in v0.9.4

Three corrections to how proofs are checked. None changes the request shape; all change what the engine will accept as proven. Proof verification checks entailment, not citation shape. Both the in-process checker and the independent nsr-proof-core verifier now unify every cited fact with the atom the rule actually needs, replay rule heads and bodies, evaluate builtins, reject relabelled builtins, and fail closed on uncertified negation. Before this, a real but unrelated fact could be cited in support of an arbitrary goal and pass. Backward chaining also gives each rule invocation a fresh variable namespace, so sibling branches cannot contaminate one another’s substitutions. Negation proofs are complete for finite stratified Datalog. An empty negation-as-failure trace no longer fails merely because some rule defines the predicate. Both proof kernels recompute the bundle’s perfect model and accept absence only when the ground atom is outside it. Negative cycles, function-generating programs, non-ground negation, and closure resource exhaustion all fail closed. Valid-time is enforced during inference. A live evaluation captures one instant and excludes facts that have expired or are not yet valid. Historical reasoning over HTTP and SSE uses the request’s as_of instant, so a past snapshot is no longer filtered against today’s clock.
If you run the offline verifier, upgrade it alongside the server. A bundle produced by v0.9.4 carries the fact and rule slices the new checker replays; an older verifier will accept proofs the server now rejects.

Behavior changes in v0.6.0 and v0.7.0

Several of these were fail-open correctness bugs. If you built against earlier documentation, the following now behave differently — in every case, more conservatively.

Confidence is capped by the weakest supporting fact (v0.7.0)

Decision confidence was 1.0 - grounding_uncertainty, decoupled from the proof and non-monotonic — a 0.4-confidence fact could yield higher confidence than a 1.0 one. An approval is now capped by its weakest supporting fact:
This is fail-safe (it only lowers values), monotonic, and a no-op when facts are certain.

Subject and action binding (v0.6.0)

A rule fires for whatever the fact base satisfies, not for what the question asks. Given may_authorize(?p,?act) :- has_authority(?p,?act) and the fact has_authority(ceo_kim, approve_wire), the engine proves may_authorize(ceo_kim, …). The gate previously counted any cited request-scoped effect wholesale, so a wire could be authorized for stranger_sven off the CEO’s authority, or delete_account authorized off refund authority. A single conclusion-head check now covers all effects: the cited rule’s effect only applies when its ground conclusion binds the request’s own subject and action. Two related binding fixes:
  • Numeric builtins — the binding gate replays a cited rule’s body to reconstruct which subject it fired for, but the replay matcher did not evaluate comparison builtins (leq, geq, lt, …). It returned “can’t tell”, so no mismatch was detected. A rule may_refund(?o) :- order_amount(?o,?v), leq(?v, 500) could approve a refund for an order whose amount did not qualify. The matcher now computes comparison builtins under the binding, exactly as the solver does.
  • Single-character subject tokens — the subject-binding token match dropped tokens shorter than 2 characters, so ord-9 and ord-4 (sharing ord, differing only in the 1-char suffix) were treated as the same subject. A rule that fired for ord-9 could bind a decision about ord-4. The match now requires every alphanumeric token, single characters included. Phrasing variance (order A1 vs order #A1) still grounds.

Abduction no longer asks for un-suppliable builtins (v0.7.0)

A failed comparison builtin such as leq(850,500) was reported in missing_facts with a resolves_with, telling an agent to “supply leq(850,500)” — impossible. Comparison builtins are now excluded; the actionable ask is the base predicate that binds the value, e.g. amount.

Soundness guarantees

A verdict never authorises something the rules do not. Five invariants hold, each regression-tested, with the full set running against a 1,260-case auto-labelled soundness corpus. Confidence is never overconfident. An approval resting on a 0.2-confidence fact reports confidence ≤ 0.2, and the relationship is monotonic — a lower fact confidence never yields a higher decision confidence.
Two limits, stated plainly:
  1. The gate’s outcome logic, the rule engine, and the token matching that produces the gate’s binding signals are all machine-checked in Lean 4, and three differential conformance harnesses bind those models to the shipped code — see Formal Verification. That is not an end-to-end verification of NSR: the neural layer, persistence, billing, and concurrency are out of scope, and the remaining gaps are listed there rather than glossed.
  2. The gate faithfully applies the rules you supply. It cannot judge whether those rules are correct. A permissive rule, faithfully enforced, still authorises what it says to.

Policy impact analysis

Before changing a policy, find out what it would have changed.
It replays your recent logged decisions through the same outcome gate under current versus candidate rules, and reports every decision whose outcome flips — with the fired rules on both sides.
This is the answer to “we can’t change the refund policy, we don’t know what it’ll break.” Replay 200 real decisions against the candidate rule and read the flips.

Idempotency

Mutating requests accept an Idempotency-Key header, Stripe-style.
A repeat within 24 hours returns the cached response byte-for-byte — not re-executed and not re-billed — with Idempotent-Replayed: true and the original decision, billing, and quota headers preserved. Keys are scoped per org, 1–255 URL-safe characters. 2xx and 4xx are cached; 5xx is not, so retries during an incident still reach a healthy backend.
All four SDKs send a key automatically on decide and decide_batch — a fresh UUID per logical call, reused across the client’s internal retries. You get safe retries without doing anything.

Metering

Each resolved decision is one billable unit. A billable outcome is gated by the org quota, which returns HTTP 402 on exhaustion. usage.outcome_cost_microdollars and usage.billing_tier report the charge, tiered by mode and proof depth. Refusals and cache hits are governed by the same billability policy — so a refusal is not a free way to probe, and a replay is not a second charge.

Verify a proof without trusting us

An approved decision carries a verifiable_bundle: the derivation plus the exact facts and rules it stands on. A proof is only proof-carrying if somebody other than the engine can check it, so the checker is a reachable endpoint. POST the bundle back, verbatim:
Response
A proof that does not check is still a 200 with a located reason — an unsound proof is a valid answer, not a client error:
Response
The handler is stateless by design. It reads no tenant state and touches no database; the bundle carries its own org_id, and cross-tenant laundering is rejected inside the checker. That is what makes the answer worth anything — the trusted computing base is the checker and the bundle, not the rest of the server.
You do not have to call us at all. The same check ships as the dependency-light nsr-proof-core crate, so you can verify bundles fully offline — in CI, in an air-gapped audit, or inside your own service. An independently verifiable claim you can only verify by asking the claimant is not independently verifiable.

The outcome loop

Confidence is only meaningful if someone checks it against reality. Record what actually happened to a decision and the engine can tell you how well its own confidence predicts outcomes.
Once outcomes are flowing, the calibration curve is the number that matters:
It buckets approved decisions by reported confidence and reports the real honored rate in each bucket, plus an Expected Calibration Error in [0, 1] where 0 is perfect. That is what lets you set an auto-approve threshold you can defend rather than guess at.
Calibration is computed only over approved decisions that have a recorded outcome. Report outcomes for the ones that went wrong and not the ones that went right and the curve will say the engine is badly calibrated when what is actually skewed is your reporting. Record both, or record neither.
POST /v1/decisions/{id}/outcome returns 404 once a decision has rotated out of the retained window, so report outcomes as they happen rather than batching them weeks later. outcome-by-ref exists so you can do that from the system that learns the outcome, using the id it already holds.

Prove it yourself

A proof harness runs labelled policy cases through the real backward-chaining engine:
Measured across commerce, access-control, supply-chain, and lending cases — two of them recursive (transitive role access, multi-level recall/BOM):
The harness exits non-zero on any unsafe approval or missed floor, so it doubles as a CI gate. Wire it into your pipeline and a policy regression fails the build.
The claim worth testing against your own cases: comparable accuracy, zero unsafe approvals, 100% auditable.

MCP server

The NSR MCP server gained a per-request timeout (NSR_TIMEOUT_MS) so an agent never hangs on a slow endpoint, plus client-side input validation that names the exact malformed rule or field instead of surfacing a cryptic 422 deserialize error.

Verification

NSR ships a verifier-as-oracle evaluation apparatus: a 1,260-case auto-labeled decision-soundness corpus, a deterministic generator, and a runner that checks any live /v1/decisions deployment against the ground-truth labels — plus in-process property-based and generative multi-invariant soundness tests.
Last modified on August 31, 2026