Metadata-Version: 2.4
Name: onkernel
Version: 0.2.0
Summary: Python SDK for Kernel — deterministic governance for AI agents
Project-URL: Homepage, https://onkernel.ai
Project-URL: Documentation, https://github.com/onkernel-ai/kernel-python#readme
Project-URL: Repository, https://github.com/onkernel-ai/kernel-python
Project-URL: Issues, https://github.com/onkernel-ai/kernel-python/issues
Project-URL: Changelog, https://github.com/onkernel-ai/kernel-python/blob/main/CHANGELOG.md
Author-email: Kernel <engineering@onkernel.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: agents,ai,governance,guardrails,llm,policy
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Provides-Extra: crypto
Requires-Dist: cryptography>=44.0; extra == 'crypto'
Provides-Extra: dev
Requires-Dist: cryptography>=44.0; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# onkernel

Python SDK for [Kernel](https://onkernel.ai) — deterministic governance for AI agents.

## Install

```bash
pip install onkernel
```

For encrypted response decryption:

```bash
pip install onkernel[crypto]
```

## Quick Start

```python
from kernel import Kernel, KernelOutcome

k = Kernel(api_key="ok_live_acme_bot1_abc123")

resp = k.execute(action="send_email", target="user@example.com", params={"body": "Hello"})

match resp.outcome:
    case KernelOutcome.ALLOWED:
        # resp.result and resp.result_message are populated
        print(resp.result_message)
    case KernelOutcome.REQUIRES_HUMAN:
        # 202 — escalate to your approval queue
        approval_id = resp.approval_id
    case KernelOutcome.BLOCKED:
        # a scanner fired; resp.violations is populated
        ...
    case KernelOutcome.DENIED:
        # a policy rule denied; resp.reason explains why
        ...
```

`ActionResponse` always carries a non-empty `result_message: str` — a
human-readable summary that's safe to surface in an LLM tool-call result.

### Handling errors

The denial path raises typed exceptions on 403:

```python
from kernel import (
    Kernel,
    ScannerBlockedError,   # scanner fired (PII, secrets, prompt injection, …)
    PolicyDeniedError,     # policy rule denied with no scanner involvement
    KernelDeniedError,     # base / alias — catch both
)

try:
    k.execute(action="export_pii_report", target="customers")
except ScannerBlockedError as e:
    # e.violation_type, e.violation_details, e.violations
    pass
except PolicyDeniedError as e:
    # e.rule_id, e.policy_id, e.reason
    pass
```

### 3-step token flow

```python
session = k.create_session(intent="onboard new customer")
token = k.request_token(session.id, action="create_account", target="stripe")
result = k.execute_token(token.token_id, agent_id="bot1")
```

## Decrypting Responses

When a policy has `encryption_enabled: true`, responses arrive encrypted:

```python
from kernel import Kernel
from kernel.crypto import load_private_key

k = Kernel(api_key="ok_live_acme_bot1_abc123")
private_key = load_private_key("path/to/private_key.pem")

resp = k.execute(action="fetch_records", target="db")
if resp.encrypted:
    data = resp.decrypt(private_key)
```

## Publishing (maintainers)

The SDK is published to PyPI as `onkernel`. Releases go out via tag push;
the `publish.yml` workflow handles build + Trusted-Publishing OIDC.

**Always release to TestPyPI first.** PyPI is fussy about metadata and
artifact integrity; a TestPyPI dry-run catches mistakes before they're
permanent (PyPI does not allow overwriting a released version).

### One-time setup

1. Create the project on PyPI: `pip install build twine && python -m build && twine upload --repository testpypi dist/*` (first manual upload claims the namespace).
2. On PyPI → project → Publishing, add a pending publisher:
   - Owner: `onkernel-ai`
   - Repository: `kernel-python`
   - Workflow: `publish.yml`
   - Environment: `pypi`
3. Repeat the publisher binding on test.pypi.org with environment `testpypi`.
4. In the GitHub repo Settings → Environments, create `pypi` and `testpypi`. Add required reviewers on `pypi` if you want a release gate.

### Cutting a release

1. Bump `pyproject.toml` `[project].version` and `src/kernel/__init__.py` `__version__` together.
2. Update `CHANGELOG.md`.
3. Pre-release dry-run:
   ```bash
   git tag v0.X.Y-rc.1
   git push --tags
   ```
   The `publish.yml` workflow detects the `-rc.N` suffix and routes to TestPyPI. Validate:
   ```bash
   pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ onkernel==0.X.Y-rc.1
   python -c "from kernel import Kernel, KernelOutcome; print(KernelOutcome.ALLOWED)"
   ```
4. Real release:
   ```bash
   git tag v0.X.Y
   git push --tags
   ```
   The same workflow routes the un-suffixed tag to real PyPI.

The workflow verifies that the tag matches `pyproject.toml [project].version`
before building — a mismatched tag fails fast instead of publishing the
wrong artifact.

### Fallback: manual API token

If Trusted Publishing isn't yet bound, set repo secret `PYPI_API_TOKEN`
and replace the OIDC publish step with:

```yaml
- run: twine upload -u __token__ -p "$PYPI_API_TOKEN" dist/*
```

Tokens carry blast-radius risk (leak = arbitrary release). Migrate to OIDC
as soon as the binding is approved on the PyPI side.
