Build with the local Soterias SDK. Get started with Python and TypeScript.
SoteriasDocsBuild
Core components

Verify cited facts against reviewed rules

Capture sources, cite exact text and promote a candidate only when Rust verifies it against a host-pinned typed rule and the complete reviewed evidence set. RC5 adds this semantic-fact verification; a model assertion alone cannot promote a fact.

When to use this

Use this when a workpaper claim needs typed corroboration from an operator-reviewed complete source set, including contrary observations.

Install the matching API preview

These examples use the API 2 preview, not names promised by the public RC5 release. Existing RC5 entry points remain available. The Python wheel below is verified on Windows x64; it is not a cross-platform release.

shell
python -m pip install https://docs.soterias.io/downloads/api-preview/soterias_local-0.1.0rc5%2Bapi2-cp311-abi3-win_amd64.whl
shell
npm install https://docs.soterias.io/downloads/api-preview/soterias-core-0.1.0-rc.5-api.2.tgz
npm install --save-dev typescript@5.8.3 @types/node@24

Python imports soterias. TypeScript imports @soterias/core. Use Python 3.11+ for this wheel and Node 22.23.4+ for these examples. For a .mts file, compile with npx tsc example.mts --target ES2022 --module NodeNext --moduleResolution NodeNext --skipLibCheck, then run the emitted .mjs file.

Before you run

The programs create synthetic ledger/bank files and their own encrypted native store. No model, server or account is required. The public unlock is for these disposable examples only. Origin independence is an operator assertion checked against the recorded source lineage, not something the SDK can discover universally.

Application walkthrough

Choose Python or TypeScript. Create example.py or example.mts and append that language's chunks in order. Each language forms one complete program; indentation and open blocks carry across chunks.

Import the packages

Import the SDK and standard-library helpers. These are the real package exports used by the executable program.

"""Local accounting corroboration through the native Rust verifier; no model/account."""
import json
from pathlib import Path
import tempfile
import time
from soterias import Citation, TrustedFactReference, SourceStore, SourceStoreError

root = Path(tempfile.mkdtemp(prefix="soterias-semantic-"))
started = time.perf_counter_ns()
now = time.time_ns() // 1_000_000
unlock = b"public-disposable-example-unlock"
store = SourceStore.create(root / "store", passphrase=unlock, tenant_id="demo", store_id="audit")
evidence = store.evidence(principal="auditor", purpose="transaction-testing")
sources, citations = [], []
for origin in ("ledger", "bank"):
    text = json.dumps({"invoice": "INV-1", "total": 1200, "origin": origin})
    path = root / (origin + ".json")
    path.write_bytes(text.encode())
    source = store.ingest_file(path, media="utf8_text", permitted_uses=["transaction-testing"], captured_at_ms=now)
    evidence.register_source(source, identity=origin, revision="v1", readers=["auditor"],
                             stale_after_ms=now+600_000, retain_until_ms=now+1_200_000)
    sources.append(source)
    citations.append(Citation(source, start=0, end=len(text), quote=text))

Step 2

Keep the exact acknowledged checkpoint. Reopening with an older pin is an error; do not silently discover and adopt newer state.

# Trusted application setup. The operator reviews independence and the complete
# evidence set. Agents must never receive this configuration or source-store keys.
rule = evidence.install_semantic_rule(predicate="amount_minor_units", subject_pointer="/invoice",
    value_pointer="/total", sources=list(zip(("ledger-origin", "bank-origin"), citations)))
claim = json.dumps({"subject": "INV-1", "predicate": "amount_minor_units",
                    "value": {"type": "integer", "value": "1200"}})
# Empty uncertainty is a candidate assertion, never proof. Rust independently
# verifies the value under the preconfigured rule before persisting any promotion.
candidate = evidence.extract_interpretation(claim, citations=citations, uncertainty=())
promotion = evidence.promote_fact(candidate, rule=rule)
assert promotion["promoted"] is True
assert promotion["report"]["classification"] == "corroborated"
reference = TrustedFactReference(promotion["reference"]["digest"])
assert evidence.check_trusted_fact(reference)["report"]["truth"] == "proven"
checkpoint = store.checkpoint()
store.close()
store = SourceStore.open(root / "store", passphrase=unlock, checkpoint=checkpoint)
evidence = store.evidence(principal="auditor", purpose="transaction-testing")
assert evidence.check_trusted_fact(reference)["report"]["truth"] == "proven"
evidence.revoke_source(sources[0])
try:
    evidence.check_trusted_fact(reference)
    raise AssertionError("revoked source was accepted")
except SourceStoreError as error:

Step 3

Check the result against independent evidence and retain refusals. The assertion makes this example fail if native verification behaves differently.

Python
    assert error.code == "evidence_source_revoked"
finally:
    store.close()
print(json.dumps({"status":"PASS", "root":str(root), "elapsed_ms":(time.perf_counter_ns()-started)/1e6,
                  "model_calls":0, "provider_tokens":None, "reports_signed":False,
                  "scope":"host-pinned typed verification; not universal truth"}))

MCP composition

This complete example creates a reviewed rule on the trusted host, then starts a loopback HTTP MCP host and calls its real semantic-fact tool. It checks that agent context cannot install or replace the rule. Save it as mcp.mjs and run node mcp.mjs. Its bearer is disposable application authentication; it is not a warrant or a grant of execution authority.

Install the matching adapter with npm install https://docs.soterias.io/downloads/api-preview/soterias-mcp-server-0.1.0-rc.5-api.2.tgz. Its SDK peer dependency shares the same native class identities as your installed preview.

mcp.mjs

Create mcp.mjs and append these chunks in order. Together they form one complete program; indentation carries across chunks.

Step 1

Import the SDK and standard-library helpers. These are the real package exports used by the executable program.

JavaScript
// Actual loopback HTTP/MCP component test, with real Rust-backed evidence.
// The bearer token is disposable application authentication, not a native warrant.
import assert from 'node:assert/strict';
import http from 'node:http';
import {randomBytes,timingSafeEqual} from 'node:crypto';
import {mkdtempSync,writeFileSync} from 'node:fs';
import {tmpdir} from 'node:os';
import {join} from 'node:path';
import {McpServer,createMcpHandler} from '@modelcontextprotocol/server';
import {toNodeHandler} from '@modelcontextprotocol/node';
import {Client,StreamableHTTPClientTransport} from '@modelcontextprotocol/client';
import {Citation,TrustedFactReference,SourceStore} from '@soterias/core';
import {registerSemanticFactTool} from '@soterias/mcp-server/semantic-facts';
const root=mkdtempSync(join(tmpdir(),'soterias-semantic-mcp-')),now=Date.now();
const store=SourceStore.create({directory:join(root,'store'),passphrase:Buffer.from('public-disposable-mcp-example'),tenantId:'demo',storeId:'audit'});
const evidence=store.evidence({principal:'auditor',purpose:'audit'}),sources=[],citations=[];
for(const origin of ['ledger','bank']){
  const text=JSON.stringify({invoice:'INV-1',total:1200,origin}),file=join(root,origin+'.json');writeFileSync(file,text);
  const source=store.ingestFile(file,{media:'utf8_text',permittedUses:['audit'],capturedAtMs:now});
  evidence.registerSource(source,{identity:origin,revision:'v1',readers:['auditor'],staleAfterMs:now+600000,retainUntilMs:now+1200000});
  sources.push(source);citations.push(new Citation(source,{start:0,end:text.length,quote:text}));
}
const rule=evidence.installSemanticRule({predicate:'amount_minor_units',subjectPointer:'/invoice',valuePointer:'/total',sources:citations.map((citation,i)=>({origin:['ledger-origin','bank-origin'][i],citation}))});
const candidate=evidence.extractInterpretation(JSON.stringify({subject:'INV-1',predicate:'amount_minor_units',value:{type:'integer',value:'1200'}}),{citations,uncertainty:[]});

Step 2

Build the next part of the local workflow. Values defined in earlier chunks remain in scope; concatenate the chunks in their displayed order.

JavaScript
const promoted=evidence.promoteFact(candidate,{rule});assert.equal(promoted.promoted,true);
const reference=new TrustedFactReference(promoted.reference.digest);
const server=new McpServer({name:'soterias-semantic-component',version:'1.0.0'});
registerSemanticFactTool(server,{repository:evidence,facts:[{name:'invoice_amount',reference}]});
const handler=createMcpHandler(()=>server,{maxSubscriptions:0,maxRequestBodySize:16384,onerror:()=>{}});
const dispatch=toNodeHandler(handler,{maxRequestBodySize:16384,onerror:()=>{}});
const token=randomBytes(32).toString('base64url'),expected=Buffer.from('Bearer '+token);
const listener=http.createServer((req,res)=>{
  const got=Buffer.from(req.headers.authorization??'');
  if(got.length!==expected.length||!timingSafeEqual(got,expected)){res.writeHead(401);res.end();return;}
  if(req.url!=='/mcp'){res.writeHead(404);res.end();return;}
  void dispatch(req,res);
});
await new Promise((resolve,reject)=>{listener.once('error',reject);listener.listen(0,'127.0.0.1',resolve);});
const url=new URL('http://127.0.0.1:'+listener.address().port+'/mcp');
const client=new Client({name:'semantic-fact-component-test',version:'1.0.0'});
let checks=0;
try{
  assert.equal((await fetch(url,{method:'POST',body:'{}'})).status,401);checks++;
  await client.connect(new StreamableHTTPClientTransport(url,{requestInit:{headers:{Authorization:'Bearer '+token}}}),{timeout:15000});
  const tools=await client.listTools();assert.deepEqual(tools.tools.map(t=>t.name),['check_trusted_fact']);checks++;
  assert.equal(tools.tools[0].inputSchema.additionalProperties,false);checks++;
  const result=await client.callTool({name:'check_trusted_fact',arguments:{fact:'invoice_amount'}});
  assert.equal(result.structuredContent.report.truth,'proven');checks++;

Step 3

Check the result against independent evidence and retain refusals. The assertion makes this example fail if native verification behaves differently.

JavaScript
  const forged=await client.callTool({name:'check_trusted_fact',arguments:{fact:'invoice_amount',principal:'other',nowMs:now,trusted:true}});
  assert(forged.isError);checks++;
  const unknown=await client.callTool({name:'check_trusted_fact',arguments:{fact:'other_fact'}});assert(unknown.isError);checks++;
  evidence.revokeSource(sources[0]);
  const revoked=await client.callTool({name:'check_trusted_fact',arguments:{fact:'invoice_amount'}});
  assert.equal(revoked.isError,true);assert.equal(revoked.structuredContent.error,'trusted_fact_unavailable');checks++;
  console.log(JSON.stringify({status:'PASS_ACTUAL_HTTP_SEMANTIC_COMPONENT',checks,root,native_warrant_authentication:false,named_client_acceptance:false,reports_signed:false}));
}finally{
  await client.close();await handler.close();listener.closeIdleConnections();
  await new Promise((resolve,reject)=>listener.close(e=>e?reject(e):resolve()));store.close();
}

Check the result

The application program prints a JSON result and preserves native refusals. For protected operations inspect status and target_observed: transport success does not imply a completed effect. The pure examples contain assertions for their exact expected values. Successful startup is not proof of production enrollment, a physical human review or current authority.

Put it into a workflow

Use the AML walkthrough for protected document reads, reviewed writes and signed outcome checks. Use multi-agent workflows for personal and enterprise orchestration. Keep each agent's proposals separate from operator authority.

Search guides, examples and API reference.