Metadata-Version: 2.4
Name: sanctum-sdk
Version: 1.0.0
Summary: CRP v2 client for Sanctum — use credentials without ever holding them.
Project-URL: Homepage, https://github.com/SanctumSec/sanctum
Project-URL: Documentation, https://github.com/SanctumSec/sanctum/tree/main/sdk/python
Author: Sanctum
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ai-agents,credentials,crp,mcp,sanctum,vault
Requires-Python: >=3.8
Requires-Dist: pynacl>=1.5
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Description-Content-Type: text/markdown

# Sanctum Python SDK

A CRP v2 client for [Sanctum](https://github.com/SanctumSec/sanctum) — the local
credential vault + data-access firewall for AI agents.

**Use, don't retrieve.** Instead of handing your agent a secret, Sanctum hands it
a short-lived *use-handle*: a URL you point your existing HTTP SDK at. The vault
injects the real credential in transit, so the secret never enters your process.

```bash
pip install sanctum-sdk
```

## Quickstart

```python
from sanctum_sdk import VaultClient
from openai import OpenAI

with VaultClient("my-agent") as sanctum:
    h = sanctum.use("openai")                    # crp/use → a handle, not a secret

    client = OpenAI(
        base_url=h.proxy_base_url,               # point the SDK at the vault
        api_key=h.token,                         # your Sanctum session, NOT the key
    )
    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "hi"}],
    )
```

Your agent never sees the OpenAI key. It sets `base_url` to the vault and passes
its **Sanctum session token** where the SDK expects an API key. The vault
authenticates the agent by that token, swaps in the real key, and forwards the
request upstream. Point any base-URL-configurable SDK the same way.

## Why this is safer

| | Retrieve (old way) | Use-handle (CRP v2) |
|---|---|---|
| Secret in your process | yes | **never** |
| Blast radius if the agent is compromised | the raw key | a revocable, TTL-bound, policy-scoped handle |
| Rotation | re-fetch everywhere | transparent — the handle is stable |

## API

```python
sanctum.use(service, *, ttl=None, identity_scope=None) -> UseHandle
sanctum.list() -> list[dict]          # services you may use (+ classification)
sanctum.lease_status(lease_id) -> dict
sanctum.revoke(lease_id) -> None
sanctum.token -> str                  # session token (== an HTTP SDK "api key")
sanctum.retrieve(path) -> str         # break-glass; deny-by-default, discouraged
```

`UseHandle` fields: `service`, `lease_id`, `proxy_base_url`, `token`,
`credential_type`, `classification`, `brokered`, `expires_at`.

### Brokered identities (Entra / OAuth2)

For credentials configured for federation, select an identity:

```python
h = sanctum.use("graph", identity_scope="agent-identity-client-id")
```

The vault performs the token exchange server-side; `h.brokered` is `True` and the
short-lived token is refreshed for the life of the lease — the handle is stable.

## Connection

By default the SDK connects to the daemon over the Unix socket
`~/.sanctum/vault.sock` and loads the agent's Ed25519 key from
`~/.sanctum/keys/<agent>.key`. Override:

```python
VaultClient("my-agent", socket_path="/run/sanctum.sock", key_path="/keys/agent.seed")
```

## Requirements

- A running Sanctum daemon (`sanctum daemon start`) with the vault unlocked.
- An enrolled agent identity (`sanctum agent add my-agent`).
- `pynacl` (installed automatically) for Ed25519 signing.

## License

Apache-2.0 — see [LICENSE](./LICENSE). (The Sanctum core daemon is separately licensed under BUSL-1.1.)
