Metadata-Version: 2.5
Name: eniyan
Version: 0.1.0
Summary: Eniyan SDK — govern your AI agents wherever they run: identity, scoped authority, JIT windows, and self-reported run telemetry.
Project-URL: Homepage, https://eniyantrust.com
Project-URL: Documentation, https://eniyantrust.com/docs
Author-email: Eniyan <stevland@eniyantrust.com>
License-Expression: Apache-2.0
Keywords: agent-identity,ai-agents,governance,mcp,rbac
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.10
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == 'mcp'
Description-Content-Type: text/markdown

# Eniyan SDK (Python)

Govern your AI agents wherever they run. This SDK wraps the Eniyan API —
agent identity verification, live scope decisions, JIT credential windows,
short-lived OAuth tokens, and self-reported run telemetry — so any agent
loop becomes Eniyan-governed in a few lines. Eniyan never hosts or observes
your loop; your agent reports metadata-only telemetry (names, scopes, token
counts, outcomes — never prompts, arguments, results, or model output).

```bash
pip install eniyan
```

## Quickstart

```python
import os
from eniyan import EniyanClient, governed_run, EniyanScopeRefused

client = EniyanClient(
    base_url="https://api.eniyantrust.com",
    api_key=os.environ["ENIYAN_API_KEY"],
    credential_token=os.environ["ENIYAN_CREDENTIAL_TOKEN"],
    agent_id=os.environ["ENIYAN_AGENT_ID"],
)

with governed_run(client, harness="my-loop", jit=True, scopes=["crm:read"]) as run:
    fetch = run.tool("fetch_accounts", scope="crm:read")(fetch_accounts)
    accounts = fetch()                      # refused under block mode BEFORE it runs
    run.model_call("claude-sonnet-5", input_tokens=1200, output_tokens=300)
```

On exit — success or crash — the run is finished, buffered steps are
flushed, and the JIT window is completed and attested.

## What each piece maps to

| SDK call | API |
|---|---|
| `client.verify()` / `client.check_scope()` | `POST /v1/credentials/verify` |
| `client.mint_token()` / `client.introspect()` | `POST /v1/oauth/token` / `/introspect` |
| `client.validate_grant()` | `POST /v1/agents/credentials/validate` |
| `client.create_task()` / `complete_task()` / `attest_task()` | JIT task lifecycle |
| `client.start_run()` / `append_steps()` / `finish_run()` | `POST /v1/runs` |

Advisory-mode scope violations do not raise — the call proceeds and the
violation is flagged server-side (`GovernanceDecision.advisory_flagged`).
Block mode raises `EniyanScopeRefused` before the tool executes.

## MCP server

`pip install "eniyan[mcp]"` and run `eniyan-mcp` to expose the same
governance operations as MCP tools for Claude Code or any MCP-capable
harness. See the gated docs for configuration.

## Development

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

`tests/integration_local.py` runs the full flow against a local Eniyan
stack (`docker compose up` from the repo root).
