Sernixa Python SDK
Project description
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.
Quickstart
pip install -e packages/sernixa
export SERNIXA_BASE_URL=http://localhost:8000
export SERNIXA_API_KEY="$YOUR_LOCAL_DEV_TOKEN"
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 terminal decision or timeout.
Configuration
SERNIXA_BASE_URL: Sernixa API URL. Defaults tohttp://localhost:8000.SERNIXA_API_KEY: bearer token for the API.SERNIXA_POLL_INTERVAL_SECONDS: approval poll interval. Defaults to2.SERNIXA_POLL_TIMEOUT_SECONDS: approval wait timeout. Defaults to600.SERNIXA_TIMEOUT_SECONDS: per-request HTTP timeout. Defaults to10.SERNIXA_MAX_RETRIES: retries for transient network errors,429, and5xx. Defaults to2.SERNIXA_LOG_LEVEL: optional SDK logger level such asINFOorDEBUG.SERNIXA_DEBUG: set totruefor 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",
api_key=os.environ["SERNIXA_API_KEY"],
poll_interval=1,
poll_timeout=120,
timeout_seconds=10,
max_retries=2,
)
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)
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 emptyintent_id, invalidrisk_level, or non-JSON metadata.SernixaRateLimitError: the backend kept returning429after 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.
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
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 proxy guards invoke, ainvoke, run, arun, and direct calls where the
underlying tool exposes them. It 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.
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 raisesSernixaRejectedError.blocked: policy/security denied the action; the SDK raisesSernixaBlockedError.expired: approval TTL elapsed; the SDK raisesSernixaExpiredError.failed: backend replay/execution evidence failed; the SDK raisesSernixaError.
Troubleshooting
Action blocked: inspectexc.reasonand the approval/audit page. Dangerous primitives and invalid signatures fail closed.SernixaValidationError: fix empty IDs, invalid risk levels, emptysystems_touched, or non-JSON metadata.SernixaConfigurationError: checkSERNIXA_BASE_URL, timeout, poll, and retry values.SernixaRateLimitError: reduce agent concurrency or increase backend limits for the environment.SernixaTimeoutError: the approval is still pending afterSERNIXA_POLL_TIMEOUT_SECONDS.- Browser works but SDK fails: verify
SERNIXA_API_KEYand 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 the demo API. A
production-like Sernixa backend must run with AUTH_BYPASS=false, real bearer
tokens, Redis-backed replay/rate-limit state, and a Postgres-backed audit store.
The present repo intentionally fails closed in RUNTIME_MODE=production_like
until that Postgres runtime store is implemented.
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, and compose smoke examples.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sernixa-0.1.0.tar.gz.
File metadata
- Download URL: sernixa-0.1.0.tar.gz
- Upload date:
- Size: 27.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b04cfdc1873db2cbcfc3c17fc99bcfcb03fed9268221cea91fe0886b0b67d231
|
|
| MD5 |
bfc0cb16f8d410d670772a91eef495c8
|
|
| BLAKE2b-256 |
d0617b2adc484f983868067e1b0c08395bdb81ea8acc82e7c7995474deeb7fc6
|
File details
Details for the file sernixa-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sernixa-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e3b337c491592375b289702b7a1711ea3982df3420bb30c0b53362649d7978a
|
|
| MD5 |
e3e0b7ae68dca6c792a7b4bf447d6ee0
|
|
| BLAKE2b-256 |
84f308f5634e1753d7942ccd138a8823f198484aa50d977d0db43fa4f69f19c7
|