Metadata-Version: 2.4
Name: xenovia-sdk
Version: 0.1.1
Summary: Decision-first Python SDK for policy-aware agent action control
Project-URL: Homepage, https://xenovia.io
Project-URL: Documentation, https://docs.xenovia.io
Project-URL: Source, https://github.com/Xenovia-io/xenovia-sdk-python
Project-URL: Issues, https://github.com/Xenovia-io/xenovia-sdk-python/issues
Keywords: agents,policy,security,governance,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: build>=1.2.2; extra == "dev"
Requires-Dist: twine>=5.1.1; extra == "dev"
Requires-Dist: ruff>=0.6.9; extra == "dev"
Requires-Dist: mypy>=1.11.2; extra == "dev"

# 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.

## Installation

```bash
pip install xenovia-sdk
```

For local development:

```bash
pip install -e ".[dev]"
```

## Quick Start

```python
from xenovia_sdk import Xenovia

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

decision = xenovia.execute(
    capability="k8s.deploy",
    payload={"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.

```python
@xenovia.guard("k8s.deploy", 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

```python
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(capability, payload, session_id=None, env=None) -> XenoviaResponse`
- `guard(capability, mode="enforce") -> decorator`

`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:

```json
{
  "capability": "k8s.deploy",
  "payload": { "...": "..." },
  "session_id": "sess_123",
  "identity": { "type": "agent", "id": "agent_7" },
  "env": "prod",
  "sdk": { "version": "0.1.0", "language": "python" }
}
```

Typical response shape:

```json
{
  "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

```python
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:

```bash
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.
