# NotaryOS SDK for Python

> **v2.2.0** — Cryptographic receipts for AI agent actions.

Issue, verify, and audit agent behavior with Ed25519 signatures. Zero external dependencies — uses only Python standard library. Python 3.8+.

## Install

```bash
pip install notaryos
```

## Quick Start — 3 Lines

```python
from notaryos import NotaryClient

notary = NotaryClient()  # works instantly, no signup needed
receipt = notary.seal("data_processing", {"key": "value"})
```

That's it. No API key needed to start — the SDK uses a free demo key automatically (10 req/min).
For production, sign up at [notaryos.org](https://notaryos.org) and pass your own key:

```python
notary = NotaryClient(api_key="notary_live_xxx")  # unlimited
```

## What You Get

Every receipt includes:
- **Ed25519 signature** — tamper-evident proof
- **Merkle chain linking** — ordered history via `previous_receipt_hash`
- **Receipt hash** — SHA-256 for public lookup
- **Verify URL** — anyone can verify without an API key

## Examples

### Seal an Action

```python
from notaryos import NotaryClient

notary = NotaryClient(api_key="notary_live_xxx")

receipt = notary.seal("financial.transfer", {
    "from": "billing-agent",
    "to": "ledger-agent",
    "amount": 150.00,
    "currency": "USD",
})

print(receipt.receipt_id)     # receipt_abc123...
print(receipt.receipt_hash)   # sha256 hex
print(receipt.signature)      # Ed25519 signature
print(receipt.chain_sequence) # position in chain
```

### Verify a Receipt

```python
# With API key (full details)
result = notary.verify(receipt)
print(result.valid)        # True
print(result.signature_ok) # True
print(result.structure_ok) # True

# Without API key (public, returns bool)
from notaryos import verify_receipt
is_valid = verify_receipt(receipt.raw)  # True
```

### Look Up a Receipt by Hash

```python
result = notary.lookup(receipt.receipt_hash)
if result["found"]:
    print(result["verification"]["valid"])  # True
```

### Chain Receipts Together

```python
step1 = notary.seal("agent.plan", {"task": "analyze data"})
step2 = notary.seal("agent.execute", {"result": "done"}, previous_receipt_hash=step1.receipt_hash)
# step2.chain_sequence is incremented, linked to step1
```

### Seal AI Reasoning Tokens

If your LLM returns reasoning tokens (DeepSeek, KIMI K2.5, Claude, etc.):

```python
# response is an OpenRouter-compatible API response
response = openai_client.chat.completions.create(
    model="deepseek/deepseek-r1",
    messages=[{"role": "user", "content": "Analyze this data"}],
)
sealed = notary.seal_reasoning(response)
print(f"Sealed {sealed['node_count']} reasoning nodes")
print(f"Provenance root: {sealed['provenance_hash']}")
```

### Counterfactual Receipts (Commit-Reveal)

Prove your agent *chose not to act* — a cryptographic proof of restraint:

```python
# Phase 1: Commit (reasoning is hashed, not stored)
result = notary.commit_counterfactual(
    action_not_taken="financial.execute_trade",
    capability_proof={"permissions": ["trade.execute"]},
    opportunity_context={"ticker": "ACME", "price": 142.50},
    decision_reason="Risk score exceeds threshold",
)

# Phase 2: Reveal (after min_reveal_delay_seconds)
reveal = notary.reveal_counterfactual(
    result["receipt_hash"],
    "Risk score exceeds threshold"
)
assert reveal["success"]

# Check status
status = notary.commit_status(result["receipt_hash"])
print(status["phase"])  # "revealed"
```

## Full API Reference

### `NotaryClient(api_key, base_url=None, timeout=30, max_retries=2)`

| Method | Auth | Description |
|--------|------|-------------|
| `seal(action_type, payload, ...)` | API Key | Issue a signed receipt (alias for `issue`) |
| `issue(action_type, payload, ...)` | API Key | Issue a signed receipt |
| `verify(receipt)` | API Key | Verify a receipt's signature and integrity |
| `verify_by_id(receipt_id)` | API Key | Verify by receipt ID (server-side lookup) |
| `lookup(receipt_hash)` | Public | Look up receipt by SHA-256 hash |
| `seal_reasoning(response, model)` | API Key | Seal AI reasoning tokens as receipts |
| `commit_counterfactual(...)` | API Key | Commit a counterfactual receipt (phase 1) |
| `reveal_counterfactual(hash, reason)` | API Key | Reveal committed reasoning (phase 2) |
| `commit_status(receipt_hash)` | API Key | Check commit-reveal lifecycle status |
| `status()` | API Key | Service health check |
| `public_key()` | API Key | Get Ed25519 public key for offline verification |
| `me()` | API Key | Get authenticated agent info (id, tier, scopes) |

### `verify_receipt(receipt_dict, base_url=None) -> bool`

Public verification without API key. Returns `True` if the receipt is valid.

## CLI

```bash
# Check service status
notaryos status

# Issue a receipt
notaryos issue notary_live_xxx my_action

# Verify a receipt
notaryos verify '{"receipt_id": "...", ...}'

# Look up by hash
notaryos lookup abc123def456
```

## Error Handling

```python
from notaryos import NotaryClient, AuthenticationError, RateLimitError, ValidationError

try:
    receipt = notary.seal("action", {"key": "value"})
except AuthenticationError:
    # Invalid or expired API key (401)
    pass
except RateLimitError as e:
    # Too many requests — wait e.retry_after seconds (429)
    pass
except ValidationError:
    # Request validation failed (422)
    pass
```

## Works With Any AI Stack

NotaryOS is LLM-agnostic. It seals *actions*, not model calls:

```python
# Your custom LLM — any model, any provider
result = my_custom_llm.generate("Analyze this document")

# Seal the proof
receipt = notary.seal("llm.inference", {
    "model": "my-custom-llm-v3",
    "output_hash": hashlib.sha256(result.encode()).hexdigest(),
})
```

## Get an API Key

1. Sign up at [notaryos.org](https://notaryos.org)
2. Generate an API key from the dashboard
3. Keys start with `notary_live_` (production) or `notary_test_` (sandbox)

## Links

- [NotaryOS Documentation](https://notaryos.org/docs)
- [API Reference](https://notaryos.org/api-docs)
- [GitHub](https://github.com/hellothere012/notaryos)

## License

BSL 1.1 (Apache 2.0 after 2029-02-25)
