Skip to main content

Decision-first Python SDK for policy-aware agent action control

Project description

Xenovia SDK for Python

Decision-first control hook for agent actions.

Full documentation:

  • docs/SDK_REFERENCE.md (complete API and mode behavior)

Core Model

Xenovia decides. Your code executes.

  • The SDK sends action intent to Xenovia for policy decisioning.
  • The SDK returns a typed response with decision and trace context.
  • Local execution stays in your environment, never in Xenovia.

Before vs After SDK

Before (proxy-only wiring, ad-hoc in each tool integration):

  • Calls can still go through the proxy, but request/response shape is custom per tool.
  • Block/failed/success handling is inconsistent across agents.
  • Sequence tracking and result-to-decision mapping are harder to do reliably.

After (SDK-wrapped integration):

  • Every call uses one contract: capability + payload + session_id + identity + env.
  • Every outcome uses one response object: status + decision + result + trace_id.
  • You can enforce or observe consistently and map call sequence + outcomes deterministically.
flowchart LR
    subgraph BEFORE["Before SDK (manual wiring)"]
      B1["Agent"] --> B2["Custom tool wrapper(s)"]
      B2 --> B3["Xenovia Proxy decision"]
      B3 --> B4["Local execution"]
      B4 --> B5["Raw / inconsistent tool result handling"]
    end

    subgraph AFTER["After SDK (standardized control hook)"]
      A1["Agent"] --> A2["Xenovia SDK execute/guard"]
      A2 --> A3["Xenovia Proxy decision + trace_id"]
      A3 --> A4{"mode"}
      A4 -- "enforce + deny" --> A5["blocked response"]
      A4 -- "allow or observe" --> A6["Local execution"]
      A6 --> A7["Unified XenoviaResponse<br/>status + decision + result + trace_id"]
      A7 --> A8["Sequence mapping + behavior controls"]
    end

Execution Flow

flowchart TD
    A["Agent / App"] --> B["Xenovia SDK (execute/guard)<br/>infers capability from module.function"]
    B --> C["Xenovia Proxy<br/>policy decision + trace_id"]
    C --> D{"Decision"}
    D -- "deny" --> E["Blocked response<br/>status=blocked + reason + trace_id"]
    D -- "allow" --> F["Local tool execution<br/>(your infra)"]
    F --> G["Capture actual result/outcome"]
    G --> H["Return unified response<br/>decision + result + trace_id"]
    H --> I["Sequence mapping<br/>session_id + capability + call order"]
    I --> J["Behavior controls<br/>detect/limit duplicate or multi-call patterns"]

Installation

pip install xenovia-sdk

For local development:

pip install -e ".[dev]"

Quick Start

Capability is inferred automatically from the calling module and function name — you do not need to name it.

from xenovia_sdk import Xenovia

xenovia = Xenovia(
    api_key="xv_...",
    endpoint="https://api.xenovia.io",
    default_env="prod",
    auto_session=True,
)

# capability inferred as "payments.transfer" when called from payments.py
decision = xenovia.execute({"service": "checkout", "version": "v2"})

if decision.is_blocked():
    print("Blocked:", decision.decision.get("reason"))
elif decision.is_success():
    print("Allowed:", decision.trace_id)
else:
    print("Failed:", decision.error)

Guard Modes

guard() wraps existing tool functions with decision-aware control. Capability is inferred from the decorated function's module and name.

# capability inferred as "k8s.deploy" when defined in k8s.py
@xenovia.guard(mode="enforce")
def deploy(payload):
    return kubectl_apply(payload)

Supported modes:

  • enforce (recommended): execute local function only when decision outcome is allow.
  • observe: always execute local function, but still return Xenovia's decision for visibility.

Migration pattern:

  1. Start with observe.
  2. Review would-have-blocked events.
  3. Move sensitive capabilities to enforce.

API Surface

Xenovia(
    api_key: str,
    endpoint: str = "https://api.xenovia.io",
    default_env: str = "prod",
    raise_on_block: bool = False,
    timeout: int = 5,
    auto_session: bool = False,
    debug: bool = False,
    identity_id: str | None = None,
    identity_type: str = "agent",
    unreachable_mode: str = "error",
    allow_insecure_http: bool = False,
)

Primary methods:

  • execute(payload, capability=None, session_id=None, env=None) -> XenoviaResponse
  • guard(capability=None, mode="enforce") -> decorator

Capability is inferred as module.function_name when not provided. It can always be overridden explicitly.

XenoviaResponse fields:

  • status: success | blocked | failed
  • result: local function output (if executed via guard) or backend-provided result
  • error: string error when present
  • decision: decision payload (outcome, rule_id, reason, ...)
  • trace_id: request trace identifier

Wire Contract

SDK request envelope:

{
  "capability": "payments.transfer",
  "payload": { "...": "..." },
  "session_id": "sess_123",
  "identity": { "type": "agent", "id": "agent_7" },
  "env": "prod",
  "sdk": { "version": "0.1.2", "language": "python" }
}

Typical response shape:

{
  "status": "blocked",
  "result": null,
  "error": "policy_violation",
  "decision": {
    "outcome": "deny",
    "rule_id": "SEQ_001",
    "reason": "unsafe_sequence"
  },
  "trace_id": "xnv_123"
}

Security Defaults

The SDK ships with opinionated safety defaults:

  • HTTPS endpoint enforcement by default (allow_insecure_http=False).
  • If allow_insecure_http=True, only localhost/loopback HTTP endpoints are permitted.
  • No secret or payload logging in normal operation.
  • Explicit fail-mode for Xenovia outages:
    • unreachable_mode="error" (default)
    • unreachable_mode="allow" (fail-open)
    • unreachable_mode="block" (fail-closed)
  • Structured identity metadata on every request.
  • Timeout required and validated.

Production Configuration Example

import os
from xenovia_sdk import Xenovia

xenovia = Xenovia(
    api_key=os.environ["XENOVIA_API_KEY"],
    endpoint=os.environ.get("XENOVIA_ENDPOINT", "https://api.xenovia.io"),
    default_env=os.environ.get("XENOVIA_ENV", "prod"),
    identity_id=os.environ.get("XENOVIA_AGENT_ID", "payments-agent"),
    auto_session=True,
    raise_on_block=False,
    unreachable_mode="block",  # fail closed for sensitive environments
)

Development

Run tests:

python -m unittest discover -s tests -v

Publishing and Security Docs

  • See PUBLISHING.md for release workflow and publishing checklist.
  • See SECURITY.md for vulnerability reporting and operational controls.
  • See CHANGELOG.md for release history.
  • See docs/SDK_REFERENCE.md for full mode matrix and behavior reference.

CI and Release Automation

  • .github/workflows/ci.yml runs tests, builds the package, and checks metadata.
  • .github/workflows/publish.yml is manual (workflow_dispatch) and supports separate targets: testpypi and pypi.
  • .github/dependabot.yml keeps dependencies and GitHub Actions updated weekly.

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

xenovia_sdk-0.1.2.tar.gz (20.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xenovia_sdk-0.1.2-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file xenovia_sdk-0.1.2.tar.gz.

File metadata

  • Download URL: xenovia_sdk-0.1.2.tar.gz
  • Upload date:
  • Size: 20.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for xenovia_sdk-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5161678d06258a92ff98c99d798ff81d3db5e734eaf52774fb768e738d7721a6
MD5 38cd1195704dc9b462cb43b4fb33ceb0
BLAKE2b-256 51da04cf686fe0024a84c69e2129d8618b76404f192f2fbace0a0c3d430697fa

See more details on using hashes here.

File details

Details for the file xenovia_sdk-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: xenovia_sdk-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for xenovia_sdk-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f67eee0cb5729837d67a7293762603abef3c9782e9ec12f9a6216a8ed4b6bd4b
MD5 9f5f8e0a38de14f35ec47fecf896113f
BLAKE2b-256 8f2a2bb189fc0a84c72808dd9eaea4f25bedf5c999baa198039f494fdd452d7c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page