Metadata-Version: 2.4
Name: attestify-sdk
Version: 0.1.5
Summary: Official Python SDK for Attestify OS — governed agent execution in a few lines.
Project-URL: Homepage, https://attestify-os.vercel.app
Project-URL: Documentation, https://attestify-os.vercel.app
Project-URL: Repository, https://github.com/attestifyagent/attestify-sdk
License: MIT
Keywords: ai-agents,attestify,governance,receipts,x402
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# attestify-sdk — Python

Add governed lane execution to any Python codebase in a few lines.

## Install

```bash
pip install attestify-sdk
```

Or directly from the repo while the package is in early access:

```bash
pip install "git+https://github.com/attestifyagent/attestify-os.git#subdirectory=sdk/python"
```

## Quick start

```python
import os
from attestify import create_client

client = create_client(api_key=os.environ["ATTESTIFY_API_KEY"])

result = client.run_lane(
    input="Summarise the latest advances in quantum error correction.",
    lane_id="researcher-v2",
    session_id="my-session-001",
    options={"verify": True, "write_memory": True},
)

print(result.output)             # lane response text
print(result.receipt.run_id)     # unique run identifier
print(result.receipt.evidence)   # full EvidenceBundle dataclass
print(result.receipt.pricing)    # cost breakdown
```

## Features

- **`create_client(api_key)`** — configure once, use anywhere
- **`client.run_lane(input, ...)`** — single call handles sessions, retries, idempotency
- **Typed receipts** — `RunReceipt` and `EvidenceBundle` dataclasses with full field coverage
- **Auto-routing** — omit `lane_id` and Attestify picks the best lane for the task
- **Idempotency** — pass `idempotency_key` to guarantee exactly-once execution
- **Budget controls** — pass `constraints={"max_cost_usdc": 0.05}` to cap spend per run
- **Webhook support** — pass `options={"webhook_url": "..."}` for async delivery
- **Zero dependencies** — stdlib only (`urllib`, `json`, `uuid`)

## API Reference

### `create_client(api_key, base_url?, max_retries?, timeout_s?)`

| Parameter | Type | Default | Description |
|---|---|---|---|
| `api_key` | `str` | **required** | Your Attestify API key (`ATTESTIFY_API_KEY`) |
| `base_url` | `str` | `https://attestify-os.vercel.app` | Override the endpoint |
| `max_retries` | `int` | `2` | Retries on transient 5xx errors |
| `timeout_s` | `float` | `60.0` | Per-attempt timeout in seconds |

---

### `client.run_lane(input, ...)`

| Parameter | Type | Description |
|---|---|---|
| `input` | `str` | **Required.** The task or intent |
| `lane_id` | `str` | Optional — omit to auto-route |
| `session_id` | `str` | Memory / conversation continuity ID |
| `idempotency_key` | `str` | Prevents duplicate charges for the same key |
| `context` | `dict` | Freeform context forwarded to the lane |
| `constraints` | `dict` | Budget / SLA constraints (see below) |
| `options` | `dict` | Runtime flags (see below) |

Returns `RunLaneResult(output, receipt, raw)`.

**`constraints` fields:**
```python
constraints={
    "max_cost_usdc": 0.05,    # abort if estimated cost exceeds this
    "max_latency_ms": 10000,  # abort if estimated latency exceeds this
    "budget_id": "proj-abc",  # link to a named budget envelope
}
```

**`options` fields:**
```python
options={
    "verify": True,                    # run output verification (default False)
    "write_memory": True,              # persist session memory (default False)
    "include_memory": True,            # inject prior memory into context
    "webhook_url": "https://...",      # async result delivery
}
```

---

### `client.get_receipt(loop_id)`

Fetch a stored receipt by its `loop_id`.

```python
receipt = client.get_receipt("loop_abc123")
print(receipt.verification)   # grade, score, output_hash
print(receipt.settlement)     # on-chain tx hash if x402 used
```

Returns `RunReceipt`.

---

### `RunReceipt` fields

| Field | Type | Description |
|---|---|---|
| `run_id` | `str` | Unique run identifier |
| `loop_id` | `str` | Persistent loop/session receipt ID |
| `lane_id` | `str` | Lane that handled the run |
| `lane_name` | `str` | Human-readable lane name |
| `output` | `str` | Lane response text |
| `paid` | `bool` | Whether x402 payment was used |
| `subscription_used` | `bool` | Whether an API key subscription covered this run |
| `evidence` | `EvidenceBundle` | Full governance evidence bundle |
| `verification` | `dict \| None` | Verification grade, score, output hash |
| `pricing` | `dict` | Cost breakdown in USDC |
| `settlement` | `dict \| None` | On-chain settlement details |
| `receipt_url` | `str` | Shareable receipt permalink |

---

## Available lanes

| `lane_id` | Description |
|---|---|
| `researcher-v2` | Deep research and synthesis |
| `analyst-v1` | Data analysis and structured output |
| `coder-v1` | Code generation and review |
| `writer-v1` | Long-form and structured writing |
| `strategist-v1` | Strategic planning and frameworks |
| `support-v1` | Customer support and triage |
| `comedian-v1` | Creative and entertainment tasks |

Omit `lane_id` entirely to let Attestify auto-route based on your `input`.

## Environment variables

```bash
ATTESTIFY_API_KEY=atst_live_...
```

## Async usage

The client is synchronous by design (zero dependencies). For async workflows:

```python
import asyncio
from attestify import create_client

client = create_client(api_key=os.environ["ATTESTIFY_API_KEY"])

async def main():
    result = await asyncio.to_thread(
        client.run_lane,
        input="Analyse Q2 revenue trends",
        lane_id="analyst-v1",
    )
    print(result.output)

asyncio.run(main())
```
