Metadata-Version: 2.4
Name: xybern
Version: 2.24.0
Summary: Identity & authorisation infrastructure for AI agents — install once, discover every agent, authorise every action.
Author-email: Xybern <info@xybern.com>
License: MIT
Project-URL: Homepage, https://www.xybern.com
Project-URL: Documentation, https://docs.xybern.com/authorization/sdk
Keywords: ai,agents,authorization,identity,governance,langchain,crewai,mcp,provenance
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.25.0
Provides-Extra: crypto
Requires-Dist: cryptography>=41.0.0; extra == "crypto"
Provides-Extra: mcp
Requires-Dist: mcp>=1.0.0; extra == "mcp"
Requires-Dist: httpx>=0.24; extra == "mcp"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"

# Xybern

**Identity & authorisation infrastructure for AI agents.** Install once — Xybern
discovers every AI agent in your system, gives each a cryptographic identity, and
(when you turn enforcement on) authorises every action *before* it executes.

```bash
pip install xybern
xybern login          # browser device-code flow (auto-links your workspace)
```

```python
from xybern import auto
auto.connect()        # discovers frameworks + agents + tools, registers them, instruments them
```

```
✓ Detected frameworks: CrewAI, LangGraph, 2 MCP servers
✓ Found 12 agents · 48 tools
✓ Registered to workspace "Acme Corp" (each issued a cryptographic identity)
✓ Mode: OBSERVE — actions logged, nothing blocked yet
```

## Where to add it

Add these two lines **once, at your app's startup — before your agents run.**
That's the whole integration.

```python
from xybern import auto
auto.connect()
# ... then your normal code: build agents, run the crew/graph, serve, etc.
```

| Your setup | Where to put it |
| --- | --- |
| Agent script (CrewAI / LangChain / OpenAI Agents / LlamaIndex) | Top of your main file, before creating agents |
| FastAPI | Right after `app = FastAPI()` |
| Celery | In the Celery app module (runs in each worker) |
| MCP server | Top of the server entry, before serving tools |
| Django | An `AppConfig.ready()` or `wsgi.py` |
| Jupyter | First cell |

> Multi-process (gunicorn / multiple Celery workers): run it in the module each
> worker imports, so every process is covered.

## What it does

- **Auto-discovery** — detects and instruments LangChain, CrewAI, OpenAI Agents SDK,
  MCP servers, LangGraph, AutoGen, Semantic Kernel, LlamaIndex (and FastAPI/Celery).
  No manual wiring; agents appear in your Xybern dashboard as your app creates them.
- **Cryptographic identity** — every discovered agent is registered and issued an
  identity, so its actions are attributable and signable.
- **Authorisation before execution** — each tool/agent action passes through Xybern's
  policy engine; `allow` / `block` / `escalate`.
- **Observe-first & fail-open** — default mode only *logs* (never blocks). When you
  switch to enforce, the SDK fails open if Xybern is unreachable, so it can't take
  your agents down.
- **Privacy** — sends content **hashes** by default, not raw payloads.

## Modes

```python
auto.connect()                 # OBSERVE (default): log + inventory, never blocks
auto.connect(mode="enforce")   # authorise actions (allow/block/escalate)
```
or persist it: `xybern enforce on` / `xybern enforce off`.

## CLI

```
xybern login [--api-key xb_...]   # device-code flow, or paste a key / set XYBERN_API_KEY
xybern agents                     # dry-run: what would be discovered
xybern doctor                     # per-framework enforcement coverage
xybern status
xybern enforce on|off
xybern run --agent NAME python your_agent.py   # authorise a program without editing it
xybern logout
```

### `xybern run`, no code change

```
xybern run --agent soc-agent python agent.py "Investigate alert ALR-1042"
```

Runs the program in this interpreter with `auto.connect()` already applied, so the
file itself is untouched. `--agent` gives the whole process one identity: it is
registered once, its tools are its capabilities, and every tool call is attributed
to it. `--enforce` / `--observe` set the mode for this run, `--wait SECONDS`
(default 900) is how long an escalated action is held for a person's decision,
`--frameworks langchain,mcp` limits the hooks.

The same in code: `auto.connect(agent="soc-agent", escalation_wait=900)`.

Every decision prints one line (`--quiet` turns it off, `XYBERN_TRACE=1` turns it on
for `auto.connect()`):

```
xybern  ✓ allowed   block_ip           soc-agent    180 ms
xybern  ⏸ held      isolate_host       soc-agent    Isolating a production host needs a person's approval, waiting for a person
xybern  ✕ refused   export_logs        soc-agent    Logs are only sent to destinations inside the Kingdom
```

### Several agents in one program

An agent the framework names (LangChain `create_agent(..., name="triage")`) gets its
own identity, and its tool calls are attributed to it. `--agent` is the identity for
actions no agent is named for.

```
xybern run --agents "responder,billing-*" python app.py    # authorise only these agents
xybern run --skip "lookup_*,get_*" python app.py           # leave these actions alone
```

Actions of an agent outside `--agents`, and actions in `--skip`, run as if the SDK
were absent: they are neither authorised nor recorded.

### Agents that hand work to other agents

When a named agent runs inside another agent's action (a lead agent whose tool runs a
sub-agent, the usual LangChain pattern), the SDK treats it as a hand-off. Nothing is
added to the program.

```
xybern  ✓ allowed   ask_responder      soc-lead     120 ms
xybern  ✓ allowed   → responder        soc-lead     hand-off, 115 ms
xybern  ✓ allowed   block_ip           responder    for soc-lead, 1 of 3 used, 150 ms
xybern  ✕ refused   export_logs        responder    for soc-lead, 'export_logs' is outside what 'soc-lead' lent, which covers block_ip
xybern  ✕ refused   → responder        triage       hand-off, Only the SOC lead instructs the responder
```

- **The hand-off is authorised first**, as an instruction from the first agent to the
  second, before the second one reads it. The communication rules of the Charter decide
  who may instruct whom.
- **What the second agent does is done for the first.** If the first lent it authority
  (a delegation grant), every action carries that grant: an action outside it, or beyond
  its budget, is refused.
- **One request is one chain.** Every action and hand-off carries the chain and its place
  in it, so the dashboard shows the request from start to end.

Agents are matched to the ones the Charter declares by name, so a Charter file that names
`soc-lead` governs the agent your code calls `soc-lead`.

## Auth options

1. **Device code** — `xybern login` opens a browser; approve + pick a workspace; a
   scoped key is minted and stored in `~/.xybern/credentials.json`.
2. **API key** — `xybern login --api-key xb_...`, or `export XYBERN_API_KEY=xb_...`,
   or `auto.connect(api_key="xb_...")`.

## Configuration

| Option | Default | Meaning |
| --- | --- | --- |
| `mode` | `observe` | `observe` (log only) or `enforce` (act on decisions) |
| `fail_open` | `True` in observe, `False` in enforce | allow actions through if Xybern is unreachable (enforce mode) |
| `redact` | `False` | send only a SHA-256 of the content (`XYBERN_REDACT=1`). Content-pattern and semantic mandates cannot evaluate hashed content; for residency use a relay or dedicated deployment instead |
| `frameworks` | all | restrict to specific frameworks (`XYBERN_FRAMEWORKS=langchain,mcp`) |
| `agent` | none | one identity for the whole process; every tool call is attributed to it (`XYBERN_AGENT`) |
| `agents` | all | authorise only the agents whose name matches, `*` allowed (`XYBERN_AGENTS=responder,billing-*`) |
| `skip` | none | action types left alone (`XYBERN_SKIP=lookup_*,get_*`) |
| `trace` | off, on under `xybern run` | one line per decision on stderr (`XYBERN_TRACE=1`) |
| `escalation_wait` | `0` | enforce mode: seconds to hold an escalated action for a person's decision; `0` refuses it at once (`XYBERN_ESCALATION_WAIT`) |

In enforce mode a refused action raises `PolicyBlocked` with the decision's reasoning,
a held one `PolicyEscalated` (or `ApprovalRejected` after a person rejects it), and a
terminated session `SessionTerminated`.

Docs: https://docs.xybern.com/authorization/sdk
