Integration & APIs
The same invariant engine is reachable from four surfaces beyond the CLI, so it can sit inside a core-banking stack, a browser, an editor, or a SupTech service. This page is the low-level detail of each surface; for the institution-facing story (the hosted API, the invariant manifest as a hand-off artifact, and where a core-banking system like iMAL or Temenos fits around all of it), see The design-time gate.
C-ABI FFI (fiqhc-ffi)
Section titled “C-ABI FFI (fiqhc-ffi)”crates/fiqhc-ffi builds a cdylib exposing a minimal, stable C ABI. UTF-8 .fiqh in,
NUL-terminated JSON diagnostics out.
/* allocate a buffer the caller fills with UTF-8 .fiqh source */char* fiqh_alloc(size_t len);void fiqh_free(char* ptr, size_t len);
/* check source; returns a malloc'd C string of JSON diagnostics (caller frees) */char* fiqh_check_json(const char* src, size_t len);void fiqh_free_cstr(char* ptr);Returned JSON is an array of { code, severity, message, citation, line, col }. Build target
libfiqhc_ffi.so (~620 KB) links from Java (JNI/JNA), .NET (P/Invoke), Python (ctypes/cffi), Go
(cgo), or C. Memory rule: every pointer the library returns is freed with the matching
fiqh_free*, never free() directly.
WebAssembly
Section titled “WebAssembly”The same crate compiles to wasm32-unknown-unknown → deducible.wasm (~180 KB) for in-browser
validation with no server round-trip. The native-only paths (nl.rs’s Command, lsp.rs’s stdin)
are std stubs on wasm and unused there. Marshalling mirrors the C ABI: call fiqh_alloc, write the
source into linear memory, call fiqh_check_json, read the NUL-terminated result, fiqh_free_cstr.
const { instance } = await WebAssembly.instantiate(bytes, imports);const { memory, fiqh_alloc, fiqh_check_json, fiqh_free_cstr } = instance.exports;// write src bytes at fiqh_alloc(len), then:const out = fiqh_check_json(ptr, len); // → ptr to JSON; read until NUL; then fiqh_free_cstr(out)Language Server (deduce lsp)
Section titled “Language Server (deduce lsp)”A stdio JSON-RPC server (std and serde_json only, with no async runtime and no tower-lsp).
Lifecycle and document methods:
| Method | Behaviour |
|---|---|
initialize / initialized |
capability handshake |
textDocument/didOpen · didChange · didSave |
re-check, then push diagnostics |
textDocument/publishDiagnostics |
server→client; precise ranges, code set, daleel in message |
shutdown / exit |
teardown |
Severity maps error → 1, warning → 2; ranges are LSP 0-based line/col with end at end-of-line
where a token span isn’t available. A VS Code extension (editors/vscode) spawns deduce lsp via
vscode-languageclient and ships a TextMate grammar for .fiqh.
Invariant gateway
Section titled “Invariant gateway”A small Node http service (binds 127.0.0.1:8799) that serves the
manifests and answers enforcement queries. It is
useful as SupTech: it checks consistency and issues no fatwa.
| Route | Purpose |
|---|---|
GET / |
dashboard |
GET /manifests |
list loaded manifests |
GET /dids |
sample DID registry (capacity middleware) |
POST /enforce |
{ target, terms } → allow/deny + cited violations (ops eq/ne/gt) |
POST /authorize |
{ target, terms, parties } → checks terms and every party’s ahliyyah |
POST /compile |
{ spec } → shells deduce check, returns { consistent, diagnostics } |
POST /attest |
{ target, terms } → /enforce, plus an append-only conformance record (below) |
GET /conformance/:target |
the attestation history for one target, with drift and chain integrity |
curl -s localhost:8799/enforce -H 'content-type: application/json' \ -d '{"target":"musharakah_mutanaqisah","terms":{"loss_share":"by_ownership","capital_guarantee":false}}'# → { "allow": true }# a disguised loan → { "allow": false, "violations": [ { "code":"RIBA-1", "citation":"al-Baqarah 2:275" }, ... ] }terms are flat dotted keys (e.g. zakat.rate_bps). The gateway never mutates state; it is a pure
decision endpoint over the manifest + the DID/ahliyyah resolver
(see Capacity).
Continuous conformance: closing the formation-vs-execution gap
Section titled “Continuous conformance: closing the formation-vs-execution gap”/enforce answers one question: are these proposed terms consistent, right now? That closes the
gap between a board’s approval and a contract’s formation. It does not, by itself, close a second
gap: nothing re-checks a booked product later, so a parameter changed in a batch job or a side
letter applied in production could drift from what was approved and nobody would know — exactly the
divergence the gateway exists to prevent, reopened one step downstream, in the deployment mode
where a bank keeps its existing core system and only gates formation through the checker.
POST /attest narrows that gap for institutions willing to re-submit a live product’s current
configuration periodically (a cadence the gateway cannot impose — that remains an operational or
supervisory policy, not something an HTTP endpoint can compel). The first attestation for a target
establishes a baseline; each later one is checked against the manifest exactly as /enforce would,
and is appended to a hash-chained, tamper-evident log:
curl -s localhost:8799/attest -H 'content-type: application/json' \ -d '{"target":"MusharakahMutanaqisahGen","terms":{"risk.capital_guarantee":"none", "...": "..."}}'# → { allowed, violations, seq, is_baseline, drift }
curl -s localhost:8799/conformance/MusharakahMutanaqisahGen# → { entries, chain_intact, broken_at_seq, ever_had_unconstrained_drift }drift distinguishes two kinds of change since the baseline: a change to a field the rule module
constrains is already caught by the allowed/violations verdict; a change to a field the rule
module does not constrain is surfaced as unconstrained_drift — visible to an auditor even
though the rule module never required it fixed, so it was never something the engine could refuse.
chain_intact: false means a past entry was edited, reordered, or deleted outside the service —
each entry’s hash covers the previous entry’s hash, so tampering with history is detectable, not
prevented.
This closes a narrow, mechanical gap. It does not verify that what is POSTed is what is actually
running in the core system — pulling the live configuration, rather than trusting what arrives,
is the integration an institution has to build; requiring that integration to run on a schedule is
what a supervisor has to impose. See also the ratification mechanism, which closes the analogous gap for the rule module itself.
Exit codes (CLI)
Section titled “Exit codes (CLI)”deduce check/build exit non-zero when a spec is inconsistent, so they drop into CI gates directly:
| Code | Meaning |
|---|---|
0 |
consistent (and, for build, artifacts emitted) |
1 |
inconsistent: one or more error diagnostics (printed to stderr as JSON or pretty) |
2 |
usage / I/O error (bad path, unreadable rule module) |