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

A smaller application API

Start with Soterias around an existing function. Add security.Executor only for operations that need native enforcement, and audit for offline verification. Python uses ainvoke; TypeScript uses invokeAsync. Existing public entry points remain compatible.

Need Start here
Observe existing work Soterias → invoke / track
Reuse a pure calculation Soterias → cache / cache_async (TypeScript: cacheAsync)
Execute an exact protected request security.Executor → prepare / invoke
Review an operation separately security.Reviewer → prepare / approve
Provision bounded authority security.Issuer / Registry / Delegation
Verify historical evidence audit.Verifier / ChainVerifier / replay

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.

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.

"""A complete local application: Python chunks on the feature pages use this source."""
import asyncio
import json
from pathlib import Path
import sqlite3
import tempfile

from soterias import Soterias

Create an application and an ordinary database

Soterias observes this existing code; it does not secure these direct writes.

# %% Create an application and an ordinary database
# Soterias observes this existing code; it does not secure these direct writes.
root = Path(tempfile.mkdtemp(prefix="soterias-invoices-"))
database = sqlite3.connect(root / "invoices.sqlite3")
database.execute("CREATE TABLE invoices (id INTEGER PRIMARY KEY, cents INTEGER)")
sdk = Soterias(workflow="invoices", directory=root / "metrics")


def post_invoice(cents):
    row = database.execute("INSERT INTO invoices(cents) VALUES (?)", (cents,))
    database.commit()
    return {"id": row.lastrowid, "cents": cents}

Observe synchronous and asynchronous calls

Repeating the same input still runs the write twice.

# %% Observe synchronous and asynchronous calls
# Repeating the same input still runs the write twice.
first = sdk.invoke(post_invoice, 1500)
second = sdk.invoke(post_invoice, 1500)
assert first["id"] != second["id"]
tracked_post = sdk.track(post_invoice)
assert tracked_post(500)["cents"] == 500


async def review_invoices():
    await asyncio.sleep(0)
    return database.execute("SELECT SUM(cents) FROM invoices").fetchone()[0]


async def finish():
    try:
        total = await sdk.ainvoke(review_invoices)
        assert total == 3500
        tracked_review = sdk.track_async(review_invoices)
        assert await tracked_review() == total
        await sdk.flush()
        summary = sdk.summary()
        assert summary["counts"]["raw"] == 5

Inspect and export local measurements

Each export is explicit; nothing is uploaded.

        # %% Inspect and export local measurements
        # Each export is explicit; nothing is uploaded.
        for name, export in (
            ("runs.json", sdk.metrics.export_json()),
            ("runs.csv", sdk.metrics.export_csv()),
            ("runs.otlp.json", sdk.metrics.export_otlp()),
        ):
            (root / name).write_bytes(export.data)
        print(json.dumps({"status": "PASS", "total_cents": total,
                          "runs": summary["counts"]["raw"], "directory": str(root)}))
    finally:

Close the runtime and database

Wait for pending recordings before leaving the process.

        # %% Close the runtime and database
        # Wait for pending recordings before leaving the process.
        await sdk.close_async()
        database.close()


asyncio.run(finish())

Add a feature

Calculation caching adds an independent verifier and version. Protected execution introduces operator configuration and a separate reviewer. Choose a feature for all capabilities and their complete inline examples. Advanced owners remain available as security.Host and the compatibility exports; the Rust authority checks and native artifacts are unchanged by the shorter names.

Search guides, examples and API reference.