Skip to main content

Sernixa Python SDK

Sernixa gates Python function execution through a deterministic approval engine. The backend decides whether an action is allowed, auto-approved, blocked, or pending human review; the SDK executes the wrapped business function locally only after an approved-style decision.

The SDK is intentionally small: it does not execute business logic in the Sernixa backend, and it does not pretend to be a full agent framework. It gives you low-friction interception points for plain Python, LangChain, CrewAI, and MCP-style tool boundaries.

Before You Start

You need:

  • A Sernixa workspace.
  • A Sernixa API base URL, for example https://api.sernixa.com for hosted environments or http://localhost:8000 for local development.
  • A browser-issued access token or an organization API key for automation.
  • One function, tool, or agent action to protect first.

The SDK sends governance metadata to Sernixa. Your function still runs in your process, and only after Sernixa returns an approved-style decision.

Quickstart

Install from PyPI:

pip install sernixa

For local development from this checkout:

pip install -e packages/sernixa

Configure the API endpoint and key:

export SERNIXA_BASE_URL=https://api.sernixa.com
export SERNIXA_API_KEY="<your-org-api-key>"

For local development, use the local FastAPI backend instead:

export SERNIXA_BASE_URL=http://localhost:8000
import sernixa

@sernixa.intercept(
    intent_id="customer-notes",
    risk_level="LOW",
    operation_class="read",
    data_sensitivity="internal",
    systems_touched=["postgres"],
    metadata={"ticket": "DEMO-1"},
)
def summarize_customer(customer_id: str) -> str:
    return f"summary for {customer_id}"

print(summarize_customer("cus_123"))

If Sernixa returns approved, auto_approved, or executed, the function runs locally. If it returns pending_review, the SDK polls until a reviewer approves or rejects the action, or until the configured timeout expires.

First Run Checklist

  1. Create or choose a Sernixa workspace.
  2. Sign in interactively or create an organization API key for automation.
  3. Export SERNIXA_BASE_URL and the selected credential.
  4. Wrap one low-risk function with @sernixa.intercept(...).
  5. Run the function and confirm the decision appears in the Command Center.
  6. Increase risk levels only after the low-risk path is working.

High and critical risk actions are not silently auto-approved. Expect them to wait for human review unless policy blocks them outright.

Configuration

  • SERNIXA_BASE_URL: Sernixa API URL. Defaults to http://localhost:8000.
  • SERNIXA_ACCESS_TOKEN: revocable browser session token. Takes precedence over an API key.
  • SERNIXA_API_KEY: bearer token for the API.
  • SERNIXA_POLL_INTERVAL_SECONDS: approval poll interval. Defaults to 2.
  • SERNIXA_POLL_TIMEOUT_SECONDS: approval wait timeout. Defaults to 600.
  • SERNIXA_TIMEOUT_SECONDS: per-request HTTP timeout. Defaults to 10.
  • SERNIXA_MAX_RETRIES: retries for transient network errors, 429, and 5xx. Defaults to 2.
  • SERNIXA_MAX_ASYNC_IN_FLIGHT: maximum concurrent async SDK HTTP requests per event loop. Defaults to 20.
  • SERNIXA_SDK_DLP_MODE: metadata DLP mode. Defaults to mask; use warn, block, or off intentionally.
  • SERNIXA_CAPTURE_ARGUMENTS: set to true to include function argument values in submitted metadata. Defaults to false.
  • SERNIXA_LOG_LEVEL: optional SDK logger level such as INFO or DEBUG.
  • SERNIXA_DEBUG: set to true for verbose SDK request/decision logging.

You can also configure a client directly:

import os
from sernixa import Client

client = Client(
    base_url="http://localhost:8000",
    access_token=os.environ.get("SERNIXA_ACCESS_TOKEN"),
    api_key=os.environ.get("SERNIXA_API_KEY"),
    poll_interval=1,
    poll_timeout=120,
    timeout_seconds=10,
    max_retries=2,
    max_async_in_flight=20,
)

Validate the configured key and evaluate a policy input directly:

identity = client.whoami()
decision = client.governance_test({"operation_class": "read"})

For an interactive application, use the browser device flow and then create a client from its revocable session token:

pending = client.start_cli_device_login(device_name="Developer workstation")
print(pending.verification_uri, pending.user_code)
login = client.poll_cli_device_login(pending.device_code)

session = Client(access_token=login.access_token)
plan = session.current_plan()
flight = session.feature_availability("flight_recorder")

The backend remains authoritative for roles, plans, and feature availability. Call logout_cli_session() to revoke a browser session. API keys remain the recommended credential for unattended automation.

If whoami() fails, fix the base URL or API key before wrapping production tools.

Intercepting Functions

@client.intercept(
    intent_id="billing-adjustment",
    risk_level="HIGH",
    operation_class="financial",
    data_sensitivity="financial",
    systems_touched=["stripe", "postgres"],
)
def adjust_invoice(invoice_id: str, amount_cents: int) -> None:
    ...

High and critical risk actions are never auto-approved by Sernixa. They remain pending review even when similar low-risk actions have a strong approval history.

Async Functions

The same decorator works on coroutines:

@client.intercept(
    intent_id="agent-read",
    risk_level="LOW",
    operation_class="read",
    data_sensitivity="internal",
    systems_touched=["vectordb"],
)
async def run_agent(query: str) -> str:
    return await agent.ainvoke(query)

Async clients reuse one httpx.AsyncClient per event loop and cap concurrent SDK requests with SERNIXA_MAX_ASYNC_IN_FLIGHT. Long-running async services should close reusable sessions during shutdown:

async with Client() as client:
    await protected_tool()

# or
client = Client()
...
await client.aclose()

Decision Handling

from sernixa import is_approved_status, is_terminal_status

assert is_approved_status("auto_approved")
assert is_terminal_status("rejected")

The SDK raises explicit exceptions for reviewer and policy outcomes:

from sernixa.exceptions import (
    SernixaBlockedError,
    SernixaConfigurationError,
    SernixaExpiredError,
    SernixaRateLimitError,
    SernixaRejectedError,
    SernixaTimeoutError,
    SernixaValidationError,
)

try:
    adjust_invoice("inv_123", 1000)
except SernixaBlockedError as exc:
    print(f"Blocked by policy: {exc.reason}")
except SernixaRejectedError as exc:
    print(f"Rejected by reviewer: {exc.reason}")
except SernixaExpiredError:
    print("Approval expired before a reviewer decided.")
except SernixaTimeoutError:
    print("SDK timed out waiting for a decision.")

Configuration and payload mistakes fail before the business function runs:

  • SernixaConfigurationError: invalid base URL, timeout, poll, or retry settings.
  • SernixaValidationError: malformed action metadata such as an empty intent_id, invalid risk_level, or non-JSON metadata.
  • SernixaRateLimitError: the backend kept returning 429 after retries.

Extra Review Metadata

Use metadata for non-sensitive context that helps the approver understand the action:

@sernixa.intercept(
    intent_id="support-note",
    risk_level="LOW",
    operation_class="update",
    data_sensitivity="internal",
    systems_touched=["postgres"],
    metadata={"change_ticket": "SUP-1842", "env": "local-demo"},
)
def write_support_note(...):
    ...

Core governance fields such as risk_level and idempotency_key cannot be overridden by extra metadata.

By default, the SDK does not upload function argument values. It sends argument counts and keyword names only, and masks sensitive-looking metadata before the request leaves the process. To include full argument values for a trusted local debugging session, set SERNIXA_CAPTURE_ARGUMENTS=true; keep the default for shared development and production-like runs.

V3 Delegation Context

For local multi-agent workflows, create a delegation token through Sernixa and attach it while any delegatee agent runs protected tools:

from sernixa import Client, delegation_scope, with_delegation

client = Client()
token = client.create_delegation_token(
    delegator_agent_id="orchestrator-agent",
    delegatee_agent_id="worker-agent",
    scope=delegation_scope(
        max_risk_level="low",
        allowed_operation_classes=["read"],
        allowed_data_sensitivities=["internal"],
        resources={"repo": ["sernixa"]},
    ),
    tool_subset=["view-details"],
)

with with_delegation(
    agent_id="worker-agent",
    token_id=token["token_id"],
    signing_secret=os.environ["SERNIXA_REQUEST_SIGNING_SECRET"],
    chain_id=token["chain_id"],
    runtime_id="local-worker-runtime",
    service_identity="spiffe://local/agent/worker-agent",
):
    view_details()

The SDK signs each delegated request with a canonical envelope, timestamp, nonce, request body hash, key ID, and runtime identity metadata. Sernixa verifies the request signature, replay status, token signature, hash chain, expiry, delegatee identity, and scope before the existing approval logic runs.

LangChain Adapter

For current LangChain agents, add one middleware instance instead of wrapping every tool:

from langchain.agents import create_agent
from sernixa import Client
from sernixa.adapters import sernixa_middleware

agent = create_agent(
    model="openai:gpt-5",
    tools=[search_customers, update_customer],
    middleware=[
        sernixa_middleware(
            client=Client(),
            environment="production",
            data_sensitivity="internal",
            systems_touched=["crm"],
        )
    ],
)

The middleware uses LangChain's current wrap_tool_call and awrap_tool_call lifecycle. It calls the handler exactly once for allow, raises SernixaReviewRequiredError for review, and raises SernixaBlockedError for deny. Tool arguments and adapter metadata are redacted before evaluation.

Use the decorator when you control the tool function:

from langchain.tools import tool
from sernixa.adapters import langchain_tool

@tool
@langchain_tool(
    intent_id="finance-tool",
    risk_level="HIGH",
    operation_class="financial",
    data_sensitivity="financial",
    systems_touched=["stripe"],
)
def transfer_funds_tool(amount_cents: int, destination_account: str) -> str:
    """Transfer funds after Sernixa approval."""
    ...

Use the object proxy when a tool object already exists:

from sernixa.adapters import secure_langchain_tool

protected_tool = secure_langchain_tool(
    existing_tool,
    intent_id="customer-lookup",
    risk_level="LOW",
    operation_class="read",
    data_sensitivity="internal",
    systems_touched=["crm"],
)

result = protected_tool.invoke({"customer_id": "cus_123"})

Install LangChain separately if you use the adapter:

pip install "sernixa[langchain]"

The dependency-free proxy remains available for older or custom tool pipelines. It guards invoke, ainvoke, run, arun, and direct calls where the underlying tool exposes them, and forwards unknown attributes to the wrapped tool.

CrewAI Adapter

Use the decorator for plain functions that become CrewAI tools:

from sernixa.adapters import crewai_tool

@crewai_tool(
    intent_id="ticket-update",
    risk_level="HIGH",
    operation_class="update",
    data_sensitivity="internal",
    systems_touched=["ticketing"],
)
def update_ticket(ticket_id: str, note: str) -> str:
    return "updated"

Use the object proxy for existing CrewAI-style tool objects:

from sernixa.adapters import secure_crewai_tool

protected_tool = secure_crewai_tool(
    existing_tool,
    intent_id="crew-ticket-update",
    risk_level="HIGH",
    operation_class="update",
    data_sensitivity="internal",
    systems_touched=["ticketing"],
)

protected_tool.run("SEC-1842")

Install CrewAI separately if you use CrewAI itself:

pip install "sernixa[crewai]"

The SDK proxy supports the common run, _run, and direct-call execution shapes without requiring CrewAI as a hard dependency.

MCP Boundary Helpers

Sernixa does not implement the full MCP protocol in this SDK. The real support in this pass is an honest boundary wrapper for MCP-style tool dispatch:

from sernixa.adapters import McpToolBoundary

boundary = McpToolBoundary(server_name="workspace-mcp", toolset_id="toolset-prod")

def read_file(path: str) -> str:
    return open(path).read()

result = boundary.invoke(
    tool_name="read_file",
    arguments={"path": "/workspace/report.md"},
    handler=read_file,
    intent_id="mcp-read-file",
    risk_level="LOW",
    operation_class="read",
    data_sensitivity="internal",
    client_name="local-agent-host",
)

Place this at the host/router boundary before dispatching a tool call to the underlying MCP server/tool implementation. Planned next work is first-class MCP server middleware and protocol-aware request/response adapters.

Gateway Run Wrapper

SernixaGateway is the target high-level developer surface for governing an existing agent or MCP/tool run call without rewriting the agent. It wraps the current approval oracle and records gateway metadata on the action request.

from sernixa import SernixaGateway

gateway = SernixaGateway(
    api_key=os.environ["SERNIXA_API_KEY"],
    mcp_profile="prod-tools",
    enforce_ebpf=True,
)

result = gateway.run(agent.run, input=user_task)

enforce_ebpf=True does not start a collector by itself. Before execution, the SDK checks /ready and requires Flight Recorder runtime support outside local_demo. In local_demo, the action is still marked as requiring runtime evidence, but unsigned local-demo evidence must not be represented as production proof. Native protocol-aware MCP middleware remains a target design until implemented. The TypeScript package now exists in the monorepo for Node action gating and gateway readiness, and is published on npm as @sernixa/sdk.

Agent Plan Guards

Use the plan guard when a chat agent, Claude-style hook runner, or Codex-style wrapper can declare intended tool calls before execution:

from sernixa import Client
from sernixa.adapters import SernixaAgentGuard, chat_plan_step

guard = SernixaAgentGuard(
    Client(),
    agent_type="chat",
    user_identity={"email": "operator@example.com"},
    context={"workspace": "support", "channel": "slack"},
)
guard.declare_plan([
    chat_plan_step(
        tool_name="calendar.create",
        action="calendar.write",
        arguments={"title": "Review"},
        resource="calendar:primary",
    )
])
guard.execute_tool(
    calendar_create,
    tool_name="calendar.create",
    action="calendar.write",
    arguments={"title": "Review"},
    resource="calendar:primary",
)

declare_plan() calls the shared backend endpoint /api/controls/governance/agent-plan/evaluate. Every step is evaluated through the same governance engine and audit chain as governance_test(). Execution is blocked if no plan was declared, the plan is denied/review-only, the requested tool is unplanned, or a plan step is reused.

State Model

  • executed: Sernixa allowed the action and the SDK executed the local function.
  • auto_approved: Sernixa policy allowed execution without human review.
  • pending_review: the SDK is waiting for a reviewer and polling the approval.
  • rejected: a reviewer denied the action; the SDK raises SernixaRejectedError.
  • blocked: policy/security denied the action; the SDK raises SernixaBlockedError.
  • expired: approval TTL elapsed; the SDK raises SernixaExpiredError.
  • failed: backend replay/execution evidence failed; the SDK raises SernixaError.

Troubleshooting

  • Action blocked: inspect exc.reason and the approval/audit page. Dangerous primitives and invalid signatures fail closed.
  • SernixaValidationError: fix empty IDs, invalid risk levels, empty systems_touched, or non-JSON metadata.
  • SernixaConfigurationError: check SERNIXA_BASE_URL, timeout, poll, and retry values.
  • SernixaRateLimitError: reduce agent concurrency or increase backend limits for the environment.
  • SernixaTimeoutError: the approval is still pending after SERNIXA_POLL_TIMEOUT_SECONDS.
  • Browser works but SDK fails: verify SERNIXA_API_KEY and that the backend URL is reachable from the Python process.

Local And Hosted Configuration

Local demo:

export SERNIXA_BASE_URL=http://localhost:8000
export SERNIXA_API_KEY=e2e-admin
export SERNIXA_POLL_INTERVAL_SECONDS=1

Hosted or shared environment:

export SERNIXA_BASE_URL=https://sernixa.example.com
export SERNIXA_API_KEY="$SERNIXA_SERVICE_TOKEN"
export SERNIXA_TIMEOUT_SECONDS=10
export SERNIXA_MAX_RETRIES=2

Use real bearer tokens, HTTPS, shared nonce/rate-limit storage, and production KMS/HSM signing before treating a hosted environment as production.

Current backend handoff note: local SDK examples target a configured API. A production-like Sernixa backend must run behind the Auth.js/Google web session boundary, accept only the short-lived API JWT minted by the web app, and use Convex plus shared Redis for production runtime state.

TypeScript handoff note: the monorepo now includes packages/sdk as a real Node client for action gating, approval polling, typed errors, and gateway readiness checks, and the package is published on npm as @sernixa/sdk. Python remains the fuller SDK for delegation request-envelope signing and framework adapters.

Release

The package is published on PyPI as sernixa. Use editable install from this repository only when developing the SDK itself.

For local repository development, use editable install from the repo root:

pip install -e packages/sernixa

Local Examples

  • examples/basic_auto_approval/: local walkthrough showing low-risk, repeated approval memory, and high-risk pending behavior.
  • examples/multi_agent_delegation/: generic orchestrator/worker delegation token flow.
  • examples/sernixa-sdk/: lower-level sync, async, LangChain, CrewAI, MCP boundary, Node gateway, and compose smoke examples.

Metadata

Release files for sernixa 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sernixa 0.4.1
File Size Uploaded Provenance Actions
sernixa-0.4.1.tar.gz 51.9 kB With provenance Details for sernixa-0.4.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sernixa 0.4.1
File Interpreter ABI Platform Actions
sernixa-0.4.1-py3-none-any.whl Python 3 none any Details for sernixa-0.4.1-py3-none-any.whl

Total release size: 93.0 kB

Release files / sernixa-0.4.1.tar.gz

Download URL sernixa-0.4.1.tar.gz
Size 51.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d1419a9d8b5a52ecc010de4c9159bb01e33714cc13b73d58e4caa102b369c918
BLAKE2b-256 checksum
How to use checksums
66e72a818e76161ec7f506f729cd4c10529ea366b2dd3b9e94dd8e09e6835e36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.

Transparency log

Release files / sernixa-0.4.1-py3-none-any.whl

Download URL sernixa-0.4.1-py3-none-any.whl
Size 41.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f66ccd63ab1e33b852d9e45323499ad4dc9c4355b389e0523db0d27dd95e9e56
BLAKE2b-256 checksum
How to use checksums
0f5cd9420123a93494deede21e987bcdb6a3c646c3ecc171d8b410cfebac5687
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.

Transparency log

Security for sernixa 0.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sernixa-0.4.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page